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).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) { userIdVal := ctx.Value("id") userId, ok := userIdVal.(int64) if !ok || userId == 0 { return nil, ecode.Fail.Sub("user_id_invalid") } exist, err := dao.Authors.Ctx(ctx). Where(dao.Authors.Columns().UserId, 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: userId, PenName: in.PenName, Bio: in.Bio, Status: 1, // 默认正常 }).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{} 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") } if err = dao.Authors.Ctx(ctx).WherePri(in.AuthorId).WithAll().Scan(&out); err != nil { return nil, ecode.Fail.Sub("author_query_failed") } return out, nil }