339 lines
9.2 KiB
Go
339 lines
9.2 KiB
Go
package users
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"server/internal/db"
|
|
"server/internal/systemUtils"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func repositoryDB() (*gorm.DB, error) {
|
|
database, err := db.GetDB()
|
|
if err != nil {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "database unavailable")
|
|
}
|
|
return database, nil
|
|
}
|
|
|
|
func CreateUser(createUserRequest UserCreateRequest) (*User, error) {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var existing User
|
|
if err := database.Where("email = ?", createUserRequest.Email).First(&existing).Error; err == nil {
|
|
return nil, fiber.NewError(fiber.StatusConflict, "user already exists")
|
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "failed to check user")
|
|
}
|
|
|
|
hashedPassword, err := systemUtils.HashPassword(createUserRequest.Password)
|
|
if err != nil {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
|
}
|
|
|
|
now := time.Now().UTC()
|
|
user := User{
|
|
Email: createUserRequest.Email,
|
|
Name: createUserRequest.Name,
|
|
Password: hashedPassword,
|
|
Permission: createUserRequest.Permission,
|
|
Status: func() UserStatus {
|
|
if createUserRequest.Status == "" {
|
|
return UserStatusPending
|
|
}
|
|
return createUserRequest.Status
|
|
}(),
|
|
Type: func() UserType {
|
|
if createUserRequest.Type == "" {
|
|
return UserType("internal")
|
|
}
|
|
return createUserRequest.Type
|
|
}(),
|
|
Avatar: func() *string {
|
|
if createUserRequest.Avatar == nil {
|
|
return nil
|
|
}
|
|
return createUserRequest.Avatar
|
|
}(),
|
|
ID: uuid.NewString(),
|
|
Details: func() *UserDetails {
|
|
if createUserRequest.Details == nil {
|
|
return nil
|
|
}
|
|
return createUserRequest.Details
|
|
}(),
|
|
Preferences: func() *UserPreferences {
|
|
if createUserRequest.Preferences == nil {
|
|
return nil
|
|
}
|
|
return createUserRequest.Preferences
|
|
}(),
|
|
CreatedAt: &now,
|
|
UpdatedAt: &now,
|
|
}
|
|
|
|
if err := database.Create(&user).Error; err != nil {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "failed to create user")
|
|
}
|
|
|
|
return GetUserByID(user.ID)
|
|
}
|
|
|
|
func UpdateUser(updateUserRequest UpdateUserRequest) (*User, error) {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
user, err := GetUserByID(updateUserRequest.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
now := time.Now().UTC()
|
|
user.Name = updateUserRequest.Name
|
|
user.Email = updateUserRequest.Email
|
|
user.UpdatedAt = &now
|
|
user.Permission = updateUserRequest.Permission
|
|
if updateUserRequest.Status != "" {
|
|
user.Status = updateUserRequest.Status
|
|
}
|
|
if updateUserRequest.Type != "" {
|
|
user.Type = updateUserRequest.Type
|
|
}
|
|
user.Permission = updateUserRequest.Permission
|
|
|
|
if err := database.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Save(user).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "failed to update user")
|
|
}
|
|
|
|
return GetUserByID(user.ID)
|
|
}
|
|
|
|
func UpdateUserDetails(updateUserDetails UpdateUserDetailsRequest) error {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if updateUserDetails.UserID == "" {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid user id")
|
|
}
|
|
|
|
input := &UserDetails{
|
|
UserID: updateUserDetails.UserID,
|
|
Title: updateUserDetails.Title,
|
|
FirstName: updateUserDetails.FirstName,
|
|
LastName: updateUserDetails.LastName,
|
|
Address: updateUserDetails.Address,
|
|
City: updateUserDetails.City,
|
|
ZipCode: updateUserDetails.ZipCode,
|
|
Country: updateUserDetails.Country,
|
|
Phone: updateUserDetails.Phone,
|
|
}
|
|
|
|
if err := database.Transaction(func(tx *gorm.DB) error {
|
|
return syncUserDetails(tx, updateUserDetails.UserID, input)
|
|
}); err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to update user details")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func UpdateUserPreferences(updateUserPreferences UpdateUserPreferencesRequest) error {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if updateUserPreferences.UserID == "" {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid user id")
|
|
}
|
|
|
|
input := &UserPreferences{
|
|
UserID: updateUserPreferences.UserID,
|
|
UseIdle: updateUserPreferences.UseIdle,
|
|
IdleTimeout: updateUserPreferences.IdleTimeout,
|
|
UseIdlePassword: updateUserPreferences.UseIdlePassword,
|
|
IdlePin: updateUserPreferences.IdlePin,
|
|
UseDirectLogin: updateUserPreferences.UseDirectLogin,
|
|
UseQuadcodeLogin: updateUserPreferences.UseQuadcodeLogin,
|
|
SendNoticesMail: updateUserPreferences.SendNoticesMail,
|
|
Language: updateUserPreferences.Language,
|
|
}
|
|
|
|
if err := database.Transaction(func(tx *gorm.DB) error {
|
|
return syncUserPreferences(tx, updateUserPreferences.UserID, input)
|
|
}); err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to update user preferences")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func UpdateUserAvatar(updateUserAvatarRequest UpdateUserAvatarRequest) (*User, error) {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
user, err := GetUserByID(updateUserAvatarRequest.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
avatar := base64.StdEncoding.EncodeToString(updateUserAvatarRequest.Img)
|
|
now := time.Now().UTC()
|
|
if err := database.Model(user).Updates(map[string]any{
|
|
"avatar": avatar,
|
|
"updated_at": now,
|
|
}).Error; err != nil {
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "failed to update user avatar")
|
|
}
|
|
|
|
return GetUserByID(user.ID)
|
|
}
|
|
|
|
func UpdateUserPassword(req UpdatePasswordRequest, id string) error {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user := User{}
|
|
if err := database.Where("uuid = ?", id).First(&user).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return fiber.NewError(fiber.StatusNotFound, "user not found")
|
|
}
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
|
|
}
|
|
hashedPassword, err := systemUtils.HashPassword(req.Password)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
|
}
|
|
now := time.Now().UTC()
|
|
if err := database.Model(&user).Updates(map[string]any{
|
|
"password": hashedPassword,
|
|
"updated_at": now,
|
|
}).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to update password")
|
|
}
|
|
if err := database.Where("user_id = ?", user.ID).Delete(&Session{}).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to revoke sessions")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetUserByID(id string) (*User, error) {
|
|
if id == "" {
|
|
return nil, fiber.NewError(fiber.StatusBadRequest, "invalid user id")
|
|
}
|
|
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var user User
|
|
if err := database.Preload("Details").Preload("Preferences").First(&user, "id = ?", id).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, fiber.NewError(fiber.StatusNotFound, "user not found")
|
|
}
|
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
|
|
}
|
|
|
|
return &user, nil
|
|
}
|
|
|
|
func DeleteUser(uuid string) error {
|
|
database, err := repositoryDB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
user, err := GetUserByID(uuid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := database.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Where("user_id = ?", user.ID).Delete(&UserDetails{}).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Where("user_id = ?", user.ID).Delete(&UserPreferences{}).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.Delete(user).Error
|
|
}); err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to delete user")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func syncUserDetails(tx *gorm.DB, userID string, input *UserDetails) error {
|
|
if input == nil {
|
|
return tx.Where("user_id = ?", userID).Delete(&UserDetails{}).Error
|
|
}
|
|
|
|
var details UserDetails
|
|
if err := tx.Where("user_id = ?", userID).First(&details).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
details = UserDetails{UserID: userID}
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
details.Title = input.Title
|
|
details.FirstName = input.FirstName
|
|
details.LastName = input.LastName
|
|
details.Address = input.Address
|
|
details.City = input.City
|
|
details.ZipCode = input.ZipCode
|
|
details.Country = input.Country
|
|
details.Phone = input.Phone
|
|
|
|
if details.ID == 0 {
|
|
return tx.Create(&details).Error
|
|
}
|
|
return tx.Save(&details).Error
|
|
}
|
|
|
|
func syncUserPreferences(tx *gorm.DB, userID string, input *UserPreferences) error {
|
|
if input == nil {
|
|
return tx.Where("user_id = ?", userID).Delete(&UserPreferences{}).Error
|
|
}
|
|
|
|
var preferences UserPreferences
|
|
if err := tx.Where("user_id = ?", userID).First(&preferences).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
preferences = UserPreferences{UserID: userID}
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
preferences.UseIdle = input.UseIdle
|
|
preferences.IdleTimeout = input.IdleTimeout
|
|
preferences.UseIdlePassword = input.UseIdlePassword
|
|
preferences.IdlePin = input.IdlePin
|
|
preferences.UseDirectLogin = input.UseDirectLogin
|
|
preferences.UseQuadcodeLogin = input.UseQuadcodeLogin
|
|
preferences.SendNoticesMail = input.SendNoticesMail
|
|
preferences.Language = input.Language
|
|
|
|
if preferences.ID == 0 {
|
|
return tx.Create(&preferences).Error
|
|
}
|
|
return tx.Save(&preferences).Error
|
|
}
|