七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
This commit is contained in:
129
internal/application/wecom/directory.go
Normal file
129
internal/application/wecom/directory.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package wecom
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
)
|
||||
|
||||
// DirectoryMember 是企微 Adapter 交给 Application 的最小成员快照。
|
||||
type DirectoryMember struct {
|
||||
UserID string
|
||||
Name string
|
||||
DepartmentIDs []int64
|
||||
}
|
||||
|
||||
// DirectoryProvider 定义拉取应用可见成员的外部端口。
|
||||
type DirectoryProvider interface {
|
||||
ListVisibleMembers(ctx context.Context, applicationID uint) ([]DirectoryMember, error)
|
||||
}
|
||||
|
||||
// MemberRepository 定义可见成员快照同步和分页查询边界。
|
||||
type MemberRepository interface {
|
||||
ReplaceVisible(ctx context.Context, applicationID uint, members []model.WeComMember, syncedAt time.Time) error
|
||||
ListVisible(ctx context.Context, applicationID uint, page, pageSize int, keyword string) ([]model.WeComMember, int64, error)
|
||||
}
|
||||
|
||||
// DirectoryService 同步并分页查询企业微信应用可见成员。
|
||||
type DirectoryService struct {
|
||||
applications interface {
|
||||
GetEnabled(ctx context.Context, applicationID uint) (*model.WeComApplication, error)
|
||||
}
|
||||
provider DirectoryProvider
|
||||
members MemberRepository
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// NewDirectoryService 创建企业微信通讯录同步用例。
|
||||
func NewDirectoryService(applications interface {
|
||||
GetEnabled(ctx context.Context, applicationID uint) (*model.WeComApplication, error)
|
||||
}, provider DirectoryProvider, members MemberRepository) *DirectoryService {
|
||||
return &DirectoryService{applications: applications, provider: provider, members: members, now: time.Now}
|
||||
}
|
||||
|
||||
// Sync 拉取并替换指定应用当前可见成员快照。
|
||||
func (s *DirectoryService) Sync(ctx context.Context, applicationID uint) (*dto.WeComMemberSyncResponse, error) {
|
||||
if s == nil || s.applications == nil || s.provider == nil || s.members == nil || applicationID == 0 {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "企业微信通讯录服务未配置")
|
||||
}
|
||||
if !canManageWeComDirectory(ctx) {
|
||||
return nil, errors.New(errors.CodeForbidden)
|
||||
}
|
||||
application, err := s.applications.GetEnabled(ctx, applicationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteMembers, err := s.provider.ListVisibleMembers(ctx, applicationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
syncedAt := s.now().UTC()
|
||||
members := make([]model.WeComMember, 0, len(remoteMembers))
|
||||
for _, member := range remoteMembers {
|
||||
departments, err := sonic.Marshal(member.DepartmentIDs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "序列化企业微信成员部门失败")
|
||||
}
|
||||
members = append(members, model.WeComMember{
|
||||
ApplicationID: applicationID, CorpID: application.CorpID, UserID: member.UserID,
|
||||
Name: member.Name, DepartmentIDs: departments, Visible: true, SyncedAt: syncedAt,
|
||||
CreatedAt: syncedAt, UpdatedAt: syncedAt,
|
||||
})
|
||||
}
|
||||
if err := s.members.ReplaceVisible(ctx, applicationID, members, syncedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dto.WeComMemberSyncResponse{ApplicationID: applicationID, SyncedCount: len(members), SyncedAt: syncedAt}, nil
|
||||
}
|
||||
|
||||
// List 分页返回本地最近一次同步的应用可见成员。
|
||||
func (s *DirectoryService) List(ctx context.Context, applicationID uint, request dto.WeComMemberListRequest) (*dto.WeComMemberListResponse, error) {
|
||||
if s == nil || s.applications == nil || s.members == nil || applicationID == 0 {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "企业微信通讯录服务未配置")
|
||||
}
|
||||
if !canManageWeComDirectory(ctx) {
|
||||
return nil, errors.New(errors.CodeForbidden)
|
||||
}
|
||||
if request.Page <= 0 {
|
||||
request.Page = constants.DefaultPage
|
||||
}
|
||||
if request.PageSize <= 0 {
|
||||
request.PageSize = constants.DefaultPageSize
|
||||
}
|
||||
if request.PageSize > constants.MaxPageSize {
|
||||
return nil, errors.New(errors.CodeInvalidParam)
|
||||
}
|
||||
if _, err := s.applications.GetEnabled(ctx, applicationID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
members, total, err := s.members.ListVisible(ctx, applicationID, request.Page, request.PageSize, request.Keyword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]dto.WeComMemberResponse, 0, len(members))
|
||||
for _, member := range members {
|
||||
var departmentIDs []int64
|
||||
if len(member.DepartmentIDs) > 0 {
|
||||
if err := sonic.Unmarshal(member.DepartmentIDs, &departmentIDs); err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "解析企业微信成员部门失败")
|
||||
}
|
||||
}
|
||||
items = append(items, dto.WeComMemberResponse{
|
||||
ApplicationID: member.ApplicationID, CorpID: member.CorpID, UserID: member.UserID,
|
||||
Name: member.Name, DepartmentIDs: departmentIDs, SyncedAt: member.SyncedAt,
|
||||
})
|
||||
}
|
||||
return &dto.WeComMemberListResponse{Items: items, Total: total, Page: request.Page, PageSize: request.PageSize}, nil
|
||||
}
|
||||
|
||||
func canManageWeComDirectory(ctx context.Context) bool {
|
||||
userType := middleware.GetUserTypeFromContext(ctx)
|
||||
return userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform
|
||||
}
|
||||
Reference in New Issue
Block a user