feat(admin): add comprehensive admin management system
- Add admin handlers and services for users, posts, comments, groups, and dashboard - Implement role permission management with ability to view and update permissions - Add database seeding for roles and Casbin permission policies - Upgrade Casbin from v2 to v3 with GORM adapter for persistent policy storage - Add admin-specific repository methods with filtering and pagination - Register new admin API routes under /api/v1/admin/*
This commit is contained in:
390
internal/service/admin_group_service.go
Normal file
390
internal/service/admin_group_service.go
Normal file
@@ -0,0 +1,390 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"carrot_bbs/internal/dto"
|
||||
"carrot_bbs/internal/model"
|
||||
"carrot_bbs/internal/repository"
|
||||
)
|
||||
|
||||
// AdminGroupService 管理端群组服务接口
|
||||
type AdminGroupService interface {
|
||||
// GetGroupList 获取群组列表(分页、搜索、筛选)
|
||||
GetGroupList(ctx context.Context, page, pageSize int, keyword, status, ownerID, startDate, endDate string) ([]dto.AdminGroupListResponse, int64, error)
|
||||
// GetGroupDetail 获取群组详情
|
||||
GetGroupDetail(ctx context.Context, groupID string) (*dto.AdminGroupDetailResponse, error)
|
||||
// GetGroupMembers 获取群组成员列表
|
||||
GetGroupMembers(ctx context.Context, groupID string, page, pageSize int) (*dto.AdminGroupMemberListResponse, error)
|
||||
// DeleteGroup 解散群组
|
||||
DeleteGroup(ctx context.Context, groupID string) error
|
||||
// UpdateGroupStatus 更新群组状态
|
||||
UpdateGroupStatus(ctx context.Context, groupID string, status string) (*dto.AdminGroupDetailResponse, error)
|
||||
// RemoveMember 移除群组成员
|
||||
RemoveMember(ctx context.Context, groupID string, userID string) error
|
||||
// TransferOwner 转让群主
|
||||
TransferOwner(ctx context.Context, groupID string, newOwnerID string) (*dto.AdminGroupDetailResponse, error)
|
||||
}
|
||||
|
||||
// adminGroupServiceImpl 管理端群组服务实现
|
||||
type adminGroupServiceImpl struct {
|
||||
groupRepo repository.GroupRepository
|
||||
userRepo *repository.UserRepository
|
||||
}
|
||||
|
||||
// NewAdminGroupService 创建管理端群组服务
|
||||
func NewAdminGroupService(
|
||||
groupRepo repository.GroupRepository,
|
||||
userRepo *repository.UserRepository,
|
||||
) AdminGroupService {
|
||||
return &adminGroupServiceImpl{
|
||||
groupRepo: groupRepo,
|
||||
userRepo: userRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// GetGroupList 获取群组列表
|
||||
func (s *adminGroupServiceImpl) GetGroupList(ctx context.Context, page, pageSize int, keyword, status, ownerID, startDate, endDate string) ([]dto.AdminGroupListResponse, int64, error) {
|
||||
groups, total, err := s.groupRepo.GetGroupList(page, pageSize, keyword, status, ownerID, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
responses := make([]dto.AdminGroupListResponse, 0, len(groups))
|
||||
for _, group := range groups {
|
||||
response := dto.AdminGroupListResponse{
|
||||
ID: group.ID,
|
||||
Name: group.Name,
|
||||
Avatar: group.Avatar,
|
||||
Description: group.Description,
|
||||
OwnerID: group.OwnerID,
|
||||
MemberCount: group.MemberCount,
|
||||
MaxMembers: group.MaxMembers,
|
||||
JoinType: int(group.JoinType),
|
||||
MuteAll: group.MuteAll,
|
||||
Status: "active", // 默认状态为active,后续可以根据需要添加状态字段
|
||||
CreatedAt: dto.FormatTime(group.CreatedAt),
|
||||
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
||||
}
|
||||
|
||||
// 获取群主信息
|
||||
if group.OwnerID != "" {
|
||||
owner, err := s.userRepo.GetByID(group.OwnerID)
|
||||
if err == nil && owner != nil {
|
||||
response.Owner = &dto.UserResponse{
|
||||
ID: owner.ID,
|
||||
Username: owner.Username,
|
||||
Nickname: owner.Nickname,
|
||||
Avatar: owner.Avatar,
|
||||
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取帖子数量
|
||||
postCount, _ := s.groupRepo.GetGroupPostCount(group.ID)
|
||||
response.PostCount = postCount
|
||||
|
||||
responses = append(responses, response)
|
||||
}
|
||||
|
||||
return responses, total, nil
|
||||
}
|
||||
|
||||
// GetGroupDetail 获取群组详情
|
||||
func (s *adminGroupServiceImpl) GetGroupDetail(ctx context.Context, groupID string) (*dto.AdminGroupDetailResponse, error) {
|
||||
group, err := s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &dto.AdminGroupDetailResponse{
|
||||
ID: group.ID,
|
||||
Name: group.Name,
|
||||
Avatar: group.Avatar,
|
||||
Description: group.Description,
|
||||
OwnerID: group.OwnerID,
|
||||
MemberCount: group.MemberCount,
|
||||
MaxMembers: group.MaxMembers,
|
||||
JoinType: int(group.JoinType),
|
||||
MuteAll: group.MuteAll,
|
||||
Status: "active",
|
||||
IsPublic: true, // 默认为公开群组,后续可以根据需要添加字段
|
||||
CreatedAt: dto.FormatTime(group.CreatedAt),
|
||||
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
||||
}
|
||||
|
||||
// 获取群主信息
|
||||
if group.OwnerID != "" {
|
||||
owner, err := s.userRepo.GetByID(group.OwnerID)
|
||||
if err == nil && owner != nil {
|
||||
response.Owner = &dto.UserResponse{
|
||||
ID: owner.ID,
|
||||
Username: owner.Username,
|
||||
Nickname: owner.Nickname,
|
||||
Email: owner.Email,
|
||||
Phone: owner.Phone,
|
||||
Avatar: owner.Avatar,
|
||||
Bio: owner.Bio,
|
||||
Website: owner.Website,
|
||||
Location: owner.Location,
|
||||
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取帖子数量
|
||||
postCount, _ := s.groupRepo.GetGroupPostCount(group.ID)
|
||||
response.PostCount = postCount
|
||||
|
||||
// 获取最新公告
|
||||
announcement, _ := s.groupRepo.GetLatestAnnouncement(groupID)
|
||||
if announcement != nil {
|
||||
response.Announcement = &dto.GroupAnnouncementResponse{
|
||||
ID: announcement.ID,
|
||||
GroupID: announcement.GroupID,
|
||||
Content: announcement.Content,
|
||||
AuthorID: announcement.AuthorID,
|
||||
IsPinned: announcement.IsPinned,
|
||||
CreatedAt: dto.FormatTime(announcement.CreatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetGroupMembers 获取群组成员列表
|
||||
func (s *adminGroupServiceImpl) GetGroupMembers(ctx context.Context, groupID string, page, pageSize int) (*dto.AdminGroupMemberListResponse, error) {
|
||||
// 先检查群组是否存在
|
||||
_, err := s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return nil, errors.New("群组不存在")
|
||||
}
|
||||
|
||||
members, total, err := s.groupRepo.GetMembersWithUserInfo(groupID, page, pageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := make([]*dto.AdminGroupMemberResponse, 0, len(members))
|
||||
for _, member := range members {
|
||||
item := &dto.AdminGroupMemberResponse{
|
||||
ID: member.ID,
|
||||
UserID: member.UserID,
|
||||
Role: member.Role,
|
||||
Nickname: member.Nickname,
|
||||
Muted: member.Muted,
|
||||
JoinedAt: dto.FormatTime(member.JoinTime),
|
||||
}
|
||||
|
||||
if member.User != nil {
|
||||
item.Username = member.User.Username
|
||||
item.Nickname = member.User.Nickname
|
||||
item.Avatar = member.User.Avatar
|
||||
item.User = &dto.UserResponse{
|
||||
ID: member.User.ID,
|
||||
Username: member.User.Username,
|
||||
Nickname: member.User.Nickname,
|
||||
Avatar: member.User.Avatar,
|
||||
CreatedAt: dto.FormatTime(member.User.CreatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
list = append(list, item)
|
||||
}
|
||||
|
||||
return &dto.AdminGroupMemberListResponse{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteGroup 解散群组
|
||||
func (s *adminGroupServiceImpl) DeleteGroup(ctx context.Context, groupID string) error {
|
||||
// 先检查群组是否存在
|
||||
_, err := s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return errors.New("群组不存在")
|
||||
}
|
||||
|
||||
return s.groupRepo.Delete(groupID)
|
||||
}
|
||||
|
||||
// UpdateGroupStatus 更新群组状态
|
||||
func (s *adminGroupServiceImpl) UpdateGroupStatus(ctx context.Context, groupID string, status string) (*dto.AdminGroupDetailResponse, error) {
|
||||
// 先检查群组是否存在
|
||||
group, err := s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return nil, errors.New("群组不存在")
|
||||
}
|
||||
|
||||
// 验证状态值
|
||||
if status != "active" && status != "dissolved" {
|
||||
return nil, errors.New("无效的状态值")
|
||||
}
|
||||
|
||||
// 如果状态是dissolved,则解散群组
|
||||
if status == "dissolved" {
|
||||
err = s.groupRepo.Delete(groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// 更新群组状态
|
||||
err = s.groupRepo.UpdateGroupStatus(groupID, status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 重新获取群组信息
|
||||
group, err = s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := &dto.AdminGroupDetailResponse{
|
||||
ID: group.ID,
|
||||
Name: group.Name,
|
||||
Avatar: group.Avatar,
|
||||
Description: group.Description,
|
||||
OwnerID: group.OwnerID,
|
||||
MemberCount: group.MemberCount,
|
||||
MaxMembers: group.MaxMembers,
|
||||
JoinType: int(group.JoinType),
|
||||
MuteAll: group.MuteAll,
|
||||
Status: status,
|
||||
IsPublic: true,
|
||||
CreatedAt: dto.FormatTime(group.CreatedAt),
|
||||
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
||||
}
|
||||
|
||||
// 获取群主信息
|
||||
if group.OwnerID != "" {
|
||||
owner, err := s.userRepo.GetByID(group.OwnerID)
|
||||
if err == nil && owner != nil {
|
||||
response.Owner = &dto.UserResponse{
|
||||
ID: owner.ID,
|
||||
Username: owner.Username,
|
||||
Nickname: owner.Nickname,
|
||||
Avatar: owner.Avatar,
|
||||
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// RemoveMember 移除群组成员
|
||||
func (s *adminGroupServiceImpl) RemoveMember(ctx context.Context, groupID string, userID string) error {
|
||||
// 先检查群组是否存在
|
||||
_, err := s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return errors.New("群组不存在")
|
||||
}
|
||||
|
||||
// 检查用户是否是群成员
|
||||
member, err := s.groupRepo.GetMember(groupID, userID)
|
||||
if err != nil {
|
||||
return errors.New("用户不是群组成员")
|
||||
}
|
||||
|
||||
// 不能移除群主
|
||||
if member.Role == model.GroupRoleOwner {
|
||||
return errors.New("不能移除群主")
|
||||
}
|
||||
|
||||
return s.groupRepo.RemoveMember(groupID, userID)
|
||||
}
|
||||
|
||||
// TransferOwner 转让群主
|
||||
func (s *adminGroupServiceImpl) TransferOwner(ctx context.Context, groupID string, newOwnerID string) (*dto.AdminGroupDetailResponse, error) {
|
||||
// 先检查群组是否存在
|
||||
group, err := s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return nil, errors.New("群组不存在")
|
||||
}
|
||||
|
||||
// 检查新群主是否是群成员
|
||||
newOwnerMember, err := s.groupRepo.GetMember(groupID, newOwnerID)
|
||||
if err != nil {
|
||||
return nil, errors.New("新群主不是群组成员")
|
||||
}
|
||||
|
||||
// 获取当前群主信息
|
||||
currentOwnerMember, err := s.groupRepo.GetMember(groupID, group.OwnerID)
|
||||
if err != nil {
|
||||
return nil, errors.New("当前群主信息不存在")
|
||||
}
|
||||
|
||||
oldOwnerID := group.OwnerID
|
||||
|
||||
// 更新当前群主为普通成员
|
||||
err = s.groupRepo.SetMemberRole(groupID, oldOwnerID, model.GroupRoleMember)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 更新新群主角色
|
||||
err = s.groupRepo.SetMemberRole(groupID, newOwnerID, model.GroupRoleOwner)
|
||||
if err != nil {
|
||||
// 回滚
|
||||
_ = s.groupRepo.SetMemberRole(groupID, oldOwnerID, model.GroupRoleOwner)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 更新群组的OwnerID
|
||||
group.OwnerID = newOwnerID
|
||||
err = s.groupRepo.Update(group)
|
||||
if err != nil {
|
||||
// 回滚
|
||||
_ = s.groupRepo.SetMemberRole(groupID, oldOwnerID, model.GroupRoleOwner)
|
||||
_ = s.groupRepo.SetMemberRole(groupID, newOwnerID, newOwnerMember.Role)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 重新获取群组信息
|
||||
group, err = s.groupRepo.GetByID(groupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
response := &dto.AdminGroupDetailResponse{
|
||||
ID: group.ID,
|
||||
Name: group.Name,
|
||||
Avatar: group.Avatar,
|
||||
Description: group.Description,
|
||||
OwnerID: group.OwnerID,
|
||||
MemberCount: group.MemberCount,
|
||||
MaxMembers: group.MaxMembers,
|
||||
JoinType: int(group.JoinType),
|
||||
MuteAll: group.MuteAll,
|
||||
Status: "active",
|
||||
IsPublic: true,
|
||||
CreatedAt: dto.FormatTime(group.CreatedAt),
|
||||
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
||||
}
|
||||
|
||||
// 获取新群主信息
|
||||
if group.OwnerID != "" {
|
||||
owner, err := s.userRepo.GetByID(group.OwnerID)
|
||||
if err == nil && owner != nil {
|
||||
response.Owner = &dto.UserResponse{
|
||||
ID: owner.ID,
|
||||
Username: owner.Username,
|
||||
Nickname: owner.Nickname,
|
||||
Avatar: owner.Avatar,
|
||||
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ = currentOwnerMember // 避免 unused variable 警告
|
||||
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user