Skip to content

Commit 7931034

Browse files
authored
Merge pull request #93 from ComputerScienceHouse/eboard-vote
E-Board Vote
2 parents 9bd0dde + 6462009 commit 7931034

7 files changed

Lines changed: 61 additions & 66 deletions

File tree

.github/pull_request_template.md

Lines changed: 0 additions & 19 deletions
This file was deleted.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ VOTE_SLACK_BOT_TOKEN=
3232
### Dev Overrides
3333
`DEV_DISABLE_ACTIVE_FILTERS="true"` will disable the requirements that you be active to vote
3434
`DEV_FORCE_IS_EVALS="true"` will force vote to treat all users as the Evals director
35+
`DEV_FORCE_IS_CHAIR="true"` will force vote to treat all users as the Chairperson
3536

3637
## Linting
3738
These will be checked by CI

docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ services:
2222
VOTE_STATE: 27a28540e47ec786b7bdad03f83171b3
2323
DEV_DISABLE_ACTIVE_FILTERS: "${DEV_DISABLE_ACTIVE_FILTERS}"
2424
DEV_FORCE_IS_EVALS: "${DEV_FORCE_IS_EVALS}"
25+
DEV_FORCE_IS_CHAIR: "${DEV_FORCE_IS_CHAIR}"
2526
ports:
2627
- "127.0.0.1:8080:8080"
2728

main.go

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,20 @@ var CONDITIONAL_GATEKEEP_URL = os.Getenv("VOTE_CONDITIONAL_URL")
3030
var VOTE_HOST = os.Getenv("VOTE_HOST")
3131

3232
// Dev mode flags
33-
var DEV_DISABLE_ACTIVE_FILTERS bool = os.Getenv("DEV_DISABLE_ACTIVE_FILTERS") == "true"
34-
var DEV_FORCE_IS_EVALS bool = os.Getenv("DEV_FORCE_IS_EVALS") == "true"
33+
var DEV_DISABLE_ACTIVE_FILTERS = os.Getenv("DEV_DISABLE_ACTIVE_FILTERS") == "true"
34+
var DEV_FORCE_IS_EVALS = os.Getenv("DEV_FORCE_IS_EVALS") == "true"
35+
var DEV_FORCE_IS_CHAIR = os.Getenv("DEV_FORCE_IS_CHAIR") == "true"
3536

3637
func inc(x int) string {
3738
return strconv.Itoa(x + 1)
3839
}
3940

40-
// Gets the number of people eligible to vote in a poll
41+
// GetVoterCount Gets the number of people eligible to vote in a poll
4142
func GetVoterCount(poll database.Poll) int {
4243
return len(poll.AllowedUsers)
4344
}
4445

45-
// Calculates the number of votes required for quorum in a poll
46+
// CalculateQuorum Calculates the number of votes required for quorum in a poll
4647
func CalculateQuorum(poll database.Poll) int {
4748
voterCount := GetVoterCount(poll)
4849
return int(math.Ceil(float64(voterCount) * poll.QuorumType))
@@ -111,23 +112,6 @@ func main() {
111112
return polls[i].Id > polls[j].Id
112113
})
113114

