Files
nysoure/server/api/resource.go
2025-12-06 16:32:32 +08:00

529 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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, &params)
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, &params)
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, &params)
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), &params)
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, &params)
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, &params)
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)
}
}