Skip to content

Commit

Permalink
templates: render teacher login using templ
Browse files Browse the repository at this point in the history
Signed-off-by: Sumner Evans <me@sumnerevans.com>
  • Loading branch information
sumnerevans committed May 26, 2024
1 parent 3b9d034 commit 1ea1182
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 88 deletions.
19 changes: 15 additions & 4 deletions internal/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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},
Expand Down Expand Up @@ -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,
Expand Down
20 changes: 10 additions & 10 deletions internal/teacherlogin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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)
Expand All @@ -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
}

Expand Down
82 changes: 82 additions & 0 deletions internal/templates/register/teacher/login.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package teacher

templ Login(email string, errText templ.Component) {
<div class="container page-header">
<div class="row">
<div class="col">
<div class="header">
<h1>Login to Teacher Account</h1>
</div>
</div>
</div>
</div>
<div class="container page-content teacher">
<form method="post" action="/register/teacher/login" class="form-floating">
<div class="row">
<div class="col m-4 mb-0">
if errText != nil {
<div class="alert alert-danger" role="alert">
@errText
</div>
} else {
<div class="alert alert-secondary" role="alert">
Don't have an account? <a href="/register/teacher/createaccount">Create an account</a> instead.
</div>
}
</div>
</div>
<div class="row">
<div class="col m-4 mt-0">
<div class="card">
<h4 class="card-header">Login</h4>
<div class="card-body">
<div class="row">
<div class="col-12">
<div class="form-floating">
<input
type="email"
name="email-address"
class="form-control"
id="email-address"
placeholder="you@example.com"
required
value={ email }
/>
<label for="email-address">Email address</label>
<div class="form-text">
This site uses
<a href="https://en.wikipedia.org/wiki/Passwordless_authentication" target="_blank">
passwordless authentication
</a>.
You will receive a magic link in your email which will allow you to sign in to your account.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row text-center pb-4">
<div class="col-md-12">
<button type="submit" class="btn btn-lg btn-primary">Login</button>
</div>
</div>
</form>
</div>
}

templ LoginEmailDoesNotExist() {
That email doesn't exist in our system. Did you want to
<a href="/register/teacher/createaccount">create an account</a> instead?
}

templ LoginEmailNotConfirmed() {
<p>
That email hasn't been confirmed yet. Please confirm your email before logging in.
</p>
<p>
Lost your confirmation email? Send an email to
<a href="mailto:support@mineshspc.com">support@mineshspc.com</a>.
</p>
}
74 changes: 0 additions & 74 deletions website/templates/teacherlogin.html

This file was deleted.

0 comments on commit 1ea1182

Please sign in to comment.