made a lot of changes for the workflow of the bot

- Timezone handling got updated
- Logs have been deleted to avoid duplicates and clean up the terminal
- removed unused code
- fixed an issue where the updating time threw errors
- improvements to the updateting of timetable data, only using a single api call now
- improved init to intitialize all needed files (classrooms, subjects etc.)
This commit is contained in:
Jannover5000r 2026-08-25 22:53:59 +02:00
parent ae5b1f7b28
commit 1d57e8a867
8 changed files with 72 additions and 96 deletions

View file

@ -42,33 +42,33 @@ func Classes(cookies []*http.Cookie) {
log.Fatalf("Error creatingrequest: %v", err) log.Fatalf("Error creatingrequest: %v", err)
return return
} }
//log.Println("prompt without extra header or cookie ", prompt) // log.Println("prompt without extra header or cookie ", prompt)
//log.Println("Cookie: ", cookies) // log.Println("Cookie: ", cookies)
prompt.Header.Set("Content-Type", "application/json") prompt.Header.Set("Content-Type", "application/json")
prompt.Header.Set("User-Agent", "Webuntis Test") prompt.Header.Set("User-Agent", "Webuntis Test")
for _, cookie := range cookies { for _, cookie := range cookies {
//if cookie.Name == "JSESSIONID" { // if cookie.Name == "JSESSIONID" {
prompt.AddCookie(cookie) prompt.AddCookie(cookie)
//log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value) //log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value)
//} //}
} }
//log.Println("Request JSON:", string(ClassesJson)) // log.Println("Request JSON:", string(ClassesJson))
out, err := http.DefaultClient.Do(prompt) out, err := http.DefaultClient.Do(prompt)
if err != nil { if err != nil {
log.Printf("Error during request: %v", err) log.Printf("Error during request: %v", err)
return return
} }
defer out.Body.Close() defer out.Body.Close()
//log.Println(out.Status) // log.Println(out.Status)
response, err := io.ReadAll(out.Body) response, err := io.ReadAll(out.Body)
if err != nil { if err != nil {
log.Printf("Error reading response body: %v", err) log.Printf("Error reading response body: %v", err)
return return
} }
//responseString := string(response) // responseString := string(response)
//log.Println("Repsonse ", responseString) // log.Println("Repsonse ", responseString)
var Response ClassesResponse var Response ClassesResponse
err = json.Unmarshal(response, &Response) err = json.Unmarshal(response, &Response)
if err != nil { if err != nil {
@ -78,9 +78,9 @@ func Classes(cookies []*http.Cookie) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = os.WriteFile("classes.json", data, 0644) err = os.WriteFile("classes.json", data, 0o644)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Println("Updated Classes") // log.Println("Updated Classes")//dont need log anymore
} }

View file