114-
closedPolls, err := database.GetClosedVotedPolls(c, claims.UserInfo.Username)
115-
if err != nil {
116-
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
117-
return
118-
}
119-
ownedPolls, err := database.GetClosedOwnedPolls(c, claims.UserInfo.Username)
120-
if err != nil {
121-
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
122-
return
123-
}
124-
closedPolls = append(closedPolls, ownedPolls...)
125-
126-
sort.Slice(closedPolls, func(i, j int) bool {
127-
return closedPolls[i].Id > closedPolls[j].Id
128-
})
129-
closedPolls = uniquePolls(closedPolls)
130-
131115
c.HTML(http.StatusOK, "index.tmpl", gin.H{
132116
"Polls": polls,
133117
"Username": claims.UserInfo.Username,
@@ -216,8 +200,19 @@ func main() {
216200
AllowWriteIns: c.PostForm("allowWriteIn") == "true",
217201
Hidden: c.PostForm("hidden") == "true",
218202
}
219-
if c.PostForm("rankedChoice") == "true" {
203+
switch c.PostForm("pollType") {
204+
case "rankedChoice":
220205
poll.VoteType = database.POLL_TYPE_RANKED
206+
case "eboard":
207+
eboard := oidcClient.GetEBoard()
208+
var usernames []string
209+
for _, member := range eboard {
210+
usernames = append(usernames, member.Username)
211+
}
212+
poll.AllowedUsers = usernames
213+
poll.AllowWriteIns = false
214+
poll.Hidden = true
215+
poll.Gatekeep = false
221216
}
222217

223218
switch c.PostForm("options") {
@@ -229,7 +224,7 @@ func main() {
229224
poll.Options = []string{}
230225
for opt := range strings.SplitSeq(c.PostForm("customOptions"), ",") {
231226
poll.Options = append(poll.Options, strings.TrimSpace(opt))
232-
if !containsString(poll.Options, "Abstain") && (poll.VoteType == database.POLL_TYPE_SIMPLE) {
227+
if !slices.Contains(poll.Options, "Abstain") && (poll.VoteType == database.POLL_TYPE_SIMPLE) {
233228
poll.Options = append(poll.Options, "Abstain")
234229
}
235230
}
@@ -283,7 +278,7 @@ func main() {
283278
writeInAdj = 1
284279
}
285280

286-
canModify := containsString(claims.UserInfo.Groups, "active_rtp") || containsString(claims.UserInfo.Groups, "eboard") || poll.CreatedBy == claims.UserInfo.Username
281+
canModify := slices.Contains(claims.UserInfo.Groups, "active_rtp") || slices.Contains(claims.UserInfo.Groups, "eboard") || poll.CreatedBy == claims.UserInfo.Username
287282

288283
c.HTML(200, "poll.tmpl", gin.H{
289284
"Id": poll.Id,
@@ -448,7 +443,7 @@ func main() {
448443
return
449444
}
450445

451-
canModify := containsString(claims.UserInfo.Groups, "active_rtp") || containsString(claims.UserInfo.Groups, "eboard") || poll.CreatedBy == claims.UserInfo.Username
446+
canModify := slices.Contains(claims.UserInfo.Groups, "active_rtp") || slices.Contains(claims.UserInfo.Groups, "eboard") || poll.CreatedBy == claims.UserInfo.Username
452447

453448
votesNeededForQuorum := int(poll.QuorumType * float64(len(poll.AllowedUsers)))
454449
c.HTML(http.StatusOK, "result.tmpl", gin.H{
@@ -525,8 +520,7 @@ func main() {
525520
}
526521

527522
if poll.CreatedBy != claims.UserInfo.Username {
528-
if containsString(claims.UserInfo.Groups, "active_rtp") || containsString(claims.UserInfo.Groups, "eboard") {
529-
} else {
523+
if !(slices.Contains(claims.UserInfo.Groups, "active_rtp") || slices.Contains(claims.UserInfo.Groups, "eboard")) {
530524
c.JSON(http.StatusForbidden, gin.H{"error": "You cannot end this poll."})
531525
return
532526
}
@@ -563,7 +557,11 @@ func main() {
563557

564558
// isEvals determines if the current user is evals, allowing for a dev mode override
565559
func isEvals(user cshAuth.CSHUserInfo) bool {
566-
return DEV_FORCE_IS_EVALS || containsString(user.Groups, "eboard-evaluations")
560+
return DEV_FORCE_IS_EVALS || slices.Contains(user.Groups, "eboard-evaluations")
561+
}
562+
563+
func isChair(user cshAuth.CSHUserInfo) bool {
564+
return DEV_FORCE_IS_CHAIR || slices.Contains(user.Groups, "eboard-chairman")
567565
}
568566

569567
// canVote determines whether a user can cast a vote.
@@ -618,12 +616,3 @@ func hasOption(poll *database.Poll, option string) bool {
618616
}
619617
return false
620618
}
621-
622-
func containsString(arr []string, val string) bool {
623-
for _, a := range arr {
624-
if a == val {
625-
return true
626-
}
627-
}
628-
return false
629-
}

templates/create.tmpl

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
<!-- <link rel="stylesheet" href="https://themeswitcher.csh.rit.edu/api/get" /> -->
66
<link rel="stylesheet" href="https://assets.csh.rit.edu/csh-material-bootstrap/4.3.1/dist/csh-material-bootstrap.min.css" media="screen">
77

8-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
8+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
99

1010
<meta name="viewport" content="width=device-width, initial-scale=1.0">
1111
</head>
1212
<body>
1313
{{ template "nav" . }}
14-
14+
1515
<div class="container main p-5">
1616
<h2>Create Poll</h2>
1717
<form action="/create" method="POST">
@@ -59,11 +59,26 @@
5959
</div>
6060
<div class="form-group">
6161
<input
62-
type="checkbox"
63-
name="rankedChoice"
64-
value="true"
62+
type="radio"
63+
name="pollType"
64+
value="rankedChoice"
6565
>
6666
<span>Ranked Choice Vote</span>
67+
<input
68+
type="radio"
69+
name="pollType"
70+
value="eboard"
71+
class="ml-3"
72+
>
73+
<span>E-Board Vote</span>
74+
<input
75+
type="radio"
76+
name="pollType"
77+
value="simple"
78+
class="ml-3"
79+
checked="checked"
80+
>
81+
<span>Simple (Single-Choice) Vote</span>
6782
</div>
6883
<div class="form-group">
6984
<input

templates/result.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<h5>Number of Eligible Voters: {{ len .EligibleVoters }}</h5>
7070
<div id="votes-needed-for-quorum">
7171
{{/* This works currently because quorum type can only be set if gatekeep is required */}}
72-
{{ if not .Gatekeep }}
72+
{{ if not (len .EligibleVoters) }}
7373
<h5>No quorum required for this poll.</h5>
7474
{{ else }}
7575
<h5>Quorum Type: {{ .Quorum }}%</h5>

users.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,32 @@ func (client *OIDCClient) getAccessToken() int {
8787
}
8888

8989
func (client *OIDCClient) GetActiveUsers() []OIDCUser {
90+
return client.GetOIDCGroup("a97a191e-5668-43f5-bc0c-6eefc2b958a7")
91+
}
92+
93+
func (client *OIDCClient) GetEBoard() []OIDCUser {
94+
return client.GetOIDCGroup("47dd1a94-853c-426d-b181-6d0714074892")
95+
}
96+
97+
func (client *OIDCClient) GetOIDCGroup(groupID string) []OIDCUser {
9098
htclient := &http.Client{}
9199
//active
92-
req, err := http.NewRequest("GET", client.providerBase+"/auth/admin/realms/csh/groups/a97a191e-5668-43f5-bc0c-6eefc2b958a7/members", nil)
100+
req, err := http.NewRequest("GET", client.providerBase+"/auth/admin/realms/csh/groups/"+groupID+"/members", nil)
93101
if err != nil {
94-
logging.Logger.WithFields(logrus.Fields{"method": "GetActiveUsers"}).Error(err)
102+
logging.Logger.WithFields(logrus.Fields{"method": "GetOIDCGroup"}).Error(err)
95103
return nil
96104
}
97105
req.Header.Add("Authorization", "Bearer "+client.accessToken)
98106
resp, err := htclient.Do(req)
99107
if err != nil {
100-
logging.Logger.WithFields(logrus.Fields{"method": "GetActiveUsers"}).Error(err)
108+
logging.Logger.WithFields(logrus.Fields{"method": "GetOIDCGroup"}).Error(err)
101109
return nil
102110
}
103111
defer resp.Body.Close()
104112
ret := make([]OIDCUser, 0)
105113
err = json.NewDecoder(resp.Body).Decode(&ret)
106114
if err != nil {
107-
logging.Logger.WithFields(logrus.Fields{"method": "GetActiveUsers"}).Error(err)
115+
logging.Logger.WithFields(logrus.Fields{"method": "GetOIDCGroup"}).Error(err)
108116
return nil
109117
}
110118
return ret

0 commit comments

Comments
 (0)