1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
use std::vec::Vec;
use std::fmt;
use std::fmt::Display;

use serde::{Serialize, Deserialize};
use serde::de::DeserializeOwned;
use reqwest::blocking::Client;
use reqwest::Error;

pub type Parameters<'a> = Vec<(&'a str, &'a str)>;

pub struct NikelAPI {
    client: Client
}

impl NikelAPI {
    pub fn new() -> NikelAPI {
        NikelAPI {
            client: Client::new()
        }
    }

    fn encode_params(params: Parameters) -> String {
        params
        .iter()
        .map(|(k, v)| format!("{}={}", k, v))
        .collect::<Vec<String>>()
        .join("&")
    } 

    fn get_url(endpoint: String, params: Parameters) -> String {
        format!("https://nikel.ml/api/{}?{}", endpoint, NikelAPI::encode_params(params))
    }

    fn get<T: DeserializeOwned>(&self, endpoint: String, params: Parameters) -> Result<Response<T>, reqwest::Error> {
        self.client.get(&NikelAPI::get_url(endpoint, params)).send()?.json::<Response<T>>()
    }

    pub fn courses(&self, params: Parameters) -> Result<Response<Course>, Error> {
        self.get("courses".to_owned(), params)
    }
    pub fn textbooks(&self, params: Parameters) -> Result<Response<Textbook>, Error> {
        self.get("textbooks".to_owned(), params)
    }
    pub fn exams(&self, params: Parameters) -> Result<Response<Exam>, Error> {
        self.get("exams".to_owned(), params)
    }
    pub fn evals(&self, params: Parameters) -> Result<Response<Eval>, Error> {
        self.get("evals".to_owned(), params)
    }
    pub fn food(&self, params: Parameters) -> Result<Response<Food>, Error> {
        self.get("food".to_owned(), params)
    }
    pub fn services(&self, params: Parameters) -> Result<Response<Service>, Error> {
        self.get("services".to_owned(), params)
    }
    pub fn buildings(&self, params: Parameters) -> Result<Response<Building>, Error> {
        self.get("buildings".to_owned(), params)
    }
    pub fn parking(&self, params: Parameters) -> Result<Response<Parking>, Error> {
        self.get("parking".to_owned(), params)
    }

}

// [ BEGIN DATA TYPES ]

// For the sake of printing
#[derive(Default, Clone, Serialize, Deserialize)]
pub struct OptionWrapper<T>(Option<T>);

impl<T: Display> fmt::Debug for OptionWrapper<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let output: String;
        if self.0.is_none() {
            output = "Unknown".to_string()
        } else {
            output = format!("{}", self.0.as_ref().unwrap())
        }
        write!(f, "{}", output)
    }
}

// [ RESPONSE STRUCT ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Response<T> {
    pub response: Vec<T>,
    pub status_code: OptionWrapper<i64>,
    pub status_message: OptionWrapper<String>,
}

