// 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 controllers import ( "errors" "fmt" "strconv" "git.smarteching.com/goffee/core" "git.smarteching.com/goffee/core/template/components" "git.smarteching.com/goffee/cup/events" "git.smarteching.com/goffee/cup/models" "git.smarteching.com/goffee/cup/utils" "gorm.io/gorm" ) func AdminUsersList(c *core.Context) *core.Response { 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: "Created", }, { Value: "Updated", }, { ValueType: "href", }, } rows := make([][]components.ContentTableTD, len(users)) for i, u := range users { row := []components.ContentTableTD{ {Value: strconv.Itoa(int(u.ID))}, {Value: u.Name}, {Value: u.Fullname}, {Value: u.Email}, {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 { // check if is submit submit := c.GetRequestParam("submit").(string) errormessages := make([]string, 0) 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) // 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 { // 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 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, }, 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) 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) 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 { return c.Response.Redirect("/admin/users") } } } // -- response template type templateData struct { FieldName components.FormInput FieldFullname components.FormInput FieldEmail components.FormInput 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, }, 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 { // 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()) } result_db.Unscoped().Delete(&origin_user) } } return c.Response.Redirect("/admin/users") }