|
|
|
@@ -149,6 +149,13 @@ func tenantAuthAdapter(tenantID types.TenantID) (adapter.TenantAuthAdapter, erro
|
|
|
|
|
if !tenantID.IsValid() {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if routed, ok := adp.(adapter.TenantRoutedAdapter); ok {
|
|
|
|
|
_, authAdp, err := routed.TenantAdapterFor(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return authAdp, nil
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, ok := adp.(adapter.TenantAuthAdapter)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, types.ErrUnsupported
|
|
|
|
@@ -160,6 +167,17 @@ func tenantBusinessAdapter(tenantID types.TenantID) (adapter.TenantBusinessAdapt
|
|
|
|
|
if !tenantID.IsValid() {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if routed, ok := adp.(adapter.TenantRoutedAdapter); ok {
|
|
|
|
|
businessAdp, _, err := routed.TenantAdapterFor(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if !businessAdp.TenantBusinessReady() {
|
|
|
|
|
return nil, types.ErrUnsupported
|
|
|
|
|
}
|
|
|
|
|
activeTenantIDs.Store(tenantID, struct{}{})
|
|
|
|
|
return businessAdp, nil
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, ok := adp.(adapter.TenantBusinessAdapter)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, types.ErrUnsupported
|
|
|
|
@@ -960,6 +978,7 @@ type MessagesPersistenceInterface interface {
|
|
|
|
|
DeleteList(tenantID types.TenantID, topic string, delID int, forUser types.Uid, msgDelAge time.Duration, ranges []types.Range) error
|
|
|
|
|
GetAll(tenantID types.TenantID, topic string, forUser types.Uid, opt *types.QueryOpt) ([]types.Message, error)
|
|
|
|
|
GetDeleted(tenantID types.TenantID, topic string, forUser types.Uid, opt *types.QueryOpt) ([]types.Range, int, error)
|
|
|
|
|
Search(tenantID types.TenantID, topic string, forUser types.Uid, query, messageType, cursor string, limit int) ([]types.Message, string, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// messagesMapper is a concrete type implementing MessagesPersistenceInterface.
|
|
|
|
@@ -1003,14 +1022,75 @@ type RelationsPersistenceInterface interface {
|
|
|
|
|
GetRelationshipContext(tenantID types.TenantID, userID, peerID types.Uid, topic string) (*types.RelationshipContext, error)
|
|
|
|
|
CanSendP2P(tenantID types.TenantID, userID, peerID types.Uid) (bool, string, error)
|
|
|
|
|
BlockUser(tenantID types.TenantID, blockerID, blockedID types.Uid, now time.Time) (*types.UserBlock, error)
|
|
|
|
|
ListBlocks(tenantID types.TenantID, blockerID types.Uid, cursor string, limit int) ([]types.BlockListItem, string, error)
|
|
|
|
|
UnblockUser(tenantID types.TenantID, blockerID, blockedID types.Uid) error
|
|
|
|
|
DeleteFriend(tenantID types.TenantID, userID, peerID types.Uid, now time.Time) error
|
|
|
|
|
UpdateFriendRemark(tenantID types.TenantID, userID, peerID types.Uid, remark string, now time.Time) (*types.Friendship, error)
|
|
|
|
|
SearchUsers(tenantID types.TenantID, viewer types.Uid, query, searchType, cursor string, limit int) ([]types.UserSearchItem, string, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type relationsMapper struct{}
|
|
|
|
|
|
|
|
|
|
var Relations RelationsPersistenceInterface
|
|
|
|
|
|
|
|
|
|
type FavoritesPersistenceInterface interface {
|
|
|
|
|
Create(tenantID types.TenantID, item *types.FavoriteItem) (*types.FavoriteItem, error)
|
|
|
|
|
List(tenantID types.TenantID, uid types.Uid, itemType, query, cursor string, limit int) ([]types.FavoriteItem, string, error)
|
|
|
|
|
Get(tenantID types.TenantID, uid types.Uid, favoriteID string) (*types.FavoriteItem, error)
|
|
|
|
|
Delete(tenantID types.TenantID, uid types.Uid, favoriteID string) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type favoritesMapper struct{}
|
|
|
|
|
|
|
|
|
|
var Favorites FavoritesPersistenceInterface
|
|
|
|
|
|
|
|
|
|
func (favoritesMapper) Create(tenantID types.TenantID, item *types.FavoriteItem) (*types.FavoriteItem, error) {
|
|
|
|
|
if item == nil || item.TenantID != tenantID || item.UserID.IsZero() || item.FavoriteID == "" {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantFavoriteCreate(tenantID, item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (favoritesMapper) List(tenantID types.TenantID, uid types.Uid, itemType, query, cursor string, limit int) ([]types.FavoriteItem, 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.TenantFavoriteList(tenantID, uid, itemType, query, cursor, limit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (favoritesMapper) Get(tenantID types.TenantID, uid types.Uid, favoriteID string) (*types.FavoriteItem, error) {
|
|
|
|
|
if uid.IsZero() || strings.TrimSpace(favoriteID) == "" {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantFavoriteGet(tenantID, uid, favoriteID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (favoritesMapper) Delete(tenantID types.TenantID, uid types.Uid, favoriteID string) error {
|
|
|
|
|
if uid.IsZero() || strings.TrimSpace(favoriteID) == "" {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantFavoriteDelete(tenantID, uid, favoriteID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (relationsMapper) CreateFriendRequest(tenantID types.TenantID, req *types.FriendRequest) (*types.FriendRequest, error) {
|
|
|
|
|
if req == nil || req.TenantID != tenantID || req.ApplicantID.IsZero() || req.TargetID.IsZero() || req.ApplicantID == req.TargetID {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
@@ -1111,6 +1191,20 @@ func (relationsMapper) BlockUser(tenantID types.TenantID, blockerID, blockedID t
|
|
|
|
|
return tenantAdp.TenantUserBlockUpsert(tenantID, blockerID, blockedID, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (relationsMapper) ListBlocks(tenantID types.TenantID, blockerID types.Uid, cursor string, limit int) ([]types.BlockListItem, string, error) {
|
|
|
|
|
if blockerID.IsZero() {
|
|
|
|
|
return nil, "", types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if limit <= 0 || limit > 100 {
|
|
|
|
|
limit = 50
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, "", err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantUserBlockList(tenantID, blockerID, cursor, limit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (relationsMapper) UnblockUser(tenantID types.TenantID, blockerID, blockedID types.Uid) error {
|
|
|
|
|
if blockerID.IsZero() || blockedID.IsZero() || blockerID == blockedID {
|
|
|
|
|
return types.ErrMalformed
|
|
|
|
@@ -1133,6 +1227,68 @@ func (relationsMapper) DeleteFriend(tenantID types.TenantID, userID, peerID type
|
|
|
|
|
return tenantAdp.TenantFriendshipDeletePair(tenantID, userID, peerID, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (relationsMapper) UpdateFriendRemark(tenantID types.TenantID, userID, peerID types.Uid, remark string, now time.Time) (*types.Friendship, error) {
|
|
|
|
|
if userID.IsZero() || peerID.IsZero() || userID == peerID || len([]rune(remark)) > 64 {
|
|
|
|
|
return nil, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantFriendshipUpdateRemark(tenantID, userID, peerID, remark, now)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (relationsMapper) SearchUsers(tenantID types.TenantID, viewer types.Uid, query, searchType, cursor string, limit int) ([]types.UserSearchItem, string, error) {
|
|
|
|
|
if viewer.IsZero() || strings.TrimSpace(query) == "" {
|
|
|
|
|
return nil, "", types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
switch searchType {
|
|
|
|
|
case "", "account", "exact_account", "phone":
|
|
|
|
|
default:
|
|
|
|
|
return nil, "", types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if limit <= 0 || limit > 50 {
|
|
|
|
|
limit = 20
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, "", err
|
|
|
|
|
}
|
|
|
|
|
users, nextCursor, err := tenantAdp.TenantUserSearch(tenantID, viewer, query, searchType, cursor, limit)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, "", err
|
|
|
|
|
}
|
|
|
|
|
items := make([]types.UserSearchItem, 0, len(users))
|
|
|
|
|
for i := range users {
|
|
|
|
|
uid := users[i].Uid()
|
|
|
|
|
ctx, err := relationshipContext(tenantAdp, tenantID, viewer, uid, viewer.P2PName(uid))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, "", err
|
|
|
|
|
}
|
|
|
|
|
items = append(items, types.UserSearchItem{
|
|
|
|
|
User: &users[i],
|
|
|
|
|
Relationship: ctx.Relationship,
|
|
|
|
|
RequestID: ctx.RequestID,
|
|
|
|
|
CanAdd: ctx.Relationship == types.RelationshipNone,
|
|
|
|
|
Action: relationshipAction(ctx.Relationship),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return items, nextCursor, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func relationshipAction(relationship string) string {
|
|
|
|
|
switch relationship {
|
|
|
|
|
case types.RelationshipFriend:
|
|
|
|
|
return "chat"
|
|
|
|
|
case types.RelationshipPendingInbound, types.RelationshipPendingOutbound:
|
|
|
|
|
return "pending"
|
|
|
|
|
case types.RelationshipBlockedByMe, types.RelationshipBlockedByPeer:
|
|
|
|
|
return "none"
|
|
|
|
|
default:
|
|
|
|
|
return "add"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func relationshipContext(tenantAdp adapter.TenantBusinessAdapter, tenantID types.TenantID, userID, peerID types.Uid, topic string) (*types.RelationshipContext, error) {
|
|
|
|
|
ctx := &types.RelationshipContext{
|
|
|
|
|
TenantID: tenantID,
|
|
|
|
@@ -1381,6 +1537,20 @@ func (messagesMapper) GetAll(tenantID types.TenantID, topic string, forUser type
|
|
|
|
|
return tenantAdp.TenantMessageGetAll(tenantID, topic, forUser, opt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (messagesMapper) Search(tenantID types.TenantID, topic string, forUser types.Uid, query, messageType, cursor string, limit int) ([]types.Message, string, error) {
|
|
|
|
|
if topic == "" || forUser.IsZero() {
|
|
|
|
|
return nil, "", types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
if limit <= 0 || limit > 100 {
|
|
|
|
|
limit = 50
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, "", err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantMessageSearch(tenantID, topic, forUser, query, messageType, cursor, limit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetDeleted returns the ranges of deleted messages and the largest DelId reported in the list.
|
|
|
|
|
func (messagesMapper) GetDeleted(tenantID types.TenantID, topic string, forUser types.Uid, opt *types.QueryOpt) ([]types.Range, int, error) {
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
@@ -1649,6 +1819,8 @@ type FilePersistenceInterface interface {
|
|
|
|
|
// LinkAttachments connects earlier uploaded attachments to a message or topic to prevent it
|
|
|
|
|
// from being garbage collected.
|
|
|
|
|
LinkAttachments(tenantID types.TenantID, topic string, msgId types.Uid, attachments []string) error
|
|
|
|
|
// UserHasAccess checks if user can download a file through an active upload, user, topic, or message reference.
|
|
|
|
|
UserHasAccess(tenantID types.TenantID, fid string, uid types.Uid) (bool, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fileMapper is concrete type which implements FilePersistenceInterface.
|
|
|
|
@@ -1738,6 +1910,17 @@ func (fileMapper) LinkAttachments(tenantID types.TenantID, topic string, msgId t
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (fileMapper) UserHasAccess(tenantID types.TenantID, fid string, uid types.Uid) (bool, error) {
|
|
|
|
|
if fid == "" || uid.IsZero() {
|
|
|
|
|
return false, types.ErrMalformed
|
|
|
|
|
}
|
|
|
|
|
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
return tenantAdp.TenantFileUserHasAccess(tenantID, fid, uid)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PersistentCacheInterface is an interface which defines methods used for accessing persistent key-value cache.
|
|
|
|
|
type PersistentCacheInterface interface {
|
|
|
|
|
// Get reads a persistent cache entry.
|
|
|
|
@@ -2004,4 +2187,5 @@ func init() {
|
|
|
|
|
Verifications = verificationMapper{}
|
|
|
|
|
Security = userSecurityMapper{}
|
|
|
|
|
Relations = relationsMapper{}
|
|
|
|
|
Favorites = favoritesMapper{}
|
|
|
|
|
}
|
|
|
|
|