diff --git a/flake.lock b/flake.lock index aa1fdb4..29bf318 100644 --- a/flake.lock +++ b/flake.lock @@ -96,11 +96,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1716293225, - "narHash": "sha256-pU9ViBVE3XYb70xZx+jK6SEVphvt7xMTbm6yDIF4xPs=", + "lastModified": 1716330097, + "narHash": "sha256-8BO3B7e3BiyIDsaKA0tY8O88rClYRTjvAp66y+VBUeU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3eaeaeb6b1e08a016380c279f8846e0bd8808916", + "rev": "5710852ba686cc1fd0d3b8e22b3117d43ba374c2", "type": "github" }, "original": { diff --git a/go.mod b/go.mod index 7cc5a5a..81b89b2 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.22.0 require ( github.com/a-h/templ v0.2.697 + github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c github.com/golang-jwt/jwt/v4 v4.5.0 github.com/mattn/go-sqlite3 v1.14.22 github.com/rs/zerolog v1.32.0 diff --git a/go.sum b/go.sum index 252e699..fea993e 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/a-h/templ v0.2.697 h1:OILxtWvD0NRJaoCOiZCopRDPW8paroKlGsrAiHLykNE= github.com/a-h/templ v0.2.697/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8= +github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c h1:WqjRVgUO039eiISCjsZC4F9onOEV93DJAk6v33rsZzY= +github.com/beeper/libserv v0.0.0-20231231202820-c7303abfc32c/go.mod h1:b9FFm9y4mEm36G8ytVmS1vkNzJa0KepmcdVY+qf7qRU= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/internal/application.go b/internal/application.go index 798c49e..d6193be 100644 --- a/internal/application.go +++ b/internal/application.go @@ -1,18 +1,24 @@ package internal import ( + "context" "fmt" "html/template" "net/http" "regexp" "strings" + "github.com/a-h/templ" + "github.com/beeper/libserv/pkg/requestlog" "github.com/rs/zerolog" "github.com/rs/zerolog/hlog" "github.com/sendgrid/sendgrid-go" "github.com/ColoradoSchoolOfMines/mineshspc.com/database" "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/config" + "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/contextkeys" + "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates" + "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates/partials" "github.com/ColoradoSchoolOfMines/mineshspc.com/website" ) @@ -91,6 +97,19 @@ type renderInfo struct { RedirectIfLoggedIn bool } +func (a *Application) SettingsContextMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + user, err := a.GetLoggedInTeacher(r) + if err == nil { + ctx = context.WithValue(ctx, contextkeys.ContextKeyLoggedInTeacher, user) + } + ctx = context.WithValue(ctx, contextkeys.ContextKeyRegistrationEnabled, a.Config.RegistrationEnabled) + ctx = context.WithValue(ctx, contextkeys.ContextKeyHostedByHTML, a.Config.HostedByHTML) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + func (a *Application) Start() { a.Log.Info().Msg("connecting to sendgrid") a.SendGridClient = sendgrid.NewSendClient(a.Config.SendgridAPIKey) @@ -98,29 +117,34 @@ func (a *Application) Start() { a.Log.Info().Msg("Starting router") router := http.NewServeMux() + router.Handle("GET /static/", http.FileServer(http.FS(website.StaticFS))) // Serve static files noArgs := func(r *http.Request) map[string]any { return nil } // Static pages staticPages := map[string]struct { - Template string - ArgGenerator func(r *http.Request) map[string]any + title string + pageName partials.PageName + content templ.Component }{ - "/{$}": {"home.html", noArgs}, - "/info": {"info.html", noArgs}, - "/authors": {"authors.html", noArgs}, - "/rules": {"rules.html", noArgs}, - "/register": {"register.html", noArgs}, - "/faq": {"faq.html", noArgs}, - "/archive": {"archive.html", a.GetArchiveTemplate}, + "GET /{$}": {"Home", partials.PageNameHome, templates.Home()}, + "GET /info/": {"Info", partials.PageNameInfo, templates.Info()}, + "GET /authors/": {"Authors", "", templates.Authors()}, + "GET /rules/": {"Rules", partials.PageNameRules, templates.Rules()}, + "GET /register/": {"Register", partials.PageNameRegister, templates.Register()}, + "GET /faq/": {"FAQ", partials.PageNameFAQ, templates.FAQ()}, + "GET /archive/": {"Archive", partials.PageNameArchive, templates.Archive(archiveInfo)}, } - for path, templateInfo := range staticPages { - router.HandleFunc("GET "+path, a.ServeTemplate(a.Log, templateInfo.Template, templateInfo.ArgGenerator)) + for path, pageInfo := range staticPages { + router.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + if len(pageInfo.pageName) > 0 { + ctx = context.WithValue(ctx, contextkeys.ContextKeyPageName, pageInfo.pageName) + } + templates.Base(pageInfo.title, pageInfo.content).Render(ctx, w) + }) } - // Serve static files - router.Handle("GET /static/", http.FileServer(http.FS(website.StaticFS))) - // Redirect pages redirects := map[string]string{ "/register/teacher": "/register/teacher/createaccount", @@ -243,7 +267,10 @@ func (a *Application) Start() { router.HandleFunc("GET /volunteer/scan", a.ServeTemplate(a.Log, "volunteerscan.html", a.GetVolunteerScanTemplate)) router.HandleFunc("GET /volunteer/checkin", a.HandleVolunteerCheckIn) + // Middleware goes from bottom up because it's doing function composition. var handler http.Handler = router + handler = a.SettingsContextMiddleware(handler) + handler = requestlog.AccessLogger(false)(handler) handler = hlog.RequestIDHandler("request_id", "RequestID")(handler) handler = hlog.NewHandler(*a.Log)(handler) diff --git a/internal/archive.go b/internal/archive.go index 7c8a73b..74ac427 100644 --- a/internal/archive.go +++ b/internal/archive.go @@ -1,227 +1,198 @@ package internal import ( - "net/http" + "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates" ) -type Link struct { - URL string - Title string -} - -type WinningTeam struct { - Place string - Name string - School string - Location string -} - -type CompetitionResult struct { - Name string - Shortname string - Teams []WinningTeam -} - -type YearInfo struct { - Year int - RecapParagraphs []string - Links []Link - Results []CompetitionResult -} - -func (a *Application) GetArchiveTemplate(*http.Request) map[string]any { - return map[string]any{ - "YearInfo": []YearInfo{ +var archiveInfo = []templates.YearInfo{ + { + Year: 2024, + RecapParagraphs: []string{ + "The 2024 competition returned to an in-person only competition, but we also had an open division. We gave a separate set of prizes for teams consisting of only first-time competitors. We did not award prizes for the open division.", + "The in-person competition had 27 teams while the open division had 31 teams.", + }, + Links: []templates.Link{ + {URL: "/static/2024-solutions.pdf", Title: "Solution Sketch Slides"}, + {URL: "https://sumnerevans.com/posts/school/2024-hspc/", Title: "Competition Recap and Solution Sketches"}, + {URL: "https://mines-hspc.kattis.com/contests/mines-hspc24/problems", Title: "Problems"}, + }, + Results: []templates.CompetitionResult{ { - Year: 2024, - RecapParagraphs: []string{ - "The 2024 competition returned to an in-person only competition, but we also had an open division. We gave a separate set of prizes for teams consisting of only first-time competitors. We did not award prizes for the open division.", - "The in-person competition had 27 teams while the open division had 31 teams.", - }, - Links: []Link{ - {"/static/2024-solutions.pdf", "Solution Sketch Slides"}, - {"https://sumnerevans.com/posts/school/2024-hspc/", "Competition Recap and Solution Sketches"}, - {"https://mines-hspc.kattis.com/contests/mines-hspc24/problems", "Problems"}, - }, - Results: []CompetitionResult{ - { - Name: "Overall Winners", - Shortname: "Overall", - Teams: []WinningTeam{ - {"1st", "Innovation Center 1", "Innovation Center SVVSD", "Longmont"}, - {"2nd", "Sigma Scripters", "Arapahoe High School", "Centennial"}, - {"3nd", "CyberRebels2", "Columbine High School", "Littleton"}, - }, - }, - { - Name: "First-Time Team Winners", - Shortname: "FirstTime", - Teams: []WinningTeam{ - {"1st", "Loopy Groupies", "Chatfield Senior High School", "Littleton"}, - {"2nd", "Lorem Ipsum", "Warren Tech", "Lakewood"}, - {"3nd", "the cows(mooooooooooooo)", "Cherry Creek High School", "Greenwood Village"}, - }, - }, + Name: "Overall Winners", + Shortname: "Overall", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Innovation Center 1", School: "Innovation Center SVVSD", Location: "Longmont"}, + {Place: "2nd", Name: "Sigma Scripters", School: "Arapahoe High School", Location: "Centennial"}, + {Place: "3nd", Name: "CyberRebels2", School: "Columbine High School", Location: "Littleton"}, }, }, { - Year: 2023, - RecapParagraphs: []string{ - "The 2023 competition again featured two divisions: beginner and advanced. As with 2022, it was a hybrid competition, but we awarded prizes for both in-person and remote winners in both divisions.", - "The advanced division featured 31 teams, while the beginner division had 34 teams.", - }, - Links: []Link{ - {"/static/2023-solutions.pdf", "Solution Sketch Slides"}, - {"https://sumnerevans.com/posts/school/2023-hspc/", "Competition Recap and Solution Sketches"}, - {"https://mines23advanced.kattis.com/problems", "Advanced Problems"}, - {"https://mines23beginner.kattis.com/problems", "Beginner Problems"}, - }, - Results: []CompetitionResult{ - { - Name: "Advanced In-Person", - Shortname: "AdvancedInPerson", - Teams: []WinningTeam{ - {"1st", "Code Rats", "Futures Lab", "Fort Collins, Colorado"}, - {"2nd", "The Spanish Inquisition", "Regis Jesuit High School", "Aurora, Colorado"}, - {"3nd", "CA is 202", "Colorado Academy", "Denver, Colorado"}, - }, - }, - { - Name: "Beginner In-Person", - Shortname: "BeginnerInPerson", - Teams: []WinningTeam{ - {"1st", "Spaghetti Code and Meatballs", "Warren Tech", "Lakewood, Colorado"}, - {"2nd", "Innovation Center 1", "Innovation Center SVVSD", "Longmont, Colorado"}, - {"3nd", "Team LuLo", "Colorado Academy", "Denver, Colorado"}, - }, - }, - { - Name: "Advanced Remote", - Shortname: "AdvancedRemote", - Teams: []WinningTeam{ - {"1st", "River Hill Team #1", "River Hill High School", "Clarksville, Maryland"}, - {"2nd", "CreekCyberBruins", "Cherry Creek High School", "Greenwood Village, Colorado"}, - {"3nd", "JMS", "Bergen County Academies", "Bergen County, New Jersey"}, - }, - }, - { - Name: "Beginner Remote", - Shortname: "BeginnerRemote", - Teams: []WinningTeam{ - {"1st", "Wormhole", "Voice of Calling NPO", "Northridge, California"}, - {"2nd", "Lineup", "Voice of Calling NPO", "Northridge, California"}, - {"3nd", "River Hill Team #2", "River Hill High School", "Clarksville, Maryland"}, - }, - }, + Name: "First-Time Team Winners", + Shortname: "FirstTime", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Loopy Groupies", School: "Chatfield Senior High School", Location: "Littleton"}, + {Place: "2nd", Name: "Lorem Ipsum", School: "Warren Tech", Location: "Lakewood"}, + {Place: "3nd", Name: "the cows(mooooooooooooo)", School: "Cherry Creek High School", Location: "Greenwood Village"}, }, }, + }, + }, + { + Year: 2023, + RecapParagraphs: []string{ + "The 2023 competition again featured two divisions: beginner and advanced. As with 2022, it was a hybrid competition, but we awarded prizes for both in-person and remote winners in both divisions.", + "The advanced division featured 31 teams, while the beginner division had 34 teams.", + }, + Links: []templates.Link{ + {URL: "/static/2023-solutions.pdf", Title: "Solution Sketch Slides"}, + {URL: "https://sumnerevans.com/posts/school/2023-hspc/", Title: "Competition Recap and Solution Sketches"}, + {URL: "https://mines23advanced.kattis.com/problems", Title: "Advanced Problems"}, + {URL: "https://mines23beginner.kattis.com/problems", Title: "Beginner Problems"}, + }, + Results: []templates.CompetitionResult{ { - Year: 2022, - RecapParagraphs: []string{ - "The 2022 competition was the first to feature two divisions: a beginner division and an advanced division. It was also the first hybrid competition with both remote and in-person contestants.", - "The advanced division had 26 teams, while the beginner division had 39 teams. Due to the number of teams, we decided to give awards to first place through fourth place.", - }, - Links: []Link{ - {"https://sumnerevans.com/posts/school/2022-hspc/", "Competition Recap and Solution Sketches"}, - {"https://mines22advanced.kattis.com/problems", "Advanced Problems"}, - {"https://mines22beginner.kattis.com/problems", "Beginner Problems"}, - }, - Results: []CompetitionResult{ - { - Name: "Advanced", - Teams: []WinningTeam{ - {"1st", "Pen A Team", "PEN Academy", "Cresskill, New Jersey"}, - {"2nd", "Cherry Creek Cobras", "Cherry Creek High School", "Greenwood Village, Colorado"}, - {"3nd", "River Hill Team 1", "River Hill High School", "Clarksville, Maryland"}, - {"4th", "The Spanish Inquisition", "Regis Jesuit High School", "Aurora, Colorado"}, - }, - }, - { - Name: "Beginner", - Teams: []WinningTeam{ - {"1st", "LLL", "Future Forward at Bollman", "Thornton, Colorado"}, - {"2nd", "Error 404: Name not found", "Colorado Academy", "Denver, Colorado"}, - {"3nd", "Liberty 1", "Liberty Common School", "Fort Collins, Colorado"}, - {"4th", "Cool Cats", "Arvada West High School", "Arvada, Colorado"}, - }, - }, + Name: "Advanced In-Person", + Shortname: "AdvancedInPerson", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Code Rats", School: "Futures Lab", Location: "Fort Collins, Colorado"}, + {Place: "2nd", Name: "The Spanish Inquisition", School: "Regis Jesuit High School", Location: "Aurora, Colorado"}, + {Place: "3nd", Name: "CA is 202", School: "Colorado Academy", Location: "Denver, Colorado"}, }, }, { - Year: 2021, - RecapParagraphs: []string{ - "The 2021 competition was an all-remote competition featuring 55 teams from across the nation.", - }, - Links: []Link{ - {"https://sumnerevans.com/posts/school/2021-hspc/", "Competition Recap and Solution Sketches"}, - {"https://mines21.kattis.com/problems", "Problems"}, - }, - Results: []CompetitionResult{ - { - Teams: []WinningTeam{ - {"1st", "River Hill HS Team 1", "River Hill High School", "Clarksville, Maryland"}, - {"2nd", "PEN A Team", "PEN Academy", "Cresskill, New Jersey"}, - {"3nd", "River Hill HS Team 2", "River Hill High School", "Clarksville, Maryland"}, - }, - }, + Name: "Beginner In-Person", + Shortname: "BeginnerInPerson", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Spaghetti Code and Meatballs", School: "Warren Tech", Location: "Lakewood, Colorado"}, + {Place: "2nd", Name: "Innovation Center 1", School: "Innovation Center SVVSD", Location: "Longmont, Colorado"}, + {Place: "3nd", Name: "Team LuLo", School: "Colorado Academy", Location: "Denver, Colorado"}, }, }, { - Year: 2020, - RecapParagraphs: []string{ - "Due to COVID, the 2020 competition was the first all-remote HSPC competition. The competition featured 30 teams.", + Name: "Advanced Remote", + Shortname: "AdvancedRemote", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "River Hill Team #1", School: "River Hill High School", Location: "Clarksville, Maryland"}, + {Place: "2nd", Name: "CreekCyberBruins", School: "Cherry Creek High School", Location: "Greenwood Village, Colorado"}, + {Place: "3nd", Name: "JMS", School: "Bergen County Academies", Location: "Bergen County, New Jersey"}, }, - Links: []Link{ - {"https://sumnerevans.com/posts/school/2020-hspc/", "Competition Recap and Solution Sketches"}, - {"https://mines20.kattis.com/problems", "Problems"}, - }, - Results: []CompetitionResult{ - { - Teams: []WinningTeam{ - {"1st", "Installation Wizards", "STEM School Highlands Ranch", "Highlands Ranch, Colorado"}, - {"2nd", "i", "STEM School Highlands Ranch", "Highlands Ranch, Colorado"}, - {"3nd", "Sun Devils", "Kent Denver", "Denver, Colorado"}, - }, - }, + }, + { + Name: "Beginner Remote", + Shortname: "BeginnerRemote", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Wormhole", School: "Voice of Calling NPO", Location: "Northridge, California"}, + {Place: "2nd", Name: "Lineup", School: "Voice of Calling NPO", Location: "Northridge, California"}, + {Place: "3nd", Name: "River Hill Team #2", School: "River Hill High School", Location: "Clarksville, Maryland"}, }, }, + }, + }, + { + Year: 2022, + RecapParagraphs: []string{ + "The 2022 competition was the first to feature two divisions: a beginner division and an advanced division. It was also the first hybrid competition with both remote and in-person contestants.", + "The advanced division had 26 teams, while the beginner division had 39 teams. Due to the number of teams, we decided to give awards to first place through fourth place.", + }, + Links: []templates.Link{ + {URL: "https://sumnerevans.com/posts/school/2022-hspc/", Title: "Competition Recap and Solution Sketches"}, + {URL: "https://mines22advanced.kattis.com/problems", Title: "Advanced Problems"}, + {URL: "https://mines22beginner.kattis.com/problems", Title: "Beginner Problems"}, + }, + Results: []templates.CompetitionResult{ { - Year: 2019, - RecapParagraphs: []string{ - "The second ever CS@Mines High School Programming Competition featured 22 teams from all around Colorado and from as far as Steamboat Springs.", + Name: "Advanced", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Pen A Team", School: "PEN Academy", Location: "Cresskill, New Jersey"}, + {Place: "2nd", Name: "Cherry Creek Cobras", School: "Cherry Creek High School", Location: "Greenwood Village, Colorado"}, + {Place: "3nd", Name: "River Hill Team 1", School: "River Hill High School", Location: "Clarksville, Maryland"}, + {Place: "4th", Name: "The Spanish Inquisition", School: "Regis Jesuit High School", Location: "Aurora, Colorado"}, }, - Links: []Link{ - {"https://sumnerevans.com/posts/school/2019-hspc/", "Competition Recap and Solution Sketches"}, - {"https://mines19.kattis.com/problems", "Problems"}, + }, + { + Name: "Beginner", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "LLL", School: "Future Forward at Bollman", Location: "Thornton, Colorado"}, + {Place: "2nd", Name: "Error 404: Name not found", School: "Colorado Academy", Location: "Denver, Colorado"}, + {Place: "3nd", Name: "Liberty 1", School: "Liberty Common School", Location: "Fort Collins, Colorado"}, + {Place: "4th", Name: "Cool Cats", School: "Arvada West High School", Location: "Arvada, Colorado"}, }, - Results: []CompetitionResult{ - { - Teams: []WinningTeam{ - {"1st", "STEM Team 1", "STEM School Highlands Ranch", "Highlands Ranch, Colorado"}, - {"2nd", "IntrospectionExceptions", "Colorado Academy", "Lakewood, Colorado"}, - {"3nd", "Team 2", "?", "?"}, - }, - }, + }, + }, + }, + { + Year: 2021, + RecapParagraphs: []string{ + "The 2021 competition was an all-remote competition featuring 55 teams from across the nation.", + }, + Links: []templates.Link{ + {URL: "https://sumnerevans.com/posts/school/2021-hspc/", Title: "Competition Recap and Solution Sketches"}, + {URL: "https://mines21.kattis.com/problems", Title: "Problems"}, + }, + Results: []templates.CompetitionResult{ + { + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "River Hill HS Team 1", School: "River Hill High School", Location: "Clarksville, Maryland"}, + {Place: "2nd", Name: "PEN A Team", School: "PEN Academy", Location: "Cresskill, New Jersey"}, + {Place: "3nd", Name: "River Hill HS Team 2", School: "River Hill High School", Location: "Clarksville, Maryland"}, }, }, + }, + }, + { + Year: 2020, + RecapParagraphs: []string{ + "Due to COVID, the 2020 competition was the first all-remote HSPC competition. The competition featured 30 teams.", + }, + Links: []templates.Link{ + {URL: "https://sumnerevans.com/posts/school/2020-hspc/", Title: "Competition Recap and Solution Sketches"}, + {URL: "https://mines20.kattis.com/problems", Title: "Problems"}, + }, + Results: []templates.CompetitionResult{ { - Year: 2018, - RecapParagraphs: []string{ - "The first ever CS@Mines High School Programming Competition featured 22 teams.", + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "Installation Wizards", School: "STEM School Highlands Ranch", Location: "Highlands Ranch, Colorado"}, + {Place: "2nd", Name: "i", School: "STEM School Highlands Ranch", Location: "Highlands Ranch, Colorado"}, + {Place: "3nd", Name: "Sun Devils", School: "Kent Denver", Location: "Denver, Colorado"}, }, - Links: []Link{ - {"https://mines18.kattis.com/problems", "Problems"}, + }, + }, + }, + { + Year: 2019, + RecapParagraphs: []string{ + "The second ever CS@Mines High School Programming Competition featured 22 teams from all around Colorado and from as far as Steamboat Springs.", + }, + Links: []templates.Link{ + {URL: "https://sumnerevans.com/posts/school/2019-hspc/", Title: "Competition Recap and Solution Sketches"}, + {URL: "https://mines19.kattis.com/problems", Title: "Problems"}, + }, + Results: []templates.CompetitionResult{ + { + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "STEM Team 1", School: "STEM School Highlands Ranch", Location: "Highlands Ranch, Colorado"}, + {Place: "2nd", Name: "IntrospectionExceptions", School: "Colorado Academy", Location: "Lakewood, Colorado"}, + {Place: "3nd", Name: "Team 2", School: "?", Location: "?"}, }, - Results: []CompetitionResult{ - { - Teams: []WinningTeam{ - {"1st", "The Crummies", "Warren Tech", "Arvada, Colorado"}, - {"2nd", "The Bean Beans", "Colorado Academy", "Lakewood, Colorado"}, - {"3nd", "Warriors", "Arapahoe High School", "Centennial, Colorado"}, - }, - }, + }, + }, + }, + { + Year: 2018, + RecapParagraphs: []string{ + "The first ever CS@Mines High School Programming Competition featured 22 teams.", + }, + Links: []templates.Link{ + {URL: "https://mines18.kattis.com/problems", Title: "Problems"}, + }, + Results: []templates.CompetitionResult{ + { + Teams: []templates.WinningTeam{ + {Place: "1st", Name: "The Crummies", School: "Warren Tech", Location: "Arvada, Colorado"}, + {Place: "2nd", Name: "The Bean Beans", School: "Colorado Academy", Location: "Lakewood, Colorado"}, + {Place: "3nd", Name: "Warriors", School: "Arapahoe High School", Location: "Centennial, Colorado"}, }, }, }, - } + }, } diff --git a/internal/contextkeys/keys.go b/internal/contextkeys/keys.go new file mode 100644 index 0000000..2d31ace --- /dev/null +++ b/internal/contextkeys/keys.go @@ -0,0 +1,10 @@ +package contextkeys + +type contextKey int + +const ( + ContextKeyLoggedInTeacher contextKey = iota + ContextKeyPageName + ContextKeyRegistrationEnabled + ContextKeyHostedByHTML +) diff --git a/internal/templates/archive.templ b/internal/templates/archive.templ new file mode 100644 index 0000000..fb1316c --- /dev/null +++ b/internal/templates/archive.templ @@ -0,0 +1,145 @@ +package templates + +import "strconv" + +type Link struct { + URL templ.SafeURL + Title string +} + +type WinningTeam struct { + Place string + Name string + School string + Location string +} + +type CompetitionResult struct { + Name string + Shortname string + Teams []WinningTeam +} + +type YearInfo struct { + Year int + RecapParagraphs []string + Links []Link + Results []CompetitionResult +} + +func accordionHeadingID(year int, shortname string) string { + return "heading" + strconv.Itoa(year) + shortname +} + +func accordionCollapseCSSID(year int, shortname string) string { + return "#" + accordionCollapseID(year, shortname) +} + +func accordionCollapseID(year int, shortname string) string { + return "winners" + strconv.Itoa(year) + shortname +} + +func trophyColor(place int) string { + switch place + 1 { + case 1: + return "#FFD700" + case 2: + return "#C0C0C0" + default: + return "#CD7F32" + } +} + +css trophyColorStyle(place int) { + color: { trophyColor(place) }; +} + +templ Archive(years []YearInfo) { +
+ Since 2018, the CS@Mines High School Programming + Competition has provided high school students an opportunity to + demonstrate their programming and problem solving skills in a + competitive environment. For more information on all of our competitions + and past problems, view + + competition summaries + . +
+{ p }
+ } ++ { team.School } • { team.Location } +
++ Note: This page is hidden on the website, but accessible at + mineshspc.com/authors. +
++ The CS@Mines High School Programming Competition is a competition for high + school students to write programs that solve problems. We model our programming + competition off well-known college-level competitions such as the + ACM ICPC, but bring an inviting set of + problems to the table suitable for high school students. +
++ Mines students are encouraged join our problem writing process. In the past, we + have had many authors from ACM, DECtech, and the CS@Mines department, as well + as help from alumni. All of our problems are reviewed by CS@Mines professors. +
++ See the sections below to get involved! + Problems are due December 31st, 2024. +
++ An outline of the problem process can be seen below. Once you join our GitHub + organization, a full contribution guide is available. The bulk of the + problem-making processes lies in making a well-defined problem and writing a + solution and test cases for it. +
++ +
++ Anyone can write and review problems! In the past, we have typically always + needed extra reviewers. Along with writing your own problem, you can help us by + writing solutions to other problems to ensure the best quality problems. +
++ We use GitHub to store + and collaborate on all of the problem code for HSPC. Due to the nature of the + competition, this repository is private. +
++ Please join our Discord server and + email erichards@mines.edu to get + involved in the problem writing process and to get access to the codebase. + Problem writers are also encouraged to volunteer the day of the competition. +
++ The best way to practice is by solving the problems from previous + competitions. You can find this all on our archive page. + We will use Kattis to run the competition, so all the problems will be given in a similar + input/output format to those seen in the + Open Kattis Archive. +
++ Teams must have a minimum of two students and a maximum of four students. +
++ We allow for two teams per school to attend our in-person competition + (we may allow more based on registration time and available space). + Any number of teams can join in the virtual open division. +
++ You can use C++, Python, Java or JavaScript. +
++ We recommend that everyone on your team know at least one of these languages in common. We + additionally recommend that teams practice submitting solutions on Kattis because the + input/output is done in a very specific manner that students may not be familiar with. +
++ Ensure that your team knows how to take in Kattis input before the competition day; + see the Kattis input tutorial { `for` } more details. + We will also send out a link to a practice competition to practice submitting code. +
++ Starting in the 2024 competition, we will only have one division for everyone. There will be 12-15 + problems, + and about a third will be "beginner", a third "novice", and a third "advanced" difficulty. +
++ "Beginner" problem concepts include: arithmetic, expressions, conditionals, and lists. +
++ "Novice" problems concepts include: loops, nested loops, lists, and maybe some data structures. +
++ "Advanced" problems concepts include: data structures (maps, sets) and algorithms (sorting/BFS/DFS) +
++ View + + last year's beginner + problems + and + + last year's advanced + problems + { `for` } a good idea of the range of difficulty for all of our problems. +
++ The competition computers run on Ubuntu and have the following programs + installed: +
++ IDEs: IntelliJ IDEA, + PyCharm, + Eclipse, + CLion. +
++ Editors: Visual Studio Code, + IDLE, + emacs, + vim +
++ The actual competition will be open for 4 hours, from 10:00 AM until 2:00 PM Mountain Time. + There are opening and closing ceremonies lasting an hour at the start and end of the competition. +
++ Yes. However, we find that using less computers benefits team problem solving ability as + there is more opportunity for collaboration. + See the rules { `for` } details. +
++ Engage in exciting problems at the Mines HSPC! + if RegistrationEnabled(ctx) { + Registration is now open for the Spring 2024 competition. + } +
+ if RegistrationEnabled(ctx) { ++ + The registration deadline is April 13th +
+ + Register Now for In-Person Competition + + } else { ++ + Registration for this year's competition has closed. + +
+ } + ++ The CS@Mines High School Programming Competition is a competition for high school + students to write programs that solve problems. +
++ Our programming competition is modelled after well-known college-level competitions + such as ICPC, but we make an inviting set of problems + suitable for high school students. +
++ Starting in the 2024 competition, we will have three tracks, in the + form of in-person beginner and advanced competitions, and an open to + anyone, all difficulty virtual division. +
+Saturday, April 20th, 2024
++ Mines is a public research university focused on science and engineering, located in Golden, + Colorado. + HSPC is organized and run by Mines ACM volunteers with funding from CS@Mines. +
++ In the 2024 competition, we were pleased to host: +
+ The competition will be at the Center for Technology and Learning Media (CTLM): + 1650 Arapahoe St, Golden, CO 80401 +
++ We recommend parking at the CTLM Parking Lot on 18th St, and will have volunteers around the + building waiting. Parking is free since it is a weekend. Please arrive before 9:00am (ideally + 8:30am) so that you can check in. The competition ends at 3:00pm. +
++ Once at CTLM, enter to the left of the “Gordian Knot,” and we will direct you to the opening + ceremony room, CTLM102. We will have volunteers and signs in case you get lost. +
++ See the Mines campus map here. +
++ Students will receive a QR code in their email which will act as their ticket for the competition. + A volunteer will scan the student's QR code to make sure all of the necessary forms have been + signed. +
++ We'll send out details via email a week before the competition describing how to test in the + practice competition. +
++ Food will be provided around 11:30am on competition day. +
++ Please email support@mineshspc.com with any questions. +
++ Before the competition.. +
++ During the competition.. +
++ After the competition.. +
+