Pick up the single-page application as frontend

This commit is contained in:
2024-06-24 23:06:20 +08:00
parent 86b2cd8140
commit 1cf675b23a
65 changed files with 2257 additions and 1410 deletions

View File

@ -85,5 +85,9 @@ func MapAPIs(app *fiber.App) {
}
return c.Next()
}).Get("/ws", websocket.New(listenWebsocket))
api.All("/*", func(c *fiber.Ctx) error {
return fiber.ErrNotFound
})
}
}

View File

@ -1,32 +1,31 @@
package server
import (
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/admin"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/api"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"github.com/gofiber/fiber/v2/middleware/filesystem"
"net/http"
"path/filepath"
"strings"
"git.solsynth.dev/hydrogen/passport/pkg/internal"
"git.solsynth.dev/hydrogen/passport/pkg/internal/i18n"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/admin"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/ui"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/favicon"
"github.com/gofiber/fiber/v2/middleware/idempotency"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/template/html/v2"
jsoniter "github.com/json-iterator/go"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
)
var A *fiber.App
type HTTPApp struct {
app *fiber.App
}
func NewServer() {
templates := html.NewFileSystem(http.FS(pkg.FS), ".gohtml")
A = fiber.New(fiber.Config{
func NewServer() *HTTPApp {
app := fiber.New(fiber.Config{
DisableStartupMessage: true,
EnableIPValidation: true,
ServerHeader: "Hydrogen.Passport",
@ -35,12 +34,10 @@ func NewServer() {
JSONEncoder: jsoniter.ConfigCompatibleWithStandardLibrary.Marshal,
JSONDecoder: jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal,
EnablePrintRoutes: viper.GetBool("debug.print_routes"),
Views: templates,
ViewsLayout: "views/index",
})
A.Use(idempotency.New())
A.Use(cors.New(cors.Config{
app.Use(idempotency.New())
app.Use(cors.New(cors.Config{
AllowCredentials: true,
AllowMethods: strings.Join([]string{
fiber.MethodGet,
@ -56,27 +53,34 @@ func NewServer() {
},
}))
A.Use(logger.New(logger.Config{
app.Use(logger.New(logger.Config{
Format: "${status} | ${latency} | ${method} ${path}\n",
Output: log.Logger,
}))
A.Use(exts.AuthMiddleware)
A.Use(i18n.I18nMiddleware)
app.Use(exts.AuthMiddleware)
app.Use(i18n.I18nMiddleware)
A.Use(favicon.New(favicon.Config{
FileSystem: http.FS(pkg.FS),
File: "views/favicon.png",
URL: "/favicon.png",
api.MapAPIs(app)
admin.MapAdminEndpoints(app)
app.Use(filesystem.New(filesystem.Config{
Root: http.Dir(viper.GetString("frontend_app")),
Index: "index.html",
NotFoundFile: "index.html",
MaxAge: 3600,
}))
api.MapAPIs(A)
admin.MapAdminEndpoints(A)
ui.MapUserInterface(A)
app.Use(favicon.New(favicon.Config{
File: filepath.Join(viper.GetString("frontend_app"), "favicon.png"),
URL: "/favicon.png",
}))
return &HTTPApp{app}
}
func Listen() {
if err := A.Listen(viper.GetString("bind")); err != nil {
func (v *HTTPApp) Listen() {
if err := v.app.Listen(viper.GetString("bind")); err != nil {
log.Fatal().Err(err).Msg("An error occurred when starting server...")
}
}

View File

@ -1,55 +0,0 @@
package ui
import (
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"html/template"
"time"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"github.com/gofiber/fiber/v2"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
"github.com/sujit-baniya/flash"
)
func selfUserinfoPage(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return DoAuthRedirect(c)
}
user := c.Locals("user").(models.Account)
var data models.Account
if err := database.C.
Where(&models.Account{BaseModel: models.BaseModel{ID: user.ID}}).
Preload("Profile").
Preload("PersonalPage").
Preload("Contacts").
First(&data).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
birthday := "Unknown"
if data.Profile.Birthday != nil {
birthday = data.Profile.Birthday.Format(time.RFC822)
}
doc := parser.
NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock).
Parse([]byte(data.PersonalPage.Content))
renderer := html.NewRenderer(html.RendererOptions{Flags: html.CommonFlags | html.HrefTargetBlank})
return c.Render("views/users/me", fiber.Map{
"info": flash.Get(c)["message"],
"uid": fmt.Sprintf("%08d", data.ID),
"joined_at": data.CreatedAt.Format(time.RFC822),
"birthday_at": birthday,
"personal_page": template.HTML(markdown.Render(doc, renderer)),
"userinfo": data,
"avatar": data.GetAvatar(),
"banner": data.GetBanner(),
}, "views/layouts/user-center")
}

View File

@ -1,34 +0,0 @@
package ui
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
func DoAuthRedirect(c *fiber.Ctx) error {
uri := c.Request().URI().FullURI()
return c.Redirect(fmt.Sprintf("/sign-in?redirect_uri=%s", string(uri)))
}
func MapUserInterface(app *fiber.App) {
pages := app.Group("/").Name("Pages")
pages.Get("/", func(c *fiber.Ctx) error {
return c.Redirect("/users/me")
})
pages.Get("/sign-up", signupPage)
pages.Get("/sign-in", signinPage)
pages.Get("/mfa", mfaRequestPage)
pages.Get("/mfa/apply", mfaApplyPage)
pages.Get("/authorize", authorizePage)
pages.Post("/sign-up", signupAction)
pages.Post("/sign-in", signinAction)
pages.Post("/mfa", mfaRequestAction)
pages.Post("/mfa/apply", mfaApplyAction)
pages.Post("/authorize", authorizeAction)
pages.Get("/users/me", selfUserinfoPage)
}

View File

@ -1,194 +0,0 @@
package ui
import (
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"github.com/gofiber/fiber/v2"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/samber/lo"
"github.com/sujit-baniya/flash"
)
func mfaRequestPage(c *fiber.Ctx) error {
ticketId := c.QueryInt("ticket", 0)
ticket, err := services.GetTicket(uint(ticketId))
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": "you must provide ticket id to perform multi-factor authenticate",
}).Redirect("/sign-in")
}
user, err := services.GetAccount(ticket.AccountID)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": "ticket related user just weirdly disappear",
}).Redirect("/sign-in")
}
factors, err := services.ListUserFactor(user.ID)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("unable to get your factors: %v", err.Error()),
}).Redirect("/sign-in")
}
factors = lo.Filter(factors, func(item models.AuthFactor, index int) bool {
return item.Type != models.PasswordAuthFactor
})
localizer := c.Locals("localizer").(*i18n.Localizer)
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaTitle"})
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaCaption"})
return c.Render("views/mfa", fiber.Map{
"info": flash.Get(c)["message"],
"redirect_uri": flash.Get(c)["redirect_uri"],
"ticket_id": ticket.ID,
"factors": lo.Map(factors, func(item models.AuthFactor, index int) fiber.Map {
return fiber.Map{
"name": services.GetFactorName(item.Type, localizer),
"id": item.ID,
}
}),
"i18n": fiber.Map{
"next": next,
"title": title,
"caption": caption,
},
}, "views/layouts/auth")
}
func mfaRequestAction(c *fiber.Ctx) error {
var data struct {
TicketID uint `form:"ticket_id" validate:"required"`
FactorID uint `form:"factor_id" validate:"required"`
}
redirectBackUri := "/sign-in"
err := exts.BindAndValidate(c, &data)
if data.TicketID > 0 {
redirectBackUri = fmt.Sprintf("/mfa?ticket=%d", data.TicketID)
}
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": err.Error(),
}).Redirect(redirectBackUri)
}
factor, err := services.GetFactor(data.FactorID)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("factor was not found: %v", err.Error()),
}).Redirect(redirectBackUri)
}
_, err = services.GetFactorCode(factor)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("unable to get factor code: %v", err.Error()),
}).Redirect(redirectBackUri)
}
return flash.WithData(c, fiber.Map{
"redirect_uri": exts.GetRedirectUri(c),
}).Redirect(fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, factor.ID))
}
func mfaApplyPage(c *fiber.Ctx) error {
ticketId := c.QueryInt("ticket", 0)
factorId := c.QueryInt("factor", 0)
ticket, err := services.GetTicket(uint(ticketId))
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("unable to find your ticket: %v", err.Error()),
}).Redirect("/sign-in")
}
factor, err := services.GetFactor(uint(factorId))
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("unable to find your factors: %v", err.Error()),
}).Redirect("/sign-in")
}
localizer := c.Locals("localizer").(*i18n.Localizer)
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"})
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaTitle"})
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaCaption"})
return c.Render("views/mfa-apply", fiber.Map{
"info": flash.Get(c)["message"],
"label": services.GetFactorName(factor.Type, localizer),
"ticket_id": ticket.ID,
"factor_id": factor.ID,
"i18n": fiber.Map{
"next": next,
"password": password,
"title": title,
"caption": caption,
},
}, "views/layouts/auth")
}
func mfaApplyAction(c *fiber.Ctx) error {
var data struct {
TicketID uint `form:"ticket_id" validate:"required"`
FactorID uint `form:"factor_id" validate:"required"`
Code string `form:"code" validate:"required"`
}
redirectBackUri := "/sign-in"
err := exts.BindAndValidate(c, &data)
if data.TicketID > 0 {
redirectBackUri = fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, data.FactorID)
}
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": err.Error(),
}).Redirect(redirectBackUri)
}
ticket, err := services.GetTicket(data.TicketID)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("unable to find your ticket: %v", err.Error()),
}).Redirect("/sign-in")
}
factor, err := services.GetFactor(data.FactorID)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("factor was not found: %v", err.Error()),
}).Redirect(redirectBackUri)
}
ticket, err = services.ActiveTicketWithMFA(ticket, factor, data.Code)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("invalid multi-factor authenticate code: %v", err.Error()),
}).Redirect(redirectBackUri)
} else if ticket.IsAvailable() != nil {
return flash.WithInfo(c, fiber.Map{
"message": "ticket weirdly still unavailable after multi-factor authenticate",
}).Redirect("/sign-in")
}
access, refresh, err := services.ExchangeToken(*ticket.GrantToken)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("failed to exchange token: %v", err.Error()),
}).Redirect("/sign-in")
} else {
exts.SetAuthCookies(c, access, refresh)
}
return c.Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/users/me")))
}

