mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 20:27:23 +00:00
Initial commit
This commit is contained in:
263
server/service/user.go
Normal file
263
server/service/user.go
Normal file
@@ -0,0 +1,263 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"nysoure/server/dao"
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/static"
|
||||
"nysoure/server/utils"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
embedAvatarCount = 1
|
||||
)
|
||||
|
||||
func CreateUser(username, password string) (model.UserViewWithToken, error) {
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
user, err := dao.CreateUser(username, hashedPassword)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
token, err := utils.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
return user.ToView().WithToken(token), nil
|
||||
}
|
||||
|
||||
func Login(username, password string) (model.UserViewWithToken, error) {
|
||||
user, err := dao.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
if model.IsNotFoundError(err) {
|
||||
return model.UserViewWithToken{}, model.NewRequestError("User not found")
|
||||
}
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(password)); err != nil {
|
||||
return model.UserViewWithToken{}, model.NewRequestError("Invalid password")
|
||||
}
|
||||
token, err := utils.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
return user.ToView().WithToken(token), nil
|
||||
}
|
||||
|
||||
func ChangePassword(id uint, oldPassword, newPassword string) (model.UserViewWithToken, error) {
|
||||
user, err := dao.GetUserByID(id)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(oldPassword)); err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
user.PasswordHash = hashedPassword
|
||||
if err := dao.UpdateUser(user); err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
token, err := utils.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
return model.UserViewWithToken{}, err
|
||||
}
|
||||
return user.ToView().WithToken(token), nil
|
||||
}
|
||||
|
||||
func ChangeAvatar(id uint, image []byte) (model.UserView, error) {
|
||||
user, err := dao.GetUserByID(id)
|
||||
if err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
if len(image) > 4*1024*1024 {
|
||||
return model.UserView{}, errors.New("image size is too large")
|
||||
}
|
||||
avatarDir := utils.GetStoragePath() + "/avatar"
|
||||
if _, err := os.Stat(avatarDir); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(avatarDir, os.ModePerm); err != nil {
|
||||
return model.UserView{}, errors.New("failed to create avatar directory")
|
||||
}
|
||||
}
|
||||
avatarPath := avatarDir + "/" + strconv.Itoa(int(user.ID))
|
||||
if err := os.WriteFile(avatarPath, image, 0644); err != nil {
|
||||
return model.UserView{}, errors.New("failed to save avatar")
|
||||
}
|
||||
user.AvatarVersion++
|
||||
if err := dao.UpdateUser(user); err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
return user.ToView(), nil
|
||||
}
|
||||
|
||||
func GetAvatar(id uint) ([]byte, error) {
|
||||
avatarPath := utils.GetStoragePath() + "/avatar/" + strconv.Itoa(int(id))
|
||||
if _, err := os.Stat(avatarPath); os.IsNotExist(err) {
|
||||
return getEmbedAvatar(id)
|
||||
}
|
||||
image, err := os.ReadFile(avatarPath)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to read avatar")
|
||||
}
|
||||
return image, nil
|
||||
}
|
||||
|
||||
func getEmbedAvatar(id uint) ([]byte, error) {
|
||||
fileIndex := id%embedAvatarCount + 1
|
||||
fileName := fmt.Sprintf("avatars/%d.png", fileIndex)
|
||||
return static.Static.ReadFile(fileName)
|
||||
}
|
||||
|
||||
func HavePermissionToUpload(id uint) error {
|
||||
user, err := dao.GetUserByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !user.IsAdmin && !user.CanUpload {
|
||||
return model.NewUnAuthorizedError("User does not have permission to upload")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetUserAdmin(adminID uint, targetUserID uint, isAdmin bool) (model.UserView, error) {
|
||||
if adminID == targetUserID {
|
||||
return model.UserView{}, model.NewRequestError("You cannot modify your own admin status")
|
||||
}
|
||||
|
||||
adminUser, err := dao.GetUserByID(adminID)
|
||||
if err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
|
||||
if !adminUser.IsAdmin {
|
||||
return model.UserView{}, model.NewUnAuthorizedError("Only administrators can modify admin status")
|
||||
}
|
||||
|
||||
targetUser, err := dao.GetUserByID(targetUserID)
|
||||
if err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
|
||||
targetUser.IsAdmin = isAdmin
|
||||
|
||||
if err := dao.UpdateUser(targetUser); err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
|
||||
return targetUser.ToView(), nil
|
||||
}
|
||||
|
||||
func SetUserUploadPermission(adminID uint, targetUserID uint, canUpload bool) (model.UserView, error) {
|
||||
adminUser, err := dao.GetUserByID(adminID)
|
||||
if err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
|
||||
if !adminUser.IsAdmin {
|
||||
return model.UserView{}, model.NewUnAuthorizedError("Only administrators can modify upload permissions")
|
||||
}
|
||||
|
||||
targetUser, err := dao.GetUserByID(targetUserID)
|
||||
if err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
|
||||
targetUser.CanUpload = canUpload
|
||||
|
||||
if err := dao.UpdateUser(targetUser); err != nil {
|
||||
return model.UserView{}, err
|
||||
}
|
||||
|
||||
return targetUser.ToView(), nil
|
||||
}
|
||||
|
||||
func ListUsers(adminID uint, page int) ([]model.UserView, int, error) {
|
||||
admin, err := dao.GetUserByID(adminID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if !admin.IsAdmin {
|
||||
return nil, 0, model.NewUnAuthorizedError("Only administrators can list users")
|
||||
}
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := 10
|
||||
|
||||
users, total, err := dao.ListUsers(page, pageSize)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
userViews := make([]model.UserView, len(users))
|
||||
for i, user := range users {
|
||||
userViews[i] = user.ToView()
|
||||
}
|
||||
|
||||
totalPages := int((total + int64(pageSize) - 1) / int64(pageSize))
|
||||
return userViews, totalPages, nil
|
||||
}
|
||||
|
||||
func SearchUsers(adminID uint, username string, page int) ([]model.UserView, int, error) {
|
||||
admin, err := dao.GetUserByID(adminID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if !admin.IsAdmin {
|
||||
return nil, 0, model.NewUnAuthorizedError("Only administrators can search users")
|
||||
}
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := 10
|
||||
|
||||
users, total, err := dao.SearchUsersByUsername(username, page, pageSize)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
userViews := make([]model.UserView, len(users))
|
||||
for i, user := range users {
|
||||
userViews[i] = user.ToView()
|
||||
}
|
||||
|
||||
totalPages := int((total + int64(pageSize) - 1) / int64(pageSize))
|
||||
return userViews, totalPages, nil
|
||||
}
|
||||
|
||||
func DeleteUser(adminID uint, targetUserID uint) error {
|
||||
admin, err := dao.GetUserByID(adminID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !admin.IsAdmin {
|
||||
return model.NewUnAuthorizedError("Only administrators can delete users")
|
||||
}
|
||||
|
||||
// Check if user is trying to delete themselves
|
||||
if adminID == targetUserID {
|
||||
return model.NewRequestError("You cannot delete your own account")
|
||||
}
|
||||
|
||||
// Check if target user exists
|
||||
_, err = dao.GetUserByID(targetUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return dao.DeleteUser(targetUserID)
|
||||
}
|
Reference in New Issue
Block a user