@ -31,7 +31,7 @@ type Room struct {
} }
func Rooms(cookies []*http.Cookie) { func Rooms(cookies []*http.Cookie) {
//log.Println("Abrufen der Stunden") // log.Println("Abrufen der Stunden")
g := getRooms{"2023-05-06 15:44:22.215292", "getRooms", map[string]interface{}{}, "2.0"} g := getRooms{"2023-05-06 15:44:22.215292", "getRooms", map[string]interface{}{}, "2.0"}
roomsJson, err := json.Marshal(g) roomsJson, err := json.Marshal(g)
if err != nil { if err != nil {
@ -45,33 +45,33 @@ func Rooms(cookies []*http.Cookie) {
log.Fatalf("Error creatingrequest: %v", err) log.Fatalf("Error creatingrequest: %v", err)
return return
} }
//log.Println("prompt without extra header or cookie ", prompt) // log.Println("prompt without extra header or cookie ", prompt)
//log.Println("Cookie: ", cookies) // log.Println("Cookie: ", cookies)
prompt.Header.Set("Content-Type", "application/json") prompt.Header.Set("Content-Type", "application/json")
prompt.Header.Set("User-Agent", "Webuntis Test") prompt.Header.Set("User-Agent", "Webuntis Test")
for _, cookie := range cookies { for _, cookie := range cookies {
//if cookie.Name == "JSESSIONID" { // if cookie.Name == "JSESSIONID" {
prompt.AddCookie(cookie) prompt.AddCookie(cookie)
// log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value) // log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value)
//} //}
} }
//log.Println("Request JSON:", string(roomsJson)) // log.Println("Request JSON:", string(roomsJson))
out, err := http.DefaultClient.Do(prompt) out, err := http.DefaultClient.Do(prompt)
if err != nil { if err != nil {
log.Printf("Error during request: %v", err) log.Printf("Error during request: %v", err)
return return
} }
defer out.Body.Close() defer out.Body.Close()
//log.Println(out.Status) // log.Println(out.Status)
response, err := io.ReadAll(out.Body) response, err := io.ReadAll(out.Body)
if err != nil { if err != nil {
log.Printf("Error reading response body: %v", err) log.Printf("Error reading response body: %v", err)
return return
} }
//responseString := string(response) // responseString := string(response)
//log.Println("Repsonse ", responseString) // log.Println("Repsonse ", responseString)
var Response RoomsResponse var Response RoomsResponse
err = json.Unmarshal(response, &Response) err = json.Unmarshal(response, &Response)
if err != nil { if err != nil {
@ -82,9 +82,9 @@ func Rooms(cookies []*http.Cookie) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = os.WriteFile("rooms.json", data, 0644) err = os.WriteFile("rooms.json", data, 0o644)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Println("Updated Rooms") // log.Println("Updated Rooms")//dont need log anymore
} }

View file

@ -42,33 +42,33 @@ func Subjects(cookies []*http.Cookie) {
log.Fatalf("Error creatingrequest: %v", err) log.Fatalf("Error creatingrequest: %v", err)
return return
} }
//log.Println("prompt without extra header or cookie ", prompt) // log.Println("prompt without extra header or cookie ", prompt)
//log.Println("Cookie: ", cookies) // log.Println("Cookie: ", cookies)
prompt.Header.Set("Content-Type", "application/json") prompt.Header.Set("Content-Type", "application/json")
prompt.Header.Set("User-Agent", "Webuntis Test") prompt.Header.Set("User-Agent", "Webuntis Test")
for _, cookie := range cookies { for _, cookie := range cookies {
//if cookie.Name == "JSESSIONID" { // if cookie.Name == "JSESSIONID" {
prompt.AddCookie(cookie) prompt.AddCookie(cookie)
//log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value) //log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value)
//} //}
} }
//log.Println("Request JSON:", string(SubjectsJson)) // log.Println("Request JSON:", string(SubjectsJson))
out, err := http.DefaultClient.Do(prompt) out, err := http.DefaultClient.Do(prompt)
if err != nil { if err != nil {
log.Printf("Error during request: %v", err) log.Printf("Error during request: %v", err)
return return
} }
defer out.Body.Close() defer out.Body.Close()
//log.Println(out.Status) // log.Println(out.Status)
response, err := io.ReadAll(out.Body) response, err := io.ReadAll(out.Body)
if err != nil { if err != nil {
log.Printf("Error reading response body: %v", err) log.Printf("Error reading response body: %v", err)
return return
} }
//responseString := string(response) // responseString := string(response)
//log.Println("Repsonse ", responseString) // log.Println("Repsonse ", responseString)
var Response SubjectsResponse var Response SubjectsResponse
err = json.Unmarshal(response, &Response) err = json.Unmarshal(response, &Response)
if err != nil { if err != nil {
@ -78,9 +78,9 @@ func Subjects(cookies []*http.Cookie) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = os.WriteFile("subjects.json", data, 0644) err = os.WriteFile("subjects.json", data, 0o644)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Println("Updated Subjects") // log.Println("Updated Subjects")//dont need log anymore
} }

View file

@ -42,33 +42,33 @@ func Teachers(cookies []*http.Cookie) {
log.Fatalf("Error creatingrequest: %v", err) log.Fatalf("Error creatingrequest: %v", err)
return return
} }
//log.Println("prompt without extra header or cookie ", prompt) // log.Println("prompt without extra header or cookie ", prompt)
//log.Println("Cookie: ", cookies) // log.Println("Cookie: ", cookies)
prompt.Header.Set("Content-Type", "application/json") prompt.Header.Set("Content-Type", "application/json")
prompt.Header.Set("User-Agent", "Webuntis Test") prompt.Header.Set("User-Agent", "Webuntis Test")
for _, cookie := range cookies { for _, cookie := range cookies {
//if cookie.Name == "JSESSIONID" { // if cookie.Name == "JSESSIONID" {
prompt.AddCookie(cookie) prompt.AddCookie(cookie)
//log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value) //log.Printf("Added JSESSIONID cookie: %s=%s", cookie.Name, cookie.Value)
//} //}
} }
//log.Println("Request JSON:", string(TeachersJson)) // log.Println("Request JSON:", string(TeachersJson))
out, err := http.DefaultClient.Do(prompt) out, err := http.DefaultClient.Do(prompt)
if err != nil { if err != nil {
log.Printf("Error during request: %v", err) log.Printf("Error during request: %v", err)
return return
} }
defer out.Body.Close() defer out.Body.Close()
//log.Println(out.Status) // log.Println(out.Status)
response, err := io.ReadAll(out.Body) response, err := io.ReadAll(out.Body)
if err != nil { if err != nil {
log.Printf("Error reading response body: %v", err) log.Printf("Error reading response body: %v", err)
return return
} }
//responseString := string(response) // responseString := string(response)
//log.Println("Repsonse ", responseString) // log.Println("Repsonse ", responseString)
var Response TeachersResponse var Response TeachersResponse
err = json.Unmarshal(response, &Response) err = json.Unmarshal(response, &Response)
if err != nil { if err != nil {
@ -78,9 +78,9 @@ func Teachers(cookies []*http.Cookie) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
err = os.WriteFile("teachers.json", data, 0644) err = os.WriteFile("teachers.json", data, 0o644)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Println("Updated Teachers") // log.Println("Updated Teachers")//dont need log anymore
} }

View file

@ -152,7 +152,7 @@ func Timetable(cookies []*http.Cookie, userID string) {
return return
} }
log.Printf("Updated timetable for user %s", userID) // log.Printf("Updated timetable for user %s", userID) // dont need log anymore
setTimetable(userID) setTimetable(userID)
} }
@ -249,5 +249,5 @@ func setTimetable(userID string) {
log.Printf("Error writing timetableFilled file: %v", err) log.Printf("Error writing timetableFilled file: %v", err)
return return
} }
log.Printf("Filled timetable for user %s", userID) // log.Printf("Filled timetable for user %s", userID)//log not needed
} }

