More functionality

This commit is contained in:
Adam Blažek 2020-08-21 12:27:36 +02:00
parent d810c8a32e
commit 9d688f5303
4 changed files with 122 additions and 23 deletions

View File

@ -1,22 +1,22 @@
import httpcore, httpclient, json, strformat, times, uri
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
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
const
iso8601 = initTimeFormat("yyyy-MM-dd'T'HH:mm:sszzz")
@ -33,6 +33,18 @@ proc newBakalari*(website: Uri, username: string, password: string): Bakalari =
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}")
body = response.body
root = body.parseJson
result.accessToken = root{"access_token"}.getStr
result.refreshToken = root{"refresh_token"}.getStr
func accessToken*(bakalari: Bakalari): string =
bakalari.accessToken

92
dva.nim
View File

@ -1,13 +1,18 @@
import json, logging, os, strformat
import json, logging, os, strformat, times, uri
import bakalari, users
when not defined(release):
let consoleLogger = newConsoleLogger()
consoleLogger.addHandler
let
const
iso8601 = initTimeFormat("yyyy-MM-dd'T'HH:mm:sszzz")
let
configDir = getConfigDir() / "dva"
userConfigDir = configDir / "userconfig"
userCredentialsDir = configDir / "usercredentials"
userDataDir = configDir / "userdata"
iterator usersFromUserConfigDir*(userConfigDir: string): User =
if not existsDir(userConfigDir):
@ -18,6 +23,7 @@ iterator usersFromUserConfigDir*(userConfigDir: string): User =
info &"Loading configuration of user {userName}"
let userConfigNode = userConfigFile.readFile.parseJson
var userConfig: UserConfig
userConfig.email = userConfigNode{"email"}.getStr
for serviceNode in userConfigNode{"services"}:
let kindStr = serviceNode{"kind"}.getStr
case kindStr
@ -29,15 +35,87 @@ iterator usersFromUserConfigDir*(userConfigDir: string): User =
userConfig.services.add(Service(kind: srvBakalariDailyTimetable))
else:
warn &"Unknown service kind: \"{kindStr}\""
yield User(name: userName, config: userConfig)
yield User(name: userName, config: userConfig, data: UserData(lastServeTime: 0.fromUnix.utc))
proc serveUser*(user: User) =
proc loadCredentials(user: User, userCredentialsDir: string) =
info &"Loading credentials of user {user.name}"
let userCredentialsFile = userCredentialsDir / user.name.addFileExt("json")
if existsFile(userCredentialsFile):
let userCredentialsNode = userCredentialsFile.readFile.parseJson
let bakalariNode = userCredentialsNode{"bakalari"}
block bakalari:
if bakalariNode != nil:
if "website" notin bakalariNode or "refresh_token" notin bakalariNode:
error "Bakaláři credentials don't include website and refresh token"
break bakalari
user.bakalari = newBakalari(
bakalariNode{"website"}.getStr.parseUri,
bakalariNode{"refresh_token"}.getStr,
)
proc storeCredentials(user: User, userCredentialsDir: string) =
info &"Storing credentials of user {user.name}"
let userCredentialsFile = userCredentialsDir / user.name.addFileExt("json")
let userCredentialsNode = newJObject()
block bakalari:
if user.bakalari != nil:
userCredentialsNode{"bakalari"} = %*{
"website": $user.bakalari.website,
"refresh_token": user.bakalari.refreshToken,
}
userCredentialsFile.writeFile userCredentialsNode.pretty
proc loadData(user: User, userDataDir: string) =
info &"Loading data of user {user.name}"
let userDataFile = userDataDir / user.name.addFileExt("json")
if existsFile(userDataFile):
let userDataNode = userDataFile.readFile.parseJson
user.data.lastServeTime = userDataNode{"last_serve_time"}.getStr.parse(iso8601)
proc storeData(user: User, userDataDir: string) =
info &"Storing data of user {user.name}"
let userDataFile = userDataDir / user.name.addFileExt("json")
let userDataNode = %*{
"last_serve_time": user.data.lastServeTime.format(iso8601)
}
userDataFile.writeFile userDataNode.pretty
proc serve*(user: User, userCredentialsDir: string, userDataDir: string) =
user.loadCredentials(userCredentialsDir)
user.loadData(userDataDir)
info &"Serving user {user.name}"
discard
let serveTime = now()
for service in user.config.services:
case service.kind
of srvBakalariMessageForwarding:
if user.bakalari == nil:
error "Bakaláři message forwarding service is enabled, but user is not logged in to Bakaláři"
continue
for message in user.bakalari.messages:
if message.sentTime >= user.data.lastServeTime:
debug "Sending a message"
else: discard
user.data.lastServeTime = serveTime
user.storeData(userDataDir)
when isMainModule:
if "--login-bakalari" in commandLineParams():
stdout.write "User: "
let userName = stdin.readLine
for user in usersFromUserConfigDir(userConfigDir):
if user.name == userName:
user.loadCredentials(userCredentialsDir)
stdout.write "Bakalari website: "
let bakalariWebsite = stdin.readLine.parseUri
stdout.write "Bakalari username: "
let bakalariUsername = stdin.readLine
stdout.write "Bakalari password: "
let bakalariPassword = stdin.readLine
user.bakalari = newBakalari(bakalariWebsite, bakalariUsername, bakalariPassword)
user.storeCredentials(userCredentialsDir)
break
for user in usersFromUserConfigDir(userConfigDir):
try:
serveUser user
user.serve(userCredentialsDir, userDataDir)
except:
error &"An exception was raised while serving user:\n {getCurrentExceptionMsg()}"
error &"An exception was raised while processing user:\n {getCurrentExceptionMsg()}\n{getCurrentException().getStackTrace}"

1
dva.nims Normal file
View File

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

View File

@ -1,3 +1,6 @@
import times
import bakalari
type
ServiceKind* = enum
srvBakalariMessageForwarding
@ -12,7 +15,12 @@ type
of srvBakalariDailyTimetable:
discard
UserConfig* = object
email*: string
services*: seq[Service]
UserData* = object
lastServeTime*: DateTime
User* = ref object
name*: string
config*: UserConfig
data*: UserData
bakalari*: Bakalari