View File

@ -1,166 +0,0 @@
package ui
import (
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"github.com/gofiber/fiber/v2"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/samber/lo"
"github.com/sujit-baniya/flash"
"html/template"
"strings"
"time"
)
func authorizePage(c *fiber.Ctx) error {
localizer := c.Locals("localizer").(*i18n.Localizer)
if err := exts.EnsureAuthenticated(c); err != nil {
return DoAuthRedirect(c)
}
user := c.Locals("user").(models.Account)
id := c.Query("client_id")
redirect := c.Query("redirect_uri")
var message string
if len(id) <= 0 || len(redirect) <= 0 {
message = "invalid request, missing query parameters"
}
var client models.ThirdClient
if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil {
message = fmt.Sprintf("unable to find client: %v", err)
} else if !client.IsDraft && !lo.Contains(client.Callbacks, strings.Split(redirect, "?")[0]) {
message = "invalid callback url"
}
var ticket models.AuthTicket
if err := database.C.Where(&models.AuthTicket{
AccountID: user.ID,
ClientID: &client.ID,
}).Where("last_grant_at IS NULL").First(&ticket).Error; err == nil {
if !(ticket.ExpiredAt != nil && ticket.ExpiredAt.Unix() < time.Now().Unix()) {
ticket, err = services.RegenSession(ticket)
if c.Query("response_type") == "code" {
return c.Redirect(fmt.Sprintf(
"%s?code=%s&state=%s",
redirect,
*ticket.GrantToken,
c.Query("state"),
))
} else if c.Query("response_type") == "token" {
if access, refresh, err := services.GetToken(ticket); err == nil {
return c.Redirect(fmt.Sprintf("%s?access_token=%s&refresh_token=%s&state=%s",
redirect,
access,
refresh, c.Query("state"),
))
}
}
}
}
decline, _ := localizer.LocalizeMessage(&i18n.Message{ID: "decline"})
approve, _ := localizer.LocalizeMessage(&i18n.Message{ID: "approve"})
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "authorizeTitle"})
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "authorizeCaption"})
qs := "/authorize?" + string(c.Request().URI().QueryString())
return c.Render("views/authorize", fiber.Map{
"info": lo.Ternary[any](len(message) > 0, message, flash.Get(c)["message"]),
"client": client,
"scopes": strings.Split(c.Query("scope"), " "),
"action_url": template.URL(qs),
"i18n": fiber.Map{
"approve": approve,
"decline": decline,
"title": title,
"caption": caption,
},
}, "views/layouts/auth")
}
func authorizeAction(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
id := c.Query("client_id")
response := c.Query("response_type")
redirect := c.Query("redirect_uri")
scope := c.Query("scope")
if err := exts.EnsureAuthenticated(c); err != nil {
return DoAuthRedirect(c)
}
redirectBackUri := "/authorize?" + string(c.Request().URI().QueryString())
if len(scope) <= 0 {
return flash.WithInfo(c, fiber.Map{
"message": "invalid request parameters",
}).Redirect(redirectBackUri)
}
var client models.ThirdClient
if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
switch response {
case "code":
// OAuth Authorization Mode
ticket, err := services.NewOauthTicket(
user,
client,
strings.Split(scope, " "),
[]string{"passport", client.Alias},
c.IP(),
c.Get(fiber.HeaderUserAgent),
)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
} else {
services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent))
return c.Redirect(fmt.Sprintf(
"%s?code=%s&state=%s",
redirect,
*ticket.GrantToken,
c.Query("state"),
))
}
case "token":
// OAuth Implicit Mode
ticket, err := services.NewOauthTicket(
user,
client,
strings.Split(scope, " "),
[]string{"passport", client.Alias},
c.IP(),
c.Get(fiber.HeaderUserAgent),
)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
} else if access, refresh, err := services.GetToken(ticket); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
} else {
services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent))
return c.Redirect(fmt.Sprintf("%s?access_token=%s&refresh_token=%s&state=%s",
redirect,
access,
refresh, c.Query("state"),
))
}
default:
return flash.WithInfo(c, fiber.Map{
"message": "unsupported response type",
}).Redirect(redirectBackUri)
}
}

