Merge branch 'main' of https://github.com/Jannover5000r/Untis-Logger
This commit is contained in:
commit
70b2961cee
7 changed files with 311 additions and 143 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ login.json
|
|||
timetable*.json
|
||||
timetableFilled*.json
|
||||
accounts.json
|
||||
login*.json
|
||||
|
|
|
|||
106
Bot/Timetable.go
106
Bot/Timetable.go
|
|
@ -88,67 +88,73 @@ func ReadLoginResultFromFile(path string) (Loginresult, error) {
|
|||
return result, err
|
||||
}
|
||||
|
||||
func Timetable(cookies []*http.Cookie) {
|
||||
loginResult, err := ReadLoginResultFromFile("login.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
func Timetable(cookies []*http.Cookie, userID string) {
|
||||
loginFile := "login.json"
|
||||
if userID != "" {
|
||||
loginFile = "login_" + userID + ".json"
|
||||
}
|
||||
|
||||
loginResult, err := ReadLoginResultFromFile(loginFile)
|
||||
if err != nil {
|
||||
log.Printf("Could not read login result for user %s: %v", userID, err)
|
||||
return
|
||||
}
|
||||
|
||||
today := time.Now().Format("20060102")
|
||||
g := getTimetable{"2023-05-06 15:44:22.215292", "getTimetable", params{today, today, loginResult.PersonID, loginResult.PersonType}, "2.0"}
|
||||
TimetablesJson, err := json.Marshal(g)
|
||||
timetablesJson, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
log.Fatalf("Error marshaling login data: %v", err)
|
||||
log.Printf("Error marshaling timetable request: %v", err)
|
||||
return
|
||||
}
|
||||
timetable := bytes.NewReader(TimetablesJson)
|
||||
timetable := bytes.NewReader(timetablesJson)
|
||||
|
||||
prompt, err := http.NewRequest("GET", Url, timetable)
|
||||
req, err := http.NewRequest("GET", Url, timetable)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creatingrequest: %v", err)
|
||||
log.Printf("Error creating timetable request: %v", err)
|
||||
return
|
||||
}
|
||||
//log.Println("prompt without extra header or cookie ", prompt)
|
||||
//log.Println("Cookie: ", cookies)
|
||||
|
||||
prompt.Header.Set("Content-Type", "application/json")
|
||||
prompt.Header.Set("User-Agent", "Webuntis Test")
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
for _, cookie := range cookies {
|
||||
//if cookie.Name == "JSESSIONID" {
|
||||
prompt.AddCookie(cookie)
|
||||
//log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value)
|
||||
//}
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
//log.Println("Request JSON:", string(TeachersJson))
|
||||
out, err := http.DefaultClient.Do(prompt)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Error during request: %v", err)
|
||||
log.Printf("Error fetching timetable: %v", err)
|
||||
return
|
||||
}
|
||||
defer out.Body.Close()
|
||||
//log.Println(out.Status)
|
||||
response, err := io.ReadAll(out.Body)
|
||||
defer resp.Body.Close()
|
||||
|
||||
response, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Error reading response body: %v", err)
|
||||
log.Printf("Error reading timetable response: %v", err)
|
||||
return
|
||||
}
|
||||
//responseString := string(response)
|
||||
//log.Println("Repsonse ", responseString)
|
||||
|
||||
var Response TimetableResponse
|
||||
err = json.Unmarshal(response, &Response)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshaling response: %v", err)
|
||||
if err := json.Unmarshal(response, &Response); err != nil {
|
||||
log.Printf("Error unmarshaling timetable response: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(Response.Result, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Printf("Error marshaling timetable result: %v", err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile("timetable.json", data, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
timetableFile := "timetable.json"
|
||||
if userID != "" {
|
||||
timetableFile = "timetable_" + userID + ".json"
|
||||
}
|
||||
log.Println("Updated Timetable")
|
||||
setTimetable()
|
||||
if err := os.WriteFile(timetableFile, data, 0644); err != nil {
|
||||
log.Printf("Error writing timetable file: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Updated timetable for user %s", userID)
|
||||
setTimetable(userID)
|
||||
}
|
||||
|
||||
func LoadIDMap(path string) (map[int]string, error) {
|
||||
|
|
@ -189,14 +195,18 @@ func formatDate(date int) string {
|
|||
day := s[6:8]
|
||||
return fmt.Sprintf("%s-%s-%s", day, month, year)
|
||||
}
|
||||
func setTimetable() {
|
||||
func setTimetable(userID string) {
|
||||
subjects, _ := LoadIDMap("subjects.json")
|
||||
rooms, _ := LoadIDMap("rooms.json")
|
||||
classes, _ := LoadIDMap("classes.json")
|
||||
timetable, _ := LoadTimetable("timetable.json")
|
||||
|
||||
timetableFile := "timetable.json"
|
||||
if userID != "" {
|
||||
timetableFile = "timetable_" + userID + ".json"
|
||||
}
|
||||
timetable, _ := LoadTimetable(timetableFile)
|
||||
|
||||
var namedTimetable []NamedTimetableEntry
|
||||
|
||||
for _, lesson := range timetable {
|
||||
var klNames, suNames, roNames []string
|
||||
for _, kl := range lesson.Kl {
|
||||
|
|
@ -224,11 +234,17 @@ func setTimetable() {
|
|||
|
||||
data, err := json.MarshalIndent(namedTimetable, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Printf("Error marshaling named timetable: %v", err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile("timetableFilled.json", data, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
timetableFilledFile := "timetableFilled.json"
|
||||
if userID != "" {
|
||||
timetableFilledFile = "timetableFilled_" + userID + ".json"
|
||||
}
|
||||
log.Println("Filled Timetable")
|
||||
if err := os.WriteFile(timetableFilledFile, data, 0644); err != nil {
|
||||
log.Printf("Error writing timetableFilled file: %v", err)
|
||||
return
|
||||
}
|
||||
log.Printf("Filled timetable for user %s", userID)
|
||||
}
|
||||
|
|
|
|||
49
Bot/Untis.go
49
Bot/Untis.go
|
|
@ -35,70 +35,59 @@ var Url = "https://thalia.webuntis.com/WebUntis/jsonrpc.do?school=Mons_Tabor"
|
|||
//var Password = os.Getenv("UNTIS_PASSWORD")
|
||||
//var USERS = os.Getenv("UNTIS_USER")
|
||||
|
||||
func Main(user, password string) {
|
||||
func Main(user, password, userID string) {
|
||||
godotenv.Load("../.env")
|
||||
cookies, err := Auth(user, password)
|
||||
cookies, err := Auth(user, password, userID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Printf("Authentication failed for user %s: %v", user, err)
|
||||
return
|
||||
}
|
||||
Rooms(cookies)
|
||||
|
||||
Classes(cookies)
|
||||
|
||||
Subjects(cookies)
|
||||
|
||||
Timetable(cookies)
|
||||
|
||||
//getTeachers sends empty response
|
||||
Timetable(cookies, userID)
|
||||
Teachers(cookies)
|
||||
}
|
||||
|
||||
func Auth(user, password string) ([]*http.Cookie, error) {
|
||||
func Auth(user, password, userID string) ([]*http.Cookie, error) {
|
||||
l := Login{"2023-05-06 15:44:22.215292", "authenticate", Params{user, password, "WebUntis Test"}, "2.0"}
|
||||
loginJSON, err := json.Marshal(l)
|
||||
if err != nil {
|
||||
log.Fatalf("Error marshaling login data: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
login := bytes.NewReader(loginJSON)
|
||||
|
||||
//log.Println("Run")
|
||||
LoginOut, err := http.Post(Url, "application/json", login)
|
||||
if err != nil {
|
||||
log.Printf("Error during authentication: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer LoginOut.Body.Close()
|
||||
|
||||
// Parse cookies from response
|
||||
cookies := LoginOut.Cookies()
|
||||
//log.Println("Received cookies:", cookies)
|
||||
//log.Println("Set-Cookie headers:", LoginOut.Header["Set-Cookie"])
|
||||
//loginRespBody, _ := io.ReadAll(LoginOut.Body)
|
||||
//log.Println("Login response body:", string(loginRespBody))
|
||||
log.Printf("Login successful for user: %s", user)
|
||||
|
||||
log.Println("Login successful")
|
||||
|
||||
//log.Println("Login successful")
|
||||
response, err := io.ReadAll(LoginOut.Body)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading response body: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var Response LoginResponse
|
||||
err = json.Unmarshal(response, &Response)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshaling response: %v", err)
|
||||
if err := json.Unmarshal(response, &Response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(Response.Result, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
err = os.WriteFile("login.json", data, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
loginFile := "login.json"
|
||||
if userID != "" {
|
||||
loginFile = "login_" + userID + ".json"
|
||||
}
|
||||
if err := os.WriteFile(loginFile, data, 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cookies, nil
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,6 +248,35 @@ func Start() {
|
|||
dg.Close()
|
||||
}
|
||||
|
||||
// DecryptedAccount holds user information with a decrypted password.
|
||||
type DecryptedAccount struct {
|
||||
UserID string
|
||||
Username string
|
||||
DecryptedPassword string
|
||||
}
|
||||
|
||||
// LoadAndDecryptAccounts loads all accounts from the JSON file and decrypts their passwords.
|
||||
func LoadAndDecryptAccounts() ([]DecryptedAccount, error) {
|
||||
accounts := loadAllAccounts()
|
||||
decryptedAccounts := make([]DecryptedAccount, 0, len(accounts))
|
||||
|
||||
for _, acc := range accounts {
|
||||
decPwd, err := decrypt(acc.Password)
|
||||
if err != nil {
|
||||
// Log the error but continue with other accounts
|
||||
fmt.Printf("Error decrypting password for user %s: %v\n", acc.UserID, err)
|
||||
continue
|
||||
}
|
||||
decryptedAccounts = append(decryptedAccounts, DecryptedAccount{
|
||||
UserID: acc.UserID,
|
||||
Username: acc.Username,
|
||||
DecryptedPassword: decPwd,
|
||||
})
|
||||
}
|
||||
|
||||
return decryptedAccounts, nil
|
||||
}
|
||||
|
||||
// Expose this for main.go to trigger notifications
|
||||
func NotifyAllUsers() {
|
||||
if DiscordSession != nil {
|
||||
|
|
@ -255,6 +284,77 @@ func NotifyAllUsers() {
|
|||
}
|
||||
}
|
||||
|
||||
// SendDM sends a direct message to a user.
|
||||
func SendDM(userID, message string) {
|
||||
if DiscordSession == nil {
|
||||
fmt.Println("Discord session not initialized, cannot send DM.")
|
||||
return
|
||||
}
|
||||
// Avoid sending messages to the "default" user placeholder
|
||||
if userID == "default" {
|
||||
return
|
||||
}
|
||||
channel, err := DiscordSession.UserChannelCreate(userID)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating DM channel for %s: %v\n", userID, err)
|
||||
return
|
||||
}
|
||||
_, err = DiscordSession.ChannelMessageSend(channel.ID, message)
|
||||
if err != nil {
|
||||
fmt.Printf("Error sending DM to %s: %v\n", userID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete account and associated files for a given userID
|
||||
func deleteAccount(userID string) error {
|
||||
var accounts []Account
|
||||
|
||||
// Load existing accounts
|
||||
data, err := os.ReadFile(accountsFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil // No accounts file means nothing to delete
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
if err := json.Unmarshal(data, &accounts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out the account with matching userID
|
||||
newAccounts := accounts[:0]
|
||||
found := false
|
||||
for _, acc := range accounts {
|
||||
if acc.UserID != userID {
|
||||
newAccounts = append(newAccounts, acc)
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return errors.New("account not found")
|
||||
}
|
||||
|
||||
// Save remaining accounts back to file
|
||||
newData, err := json.MarshalIndent(newAccounts, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(accountsFile, newData, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete associated timetable files
|
||||
os.Remove(getTimetableFile(userID))
|
||||
os.Remove(getTimetableFilledFile(userID))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
// Ignore bot's own messages
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
|
|
@ -279,6 +379,29 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
|
|||
return
|
||||
}
|
||||
|
||||
// Handle "!deleteaccount" and "!removeaccount" commands
|
||||
if m.GuildID != "" && (m.Content == "!deleteaccount" || m.Content == "!removeaccount") {
|
||||
// Delete the command message for privacy
|
||||
_ = s.ChannelMessageDelete(m.ChannelID, m.ID)
|
||||
|
||||
err := deleteAccount(m.Author.ID)
|
||||
if err != nil {
|
||||
// Create DM channel to notify of error
|
||||
channel, err := s.UserChannelCreate(m.Author.ID)
|
||||
if err == nil {
|
||||
s.ChannelMessageSend(channel.ID, "Failed to delete your account: "+err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Notify success via DM
|
||||
channel, err := s.UserChannelCreate(m.Author.ID)
|
||||
if err == nil {
|
||||
s.ChannelMessageSend(channel.ID, "Your account has been successfully deleted.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle DMs for the two-step process
|
||||
if m.GuildID == "" {
|
||||
stateMutex.Lock()
|
||||
|
|
|
|||
8
go.mod
8
go.mod
|
|
@ -1,6 +1,6 @@
|
|||
module untislogger
|
||||
|
||||
go 1.24
|
||||
go 1.25.2
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/discordgo v0.29.0
|
||||
|
|
@ -8,7 +8,7 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
)
|
||||
|
|
|
|||
9
go.sum
9
go.sum
|
|
@ -1,14 +1,17 @@
|
|||
github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno=
|
||||
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
|||
156
main.go
156
main.go
|
|
@ -80,45 +80,74 @@ func isScheduledTime(now time.Time) bool {
|
|||
return false
|
||||
}
|
||||
func scheduleTimetableUpdate() {
|
||||
var prevData []byte
|
||||
//declare user and pass
|
||||
godotenv.Load(".env")
|
||||
var password = os.Getenv("UNTIS_PASSWORD")
|
||||
var user = os.Getenv("UNTIS_USER")
|
||||
Untis.Main(user, password)
|
||||
// Initial read of the file
|
||||
data, err := os.ReadFile("timetableFilled.json")
|
||||
if err == nil {
|
||||
prevData = data
|
||||
prevData := make(map[string][]byte)
|
||||
|
||||
// Function to update all users
|
||||
updateAllUsers := func() {
|
||||
// Load all registered users
|
||||
accounts, err := BotStart.LoadAndDecryptAccounts()
|
||||
if err != nil {
|
||||
log.Printf("Error loading accounts: %v", err)
|
||||
}
|
||||
|
||||
// Ticker for checking timetable changes every hour
|
||||
hourTicker := time.NewTicker(1 * time.Minute)
|
||||
// Add the default user from .env
|
||||
defaultUser := os.Getenv("UNTIS_USER")
|
||||
defaultPassword := os.Getenv("UNTIS_PASSWORD")
|
||||
if defaultUser != "" && defaultPassword != "" {
|
||||
accounts = append(accounts, BotStart.DecryptedAccount{
|
||||
UserID: "default",
|
||||
Username: defaultUser,
|
||||
DecryptedPassword: defaultPassword,
|
||||
})
|
||||
}
|
||||
|
||||
// Process each user
|
||||
for _, acc := range accounts {
|
||||
// Fetch the latest timetable
|
||||
Untis.Main(acc.Username, acc.DecryptedPassword, acc.UserID)
|
||||
|
||||
// Check for changes
|
||||
timetableFile := fmt.Sprintf("timetableFilled_%s.json", acc.UserID)
|
||||
if acc.UserID == "default" {
|
||||
timetableFile = "timetableFilled.json"
|
||||
}
|
||||
data, err := os.ReadFile(timetableFile)
|
||||
if err != nil {
|
||||
log.Printf("Error reading timetable for user %s: %v", acc.Username, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if prev, ok := prevData[acc.UserID]; ok && !bytes.Equal(data, prev) {
|
||||
log.Printf("Timetable has changed for user %s.", acc.Username)
|
||||
BotStart.SendDM(acc.UserID, "Your timetable has changed!")
|
||||
}
|
||||
prevData[acc.UserID] = data
|
||||
}
|
||||
}
|
||||
|
||||
// Initial update
|
||||
updateAllUsers()
|
||||
|
||||
// Ticker for periodic updates
|
||||
hourTicker := time.NewTicker(1 * time.Minute) // For testing, 1 minute. Change to 1 * time.Hour for production.
|
||||
go func() {
|
||||
for range hourTicker.C {
|
||||
Untis.Main(user, password)
|
||||
data, err := os.ReadFile("timetableFilled.json")
|
||||
if err != nil {
|
||||
log.Printf("Error reading timetable: %v", err)
|
||||
} else if !bytes.Equal(data, prevData) {
|
||||
log.Println("Timetable file has changed.")
|
||||
sendUpdateDiscordWebhook()
|
||||
prevData = data
|
||||
}
|
||||
// Trigger bot notifications for all users
|
||||
BotStart.NotifyAllUsers()
|
||||
updateAllUsers()
|
||||
}
|
||||
}()
|
||||
|
||||
// Ticker for checking scheduled times every minute
|
||||
// Ticker for scheduled lesson notifications
|
||||
startMinuteTicker(func() {
|
||||
now := time.Now()
|
||||
if isScheduledTime(now) {
|
||||
log.Println("Scheduled time reached, updating and running Run()")
|
||||
Untis.Main(user, password)
|
||||
log.Println("Updated now running Run()")
|
||||
Run()
|
||||
log.Println("Finished running Run")
|
||||
log.Println("Scheduled time reached, running notifications...")
|
||||
accounts, _ := BotStart.LoadAndDecryptAccounts()
|
||||
// Also notify the default user
|
||||
accounts = append(accounts, BotStart.DecryptedAccount{UserID: "default"})
|
||||
for _, acc := range accounts {
|
||||
Run(acc.UserID)
|
||||
}
|
||||
log.Println("Finished running notifications.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -136,42 +165,49 @@ func startMinuteTicker(f func()) {
|
|||
}()
|
||||
}
|
||||
|
||||
/*
|
||||
#Main Run Function
|
||||
*/
|
||||
func Run() {
|
||||
log.Println("Sending next Lesson")
|
||||
codeByStartTime, err := MapTimeToCode("timetableFilled.json")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
func Run(userID string) {
|
||||
timetableFile := "timetableFilled.json"
|
||||
if userID != "default" {
|
||||
timetableFile = fmt.Sprintf("timetableFilled_%s.json", userID)
|
||||
}
|
||||
log.Printf("Sending next lesson for user %s", userID)
|
||||
|
||||
// Check if the timetable file exists
|
||||
if _, err := os.Stat(timetableFile); os.IsNotExist(err) {
|
||||
log.Printf("Timetable file %s not found for user %s.", timetableFile, userID)
|
||||
return
|
||||
}
|
||||
|
||||
roomByStartTime, err := MapTimeToRoom("timetableFilled.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
subjectByStartTime, err := MapTimeToSubject("timetableFilled.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
codeByStartTime, _ := MapTimeToCode(timetableFile)
|
||||
roomByStartTime, _ := MapTimeToRoom(timetableFile)
|
||||
subjectByStartTime, _ := MapTimeToSubject(timetableFile)
|
||||
|
||||
now := time.Now().Format("15:04")
|
||||
nextTime, room, found := NextRoomForTime(roomByStartTime, now)
|
||||
if found {
|
||||
log.Println("found Room")
|
||||
Subject, found := NextSubjectForTime(subjectByStartTime, now)
|
||||
if found {
|
||||
log.Println("Found Subject")
|
||||
Status, found := NextCodeForTime(codeByStartTime, now)
|
||||
if found {
|
||||
log.Println("Found Status")
|
||||
fmt.Printf("Next time: %s, Room: %s\n", nextTime, room)
|
||||
sendDiscordWebhook(Subject, room, nextTime, Status)
|
||||
} else {
|
||||
sendDiscordWebhook(Subject, room, nextTime, "")
|
||||
}
|
||||
}
|
||||
nextTime, room, foundRoom := NextRoomForTime(roomByStartTime, now)
|
||||
if !foundRoom {
|
||||
return // No upcoming lessons
|
||||
}
|
||||
|
||||
subject, foundSubject := NextSubjectForTime(subjectByStartTime, now)
|
||||
if !foundSubject {
|
||||
return // Should not happen if room was found
|
||||
}
|
||||
|
||||
status, _ := NextCodeForTime(codeByStartTime, now)
|
||||
|
||||
var message string
|
||||
if status != "" {
|
||||
message = fmt.Sprintf("Next lesson: **%s** in room **%s** at **%s**. Status: **%s**", subject, room, nextTime, status)
|
||||
} else {
|
||||
message = fmt.Sprintf("Next lesson: **%s** in room **%s** at **%s**.", subject, room, nextTime)
|
||||
}
|
||||
|
||||
if userID == "default" {
|
||||
// The default user still sends to the webhook
|
||||
sendDiscordWebhook(subject, room, nextTime, status)
|
||||
} else {
|
||||
BotStart.SendDM(userID, message)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue