321 lines
8.8 KiB
Go
321 lines
8.8 KiB
Go
package author
|
|
|
|
import (
|
|
"context"
|
|
"server/internal/dao"
|
|
"server/internal/model"
|
|
"server/internal/model/do"
|
|
"server/internal/service"
|
|
"server/utility/ecode"
|
|
"server/utility/encrypt"
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
)
|
|
|
|
type sAuthor struct{}
|
|
|
|
func New() service.IAuthor {
|
|
return &sAuthor{}
|
|
}
|
|
func init() {
|
|
service.RegisterAuthor(New())
|
|
}
|
|
|
|
// List retrieves a paginated list of authors
|
|
func (s *sAuthor) List(ctx context.Context, in *model.AuthorListIn) (out *model.AuthorListOut, err error) {
|
|
out = &model.AuthorListOut{}
|
|
m := dao.Authors.Ctx(ctx)
|
|
if in.PenName != "" {
|
|
m = m.Where(dao.Authors.Columns().PenName+" like ?", "%"+in.PenName+"%")
|
|
}
|
|
if in.Status != 0 {
|
|
m = m.Where(dao.Authors.Columns().Status, in.Status)
|
|
}
|
|
if err = m.Page(in.Page, in.Size).WithAll().ScanAndCount(&out.List, &out.Total, false); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// Create adds a new author
|
|
func (s *sAuthor) Create(ctx context.Context, in *model.AuthorAddIn) (out *model.AuthorCRUDOut, err error) {
|
|
// 开启事务,确保用户和作者同时写入
|
|
err = dao.Authors.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
|
// 检查该 userId 是否已存在作者
|
|
exist, err := dao.Authors.Ctx(ctx).TX(tx).
|
|
Where(dao.Authors.Columns().UserId, in.UserId).
|
|
Exist()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if exist {
|
|
return ecode.Params.Sub("author_user_exists")
|
|
}
|
|
|
|
// 检查用户是否存在
|
|
userExist, err := dao.Users.Ctx(ctx).TX(tx).
|
|
Where(dao.Users.Columns().Id, in.UserId).
|
|
Exist()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if !userExist {
|
|
// 不存在则创建用户,用户名用笔名,密码默认 Aa123456
|
|
hash, err := encrypt.EncryptPassword("Aa123456")
|
|
if err != nil {
|
|
return ecode.Fail.Sub("password_encryption_failed")
|
|
}
|
|
result, err := dao.Users.Ctx(ctx).TX(tx).Data(do.Users{
|
|
Username: in.PenName,
|
|
PasswordHash: hash,
|
|
}).InsertAndGetId()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("author_create_failed")
|
|
}
|
|
in.UserId = result
|
|
}
|
|
|
|
// 创建作者
|
|
_, err = dao.Authors.Ctx(ctx).TX(tx).Data(do.Authors{
|
|
UserId: in.UserId,
|
|
PenName: in.PenName,
|
|
Bio: in.Bio,
|
|
Status: in.Status,
|
|
}).Insert()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("author_create_failed")
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &model.AuthorCRUDOut{Success: true}, nil
|
|
}
|
|
|
|
// Update edits an author
|
|
func (s *sAuthor) Update(ctx context.Context, in *model.AuthorEditIn) (out *model.AuthorCRUDOut, err error) {
|
|
exist, err := dao.Authors.Ctx(ctx).
|
|
WherePri(in.Id).
|
|
Exist()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if !exist {
|
|
return nil, ecode.NotFound.Sub("author_not_found")
|
|
}
|
|
_, err = dao.Authors.Ctx(ctx).
|
|
WherePri(in.Id).
|
|
Data(do.Authors{
|
|
PenName: in.PenName,
|
|
Bio: in.Bio,
|
|
Status: in.Status,
|
|
}).Update()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_update_failed")
|
|
}
|
|
return &model.AuthorCRUDOut{Success: true}, nil
|
|
}
|
|
|
|
// Delete removes an author by id
|
|
func (s *sAuthor) Delete(ctx context.Context, in *model.AuthorDelIn) (out *model.AuthorCRUDOut, err error) {
|
|
exist, err := dao.Authors.Ctx(ctx).
|
|
WherePri(in.Id).
|
|
Exist()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if !exist {
|
|
return nil, ecode.NotFound.Sub("author_not_found")
|
|
}
|
|
|
|
// 开启事务,删除作者及相关数据
|
|
err = dao.Authors.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
|
// 1. 删除作者相关的用户关注记录
|
|
_, err := dao.UserFollowAuthors.Ctx(ctx).TX(tx).
|
|
Where(dao.UserFollowAuthors.Columns().AuthorId, in.Id).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("follow_author_delete_failed")
|
|
}
|
|
|
|
// 2. 删除作者相关的书籍(这里需要递归删除书籍相关的所有数据)
|
|
// 先查询该作者的所有书籍ID
|
|
var bookIds []int64
|
|
err = dao.Books.Ctx(ctx).TX(tx).
|
|
Where(dao.Books.Columns().AuthorId, in.Id).
|
|
Fields("id").
|
|
Scan(&bookIds)
|
|
if err != nil {
|
|
return ecode.Fail.Sub("book_query_failed")
|
|
}
|
|
|
|
if len(bookIds) > 0 {
|
|
// 删除书籍相关的章节
|
|
_, err = dao.Chapters.Ctx(ctx).TX(tx).
|
|
WhereIn(dao.Chapters.Columns().BookId, bookIds).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("chapter_delete_failed")
|
|
}
|
|
|
|
// 删除书籍相关的用户阅读记录
|
|
_, err = dao.UserReadRecords.Ctx(ctx).TX(tx).
|
|
WhereIn(dao.UserReadRecords.Columns().BookId, bookIds).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("read_record_delete_failed")
|
|
}
|
|
|
|
// 删除书籍相关的用户阅读历史
|
|
_, err = dao.UserReadHistory.Ctx(ctx).TX(tx).
|
|
WhereIn(dao.UserReadHistory.Columns().BookId, bookIds).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("history_delete_failed")
|
|
}
|
|
|
|
// 删除书籍相关的用户书架
|
|
_, err = dao.Bookshelves.Ctx(ctx).TX(tx).
|
|
WhereIn(dao.Bookshelves.Columns().BookId, bookIds).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("bookshelf_delete_failed")
|
|
}
|
|
|
|
// 删除书籍相关的用户评分
|
|
_, err = dao.BookRatings.Ctx(ctx).TX(tx).
|
|
WhereIn(dao.BookRatings.Columns().BookId, bookIds).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("rating_delete_failed")
|
|
}
|
|
|
|
// 删除书籍相关的章节购买记录
|
|
_, err = dao.UserChapterPurchases.Ctx(ctx).TX(tx).
|
|
WhereIn(dao.UserChapterPurchases.Columns().BookId, bookIds).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("purchase_delete_failed")
|
|
}
|
|
|
|
// 最后删除书籍
|
|
_, err = dao.Books.Ctx(ctx).TX(tx).
|
|
Where(dao.Books.Columns().AuthorId, in.Id).
|
|
Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("book_delete_failed")
|
|
}
|
|
}
|
|
|
|
// 3. 最后删除作者
|
|
_, err = dao.Authors.Ctx(ctx).TX(tx).WherePri(in.Id).Delete()
|
|
if err != nil {
|
|
return ecode.Fail.Sub("author_delete_failed")
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &model.AuthorCRUDOut{Success: true}, nil
|
|
}
|
|
|
|
// Apply 允许用户申请成为作者
|
|
func (s *sAuthor) Apply(ctx context.Context, in *model.AuthorApplyIn) (out *model.AuthorApplyOut, err error) {
|
|
exist, err := dao.Authors.Ctx(ctx).
|
|
Where(dao.Authors.Columns().UserId, in.UserId).
|
|
Exist()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if exist {
|
|
return nil, ecode.Params.Sub("author_user_exists")
|
|
}
|
|
if _, err := dao.Authors.Ctx(ctx).Data(do.Authors{
|
|
UserId: in.UserId,
|
|
PenName: in.PenName,
|
|
Bio: in.Bio,
|
|
Status: 2, // 默认禁用
|
|
}).Insert(); err != nil {
|
|
return nil, ecode.Fail.Sub("author_create_failed")
|
|
}
|
|
return &model.AuthorApplyOut{Success: true}, nil
|
|
}
|
|
func (s *sAuthor) Detail(ctx context.Context, in *model.AuthorDetailIn) (out *model.AuthorDetailOut, err error) {
|
|
out = &model.AuthorDetailOut{}
|
|
err = dao.Authors.Ctx(ctx).WherePri(in.AuthorId).WithAll().Scan(&out)
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if out == nil {
|
|
return nil, ecode.NotFound.Sub("author_not_found")
|
|
}
|
|
userId := ctx.Value("id")
|
|
if userId != nil {
|
|
exist, err := dao.UserFollowAuthors.Ctx(ctx).
|
|
Where(dao.UserFollowAuthors.Columns().UserId, userId).
|
|
Where(dao.UserFollowAuthors.Columns().AuthorId, in.AuthorId).
|
|
Exist()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("user_follow_author_query_failed")
|
|
}
|
|
out.IsFollowed = exist
|
|
}
|
|
// 查询作者作品数量
|
|
out.WorksCount, err = dao.Books.Ctx(ctx).
|
|
Where(dao.Books.Columns().AuthorId, in.AuthorId).
|
|
Count()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_book_count_failed")
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// AuthorInfo 获取作者信息
|
|
func (s *sAuthor) AuthorInfo(ctx context.Context, in *model.AuthorInfoIn) (out *model.AuthorInfoOut, err error) {
|
|
exist, err := dao.Authors.Ctx(ctx).Where(dao.Authors.Columns().UserId, in.UserId).Exist()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if !exist {
|
|
return nil, ecode.NotFound.Sub("author_not_found")
|
|
}
|
|
|
|
var author struct {
|
|
Id int64 `json:"id"`
|
|
PenName string `json:"penName"`
|
|
}
|
|
err = dao.Authors.Ctx(ctx).Where(dao.Authors.Columns().UserId, in.UserId).Fields("id, pen_name").Scan(&author)
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
|
|
return &model.AuthorInfoOut{
|
|
Id: author.Id,
|
|
PenName: author.PenName,
|
|
Role: "author",
|
|
}, nil
|
|
}
|
|
|
|
// 审核作者申请(通过/拒绝)
|
|
func (s *sAuthor) Review(ctx context.Context, in *model.AuthorReviewIn) (out *model.AuthorReviewOut, err error) {
|
|
exist, err := dao.Authors.Ctx(ctx).WherePri(in.AuthorId).Exist()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_query_failed")
|
|
}
|
|
if !exist {
|
|
return nil, ecode.NotFound.Sub("author_not_found")
|
|
}
|
|
_, err = dao.Authors.Ctx(ctx).WherePri(in.AuthorId).Data(do.Authors{
|
|
Status: in.Status,
|
|
}).Update()
|
|
if err != nil {
|
|
return nil, ecode.Fail.Sub("author_review_failed")
|
|
}
|
|
return &model.AuthorReviewOut{Success: true}, nil
|
|
}
|