View file

@ -44,6 +44,7 @@ func Main(user, password, userID string) {
Subjects(cookies) Subjects(cookies)
Timetable(cookies, userID) Timetable(cookies, userID)
Teachers(cookies) Teachers(cookies)
log.Printf("updated everything for user: %s ", user)
} }
func Update(user, password, userID string) { func Update(user, password, userID string) {
@ -54,6 +55,7 @@ func Update(user, password, userID string) {
return return
} }
Timetable(cookies, userID) Timetable(cookies, userID)
log.Printf("Updated info for user: %s ", user)
} }
func Auth(user, password, userID string) ([]*http.Cookie, error) { func Auth(user, password, userID string) ([]*http.Cookie, error) {
@ -73,7 +75,7 @@ func Auth(user, password, userID string) ([]*http.Cookie, error) {
defer LoginOut.Body.Close() defer LoginOut.Body.Close()
cookies := LoginOut.Cookies() cookies := LoginOut.Cookies()
log.Printf("Login successful for user: %s", user) // log.Printf("Login successful for user: %s", user)//log not needed
response, err := io.ReadAll(LoginOut.Body) response, err := io.ReadAll(LoginOut.Body)
if err != nil { if err != nil {

View file

@ -1,9 +1,24 @@
package Untis package Untis
import "time" import (
"log"
"os"
"time"
var Location *time.Location "github.com/joho/godotenv"
)
var (
locerr error
Location *time.Location
)
func GetTime() time.Time { func GetTime() time.Time {
godotenv.Load("../.env")
timezone := os.Getenv("LOCATION_ENV")
Location, locerr = time.LoadLocation(timezone)
if locerr != nil {
log.Fatalf("Failed to load Timezone: %v", locerr)
}
return time.Now().In(Location) return time.Now().In(Location)
} }

67
main.go
View file

@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -93,7 +93,7 @@ func init() {
} }
discordWebhookURL = os.Getenv("DISCORD_WEBHOOK_URL") discordWebhookURL = os.Getenv("DISCORD_WEBHOOK_URL")
log.Println("Initializing application...") log.Println("Initializing application...")
log.Printf("DISCORD_WEBHOOK_URL: %q", discordWebhookURL) // log.Printf("DISCORD_WEBHOOK_URL: %q", discordWebhookURL) //Debug info, not needed at the moment
// Check if Discord webhook is configured // Check if Discord webhook is configured
if discordWebhookURL != "" { if discordWebhookURL != "" {
@ -101,36 +101,19 @@ func init() {
} else { } else {
log.Println("No Discord webhook provided, Discord notifications will be disabled") log.Println("No Discord webhook provided, Discord notifications will be disabled")
} }
locEnv := os.Getenv("LOCATION_ENV")
var locerr error
Untis.Location, locerr = time.LoadLocation(locEnv)
if locerr != nil {
log.Fatalf("Failed to load Timezone: %v", locerr)
}
log.Printf("Timezone set to: %s", location)
initUpdate() initUpdate()
} }
func main() { func main() {
godotenv.Load(".env")
go BotStart.Start() go BotStart.Start()
go scheduleTimetableUpdate() scheduleTimetableUpdate()
sigChan := make(chan os.Signal, 1) sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
log.Println("Program is running. Press Ctrl+C to stop.")
// Start logging
// Run()
// Block until we receive a signal
<-sigChan <-sigChan
log.Println("Shutting down...") log.Println("Shutting down...")
} }
func getTime() time.Time {
return time.Now().In(location)
}
func isScheduledTime(now time.Time) bool { func isScheduledTime(now time.Time) bool {
scheduled := []string{"07:45", "08:35", "09:35", "10:25", "11:25", "12:15", "13:40", "14:25", "15:20", "16:00"} scheduled := []string{"07:45", "08:35", "09:35", "10:25", "11:25", "12:15", "13:40", "14:25", "15:20", "16:00"}
current := now.Format("15:04") current := now.Format("15:04")
@ -143,29 +126,9 @@ func isScheduledTime(now time.Time) bool {
} }
func initUpdate() { func initUpdate() {
// Load all registered users
accounts, err := BotStart.LoadAndDecryptAccounts()
if err != nil {
log.Printf("Error loading accounts: %v", err)
}
// Add the default user from .env
defaultUser := os.Getenv("UNTIS_USER") defaultUser := os.Getenv("UNTIS_USER")
defaultPassword := os.Getenv("UNTIS_PASSWORD") defaultPassword := os.Getenv("UNTIS_PASSWORD")
if defaultUser != "" && defaultPassword != "" { Untis.Main(defaultUser, defaultPassword, "default")
accounts = append(accounts, BotStart.DecryptedAccount{
UserID: "default",
Username: defaultUser,
DecryptedPassword: defaultPassword,
})
}
// Process each user
for _, acc := range accounts {
// Fetch the latest timetable and only timetable
Untis.Main(acc.Username, acc.DecryptedPassword, acc.UserID)
time.Sleep(3 * time.Second)
}
} }
func scheduleTimetableUpdate() { func scheduleTimetableUpdate() {
@ -178,7 +141,6 @@ func scheduleTimetableUpdate() {
if err != nil { if err != nil {
log.Printf("Error loading accounts: %v", err) log.Printf("Error loading accounts: %v", err)
} }
// Add the default user from .env // Add the default user from .env
defaultUser := os.Getenv("UNTIS_USER") defaultUser := os.Getenv("UNTIS_USER")
defaultPassword := os.Getenv("UNTIS_PASSWORD") defaultPassword := os.Getenv("UNTIS_PASSWORD")
@ -194,7 +156,6 @@ func scheduleTimetableUpdate() {
for _, acc := range accounts { for _, acc := range accounts {
// Fetch the latest timetable and only timetable // Fetch the latest timetable and only timetable
Untis.Update(acc.Username, acc.DecryptedPassword, acc.UserID) Untis.Update(acc.Username, acc.DecryptedPassword, acc.UserID)
time.Sleep(3 * time.Second)
// Check for changes // Check for changes
timetableFile := fmt.Sprintf("timetableFilled_%s.json", acc.UserID) timetableFile := fmt.Sprintf("timetableFilled_%s.json", acc.UserID)
@ -230,10 +191,10 @@ func scheduleTimetableUpdate() {
prevTimeslotMap := make(map[string]NamedTimetableEntry) prevTimeslotMap := make(map[string]NamedTimetableEntry)
// Get current date to filter out new day changes // Get current date to filter out new day changes
today := getTime().Format("02-01-2006") today := Untis.GetTime().Format("02-01-2006")
// Get current time to filter any changes to Timetable before 3am so the new day changes stop // Get current time to filter any changes to Timetable before 3am so the new day changes stop
// //
now := getTime() now := Untis.GetTime()
// If before 1am stop and update userdata // If before 1am stop and update userdata
if now.Hour() < 1 { if now.Hour() < 1 {
prevData[acc.UserID] = data prevData[acc.UserID] = data
@ -337,14 +298,11 @@ func scheduleTimetableUpdate() {
sendUpdateDiscordWebhookWithDetails(changes) sendUpdateDiscordWebhookWithDetails(changes)
} }
} }
} else {
// First run — no previous data, so don't notify
log.Printf("First timetable fetch for user %s", acc.Username)
} }
// Always update prevData // Always update prevData
prevData[acc.UserID] = data prevData[acc.UserID] = data
} }
time.Sleep(3 * time.Second)
} }
// Initial update // Initial update
@ -360,7 +318,7 @@ func scheduleTimetableUpdate() {
// Ticker for scheduled lesson notifications // Ticker for scheduled lesson notifications
startMinuteTicker(func() { startMinuteTicker(func() {
now := getTime() now := Untis.GetTime()
if isScheduledTime(now) { if isScheduledTime(now) {
log.Println("Scheduled time reached, running notifications...") log.Println("Scheduled time reached, running notifications...")
accounts, _ := BotStart.LoadAndDecryptAccounts() accounts, _ := BotStart.LoadAndDecryptAccounts()
@ -372,10 +330,11 @@ func scheduleTimetableUpdate() {
log.Println("Finished running notifications.") log.Println("Finished running notifications.")
} }
}) })
log.Println("Updated all users")
} }
func startMinuteTicker(f func()) { func startMinuteTicker(f func()) {
now := getTime() now := Untis.GetTime()
next := now.Truncate(time.Minute).Add(time.Minute) next := now.Truncate(time.Minute).Add(time.Minute)
time.Sleep(time.Until(next)) time.Sleep(time.Until(next))
ticker := time.NewTicker(1 * time.Minute) ticker := time.NewTicker(1 * time.Minute)
@ -404,7 +363,7 @@ func Run(userID string) {
roomByStartTime, _ := MapTimeToRoom(timetableFile) roomByStartTime, _ := MapTimeToRoom(timetableFile)
subjectByStartTime, _ := MapTimeToSubject(timetableFile) subjectByStartTime, _ := MapTimeToSubject(timetableFile)
now := getTime().Format("15:04") now := Untis.GetTime().Format("15:04")
nextTime, room, foundRoom := NextRoomForTime(roomByStartTime, now) nextTime, room, foundRoom := NextRoomForTime(roomByStartTime, now)
if !foundRoom { if !foundRoom {
@ -653,7 +612,7 @@ func sendDiscordWebhook(subject string, room string, nextTime string, Status str
if resp.StatusCode >= 200 && resp.StatusCode < 300 { if resp.StatusCode >= 200 && resp.StatusCode < 300 {
log.Println("Discord webhook notification sent successfully") log.Println("Discord webhook notification sent successfully")
} else { } else {
body, _ := ioutil.ReadAll(resp.Body) body, _ := io.ReadAll(resp.Body)
log.Printf("Discord webhook failed with status %d: %s", resp.StatusCode, string(body)) log.Printf("Discord webhook failed with status %d: %s", resp.StatusCode, string(body))
} }
} }
@ -684,7 +643,7 @@ func sendUpdateDiscordWebhookWithDetails(changes []string) {
if resp.StatusCode >= 200 && resp.StatusCode < 300 { if resp.StatusCode >= 200 && resp.StatusCode < 300 {
log.Println("Detailed Discord webhook sent successfully") log.Println("Detailed Discord webhook sent successfully")
} else { } else {
body, _ := ioutil.ReadAll(resp.Body) body, _ := io.ReadAll(resp.Body)
log.Printf("Discord webhook failed with status %d: %s", resp.StatusCode, string(body)) log.Printf("Discord webhook failed with status %d: %s", resp.StatusCode, string(body))
} }
} }