View File

@ -1,93 +0,0 @@
package ui
import (
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"github.com/gofiber/fiber/v2"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/samber/lo"
"github.com/sujit-baniya/flash"
)
func signinPage(c *fiber.Ctx) error {
localizer := c.Locals("localizer").(*i18n.Localizer)
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
username, _ := localizer.LocalizeMessage(&i18n.Message{ID: "username"})
password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"})
signup, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupTitle"})
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinTitle"})
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinCaption"})
requiredNotify, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinRequired"})
var info any
if flash.Get(c)["message"] != nil {
info = flash.Get(c)["message"]
} else {
info = requiredNotify
}
return c.Render("views/signin", fiber.Map{
"info": info,
"i18n": fiber.Map{
"next": next,
"username": username,
"password": password,
"signup": signup,
"title": title,
"caption": caption,
},
}, "views/layouts/auth")
}
func signinAction(c *fiber.Ctx) error {
var data struct {
Username string `form:"username" validate:"required"`
Password string `form:"password" validate:"required"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
return flash.WithInfo(c, fiber.Map{
"message": err.Error(),
}).Redirect("/sign-in")
}
user, err := services.LookupAccount(data.Username)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("account was not found: %v", err.Error()),
}).Redirect("/sign-in")
}
ticket, err := services.NewTicket(user, c.IP(), c.Get(fiber.HeaderUserAgent))
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("unable setup ticket: %v", err.Error()),
}).Redirect("/sign-in")
}
ticket, err = services.ActiveTicketWithPassword(ticket, data.Password)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("invalid password: %v", err.Error()),
}).Redirect("/sign-in")
}
if ticket.IsAvailable() != nil {
return flash.WithData(c, fiber.Map{
"redirect_uri": exts.GetRedirectUri(c),
}).Redirect(fmt.Sprintf("/mfa?ticket=%d", ticket.ID))
}
access, refresh, err := services.ExchangeToken(*ticket.GrantToken)
if err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("failed to exchange token: %v", err.Error()),
}).Redirect("/sign-in")
} else {
exts.SetAuthCookies(c, access, refresh)
}
return c.Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/users/me")))
}

View File

@ -1,87 +0,0 @@
package ui
import (
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"github.com/gofiber/fiber/v2"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/samber/lo"
"github.com/spf13/viper"
"github.com/sujit-baniya/flash"
)
func signupPage(c *fiber.Ctx) error {
localizer := c.Locals("localizer").(*i18n.Localizer)
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
email, _ := localizer.LocalizeMessage(&i18n.Message{ID: "email"})
nickname, _ := localizer.LocalizeMessage(&i18n.Message{ID: "nickname"})
username, _ := localizer.LocalizeMessage(&i18n.Message{ID: "username"})
password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"})
magicToken, _ := localizer.LocalizeMessage(&i18n.Message{ID: "magicToken"})
signin, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinTitle"})
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupTitle"})
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupCaption"})
return c.Render("views/signup", fiber.Map{
"info": flash.Get(c)["message"],
"use_magic_token": viper.GetBool("use_registration_magic_token"),
"i18n": fiber.Map{
"next": next,
"email": email,
"username": username,
"nickname": nickname,
"password": password,
"magic_token": magicToken,
"signin": signin,
"title": title,
"caption": caption,
},
}, "views/layouts/auth")
}
func signupAction(c *fiber.Ctx) error {
var data struct {
Name string `form:"name" validate:"required,lowercase,alphanum,min=4,max=16"`
Nick string `form:"nick" validate:"required,min=4,max=24"`
Email string `form:"email" validate:"required,email"`
Password string `form:"password" validate:"required,min=4,max=32"`
MagicToken string `form:"magic_token"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
return flash.WithInfo(c, fiber.Map{
"message": err.Error(),
}).Redirect("/sign-up")
} else if viper.GetBool("use_registration_magic_token") && len(data.MagicToken) <= 0 {
return flash.WithInfo(c, fiber.Map{
"message": "magic token was required",
}).Redirect("/sign-up")
} else if viper.GetBool("use_registration_magic_token") {
if tk, err := services.ValidateMagicToken(data.MagicToken, models.RegistrationMagicToken); err != nil {
return flash.WithInfo(c, fiber.Map{
"message": fmt.Sprintf("magic token was invalid: %v", err.Error()),
}).Redirect("/sign-up")
} else {
database.C.Delete(&tk)
}
}
if _, err := services.CreateAccount(
data.Name,
data.Nick,
data.Email,
data.Password,
); err != nil {
return flash.WithInfo(c, fiber.Map{
"message": err.Error(),
}).Redirect("/sign-up")
} else {
return flash.WithInfo(c, fiber.Map{
"message": "account has been created. now you can sign in!",
}).Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/sign-in")))
}
}