// Copyright (c) 2026 Zeni Kim // Use of this source code is governed by MIT-style // license that can be found in the LICENSE file. package controllers import ( "errors" "fmt" "net/http" "os" "strconv" "git.smarteching.com/goffee/core" "git.smarteching.com/goffee/core/template/components" "git.smarteching.com/goffee/cup/models" "gorm.io/gorm" ) func AppSignin(c *core.Context) *core.Response { email := c.GetRequestParam("email") password := c.GetRequestParam("password") // check if template engine is enable TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") if TemplateEnableStr == "" { TemplateEnableStr = "false" } TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) // Apps web only works if template is enabled in environment if !TemplateEnable { return c.Response.Redirect("/applogin") } data := map[string]interface{}{ "email": email, "password": password, } rules := map[string]interface{}{ "email": "required|email", "password": "required", } v := c.GetValidator().Validate(data, rules) if v.Failed() { c.GetLogger().Error(v.GetErrorMessagesJson()) return c.Response.Redirect("/applogin") } var user models.User res := c.GetGorm().Where("email = ?", c.CastToString(email)).First(&user) if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) { c.GetLogger().Error(res.Error.Error()) return c.Response.Redirect("/applogin") } if res.Error != nil && errors.Is(res.Error, gorm.ErrRecordNotFound) { return c.Response.Redirect("/applogin") } ok, err := c.GetHashing().CheckPasswordHash(user.Password, c.CastToString(password)) if err != nil { c.GetLogger().Error(err.Error()) return c.Response.Redirect("/applogin") } if !ok { return c.Response.Redirect("/applogin") } token, err := c.GetJWT().GenerateToken(map[string]interface{}{ "userID": user.ID, }) if err != nil { c.GetLogger().Error(err.Error()) return c.Response.Redirect("/applogin") } // cache the token userAgent := c.GetUserAgent() hashedCacheKey := core.CreateAuthTokenHashedCacheKey(user.ID, userAgent) err = c.GetCache().Set(hashedCacheKey, token) // delete data from old sessions sessionKey := fmt.Sprintf("sess_%v", userAgent) hashedSessionKey := core.CreateAuthTokenHashedCacheKey(user.ID, sessionKey) _ = c.GetCache().Delete(hashedSessionKey) if err != nil { c.GetLogger().Error(err.Error()) // TODO set error in session return c.Response.Redirect("/applogin") } // create cookie err = core.SetCookie(c.Response.HttpResponseWriter, email.(string), token) if err != nil { panic(fmt.Sprintf("Error write encrypted cookie: %v", err)) return c.Response.SetStatusCode(http.StatusInternalServerError) } // redirect to app return c.Response.Redirect("/dashboard") } func AppSignout(c *core.Context) *core.Response { // check if template engine is enable TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") if TemplateEnableStr == "" { TemplateEnableStr = "false" } TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) // Apps web only works if template is enabled in environment if !TemplateEnable { return c.Response.Redirect("/applogin") } token := "" // get cookie usercookie, err := c.GetCookie() if err != nil { // the cookie could not be read/decrypted, still make sure it is removed from the client core.ClearCookie(c.Response.HttpResponseWriter) return c.Response.Redirect("/applogin") } token = usercookie.Token if token == "" { // no token present, still clear any (possibly present) cookie on the client core.ClearCookie(c.Response.HttpResponseWriter) return c.Response.Redirect("/applogin") } payload, err := c.GetJWT().DecodeToken(token) if err != nil { // the token is invalid, clear the cookie on the client core.ClearCookie(c.Response.HttpResponseWriter) return c.Response.Redirect("/applogin") } userAgent := c.GetUserAgent() hashedCacheKey := core.CreateAuthTokenHashedCacheKey(uint(c.CastToInt(payload["userID"])), userAgent) err = c.GetCache().Delete(hashedCacheKey) if err != nil { // failed to invalidate the cached token, still clear the cookie on the client core.ClearCookie(c.Response.HttpResponseWriter) return c.Response.Redirect("/applogin") } // successful signout: the token is removed from the cache, also clear // the cookie on the client before the final redirect core.ClearCookie(c.Response.HttpResponseWriter) return c.Response.Redirect("/applogin") } // Show basic app login func AppLogin(c *core.Context) *core.Response { // check if template engine is enable TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") if TemplateEnableStr == "" { TemplateEnableStr = "false" } TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) if TemplateEnable { // initiate authority session := c.GetSession() // true if session is active hassession := session.Init(c) // only show login if no has session if !hassession { type templateData struct{} tmplData := templateData{} return c.Response.Template("login.html", tmplData) } else { // first, include all compoments type templateData struct { PageCard components.PageCard } // now fill data of the components tmplData := templateData{ PageCard: components.PageCard{ CardTitle: "Golang Framework", CardBody: "Welcome to Goffee", }, } return c.Response.Template("welcome.html", tmplData) } } else { return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{ "message": "Apps web only works if template is enabled in environment", })) } } // This page is cookie protected by hook func WelcomeToDashboard(c *core.Context) *core.Response { type templateData struct{} return c.Response.Template("dashboard.html", templateData{}) }