2020-09-11 19:05:32 +02:00
|
|
|
import httpcore, httpclient, json, options, strformat, tables, times, uri
|
2020-09-27 15:51:44 +02:00
|
|
|
import elvis, zero_functional
|
2020-09-04 11:32:45 +02:00
|
|
|
|
|
|
|
type
|
|
|
|
Bakalari* = ref object
|
|
|
|
website*: Uri
|
|
|
|
accessToken*: string
|
|
|
|
refreshToken*: string
|
2020-09-27 15:51:44 +02:00
|
|
|
Grade* = object
|
|
|
|
text*: string
|
|
|
|
weight*: int
|
|
|
|
caption*: string
|
|
|
|
addTime*: DateTime
|
|
|
|
editTime*: DateTime
|
|
|
|
GradedSubject* = object
|
|
|
|
name*: string
|
|
|
|
abbrev*: string
|
|
|
|
grades*: seq[Grade]
|
2020-09-04 11:32:45 +02:00
|
|
|
Homework* = object
|
|
|
|
id*: string
|
|
|
|
subject*: string
|
|
|
|
teacher*: string
|
|
|
|
content*: string
|
|
|
|
startTime*: DateTime
|
|
|
|
endTime*: DateTime
|
|
|
|
Message* = object
|
|
|
|
title*: string
|
|
|
|
sender*: string
|
|
|
|
text*: string
|
|
|
|
sentTime*: DateTime
|
|
|
|
Hour* = ref object
|
|
|
|
number*: string
|
|
|
|
beginTime*: string
|
|
|
|
endTime*: string
|
|
|
|
Room* = ref object
|
|
|
|
name*: string
|
|
|
|
abbrev*: string
|
|
|
|
Subject* = ref object
|
|
|
|
name*: string
|
|
|
|
abbrev*: string
|
|
|
|
Teacher* = ref object
|
|
|
|
name*: string
|
|
|
|
abbrev*: string
|
|
|
|
Lesson* = object
|
|
|
|
hour*: Hour
|
|
|
|
room*: Room
|
|
|
|
subject*: Subject
|
|
|
|
teacher*: Teacher
|
2020-09-11 19:05:32 +02:00
|
|
|
change*: Option[string]
|
2020-09-04 11:32:45 +02:00
|
|
|
Day* = object
|
|
|
|
lessons*: seq[Lesson]
|
|
|
|
dayOfWeek*: int
|
|
|
|
date*: DateTime
|
|
|
|
Timetable* = object
|
|
|
|
days*: seq[Day]
|
|
|
|
|
|
|
|
const
|
|
|
|
iso8601 = initTimeFormat("yyyy-MM-dd'T'HH:mm:sszzz")
|
|
|
|
|
2020-09-04 20:43:05 +02:00
|
|
|
let
|
|
|
|
invalidHour = Hour(number: "-", beginTime: "--:--", endTime: "--:--")
|
|
|
|
invalidRoom = Room(name: "---", abbrev: "---")
|
|
|
|
invalidSubject = Subject(name: "---", abbrev: "---")
|
|
|
|
invalidTeacher = Teacher(name: "---", abbrev: "---")
|
|
|
|
|
2020-09-04 11:32:45 +02:00
|
|
|
proc newBakalari*(website: Uri, username: string, password: string): Bakalari =
|
|
|
|
new result
|
|
|
|
result.website = website
|
|
|
|
let
|
|
|
|
api = website / "api/login"
|
|
|
|
client = newHttpClient()
|
|
|
|
response = client.post($api, body = &"client_id=ANDR&grant_type=password&username={username}&password={password}")
|
|
|
|
root = response.body.parseJson
|
|
|
|
result.accessToken = root{"access_token"}.getStr
|
|
|
|
result.refreshToken = root{"refresh_token"}.getStr
|
|
|
|
|
|
|
|
proc newBakalari*(website: Uri, refreshToken: string): Bakalari =
|
|
|
|
new result
|
|
|
|
result.website = website
|
|
|
|
let
|
|
|
|
api = website / "api/login"
|
|
|
|
client = newHttpClient()
|
|
|
|
response = client.post($api, body = &"client_id=ANDR&grant_type=refresh_token&refresh_token={refreshToken}")
|
|
|
|
root = response.body.parseJson
|
|
|
|
result.accessToken = root{"access_token"}.getStr
|
|
|
|
result.refreshToken = root{"refresh_token"}.getStr
|
|
|
|
|
|
|
|
func accessToken*(bakalari: Bakalari): string =
|
|
|
|
bakalari.accessToken
|
|
|
|
|
|
|
|
func refreshToken*(bakalari: Bakalari): string =
|
|
|
|
bakalari.refreshToken
|
|
|
|
|
|
|
|
proc renewTokens(bakalari: Bakalari) =
|
|
|
|
let
|
|
|
|
api = bakalari.website / "api/login"
|
|
|
|
client = newHttpClient()
|
|
|
|
response = client.post($api, body = &"client_id=ANDR&grant_type=refresh_token&refresh_token={bakalari.refreshToken}")
|
|
|
|
body = response.body
|
|
|
|
root = body.parseJson
|
|
|
|
bakalari.accessToken = root{"access_token"}.getStr
|
|
|
|
bakalari.refreshToken = root{"refresh_token"}.getStr
|
|
|
|
|
|
|
|
proc getEndpoint*(bakalari: Bakalari, endpoint: string): JsonNode =
|
|
|
|
let
|
|
|
|
api = bakalari.website / "api/3" / endpoint
|
|
|
|
client = newHttpClient(headers = newHttpHeaders {
|
|
|
|
"Authorization": "Bearer " & bakalari.accessToken,
|
|
|
|
})
|
|
|
|
response = client.get($api)
|
|
|
|
body = response.body
|
|
|
|
bakalari.renewTokens
|
|
|
|
result = body.parseJson
|
|
|
|
|
|
|
|
proc postEndpoint*(bakalari: Bakalari, endpoint: string): JsonNode =
|
|
|
|
let
|
|
|
|
api = bakalari.website / "api/3" / endpoint
|
|
|
|
client = newHttpClient(headers = newHttpHeaders {
|
|
|
|
"Authorization": "Bearer " & bakalari.accessToken,
|
|
|
|
})
|
|
|
|
response = client.post($api)
|
|
|
|
body = response.body
|
|
|
|
bakalari.renewTokens
|
|
|
|
result = body.parseJson
|
|
|
|
|
2020-09-27 15:51:44 +02:00
|
|
|
iterator grades*(bakalari: Bakalari): GradedSubject =
|
|
|
|
let root = bakalari.getEndpoint("marks")
|
|
|
|
for subjectNode in root{"Subjects"}:
|
|
|
|
yield GradedSubject(
|
|
|
|
name: subjectNode{"Subject"}{"Name"}.getStr,
|
|
|
|
abbrev: subjectNode{"Subject"}{"Abbrev"}.getStr,
|
|
|
|
grades: subjectNode{"Marks"} --> (gradeNode) --> map(
|
|
|
|
Grade(
|
|
|
|
text: gradeNode{"MarkText"}.getStr,
|
|
|
|
weight: gradeNode{"Weight"}.getInt,
|
|
|
|
caption: gradeNode{"Caption"}.getStr,
|
|
|
|
addTime: gradeNode{"MarkDate"}.getStr.parse(iso8601),
|
|
|
|
editTime: gradeNode{"EditDate"}.getStr.parse(iso8601),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2020-09-04 11:32:45 +02:00
|
|
|
iterator homework*(bakalari: Bakalari): Homework =
|
|
|
|
let root = bakalari.getEndpoint("homeworks")
|
|
|
|
for node in root{"Homeworks"}.getElems:
|
|
|
|
yield Homework(
|
|
|
|
id: node{"ID"}.getStr,
|
|
|
|
subject: node{"Subject"}{"Name"}.getStr,
|
|
|
|
teacher: node{"Teacher"}.getStr,
|
|
|
|
content: node{"Content"}.getStr,
|
|
|
|
startTime: node{"DateStart"}.getStr.parse(iso8601),
|
|
|
|
endTime: node{"DateEnd"}.getStr.parse(iso8601),
|
|
|
|
)
|
|
|
|
|
|
|
|
iterator messages*(bakalari: Bakalari): Message =
|
|
|
|
let root = bakalari.postEndpoint("komens/messages/received")
|
|
|
|
for node in root{"Messages"}.getElems:
|
|
|
|
yield Message(
|
|
|
|
title: node{"Title"}.getStr,
|
|
|
|
sender: node{"Sender"}{"Name"}.getStr,
|
|
|
|
text: node{"Text"}.getStr,
|
|
|
|
sentTime: node{"SentDate"}.getStr.parse(iso8601)
|
|
|
|
)
|
|
|
|
|
2020-09-11 19:38:55 +02:00
|
|
|
proc timetable*(bakalari: Bakalari, permanent: bool, date: Option[DateTime] = none(DateTime)): Timetable =
|
|
|
|
var endpoint = permanent ? "timetable/permanent" ! "timetable/actual"
|
|
|
|
if date.isSome:
|
|
|
|
endpoint &= "?date=" & date.unsafeGet.format("yyyy-MM-dd")
|
|
|
|
let root = bakalari.getEndpoint(endpoint)
|
2020-09-04 11:32:45 +02:00
|
|
|
var hours: Table[int, Hour]
|
|
|
|
for hourNode in root{"Hours"}:
|
|
|
|
hours[hourNode{"Id"}.getInt] = Hour(
|
|
|
|
number: hourNode{"Caption"}.getStr,
|
|
|
|
beginTime: hourNode{"BeginTime"}.getStr,
|
|
|
|
endTime: hourNode{"EndTime"}.getStr,
|
|
|
|
)
|
|
|
|
var rooms: Table[string, Room]
|
|
|
|
for roomNode in root{"Rooms"}:
|
|
|
|
rooms[roomNode{"Id"}.getStr] = Room(
|
|
|
|
name: roomNode{"Name"}.getStr,
|
|
|
|
abbrev: roomNode{"Abbrev"}.getStr,
|
|
|
|
)
|
|
|
|
var subjects: Table[string, Subject]
|
|
|
|
for subjectNode in root{"Subjects"}:
|
|
|
|
subjects[subjectNode{"Id"}.getStr] = Subject(
|
|
|
|
name: subjectNode{"Name"}.getStr,
|
|
|
|
abbrev: subjectNode{"Abbrev"}.getStr,
|
|
|
|
)
|
|
|
|
var teachers: Table[string, Teacher]
|
|
|
|
for teacherNode in root{"Teachers"}:
|
|
|
|
teachers[teacherNode{"Id"}.getStr] = Teacher(
|
|
|
|
name: teacherNode{"Name"}.getStr,
|
|
|
|
abbrev: teacherNode{"Abbrev"}.getStr,
|
|
|
|
)
|
|
|
|
for dayNode in root{"Days"}:
|
|
|
|
var day: Day
|
|
|
|
for lessonNode in dayNode{"Atoms"}:
|
|
|
|
var lesson: Lesson
|
2020-09-04 20:43:05 +02:00
|
|
|
lesson.hour = hours.getOrDefault(lessonNode{"HourId"}.getInt, invalidHour)
|
|
|
|
lesson.room = rooms.getOrDefault(lessonNode{"RoomId"}.getStr, invalidRoom)
|
|
|
|
lesson.subject = subjects.getOrDefault(lessonNode{"SubjectId"}.getStr, invalidSubject)
|
|
|
|
lesson.teacher = teachers.getOrDefault(lessonNode{"TeacherId"}.getStr, invalidTeacher)
|
2020-09-11 19:05:32 +02:00
|
|
|
if lessonNode{"Change"}.kind != JNull:
|
|
|
|
lesson.change = some(lessonNode{"Change"}{"Description"}.getStr)
|
2020-09-04 11:32:45 +02:00
|
|
|
day.lessons.add lesson
|
|
|
|
day.dayOfWeek = dayNode{"DayOfWeek"}.getInt
|
|
|
|
day.date = dayNode{"Date"}.getStr.parse(iso8601)
|
|
|
|
result.days.add day
|