// Copyright 2023 wanderer // SPDX-License-Identifier: AGPL-3.0-only package handlers import ( "context" "errors" "net/http" "git.dotya.ml/mirre-mt/pcmt/ent" moduser "git.dotya.ml/mirre-mt/pcmt/modules/user" "github.com/gorilla/sessions" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" ) func Signup() echo.HandlerFunc { return func(c echo.Context) error { defer addHeaders(c) sess, _ := session.Get(setting.SessionCookieName(), c) if sess != nil { if uname, ok := sess.Values["username"].(string); ok && uname != "" { return c.Redirect(http.StatusFound, "/home") } } csrf := c.Get("csrf").(string) p := newPage() p.Title = "Sign up" p.Current = "signup" p.CSRF = csrf err := c.Render( http.StatusOK, "signup.tmpl", p, ) if err != nil { log.Warnf("error: %q", err) return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) } return nil } } func SignupPost(client *ent.Client) echo.HandlerFunc { return func(c echo.Context) error { defer addHeaders(c) cu := new(userSignup) if err := c.Bind(cu); err != nil { return renderErrorPage( c, http.StatusBadRequest, http.StatusText(http.StatusBadRequest), err.Error(), ) } if cu.Username == "" || cu.Email == "" || cu.Password == "" { c.Logger().Error("username or email or password not set, returning to /singup") return c.Redirect(http.StatusFound, "/singup") } if err := c.Validate(cu); err != nil { return renderErrorPage( c, http.StatusBadRequest, http.StatusText(http.StatusBadRequest)+" - "+ErrValidationFailed.Error(), err.Error(), ) } username := cu.Username email := cu.Email passwd := cu.Password ctx := context.WithValue(context.Background(), moduser.CtxKey{}, slogger) exists, err := moduser.Exists(ctx, client, username, email) if err != nil { c.Logger().Error("error checking whether user exists", err) return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), err.Error(), ) } if exists { c.Logger().Error("username/email already taken") return c.Redirect(http.StatusSeeOther, "/signup") } u, err := moduser.CreateUser( ctx, client, email, username, passwd, ) if err != nil { if errors.Is(err, errors.New("username is not unique")) { c.Logger().Error("username already taken") // TODO: re-render signup page with a flash message // stating what went wrong. return c.Redirect(http.StatusSeeOther, "/signup") } return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" - failed to create schema resources", err.Error(), ) } log.Infof("successfully registered user '%s'", u.Username) log.Debug("user details", "id", u.ID, "email", u.Email, "isAdmin", u.IsAdmin) sess, _ := session.Get(setting.SessionCookieName(), c) sess.Options = &sessions.Options{ Path: "/", MaxAge: setting.SessionMaxAge(), HttpOnly: true, Secure: setting.HTTPSecure(), SameSite: http.SameSiteStrictMode, } sess.Values["username"] = username err = sess.Save(c.Request(), c.Response()) if err != nil { c.Logger().Error("failed to save session") return renderErrorPage( c, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)+" (make sure you've got cookies enabled)", err.Error(), ) } return c.Redirect(http.StatusMovedPermanently, "/home") } }