dnote/pkg/server/controllers/users.go
2021-01-06 21:29:06 +11:00

164 lines
3.8 KiB
Go

package controllers
import (
"net/http"
"github.com/dnote/dnote/pkg/server/app"
"github.com/dnote/dnote/pkg/server/config"
"github.com/dnote/dnote/pkg/server/database"
"github.com/dnote/dnote/pkg/server/log"
"github.com/dnote/dnote/pkg/server/views"
"github.com/pkg/errors"
)
// NewUsers creates a new Users controller.
// It panics if the necessary templates are not parsed.
func NewUsers(cfg config.Config, app *app.App) *Users {
return &Users{
NewView: views.NewView(cfg.PageTemplateDir, views.Config{Title: "Join", Layout: "base"}, "users/new"),
LoginView: views.NewView(cfg.PageTemplateDir, views.Config{Title: "Login", Layout: "base"}, "users/login"),
app: app,
}
}
// Users is a user controller.
type Users struct {
NewView *views.View
LoginView *views.View
app *app.App
}
// New renders user registration page
func (u *Users) New(w http.ResponseWriter, r *http.Request) {
var form RegistrationForm
parseURLParams(r, &form)
u.NewView.Render(w, r, form)
}
// RegistrationForm is the form data for registering
type RegistrationForm struct {
Email string `schema:"email"`
Password string `schema:"password"`
}
// Create handles register
func (u *Users) Create(w http.ResponseWriter, r *http.Request) {
vd := views.Data{}
var form RegistrationForm
if err := parseForm(r, &form); err != nil {
vd.SetAlert(err)
u.NewView.Render(w, r, vd)
return
}
user, err := u.app.CreateUser(form.Email, form.Password)
if err != nil {
handleHTMLError(w, r, err, "creating user", u.NewView, &vd)
return
}
session, err := u.app.SignIn(&user)
if err != nil {
handleHTMLError(w, r, err, "signing in a user", u.LoginView, &vd)
return
}
setSessionCookie(w, session.Key, session.ExpiresAt)
http.Redirect(w, r, "/", http.StatusFound)
if err := u.app.SendWelcomeEmail(form.Email); err != nil {
log.ErrorWrap(err, "sending welcome email")
}
}
// LoginForm is the form data for log in
type LoginForm struct {
Email string `schema:"email" json:"email"`
Password string `schema:"password" json:"password"`
}
func (u *Users) login(r *http.Request) (*database.Session, error) {
var form LoginForm
if err := parseRequestData(r, &form); err != nil {
return nil, err
}
user, err := u.app.Authenticate(form.Email, form.Password)
if err != nil {
// If the user is not found, treat it as invalid login
if err == app.ErrNotFound {
return nil, app.ErrLoginInvalid
}
return nil, err
}
s, err := u.app.SignIn(user)
if err != nil {
return nil, err
}
return s, nil
}
// Login handles login
func (u *Users) Login(w http.ResponseWriter, r *http.Request) {
vd := views.Data{}
session, err := u.login(r)
if err != nil {
handleHTMLError(w, r, err, "logging in user", u.LoginView, &vd)
return
}
setSessionCookie(w, session.Key, session.ExpiresAt)
http.Redirect(w, r, "/", http.StatusFound)
}
// V3Login handles login
func (u *Users) V3Login(w http.ResponseWriter, r *http.Request) {
session, err := u.login(r)
if err != nil {
handleJSONError(w, err, "logging in user")
return
}
respondWithSession(w, http.StatusOK, session)
}
func (u *Users) logout(r *http.Request) error {
key, err := GetCredential(r)
if err != nil {
return errors.Wrap(err, "getting credentials")
}
if err = u.app.DeleteSession(key); err != nil {
return errors.Wrap(err, "deleting session")
}
return nil
}
// Logout handles logout
func (u *Users) Logout(w http.ResponseWriter, r *http.Request) {
var vd views.Data
if err := u.logout(r); err != nil {
handleHTMLError(w, r, err, "logging out", u.LoginView, &vd)
return
}
unsetSessionCookie(w)
http.Redirect(w, r, "/login", http.StatusFound)
}
// V3Logout handles logout via API
func (u *Users) V3Logout(w http.ResponseWriter, r *http.Request) {
if err := u.logout(r); err != nil {
handleJSONError(w, err, "logging out")
return
}
unsetSessionCookie(w)
w.WriteHeader(http.StatusNoContent)
}