Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .vote.go.swp
Binary file not shown.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ COPY --from=0 /app/main main
COPY keys/sp-cert.pem keys/sp-cert.pem
COPY keys/sp-key.pem keys/sp-key.pem
COPY .env .env
ENV ENV=prod
ENV ENV=""
CMD ["/app/main"]
2 changes: 1 addition & 1 deletion docker-compose-saml.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
auth:
ports:
- 443:443
- 443:443
build:
dockerfile: Dockerfile.dev
command: air
Expand Down
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,13 @@ func (r *Router) index(w http.ResponseWriter, req *http.Request) {
if hasUserId {
row := r.db.QueryRow(`
UPDATE users SET last_seen_timestamp = strftime('%s', 'now') WHERE buck_id = ?1
RETURNING name_num, discord_id, added_to_mailinglist
RETURNING name_num, discord_id, added_to_mailinglist, is_admin
`, userId)
var nameNum string
var discordId sql.NullString
var isOnMailingList bool
err := row.Scan(&nameNum, &discordId, &isOnMailingList)
var isAdmin bool
err := row.Scan(&nameNum, &discordId, &isOnMailingList, &isAdmin)
if err != nil {
log.Println("Failed to get user:", err, userId)
http.Redirect(w, req, "/signout", http.StatusTemporaryRedirect)
Expand Down Expand Up @@ -190,6 +191,7 @@ func (r *Router) index(w http.ResponseWriter, req *http.Request) {
"canAttend": canAttend,
"hasLinkedDiscord": discordId.Valid,
"isOnMailingList": isOnMailingList,
"isAdmin": isAdmin,
})
if err != nil {
log.Println("Failed to render template:", err)
Expand Down
7 changes: 7 additions & 0 deletions migrations/seed.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
BEGIN;
INSERT OR REPLACE INTO users
(buck_id, discord_id, display_name, name_num, last_seen_timestamp, last_attended_timestamp, added_to_mailinglist, student, alum, employee, faculty, is_admin)
VALUES
(500123456, NULL, 'Brutus Buckeye', 'buckeye.1', NULL, NULL, 1,1,0,0,0,1);

INSERT OR REPLACE INTO users
(buck_id, discord_id, display_name, name_num, last_seen_timestamp, last_attended_timestamp, added_to_mailinglist, student, alum, employee, faculty)
VALUES
Expand Down Expand Up @@ -1001,3 +1007,4 @@ VALUES
(525119038,NULL,'Rickie Cheetam','cheetam.4576',1684794159,1652435455,0,1,0,1,0),
(506436165,6536698969953349102,'Brook Andreu','andreu.3878',1638836524,1651666692,0,1,1,1,0),
(533335732,NULL,'Gale Biggins','biggins.3347',1655272710,1663024697,1,1,0,0,1);
COMMIT;
75 changes: 43 additions & 32 deletions templates/admin-vote-edit-partial.html.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,42 @@
<p class="font-bold">Election Name</p>
<p>{{ .electionName }}</p>
<p class="font-bold">Candidates</p>
<ul class="flex flex-col gap-1 list-disc list-inside">
{{
range.candidates
}}
<li>{{ .Name }}{{ if $.done }}: {{ .Votes }}{{ end }}</li>
{{
end
}}
</ul>
<div class="relative overflow-x-auto">
<table class="w-full text-sm text-left rtl:text-right">
<thead class="dark:bg-gray-400">
<tr>
<th class="px-6 py-3">
Name
</th>
<th class="px-6 py-3">
Vote Count
</th>
<th class="px-6 py-3">
Percentage
</th>
</tr>
</thead>
<tbody>
{{
range .candidates
}}
<tr class="bg-white border-b dark:bg-gray-200 dark:border-gray-300 border-gray-200">
<th scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
{{ .Name }}
</th>
<td class="px-6 py-4">
{{ .Votes }}
</td>
<td class="px-6 py-4">
{{ printf "%.2f" .Percentage }}%
</td>
</tr>
{{
end
}}
</tbody>
</table>
</div>
<p>{{ .totalVotes }} total vote{{ if ne .totalVotes 1 }}s{{ end }}</p>
{{ if not .done }}
<a
Expand All @@ -26,28 +53,14 @@
{{ else }}
<div id="form">
<p class="font-bold">Election Name</p>
<input
type="text"
name="electionName"
value="{{ .electionName }}"
hx-trigger="input changed delay:500ms"
hx-patch="/admin/vote/{{ .electionId }}"
/>
<input type="text" name="electionName" value="{{ .electionName }}" hx-trigger="input changed delay:500ms" hx-patch="/admin/vote/{{ .electionId }}" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="New Name" required />
<p class="font-bold">Candidates</p>
<ul>
{{
range.candidates
}}
<li class="flex items-center before:content-['•'] before:mr-2 group">
<input
type="text"
name="candidateName"
value="{{ .Name }}"
hx-trigger="input changed delay:500ms"
hx-patch="/admin/vote/{{ $.electionId }}/{{ .Id }}"
/>
{{ range.candidates }}
<li class="flex items-center before:mr-2 group">
<input type="text" name="candidateName" value="{{ .Name }}" hx-trigger="input changed delay:500ms" hx-patch="/admin/vote/{{ $.electionId }}/{{ .Id }}" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="New Name" required />
<button
class="ml-1 text-red-700 hidden group-hover:block"
class="ml-1 text-red-700 group-hover:block"
hx-delete="/admin/vote/{{ $.electionId }}/{{ .Id }}"
hx-target="#form"
>
Expand All @@ -71,12 +84,10 @@
</svg>
</button>
</li>
{{
end
}}
{{ end }}
<li>
<button
class="italic"
class="secondary-button"
hx-put="/admin/vote/{{ .electionId }}"
hx-target="#form"
>
Expand Down
10 changes: 0 additions & 10 deletions templates/admin-vote-edit.html.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@
{{ if .done }}
<div>
<canvas id="candidatesChart"></canvas>
<div id="labels" class="hidden">
{{ range.candidates }}
<p>{{ .Name }}</p>
{{ end }}
</div>
<div id="datas" class="hidden">
{{ range.candidates }}
<p>{{ .Votes }}</p>
{{ end }}
</div>
<script>
(function () {
const candidatesChart = document.getElementById("candidatesChart");
Expand Down
95 changes: 65 additions & 30 deletions templates/admin-vote.html.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,70 @@
{{ define "admin" }}
<div class="card">
<div class="card-title">Admin Votes</div>
<div class="card-content">
<a hx-boost="true" href="/admin/vote/new" class="secondary-button"
>New Vote</a
>

<div>
<h1>Past Votes</h1>
<ul class="list-disc list-inside">
{{
range.pastElections
}}
<li>
<a
class="font-bold"
hx-boost="true"
href="/admin/vote/{{ .ElectionId }}"
>{{ .Name }}</a
>
{{ if .Published }}<em>published</em>{{ end }}

{{ if .Done }}
<em>completed {{ .DoneTime }}</em>
{{ end }}
</li>
{{
end
}}
</ul>
</div>
</div>
<a hx-boost="true" href="/admin/vote/new" class="secondary-button"
>New Vote</a
>
<div class="container">
<div class="subcard">
<h5 class="mb-3 text-base font-semibold">
Unpublished
</h5>
<ul>
{{ range.pastElections }}
<li>
{{ if and (not .Published) (not .Done) }}
<span class="flex-1 ms-3 whitespace-nowrap">
<a
hx-boost="true"
href="/admin/vote/{{ .ElectionId }}"
>{{ .Name }}</a
>
</span>
{{ end }}
</li>
{{ end }}
</ul>
</div>
<div class="subcard">
<h5 class="mb-3 text-base font-semibold">
Published
</h5>
<ul>
{{ range.pastElections }}
<li>
{{ if .Published }}
<span class="flex-1 ms-3 whitespace-nowrap">
<a
hx-boost="true"
href="/admin/vote/{{ .ElectionId }}"
>{{ .Name }}</a
>
</span>
{{ end }}
</li>
{{ end }}
</ul>
</div>
<div class="subcard">
<h5 class="mb-3 text-base font-semibold">
Closed
</h5>
<ul>
{{ range.pastElections }}
<li>
{{ if .Done }}
<span class="flex-1 ms-3 whitespace-nowrap">
<a
hx-boost="true"
href="/admin/vote/{{ .ElectionId }}"
>{{ .Name }}</a
>
</span>
{{ end }}
</li>
{{ end }}
</ul>
</div>
</div>
</div>
{{ end }}
2 changes: 2 additions & 0 deletions templates/base.html.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
@tailwind components;
@tailwind utilities;
.card { @apply shadow-md rounded-sm border; }
.container {@apply flex flex-col gap-4 p-2; }
.subcard { @apply w-full max-w-sm p-4 bg-white border border-gray-200 rounded-lg shadow-sm sm:p-6 dark:bg-gray-100 dark:border-gray-100; }
.card-title { @apply shadow-sm py-2 px-3 font-bold; }
.card-content { @apply py-2 px-3; }
.external-link { @apply text-blue-500; }
Expand Down
15 changes: 15 additions & 0 deletions templates/index.html.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,20 @@
</ul>
</div>
</div>
{{ if .isAdmin }}
<div class="card">
<div class="card-title">Admin Dashboard</div>
<div class="card-content">
<p class="mb-2">
You are an admin. Click
<a
class="external-link"
href="/admin"
>here</a
> to go to the admin page.
</p>
</div>
</div>
{{ end }}
</div>
{{ end }}
36 changes: 27 additions & 9 deletions vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,10 @@ func (r *Router) adminVoteEdit(w http.ResponseWriter, req *http.Request) {
done := timestamp > 1

type Candidate struct {
Id int
Name string
Votes int
Id int
Name string
Votes int
Percentage float64
}

var orderBy string
Expand Down Expand Up @@ -307,6 +308,15 @@ func (r *Router) adminVoteEdit(w http.ResponseWriter, req *http.Request) {
totalVotes += candidate.Votes
}

for i := range candidates {
if totalVotes > 0 {
percentage := (float64(candidates[i].Votes) * 100.0) / float64(totalVotes)
candidates[i].Percentage = percentage
} else {
candidates[i].Percentage = 0.0
}
}

if !published && req.Method == "PUT" {
candidate := Candidate{Name: "New Candidate"}
err := r.db.QueryRow("INSERT INTO candidates (election_id, name) VALUES (?, 'New Candidate') RETURNING candidate_id", electionId).Scan(&candidate.Id)
Expand Down Expand Up @@ -486,37 +496,45 @@ func (r *Router) adminVotePublish(w http.ResponseWriter, req *http.Request) {
}

type Candidate struct {
Id int
Name string
Id int
Name string
Votes int
Percentage float64
}

rows, err := r.db.Query("SELECT candidate_id, name FROM candidates WHERE election_id = ?", electionId)
rows, err := r.db.Query("SELECT candidate_id, name, votes FROM candidates WHERE election_id = ?", electionId)
if err != nil {
log.Println("Failed to get candidates:", err)
log.Println("Facandidateiled to get candidates:", err)
http.Error(w, "Failed to get candidates", http.StatusInternalServerError)
return
}
defer rows.Close()

var candidates []Candidate
totalVotes := 0

for rows.Next() {
var candidate Candidate
err = rows.Scan(&candidate.Id, &candidate.Name)
err = rows.Scan(&candidate.Id, &candidate.Name, &candidate.Votes)
if err != nil {
log.Println("Failed to get candidate:", err)
http.Error(w, "Failed to get candidate", http.StatusInternalServerError)
return
}
candidates = append(candidates, candidate)
totalVotes += candidate.Votes
}

for i := range candidates {
candidates[i].Percentage = 0.0
}

err = Templates.ExecuteTemplate(w, "admin-vote-edit-partial.html.tpl", map[string]any{
"published": true,
"electionName": electionName,
"electionId": electionId,
"candidates": candidates,
"totalVotes": 0,
"totalVotes": totalVotes,
})
if err != nil {
log.Println("Failed to render template:", err)
Expand Down