add base goffee
This commit is contained in:
parent
c95e8a9245
commit
ac2cfa9fe1
108 changed files with 64018 additions and 0 deletions
604
controllers/adminusers.go
Normal file
604
controllers/adminusers.go
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
// Copyright (c) 2024 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"git.smarteching.com/goffee/core"
|
||||
"git.smarteching.com/goffee/core/template/components"
|
||||
"git.smarteching.com/jacs/goffeetabler/events"
|
||||
"git.smarteching.com/jacs/goffeetabler/models"
|
||||
"git.smarteching.com/jacs/goffeetabler/utils"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func AdminUsersList(c *core.Context) *core.Response {
|
||||
|
||||
// initiate authority
|
||||
auth := new(utils.Authority)
|
||||
var session = new(utils.SessionUser)
|
||||
// true if session is active
|
||||
hassession := session.Init(c)
|
||||
|
||||
if !hassession {
|
||||
type emptytemplate struct{}
|
||||
emptyData := emptytemplate{}
|
||||
return c.Response.Template("nopermission.html", emptyData)
|
||||
}
|
||||
|
||||
session_uid := session.GetUserID()
|
||||
// check if user has role admin
|
||||
is_admin, _ := auth.CheckUserRole(c, session_uid, "admin")
|
||||
|
||||
if !is_admin {
|
||||
type emptytemplate struct{}
|
||||
emptyData := emptytemplate{}
|
||||
return c.Response.Template("nopermission.html", emptyData)
|
||||
}
|
||||
|
||||
// continue if has session and is admin
|
||||
var users []models.User
|
||||
db := c.GetGorm()
|
||||
db.Find(&users)
|
||||
|
||||
// -- response template
|
||||
type templateData struct {
|
||||
TableUsers components.ContentTable
|
||||
AddButton components.ContentHref
|
||||
}
|
||||
|
||||
cols := []components.ContentTableTH{
|
||||
{
|
||||
Value: "UID",
|
||||
ValueType: "number",
|
||||
},
|
||||
{
|
||||
Value: "Name",
|
||||
ValueType: "string",
|
||||
},
|
||||
{
|
||||
Value: "Fullname",
|
||||
ValueType: "string",
|
||||
},
|
||||
{
|
||||
Value: "Email",
|
||||
ValueType: "string",
|
||||
},
|
||||
{
|
||||
Value: "Roles",
|
||||
ValueType: "string",
|
||||
},
|
||||
{
|
||||
Value: "Created",
|
||||
},
|
||||
{
|
||||
Value: "Updated",
|
||||
},
|
||||
{
|
||||
ValueType: "href",
|
||||
},
|
||||
}
|
||||
|
||||
var listroles string
|
||||
rows := make([][]components.ContentTableTD, len(users))
|
||||
for i, u := range users {
|
||||
|
||||
roles, _ := auth.GetUserRoles(c, u.ID)
|
||||
listroles = ""
|
||||
|
||||
for _, role := range roles {
|
||||
if listroles != "" {
|
||||
listroles += ", "
|
||||
}
|
||||
listroles += role.Name
|
||||
}
|
||||
|
||||
row := []components.ContentTableTD{
|
||||
{Value: strconv.Itoa(int(u.ID))},
|
||||
{Value: u.Name},
|
||||
{Value: u.Fullname},
|
||||
{Value: u.Email},
|
||||
{Value: listroles},
|
||||
{Value: utils.FormatUnix(u.Created)},
|
||||
{Value: utils.FormatUnix(u.Updated)},
|
||||
{Value: components.ContentHref{
|
||||
Text: "edit",
|
||||
Link: "/admin/users/edit/" + strconv.Itoa(int(u.ID)),
|
||||
TypeClass: "outline-secondary",
|
||||
}},
|
||||
}
|
||||
rows[i] = row
|
||||
}
|
||||
|
||||
tmplData := templateData{
|
||||
TableUsers: components.ContentTable{
|
||||
ID: "table_demo",
|
||||
AllTH: cols,
|
||||
AllTD: rows,
|
||||
},
|
||||
AddButton: components.ContentHref{
|
||||
Text: "Register",
|
||||
Link: "/admin/users/add",
|
||||
IsButton: true,
|
||||
TypeClass: "outline-primary",
|
||||
},
|
||||
}
|
||||
return c.Response.Template("admin_userlist.html", tmplData)
|
||||
}
|
||||
|
||||
func AdminUsersAdd(c *core.Context) *core.Response {
|
||||
|
||||
// initiate authority
|
||||
auth := new(utils.Authority)
|
||||
var session = new(utils.SessionUser)
|
||||
// true if session is active
|
||||
hassession := session.Init(c)
|
||||
|
||||
if !hassession {
|
||||
type emptytemplate struct{}
|
||||
emptyData := emptytemplate{}
|
||||
return c.Response.Template("nopermission.html", emptyData)
|
||||
}
|
||||
|
||||
session_uid := session.GetUserID()
|
||||
// check if user has role admin
|
||||
is_admin, _ := auth.CheckUserRole(c, session_uid, "admin")
|
||||
|
||||
if !is_admin {
|
||||
type emptytemplate struct{}
|
||||
emptyData := emptytemplate{}
|
||||
return c.Response.Template("nopermission.html", emptyData)
|
||||
}
|
||||
|
||||
// check if is submit
|
||||
submit := c.GetRequestParam("submit").(string)
|
||||
errormessages := make([]string, 0)
|
||||
var listroles []components.FormCheckboxItem
|
||||
systemroles, _ := auth.GetAllRoles(c)
|
||||
|
||||
for _, systemrole := range systemroles {
|
||||
var userrole components.FormCheckboxItem
|
||||
userrole.Label = systemrole.Name
|
||||
userrole.Name = "roles"
|
||||
userrole.Value = systemrole.Slug
|
||||
if systemrole.Slug == "authenticated" {
|
||||
userrole.IsChecked = true
|
||||
}
|
||||
listroles = append(listroles, userrole)
|
||||
}
|
||||
|
||||
name := ""
|
||||
fullname := ""
|
||||
email := ""
|
||||
password := ""
|
||||
|
||||
if submit != "" {
|
||||
|
||||
name = c.GetRequestParam("name").(string)
|
||||
fullname = c.GetRequestParam("fullname").(string)
|
||||
email = c.GetRequestParam("email").(string)
|
||||
password = c.GetRequestParam("password").(string)
|
||||
roles := c.GetRequesForm("roles").([]string)
|
||||
|
||||
// check if email exists
|
||||
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())
|
||||
errormessages = append(errormessages, "Error")
|
||||
}
|
||||
if res.Error == nil {
|
||||
errormessages = append(errormessages, "Error, email already exists in the database")
|
||||
}
|
||||
|
||||
// validation data
|
||||
data := map[string]interface{}{
|
||||
"name": name,
|
||||
"fullname": fullname,
|
||||
"email": email,
|
||||
"password": password,
|
||||
}
|
||||
// validation rules
|
||||
rules := map[string]interface{}{
|
||||
"name": "required|alphaNumeric",
|
||||
"fullname": "required",
|
||||
"email": "required|email",
|
||||
"password": "required|length:6,20",
|
||||
}
|
||||
// validate
|
||||
v := c.GetValidator().Validate(data, rules)
|
||||
if v.Failed() {
|
||||
c.GetLogger().Error(v.GetErrorMessagesJson())
|
||||
for _, v := range v.GetErrorMessagesMap() {
|
||||
errormessages = append(errormessages, v)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errormessages) == 0 {
|
||||
|
||||
//hash the password
|
||||
passwordHashed, _ := c.GetHashing().HashPassword(c.CastToString(password))
|
||||
// store the record in db
|
||||
user = models.User{
|
||||
Name: c.CastToString(name),
|
||||
Fullname: c.CastToString(fullname),
|
||||
Email: c.CastToString(email),
|
||||
Password: passwordHashed,
|
||||
}
|
||||
res = c.GetGorm().Create(&user)
|
||||
if res.Error != nil {
|
||||
c.GetLogger().Error(res.Error.Error())
|
||||
errormessages = append(errormessages, res.Error.Error())
|
||||
} else {
|
||||
|
||||
// assign roles
|
||||
for _, role := range roles {
|
||||
auth.AssignRoleToUser(c, user.ID, role)
|
||||
}
|
||||
|
||||
// fire user registered event
|
||||
err := c.GetEventsManager().Fire(&core.Event{Name: events.USER_REGISTERED, Payload: map[string]interface{}{
|
||||
"user": user,
|
||||
}})
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
errormessages = append(errormessages, "Internal server error")
|
||||
} else {
|
||||
// redirect to list
|
||||
return c.Response.Redirect("/admin/users")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// -- response template
|
||||
type templateData struct {
|
||||
FieldName components.FormInput
|
||||
FieldFullname components.FormInput
|
||||
FieldEmail components.FormInput
|
||||
FieldRoles components.FormCheckbox
|
||||
FieldPassword components.FormInput
|
||||
ErrorMessages []string
|
||||
SubmitButton components.FormButton
|
||||
}
|
||||
|
||||
tmplData := templateData{
|
||||
FieldName: components.FormInput{
|
||||
ID: "name",
|
||||
Label: "Name",
|
||||
Type: "text",
|
||||
Value: name,
|
||||
IsRequired: true,
|
||||
},
|
||||
FieldFullname: components.FormInput{
|
||||
ID: "fullname",
|
||||
Label: "Full name",
|
||||
Type: "text",
|
||||
Value: fullname,
|
||||
IsRequired: true,
|
||||
},
|
||||
FieldEmail: components.FormInput{
|
||||
ID: "email",
|
||||
Label: "e-mail",
|
||||
Type: "text",
|
||||
Value: email,
|
||||
//Autocomplete: true,
|
||||
IsRequired: true,
|
||||
},
|
||||
FieldRoles: components.FormCheckbox{
|
||||
Label: "Roles",
|
||||
AllCheckbox: listroles,
|
||||
},
|
||||
FieldPassword: components.FormInput{
|
||||
ID: "password",
|
||||
Label: "Password",
|
||||
Type: "password",
|
||||
Value: password,
|
||||
IsRequired: true,
|
||||
},
|
||||
SubmitButton: components.FormButton{
|
||||
ID: "submit",
|
||||
Text: "Add user",
|
||||
Value: "submit",
|
||||
IsSubmit: true,
|
||||
TypeClass: "primary",
|
||||
},
|
||||
ErrorMessages: errormessages,
|
||||
}
|
||||
return c.Response.Template("admin_useradd.html", tmplData)
|
||||
|
||||
}
|
||||
|
||||
func AdminUsersEdit(c *core.Context) *core.Response {
|
||||
|
||||
// check if is submit
|
||||
submit := c.GetRequestParam("submit").(string)
|
||||
|
||||
user_id := c.GetPathParam("id")
|
||||
|
||||
errormessages := make([]string, 0)
|
||||
// initiate authority
|
||||
auth := new(utils.Authority)
|
||||
|
||||
var listroles []components.FormCheckboxItem
|
||||
|
||||
systemroles, _ := auth.GetAllRoles(c)
|
||||
user_id_uint, _ := strconv.ParseUint(user_id.(string), 10, 32)
|
||||
|
||||
userroles, _ := auth.GetUserRoles(c, uint(user_id_uint))
|
||||
|
||||
for _, systemrole := range systemroles {
|
||||
var userrole components.FormCheckboxItem
|
||||
userrole.Label = systemrole.Name
|
||||
userrole.Name = "roles"
|
||||
userrole.Value = systemrole.Slug
|
||||
for _, ur := range userroles {
|
||||
if ur.Slug == systemrole.Slug {
|
||||
userrole.IsChecked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
listroles = append(listroles, userrole)
|
||||
}
|
||||
|
||||
var origin_user models.User
|
||||
|
||||
db := c.GetGorm()
|
||||
// check if existes
|
||||
result_db := db.First(&origin_user, user_id)
|
||||
if result_db.RowsAffected == 0 {
|
||||
c.GetLogger().Error("User ID not found")
|
||||
return c.Response.Redirect("/admin/users")
|
||||
}
|
||||
|
||||
name := origin_user.Name
|
||||
fullname := origin_user.Fullname
|
||||
email := origin_user.Email
|
||||
password := ""
|
||||
user_id_string := c.GetPathParam("id").(string)
|
||||
|
||||
if submit != "" {
|
||||
|
||||
name = c.GetRequestParam("name").(string)
|
||||
fullname = c.GetRequestParam("fullname").(string)
|
||||
email = c.GetRequestParam("email").(string)
|
||||
password = c.GetRequestParam("password").(string)
|
||||
roles := c.GetRequesForm("roles").([]string)
|
||||
key := c.GetRequestParam("key")
|
||||
|
||||
// check if email exists
|
||||
var user models.User
|
||||
res := c.GetGorm().Where("email = ? AND id != ?", c.CastToString(email), key).First(&user)
|
||||
if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
||||
c.GetLogger().Error(res.Error.Error())
|
||||
errormessages = append(errormessages, "Error")
|
||||
}
|
||||
if res.Error == nil {
|
||||
errormessages = append(errormessages, "Error, email already exists to another user")
|
||||
}
|
||||
|
||||
// validation data
|
||||
data := map[string]interface{}{
|
||||
"name": name,
|
||||
"fullname": fullname,
|
||||
"email": email,
|
||||
}
|
||||
// validation rules
|
||||
rules := map[string]interface{}{
|
||||
"name": "required|alphaNumeric",
|
||||
"fullname": "required",
|
||||
"email": "required|email",
|
||||
}
|
||||
|
||||
// nee update password
|
||||
if password != "" {
|
||||
data["password"] = password
|
||||
rules["password"] = "required|length:6,20"
|
||||
}
|
||||
// validate
|
||||
v := c.GetValidator().Validate(data, rules)
|
||||
if v.Failed() {
|
||||
c.GetLogger().Error(v.GetErrorMessagesJson())
|
||||
for _, v := range v.GetErrorMessagesMap() {
|
||||
errormessages = append(errormessages, v)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errormessages) == 0 {
|
||||
|
||||
//hash the password
|
||||
if password != "" {
|
||||
passwordHashed, _ := c.GetHashing().HashPassword(c.CastToString(password))
|
||||
origin_user.Password = passwordHashed
|
||||
}
|
||||
// store the record in db
|
||||
origin_user.Name = name
|
||||
origin_user.Fullname = fullname
|
||||
origin_user.Email = email
|
||||
|
||||
result_db = db.Save(&origin_user)
|
||||
if result_db.RowsAffected == 0 {
|
||||
c.GetLogger().Error("Admin user: error updating")
|
||||
errormessages = append(errormessages, fmt.Sprintf("Error updating user %s:", user_id_string))
|
||||
} else {
|
||||
|
||||
// delete roles
|
||||
auth.RevokeAllUserRole(c, origin_user.ID)
|
||||
// assign roles
|
||||
for _, role := range roles {
|
||||
auth.AssignRoleToUser(c, origin_user.ID, role)
|
||||
}
|
||||
|
||||
return c.Response.Redirect("/admin/users")
|
||||
}
|
||||
}
|
||||
}
|
||||
// -- response template
|
||||
type templateData struct {
|
||||
FieldName components.FormInput
|
||||
FieldFullname components.FormInput
|
||||
FieldEmail components.FormInput
|
||||
FieldRoles components.FormCheckbox
|
||||
FieldPassword components.FormInput
|
||||
FieldKey components.FormInput
|
||||
ErrorMessages []string
|
||||
SubmitButton components.FormButton
|
||||
DeleteButton components.FormButton
|
||||
}
|
||||
|
||||
tmplData := templateData{
|
||||
FieldName: components.FormInput{
|
||||
ID: "name",
|
||||
Label: "Name",
|
||||
Type: "text",
|
||||
Value: name,
|
||||
IsRequired: true,
|
||||
},
|
||||
FieldFullname: components.FormInput{
|
||||
ID: "fullname",
|
||||
Label: "Full name",
|
||||
Type: "text",
|
||||
Value: fullname,
|
||||
IsRequired: true,
|
||||
},
|
||||
FieldEmail: components.FormInput{
|
||||
ID: "email",
|
||||
Label: "e-mail",
|
||||
Type: "text",
|
||||
Value: email,
|
||||
//Autocomplete: true,
|
||||
IsRequired: true,
|
||||
},
|
||||
FieldRoles: components.FormCheckbox{
|
||||
Label: "Roles",
|
||||
AllCheckbox: listroles,
|
||||
},
|
||||
FieldPassword: components.FormInput{
|
||||
ID: "password",
|
||||
Label: "Password",
|
||||
Type: "password",
|
||||
Hint: "Leave blank if you don't want to change it",
|
||||
Value: password,
|
||||
IsRequired: false,
|
||||
},
|
||||
FieldKey: components.FormInput{
|
||||
ID: "key",
|
||||
Type: "hidden",
|
||||
Value: user_id_string,
|
||||
},
|
||||
SubmitButton: components.FormButton{
|
||||
ID: "submit",
|
||||
Text: "Update user",
|
||||
Value: "submit",
|
||||
IsSubmit: true,
|
||||
TypeClass: "primary",
|
||||
},
|
||||
DeleteButton: components.FormButton{
|
||||
ID: "submit",
|
||||
Text: "Delete user",
|
||||
Value: "submit",
|
||||
IsSubmit: true,
|
||||
TypeClass: "warning",
|
||||
},
|
||||
ErrorMessages: errormessages,
|
||||
}
|
||||
return c.Response.Template("admin_useredit.html", tmplData)
|
||||
|
||||
}
|
||||
|
||||
func AdminUsersDelete(c *core.Context) *core.Response {
|
||||
|
||||
user_id := c.GetRequestParam("key").(string)
|
||||
|
||||
errormessages := make([]string, 0)
|
||||
warningmessages := make([]string, 0)
|
||||
|
||||
var origin_user models.User
|
||||
|
||||
db := c.GetGorm()
|
||||
// check if existes
|
||||
result_db := db.First(&origin_user, user_id)
|
||||
if result_db.RowsAffected == 0 {
|
||||
errormessages = append(errormessages, "User ID not found")
|
||||
} else {
|
||||
// check if is the seed user
|
||||
seed := "1"
|
||||
if user_id == seed {
|
||||
errormessages = append(errormessages, "You can't delete the seed user")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// sample warning message
|
||||
warningmessages = append(warningmessages, fmt.Sprintf("Are you sure you want to cancel the account %s?", origin_user.Name))
|
||||
|
||||
// -- response template
|
||||
type templateData struct {
|
||||
ErrorMessages []string
|
||||
WarningMessages []string
|
||||
FieldKey components.FormInput
|
||||
ConfirmButton components.FormButton
|
||||
BackButton components.ContentHref
|
||||
}
|
||||
|
||||
tmplData := templateData{
|
||||
FieldKey: components.FormInput{
|
||||
ID: "key",
|
||||
Type: "hidden",
|
||||
Value: user_id,
|
||||
},
|
||||
ConfirmButton: components.FormButton{
|
||||
ID: "submit",
|
||||
Text: "Confirm",
|
||||
Value: "submit",
|
||||
IsSubmit: true,
|
||||
TypeClass: "primary",
|
||||
},
|
||||
BackButton: components.ContentHref{
|
||||
Link: "/admin/users",
|
||||
Text: "Cancel",
|
||||
IsButton: true,
|
||||
},
|
||||
ErrorMessages: errormessages,
|
||||
WarningMessages: warningmessages,
|
||||
}
|
||||
return c.Response.Template("admin_confirmuserdel.html", tmplData)
|
||||
|
||||
}
|
||||
|
||||
func AdminUsersDelConfirm(c *core.Context) *core.Response {
|
||||
|
||||
user_id := c.GetRequestParam("key").(string)
|
||||
|
||||
var origin_user models.User
|
||||
|
||||
db := c.GetGorm()
|
||||
// check if existes
|
||||
result_db := db.First(&origin_user, user_id)
|
||||
if result_db.RowsAffected != 0 {
|
||||
// check if is the seed user
|
||||
seed := "1"
|
||||
if user_id != seed {
|
||||
|
||||
// initiate authority
|
||||
auth := new(utils.Authority)
|
||||
// Delete the user
|
||||
// fire user delete event
|
||||
err := c.GetEventsManager().Fire(&core.Event{Name: events.USER_DELETED, Payload: map[string]interface{}{
|
||||
"user": origin_user,
|
||||
}})
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
}
|
||||
auth.RevokeAllUserRole(c, origin_user.ID)
|
||||
result_db.Unscoped().Delete(&origin_user)
|
||||
}
|
||||
}
|
||||
|
||||
return c.Response.Redirect("/admin/users")
|
||||
|
||||
}
|
||||
478
controllers/authentication.go
Normal file
478
controllers/authentication.go
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
// Copyright 2023 Harran Ali <harran.m@gmail.com>. All rights reserved.
|
||||
// Copyright (c) 2024 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.smarteching.com/goffee/core"
|
||||
"git.smarteching.com/jacs/goffeetabler/events"
|
||||
"git.smarteching.com/jacs/goffeetabler/models"
|
||||
"git.smarteching.com/jacs/goffeetabler/utils"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func Signup(c *core.Context) *core.Response {
|
||||
name := c.GetRequestParam("name")
|
||||
fullname := c.GetRequestParam("fullname")
|
||||
email := c.GetRequestParam("email")
|
||||
password := c.GetRequestParam("password")
|
||||
// check if email exists
|
||||
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.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal error",
|
||||
}))
|
||||
}
|
||||
if res.Error == nil {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "email already exists in the database",
|
||||
}))
|
||||
}
|
||||
|
||||
// validation data
|
||||
data := map[string]interface{}{
|
||||
"name": name,
|
||||
"fullname": fullname,
|
||||
"email": email,
|
||||
"password": password,
|
||||
}
|
||||
// validation rules
|
||||
rules := map[string]interface{}{
|
||||
"name": "required|alphaNumeric",
|
||||
"fullname": "required",
|
||||
"email": "required|email",
|
||||
"password": "required|length:6,20",
|
||||
}
|
||||
// validate
|
||||
v := c.GetValidator().Validate(data, rules)
|
||||
if v.Failed() {
|
||||
c.GetLogger().Error(v.GetErrorMessagesJson())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(v.GetErrorMessagesJson())
|
||||
}
|
||||
|
||||
//hash the password
|
||||
passwordHashed, err := c.GetHashing().HashPassword(c.CastToString(password))
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": err.Error(),
|
||||
}))
|
||||
}
|
||||
// store the record in db
|
||||
user = models.User{
|
||||
Name: c.CastToString(name),
|
||||
Fullname: c.CastToString(fullname),
|
||||
Email: c.CastToString(email),
|
||||
Password: passwordHashed,
|
||||
}
|
||||
res = c.GetGorm().Create(&user)
|
||||
if res.Error != nil {
|
||||
c.GetLogger().Error(res.Error.Error())
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": res.Error.Error(),
|
||||
}))
|
||||
}
|
||||
|
||||
token, err := c.GetJWT().GenerateToken(map[string]interface{}{
|
||||
"userID": user.ID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
|
||||
// cache the token
|
||||
userAgent := c.GetUserAgent()
|
||||
hashedCacheKey := utils.CreateAuthTokenHashedCacheKey(user.ID, userAgent)
|
||||
err = c.GetCache().Set(hashedCacheKey, token)
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
|
||||
// fire user registered event
|
||||
err = c.GetEventsManager().Fire(&core.Event{Name: events.USER_REGISTERED, Payload: map[string]interface{}{
|
||||
"user": user,
|
||||
}})
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
|
||||
return c.Response.Json(c.MapToJson(map[string]string{
|
||||
"token": token,
|
||||
}))
|
||||
}
|
||||
|
||||
func Signin(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)
|
||||
|
||||
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())
|
||||
if TemplateEnable {
|
||||
// TODO set error in session
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(v.GetErrorMessagesJson())
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
if TemplateEnable {
|
||||
// TODO set error in session
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if res.Error != nil && errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
||||
if TemplateEnable {
|
||||
// TODO set error in session
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid email or password",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
ok, err := c.GetHashing().CheckPasswordHash(user.Password, c.CastToString(password))
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
if TemplateEnable {
|
||||
// TODO set error in session
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": err.Error(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
if TemplateEnable {
|
||||
// TODO set error in session
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid email or password",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
token, err := c.GetJWT().GenerateToken(map[string]interface{}{
|
||||
"userID": user.ID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
// TODO set error in session
|
||||
if TemplateEnable {
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
}
|
||||
// cache the token
|
||||
userAgent := c.GetUserAgent()
|
||||
hashedCacheKey := utils.CreateAuthTokenHashedCacheKey(user.ID, userAgent)
|
||||
err = c.GetCache().Set(hashedCacheKey, token)
|
||||
|
||||
// delete data from old sessions
|
||||
sessionKey := fmt.Sprintf("sess_%v", userAgent)
|
||||
hashedSessionKey := utils.CreateAuthTokenHashedCacheKey(user.ID, sessionKey)
|
||||
_ = c.GetCache().Delete(hashedSessionKey)
|
||||
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
if TemplateEnable {
|
||||
// TODO set error in session
|
||||
return c.Response.Redirect("/applogin")
|
||||
} else {
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if TemplateEnable {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// redirecto to app
|
||||
return c.Response.Redirect("/appsample")
|
||||
} else {
|
||||
return c.Response.Json(c.MapToJson(map[string]string{
|
||||
"token": token,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func ResetPasswordRequest(c *core.Context) *core.Response {
|
||||
email := c.GetRequestParam("email")
|
||||
|
||||
// validation data
|
||||
data := map[string]interface{}{
|
||||
"email": email,
|
||||
}
|
||||
// validation rules
|
||||
rules := map[string]interface{}{
|
||||
"email": "required|email",
|
||||
}
|
||||
// validate
|
||||
v := c.GetValidator().Validate(data, rules)
|
||||
if v.Failed() {
|
||||
c.GetLogger().Error(v.GetErrorMessagesJson())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(v.GetErrorMessagesJson())
|
||||
}
|
||||
|
||||
// check email in the database
|
||||
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.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
if res.Error != nil && errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "email not found in our database",
|
||||
}))
|
||||
}
|
||||
|
||||
// generate the link
|
||||
expiresAt := time.Now().Add(time.Hour * 3).Unix()
|
||||
linkCodeData := map[string]string{
|
||||
"userID": c.CastToString(user.ID),
|
||||
"expiresAt": c.CastToString(expiresAt),
|
||||
}
|
||||
code := uuid.NewString()
|
||||
c.GetCache().SetWithExpiration(code, c.MapToJson(linkCodeData), time.Hour*3)
|
||||
err := c.GetEventsManager().Fire(&core.Event{Name: events.USER_PASSWORD_RESET_REQUESTED, Payload: map[string]interface{}{
|
||||
"user": user,
|
||||
"code": code,
|
||||
}})
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
|
||||
return c.Response.Json(c.MapToJson(map[string]string{
|
||||
"message": "reset password email sent successfully",
|
||||
}))
|
||||
}
|
||||
|
||||
func SetNewPassword(c *core.Context) *core.Response {
|
||||
urlCode := c.CastToString(c.GetPathParam("code"))
|
||||
linkCodeDataStr, err := c.GetCache().Get(urlCode)
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid link",
|
||||
}))
|
||||
}
|
||||
var linkCode map[string]interface{}
|
||||
json.Unmarshal([]byte(linkCodeDataStr), &linkCode)
|
||||
expiresAtUnix, err := strconv.ParseInt(c.CastToString(linkCode["expiresAt"]), 10, 64)
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid link",
|
||||
}))
|
||||
}
|
||||
expiresAt := time.Unix(expiresAtUnix, 0)
|
||||
if time.Now().After(expiresAt) {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid link",
|
||||
}))
|
||||
}
|
||||
userID, err := strconv.ParseUint(c.CastToString(linkCode["userID"]), 10, 64)
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid link",
|
||||
}))
|
||||
}
|
||||
|
||||
oldPassword := c.CastToString(c.GetRequestParam("old_password"))
|
||||
newPassword := c.CastToString(c.GetRequestParam("new_password"))
|
||||
newPasswordConfirm := c.CastToString(c.GetRequestParam("new_password_confirm"))
|
||||
|
||||
// validation data
|
||||
data := map[string]interface{}{
|
||||
"old_password": oldPassword,
|
||||
"new_password": newPassword,
|
||||
"new_password_confirm": newPasswordConfirm,
|
||||
}
|
||||
// validation rules
|
||||
rules := map[string]interface{}{
|
||||
"old_password": "required|length:6,10",
|
||||
"new_password": "required|length:6,10",
|
||||
"new_password_confirm": "required|length:6,10",
|
||||
}
|
||||
// validate
|
||||
v := c.GetValidator().Validate(data, rules)
|
||||
if v.Failed() {
|
||||
c.GetLogger().Error(v.GetErrorMessagesJson())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(v.GetErrorMessagesJson())
|
||||
}
|
||||
|
||||
var user models.User
|
||||
res := c.GetGorm().Where("id = ?", userID).First(&user)
|
||||
if res.Error != nil {
|
||||
c.GetLogger().Error(res.Error.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid link",
|
||||
}))
|
||||
}
|
||||
|
||||
SamePassword, err := c.GetHashing().CheckPasswordHash(user.Password, oldPassword)
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid link",
|
||||
}))
|
||||
}
|
||||
|
||||
if !SamePassword {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "the old password is incorrect",
|
||||
}))
|
||||
}
|
||||
|
||||
if newPassword != newPasswordConfirm {
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "new password does not match new password confirmation",
|
||||
}))
|
||||
}
|
||||
|
||||
hashedNewPassword, err := c.GetHashing().HashPassword(newPassword)
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusUnprocessableEntity).Json(c.MapToJson(map[string]string{
|
||||
"message": "invalid password",
|
||||
}))
|
||||
}
|
||||
|
||||
user.Password = hashedNewPassword
|
||||
c.GetGorm().Save(&user)
|
||||
|
||||
err = c.GetEventsManager().Fire(&core.Event{Name: events.PASSWORD_CHANGED, Payload: map[string]interface{}{
|
||||
"user": user,
|
||||
}})
|
||||
|
||||
if err != nil {
|
||||
c.GetLogger().Error(err.Error())
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]string{
|
||||
"message": "internal server error",
|
||||
}))
|
||||
}
|
||||
|
||||
return c.Response.Json(c.MapToJson(map[string]string{
|
||||
"message": "password changed successfully",
|
||||
}))
|
||||
}
|
||||
|
||||
func Signout(c *core.Context) *core.Response {
|
||||
|
||||
// check if template engine is enable
|
||||
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
||||
if TemplateEnableStr == "" {
|
||||
TemplateEnableStr = "false"
|
||||
}
|
||||
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
||||
|
||||
token := ""
|
||||
|
||||
if TemplateEnable {
|
||||
// get cookie
|
||||
usercookie, err := c.GetCookie()
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
token = usercookie.Token
|
||||
} else {
|
||||
tokenRaw := c.GetHeader("Authorization")
|
||||
token = strings.TrimSpace(strings.Replace(tokenRaw, "Bearer", "", 1))
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": "unauthorized",
|
||||
}))
|
||||
}
|
||||
payload, err := c.GetJWT().DecodeToken(token)
|
||||
if err != nil {
|
||||
return c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": "unauthorized",
|
||||
}))
|
||||
}
|
||||
userAgent := c.GetUserAgent()
|
||||
hashedCacheKey := utils.CreateAuthTokenHashedCacheKey(uint(c.CastToInt(payload["userID"])), userAgent)
|
||||
|
||||
err = c.GetCache().Delete(hashedCacheKey)
|
||||
if err != nil {
|
||||
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": "internal error",
|
||||
}))
|
||||
}
|
||||
|
||||
return c.Response.SetStatusCode(http.StatusOK).Json(c.MapToJson(map[string]interface{}{
|
||||
"message": "signed out successfully",
|
||||
}))
|
||||
}
|
||||
54
controllers/home.go
Normal file
54
controllers/home.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2023 Harran Ali <harran.m@gmail.com>. All rights reserved.
|
||||
// Copyright (c) 2024 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"git.smarteching.com/goffee/core"
|
||||
"git.smarteching.com/goffee/core/template/components"
|
||||
)
|
||||
|
||||
// Show home page
|
||||
func WelcomeHome(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 {
|
||||
|
||||
// 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 {
|
||||
message := "{\"message\": \"Welcome to Goffee\"}"
|
||||
return c.Response.Json(message)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Show dashboard
|
||||
func WelcomeToDashboard(c *core.Context) *core.Response {
|
||||
message := "{\"message\": \"Welcome to Dashboard\"}"
|
||||
return c.Response.Json(message)
|
||||
}
|
||||
52
controllers/queuesample.go
Normal file
52
controllers/queuesample.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 2025 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"git.smarteching.com/goffee/core"
|
||||
"git.smarteching.com/jacs/goffeetabler/workers"
|
||||
"github.com/hibiken/asynq"
|
||||
)
|
||||
|
||||
// Make samples queues
|
||||
func Queuesample(c *core.Context) *core.Response {
|
||||
|
||||
// Get client queue asynq
|
||||
client := c.GetQueueClient()
|
||||
|
||||
// Create a task with typename and payload.
|
||||
payload, err := json.Marshal(workers.EmailTaskPayload{UserID: 42})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
t1 := asynq.NewTask(workers.TypeWelcomeEmail, payload)
|
||||
|
||||
t2 := asynq.NewTask(workers.TypeReminderEmail, payload)
|
||||
|
||||
// Process the task immediately.
|
||||
info, err := client.Enqueue(t1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf(" [*] Successfully enqueued task: %+v", info)
|
||||
|
||||
// Process 2 task 1 min later.
|
||||
for i := 1; i < 3; i++ {
|
||||
info, err = client.Enqueue(t2, asynq.ProcessIn(1*time.Minute))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf(" [*] Successfully enqueued task: %+v", info)
|
||||
}
|
||||
|
||||
message := "{\"message\": \"Task queued\"}"
|
||||
return c.Response.Json(message)
|
||||
|
||||
}
|
||||
149
controllers/sample.go
Normal file
149
controllers/sample.go
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) 2024 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.smarteching.com/goffee/core"
|
||||
"git.smarteching.com/goffee/core/template/components"
|
||||
"git.smarteching.com/jacs/goffeetabler/utils"
|
||||
)
|
||||
|
||||
// Show basic template
|
||||
func Sample(c *core.Context) *core.Response {
|
||||
|
||||
// first, include all compoments
|
||||
type templateData struct {
|
||||
PageCard components.PageCard
|
||||
}
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{
|
||||
PageCard: components.PageCard{
|
||||
CardTitle: "Framework Goffee",
|
||||
CardBody: "Powered by Golang",
|
||||
},
|
||||
}
|
||||
|
||||
return c.Response.Template("basic.html", tmplData)
|
||||
|
||||
}
|
||||
|
||||
// Show basic app login
|
||||
func AppLogin(c *core.Context) *core.Response {
|
||||
|
||||
// first, include all compoments
|
||||
// first, include all compoments
|
||||
type templateData struct {
|
||||
PageCard components.PageCard
|
||||
}
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{
|
||||
PageCard: components.PageCard{
|
||||
CardTitle: "Card title",
|
||||
CardBody: "Loerm ipsum at deim",
|
||||
},
|
||||
}
|
||||
return c.Response.Template("login.html", tmplData)
|
||||
}
|
||||
|
||||
// Show basic app login
|
||||
func AppSession(c *core.Context) *core.Response {
|
||||
|
||||
var session = new(utils.SessionUser)
|
||||
|
||||
// true if session is active
|
||||
hassession := session.Init(c)
|
||||
|
||||
//session.Set("numberdos", 66)
|
||||
|
||||
type templateData struct {
|
||||
PageCard components.PageCard
|
||||
}
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{}
|
||||
|
||||
if hassession {
|
||||
|
||||
sesiondata := ""
|
||||
cardtitle := fmt.Sprintf("Session user id: %v", session.GetUserID())
|
||||
numberdos, ok := session.Get("numberdos")
|
||||
|
||||
if numberdos != nil {
|
||||
numberdos = numberdos.(float64) + 10
|
||||
} else {
|
||||
numberdos = 10
|
||||
}
|
||||
|
||||
session.Set("numberdos", numberdos)
|
||||
|
||||
if ok {
|
||||
sesiondata = fmt.Sprintf("OK, Session numberdos has %v", numberdos)
|
||||
} else {
|
||||
sesiondata = fmt.Sprintf("No ok, session numberdos has %v", numberdos)
|
||||
}
|
||||
|
||||
// delete single
|
||||
//session.Delete("numberdos")
|
||||
|
||||
// delete all data
|
||||
//session.Flush()
|
||||
|
||||
tmplData = templateData{
|
||||
PageCard: components.PageCard{
|
||||
CardTitle: cardtitle,
|
||||
CardBody: sesiondata,
|
||||
},
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
// first, include all compoments
|
||||
type templateData struct {
|
||||
PageCard components.PageCard
|
||||
ContentDropdown components.ContentDropdown
|
||||
}
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{
|
||||
PageCard: components.PageCard{
|
||||
CardTitle: "Protected page",
|
||||
CardBody: "If you can see this page, your are loggedin",
|
||||
},
|
||||
ContentDropdown: components.ContentDropdown{
|
||||
Label: "dropdown",
|
||||
Items: []components.ContentDropdownItem{
|
||||
{
|
||||
Text: "Signout",
|
||||
Link: "#",
|
||||
ID: "signout",
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
//fmt.Printf("Outside cookie user is: %s", user.Email)
|
||||
|
||||
return c.Response.Template("app.html", tmplData)
|
||||
|
||||
}
|
||||
863
controllers/themedemo.go
Normal file
863
controllers/themedemo.go
Normal file
|
|
@ -0,0 +1,863 @@
|
|||
// Copyright (c) 2024 Zeni Kim <zenik@smarteching.com>
|
||||
// Use of this source code is governed by MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"git.smarteching.com/goffee/core"
|
||||
"git.smarteching.com/goffee/core/template/components"
|
||||
)
|
||||
|
||||
// Show home page
|
||||
func Themedemo(c *core.Context) *core.Response {
|
||||
|
||||
// check if template engine is enabled
|
||||
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
||||
if TemplateEnableStr == "" {
|
||||
TemplateEnableStr = "false"
|
||||
}
|
||||
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
||||
|
||||
if TemplateEnable {
|
||||
|
||||
// first, include all compoments
|
||||
type templateData struct {
|
||||
PageCard components.PageCard
|
||||
}
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{
|
||||
PageCard: components.PageCard{
|
||||
CardTitle: "Card title",
|
||||
CardBody: "Loerm ipsum at deim",
|
||||
},
|
||||
}
|
||||
|
||||
return c.Response.Template("custom_theme_base.html", tmplData)
|
||||
|
||||
} else {
|
||||
|
||||
message := "{\"message\": \"Error, template not enabled\"}"
|
||||
return c.Response.Json(message)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Show form element page
|
||||
func Themeform(c *core.Context) *core.Response {
|
||||
|
||||
// check if template engine is enabled
|
||||
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
||||
if TemplateEnableStr == "" {
|
||||
TemplateEnableStr = "false"
|
||||
}
|
||||
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
||||
|
||||
if TemplateEnable {
|
||||
|
||||
// first, include all compoments
|
||||
type templateData struct {
|
||||
FormText components.FormInput
|
||||
FormEmail components.FormInput
|
||||
FormButton components.FormButton
|
||||
FormSelectCity components.FormSelect
|
||||
FormTextarea components.FormTextarea
|
||||
FormRadio components.FormRadio
|
||||
FormCheckbox components.FormCheckbox
|
||||
}
|
||||
|
||||
// for select options
|
||||
var allOptions []components.FormSelectOption
|
||||
var option components.FormSelectOption
|
||||
option.Value = "ch"
|
||||
option.Caption = "China"
|
||||
allOptions = append(allOptions, option)
|
||||
option.Value = "ba"
|
||||
option.Caption = "Buenos Aires"
|
||||
allOptions = append(allOptions, option)
|
||||
option.Value = "fr"
|
||||
option.Caption = "France"
|
||||
selectedOption := option
|
||||
allOptions = append(allOptions, option)
|
||||
|
||||
// for radio options
|
||||
var allOptionsr []components.FormRadioItem
|
||||
var optionr components.FormRadioItem
|
||||
optionr.ID = "citysch"
|
||||
optionr.Name = "citys"
|
||||
optionr.Value = "china"
|
||||
optionr.Label = "China"
|
||||
allOptionsr = append(allOptionsr, optionr)
|
||||
optionr.ID = "citysba"
|
||||
optionr.Name = "citys"
|
||||
optionr.Value = "buenosaires"
|
||||
optionr.Label = "Buenos Aires"
|
||||
//optionr.IsDisabled = true
|
||||
allOptionsr = append(allOptionsr, optionr)
|
||||
|
||||
// for radio options
|
||||
var allOptionsc []components.FormCheckboxItem
|
||||
var optionc components.FormCheckboxItem
|
||||
optionc.ID = "citysch"
|
||||
optionc.Name = "citys"
|
||||
optionc.Value = "china"
|
||||
optionc.Label = "China"
|
||||
allOptionsc = append(allOptionsc, optionc)
|
||||
optionc.ID = "citysba"
|
||||
optionc.Name = "citys"
|
||||
optionc.Value = "buenosaires"
|
||||
optionc.Label = "Buenos Aires"
|
||||
allOptionsc = append(allOptionsc, optionc)
|
||||
optionc.ID = "london"
|
||||
optionc.Name = "london"
|
||||
optionc.Value = "london"
|
||||
optionc.Label = "London"
|
||||
//optionc.IsChecked = true
|
||||
allOptionsc = append(allOptionsc, optionc)
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{
|
||||
FormText: components.FormInput{
|
||||
ID: "text",
|
||||
Label: "Name",
|
||||
Type: "text",
|
||||
Hint: "This is sample hint",
|
||||
Placeholder: "Enter your name",
|
||||
},
|
||||
FormEmail: components.FormInput{
|
||||
ID: "email",
|
||||
Label: "Email",
|
||||
Type: "email",
|
||||
IsRequired: true,
|
||||
Placeholder: "Enter your email address",
|
||||
},
|
||||
FormButton: components.FormButton{
|
||||
Text: "Login",
|
||||
IsSubmit: true,
|
||||
TypeClass: "primary",
|
||||
},
|
||||
FormSelectCity: components.FormSelect{
|
||||
ID: "city",
|
||||
Label: "Select city",
|
||||
AllOptions: allOptions,
|
||||
SelectedOption: selectedOption,
|
||||
},
|
||||
FormTextarea: components.FormTextarea{
|
||||
ID: "text",
|
||||
Label: "Example textarea",
|
||||
},
|
||||
FormRadio: components.FormRadio{
|
||||
Label: "Radio buttons",
|
||||
AllRadios: allOptionsr,
|
||||
},
|
||||
FormCheckbox: components.FormCheckbox{
|
||||
Label: "Checkbox options",
|
||||
AllCheckbox: allOptionsc,
|
||||
},
|
||||
}
|
||||
return c.Response.Template("custom_theme_formpage.html", tmplData)
|
||||
|
||||
} else {
|
||||
|
||||
message := "{\"message\": \"Error, template not enabled\"}"
|
||||
return c.Response.Json(message)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ThemeElements(c *core.Context) *core.Response {
|
||||
// check if template engine is enabled
|
||||
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
||||
if TemplateEnableStr == "" {
|
||||
TemplateEnableStr = "false"
|
||||
}
|
||||
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
||||
|
||||
if TemplateEnable {
|
||||
type templateData struct {
|
||||
Buttons []components.FormButton
|
||||
Hrefs []components.ContentHref
|
||||
Badges []components.ContentBadge
|
||||
Dropdowns []components.ContentDropdown
|
||||
Lists []components.ContentList
|
||||
Menus []components.PageNav
|
||||
}
|
||||
buttons := []components.FormButton{
|
||||
{
|
||||
Text: "primary",
|
||||
TypeClass: "primary",
|
||||
},
|
||||
{
|
||||
Text: "secondary",
|
||||
TypeClass: "secondary",
|
||||
},
|
||||
{
|
||||
Text: "success",
|
||||
TypeClass: "success",
|
||||
},
|
||||
{
|
||||
Text: "danger",
|
||||
TypeClass: "danger",
|
||||
},
|
||||
{
|
||||
Text: "warning",
|
||||
TypeClass: "warning",
|
||||
},
|
||||
{
|
||||
Text: "info",
|
||||
TypeClass: "info",
|
||||
},
|
||||
{
|
||||
Text: "light",
|
||||
TypeClass: "light",
|
||||
},
|
||||
{
|
||||
Text: "dark",
|
||||
TypeClass: "dark",
|
||||
},
|
||||
{
|
||||
Text: "link",
|
||||
TypeClass: "link",
|
||||
},
|
||||
{
|
||||
Text: "disabled",
|
||||
TypeClass: "primary",
|
||||
IsDisabled: true,
|
||||
},
|
||||
{
|
||||
Text: "outline-primary",
|
||||
TypeClass: "outline-primary",
|
||||
},
|
||||
{
|
||||
Text: "outline-secondary",
|
||||
TypeClass: "outline-secondary",
|
||||
},
|
||||
{
|
||||
Text: "outline-success",
|
||||
TypeClass: "outline-success",
|
||||
},
|
||||
{
|
||||
Text: "outline-danger",
|
||||
TypeClass: "outline-danger",
|
||||
},
|
||||
{
|
||||
Text: "outline-warning",
|
||||
TypeClass: "outline-warning",
|
||||
},
|
||||
{
|
||||
Text: "outline-info",
|
||||
TypeClass: "outline-info",
|
||||
},
|
||||
{
|
||||
Text: "outline-light",
|
||||
TypeClass: "outline-light",
|
||||
},
|
||||
{
|
||||
Text: "outline-dark",
|
||||
TypeClass: "outline-dark",
|
||||
},
|
||||
}
|
||||
hrefs := []components.ContentHref{
|
||||
{
|
||||
Text: "href",
|
||||
Link: "#",
|
||||
IsButton: false,
|
||||
},
|
||||
{
|
||||
Text: "link",
|
||||
Link: "#",
|
||||
IsButton: false,
|
||||
TypeClass: "link",
|
||||
},
|
||||
{
|
||||
Text: "button",
|
||||
Link: "#",
|
||||
IsButton: true,
|
||||
TypeClass: "primary",
|
||||
},
|
||||
{
|
||||
Text: "href disabled",
|
||||
Link: "#",
|
||||
IsButton: false,
|
||||
IsDisabled: true,
|
||||
},
|
||||
{
|
||||
Text: "link disabled",
|
||||
Link: "#",
|
||||
TypeClass: "link",
|
||||
IsDisabled: true,
|
||||
},
|
||||
{
|
||||
Text: "button disabled",
|
||||
Link: "#",
|
||||
IsButton: true,
|
||||
TypeClass: "primary",
|
||||
IsDisabled: true,
|
||||
},
|
||||
}
|
||||
badges := []components.ContentBadge{
|
||||
{
|
||||
Text: "primary",
|
||||
TypeClass: "primary",
|
||||
},
|
||||
{
|
||||
Text: "secondary",
|
||||
TypeClass: "secondary",
|
||||
},
|
||||
{
|
||||
Text: "success",
|
||||
TypeClass: "success",
|
||||
},
|
||||
{
|
||||
Text: "danger",
|
||||
TypeClass: "danger",
|
||||
},
|
||||
{
|
||||
Text: "warning",
|
||||
TypeClass: "warning",
|
||||
},
|
||||
{
|
||||
Text: "info",
|
||||
TypeClass: "info",
|
||||
},
|
||||
{
|
||||
Text: "light",
|
||||
TypeClass: "light",
|
||||
},
|
||||
{
|
||||
Text: "dark",
|
||||
TypeClass: "dark",
|
||||
},
|
||||
{
|
||||
Text: "outline",
|
||||
TypeClass: "primary",
|
||||
IsOutline: true,
|
||||
},
|
||||
{
|
||||
Text: "outline",
|
||||
TypeClass: "success",
|
||||
IsOutline: true,
|
||||
},
|
||||
{
|
||||
Text: "outline",
|
||||
TypeClass: "danger",
|
||||
IsOutline: true,
|
||||
},
|
||||
{
|
||||
Text: "outline",
|
||||
TypeClass: "warning",
|
||||
IsOutline: true,
|
||||
},
|
||||
}
|
||||
dropdowns := []components.ContentDropdown{
|
||||
// dropdown
|
||||
{
|
||||
Label: "dropdown",
|
||||
Items: []components.ContentDropdownItem{
|
||||
{
|
||||
Text: "item ",
|
||||
Link: "#",
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// dropdown
|
||||
{
|
||||
Label: "primary",
|
||||
TypeClass: "primary",
|
||||
Items: []components.ContentDropdownItem{
|
||||
{
|
||||
Text: "item ",
|
||||
Link: "#",
|
||||
},
|
||||
{
|
||||
Text: "item ",
|
||||
Link: "#",
|
||||
IsActive: true,
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// dropdown
|
||||
{
|
||||
Label: "outline",
|
||||
TypeClass: "outline-primary",
|
||||
Items: []components.ContentDropdownItem{
|
||||
{
|
||||
Text: "item ",
|
||||
Link: "#",
|
||||
},
|
||||
},
|
||||
},
|
||||
// dropdown
|
||||
{
|
||||
Label: "disabled",
|
||||
TypeClass: "primary",
|
||||
IsDisabled: true,
|
||||
// items
|
||||
},
|
||||
}
|
||||
list := []components.ContentList{
|
||||
// basic list
|
||||
{
|
||||
Items: []components.ContentListItem{
|
||||
{
|
||||
Text: "item 1",
|
||||
},
|
||||
{
|
||||
Text: "item 2",
|
||||
EndElement: "end text",
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// description list
|
||||
{
|
||||
Items: []components.ContentListItem{
|
||||
{
|
||||
Text: "item 1",
|
||||
Description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ",
|
||||
},
|
||||
{
|
||||
Text: "item 2",
|
||||
Description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// list with class
|
||||
{
|
||||
Items: []components.ContentListItem{
|
||||
{
|
||||
Text: "class primary",
|
||||
TypeClass: "primary",
|
||||
},
|
||||
{
|
||||
Text: "class success",
|
||||
TypeClass: "success",
|
||||
},
|
||||
{
|
||||
Text: "class danger",
|
||||
TypeClass: "danger",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
menus := []components.PageNav{
|
||||
// nav
|
||||
{
|
||||
NavClass: "nav-pills",
|
||||
NavItems: []components.PageNavItem{
|
||||
{
|
||||
Text: "item active",
|
||||
Link: "#",
|
||||
IsActive: true,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
ChildItems: []components.PageNavItem{
|
||||
{
|
||||
Text: "item ",
|
||||
Link: "#",
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// nav
|
||||
{
|
||||
NavClass: "",
|
||||
NavItems: []components.PageNavItem{
|
||||
{
|
||||
Text: "item active",
|
||||
Link: "#",
|
||||
IsActive: true,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// nav underline
|
||||
{
|
||||
NavClass: "nav-underline",
|
||||
NavItems: []components.PageNavItem{
|
||||
{
|
||||
Text: "item active",
|
||||
Link: "#",
|
||||
IsActive: true,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// nav tabs
|
||||
{
|
||||
NavClass: "",
|
||||
IsTab: true,
|
||||
NavItems: []components.PageNavItem{
|
||||
{
|
||||
Text: "tab active",
|
||||
Link: "#",
|
||||
IsActive: true,
|
||||
},
|
||||
{
|
||||
Text: "tab",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "tab",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "tab disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// nav vertical
|
||||
{
|
||||
NavClass: "",
|
||||
IsVertical: true,
|
||||
NavItems: []components.PageNavItem{
|
||||
{
|
||||
Text: "item active",
|
||||
Link: "#",
|
||||
IsActive: true,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item",
|
||||
Link: "#",
|
||||
IsActive: false,
|
||||
},
|
||||
{
|
||||
Text: "item disabled",
|
||||
Link: "#",
|
||||
IsDisabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tmplData := templateData{
|
||||
Buttons: buttons,
|
||||
Hrefs: hrefs,
|
||||
Badges: badges,
|
||||
Dropdowns: dropdowns,
|
||||
Lists: list,
|
||||
Menus: menus,
|
||||
}
|
||||
return c.Response.Template("custom_theme_elements.html", tmplData)
|
||||
|
||||
} else {
|
||||
|
||||
message := "{\"message\": \"Error, template not enabled\"}"
|
||||
return c.Response.Json(message)
|
||||
}
|
||||
}
|
||||
|
||||
// Show form element page
|
||||
func Themecontent(c *core.Context) *core.Response {
|
||||
|
||||
// check if template engine is enabled
|
||||
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
||||
if TemplateEnableStr == "" {
|
||||
TemplateEnableStr = "false"
|
||||
}
|
||||
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
||||
|
||||
if TemplateEnable {
|
||||
|
||||
// first, include all compoments
|
||||
type templateData struct {
|
||||
ContentTable components.ContentTable
|
||||
ContentTabledetail components.ContentTabledetail
|
||||
ContentGraph components.ContentGraph
|
||||
FieldText components.FormInput
|
||||
FormSelectCityM components.FormSelect
|
||||
Pagination components.ContentPagination
|
||||
ShouldShowPagination bool
|
||||
}
|
||||
|
||||
// for select options
|
||||
var allOptions []components.FormSelectOption
|
||||
var option components.FormSelectOption
|
||||
option.Value = "ch"
|
||||
option.Caption = "China"
|
||||
allOptions = append(allOptions, option)
|
||||
option.Value = "ba"
|
||||
option.Caption = "Buenos Aires"
|
||||
allOptions = append(allOptions, option)
|
||||
option.Value = "fr"
|
||||
option.Caption = "France"
|
||||
selectedOption := option
|
||||
allOptions = append(allOptions, option)
|
||||
option.Value = "kr"
|
||||
option.Caption = "Korea"
|
||||
allOptions = append(allOptions, option)
|
||||
|
||||
// for custom attributes in form
|
||||
var customAtt []components.CustomAtt
|
||||
var attribute components.CustomAtt
|
||||
attribute.AttName = "code"
|
||||
attribute.AttValue = "five"
|
||||
customAtt = append(customAtt, attribute)
|
||||
attribute.AttName = "mytag"
|
||||
attribute.AttValue = "My value"
|
||||
customAtt = append(customAtt, attribute)
|
||||
|
||||
// TABLES
|
||||
// for th head
|
||||
var allTh []components.ContentTableTH
|
||||
var th components.ContentTableTH
|
||||
th.Value = "Column heading 1"
|
||||
allTh = append(allTh, th)
|
||||
th.Value = "Column heading 2"
|
||||
allTh = append(allTh, th)
|
||||
th.ID = "ba"
|
||||
th.Value = "Column heading 3"
|
||||
allTh = append(allTh, th)
|
||||
th.Value = "Column badge"
|
||||
th.ValueType = "badge" // column type badge
|
||||
allTh = append(allTh, th)
|
||||
th.Value = "Column action"
|
||||
th.ValueType = "href" // column type href
|
||||
allTh = append(allTh, th)
|
||||
|
||||
// for td items
|
||||
var allTd [][]components.ContentTableTD
|
||||
//var vals []components.ContentTableTD
|
||||
// rows
|
||||
for i := 1; i <= 28; i++ {
|
||||
vals := make([]components.ContentTableTD, len(allTh))
|
||||
for b := 0; b < len(allTh)-2; b++ {
|
||||
vals[b].Value = fmt.Sprintf("%s%d%d", "TD data: ", i, b)
|
||||
vals[b].ID = fmt.Sprintf("%s%d%d", "idtd_", i, b)
|
||||
}
|
||||
// column badge
|
||||
vals[len(allTh)-2].Value = components.ContentBadge{
|
||||
Text: "success",
|
||||
TypeClass: "success",
|
||||
}
|
||||
// last column href
|
||||
vals[len(allTh)-1].Value = components.ContentHref{
|
||||
Text: "edit",
|
||||
Link: "#",
|
||||
}
|
||||
allTd = append(allTd, vals)
|
||||
}
|
||||
|
||||
// Pagination demo
|
||||
// start config
|
||||
limit := 10
|
||||
shouldShowPagination := false
|
||||
pageViewTableOffset := 0
|
||||
// Get the length of AllOptions
|
||||
totalrecords := len(allTd)
|
||||
// get current table offset
|
||||
tpage := c.RequestParamExists("tpage")
|
||||
if tpage {
|
||||
pageViewTableOffset, _ = strconv.Atoi(c.GetRequestParam("tpage").(string))
|
||||
}
|
||||
|
||||
// start default option paginator
|
||||
var pagination components.ContentPagination
|
||||
pagination.PageStartRecord = pageViewTableOffset + 1
|
||||
pagination.PageEndRecord = 0
|
||||
pagination.TotalRecords = 0
|
||||
pagination.PrevLink = ""
|
||||
pagination.NextLink = ""
|
||||
|
||||
// check current page
|
||||
// fake function to emulate a query offset
|
||||
newTd := getPaginatedPageViews(allTd, limit, pageViewTableOffset)
|
||||
|
||||
if len(newTd) > 0 {
|
||||
pagination.TotalRecords = totalrecords
|
||||
pagination.PageStartRecord = pageViewTableOffset + 1
|
||||
pagination.PageEndRecord = pageViewTableOffset + len(newTd)
|
||||
shouldShowPagination = totalrecords > limit
|
||||
}
|
||||
|
||||
if shouldShowPagination && pageViewTableOffset != 0 {
|
||||
pagination.PrevLink = fmt.Sprintf("/themecontent?tpage=%d", pageViewTableOffset-limit)
|
||||
}
|
||||
|
||||
if shouldShowPagination && pageViewTableOffset+limit < totalrecords {
|
||||
pagination.NextLink = fmt.Sprintf("/themecontent?tpage=%d", pageViewTableOffset+limit)
|
||||
}
|
||||
|
||||
// for td items in table detail
|
||||
var allTdetail []components.ContentTabledetailTD
|
||||
// table detail
|
||||
var thd components.ContentTabledetailTD
|
||||
thd.Caption = "Continent"
|
||||
thd.Value = "Asia"
|
||||
allTdetail = append(allTdetail, thd)
|
||||
thd.Caption = "Country"
|
||||
thd.Value = "South Korea"
|
||||
allTdetail = append(allTdetail, thd)
|
||||
thd.Caption = "Capital"
|
||||
thd.Value = "Seoul"
|
||||
allTdetail = append(allTdetail, thd)
|
||||
thd.Caption = "Details"
|
||||
thd.ValueType = "href" // column type href
|
||||
thd.Value = components.ContentHref{
|
||||
Text: "edit",
|
||||
Link: "#",
|
||||
}
|
||||
allTdetail = append(allTdetail, thd)
|
||||
thd.Caption = "Notifications"
|
||||
thd.ValueType = "badge" // column type href
|
||||
thd.Value = components.ContentBadge{
|
||||
Text: "success",
|
||||
TypeClass: "success",
|
||||
}
|
||||
allTdetail = append(allTdetail, thd)
|
||||
|
||||
// random values for pie
|
||||
one := rand.IntN(50)
|
||||
two := rand.IntN(50)
|
||||
three := rand.IntN(50)
|
||||
valuesgraph := fmt.Sprintf("%d|%d|%d", one, two, three)
|
||||
|
||||
// now fill data of the components
|
||||
tmplData := templateData{
|
||||
FormSelectCityM: components.FormSelect{
|
||||
ID: "city",
|
||||
Label: "Select city",
|
||||
AllOptions: allOptions,
|
||||
SelectedOption: selectedOption,
|
||||
IsMultiple: true,
|
||||
},
|
||||
FieldText: components.FormInput{
|
||||
ID: "text",
|
||||
Label: "Name",
|
||||
Type: "text",
|
||||
Hint: "This is sample hint",
|
||||
Placeholder: "Enter your name",
|
||||
CustomAtt: customAtt,
|
||||
},
|
||||
ContentTable: components.ContentTable{
|
||||
ID: "table_demo",
|
||||
AllTH: allTh,
|
||||
AllTD: newTd,
|
||||
},
|
||||
ContentTabledetail: components.ContentTabledetail{
|
||||
ID: "table_demodetail",
|
||||
Title: "Sample table detail",
|
||||
HeadClass: "table-warning",
|
||||
AllTD: allTdetail,
|
||||
},
|
||||
ContentGraph: components.ContentGraph{
|
||||
Graph: "pie",
|
||||
Labels: "Berlin|Paris|Venecia",
|
||||
Values: valuesgraph,
|
||||
},
|
||||
Pagination: pagination,
|
||||
ShouldShowPagination: shouldShowPagination,
|
||||
}
|
||||
|
||||
return c.Response.Template("custom_theme_contentpage.html", tmplData)
|
||||
|
||||
} else {
|
||||
|
||||
message := "{\"message\": \"Error, template not enabled\"}"
|
||||
return c.Response.Json(message)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getPaginatedPageViews(values [][]components.ContentTableTD, limit int, offset int) [][]components.ContentTableTD {
|
||||
|
||||
// Validate the offset and adjust if necessary
|
||||
if offset < 0 {
|
||||
offset = 0 // Ensure offset is not negative
|
||||
} else if offset >= len(values) {
|
||||
var emptytd [][]components.ContentTableTD
|
||||
return emptytd
|
||||
}
|
||||
|
||||
// Calculate the end index (limit the slice to the size of the array)
|
||||
end := offset + limit
|
||||
if end > len(values) {
|
||||
end = len(values) // Ensure end doesn't exceed the length of the array
|
||||
}
|
||||
|
||||
return values[offset:end] // Slice the array
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue