From 29bdaf069e8ed42ffc8b31d3c26345608096cce3 Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Thu, 13 Mar 2025 22:49:40 +0000 Subject: [PATCH 1/6] Add logging and new flags for attendance program. --- README.md | 4 ++++ main.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++---- utils.go | 68 +++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 119 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ac9a9e2..23274fb 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,10 @@ gisem_presencas.exe -w value ## Flags - `-w` or `-wait`: Time to wait in between refreshes (default is 10 seconds). +- `-l` or `-log`: Send the output to a file. +- `-m` or `-maxtime`: Sets a maxmium time for the program to try set Attendance (default is -1 (forever)). +- `-r` or `-replace`: Forces the program into replacing the existing saved password. +- `-v` or `-verbose`: Shows addicional info. ## Project Structure diff --git a/main.go b/main.go index 1db10ac..680af79 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "os" // added for logging to file "time" "github.com/chromedp/chromedp" @@ -14,21 +15,68 @@ const ( ) var waitTime int +var isVerbose bool +var maxTime int func main() { //* Parse the flags - wait, headless, err := parseFlags() + wait, verbose, headless, logFile, timeout, replacePass, err := parseFlags() if err != nil { log.Fatalf("Failed to parse flags: %v", err) } waitTime = wait + isVerbose = verbose + maxTime = timeout + if logFile != "" { + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + log.Fatalf("Failed to open log file: %v", err) + } + defer file.Close() + log.SetOutput(file) + } - fmt.Println("Waiting time:", waitTime) + if isVerbose { + fmt.Println("Waiting time:", waitTime) + fmt.Println("Verbose mode:", isVerbose) + fmt.Println("Headless mode:", headless) + if logFile == "" { + fmt.Println("Logging to file: disabled") + + } else { + fmt.Println("Logging to file:", logFile) + } + + if maxTime == -1 { + fmt.Println("Max time: disabled") + } else { + fmt.Println("Max time:", maxTime) + } + } //* Welcome message welcomeMessage() + if logFile != "" { + fmt.Println("Logging to file:", logFile) + fmt.Println("(No text will be shown because logging is enabled, dont worry, the program is still running)") + log.Print("Starting new program... (logging to file)\n\n") + isVerbose = true + } + creds, err := getCreds() + + if replacePass { + creds, err = promptAndSaveCreds(credFile) + if err != nil { + log.Fatalf("Failed to get credentials: %v", err) + } + if isVerbose { + log.Println("Credentials replaced") + } + + } + if err != nil { // If the credentials file doesn't exist, prompt for credentials if err.Error() == "credentials file not found: stat "+credFile+": no such file or directory" { @@ -59,6 +107,9 @@ func main() { log.Fatalf("Failed to navigate: %v", err) } + if isVerbose { + log.Println("Navigated to the website") + } //* Check if there's a login button var isVisible bool if err := chromedp.Run(ctx, chromedp.Tasks{ @@ -68,15 +119,25 @@ func main() { log.Fatalf("Failed to evaluate: %v", err) } + if isVerbose { + log.Println("Login button visible:", isVisible) + } + if isVisible { log.Println("Logging in...") if err := login(ctx, creds); err != nil { log.Fatalf("Failed to login: %v", err) } time.Sleep(1 * time.Second) - log.Println("Waiting for activation...") + log.Println("Logged in!") + if isVerbose { + log.Println("Waiting for activation...") + } if err := marcarPresenca(ctx); err != nil { - log.Fatalf("Failed to mark presence: %v", err) + log.Println("Failed to mark presence: %v", err) + } else { + log.Println("Presence marked!") } } + log.Print("Program finished successfully! (logging to file) \n\n") } diff --git a/utils.go b/utils.go index 075ff2d..57deb00 100644 --- a/utils.go +++ b/utils.go @@ -9,6 +9,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "flag" "fmt" "io" @@ -106,24 +107,37 @@ func decrypt(encryptedHex, passphrase string) (string, error) { return string(plaintext), nil } -func parseFlags() (int, bool, error) { +func parseFlags() (int, bool, bool, string, int, bool, error) { //* Set the flags - wait := flag.Int("w", 10, "Time to wait in between refreshes") - flag.IntVar(wait, "wait", 10, "Time to wait in between refreshes") + wait := flag.Int("w", 10, "\tTime to wait in between refreshes") + flag.IntVar(wait, "wait", 10, "\tTime to wait in between refreshes") + + // Verbose mode + isVerbose := flag.Bool("v", false, "\tEnable verbose mode") + flag.BoolVar(isVerbose, "verbose", false, "\tEnable verbose mode") // By default, run in headless mode - headless := flag.Bool("h", true, "Run in headless mode") - flag.BoolVar(headless, "headless", true, "Run in headless mode") + headless := flag.Bool("h", true, "\tRun in headless mode") + flag.BoolVar(headless, "headless", true, "\tRun in headless mode") + + // Log to file + logFile := flag.String("l", "", "\tLog output to file") + flag.StringVar(logFile, "log", "", "\tLog output to file") + + // Maximum time to run the program (minutes) + maxTime := flag.Int("m", -1, "\tMaximum time to run the program (minutes)") + flag.IntVar(maxTime, "maxtime", -1, "\tMaximum time to run the program (minutes)") + + replacePass := flag.Bool("r", false, "\tReplace saved credentials") + flag.BoolVar(replacePass, "replace", false, "\tReplace saved credentials") flag.Parse() if *wait < 0 { - return 0, false, fmt.Errorf("invalid wait time: %d", *wait) + return 0, false, false, "", -1, false, fmt.Errorf("invalid wait time: %d", *wait) } - fmt.Println(*headless) - - return *wait, *headless, nil + return *wait, *isVerbose, *headless, *logFile, *maxTime, *replacePass, nil } func welcomeMessage() { @@ -253,7 +267,7 @@ func saveCreds(filePath, username, password string) (Credentials, error) { return Credentials{}, fmt.Errorf("could not write credentials to file: %v", err) } - fmt.Println("Credentials saved successfully!") + log.Println("Credentials saved successfully!") return creds, nil } @@ -279,6 +293,12 @@ func login(ctx context.Context, creds Credentials) error { func marcarPresenca(ctx context.Context) error { var attempt int + startTime := time.Now() + + if isVerbose || maxTime != -1 { + log.Printf("Starting attendance registration at %s\n", startTime.Format(time.RFC1123)) + } + for attempt = 1; attempt <= maxRetries; attempt++ { if err := chromedp.Run(ctx, chromedp.ActionFunc(func(ctx context.Context) error { @@ -286,23 +306,23 @@ func marcarPresenca(ctx context.Context) error { waitCtx, cancel := context.WithTimeout(ctx, time.Duration(waitTime)*time.Second) defer cancel() - //Try to wait for the element err := chromedp.Run(waitCtx, chromedp.WaitVisible(menuPresencas)) if err == nil { - fmt.Println("Navigation menu is visible!") + if isVerbose { + log.Println("Navigation menu is visible!") + } } chromedp.Run(waitCtx, chromedp.Click(menuPresencas)) - fmt.Println("Navigation menu clicked!") var currentURL string if err := chromedp.Location(¤tURL).Do(ctx); err != nil { return err } if strings.Contains(currentURL, "obterAulasMarcarPresenca") { - fmt.Println("Attendance page loaded!") - fmt.Println("Registering attendance...") + log.Println("Attendance page loaded :", time.Now().Format(time.RFC1123)) + log.Println("Registering attendance... : ", time.Now().Format(time.RFC1123)) break } @@ -310,6 +330,14 @@ func marcarPresenca(ctx context.Context) error { return err } time.Sleep(time.Duration(waitTime) * time.Second) + + if maxTime != -1 { + elapsedMinutes := time.Since(startTime).Minutes() + if int(elapsedMinutes) >= maxTime { + log.Println("Maximum time reached, attendance not registered", time.Now().Format(time.RFC1123)) + return errors.New("maximum time reached") + } + } } return nil }), @@ -327,11 +355,11 @@ func marcarPresenca(ctx context.Context) error { select { case alertMessage := <-ch: if strings.Contains(alertMessage, "sucesso") { - fmt.Println("Attendance registered successfully!") + log.Println("Attendance registered successfully! : ", time.Now().Format(time.RFC1123)) } else if strings.Contains(alertMessage, "anteriormente") { - fmt.Println("Attendance previously registered!") + log.Println("Attendance previously registered! : ", time.Now().Format(time.RFC1123)) } else { - fmt.Println("Error registering attendance: ", alertMessage) + log.Println("Error registering attendance: ", alertMessage) } case <-time.After(time.Duration(waitTime) * time.Second): return fmt.Errorf("timeout waiting for alert") @@ -339,6 +367,10 @@ func marcarPresenca(ctx context.Context) error { return nil }), ); err != nil { + // Check if the error was due to maximum time reached + if err.Error() == "maximum time reached" { + return err + } log.Printf("Attempt %d: Failed to register attendance: %v", attempt, err) time.Sleep(5 * time.Second) continue From 3c72abd3be6e7a34c1d7ec183fc70f2c91634faf Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Thu, 13 Mar 2025 22:52:01 +0000 Subject: [PATCH 2/6] Fixed verbose logging condition --- main.go | 1 + utils.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 680af79..5e22c9d 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ const ( var waitTime int var isVerbose bool var maxTime int +var logFile string func main() { //* Parse the flags diff --git a/utils.go b/utils.go index 57deb00..973bb5d 100644 --- a/utils.go +++ b/utils.go @@ -310,7 +310,7 @@ func marcarPresenca(ctx context.Context) error { chromedp.WaitVisible(menuPresencas)) if err == nil { - if isVerbose { + if isVerbose && logFile == "" { log.Println("Navigation menu is visible!") } } From 072d23fed68ef909a4171bd380e1c8db0d7ebce7 Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Thu, 13 Mar 2025 22:53:43 +0000 Subject: [PATCH 3/6] Small Fix. --- utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils.go b/utils.go index 973bb5d..4e1014d 100644 --- a/utils.go +++ b/utils.go @@ -310,7 +310,7 @@ func marcarPresenca(ctx context.Context) error { chromedp.WaitVisible(menuPresencas)) if err == nil { - if isVerbose && logFile == "" { + if isVerbose && logFile != "" { log.Println("Navigation menu is visible!") } } From 62b5f3096694bd63e2a14a2ff37e19bb314bafe2 Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Thu, 13 Mar 2025 22:55:19 +0000 Subject: [PATCH 4/6] Added MaxTime to the logging. --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 5e22c9d..51736fb 100644 --- a/main.go +++ b/main.go @@ -49,9 +49,9 @@ func main() { } if maxTime == -1 { - fmt.Println("Max time: disabled") + log.Println("Max time: disabled") } else { - fmt.Println("Max time:", maxTime) + log.Println("Max time:", maxTime) } } From d7a9c847b05afd8de341741e60ff1b750e7ed1ba Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Thu, 13 Mar 2025 22:56:47 +0000 Subject: [PATCH 5/6] Another Small fix! Last one I promise. --- main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main.go b/main.go index 51736fb..2b9dcb5 100644 --- a/main.go +++ b/main.go @@ -63,6 +63,12 @@ func main() { fmt.Println("(No text will be shown because logging is enabled, dont worry, the program is still running)") log.Print("Starting new program... (logging to file)\n\n") isVerbose = true + + if maxTime == -1 { + log.Println("Max time: disabled") + } else { + log.Println("Max time:", maxTime) + } } creds, err := getCreds() From 832ee30b86a347aaca974689103e53b18292f8a7 Mon Sep 17 00:00:00 2001 From: Afonso Sousa <145158518+AfonsoCMSousa@users.noreply.github.com> Date: Thu, 13 Mar 2025 23:10:25 +0000 Subject: [PATCH 6/6] Fixed issue related to misinterpretation in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 23274fb..294859b 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ gisem_presencas.exe -w value - `-w` or `-wait`: Time to wait in between refreshes (default is 10 seconds). - `-l` or `-log`: Send the output to a file. - `-m` or `-maxtime`: Sets a maxmium time for the program to try set Attendance (default is -1 (forever)). -- `-r` or `-replace`: Forces the program into replacing the existing saved password. +- `-r` or `-replace`: Forces the program into replacing the existing saved credentials. - `-v` or `-verbose`: Shows addicional info. ## Project Structure