feat: add workbench and client settings APIs

This commit is contained in:
richjohnrambo
2026-08-13 23:43:24 +08:00
parent dfcccbb761
commit fa75c0f0f9
17 changed files with 6184 additions and 9 deletions
+549
View File
@@ -1018,6 +1018,7 @@ type CallsPersistenceInterface interface {
Create(tenantID types.TenantID, record *types.CallRecord) error
Accept(tenantID types.TenantID, callID string, seq int, acceptedAt time.Time) error
Finish(tenantID types.TenantID, callID string, seq int, status string, durationMS int64, finishedAt time.Time) error
List(tenantID types.TenantID, uid types.Uid, topic, cursor string, limit int) ([]types.CallRecord, string, error)
}
type callsMapper struct{}
@@ -1064,6 +1065,521 @@ func (callsMapper) Finish(tenantID types.TenantID, callID string, seq int, statu
return tenantAdp.TenantCallFinish(tenantID, callID, seq, status, durationMS, finishedAt)
}
func (callsMapper) List(tenantID types.TenantID, uid types.Uid, topic, cursor string, limit int) ([]types.CallRecord, string, error) {
if uid.IsZero() {
return nil, "", types.ErrMalformed
}
if limit <= 0 || limit > 100 {
limit = 50
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, "", err
}
return tenantAdp.TenantCallList(tenantID, uid, strings.TrimSpace(topic), strings.TrimSpace(cursor), limit)
}
type WorkbenchPersistenceInterface interface {
Get(tenantID types.TenantID, uid types.Uid) ([]types.WorkbenchModule, int, error)
}
type workbenchMapper struct{}
var Workbench WorkbenchPersistenceInterface
func (workbenchMapper) Get(tenantID types.TenantID, uid types.Uid) ([]types.WorkbenchModule, int, error) {
if uid.IsZero() {
return nil, 0, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, 0, err
}
return tenantAdp.TenantWorkbenchModules(tenantID, uid)
}
type OrganizationPersistenceInterface interface {
ListDepartments(tenantID types.TenantID, uid types.Uid, parentID, cursor string, limit int) ([]types.OrganizationDepartment, string, error)
ListMembers(tenantID types.TenantID, uid types.Uid, departmentID, cursor string, limit int) ([]types.OrganizationMember, string, error)
Search(tenantID types.TenantID, uid types.Uid, queryText, resultTypes, cursor string, limit int) ([]types.OrganizationSearchItem, string, error)
}
type organizationMapper struct{}
var Organization OrganizationPersistenceInterface
func (organizationMapper) ListDepartments(tenantID types.TenantID, uid types.Uid, parentID, cursor string, limit int) ([]types.OrganizationDepartment, string, error) {
if uid.IsZero() {
return nil, "", types.ErrMalformed
}
if limit <= 0 || limit > 100 {
limit = 50
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, "", err
}
return tenantAdp.TenantOrganizationDepartments(tenantID, uid, strings.TrimSpace(parentID), strings.TrimSpace(cursor), limit)
}
func (organizationMapper) ListMembers(tenantID types.TenantID, uid types.Uid, departmentID, cursor string, limit int) ([]types.OrganizationMember, string, error) {
if uid.IsZero() || strings.TrimSpace(departmentID) == "" {
return nil, "", types.ErrMalformed
}
if limit <= 0 || limit > 100 {
limit = 50
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, "", err
}
return tenantAdp.TenantOrganizationMembers(tenantID, uid, strings.TrimSpace(departmentID), strings.TrimSpace(cursor), limit)
}
func (organizationMapper) Search(tenantID types.TenantID, uid types.Uid, queryText, resultTypes, cursor string, limit int) ([]types.OrganizationSearchItem, string, error) {
if uid.IsZero() || strings.TrimSpace(queryText) == "" {
return nil, "", types.ErrMalformed
}
if limit <= 0 || limit > 100 {
limit = 50
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, "", err
}
return tenantAdp.TenantOrganizationSearch(tenantID, uid, strings.TrimSpace(queryText), strings.TrimSpace(resultTypes), strings.TrimSpace(cursor), limit)
}
type MeetingsPersistenceInterface interface {
Create(tenantID types.TenantID, uid types.Uid, meeting *types.Meeting, attendeeIDs []types.Uid) (*types.Meeting, error)
Get(tenantID types.TenantID, uid types.Uid, meetingID string) (*types.Meeting, error)
Update(tenantID types.TenantID, uid types.Uid, meetingID string, patch types.MeetingPatch, idempotencyKey string) (*types.Meeting, error)
Cancel(tenantID types.TenantID, uid types.Uid, meetingID, idempotencyKey string) (*types.Meeting, error)
Remind(tenantID types.TenantID, uid types.Uid, meetingID, idempotencyKey string) ([]types.MeetingParticipant, error)
Respond(tenantID types.TenantID, uid types.Uid, meetingID, response string, version int) (*types.Meeting, error)
}
type meetingsMapper struct{}
var Meetings MeetingsPersistenceInterface
func (meetingsMapper) Create(tenantID types.TenantID, uid types.Uid, meeting *types.Meeting, attendeeIDs []types.Uid) (*types.Meeting, error) {
if uid.IsZero() || meeting == nil || !validMeetingForCreate(meeting) {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMeetingCreate(tenantID, uid, meeting, attendeeIDs)
}
func (meetingsMapper) Get(tenantID types.TenantID, uid types.Uid, meetingID string) (*types.Meeting, error) {
if uid.IsZero() || strings.TrimSpace(meetingID) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMeetingGet(tenantID, uid, strings.TrimSpace(meetingID))
}
func (meetingsMapper) Update(tenantID types.TenantID, uid types.Uid, meetingID string, patch types.MeetingPatch, idempotencyKey string) (*types.Meeting, error) {
if uid.IsZero() || strings.TrimSpace(meetingID) == "" || patch.Version <= 0 || !validMeetingPatch(patch) {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMeetingUpdate(tenantID, uid, strings.TrimSpace(meetingID), patch, strings.TrimSpace(idempotencyKey))
}
func (meetingsMapper) Cancel(tenantID types.TenantID, uid types.Uid, meetingID, idempotencyKey string) (*types.Meeting, error) {
if uid.IsZero() || strings.TrimSpace(meetingID) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMeetingCancel(tenantID, uid, strings.TrimSpace(meetingID), strings.TrimSpace(idempotencyKey))
}
func (meetingsMapper) Remind(tenantID types.TenantID, uid types.Uid, meetingID, idempotencyKey string) ([]types.MeetingParticipant, error) {
if uid.IsZero() || strings.TrimSpace(meetingID) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMeetingRemind(tenantID, uid, strings.TrimSpace(meetingID), strings.TrimSpace(idempotencyKey))
}
func (meetingsMapper) Respond(tenantID types.TenantID, uid types.Uid, meetingID, response string, version int) (*types.Meeting, error) {
if uid.IsZero() || strings.TrimSpace(meetingID) == "" || !validMeetingResponse(response) || version <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMeetingRespond(tenantID, uid, strings.TrimSpace(meetingID), strings.TrimSpace(response), version)
}
func validMeetingForCreate(meeting *types.Meeting) bool {
return strings.TrimSpace(meeting.MeetingID) != "" &&
strings.TrimSpace(meeting.Title) != "" &&
!meeting.StartAt.IsZero() &&
!meeting.EndAt.IsZero() &&
meeting.EndAt.After(meeting.StartAt)
}
func validMeetingPatch(patch types.MeetingPatch) bool {
if patch.Title == nil && patch.StartAt == nil && patch.EndAt == nil && patch.Location == nil && patch.ReminderMinutes == nil {
return false
}
if patch.Title != nil && strings.TrimSpace(*patch.Title) == "" {
return false
}
if patch.StartAt != nil && patch.EndAt != nil && !patch.EndAt.After(*patch.StartAt) {
return false
}
return true
}
func validMeetingResponse(response string) bool {
switch strings.TrimSpace(response) {
case types.MeetingResponseAccepted, types.MeetingResponseDeclined, types.MeetingResponseTentative:
return true
default:
return false
}
}
type DailyReportsPersistenceInterface interface {
List(tenantID types.TenantID, uid types.Uid, scope, from, to, status, cursor string, limit int) ([]types.DailyReport, string, error)
CreateDraft(tenantID types.TenantID, uid types.Uid, reportID string, reportDate time.Time) (*types.DailyReport, error)
Get(tenantID types.TenantID, uid types.Uid, reportID string) (*types.DailyReport, error)
SaveDraft(tenantID types.TenantID, uid types.Uid, reportID, content string, attachments []string, version int) (*types.DailyReport, error)
Submit(tenantID types.TenantID, uid types.Uid, reportID string, version int) (*types.DailyReport, error)
Stats(tenantID types.TenantID, uid types.Uid, date time.Time, departmentID string) (*types.DailyReportStats, error)
Remind(tenantID types.TenantID, uid types.Uid, date time.Time, userIDs []types.Uid, idempotencyKey string) ([]types.Uid, error)
}
type dailyReportsMapper struct{}
var DailyReports DailyReportsPersistenceInterface
func (dailyReportsMapper) List(tenantID types.TenantID, uid types.Uid, scope, from, to, status, cursor string, limit int) ([]types.DailyReport, string, error) {
if uid.IsZero() {
return nil, "", types.ErrMalformed
}
if limit <= 0 || limit > 100 {
limit = 50
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, "", err
}
return tenantAdp.TenantDailyReportList(tenantID, uid, strings.TrimSpace(scope), strings.TrimSpace(from), strings.TrimSpace(to), strings.TrimSpace(status), strings.TrimSpace(cursor), limit)
}
func (dailyReportsMapper) CreateDraft(tenantID types.TenantID, uid types.Uid, reportID string, reportDate time.Time) (*types.DailyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" || reportDate.IsZero() {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDailyReportCreateDraft(tenantID, uid, strings.TrimSpace(reportID), reportDate)
}
func (dailyReportsMapper) Get(tenantID types.TenantID, uid types.Uid, reportID string) (*types.DailyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDailyReportGet(tenantID, uid, strings.TrimSpace(reportID))
}
func (dailyReportsMapper) SaveDraft(tenantID types.TenantID, uid types.Uid, reportID, content string, attachments []string, version int) (*types.DailyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" || version <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDailyReportSaveDraft(tenantID, uid, strings.TrimSpace(reportID), content, attachments, version)
}
func (dailyReportsMapper) Submit(tenantID types.TenantID, uid types.Uid, reportID string, version int) (*types.DailyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" || version <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDailyReportSubmit(tenantID, uid, strings.TrimSpace(reportID), version)
}
func (dailyReportsMapper) Stats(tenantID types.TenantID, uid types.Uid, date time.Time, departmentID string) (*types.DailyReportStats, error) {
if uid.IsZero() || date.IsZero() {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDailyReportStats(tenantID, uid, date, strings.TrimSpace(departmentID))
}
func (dailyReportsMapper) Remind(tenantID types.TenantID, uid types.Uid, date time.Time, userIDs []types.Uid, idempotencyKey string) ([]types.Uid, error) {
if uid.IsZero() || date.IsZero() || strings.TrimSpace(idempotencyKey) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDailyReportRemind(tenantID, uid, date, userIDs, strings.TrimSpace(idempotencyKey))
}
type MonthlyReportsPersistenceInterface interface {
List(tenantID types.TenantID, uid types.Uid, scope, fromMonth, toMonth, status, cursor string, limit int) ([]types.MonthlyReport, string, error)
CreateDraft(tenantID types.TenantID, uid types.Uid, reportID, month string) (*types.MonthlyReport, error)
Get(tenantID types.TenantID, uid types.Uid, reportID string) (*types.MonthlyReport, error)
SaveDraft(tenantID types.TenantID, uid types.Uid, reportID, workSummary, nextPlan string, attachments []string, version int) (*types.MonthlyReport, error)
Submit(tenantID types.TenantID, uid types.Uid, reportID string, version int) (*types.MonthlyReport, error)
Stats(tenantID types.TenantID, uid types.Uid, month, departmentID string) (*types.MonthlyReportStats, error)
}
type monthlyReportsMapper struct{}
var MonthlyReports MonthlyReportsPersistenceInterface
func (monthlyReportsMapper) List(tenantID types.TenantID, uid types.Uid, scope, fromMonth, toMonth, status, cursor string, limit int) ([]types.MonthlyReport, string, error) {
if uid.IsZero() {
return nil, "", types.ErrMalformed
}
if limit <= 0 || limit > 100 {
limit = 50
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, "", err
}
return tenantAdp.TenantMonthlyReportList(tenantID, uid, strings.TrimSpace(scope), strings.TrimSpace(fromMonth), strings.TrimSpace(toMonth), strings.TrimSpace(status), strings.TrimSpace(cursor), limit)
}
func (monthlyReportsMapper) CreateDraft(tenantID types.TenantID, uid types.Uid, reportID, month string) (*types.MonthlyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" || strings.TrimSpace(month) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMonthlyReportCreateDraft(tenantID, uid, strings.TrimSpace(reportID), strings.TrimSpace(month))
}
func (monthlyReportsMapper) Get(tenantID types.TenantID, uid types.Uid, reportID string) (*types.MonthlyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMonthlyReportGet(tenantID, uid, strings.TrimSpace(reportID))
}
func (monthlyReportsMapper) SaveDraft(tenantID types.TenantID, uid types.Uid, reportID, workSummary, nextPlan string, attachments []string, version int) (*types.MonthlyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" || version <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMonthlyReportSaveDraft(tenantID, uid, strings.TrimSpace(reportID), workSummary, nextPlan, attachments, version)
}
func (monthlyReportsMapper) Submit(tenantID types.TenantID, uid types.Uid, reportID string, version int) (*types.MonthlyReport, error) {
if uid.IsZero() || strings.TrimSpace(reportID) == "" || version <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMonthlyReportSubmit(tenantID, uid, strings.TrimSpace(reportID), version)
}
func (monthlyReportsMapper) Stats(tenantID types.TenantID, uid types.Uid, month, departmentID string) (*types.MonthlyReportStats, error) {
if uid.IsZero() || strings.TrimSpace(month) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMonthlyReportStats(tenantID, uid, strings.TrimSpace(month), strings.TrimSpace(departmentID))
}
type MailboxPersistenceInterface interface {
Config(tenantID types.TenantID, uid types.Uid) (*types.MailboxConfig, error)
Submit(tenantID types.TenantID, uid types.Uid, submission *types.MailboxSubmission, idempotencyKey string) (*types.MailboxSubmission, error)
}
type mailboxMapper struct{}
var Mailbox MailboxPersistenceInterface
func (mailboxMapper) Config(tenantID types.TenantID, uid types.Uid) (*types.MailboxConfig, error) {
if uid.IsZero() {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMailboxConfigGet(tenantID, uid)
}
func (mailboxMapper) Submit(tenantID types.TenantID, uid types.Uid, submission *types.MailboxSubmission, idempotencyKey string) (*types.MailboxSubmission, error) {
if uid.IsZero() || submission == nil || strings.TrimSpace(submission.SubmissionID) == "" ||
strings.TrimSpace(submission.Subject) == "" || strings.TrimSpace(submission.Content) == "" ||
strings.TrimSpace(idempotencyKey) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantMailboxSubmissionCreate(tenantID, uid, submission, strings.TrimSpace(idempotencyKey))
}
type ProfilePersistenceInterface interface {
Get(tenantID types.TenantID, uid types.Uid) (*types.UserProfile, error)
Update(tenantID types.TenantID, uid types.Uid, patch types.UserProfilePatch) (*types.UserProfile, error)
GetPrivacy(tenantID types.TenantID, uid types.Uid) (*types.UserPrivacySettings, error)
UpdatePrivacy(tenantID types.TenantID, uid types.Uid, patch types.UserPrivacyPatch) (*types.UserPrivacySettings, error)
}
type profileMapper struct{}
var Profiles ProfilePersistenceInterface
type AppReleasePersistenceInterface interface {
Latest(tenantID types.TenantID, platform, channel string) (*types.AppRelease, error)
}
type appReleaseMapper struct{}
var AppReleases AppReleasePersistenceInterface
func (appReleaseMapper) Latest(tenantID types.TenantID, platform, channel string) (*types.AppRelease, error) {
platform = strings.ToLower(strings.TrimSpace(platform))
channel = strings.ToLower(strings.TrimSpace(channel))
if platform == "" || channel == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantAppReleaseLatest(tenantID, platform, channel)
}
type DevicePushTokenPersistenceInterface interface {
Upsert(tenantID types.TenantID, token *types.DevicePushToken) (*types.DevicePushToken, error)
}
type devicePushTokenMapper struct{}
var DevicePushTokens DevicePushTokenPersistenceInterface
func (devicePushTokenMapper) Upsert(tenantID types.TenantID, token *types.DevicePushToken) (*types.DevicePushToken, error) {
if token == nil || token.UserID.IsZero() || strings.TrimSpace(token.DeviceID) == "" ||
strings.TrimSpace(token.Provider) == "" || strings.TrimSpace(token.Token) == "" {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantDevicePushTokenUpsert(tenantID, token)
}
func (profileMapper) Get(tenantID types.TenantID, uid types.Uid) (*types.UserProfile, error) {
if uid.IsZero() {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantUserProfileGet(tenantID, uid)
}
func (profileMapper) Update(tenantID types.TenantID, uid types.Uid, patch types.UserProfilePatch) (*types.UserProfile, error) {
if uid.IsZero() || patch.Version <= 0 || !validUserProfilePatch(patch) {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantUserProfileUpdate(tenantID, uid, patch)
}
func (profileMapper) GetPrivacy(tenantID types.TenantID, uid types.Uid) (*types.UserPrivacySettings, error) {
if uid.IsZero() {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantUserPrivacyGet(tenantID, uid)
}
func (profileMapper) UpdatePrivacy(tenantID types.TenantID, uid types.Uid, patch types.UserPrivacyPatch) (*types.UserPrivacySettings, error) {
if uid.IsZero() || patch.Version <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantUserPrivacyUpdate(tenantID, uid, patch)
}
func validUserProfilePatch(patch types.UserProfilePatch) bool {
if patch.AvatarFileID == nil && patch.Nickname == nil && patch.BirthDate == nil && patch.Signature == nil && patch.Gender == nil && patch.Region == nil {
return false
}
if patch.Nickname != nil {
name := strings.TrimSpace(*patch.Nickname)
if len([]rune(name)) == 0 || len([]rune(name)) > 32 {
return false
}
}
if patch.Signature != nil && len([]rune(*patch.Signature)) > 120 {
return false
}
return true
}
type RelationsPersistenceInterface interface {
CreateFriendRequest(tenantID types.TenantID, req *types.FriendRequest) (*types.FriendRequest, error)
ListFriendRequests(tenantID types.TenantID, uid types.Uid, direction, status, cursor string, limit int) ([]types.FriendRequestListItem, string, error)
@@ -2015,6 +2531,8 @@ type UserSecurityPersistenceInterface interface {
GetIndependentPassword(tenantID types.TenantID, uid types.Uid, purpose string) (*types.IndependentPassword, error)
UpsertIndependentPassword(tenantID types.TenantID, pass *types.IndependentPassword) error
UpdateIndependentPasswordAttempts(tenantID types.TenantID, uid types.Uid, purpose string, attempts int, lockedUntil *time.Time, updatedAt time.Time) error
GetYouthMode(tenantID types.TenantID, uid types.Uid) (*types.YouthModeSettings, error)
SetYouthMode(tenantID types.TenantID, uid types.Uid, enabled bool, policyVersion int, now time.Time) (*types.YouthModeSettings, error)
CreateSystemNotification(tenantID types.TenantID, notification *types.SystemNotification) error
ListSystemNotifications(tenantID types.TenantID, uid types.Uid, cursor string, limit int) ([]types.SystemNotification, string, error)
MarkSystemNotificationRead(tenantID types.TenantID, uid types.Uid, eventID string, readAt time.Time) error
@@ -2106,6 +2624,28 @@ func (userSecurityMapper) UpdateIndependentPasswordAttempts(tenantID types.Tenan
return tenantAdp.TenantIndependentPasswordUpdateAttempts(tenantID, uid, purpose, attempts, lockedUntil, updatedAt)
}
func (userSecurityMapper) GetYouthMode(tenantID types.TenantID, uid types.Uid) (*types.YouthModeSettings, error) {
if uid.IsZero() {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantYouthModeGet(tenantID, uid)
}
func (userSecurityMapper) SetYouthMode(tenantID types.TenantID, uid types.Uid, enabled bool, policyVersion int, now time.Time) (*types.YouthModeSettings, error) {
if uid.IsZero() || policyVersion <= 0 {
return nil, types.ErrMalformed
}
tenantAdp, err := tenantBusinessAdapter(tenantID)
if err != nil {
return nil, err
}
return tenantAdp.TenantYouthModeSet(tenantID, uid, enabled, policyVersion, now)
}
func (userSecurityMapper) CreateSystemNotification(tenantID types.TenantID, notification *types.SystemNotification) error {
if notification == nil || notification.TenantID != tenantID {
return types.ErrMalformed
@@ -2232,6 +2772,15 @@ func init() {
Subs = subsMapper{}
Messages = messagesMapper{}
Calls = callsMapper{}
Workbench = workbenchMapper{}
Organization = organizationMapper{}
Meetings = meetingsMapper{}
DailyReports = dailyReportsMapper{}
MonthlyReports = monthlyReportsMapper{}
Mailbox = mailboxMapper{}
Profiles = profileMapper{}
AppReleases = appReleaseMapper{}
DevicePushTokens = devicePushTokenMapper{}
Devices = deviceMapper{}
Files = fileMapper{}
PCache = pcacheMapper{}
+1
View File
@@ -12,6 +12,7 @@ const (
)
type CallRecord struct {
ID int64 `db:"id"`
TenantID TenantID `db:"tenant_id" json:"-" bson:"tenant_id"`
CallID string `db:"call_id"`
Topic string
+36
View File
@@ -0,0 +1,36 @@
package types
import "time"
const MailboxSubmissionStatusReceived = "received"
type MailboxNotice struct {
Title string
Content string
UpdatedAt time.Time
}
type MailboxConfig struct {
Enabled bool
AllowAnonymous bool
RequiredFields []string
MaxLength int
AttachmentPolicy map[string]any
Notice MailboxNotice
UpdatedAt time.Time
}
type MailboxSubmission struct {
ID int64
SubmissionID string
SenderID Uid
Subject string
Content string
Anonymous bool
AttachmentFileIDs []string
NoticeVersion string
Status string
SubmittedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
+50
View File
@@ -0,0 +1,50 @@
package types
import "time"
const (
MeetingStateScheduled = "scheduled"
MeetingStateCanceled = "canceled"
MeetingResponsePending = "pending"
MeetingResponseAccepted = "accepted"
MeetingResponseDeclined = "declined"
MeetingResponseTentative = "tentative"
)
type Meeting struct {
ID int64
MeetingID string
OrganizerID Uid
Title string
StartAt time.Time
EndAt time.Time
Location string
State string
ReminderMinutes []int
IdempotencyKey string
Version int
CanceledAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
Participants []MeetingParticipant
}
type MeetingParticipant struct {
ID int64
MeetingID string
UserID Uid
Response string
ResponseAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type MeetingPatch struct {
Title *string
StartAt *time.Time
EndAt *time.Time
Location *string
ReminderMinutes []int
Version int
}
+40
View File
@@ -0,0 +1,40 @@
package types
import "time"
type OrganizationDepartment struct {
ID int64 `db:"id"`
DepartmentID string `db:"department_id"`
Name string `db:"name"`
ParentID string `db:"parent_id"`
SortOrder int `db:"sort_order"`
ChildCount int `db:"child_count"`
MemberCount int `db:"member_count"`
Version int `db:"version"`
State string `db:"state"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type OrganizationMember struct {
ID int64 `db:"id"`
DepartmentID string `db:"department_id"`
UserID Uid `db:"-"`
DisplayName string `db:"display_name"`
Position string `db:"position"`
AvatarFileID string `db:"avatar_file_id"`
Mobile string `db:"mobile"`
Email string `db:"email"`
Status string `db:"employment_state"`
Contactable bool `db:"contactable"`
SortOrder int `db:"sort_order"`
Version int `db:"version"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type OrganizationSearchItem struct {
Type string
Department *OrganizationDepartment
Member *OrganizationMember
}
+86
View File
@@ -0,0 +1,86 @@
package types
import "time"
type UserProfile struct {
UserID Uid
AvatarFileID string
Nickname string
BirthDate string
Signature string
Gender string
Region string
PublicAccount string
Version int
CreatedAt time.Time
UpdatedAt time.Time
}
type UserProfilePatch struct {
AvatarFileID *string
Nickname *string
BirthDate *string
Signature *string
Gender *string
Region *string
Version int
}
type UserPrivacySettings struct {
UserID Uid
AddMeMethods map[string]bool
ProfileVisibility string
LastSeenVisibility string
ReadReceipts bool
Version int
CreatedAt time.Time
UpdatedAt time.Time
}
type UserPrivacyPatch struct {
AddMeMethods map[string]bool
ProfileVisibility *string
LastSeenVisibility *string
ReadReceipts *bool
Version int
}
type AppRelease struct {
ID int64
Platform string
Channel string
LatestVersion string
MinSupportedVersion string
UpdateType string
ReleaseNotes string
StoreURL string
PackageURL string
Checksum string
RemindAfterSeconds int
PublishedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type YouthModeSettings struct {
UserID Uid
Enabled bool
PolicyVersion int
Restrictions []string
PasswordSet bool
CanEnable bool
EnabledAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type DevicePushToken struct {
UserID Uid
DeviceID string
Provider string
Token string
AppVersion string
Platform string
UpdatedAt time.Time
CreatedAt time.Time
}
+51
View File
@@ -0,0 +1,51 @@
package types
import "time"
const (
DailyReportStatusDraft = "draft"
DailyReportStatusSubmitted = "submitted"
)
type DailyReport struct {
ID int64
ReportID string
AuthorID Uid
ReportDate time.Time
Content string
Attachments []string
Status string
ReadState string
Version int
SubmittedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type DailyReportStats struct {
ExpectedCount int
SubmittedCount int
MissingCount int
}
type MonthlyReport struct {
ID int64
ReportID string
AuthorID Uid
Month string
WorkSummary string
NextPlan string
Attachments []string
Status string
ReadState string
Version int
SubmittedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type MonthlyReportStats struct {
ExpectedCount int
SubmittedCount int
MissingCount int
}
+17
View File
@@ -0,0 +1,17 @@
package types
import "time"
type WorkbenchModule struct {
ID int64 `db:"id"`
Code string `db:"code"`
Name string `db:"name"`
IconFileID string `db:"icon_file_id"`
Route string `db:"route"`
SortOrder int `db:"sort_order"`
UnreadKey string `db:"unread_key"`
Enabled bool `db:"enabled"`
Permission string `db:"permission"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}