mirror of
https://github.com/wgh136/nysoure.git
synced 2025-12-15 07:31:14 +00:00
529 lines
14 KiB
Go
529 lines
14 KiB
Go
package api
|
||
|
||
import (
|
||
"encoding/json"
|
||
"net/url"
|
||
"nysoure/server/dao"
|
||
"nysoure/server/model"
|
||
"nysoure/server/service"
|
||
"nysoure/server/utils"
|
||
"strconv"
|
||
|
||
"github.com/gofiber/fiber/v3/log"
|
||
|
||
"github.com/gofiber/fiber/v3"
|
||
)
|
||
|
||
func updateSiteMapAndRss(baseURL string) {
|
||
resources, err := dao.GetAllResources()
|
||
if err != nil {
|
||
log.Error("Error getting resources: ", err)
|
||
}
|
||
utils.GenerateSiteMap(baseURL, resources)
|
||
utils.GenerateRss(baseURL, resources)
|
||
}
|
||
|
||
func handleCreateResource(c fiber.Ctx) error {
|
||
var params service.ResourceParams
|
||
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
|
||
}
|
||
updateSiteMapAndRss(c.BaseURL())
|
||
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")
|
||
}
|
||
host := c.Hostname()
|
||
resource, err := service.GetResource(uint(id), host, c)
|
||
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
|
||
}
|
||
updateSiteMapAndRss(c.BaseURL())
|
||
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")
|
||
}
|
||
sortStr := c.Query("sort")
|
||
if sortStr == "" {
|
||
sortStr = "0"
|
||
}
|
||
sortInt, err := strconv.Atoi(sortStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid sort parameter")
|
||
}
|
||
if sortInt < 0 || sortInt > 5 {
|
||
return model.NewRequestError("Sort parameter out of range")
|
||
}
|
||
sort := model.RSort(sortInt)
|
||
resources, maxPage, err := service.GetResourceList(page, sort)
|
||
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 handleListResourcesWithTag(c fiber.Ctx) error {
|
||
tag := c.Params("tag")
|
||
if tag == "" {
|
||
return model.NewRequestError("Tag is required")
|
||
}
|
||
tag, err := url.PathUnescape(tag)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid tag")
|
||
}
|
||
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.GetResourcesWithTag(tag, 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 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 handleGetResourcesWithUser(c fiber.Ctx) error {
|
||
username := c.Params("username")
|
||
if username == "" {
|
||
return model.NewRequestError("Username is required")
|
||
}
|
||
username, err := url.PathUnescape(username)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid username")
|
||
}
|
||
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.GetResourcesWithUser(username, 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 handleUpdateResource(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")
|
||
}
|
||
var params service.ResourceParams
|
||
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 update a resource")
|
||
}
|
||
err = service.UpdateResource(uid, uint(id), ¶ms)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
updateSiteMapAndRss(c.BaseURL())
|
||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||
Success: true,
|
||
Data: nil,
|
||
Message: "Resource updated successfully",
|
||
})
|
||
}
|
||
|
||
func handleGetRandomResource(c fiber.Ctx) error {
|
||
host := c.Hostname()
|
||
resource, err := service.RandomResource(host)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if resource == nil {
|
||
return model.NewNotFoundError("No resources found")
|
||
}
|
||
return c.Status(fiber.StatusOK).JSON(model.Response[model.ResourceDetailView]{
|
||
Success: true,
|
||
Data: *resource,
|
||
Message: "Random resource retrieved successfully",
|
||
})
|
||
}
|
||
|
||
func handleGetPinnedResources(c fiber.Ctx) error {
|
||
views, err := service.GetPinnedResources()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if views == nil {
|
||
views = []model.ResourceView{}
|
||
}
|
||
return c.Status(fiber.StatusOK).JSON(model.Response[[]model.ResourceView]{
|
||
Success: true,
|
||
Data: views,
|
||
Message: "Pinned resources retrieved successfully",
|
||
})
|
||
}
|
||
|
||
func handleGetCharactersFromVndb(c fiber.Ctx) error {
|
||
vnID := c.Query("vnid")
|
||
if vnID == "" {
|
||
return model.NewRequestError("VNDB ID is required")
|
||
}
|
||
uid, ok := c.Locals("uid").(uint)
|
||
if !ok {
|
||
return model.NewUnAuthorizedError("You must be logged in to get characters from VNDB")
|
||
}
|
||
characters, err := service.GetCharactersFromVndb(vnID, uid)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return c.Status(fiber.StatusOK).JSON(model.Response[[]service.CharacterParams]{
|
||
Success: true,
|
||
Data: characters,
|
||
Message: "Characters retrieved successfully",
|
||
})
|
||
}
|
||
|
||
func handleUpdateCharacterImage(c fiber.Ctx) error {
|
||
resourceIdStr := c.Params("resourceId")
|
||
characterIdStr := c.Params("characterId")
|
||
if resourceIdStr == "" || characterIdStr == "" {
|
||
return model.NewRequestError("Resource ID and Character ID are required")
|
||
}
|
||
resourceId, err := strconv.Atoi(resourceIdStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid resource ID")
|
||
}
|
||
characterId, err := strconv.Atoi(characterIdStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid character ID")
|
||
}
|
||
|
||
var params struct {
|
||
ImageID uint `json:"image_id"`
|
||
}
|
||
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 update a character")
|
||
}
|
||
|
||
err = service.UpdateCharacterImage(uid, uint(resourceId), uint(characterId), params.ImageID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||
Success: true,
|
||
Data: nil,
|
||
Message: "Character image updated successfully",
|
||
})
|
||
}
|
||
|
||
func handleGetLowResolutionCharacters(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")
|
||
}
|
||
|
||
// 支持自定义页面大小,默认50,最大1000
|
||
pageSizeStr := c.Query("page_size")
|
||
if pageSizeStr == "" {
|
||
pageSizeStr = "50"
|
||
}
|
||
pageSize, err := strconv.Atoi(pageSizeStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid page_size parameter")
|
||
}
|
||
if pageSize > 1000 {
|
||
pageSize = 1000 // 限制最大页面大小
|
||
}
|
||
if pageSize < 1 {
|
||
pageSize = 1
|
||
}
|
||
|
||
maxWidthStr := c.Query("max_width")
|
||
if maxWidthStr == "" {
|
||
maxWidthStr = "800" // 默认最大宽度800px
|
||
}
|
||
maxWidth, err := strconv.Atoi(maxWidthStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid max_width parameter")
|
||
}
|
||
|
||
maxHeightStr := c.Query("max_height")
|
||
if maxHeightStr == "" {
|
||
maxHeightStr = "800" // 默认最大高度800px
|
||
}
|
||
maxHeight, err := strconv.Atoi(maxHeightStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid max_height parameter")
|
||
}
|
||
|
||
characters, totalPages, err := service.GetLowResolutionCharacters(page, pageSize, maxWidth, maxHeight)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if characters == nil {
|
||
characters = []model.LowResCharacterView{}
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.LowResCharacterView]{
|
||
Success: true,
|
||
Data: characters,
|
||
TotalPages: totalPages,
|
||
Message: "Low resolution characters retrieved successfully",
|
||
})
|
||
}
|
||
|
||
func handleGetLowResolutionResourceImages(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")
|
||
}
|
||
|
||
// 支持自定义页面大小,默认50,最大1000
|
||
pageSizeStr := c.Query("page_size")
|
||
if pageSizeStr == "" {
|
||
pageSizeStr = "50"
|
||
}
|
||
pageSize, err := strconv.Atoi(pageSizeStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid page_size parameter")
|
||
}
|
||
if pageSize > 1000 {
|
||
pageSize = 1000 // 限制最大页面大小
|
||
}
|
||
if pageSize < 1 {
|
||
pageSize = 1
|
||
}
|
||
|
||
maxWidthStr := c.Query("max_width")
|
||
if maxWidthStr == "" {
|
||
maxWidthStr = "800" // 默认最大宽度800px
|
||
}
|
||
maxWidth, err := strconv.Atoi(maxWidthStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid max_width parameter")
|
||
}
|
||
|
||
maxHeightStr := c.Query("max_height")
|
||
if maxHeightStr == "" {
|
||
maxHeightStr = "800" // 默认最大高度800px
|
||
}
|
||
maxHeight, err := strconv.Atoi(maxHeightStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid max_height parameter")
|
||
}
|
||
|
||
images, totalPages, err := service.GetLowResolutionResourceImages(page, pageSize, maxWidth, maxHeight)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if images == nil {
|
||
images = []model.LowResResourceImageView{}
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.LowResResourceImageView]{
|
||
Success: true,
|
||
Data: images,
|
||
TotalPages: totalPages,
|
||
Message: "Low resolution resource images retrieved successfully",
|
||
})
|
||
}
|
||
|
||
func handleUpdateResourceImage(c fiber.Ctx) error {
|
||
resourceIdStr := c.Params("resourceId")
|
||
oldImageIdStr := c.Params("oldImageId")
|
||
if resourceIdStr == "" || oldImageIdStr == "" {
|
||
return model.NewRequestError("Resource ID and Old Image ID are required")
|
||
}
|
||
resourceId, err := strconv.Atoi(resourceIdStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid resource ID")
|
||
}
|
||
oldImageId, err := strconv.Atoi(oldImageIdStr)
|
||
if err != nil {
|
||
return model.NewRequestError("Invalid old image ID")
|
||
}
|
||
|
||
var params struct {
|
||
NewImageID uint `json:"new_image_id"`
|
||
}
|
||
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 update a resource image")
|
||
}
|
||
|
||
err = service.UpdateResourceImage(uid, uint(resourceId), uint(oldImageId), params.NewImageID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||
Success: true,
|
||
Data: nil,
|
||
Message: "Resource image updated successfully",
|
||
})
|
||
}
|
||
|
||
func AddResourceRoutes(api fiber.Router) {
|
||
resource := api.Group("/resource")
|
||
{
|
||
resource.Post("/", handleCreateResource)
|
||
resource.Get("/search", handleSearchResources)
|
||
resource.Get("/", handleListResources)
|
||
resource.Get("/random", handleGetRandomResource)
|
||
resource.Get("/pinned", handleGetPinnedResources)
|
||
resource.Get("/vndb/characters", handleGetCharactersFromVndb)
|
||
resource.Get("/characters/low-resolution", handleGetLowResolutionCharacters)
|
||
resource.Get("/images/low-resolution", handleGetLowResolutionResourceImages)
|
||
resource.Get("/:id", handleGetResource)
|
||
resource.Delete("/:id", handleDeleteResource)
|
||
resource.Get("/tag/:tag", handleListResourcesWithTag)
|
||
resource.Get("/user/:username", handleGetResourcesWithUser)
|
||
resource.Post("/:id", handleUpdateResource)
|
||
resource.Put("/:resourceId/character/:characterId/image", handleUpdateCharacterImage)
|
||
resource.Put("/:resourceId/image/:oldImageId", handleUpdateResourceImage)
|
||
}
|
||
}
|