|
|
|
@@ -129,6 +129,7 @@ type storeObj struct{}
|
|
|
|
|
// TenantsPersistenceInterface defines tenant registry lookups used before authentication.
|
|
|
|
|
type TenantsPersistenceInterface interface {
|
|
|
|
|
GetByCode(code string) (*types.Tenant, error)
|
|
|
|
|
GetByID(id types.TenantID) (*types.Tenant, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type tenantsMapper struct{}
|
|
|
|
@@ -145,6 +146,18 @@ func (tenantsMapper) GetByCode(code string) (*types.Tenant, error) {
|
|
|
|
|
return tenantAdp.TenantGetByCode(code)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetByID resolves an internal tenant ID to its registry record.
|
|
|
|
|
func (tenantsMapper) GetByID(id types.TenantID) (*types.Tenant, error) {
|
|
|
|
|
if !id.IsValid() {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, ok := adp.(adapter.TenantAdapter)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, types.ErrUnsupported
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGetByID(id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func tenantAuthAdapter(tenantID types.TenantID) (adapter.TenantAuthAdapter, error) {
|
|
|
|
|
if !tenantID.IsValid() {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
@@ -1080,6 +1093,7 @@ func (callsMapper) List(tenantID types.TenantID, uid types.Uid, topic, cursor st
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type GroupBusinessPersistenceInterface interface {
|
|
|
|
|
CreateGroup(types.TenantID, *types.Topic, types.Uid, any, *types.GroupSettings, []types.Uid, any, time.Time) error
|
|
|
|
|
CreateSettings(types.TenantID, *types.GroupSettings) (*types.GroupSettings, error)
|
|
|
|
|
GetSettings(types.TenantID, string) (*types.GroupSettings, error)
|
|
|
|
|
UpdateSettings(types.TenantID, string, types.GroupSettingsPatch) (*types.GroupSettings, error)
|
|
|
|
@@ -1090,19 +1104,41 @@ type GroupBusinessPersistenceInterface interface {
|
|
|
|
|
CreateInvitation(types.TenantID, *types.GroupInvitation) (*types.GroupInvitation, error)
|
|
|
|
|
CreateJoinRequest(types.TenantID, *types.GroupJoinRequest) (*types.GroupJoinRequest, error)
|
|
|
|
|
ListJoinRequests(types.TenantID, string, string, string, int) ([]types.GroupJoinRequest, string, error)
|
|
|
|
|
ResolveJoinRequest(types.TenantID, string, string, types.Uid, string, string, int, time.Time) (*types.GroupJoinRequest, error)
|
|
|
|
|
ResolveJoinRequest(types.TenantID, string, string, types.Uid, string, string, int, any, time.Time) (*types.GroupJoinRequest, error)
|
|
|
|
|
LatestAnnouncement(types.TenantID, string) (*types.GroupAnnouncement, error)
|
|
|
|
|
PutAnnouncement(types.TenantID, *types.GroupAnnouncement, int) (*types.GroupAnnouncement, error)
|
|
|
|
|
ReadAnnouncement(types.TenantID, string, string, types.Uid, time.Time) error
|
|
|
|
|
ListMutes(types.TenantID, string, string, int) ([]types.GroupMute, string, error)
|
|
|
|
|
UpsertMute(types.TenantID, *types.GroupMute) (*types.GroupMute, error)
|
|
|
|
|
DeleteMute(types.TenantID, string, types.Uid, types.Uid, time.Time) error
|
|
|
|
|
InviteMember(types.TenantID, string, types.Uid, types.Uid, string, string, any, time.Time) (bool, error)
|
|
|
|
|
Leave(types.TenantID, string, types.Uid, time.Time) error
|
|
|
|
|
UpdateRole(types.TenantID, string, types.Uid, types.Uid, string, types.AccessMode, time.Time) error
|
|
|
|
|
TransferOwner(types.TenantID, string, types.Uid, types.Uid, int, time.Time) error
|
|
|
|
|
CanPost(types.TenantID, string, types.Uid, bool, time.Time) (bool, error)
|
|
|
|
|
ListPendingEvents(types.TenantID, int, time.Time) ([]types.GroupEvent, error)
|
|
|
|
|
MarkEventDelivered(types.TenantID, string, time.Time) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type groupBusinessMapper struct{}
|
|
|
|
|
|
|
|
|
|
var GroupBusiness GroupBusinessPersistenceInterface
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) CreateGroup(tenantID types.TenantID, topic *types.Topic, owner types.Uid, ownerPrivate any,
|
|
|
|
|
settings *types.GroupSettings, members []types.Uid, memberPrivate any, now time.Time) error {
|
|
|
|
|
if topic == nil || topic.TenantID != tenantID || owner.IsZero() || settings == nil || settings.Topic != topic.Id {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
topic.InitTimes()
|
|
|
|
|
topic.TouchedAt = topic.CreatedAt
|
|
|
|
|
topic.Owner = owner.String()
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupCreate(tenantID, topic, owner, ownerPrivate, settings, members, memberPrivate, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) CreateSettings(tenantID types.TenantID, settings *types.GroupSettings) (*types.GroupSettings, error) {
|
|
|
|
|
if settings == nil || settings.Topic == "" || settings.OwnerUserID.IsZero() || settings.CreatedBy.IsZero() {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
@@ -1219,7 +1255,7 @@ func (groupBusinessMapper) ListJoinRequests(tenantID types.TenantID, topic, stat
|
|
|
|
|
return tenantAdp.TenantGroupJoinRequestList(tenantID, strings.TrimSpace(topic), strings.TrimSpace(status), strings.TrimSpace(cursor), limit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) ResolveJoinRequest(tenantID types.TenantID, topic, requestID string, actor types.Uid, action, rejectReason string, version int, now time.Time) (*types.GroupJoinRequest, error) {
|
|
|
|
|
func (groupBusinessMapper) ResolveJoinRequest(tenantID types.TenantID, topic, requestID string, actor types.Uid, action, rejectReason string, version int, memberPrivate any, now time.Time) (*types.GroupJoinRequest, error) {
|
|
|
|
|
if strings.TrimSpace(topic) == "" || strings.TrimSpace(requestID) == "" || actor.IsZero() || now.IsZero() {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
@@ -1227,7 +1263,7 @@ func (groupBusinessMapper) ResolveJoinRequest(tenantID types.TenantID, topic, re
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupJoinRequestResolve(tenantID, strings.TrimSpace(topic), strings.TrimSpace(requestID), actor, strings.TrimSpace(action), strings.TrimSpace(rejectReason), version, now)
|
|
|
|
|
return tenantAdp.TenantGroupJoinRequestResolve(tenantID, strings.TrimSpace(topic), strings.TrimSpace(requestID), actor, strings.TrimSpace(action), strings.TrimSpace(rejectReason), version, memberPrivate, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) LatestAnnouncement(tenantID types.TenantID, topic string) (*types.GroupAnnouncement, error) {
|
|
|
|
@@ -1299,6 +1335,87 @@ func (groupBusinessMapper) DeleteMute(tenantID types.TenantID, topic string, uid
|
|
|
|
|
return tenantAdp.TenantGroupMuteDelete(tenantID, strings.TrimSpace(topic), uid, actor, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) InviteMember(tenantID types.TenantID, topic string, inviter, target types.Uid,
|
|
|
|
|
message, idempotencyKey string, private any, now time.Time) (bool, error) {
|
|
|
|
|
if strings.TrimSpace(topic) == "" || inviter.IsZero() || target.IsZero() || now.IsZero() {
|
|
|
|
|
return false, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupInviteMember(tenantID, strings.TrimSpace(topic), inviter, target,
|
|
|
|
|
strings.TrimSpace(message), strings.TrimSpace(idempotencyKey), private, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) Leave(tenantID types.TenantID, topic string, uid types.Uid, now time.Time) error {
|
|
|
|
|
if strings.TrimSpace(topic) == "" || uid.IsZero() || now.IsZero() {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupLeave(tenantID, strings.TrimSpace(topic), uid, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) UpdateRole(tenantID types.TenantID, topic string, actor, target types.Uid,
|
|
|
|
|
role string, modeGiven types.AccessMode, now time.Time) error {
|
|
|
|
|
if strings.TrimSpace(topic) == "" || actor.IsZero() || target.IsZero() || now.IsZero() {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupRoleUpdate(tenantID, strings.TrimSpace(topic), actor, target, strings.TrimSpace(role), modeGiven, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) TransferOwner(tenantID types.TenantID, topic string, previousOwner, newOwner types.Uid,
|
|
|
|
|
version int, now time.Time) error {
|
|
|
|
|
if strings.TrimSpace(topic) == "" || previousOwner.IsZero() || newOwner.IsZero() || now.IsZero() {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupOwnerTransfer(tenantID, strings.TrimSpace(topic), previousOwner, newOwner, version, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) CanPost(tenantID types.TenantID, topic string, uid types.Uid, admin bool, now time.Time) (bool, error) {
|
|
|
|
|
if strings.TrimSpace(topic) == "" || uid.IsZero() || now.IsZero() {
|
|
|
|
|
return false, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupCanPost(tenantID, strings.TrimSpace(topic), uid, admin, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) ListPendingEvents(tenantID types.TenantID, limit int, now time.Time) ([]types.GroupEvent, error) {
|
|
|
|
|
if limit <= 0 || limit > 100 {
|
|
|
|
|
limit = 50
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupEventListPending(tenantID, limit, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (groupBusinessMapper) MarkEventDelivered(tenantID types.TenantID, eventID string, now time.Time) error {
|
|
|
|
|
if strings.TrimSpace(eventID) == "" || now.IsZero() {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantGroupEventMarkDelivered(tenantID, strings.TrimSpace(eventID), now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type WorkbenchPersistenceInterface interface {
|
|
|
|
|
Get(tenantID types.TenantID, uid types.Uid) ([]types.WorkbenchModule, int, error)
|
|
|
|
|
}
|
|
|
|
@@ -1724,6 +1841,10 @@ type DevicePushTokenPersistenceInterface interface {
|
|
|
|
|
Upsert(tenantID types.TenantID, token *types.DevicePushToken) (*types.DevicePushToken, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type DevicePushTokenQueryInterface interface {
|
|
|
|
|
GetAll(tenantID types.TenantID, uid ...types.Uid) (map[types.Uid][]types.DeviceDef, int, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type devicePushTokenMapper struct{}
|
|
|
|
|
|
|
|
|
|
var DevicePushTokens DevicePushTokenPersistenceInterface
|
|
|
|
@@ -1740,6 +1861,20 @@ func (devicePushTokenMapper) Upsert(tenantID types.TenantID, token *types.Device
|
|
|
|
|
return tenantAdp.TenantDevicePushTokenUpsert(tenantID, token)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (devicePushTokenMapper) GetAll(tenantID types.TenantID, uids ...types.Uid) (map[types.Uid][]types.DeviceDef, int, error) {
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, 0, err
|
|
|
|
|
}
|
|
|
|
|
reader, ok := tenantAdp.(interface {
|
|
|
|
|
TenantDevicePushTokenGetAll(types.TenantID, ...types.Uid) (map[types.Uid][]types.DeviceDef, int, error)
|
|
|
|
|
})
|
|
|
|
|
if !ok {
|
|
|
|
|
return map[types.Uid][]types.DeviceDef{}, 0, nil
|
|
|
|
|
}
|
|
|
|
|
return reader.TenantDevicePushTokenGetAll(tenantID, uids...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type SafetyPersistenceInterface interface {
|
|
|
|
|
CreateRiskChallenge(tenantID types.TenantID, challenge *types.RiskChallenge) (*types.RiskChallenge, error)
|
|
|
|
|
ConfirmRiskChallenge(tenantID types.TenantID, uid types.Uid, challengeID, decision, actionTokenID string, now time.Time) (*types.RiskChallenge, error)
|
|
|
|
@@ -1863,7 +1998,7 @@ func (profileMapper) GetPrivacy(tenantID types.TenantID, uid types.Uid) (*types.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (profileMapper) UpdatePrivacy(tenantID types.TenantID, uid types.Uid, patch types.UserPrivacyPatch) (*types.UserPrivacySettings, error) {
|
|
|
|
|
if uid.IsZero() || patch.Version <= 0 {
|
|
|
|
|
if uid.IsZero() || patch.Version <= 0 || !validUserPrivacyPatch(patch) {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
@@ -1873,6 +2008,31 @@ func (profileMapper) UpdatePrivacy(tenantID types.TenantID, uid types.Uid, patch
|
|
|
|
|
return tenantAdp.TenantUserPrivacyUpdate(tenantID, uid, patch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validUserPrivacyPatch(patch types.UserPrivacyPatch) bool {
|
|
|
|
|
if patch.AddMeMethods == nil && patch.ProfileVisibility == nil && patch.LastSeenVisibility == nil && patch.ReadReceipts == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for method := range patch.AddMeMethods {
|
|
|
|
|
switch method {
|
|
|
|
|
case "account", "phone", "qr", "group":
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
validVisibility := func(value *string) bool {
|
|
|
|
|
if value == nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
switch strings.TrimSpace(*value) {
|
|
|
|
|
case "everyone", "friends", "nobody":
|
|
|
|
|
return true
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return validVisibility(patch.ProfileVisibility) && validVisibility(patch.LastSeenVisibility)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
@@ -2321,20 +2481,77 @@ func normalizeClientMsgID(head types.KVMap) (string, error) {
|
|
|
|
|
|
|
|
|
|
func validateMessageHeaders(head types.KVMap) error {
|
|
|
|
|
if schema, ok := head["x-im-schema"]; ok {
|
|
|
|
|
value, ok := schema.(string)
|
|
|
|
|
if !ok || !validIMMessageHeaderToken(value, 32) {
|
|
|
|
|
if !validIMMessageSchema(schema) {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if msgType, ok := head["type"]; ok {
|
|
|
|
|
value, ok := msgType.(string)
|
|
|
|
|
if !ok || !validIMMessageType(value) {
|
|
|
|
|
legacyType, hasLegacyType := messageHeaderString(head, "type")
|
|
|
|
|
productType, hasProductType := messageHeaderString(head, "x-im-type")
|
|
|
|
|
if raw, ok := head["type"]; ok && (!hasLegacyType || !validIMMessageType(legacyType)) {
|
|
|
|
|
_ = raw
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if raw, ok := head["x-im-type"]; ok && (!hasProductType || !validIMMessageType(productType)) {
|
|
|
|
|
_ = raw
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if hasLegacyType && hasProductType {
|
|
|
|
|
if canonicalIMMessageType(legacyType) != canonicalIMMessageType(productType) {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validIMMessageSchema(value any) bool {
|
|
|
|
|
switch typed := value.(type) {
|
|
|
|
|
case string:
|
|
|
|
|
return strings.TrimSpace(typed) == "1"
|
|
|
|
|
case json.Number:
|
|
|
|
|
parsed, err := typed.Int64()
|
|
|
|
|
return err == nil && parsed == 1
|
|
|
|
|
case float64:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case float32:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case int:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case int8:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case int16:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case int32:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case int64:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case uint:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case uint8:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case uint16:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case uint32:
|
|
|
|
|
return typed == 1
|
|
|
|
|
case uint64:
|
|
|
|
|
return typed == 1
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func messageHeaderString(head types.KVMap, key string) (string, bool) {
|
|
|
|
|
value, ok := head[key]
|
|
|
|
|
if !ok {
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
text, ok := value.(string)
|
|
|
|
|
if !ok {
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
text = strings.TrimSpace(text)
|
|
|
|
|
return text, text != ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validIMMessageHeaderToken(value string, max int) bool {
|
|
|
|
|
value = strings.TrimSpace(value)
|
|
|
|
|
if value == "" || len(value) > max {
|
|
|
|
@@ -2351,13 +2568,27 @@ func validIMMessageHeaderToken(value string, max int) bool {
|
|
|
|
|
|
|
|
|
|
func validIMMessageType(value string) bool {
|
|
|
|
|
switch strings.TrimSpace(value) {
|
|
|
|
|
case "text", "image", "file", "audio", "video", "location", "contact", "card", "call", "system":
|
|
|
|
|
case "text", "image", "file", "audio", "voice", "video", "location", "contact", "contact_card",
|
|
|
|
|
"card", "link", "forward_bundle", "sticker", "call", "system", "system_event":
|
|
|
|
|
return true
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func canonicalIMMessageType(value string) string {
|
|
|
|
|
switch strings.TrimSpace(value) {
|
|
|
|
|
case "audio":
|
|
|
|
|
return "voice"
|
|
|
|
|
case "contact":
|
|
|
|
|
return "contact_card"
|
|
|
|
|
case "system":
|
|
|
|
|
return "system_event"
|
|
|
|
|
default:
|
|
|
|
|
return strings.TrimSpace(value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteList deletes multiple messages defined by a list of ranges.
|
|
|
|
|
func (messagesMapper) DeleteList(tenantID types.TenantID, topic string, delID int, forUser types.Uid, msgDelAge time.Duration, ranges []types.Range) error {
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|