// [ COURSES ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Course {
    pub id: OptionWrapper<String>,
    pub code: OptionWrapper<String>,
    pub name: OptionWrapper<String>,
    pub description: OptionWrapper<String>,
    pub division: OptionWrapper<String>,
    pub department: OptionWrapper<String>,
    pub prerequisites: OptionWrapper<String>,
    pub corequisites: OptionWrapper<String>,
    pub exclusions: OptionWrapper<String>,
    pub recommended_preparation: OptionWrapper<String>,
    pub level: OptionWrapper<String>,
    pub campus: OptionWrapper<String>,
    pub term: OptionWrapper<String>,
    pub arts_and_science_breadth: OptionWrapper<String>,
    pub arts_and_science_distribution: OptionWrapper<String>,
    pub utm_distribution: OptionWrapper<String>,
    pub utsc_breadth: OptionWrapper<String>,
    pub apsc_electives: OptionWrapper<String>,
    pub meeting_sections: Vec<CoursesMeetingSection>,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct CoursesMeetingSection {
    pub code: OptionWrapper<String>,
    pub instructors: Vec<String>,
    pub times: Vec<Time>,
    pub size: OptionWrapper<i64>,
    pub enrollment: OptionWrapper<i64>,
    pub waitlist_option: OptionWrapper<bool>,
    pub delivery: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Time {
    pub day: OptionWrapper<String>,
    pub start: OptionWrapper<i64>,
    pub end: OptionWrapper<i64>,
    pub duration: OptionWrapper<i64>,
    pub location: OptionWrapper<String>,
}

// [ TEXTBOOKS ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Textbook {
    pub id: OptionWrapper<String>,
    pub isbn: OptionWrapper<String>,
    pub title: OptionWrapper<String>,
    pub edition: OptionWrapper<i64>,
    pub author: OptionWrapper<String>,
    pub image: OptionWrapper<String>,
    pub price: OptionWrapper<f64>,
    pub url: OptionWrapper<String>,
    pub courses: Vec<TextbooksCourse>,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct TextbooksCourse {
    pub id: OptionWrapper<String>,
    pub code: OptionWrapper<String>,
    pub requirement: OptionWrapper<String>,
    pub meeting_sections: Vec<TextbooksMeetingSection>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct TextbooksMeetingSection {
    pub code: OptionWrapper<String>,
    pub instructors: Vec<String>,
}

// [ EXAMS ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Exam {
    pub id: OptionWrapper<String>,
    pub course_id: OptionWrapper<String>,
    pub course_code: OptionWrapper<String>,
    pub campus: OptionWrapper<String>,
    pub date: OptionWrapper<String>,
    pub start: OptionWrapper<i64>,
    pub end: OptionWrapper<i64>,
    pub duration: OptionWrapper<i64>,
    pub sections: Vec<ExamSection>,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct ExamSection {
    pub lecture_code: OptionWrapper<String>,
    pub split: OptionWrapper<String>,
    pub location: OptionWrapper<String>,
}

// [ EVALS ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Eval {
    pub id: OptionWrapper<String>,
    pub name: OptionWrapper<String>,
    pub campus: OptionWrapper<String>,
    pub terms: Vec<EvalTerm>,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct EvalTerm {
    pub term: OptionWrapper<String>,
    pub lectures: Vec<EvalLecture>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct EvalLecture {
    pub lecture_code: OptionWrapper<String>,
    pub firstname: OptionWrapper<String>,
    pub lastname: OptionWrapper<String>,
    pub s1: OptionWrapper<f64>,
    pub s2: OptionWrapper<f64>,
    pub s3: OptionWrapper<f64>,
    pub s4: OptionWrapper<f64>,
    pub s5: OptionWrapper<f64>,
    pub s6: OptionWrapper<f64>,
    pub invited: OptionWrapper<i64>,
    pub responses: OptionWrapper<i64>,
}

// [ FOOD ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Food {
    pub id: OptionWrapper<String>,
    pub name: OptionWrapper<String>,
    pub description: OptionWrapper<String>,
    pub tags: OptionWrapper<String>,
    pub campus: OptionWrapper<String>,
    pub address: OptionWrapper<String>,
    pub coordinates: Coordinates,
    pub hours: Hours,
    pub image: OptionWrapper<String>,
    pub url: OptionWrapper<String>,
    pub twitter: OptionWrapper<String>,
    pub facebook: OptionWrapper<String>,
    pub attributes: Vec<String>,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Hours {
    pub sunday: Sunday,
    pub monday: Monday,
    pub tuesday: Tuesday,
    pub wednesday: Wednesday,
    pub thursday: Thursday,
    pub friday: Friday,
    pub saturday: Saturday,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Sunday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Monday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Tuesday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Wednesday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Thursday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Friday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Saturday {
    pub closed: OptionWrapper<bool>,
    pub open: OptionWrapper<i64>,
    pub close: OptionWrapper<i64>,
}

// [ SERVICES ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Service {
    pub id: OptionWrapper<String>,
    pub name: OptionWrapper<String>,
    pub alias: OptionWrapper<String>,
    pub building_id: OptionWrapper<String>,
    pub description: OptionWrapper<String>,
    pub campus: OptionWrapper<String>,
    pub address: OptionWrapper<String>,
    pub image: OptionWrapper<String>,
    pub coordinates: Coordinates,
    pub tags: OptionWrapper<String>,
    pub attributes: Vec<String>,
    pub last_updated: OptionWrapper<String>,
}

// [ BUILDINGS ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Building {
    pub id: OptionWrapper<String>,
    pub code: OptionWrapper<String>,
    pub tags: OptionWrapper<String>,
    pub name: OptionWrapper<String>,
    pub short_name: OptionWrapper<String>,
    pub address: BuildingAddress,
    pub coordinates: Coordinates,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct BuildingAddress {
    pub street: OptionWrapper<String>,
    pub city: OptionWrapper<String>,
    pub province: OptionWrapper<String>,
    pub country: OptionWrapper<String>,
    pub postal: OptionWrapper<String>,
}

// [ PARKING ]

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Parking {
    pub id: OptionWrapper<String>,
    pub name: OptionWrapper<String>,
    pub alias: OptionWrapper<String>,
    pub building_id: OptionWrapper<String>,
    pub description: OptionWrapper<String>,
    pub campus: OptionWrapper<String>,
    pub address: OptionWrapper<String>,
    pub coordinates: Coordinates,
    pub last_updated: OptionWrapper<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Coordinates {
    pub latitude: OptionWrapper<f64>,
    pub longitude: OptionWrapper<f64>,
}