feat: add im relationship flows
This commit is contained in:
@@ -995,6 +995,157 @@ func (messagesMapper) Edit(tenantID types.TenantID, topic string, seq int, actor
|
||||
return tenantAdp.TenantMessageEdit(tenantID, topic, seq, actor, expectedVersion, head, content, reason, editedAt)
|
||||
}
|
||||
|
||||
type RelationsPersistenceInterface interface {
|
||||
CreateFriendRequest(tenantID types.TenantID, req *types.FriendRequest) (*types.FriendRequest, error)
|
||||
ResolveFriendRequest(tenantID types.TenantID, requestID string, actor types.Uid, status string, handledAt time.Time) (*types.FriendRequest, error)
|
||||
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)
|
||||
UnblockUser(tenantID types.TenantID, blockerID, blockedID types.Uid) error
|
||||
DeleteFriend(tenantID types.TenantID, userID, peerID types.Uid, now time.Time) error
|
||||
}
|
||||
|
||||
type relationsMapper struct{}
|
||||
|
||||
var Relations RelationsPersistenceInterface
|
||||
|
||||
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
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantFriendRequestCreate(tenantID, req)
|
||||
}
|
||||
|
||||
func (relationsMapper) ResolveFriendRequest(tenantID types.TenantID, requestID string, actor types.Uid, status string, handledAt time.Time) (*types.FriendRequest, error) {
|
||||
if strings.TrimSpace(requestID) == "" || actor.IsZero() || (status != types.FriendRequestAccepted && status != types.FriendRequestRejected) {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := tenantAdp.TenantFriendRequestResolve(tenantID, requestID, actor, status, handledAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status == types.FriendRequestAccepted {
|
||||
if err := tenantAdp.TenantFriendshipUpsertPair(tenantID, req.ApplicantID, req.TargetID, "", handledAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (relationsMapper) GetRelationshipContext(tenantID types.TenantID, userID, peerID types.Uid, topic string) (*types.RelationshipContext, error) {
|
||||
if userID.IsZero() || peerID.IsZero() || userID == peerID {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return relationshipContext(tenantAdp, tenantID, userID, peerID, topic)
|
||||
}
|
||||
|
||||
func (relationsMapper) CanSendP2P(tenantID types.TenantID, userID, peerID types.Uid) (bool, string, error) {
|
||||
ctx, err := (relationsMapper{}).GetRelationshipContext(tenantID, userID, peerID, "")
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if ctx.Relationship == types.RelationshipFriend {
|
||||
return true, ctx.Relationship, nil
|
||||
}
|
||||
return false, ctx.Relationship, nil
|
||||
}
|
||||
|
||||
func (relationsMapper) BlockUser(tenantID types.TenantID, blockerID, blockedID types.Uid, now time.Time) (*types.UserBlock, error) {
|
||||
if blockerID.IsZero() || blockedID.IsZero() || blockerID == blockedID {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantUserBlockUpsert(tenantID, blockerID, blockedID, now)
|
||||
}
|
||||
|
||||
func (relationsMapper) UnblockUser(tenantID types.TenantID, blockerID, blockedID types.Uid) error {
|
||||
if blockerID.IsZero() || blockedID.IsZero() || blockerID == blockedID {
|
||||
return types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tenantAdp.TenantUserBlockDelete(tenantID, blockerID, blockedID)
|
||||
}
|
||||
|
||||
func (relationsMapper) DeleteFriend(tenantID types.TenantID, userID, peerID types.Uid, now time.Time) error {
|
||||
if userID.IsZero() || peerID.IsZero() || userID == peerID {
|
||||
return types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tenantAdp.TenantFriendshipDeletePair(tenantID, userID, peerID, now)
|
||||
}
|
||||
|
||||
func relationshipContext(tenantAdp adapter.TenantBusinessAdapter, tenantID types.TenantID, userID, peerID types.Uid, topic string) (*types.RelationshipContext, error) {
|
||||
ctx := &types.RelationshipContext{
|
||||
TenantID: tenantID,
|
||||
UserID: userID,
|
||||
PeerID: peerID,
|
||||
Topic: topic,
|
||||
Relationship: types.RelationshipNone,
|
||||
}
|
||||
peer, err := tenantAdp.TenantUserGet(tenantID, peerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.Peer = peer
|
||||
if block, err := tenantAdp.TenantUserBlockGet(tenantID, userID, peerID); err != nil {
|
||||
return nil, err
|
||||
} else if block != nil {
|
||||
ctx.Relationship = types.RelationshipBlockedByMe
|
||||
return ctx, nil
|
||||
}
|
||||
if block, err := tenantAdp.TenantUserBlockGet(tenantID, peerID, userID); err != nil {
|
||||
return nil, err
|
||||
} else if block != nil {
|
||||
ctx.Relationship = types.RelationshipBlockedByPeer
|
||||
return ctx, nil
|
||||
}
|
||||
if friendship, err := tenantAdp.TenantFriendshipGet(tenantID, userID, peerID); err != nil {
|
||||
return nil, err
|
||||
} else if friendship != nil && friendship.Status == types.RelationshipFriend {
|
||||
ctx.Relationship = types.RelationshipFriend
|
||||
ctx.CanSend = true
|
||||
if ctx.Topic == "" {
|
||||
ctx.Topic = friendship.Topic
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
req, err := tenantAdp.TenantFriendRequestLatestBetween(tenantID, userID, peerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req != nil && req.Status == types.FriendRequestPending && req.ExpiresAt.After(time.Now()) {
|
||||
ctx.RequestID = req.RequestID
|
||||
ctx.PendingStatus = req.Status
|
||||
if req.ApplicantID == userID {
|
||||
ctx.Relationship = types.RelationshipPendingOutbound
|
||||
} else {
|
||||
ctx.Relationship = types.RelationshipPendingInbound
|
||||
}
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// Save message
|
||||
func (messagesMapper) Save(tenantID types.TenantID, msg *types.Message, attachmentURLs []string, readBySender bool) (*types.MessageSaveResult, error) {
|
||||
if msg == nil || msg.TenantID != tenantID {
|
||||
@@ -1814,4 +1965,5 @@ func init() {
|
||||
PCache = pcacheMapper{}
|
||||
Verifications = verificationMapper{}
|
||||
Security = userSecurityMapper{}
|
||||
Relations = relationsMapper{}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
FriendRequestPending = "pending"
|
||||
FriendRequestAccepted = "accepted"
|
||||
FriendRequestRejected = "rejected"
|
||||
FriendRequestExpired = "expired"
|
||||
|
||||
RelationshipNone = "none"
|
||||
RelationshipFriend = "friend"
|
||||
RelationshipPendingInbound = "pending_inbound"
|
||||
RelationshipPendingOutbound = "pending_outbound"
|
||||
RelationshipBlockedByMe = "blocked_by_me"
|
||||
RelationshipBlockedByPeer = "blocked_by_peer"
|
||||
)
|
||||
|
||||
type FriendRequest struct {
|
||||
ID int64
|
||||
TenantID TenantID `db:"tenant_id" json:"-" bson:"tenant_id"`
|
||||
RequestID string `db:"request_id"`
|
||||
ApplicantID Uid `db:"applicant_id"`
|
||||
TargetID Uid `db:"target_id"`
|
||||
Message string
|
||||
Source string
|
||||
SourceTopic string `db:"source_topic"`
|
||||
Status string
|
||||
IdempotencyKey string `db:"idempotency_key"`
|
||||
ExpiresAt time.Time `db:"expires_at"`
|
||||
HandledAt *time.Time `db:"handled_at"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
type Friendship struct {
|
||||
TenantID TenantID `db:"tenant_id" json:"-" bson:"tenant_id"`
|
||||
UserID Uid `db:"user_id"`
|
||||
PeerID Uid `db:"peer_id"`
|
||||
Status string
|
||||
Remark string
|
||||
Topic string
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
type UserBlock struct {
|
||||
TenantID TenantID `db:"tenant_id" json:"-" bson:"tenant_id"`
|
||||
BlockerID Uid `db:"blocker_id"`
|
||||
BlockedID Uid `db:"blocked_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
type RelationshipContext struct {
|
||||
TenantID TenantID `json:"-"`
|
||||
UserID Uid `json:"-"`
|
||||
PeerID Uid `json:"-"`
|
||||
Topic string `json:"topic"`
|
||||
Relationship string `json:"relationship"`
|
||||
CanSend bool `json:"can_send"`
|
||||
RequestID string `json:"request_id,omitempty"`
|
||||
PendingStatus string `json:"pending_status,omitempty"`
|
||||
Peer *User `json:"peer,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user