Semi-working signin and timetable

This commit is contained in:
xigoi 2020-09-04 11:32:45 +02:00
commit 64745479c6
4 changed files with 239 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*
!*.*
!/**/
*.swp
*.un~
.netrwhist
*.json

169
bakalari.nim Normal file
View File

@ -0,0 +1,169 @@
import httpcore, httpclient, json, strformat, tables, times, uri
import elvis
type
Bakalari* = ref object
website*: Uri
accessToken*: string
refreshToken*: string
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
Day* = object
lessons*: seq[Lesson]
dayOfWeek*: int
date*: DateTime
Timetable* = object
days*: seq[Day]
const
iso8601 = initTimeFormat("yyyy-MM-dd'T'HH:mm:sszzz")
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
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)
)
proc timetable*(bakalari: Bakalari, permanent: bool): Timetable =
let root = bakalari.getEndpoint(permanent ? "timetable/permanent" ! "timetable/actual")
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
lesson.hour = hours[lessonNode{"HourId"}.getInt]
lesson.subject = subjects[lessonNode{"SubjectId"}.getStr]
lesson.teacher = teachers[lessonNode{"TeacherId"}.getStr]
lesson.room = rooms[lessonNode{"RoomId"}.getStr]
day.lessons.add lesson
day.dayOfWeek = dayNode{"DayOfWeek"}.getInt
day.date = dayNode{"Date"}.getStr.parse(iso8601)
result.days.add day

62
bk.nim Normal file
View File

@ -0,0 +1,62 @@
import json, os, times, unicode, uri
import cligen
import bakalari
type
Config = object
website: string
username: string
refreshToken: string
const
defaultConfigFile = getConfigDir() / "bk.json"
proc loadConfig(configFile = defaultConfigFile): Config =
defaultConfigFile.readFile.parseJson.to(Config)
proc saveConfig(configFile = defaultConfigFile, config: Config) =
configFile.writeFile((%*config).pretty)
proc signin(
website: string,
username: string,
password: string,
configFile = defaultConfigFile,
) =
let
bakalari = newBakalari(website.parseUri, username, password)
config = Config(
website: website,
username: username,
refreshToken: bakalari.refreshToken,
)
configFile.saveConfig(config)
proc rozvrh(
configFile = defaultConfigFile,
date = "",
oneDay = false,
permanent = false,
) =
var config = configFile.loadConfig
let bakalari = newBakalari(config.website.parseUri, config.refreshToken)
config.refreshToken = bakalari.refreshToken
configFile.saveConfig(config)
let timetable = bakalari.timetable(permanent)
for day in timetable.days:
stdout.writeLine day.date.format("yyyyMMdd")
for lesson in day.lessons:
var line = ""
line &= lesson.hour.number
line &= ". "
line &= lesson.hour.beginTime.align(5, '0'.Rune)
line &= "-"
line &= lesson.hour.endTime.align(5, '0'.Rune)
line &= " "
line &= lesson.subject.abbrev.align(4)
line &= " "
line &= lesson.teacher.abbrev.align(4)
line &= " "
line &= lesson.room.abbrev.align(4)
stdout.writeLine line
dispatchMulti([signin], [rozvrh])

1
bk.nims Normal file
View File

@ -0,0 +1 @@
--define:ssl