mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 12:17:24 +00:00
Initial commit
This commit is contained in:
254
server/api/file.go
Normal file
254
server/api/file.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/gofiber/fiber/v3/log"
|
||||
"mime/multipart"
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/service"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func AddFileRoutes(router fiber.Router) {
|
||||
fileGroup := router.Group("/files")
|
||||
{
|
||||
fileGroup.Post("/upload/init", initUpload)
|
||||
fileGroup.Post("/upload/block/:id/:index", uploadBlock)
|
||||
fileGroup.Post("/upload/finish/:id", finishUpload)
|
||||
fileGroup.Post("/redirect", createRedirectFile)
|
||||
fileGroup.Get("/:id", getFile)
|
||||
fileGroup.Put("/:id", updateFile)
|
||||
fileGroup.Delete("/:id", deleteFile)
|
||||
}
|
||||
}
|
||||
|
||||
// initUpload 初始化文件上传过程
|
||||
func initUpload(c fiber.Ctx) error {
|
||||
uid := c.Locals("uid").(uint)
|
||||
|
||||
type InitUploadRequest struct {
|
||||
Filename string `json:"filename"`
|
||||
Description string `json:"description"`
|
||||
FileSize int64 `json:"file_size"`
|
||||
ResourceID uint `json:"resource_id"`
|
||||
StorageID uint `json:"storage_id"`
|
||||
}
|
||||
|
||||
var req InitUploadRequest
|
||||
if err := c.Bind().Body(&req); err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的请求参数",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := service.CreateUploadingFile(uid, req.Filename, req.Description, req.FileSize, req.ResourceID, req.StorageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[*model.UploadingFileView]{
|
||||
Success: true,
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
|
||||
// uploadBlock 上传文件块
|
||||
func uploadBlock(c fiber.Ctx) error {
|
||||
uid := c.Locals("uid").(uint)
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的文件ID",
|
||||
})
|
||||
}
|
||||
|
||||
index, err := strconv.Atoi(c.Params("index"))
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的块索引",
|
||||
})
|
||||
}
|
||||
|
||||
file, err := c.Request().MultipartForm()
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的文件数据",
|
||||
})
|
||||
}
|
||||
|
||||
if len(file.File["block"]) == 0 {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "没有找到文件块",
|
||||
})
|
||||
}
|
||||
|
||||
fileHeader := file.File["block"][0]
|
||||
fileContent, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
log.Error("打开文件块失败: ", err)
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "打开文件块失败",
|
||||
})
|
||||
}
|
||||
defer func(fileContent multipart.File) {
|
||||
_ = fileContent.Close()
|
||||
}(fileContent)
|
||||
|
||||
data := make([]byte, fileHeader.Size)
|
||||
if _, err := fileContent.Read(data); err != nil {
|
||||
log.Error("读取文件块失败: ", err)
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "读取文件块失败",
|
||||
})
|
||||
}
|
||||
|
||||
if err := service.UploadBlock(uid, uint(id), index, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: fmt.Sprintf("块 %d 上传成功", index),
|
||||
})
|
||||
}
|
||||
|
||||
// finishUpload 完成文件上传
|
||||
func finishUpload(c fiber.Ctx) error {
|
||||
uid := c.Locals("uid").(uint)
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的文件ID",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := service.FinishUploadingFile(uid, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[*model.FileView]{
|
||||
Success: true,
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
|
||||
// createRedirectFile 创建重定向文件
|
||||
func createRedirectFile(c fiber.Ctx) error {
|
||||
uid := c.Locals("uid").(uint)
|
||||
|
||||
type CreateRedirectFileRequest struct {
|
||||
Filename string `json:"filename"`
|
||||
Description string `json:"description"`
|
||||
ResourceID uint `json:"resource_id"`
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
}
|
||||
|
||||
var req CreateRedirectFileRequest
|
||||
if err := c.Bind().Body(&req); err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的请求参数",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := service.CreateRedirectFile(uid, req.Filename, req.Description, req.ResourceID, req.RedirectURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[*model.FileView]{
|
||||
Success: true,
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
|
||||
// getFile 获取文件信息
|
||||
func getFile(c fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的文件ID",
|
||||
})
|
||||
}
|
||||
|
||||
file, err := service.GetFile(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[*model.FileView]{
|
||||
Success: true,
|
||||
Data: file,
|
||||
})
|
||||
}
|
||||
|
||||
// updateFile 更新文件信息
|
||||
func updateFile(c fiber.Ctx) error {
|
||||
uid := c.Locals("uid").(uint)
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的文件ID",
|
||||
})
|
||||
}
|
||||
|
||||
type UpdateFileRequest struct {
|
||||
Filename string `json:"filename"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
var req UpdateFileRequest
|
||||
if err := c.Bind().Body(&req); err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的请求参数",
|
||||
})
|
||||
}
|
||||
|
||||
result, err := service.UpdateFile(uid, uint(id), req.Filename, req.Description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[*model.FileView]{
|
||||
Success: true,
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
|
||||
// deleteFile 删除文件
|
||||
func deleteFile(c fiber.Ctx) error {
|
||||
uid := c.Locals("uid").(uint)
|
||||
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: false,
|
||||
Message: "无效的文件ID",
|
||||
})
|
||||
}
|
||||
|
||||
if err := service.DeleteFile(uid, uint(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "文件删除成功",
|
||||
})
|
||||
}
|
86
server/api/image.go
Normal file
86
server/api/image.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"net/http"
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/service"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func handleUploadImage(c fiber.Ctx) error {
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
if err := service.HavePermissionToUpload(uid); err != nil {
|
||||
return err
|
||||
}
|
||||
data := c.Body()
|
||||
contentType := http.DetectContentType(data)
|
||||
if !strings.HasPrefix(contentType, "image/") {
|
||||
return model.NewRequestError("Invalid image format")
|
||||
}
|
||||
id, err := service.CreateImage(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[uint]{
|
||||
Success: true,
|
||||
Data: id,
|
||||
Message: "Image uploaded successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleGetImage(c fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
if idStr == "" {
|
||||
return model.NewRequestError("Image ID is required")
|
||||
}
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid image ID")
|
||||
}
|
||||
image, err := service.GetImage(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contentType := http.DetectContentType(image)
|
||||
c.Set("Content-Type", contentType)
|
||||
return c.Send(image)
|
||||
}
|
||||
|
||||
func handleDeleteImage(c fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
if idStr == "" {
|
||||
return model.NewRequestError("Image ID is required")
|
||||
}
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid image ID")
|
||||
}
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
if err := service.HavePermissionToUpload(uid); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := service.DeleteImage(uint(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "Image deleted successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func AddImageRoutes(api fiber.Router) {
|
||||
image := api.Group("/image")
|
||||
{
|
||||
image.Put("/", handleUploadImage)
|
||||
image.Get("/:id", handleGetImage)
|
||||
image.Delete("/:id", handleDeleteImage)
|
||||
}
|
||||
}
|
139
server/api/resource.go
Normal file
139
server/api/resource.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/service"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
func handleCreateResource(c fiber.Ctx) error {
|
||||
var params service.ResourceCreateParams
|
||||
body := c.Body()
|
||||
err := json.Unmarshal(body, ¶ms)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid request body")
|
||||
}
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("You must be logged in to create a resource")
|
||||
}
|
||||
id, err := service.CreateResource(uid, ¶ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[uint]{
|
||||
Success: true,
|
||||
Data: id,
|
||||
Message: "Resource created successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleGetResource(c fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
if idStr == "" {
|
||||
return model.NewRequestError("Resource ID is required")
|
||||
}
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid resource ID")
|
||||
}
|
||||
resource, err := service.GetResource(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.ResourceDetailView]{
|
||||
Success: true,
|
||||
Data: *resource,
|
||||
Message: "Resource retrieved successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleDeleteResource(c fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
if idStr == "" {
|
||||
return model.NewRequestError("Resource ID is required")
|
||||
}
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid resource ID")
|
||||
}
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("You must be logged in to delete a resource")
|
||||
}
|
||||
err = service.DeleteResource(uid, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Data: nil,
|
||||
Message: "Resource deleted successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleListResources(c fiber.Ctx) error {
|
||||
pageStr := c.Query("page")
|
||||
if pageStr == "" {
|
||||
pageStr = "1"
|
||||
}
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid page number")
|
||||
}
|
||||
resources, maxPage, err := service.GetResourceList(page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resources == nil {
|
||||
resources = []model.ResourceView{}
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.ResourceView]{
|
||||
Success: true,
|
||||
Data: resources,
|
||||
TotalPages: maxPage,
|
||||
Message: "Resources retrieved successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleSearchResources(c fiber.Ctx) error {
|
||||
query := c.Query("keyword")
|
||||
if query == "" {
|
||||
return model.NewRequestError("Search query is required")
|
||||
}
|
||||
pageStr := c.Query("page")
|
||||
if pageStr == "" {
|
||||
pageStr = "1"
|
||||
}
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid page number")
|
||||
}
|
||||
resources, totalPages, err := service.SearchResource(query, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resources == nil {
|
||||
resources = []model.ResourceView{}
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.ResourceView]{
|
||||
Success: true,
|
||||
Data: resources,
|
||||
TotalPages: totalPages,
|
||||
Message: "Resources retrieved successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func AddResourceRoutes(api fiber.Router) {
|
||||
resource := api.Group("/resource")
|
||||
{
|
||||
resource.Post("/", handleCreateResource)
|
||||
resource.Get("/search", handleSearchResources)
|
||||
resource.Get("/", handleListResources)
|
||||
resource.Get("/:id", handleGetResource)
|
||||
resource.Delete("/:id", handleDeleteResource)
|
||||
}
|
||||
}
|
118
server/api/storage.go
Normal file
118
server/api/storage.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/service"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
func handleCreateS3Storage(c fiber.Ctx) error {
|
||||
var params service.CreateS3StorageParams
|
||||
if err := c.Bind().JSON(¶ms); err != nil {
|
||||
return model.NewRequestError("Invalid request body")
|
||||
}
|
||||
|
||||
if params.Name == "" || params.EndPoint == "" || params.AccessKeyID == "" ||
|
||||
params.SecretAccessKey == "" || params.BucketName == "" {
|
||||
return model.NewRequestError("All fields are required")
|
||||
}
|
||||
|
||||
if params.MaxSizeInMB <= 0 {
|
||||
return model.NewRequestError("Max size must be greater than 0")
|
||||
}
|
||||
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("You are not authorized to perform this action")
|
||||
}
|
||||
|
||||
err := service.CreateS3Storage(uid, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "S3 storage created successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleCreateLocalStorage(c fiber.Ctx) error {
|
||||
var params service.CreateLocalStorageParams
|
||||
if err := c.Bind().JSON(¶ms); err != nil {
|
||||
return model.NewRequestError("Invalid request body")
|
||||
}
|
||||
|
||||
if params.Name == "" || params.Path == "" {
|
||||
return model.NewRequestError("All fields are required")
|
||||
}
|
||||
|
||||
if params.MaxSizeInMB <= 0 {
|
||||
return model.NewRequestError("Max size must be greater than 0")
|
||||
}
|
||||
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("You are not authorized to perform this action")
|
||||
}
|
||||
|
||||
err := service.CreateLocalStorage(uid, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "Local storage created successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleListStorages(c fiber.Ctx) error {
|
||||
storages, err := service.ListStorages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if storages == nil {
|
||||
storages = []model.StorageView{}
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[*[]model.StorageView]{
|
||||
Success: true,
|
||||
Data: &storages,
|
||||
Message: "Storages retrieved successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleDeleteStorage(c fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid storage ID")
|
||||
}
|
||||
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("You are not authorized to perform this action")
|
||||
}
|
||||
|
||||
err = service.DeleteStorage(uid, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "Storage deleted successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func AddStorageRoutes(r fiber.Router) {
|
||||
s := r.Group("storage")
|
||||
s.Post("/s3", handleCreateS3Storage)
|
||||
s.Post("/local", handleCreateLocalStorage)
|
||||
s.Get("/", handleListStorages)
|
||||
s.Delete("/:id", handleDeleteStorage)
|
||||
}
|
68
server/api/tag.go
Normal file
68
server/api/tag.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/service"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func handleCreateTag(c fiber.Ctx) error {
|
||||
tag := c.FormValue("name")
|
||||
if tag == "" {
|
||||
return model.NewRequestError("name is required")
|
||||
}
|
||||
t, err := service.CreateTag(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.TagView]{
|
||||
Success: true,
|
||||
Data: *t,
|
||||
Message: "Tag created successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleSearchTag(c fiber.Ctx) error {
|
||||
keyword := c.Query("keyword")
|
||||
if keyword == "" {
|
||||
return model.NewRequestError("Keyword is required")
|
||||
}
|
||||
tags, err := service.SearchTag(keyword)
|
||||
if tags == nil {
|
||||
tags = []model.TagView{}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[*[]model.TagView]{
|
||||
Success: true,
|
||||
Data: &tags,
|
||||
Message: "Tags retrieved successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleDeleteTag(c fiber.Ctx) error {
|
||||
id, err := strconv.Atoi(c.Params("id"))
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid tag ID")
|
||||
}
|
||||
err = service.DeleteTag(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Data: nil,
|
||||
Message: "Tag deleted successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func AddTagRoutes(api fiber.Router) {
|
||||
tag := api.Group("/tag")
|
||||
{
|
||||
tag.Post("/", handleCreateTag)
|
||||
tag.Get("/search", handleSearchTag)
|
||||
tag.Delete("/:id", handleDeleteTag)
|
||||
}
|
||||
}
|
282
server/api/user.go
Normal file
282
server/api/user.go
Normal file
@@ -0,0 +1,282 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"nysoure/server/model"
|
||||
"nysoure/server/service"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
func handleUserRegister(c fiber.Ctx) error {
|
||||
username := c.FormValue("username")
|
||||
password := c.FormValue("password")
|
||||
if username == "" || password == "" {
|
||||
return model.NewRequestError("Username and password are required")
|
||||
}
|
||||
if len(password) < 6 {
|
||||
return model.NewRequestError("Password must be at least 6 characters long")
|
||||
}
|
||||
if len(username) < 3 {
|
||||
return model.NewRequestError("Username must be at least 3 characters long")
|
||||
}
|
||||
user, err := service.CreateUser(username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserViewWithToken]{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "User created successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleUserLogin(c fiber.Ctx) error {
|
||||
username := c.FormValue("username")
|
||||
password := c.FormValue("password")
|
||||
if username == "" || password == "" {
|
||||
return model.NewRequestError("Username and password are required")
|
||||
}
|
||||
user, err := service.Login(username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserViewWithToken]{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "Login successful",
|
||||
})
|
||||
}
|
||||
|
||||
func handleUserChangePassword(c fiber.Ctx) error {
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
oldPassword := c.FormValue("old_password")
|
||||
newPassword := c.FormValue("new_password")
|
||||
if oldPassword == "" || newPassword == "" {
|
||||
return model.NewRequestError("Old and new passwords are required")
|
||||
}
|
||||
user, err := service.ChangePassword(uid, oldPassword, newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserViewWithToken]{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "Password changed successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleUserChangeAvatar(c fiber.Ctx) error {
|
||||
uid, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
file, err := c.FormFile("avatar")
|
||||
if err != nil {
|
||||
return model.NewRequestError("Avatar file is required")
|
||||
}
|
||||
f, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageData, err := io.ReadAll(f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := service.ChangeAvatar(uid, imageData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserView]{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "Avatar changed successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleGetUserAvatar(c fiber.Ctx) error {
|
||||
idStr := c.Params("id")
|
||||
uid, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid user ID")
|
||||
}
|
||||
avatar, err := service.GetAvatar(uint(uid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contentType := http.DetectContentType(avatar)
|
||||
c.Set("Content-Type", contentType)
|
||||
c.Set("Cache-Control", "public, max-age=31536000")
|
||||
return c.Send(avatar)
|
||||
}
|
||||
|
||||
func handleSetUserAdmin(c fiber.Ctx) error {
|
||||
adminID, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
|
||||
userIDStr := c.FormValue("user_id")
|
||||
if userIDStr == "" {
|
||||
return model.NewRequestError("User ID is required")
|
||||
}
|
||||
|
||||
userID, err := strconv.Atoi(userIDStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid user ID")
|
||||
}
|
||||
|
||||
isAdminStr := c.FormValue("is_admin")
|
||||
if isAdminStr == "" {
|
||||
return model.NewRequestError("is_admin parameter is required")
|
||||
}
|
||||
|
||||
isAdmin := isAdminStr == "true" || isAdminStr == "1"
|
||||
|
||||
user, err := service.SetUserAdmin(adminID, uint(userID), isAdmin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserView]{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "User admin status updated successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleSetUserUploadPermission(c fiber.Ctx) error {
|
||||
adminID, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
|
||||
userIDStr := c.FormValue("user_id")
|
||||
if userIDStr == "" {
|
||||
return model.NewRequestError("User ID is required")
|
||||
}
|
||||
|
||||
userID, err := strconv.Atoi(userIDStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid user ID")
|
||||
}
|
||||
|
||||
canUploadStr := c.FormValue("can_upload")
|
||||
if canUploadStr == "" {
|
||||
return model.NewRequestError("can_upload parameter is required")
|
||||
}
|
||||
|
||||
canUpload := canUploadStr == "true" || canUploadStr == "1"
|
||||
|
||||
user, err := service.SetUserUploadPermission(adminID, uint(userID), canUpload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[model.UserView]{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "User upload permission updated successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleListUsers(c fiber.Ctx) error {
|
||||
adminID, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
|
||||
pageStr := c.Query("page", "1")
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
users, totalPages, err := service.ListUsers(adminID, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.UserView]{
|
||||
Success: true,
|
||||
TotalPages: totalPages,
|
||||
Data: users,
|
||||
Message: "Users retrieved successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleSearchUsers(c fiber.Ctx) error {
|
||||
adminID, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
|
||||
username := c.Query("username", "")
|
||||
if username == "" {
|
||||
return model.NewRequestError("Username search parameter is required")
|
||||
}
|
||||
|
||||
pageStr := c.Query("page", "1")
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
users, totalPages, err := service.SearchUsers(adminID, username, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.UserView]{
|
||||
Success: true,
|
||||
TotalPages: totalPages,
|
||||
Data: users,
|
||||
Message: "Users found successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func handleDeleteUser(c fiber.Ctx) error {
|
||||
adminID, ok := c.Locals("uid").(uint)
|
||||
if !ok {
|
||||
return model.NewUnAuthorizedError("Unauthorized")
|
||||
}
|
||||
|
||||
userIDStr := c.FormValue("user_id")
|
||||
if userIDStr == "" {
|
||||
return model.NewRequestError("User ID is required")
|
||||
}
|
||||
|
||||
userID, err := strconv.Atoi(userIDStr)
|
||||
if err != nil {
|
||||
return model.NewRequestError("Invalid user ID")
|
||||
}
|
||||
|
||||
if err := service.DeleteUser(adminID, uint(userID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||
Success: true,
|
||||
Message: "User deleted successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func AddUserRoutes(r fiber.Router) {
|
||||
u := r.Group("user")
|
||||
u.Post("/register", handleUserRegister)
|
||||
u.Post("/login", handleUserLogin)
|
||||
u.Put("/avatar", handleUserChangeAvatar)
|
||||
u.Post("/password", handleUserChangePassword)
|
||||
u.Get("/avatar/:id", handleGetUserAvatar)
|
||||
u.Post("/set_admin", handleSetUserAdmin)
|
||||
u.Post("/set_upload_permission", handleSetUserUploadPermission)
|
||||
u.Get("/list", handleListUsers)
|
||||
u.Get("/search", handleSearchUsers)
|
||||
u.Post("/delete", handleDeleteUser)
|
||||
}
|
Reference in New Issue
Block a user