Skip to content

Commit

Permalink
resend activation token
Browse files Browse the repository at this point in the history
  • Loading branch information
bueti committed Nov 15, 2023
1 parent e8c096a commit 418180c
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 2 deletions.
2 changes: 2 additions & 0 deletions cmd/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ func (app *application) registerRoutes() {
app.echo.GET("/users", app.listUsersHandler, app.authenticate, app.requireRole("admin"))
app.echo.GET("/users/:id", app.getUserHandler, app.authenticate)
app.echo.GET("/users/activate", app.activateUserHandler)
app.echo.GET("/users/resend-activation", app.getResendActivationLinkHandler)
app.echo.POST("/users/resend-activation", app.postResendActivationLinkHandler)
app.echo.GET("/signup", app.signupHandler)
app.echo.POST("/signup", app.createUserHandler)
app.echo.GET("/login", app.loginHandler)
Expand Down
39 changes: 39 additions & 0 deletions cmd/api/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,45 @@ func (app *application) activateUserHandler(c echo.Context) error {
return c.Render(http.StatusOK, "home.tmpl.html", data)
}

// getResendActivationLinkHandler handles the display of the resend activation link form.
func (app *application) getResendActivationLinkHandler(c echo.Context) error {
return c.Render(http.StatusOK, "resend_activation_link.tmpl.html", app.newTemplateData(c))
}

// postResendActivationLinkHandler handles the resending of an activation link.
func (app *application) postResendActivationLinkHandler(c echo.Context) error {
email := c.FormValue("email")
user, err := app.models.Users.GetByEmail(email)
if err != nil {
app.sessionManager.Put(c.Request().Context(), "flash_error", "No user exists with this email address.")
data := app.newTemplateData(c)
return c.Render(http.StatusBadRequest, "home.tmpl.html", data)
}

token, err := app.models.Tokens.New(user.ID, 3*24*time.Hour, model.ScopeActivation)
if err != nil {
app.sessionManager.Put(c.Request().Context(), "flash_error", "Internal Server Error. Please try again later.")
data := app.newTemplateData(c)
return c.Render(http.StatusBadRequest, "home.tmpl.html", data)
}

go func() {
data := map[string]any{
"activationToken": token.Plaintext,
"userID": user.ID,
}

err = app.mailer.Send(user.Email, "welcome.tmpl.html", data)
if err != nil {
log.Error(err)
}
}()

app.sessionManager.Put(c.Request().Context(), "flash", "The activation link has been resent. Please check your mailbox.")
data := app.newTemplateData(c)
return c.Render(http.StatusOK, "home.tmpl.html", data)
}

func (app *application) listUsersHandler(c echo.Context) error {
users, err := app.models.Users.List()
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions internal/model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ func (u *UserModel) GetByID(id uuid.UUID) (*User, error) {
return user, nil
}

// GetByEmail returns a user based on the email address.
func (u *UserModel) GetByEmail(email string) (*User, error) {
user := new(User)
result := u.DB.Where("email = ?", email).First(&user)
if result.Error != nil {
return nil, result.Error
}
return user, nil
}

func (u *UserModel) GetRole(c echo.Context) (string, error) {
user := c.Get("user").(*User)
return user.Role, nil
Expand Down
8 changes: 6 additions & 2 deletions ui/html/pages/login.tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,21 @@ <h2 class="text-2xl font-bold text-gray-900">Login</h2>
<input type="password" name="password" id="password" placeholder="Password"
class="px-4 py-3 rounded-lg shadow-lg focus:outline-none focus:shadow-outline"/>
</div>
<!-- remember me button -->
<!-- remember me button
<div class="flex items-center mt-4">
<input type="checkbox" name="remember" id="remember" class="mr-2">
<label for="remember" class="text-gray-600">Remember Me</label>
</div>
<div class="mt-6">
-->
<div>
<button type="submit"
class="px-5 py-3 mt-8 font-medium text-indigo-600 bg-white rounded-md shadow-lg hover:bg-indigo-50">
Login
</button>
</div>
<div class="flex items-center justify-between mt-4">
<a href="/users/resend-activation" class="text-xs text-gray-500 hover:underline">Resend Activation Token</a>
</div>
</form>
{{template "twoGridFoot" .}}
{{end}}
22 changes: 22 additions & 0 deletions ui/html/pages/resend_activation_link.tmpl.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{define "title"}}Resend Activation Token{{end}}

{{define "main"}}
{{template "twoGridHead" .}}
<h2 class="text-2xl font-bold text-gray-900">Resend Activation Token</h2>
<p class="mt-4 text-gray-600">Please enter your email address below to resend your activation token.</p>
<form class="mt-8" action="/users/resend-activation" method="post">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<div class="flex flex-col">
<label for="email" class="hidden">Email</label>
<input type="email" name="email" id="email" placeholder="Email"
class="px-4 py-3 rounded-lg shadow-lg focus:outline-none focus:shadow-outline"/>
</div>
<div class="mt-6">
<button type="submit"
class="px-5 py-3 mt-8 font-medium text-indigo-600 bg-white rounded-md shadow-lg hover:bg-indigo-50">
Resend Activation Token
</button>
</div>
</form>
{{template "twoGridFoot" .}}
{{end}}
10 changes: 10 additions & 0 deletions ui/static/css/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,11 @@ video {
line-height: 1.75rem;
}

.text-xs {
font-size: 0.75rem;
line-height: 1rem;
}

.font-bold {
font-weight: 700;
}
Expand All @@ -815,6 +820,11 @@ video {
color: rgb(156 163 175 / var(--tw-text-opacity));
}

.text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}

.text-gray-600 {
--tw-text-opacity: 1;
color: rgb(75 85 99 / var(--tw-text-opacity));
Expand Down

0 comments on commit 418180c

Please sign in to comment.