From 0b18a29521ec8cb46bf0de21a86ff2f5e7a9da9c Mon Sep 17 00:00:00 2001 From: pikachu0542 <112343747+pikachu0542@users.noreply.github.com> Date: Mon, 16 Feb 2026 11:16:31 -0500 Subject: [PATCH 1/4] Add feedback for why users cant vote (#74) * Added alert on results screen for when you already voted * Added banner alert telling user that they already voted * Tried to make the alert have vertically centered text * Fixed vertical centering (thanks noah) * Added alert for if user is inactive * Updated alert to account for inactive and gatekept, added alert for db error * Updated alert to account for inactive and gatekept, added alert for db error * Added sentence telling people to contact evals or opcomm for more info --- main.go | 1 + templates/result.tmpl | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/main.go b/main.go index a5f1a2a..19eb373 100644 --- a/main.go +++ b/main.go @@ -430,6 +430,7 @@ func main() { "IsOpen": poll.Open, "IsHidden": poll.Hidden, "CanModify": canModify, + "CanVote": canVote(claims.UserInfo, *poll, poll.AllowedUsers), "Username": claims.UserInfo.Username, "FullName": claims.UserInfo.FullName, "Gatekeep": poll.Gatekeep, diff --git a/templates/result.tmpl b/templates/result.tmpl index 9e81f54..5e5e1c2 100644 --- a/templates/result.tmpl +++ b/templates/result.tmpl @@ -9,6 +9,12 @@ media="screen" /> + +
+ {{ if eq .CanVote 9 }} + + {{ else if eq .CanVote 1 }} + + {{ else if gt .CanVote 1 }} + + {{ end }} +

{{ .ShortDescription }}

{{ if .LongDescription }}

{{ .LongDescription | MakeLinks }}

@@ -38,6 +71,7 @@

Results will be available once the poll closes

{{ else }} + {{/* Displays information about required quorum and number of voters */}}
Number of Eligible Voters: {{ len .EligibleVoters }}
From ccd38303e9b61ac2674a4daa4486d5095f7c8a88 Mon Sep 17 00:00:00 2001 From: pikachu0542 <112343747+pikachu0542@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:03:54 -0500 Subject: [PATCH 2/4] Move closed polls to separate page (#75) --- main.go | 29 +++++++++++++++++++++- templates/closed.tmpl | 48 +++++++++++++++++++++++++++++++++++++ templates/create.tmpl | 14 ++--------- templates/hidden.tmpl | 15 ++---------- templates/index.tmpl | 48 ++++--------------------------------- templates/nav.tmpl | 18 ++++++++++++++ templates/poll.tmpl | 13 +--------- templates/result.tmpl | 13 +--------- templates/unauthorized.tmpl | 13 +--------- 9 files changed, 106 insertions(+), 105 deletions(-) create mode 100644 templates/closed.tmpl create mode 100644 templates/nav.tmpl diff --git a/main.go b/main.go index 19eb373..f63d8a4 100644 --- a/main.go +++ b/main.go @@ -126,7 +126,34 @@ func main() { closedPolls = uniquePolls(closedPolls) c.HTML(200, "index.tmpl", gin.H{ - "Polls": polls, + "Polls": polls, + "Username": claims.UserInfo.Username, + "FullName": claims.UserInfo.FullName, + }) + })) + + r.GET("/closed", csh.AuthWrapper(func(c *gin.Context) { + cl, _ := c.Get("cshauth") + claims := cl.(cshAuth.CSHClaims) + + closedPolls, err := database.GetClosedVotedPolls(c, claims.UserInfo.Username) + if err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + ownedPolls, err := database.GetClosedOwnedPolls(c, claims.UserInfo.Username) + if err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + closedPolls = append(closedPolls, ownedPolls...) + + sort.Slice(closedPolls, func(i, j int) bool { + return closedPolls[i].Id > closedPolls[j].Id + }) + closedPolls = uniquePolls(closedPolls) + + c.HTML(200, "closed.tmpl", gin.H{ "ClosedPolls": closedPolls, "Username": claims.UserInfo.Username, "FullName": claims.UserInfo.FullName, diff --git a/templates/closed.tmpl b/templates/closed.tmpl new file mode 100644 index 0000000..199036f --- /dev/null +++ b/templates/closed.tmpl @@ -0,0 +1,48 @@ + + + + CSH Vote + + + + + + + + {{ template "nav" . }} +
+

+
Closed Polls
+

+
+
+ +
+
+ + diff --git a/templates/create.tmpl b/templates/create.tmpl index 1fbeeba..14f1299 100644 --- a/templates/create.tmpl +++ b/templates/create.tmpl @@ -7,18 +7,8 @@ - + {{ template "nav" . }} +

Create Poll

diff --git a/templates/hidden.tmpl b/templates/hidden.tmpl index e7a0969..a2740be 100644 --- a/templates/hidden.tmpl +++ b/templates/hidden.tmpl @@ -20,19 +20,8 @@ - - + {{ template "nav" . }} +
- + {{ template "nav" . }}

Active Polls
@@ -47,43 +36,16 @@ class="list-group-item list-group-item-action" href="/poll/{{ $poll.Id }}" > - {{ - $poll.ShortDescription - }} - - (created by {{ $poll.CreatedBy }}) - - - {{ - end - }} - -

-
-

Closed Polls

-
-
-
diff --git a/templates/nav.tmpl b/templates/nav.tmpl new file mode 100644 index 0000000..7c746f8 --- /dev/null +++ b/templates/nav.tmpl @@ -0,0 +1,18 @@ +{{ define "nav" }} + + +{{ end }} \ No newline at end of file diff --git a/templates/poll.tmpl b/templates/poll.tmpl index a501a09..0f074a3 100644 --- a/templates/poll.tmpl +++ b/templates/poll.tmpl @@ -12,18 +12,7 @@ - + {{ template "nav" . }}

{{ .ShortDescription }}

diff --git a/templates/result.tmpl b/templates/result.tmpl index 5e5e1c2..45d060b 100644 --- a/templates/result.tmpl +++ b/templates/result.tmpl @@ -17,18 +17,7 @@ - + {{ template "nav" . }}
{{ if eq .CanVote 9 }} diff --git a/templates/unauthorized.tmpl b/templates/unauthorized.tmpl index 8d18de1..0a5d226 100644 --- a/templates/unauthorized.tmpl +++ b/templates/unauthorized.tmpl @@ -20,18 +20,7 @@ - + {{ template "nav" . }}
Date: Wed, 18 Feb 2026 10:28:42 -0500 Subject: [PATCH 3/4] Miscellanous qol changes (#78) * Explicitly connect to database from main instead of from database.go * Added godotenv to automatically load .env if it exists * Small changes suggested by go compiler * Fixed incorrect method names in logs * Replaced context.TODO() with context.Background() * Updated gitignore to ignore .vscode * Revert "Small changes suggested by go compiler" This reverts commit 1dd301c1e393e984b3837f113a563f6c6a735e83. * Change suggested by go compiler --- .gitignore | 3 ++- constitutional.go | 4 ++-- database/database.go | 6 +++--- go.mod | 1 + go.sum | 2 ++ main.go | 3 +++ users.go | 14 ++++++++------ 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index fac86fa..20e2001 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env* vote -.idea/ \ No newline at end of file +.idea/ +.vscode/ \ No newline at end of file diff --git a/constitutional.go b/constitutional.go index 7528b34..4fc412c 100644 --- a/constitutional.go +++ b/constitutional.go @@ -49,8 +49,8 @@ func InitConstitution() { startOfDay := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local) nextMidnight := startOfDay.AddDate(0, 0, 1) fmt.Println(nextMidnight) - fmt.Println(nextMidnight.Sub(time.Now())) - ticker := time.NewTicker(nextMidnight.Sub(time.Now())) + fmt.Println(time.Until(nextMidnight)) + ticker := time.NewTicker(time.Until(nextMidnight)) first := true go func() { for { diff --git a/database/database.go b/database/database.go index d03bc42..238fe85 100644 --- a/database/database.go +++ b/database/database.go @@ -21,7 +21,7 @@ const ( Updated UpsertResult = 1 ) -var Client *mongo.Client = Connect() +var Client *mongo.Client var db = "" func Connect() *mongo.Client { @@ -33,7 +33,7 @@ func Connect() *mongo.Client { logging.Logger.WithFields(logrus.Fields{"module": "database", "method": "Connect"}).Info("beginning database connection") - ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() uri := os.Getenv("VOTE_MONGODB_URI") @@ -54,7 +54,7 @@ func Connect() *mongo.Client { } func Disconnect() { - ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := Client.Disconnect(ctx); err != nil { diff --git a/go.mod b/go.mod index c16c793..2f6a5d5 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.1 require ( github.com/computersciencehouse/csh-auth v0.1.0 github.com/gin-gonic/gin v1.11.0 + github.com/joho/godotenv v1.5.1 github.com/sirupsen/logrus v1.9.3 github.com/slack-go/slack v0.17.3 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index b325fdf..778f6f7 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= diff --git a/main.go b/main.go index f63d8a4..cccf7dc 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ import ( "github.com/computersciencehouse/vote/logging" "github.com/computersciencehouse/vote/sse" "github.com/gin-gonic/gin" + "github.com/joho/godotenv" "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson/primitive" "mvdan.cc/xurls/v2" @@ -57,6 +58,8 @@ func MakeLinks(s string) template.HTML { var oidcClient = OIDCClient{} func main() { + godotenv.Load() + database.Client = database.Connect() r := gin.Default() r.StaticFS("/static", http.Dir("static")) r.SetFuncMap(template.FuncMap{ diff --git a/users.go b/users.go index d20a390..ea00283 100644 --- a/users.go +++ b/users.go @@ -64,22 +64,22 @@ func (client *OIDCClient) getAccessToken() int { authData.Set("grant_type", "client_credentials") resp, err := htclient.PostForm(cshAuth.ProviderURI+"/protocol/openid-connect/token", authData) if err != nil { - logging.Logger.WithFields(logrus.Fields{"method": "setupOidcClient"}).Error(err) + logging.Logger.WithFields(logrus.Fields{"method": "getAccessToken"}).Error(err) return 0 } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - logging.Logger.WithFields(logrus.Fields{"method": "setupOidcClient", "statusCode": resp.StatusCode}).Error(resp.Status) + logging.Logger.WithFields(logrus.Fields{"method": "getAccessToken", "statusCode": resp.StatusCode}).Error(resp.Status) return 0 } respData := make(map[string]interface{}) err = json.NewDecoder(resp.Body).Decode(&respData) if err != nil { - logging.Logger.WithFields(logrus.Fields{"method": "setupOidcClient"}).Error(err) + logging.Logger.WithFields(logrus.Fields{"method": "getAccessToken"}).Error(err) return 0 } if respData["error"] != nil { - logging.Logger.WithFields(logrus.Fields{"method": "setupOidcClient"}).Error(respData) + logging.Logger.WithFields(logrus.Fields{"method": "getAccessToken"}).Error(respData) return 0 } client.accessToken = respData["access_token"].(string) @@ -91,19 +91,20 @@ func (client *OIDCClient) GetActiveUsers() []OIDCUser { //active req, err := http.NewRequest("GET", client.providerBase+"/auth/admin/realms/csh/groups/a97a191e-5668-43f5-bc0c-6eefc2b958a7/members", nil) if err != nil { + logging.Logger.WithFields(logrus.Fields{"method": "GetActiveUsers"}).Error(err) return nil } req.Header.Add("Authorization", "Bearer "+client.accessToken) resp, err := htclient.Do(req) if err != nil { - logging.Logger.WithFields(logrus.Fields{"method": "GetAllUsers"}).Error(err) + logging.Logger.WithFields(logrus.Fields{"method": "GetActiveUsers"}).Error(err) return nil } defer resp.Body.Close() ret := make([]OIDCUser, 0) err = json.NewDecoder(resp.Body).Decode(&ret) if err != nil { - logging.Logger.WithFields(logrus.Fields{"method": "GetAllUsers"}).Error(err) + logging.Logger.WithFields(logrus.Fields{"method": "GetActiveUsers"}).Error(err) return nil } return ret @@ -118,6 +119,7 @@ func (client *OIDCClient) GetUserInfo(user *OIDCUser) { req, err := http.NewRequest("GET", client.providerBase+"/auth/admin/realms/csh/users/"+user.Uuid+arg, nil) // also "users/{user-id}/groups" if err != nil { + logging.Logger.WithFields(logrus.Fields{"method": "GetUserInfo"}).Error(err) return } req.Header.Add("Authorization", "Bearer "+client.accessToken) From 37c99b23780d51b951e841f031ceacc10f89ed43 Mon Sep 17 00:00:00 2001 From: pikachu0542 <112343747+pikachu0542@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:18:04 -0500 Subject: [PATCH 4/4] Merge nav fixes into dev (#81) * Moved navbar code to its own template * Moved closed polls to separate page, added link on navbar to poll creation page * Added open polls link to navbar for more intuitive navigation * Changed nav link order * Fixed small formatting inconsistency * More formatting fixes * Added hamburger mobile menu (#80) --- templates/closed.tmpl | 3 +++ templates/create.tmpl | 3 +++ templates/hidden.tmpl | 3 +++ templates/index.tmpl | 5 ++++- templates/nav.tmpl | 34 ++++++++++++++++++++++++++-------- templates/poll.tmpl | 3 +++ templates/result.tmpl | 3 +++ templates/unauthorized.tmpl | 3 +++ 8 files changed, 48 insertions(+), 9 deletions(-) diff --git a/templates/closed.tmpl b/templates/closed.tmpl index 199036f..c0a02f9 100644 --- a/templates/closed.tmpl +++ b/templates/closed.tmpl @@ -8,6 +8,9 @@ href="https://assets.csh.rit.edu/csh-material-bootstrap/4.3.1/dist/csh-material-bootstrap.min.css" media="screen" /> + + + - {{ template "nav" . }} +

Active Polls
diff --git a/templates/nav.tmpl b/templates/nav.tmpl index 7c746f8..0942983 100644 --- a/templates/nav.tmpl +++ b/templates/nav.tmpl @@ -2,17 +2,35 @@ {{ end }} \ No newline at end of file diff --git a/templates/poll.tmpl b/templates/poll.tmpl index 0f074a3..95196be 100644 --- a/templates/poll.tmpl +++ b/templates/poll.tmpl @@ -4,6 +4,9 @@ CSH Vote + + +