diff --git a/controllers/authentication.go b/controllers/authentication.go
index a58b71d..4830a2d 100644
--- a/controllers/authentication.go
+++ b/controllers/authentication.go
@@ -468,6 +468,32 @@ func AppLogin(c *core.Context) *core.Response {
return c.Response.Template("login.html", tmplData)
}
+// Show basic app login
+func AppSession(c *core.Context) *core.Response {
+
+ var session = new(utils.SessionUser)
+
+ hassession := session.Init(c)
+
+ type templateData struct {
+ PageCard components.PageCard
+ }
+
+ // now fill data of the components
+ tmplData := templateData{}
+
+ if hassession {
+
+ return c.Response.Template("appsession.html", tmplData)
+
+ } else {
+
+ return c.Response.Template("login.html", tmplData)
+
+ }
+
+}
+
// Show basic app sample
func AppSample(c *core.Context) *core.Response {
diff --git a/routes.go b/routes.go
index 18c72be..610fbcb 100644
--- a/routes.go
+++ b/routes.go
@@ -41,4 +41,7 @@ func registerRoutes() {
controller.Get("/applogin", controllers.AppLogin, hooks.CheckSessionCookie)
controller.Post("/applogin", controllers.AppLogin, hooks.CheckSessionCookie)
+
+ controller.Get("/appsession", controllers.AppSession)
+ controller.Post("/appsession", controllers.AppSession)
}
diff --git a/storage/templates/appsession.html b/storage/templates/appsession.html
new file mode 100644
index 0000000..32364f0
--- /dev/null
+++ b/storage/templates/appsession.html
@@ -0,0 +1,12 @@
+
+
+ {{template "page_head" "Sample page test session vars"}}
+
+
+
+ {{template "page_card" .PageCard}}
+
+
+ {{template "page_footer"}}
+
+
\ No newline at end of file
diff --git a/utils/session.go b/utils/session.go
new file mode 100644
index 0000000..c792ba5
--- /dev/null
+++ b/utils/session.go
@@ -0,0 +1,178 @@
+// Copyright (c) 2024 Zeni Kim
+// Use of this source code is governed by MIT-style
+// license that can be found in the LICENSE file.
+
+package utils
+
+import (
+ "crypto/md5"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "encoding/json"
+
+ "git.smarteching.com/goffee/core"
+ "git.smarteching.com/goffee/cup/models"
+ "gorm.io/gorm"
+)
+
+type SessionUser struct {
+ mu sync.RWMutex
+ context *core.Context
+ userID uint
+ hashedSessionKey string
+ authenticated bool
+ sessionStart time.Time
+ values map[string]interface{}
+}
+
+// start the struct
+func (s *SessionUser) Init(c *core.Context) bool {
+
+ // check session cookie
+ pass := true
+ token := ""
+ s.context = c
+
+ payload := make(map[string]interface{})
+
+ usercookie, err := c.GetCookie()
+ if err != nil {
+
+ }
+
+ token = usercookie.Token
+
+ if token == "" {
+
+ pass = false
+
+ } else {
+
+ payload, err = c.GetJWT().DecodeToken(token)
+
+ if err != nil {
+ pass = false
+ } else {
+
+ userID := uint(c.CastToInt(payload["userID"]))
+ userAgent := c.GetUserAgent()
+ hashedCacheKey := CreateAuthTokenHashedCacheKey(userID, userAgent)
+
+ cachedToken, err := c.GetCache().Get(hashedCacheKey)
+
+ if err != nil {
+ pass = false
+ } else if cachedToken != token {
+ pass = false
+ } else {
+ var user models.User
+ res := c.GetGorm().Where("id = ?", userID).First(&user)
+ if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) {
+ pass = false
+ }
+
+ // if have session start the struct
+ if pass {
+
+ userAgent := c.GetUserAgent()
+ sessionKey := fmt.Sprintf("session%v_%v", userID, userAgent)
+ s.hashedSessionKey = fmt.Sprintf("%v", fmt.Sprintf("%x", md5.Sum([]byte(sessionKey))))
+ value, err := c.GetCache().Get(s.hashedSessionKey)
+
+ if err != nil {
+ s.values = make(map[string]interface{})
+ s.authenticated = true
+ s.userID = userID
+
+ if len(value) > 0 {
+ err := json.Unmarshal([]byte(value), &s.values)
+ if err != nil {
+
+ }
+ } else {
+
+ }
+ }
+
+ return true
+
+ } else {
+
+ s.hashedSessionKey = ""
+ s.authenticated = false
+ s.userID = 0
+ return false
+ }
+ }
+ }
+ }
+
+ return false
+}
+
+func (s *SessionUser) Set(key string, value interface{}) error {
+ s.mu.Lock()
+ s.values[key] = value
+ s.mu.Unlock()
+ return s.Save()
+}
+
+func (s *SessionUser) Get(key string) (interface{}, bool) {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+ val, ok := s.values[key]
+ return val, ok
+}
+
+func (s *SessionUser) Delete(key string) interface{} {
+ s.mu.RLock()
+ v, ok := s.values[key]
+ s.mu.RUnlock()
+ if ok {
+ s.mu.Lock()
+ delete(s.values, key)
+ s.mu.Unlock()
+ }
+ s.Save()
+ return v
+}
+
+func (s *SessionUser) Flush() error {
+ s.mu.Lock()
+ s.values = make(map[string]interface{})
+ s.mu.Unlock()
+ return s.Save()
+}
+
+func (s *SessionUser) Save() error {
+
+ var value string
+
+ s.mu.RLock()
+
+ if len(s.values) > 0 {
+ buf, err := json.Marshal(&s.values)
+ if err != nil {
+ s.mu.RUnlock()
+ return err
+ }
+ value = string(buf)
+
+ }
+
+ s.mu.RUnlock()
+
+ if len(value) > 0 {
+ s.context.GetCache().Set(s.hashedSessionKey, value)
+ }
+
+ return nil
+}
+
+func (s *SessionUser) GetUserID() uint {
+
+ return s.userID
+}