From 1ea1182f7ac66bf616e096f7a460cba5a8b1bc9f Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sun, 26 May 2024 16:44:32 -0600 Subject: [PATCH] templates: render teacher login using templ Signed-off-by: Sumner Evans --- internal/application.go | 19 ++++- internal/teacherlogin.go | 20 ++--- .../templates/register/teacher/login.templ | 82 +++++++++++++++++++ website/templates/teacherlogin.html | 74 ----------------- 4 files changed, 107 insertions(+), 88 deletions(-) create mode 100644 internal/templates/register/teacher/login.templ delete mode 100644 website/templates/teacherlogin.html diff --git a/internal/application.go b/internal/application.go index 139392b..406ddb2 100644 --- a/internal/application.go +++ b/internal/application.go @@ -19,6 +19,7 @@ import ( "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/contextkeys" "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates" "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates/partials" + registerteacher "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates/register/teacher" "github.com/ColoradoSchoolOfMines/mineshspc.com/website" ) @@ -31,7 +32,6 @@ type Application struct { ConfirmEmailRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) VolunteerConfirmEmailRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) AdminConfirmEmailRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) - TeacherLoginRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) EmailLoginRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) StudentConfirmInfoRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) TeamAddMemberRenderer func(w http.ResponseWriter, r *http.Request, extraData map[string]any) @@ -157,8 +157,21 @@ func (a *Application) Start() { router.Handle("GET /register/student/", http.RedirectHandler("/", http.StatusTemporaryRedirect)) router.Handle("GET /register/parent/", http.RedirectHandler("/", http.StatusTemporaryRedirect)) + router.HandleFunc("GET /register/teacher/login", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + if teacher, ok := ctx.Value(contextkeys.ContextKeyLoggedInTeacher).(*database.Teacher); ok { + if teacher.SchoolCity == "" || teacher.SchoolName == "" || teacher.SchoolState == "" { + http.Redirect(w, r, "/register/teacher/schoolinfo", http.StatusSeeOther) + } else { + http.Redirect(w, r, "/register/teacher/teams", http.StatusSeeOther) + } + } + + templates.Base("Teacher Login", registerteacher.Login("", nil)).Render(ctx, w) + }) + router.HandleFunc("POST /register/teacher/login", a.HandleTeacherLogin) + // Registration renderers - a.TeacherLoginRenderer = a.ServeTemplateExtra(a.Log, "teacherlogin.html", a.GetEmailLoginTemplate) a.TeacherCreateAccountRenderer = a.ServeTemplateExtra(a.Log, "teachercreateaccount.html", a.GetTeacherCreateAccountTemplate) a.ConfirmEmailRenderer = a.ServeTemplateExtra(a.Log, "confirmemail.html", a.GetEmailLoginTemplate) a.VolunteerConfirmEmailRenderer = a.ServeTemplateExtra(a.Log, "volunteerconfirmemail.html", a.GetEmailLoginTemplate) @@ -170,7 +183,6 @@ func (a *Application) Start() { registrationPages := map[string]renderInfo{ "/register/teacher/confirmemail": {a.ConfirmEmailRenderer, true}, "/register/teacher/createaccount": {a.TeacherCreateAccountRenderer, true}, - "/register/teacher/login": {a.TeacherLoginRenderer, true}, "/register/teacher/schoolinfo": {a.ServeTemplateExtra(a.Log, "schoolinfo.html", a.GetTeacherSchoolInfoTemplate), false}, "/register/teacher/teams": {a.ServeTemplateExtra(a.Log, "teams.html", a.GetTeacherTeamsTemplate), false}, "/register/teacher/team/edit": {a.ServeTemplateExtra(a.Log, "teamedit.html", a.GetTeacherTeamEditTemplate), false}, @@ -221,7 +233,6 @@ func (a *Application) Start() { // Form Post Handlers formHandlers := map[string]func(w http.ResponseWriter, r *http.Request){ - "/register/teacher/login": a.HandleTeacherLogin, "/register/teacher/createaccount": a.HandleTeacherCreateAccount, "/register/teacher/schoolinfo": a.HandleTeacherSchoolInfo, "/register/teacher/team/edit": a.HandleTeacherTeamEdit, diff --git a/internal/teacherlogin.go b/internal/teacherlogin.go index 28bded3..488e4ad 100644 --- a/internal/teacherlogin.go +++ b/internal/teacherlogin.go @@ -10,6 +10,9 @@ import ( "github.com/golang-jwt/jwt/v4" "github.com/sendgrid/sendgrid-go/helpers/mail" + + "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates" + registerteacher "github.com/ColoradoSchoolOfMines/mineshspc.com/internal/templates/register/teacher" ) type Issuer string @@ -35,7 +38,9 @@ func (a *Application) GetEmailLoginTemplate(r *http.Request) map[string]any { } func (a *Application) CreateEmailLoginJWT(email string) *jwt.Token { - // TODO invent some way to make this a one-time token + // TODO invent some way to make this a one-time token (maybe just add extra + // random token in here and then store all of the tokens we have seen in + // RAM) return jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.RegisteredClaims{ Issuer: string(IssuerEmailLogin), Subject: email, @@ -45,6 +50,7 @@ func (a *Application) CreateEmailLoginJWT(email string) *jwt.Token { func (a *Application) HandleTeacherLogin(w http.ResponseWriter, r *http.Request) { log := a.Log.With().Str("page_name", "teacher_create_account").Logger() + ctx := log.WithContext(r.Context()) if err := r.ParseForm(); err != nil { log.Err(err).Msg("failed to parse form") w.WriteHeader(http.StatusBadRequest) @@ -59,20 +65,14 @@ func (a *Application) HandleTeacherLogin(w http.ResponseWriter, r *http.Request) } log = log.With().Str("email", emailAddress).Logger() - teacher, err := a.DB.GetTeacherByEmail(r.Context(), emailAddress) + teacher, err := a.DB.GetTeacherByEmail(ctx, emailAddress) if err != nil { log.Warn().Err(err).Msg("failed to find teacher by email") - a.TeacherLoginRenderer(w, r, map[string]any{ - "Email": emailAddress, - "EmailNotFound": true, - }) + templates.Base("Teacher Login", registerteacher.Login(emailAddress, registerteacher.LoginEmailDoesNotExist())).Render(ctx, w) return } else if !teacher.EmailConfirmed { log.Warn().Err(err).Msg("teacher email not confirmed, not sending login code to avoid amplification attacks") - a.TeacherLoginRenderer(w, r, map[string]any{ - "Email": emailAddress, - "EmailNotConfirmed": true, - }) + templates.Base("Teacher Login", registerteacher.Login(emailAddress, registerteacher.LoginEmailNotConfirmed())).Render(ctx, w) return } diff --git a/internal/templates/register/teacher/login.templ b/internal/templates/register/teacher/login.templ new file mode 100644 index 0000000..1ca651f --- /dev/null +++ b/internal/templates/register/teacher/login.templ @@ -0,0 +1,82 @@ +package teacher + +templ Login(email string, errText templ.Component) { + +
+
+
+
+ if errText != nil { + + } else { + + } +
+
+
+
+
+

Login

+
+
+
+
+ + +
+ This site uses + + passwordless authentication + . + You will receive a magic link in your email which will allow you to sign in to your account. +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+} + +templ LoginEmailDoesNotExist() { + That email doesn't exist in our system. Did you want to + create an account instead? +} + +templ LoginEmailNotConfirmed() { +

+ That email hasn't been confirmed yet. Please confirm your email before logging in. +

+

+ Lost your confirmation email? Send an email to + support@mineshspc.com. +

+} diff --git a/website/templates/teacherlogin.html b/website/templates/teacherlogin.html deleted file mode 100644 index b24ef7b..0000000 --- a/website/templates/teacherlogin.html +++ /dev/null @@ -1,74 +0,0 @@ -{{ define "title" }}Teacher Login{{ end }} - -{{ define "content" }} - - -
-
-
-
- {{ with .Data.EmailNotFound }} - - {{ else }} - {{ with .Data.EmailNotConfirmed }} - - {{ else }} - - {{ end }} - {{ end }} -
-
-
-
-
-

Login

-
-
-
-
- - -
- This site uses - passwordless authentication. - You will receive a magic link in your email which will allow you to sign in to your account. -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-{{ end }}