Add charactor api.

This commit is contained in:
2025-11-15 16:00:26 +08:00
parent 5cd708454a
commit c9c8eac734
5 changed files with 170 additions and 44 deletions

View File

@@ -239,7 +239,7 @@ func handleUpdateResource(c fiber.Ctx) error {
if !ok { if !ok {
return model.NewUnAuthorizedError("You must be logged in to update a resource") return model.NewUnAuthorizedError("You must be logged in to update a resource")
} }
err = service.EditResource(uid, uint(id), &params) err = service.UpdateResource(uid, uint(id), &params)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -16,10 +16,18 @@ import (
func CreateResource(r model.Resource) (model.Resource, error) { func CreateResource(r model.Resource) (model.Resource, error) {
err := db.Transaction(func(tx *gorm.DB) error { err := db.Transaction(func(tx *gorm.DB) error {
r.ModifiedTime = time.Now() r.ModifiedTime = time.Now()
charactors := r.Charactors
r.Charactors = nil
err := tx.Create(&r).Error err := tx.Create(&r).Error
if err != nil { if err != nil {
return err return err
} }
for _, c := range charactors {
c.ResourceID = r.ID
if err := tx.Create(&c).Error; err != nil {
return err
}
}
if err := tx.Model(&model.User{}).Where("id = ?", r.UserID).Update("resources_count", gorm.Expr("resources_count + ?", 1)).Error; err != nil { if err := tx.Model(&model.User{}).Where("id = ?", r.UserID).Update("resources_count", gorm.Expr("resources_count + ?", 1)).Error; err != nil {
return err return err
} }
@@ -42,6 +50,7 @@ func GetResourceByID(id uint) (model.Resource, error) {
Preload("Files"). Preload("Files").
Preload("Files.User"). Preload("Files.User").
Preload("Files.Storage"). Preload("Files.Storage").
Preload("Charactors").
First(&r, id).Error; err != nil { First(&r, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return model.Resource{}, model.NewNotFoundError("Resource not found") return model.Resource{}, model.NewNotFoundError("Resource not found")
@@ -99,22 +108,60 @@ func GetResourceList(page, pageSize int, sort model.RSort) ([]model.Resource, in
func UpdateResource(r model.Resource) error { func UpdateResource(r model.Resource) error {
// Update a resource in the database // Update a resource in the database
images := r.Images return db.Transaction(func(tx *gorm.DB) error {
tags := r.Tags images := r.Images
r.Images = nil tags := r.Tags
r.Tags = nil charactors := r.Charactors
r.Files = nil r.Charactors = nil
r.ModifiedTime = time.Now() r.Images = nil
if err := db.Save(&r).Error; err != nil { r.Tags = nil
return err r.Files = nil
} r.ModifiedTime = time.Now()
if err := db.Model(&r).Association("Images").Replace(images); err != nil { oldCharactors := []model.Charactor{}
return err if err := db.Model(&model.Charactor{}).Where("resource_id = ?", r.ID).Find(&oldCharactors).Error; err != nil {
} return err
if err := db.Model(&r).Association("Tags").Replace(tags); err != nil { }
return err if err := db.Save(&r).Error; err != nil {
} return err
return nil }
if err := db.Model(&r).Association("Images").Replace(images); err != nil {
return err
}
if err := db.Model(&r).Association("Tags").Replace(tags); err != nil {
return err
}
for _, c := range oldCharactors {
shouldDelete := true
for _, nc := range charactors {
if c.ID == nc.ID {
shouldDelete = false
break
}
}
if shouldDelete {
if err := tx.Delete(&c).Error; err != nil {
return err
}
}
}
for _, c := range charactors {
shouldAdd := true
for _, oc := range oldCharactors {
if c.Equal(&oc) {
shouldAdd = false
break
}
}
if shouldAdd {
c.ID = 0
c.ResourceID = r.ID
if err := tx.Create(&c).Error; err != nil {
return err
}
}
}
return nil
})
} }
func DeleteResource(id uint) error { func DeleteResource(id uint) error {

44
server/model/charactor.go Normal file
View File

@@ -0,0 +1,44 @@
package model
type Charactor struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string `gorm:"type:varchar(100);not null"`
Alias []string `gorm:"serializer:json"`
CV string `gorm:"type:varchar(100)"`
ImageID uint
ResourceID uint
Image *Image `gorm:"foreignKey:ImageID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CharactorView struct {
Id uint `json:"id"`
Name string `json:"name"`
Alias []string `json:"alias"`
CV string `json:"cv"`
Image uint `json:"image"`
}
func (c *Charactor) ToView() *CharactorView {
return &CharactorView{
Id: c.ID,
Name: c.Name,
Alias: c.Alias,
CV: c.CV,
Image: c.ImageID,
}
}
func (c *Charactor) Equal(other *Charactor) bool {
if c.Name != other.Name || c.CV != other.CV || c.ImageID != other.ImageID {
return false
}
if len(c.Alias) != len(other.Alias) {
return false
}
for i := range c.Alias {
if c.Alias[i] != other.Alias[i] {
return false
}
}
return true
}

View File

@@ -21,8 +21,9 @@ type Resource struct {
Downloads uint Downloads uint
Comments uint Comments uint
ModifiedTime time.Time ModifiedTime time.Time
Gallery []uint `gorm:"serializer:json"` Gallery []uint `gorm:"serializer:json"`
GalleryNsfw []uint `gorm:"serializer:json"` GalleryNsfw []uint `gorm:"serializer:json"`
Charactors []Charactor `gorm:"foreignKey:ResourceID"`
} }
type Link struct { type Link struct {
@@ -40,22 +41,23 @@ type ResourceView struct {
} }
type ResourceDetailView struct { type ResourceDetailView struct {
ID uint `json:"id"` ID uint `json:"id"`
Title string `json:"title"` Title string `json:"title"`
AlternativeTitles []string `json:"alternativeTitles"` AlternativeTitles []string `json:"alternativeTitles"`
Links []Link `json:"links"` Links []Link `json:"links"`
Article string `json:"article"` Article string `json:"article"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
Tags []TagView `json:"tags"` Tags []TagView `json:"tags"`
Images []ImageView `json:"images"` Images []ImageView `json:"images"`
Files []FileView `json:"files"` Files []FileView `json:"files"`
Author UserView `json:"author"` Author UserView `json:"author"`
Views uint `json:"views"` Views uint `json:"views"`
Downloads uint `json:"downloads"` Downloads uint `json:"downloads"`
Comments uint `json:"comments"` Comments uint `json:"comments"`
Related []ResourceView `json:"related"` Related []ResourceView `json:"related"`
Gallery []uint `json:"gallery"` Gallery []uint `json:"gallery"`
GalleryNsfw []uint `json:"galleryNsfw"` GalleryNsfw []uint `json:"galleryNsfw"`
Charactors []CharactorView `json:"charactors"`
} }
func (r *Resource) ToView() ResourceView { func (r *Resource) ToView() ResourceView {
@@ -94,6 +96,10 @@ func (r *Resource) ToDetailView() ResourceDetailView {
for i, file := range r.Files { for i, file := range r.Files {
files[i] = *file.ToView() files[i] = *file.ToView()
} }
charactors := make([]CharactorView, len(r.Charactors))
for i, charactor := range r.Charactors {
charactors[i] = *charactor.ToView()
}
return ResourceDetailView{ return ResourceDetailView{
ID: r.ID, ID: r.ID,
Title: r.Title, Title: r.Title,
@@ -110,5 +116,6 @@ func (r *Resource) ToDetailView() ResourceDetailView {
Comments: r.Comments, Comments: r.Comments,
Gallery: r.Gallery, Gallery: r.Gallery,
GalleryNsfw: r.GalleryNsfw, GalleryNsfw: r.GalleryNsfw,
Charactors: charactors,
} }
} }

View File

@@ -22,14 +22,22 @@ const (
) )
type ResourceParams struct { type ResourceParams struct {
Title string `json:"title" binding:"required"` Title string `json:"title" binding:"required"`
AlternativeTitles []string `json:"alternative_titles"` AlternativeTitles []string `json:"alternative_titles"`
Links []model.Link `json:"links"` Links []model.Link `json:"links"`
Tags []uint `json:"tags"` Tags []uint `json:"tags"`
Article string `json:"article"` Article string `json:"article"`
Images []uint `json:"images"` Images []uint `json:"images"`
Gallery []uint `json:"gallery"` Gallery []uint `json:"gallery"`
GalleryNsfw []uint `json:"gallery_nsfw"` GalleryNsfw []uint `json:"gallery_nsfw"`
Charactors []CharactorParams `json:"charactors"`
}
type CharactorParams struct {
Name string `json:"name" binding:"required"`
Alias []string `json:"alias"`
CV string `json:"cv"`
Image uint `json:"image"`
} }
func CreateResource(uid uint, params *ResourceParams) (uint, error) { func CreateResource(uid uint, params *ResourceParams) (uint, error) {
@@ -69,6 +77,15 @@ func CreateResource(uid uint, params *ResourceParams) (uint, error) {
nsfw = append(nsfw, id) nsfw = append(nsfw, id)
} }
} }
charactors := make([]model.Charactor, len(params.Charactors))
for i, c := range params.Charactors {
charactors[i] = model.Charactor{
Name: c.Name,
Alias: c.Alias,
CV: c.CV,
ImageID: c.Image,
}
}
r := model.Resource{ r := model.Resource{
Title: params.Title, Title: params.Title,
AlternativeTitles: params.AlternativeTitles, AlternativeTitles: params.AlternativeTitles,
@@ -79,6 +96,7 @@ func CreateResource(uid uint, params *ResourceParams) (uint, error) {
UserID: uid, UserID: uid,
Gallery: gallery, Gallery: gallery,
GalleryNsfw: nsfw, GalleryNsfw: nsfw,
Charactors: charactors,
} }
if r, err = dao.CreateResource(r); err != nil { if r, err = dao.CreateResource(r); err != nil {
return 0, err return 0, err
@@ -451,7 +469,7 @@ func GetResourcesWithUser(username string, page int) ([]model.ResourceView, int,
return views, totalPages, nil return views, totalPages, nil
} }
func EditResource(uid, rid uint, params *ResourceParams) error { func UpdateResource(uid, rid uint, params *ResourceParams) error {
isAdmin, err := checkUserCanUpload(uid) isAdmin, err := checkUserCanUpload(uid)
if err != nil { if err != nil {
log.Error("checkUserCanUpload error: ", err) log.Error("checkUserCanUpload error: ", err)
@@ -477,6 +495,15 @@ func EditResource(uid, rid uint, params *ResourceParams) error {
nsfw = append(nsfw, id) nsfw = append(nsfw, id)
} }
} }
charactors := make([]model.Charactor, len(params.Charactors))
for i, c := range params.Charactors {
charactors[i] = model.Charactor{
Name: c.Name,
Alias: c.Alias,
CV: c.CV,
ImageID: c.Image,
}
}
r.Title = params.Title r.Title = params.Title
r.AlternativeTitles = params.AlternativeTitles r.AlternativeTitles = params.AlternativeTitles
@@ -484,6 +511,7 @@ func EditResource(uid, rid uint, params *ResourceParams) error {
r.Links = params.Links r.Links = params.Links
r.Gallery = gallery r.Gallery = gallery
r.GalleryNsfw = nsfw r.GalleryNsfw = nsfw
r.Charactors = charactors
images := make([]model.Image, len(params.Images)) images := make([]model.Image, len(params.Images))
for i, id := range params.Images { for i, id := range params.Images {