fix: preserve pending support state on private profiles
Deploy olons-server production / deploy (push) Successful in 2m42s
Deploy olons-server production / deploy (push) Successful in 2m42s
This commit is contained in:
@@ -388,6 +388,12 @@ func IsConflict(err error) bool {
|
|||||||
return errors.As(err, &target) && target.Status == http.StatusConflict
|
return errors.As(err, &target) && target.Status == http.StatusConflict
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsFriendRequestConflict(err error) bool {
|
||||||
|
var target *Error
|
||||||
|
return errors.As(err, &target) && target.Status == http.StatusConflict &&
|
||||||
|
strings.EqualFold(strings.TrimSpace(target.Reason), "FRIEND_REQUEST_CONFLICT")
|
||||||
|
}
|
||||||
|
|
||||||
func IsPermissionDenied(err error) bool {
|
func IsPermissionDenied(err error) bool {
|
||||||
var target *Error
|
var target *Error
|
||||||
return errors.As(err, &target) && target.Status == http.StatusForbidden
|
return errors.As(err, &target) && target.Status == http.StatusForbidden
|
||||||
|
|||||||
+21
-23
@@ -125,42 +125,42 @@ func (s *Service) OpenSession(ctx context.Context, tenantID, memberID, serviceID
|
|||||||
if !strings.EqualFold(strings.TrimSpace(imSession.UserID), strings.TrimSpace(identity.IMUserID)) {
|
if !strings.EqualFold(strings.TrimSpace(imSession.UserID), strings.TrimSpace(identity.IMUserID)) {
|
||||||
return nil, ErrIMUnavailable
|
return nil, ErrIMUnavailable
|
||||||
}
|
}
|
||||||
var conversation *imclient.Conversation
|
|
||||||
profile, err := s.im.UserProfile(ctx, imSession.Token, agent.IMUserID)
|
profile, err := s.im.UserProfile(ctx, imSession.Token, agent.IMUserID)
|
||||||
|
relationship := ""
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !imclient.IsPermissionDenied(err) {
|
if !imclient.IsPermissionDenied(err) {
|
||||||
return nil, fmt.Errorf("query customer service relationship: %w", err)
|
return nil, fmt.Errorf("query customer service relationship: %w", err)
|
||||||
}
|
}
|
||||||
conversation, err = s.im.EnsureP2P(ctx, imSession.Token, agent.IMUserID,
|
key := fmt.Sprintf("customer-service:%d:%d:%d", tenantID, memberID, serviceID)
|
||||||
fmt.Sprintf("p2p:%s:%s", identity.IMUserID, agent.IMUserID))
|
request, requestErr := s.im.CreateFriendRequest(ctx, imSession.Token, agent.IMUserID, key)
|
||||||
if err != nil {
|
if imclient.IsFriendRequestConflict(requestErr) {
|
||||||
return nil, fmt.Errorf("query customer service relationship: %w", err)
|
return nil, ErrRelationPending
|
||||||
}
|
}
|
||||||
}
|
if requestErr != nil {
|
||||||
relationship := ""
|
if imclient.IsConflict(requestErr) {
|
||||||
if profile != nil {
|
return nil, ErrRelationDenied
|
||||||
relationship = strings.TrimSpace(profile.Relationship)
|
}
|
||||||
|
return nil, fmt.Errorf("create customer service friend request: %w", requestErr)
|
||||||
|
}
|
||||||
|
relationship = strings.TrimSpace(request.Status)
|
||||||
} else {
|
} else {
|
||||||
relationship = strings.TrimSpace(conversation.Relationship)
|
relationship = strings.TrimSpace(profile.Relationship)
|
||||||
}
|
}
|
||||||
switch relationship {
|
switch relationship {
|
||||||
case "friend":
|
case "friend":
|
||||||
case "none", "":
|
case "none", "":
|
||||||
key := fmt.Sprintf("customer-service:%d:%d:%d", tenantID, memberID, serviceID)
|
key := fmt.Sprintf("customer-service:%d:%d:%d", tenantID, memberID, serviceID)
|
||||||
request, requestErr := s.im.CreateFriendRequest(ctx, imSession.Token, agent.IMUserID, key)
|
request, requestErr := s.im.CreateFriendRequest(ctx, imSession.Token, agent.IMUserID, key)
|
||||||
|
if imclient.IsFriendRequestConflict(requestErr) {
|
||||||
|
return nil, ErrRelationPending
|
||||||
|
}
|
||||||
if requestErr != nil && !imclient.IsConflict(requestErr) {
|
if requestErr != nil && !imclient.IsConflict(requestErr) {
|
||||||
return nil, fmt.Errorf("create customer service friend request: %w", requestErr)
|
return nil, fmt.Errorf("create customer service friend request: %w", requestErr)
|
||||||
}
|
}
|
||||||
if requestErr != nil {
|
if requestErr != nil {
|
||||||
conversation, err = s.im.EnsureP2P(ctx, imSession.Token, agent.IMUserID,
|
return nil, ErrRelationDenied
|
||||||
fmt.Sprintf("p2p:%s:%s", identity.IMUserID, agent.IMUserID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("refresh customer service relationship: %w", err)
|
|
||||||
}
|
|
||||||
relationship = strings.TrimSpace(conversation.Relationship)
|
|
||||||
} else {
|
} else {
|
||||||
relationship = strings.TrimSpace(request.Status)
|
relationship = strings.TrimSpace(request.Status)
|
||||||
conversation = nil
|
|
||||||
}
|
}
|
||||||
if relationship != "accepted" && relationship != "friend" {
|
if relationship != "accepted" && relationship != "friend" {
|
||||||
return nil, ErrRelationPending
|
return nil, ErrRelationPending
|
||||||
@@ -170,12 +170,10 @@ func (s *Service) OpenSession(ctx context.Context, tenantID, memberID, serviceID
|
|||||||
default:
|
default:
|
||||||
return nil, ErrRelationDenied
|
return nil, ErrRelationDenied
|
||||||
}
|
}
|
||||||
if conversation == nil {
|
conversation, err := s.im.EnsureP2P(ctx, imSession.Token, agent.IMUserID,
|
||||||
conversation, err = s.im.EnsureP2P(ctx, imSession.Token, agent.IMUserID,
|
fmt.Sprintf("p2p:%s:%s", identity.IMUserID, agent.IMUserID))
|
||||||
fmt.Sprintf("p2p:%s:%s", identity.IMUserID, agent.IMUserID))
|
if err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("ensure customer service conversation: %w", err)
|
||||||
return nil, fmt.Errorf("ensure customer service conversation: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if strings.TrimSpace(conversation.Topic) == "" || (conversation.Relationship != "" && conversation.Relationship != "friend") || !conversation.CanSend {
|
if strings.TrimSpace(conversation.Topic) == "" || (conversation.Relationship != "" && conversation.Relationship != "friend") || !conversation.CanSend {
|
||||||
return nil, ErrRelationDenied
|
return nil, ErrRelationDenied
|
||||||
|
|||||||
@@ -37,13 +37,15 @@ func (r *repositoryStub) SaveMemberIMIdentity(_ context.Context, identity *store
|
|||||||
}
|
}
|
||||||
|
|
||||||
type imStub struct {
|
type imStub struct {
|
||||||
friendRequests int
|
friendRequests int
|
||||||
loginAttempts int
|
loginAttempts int
|
||||||
resetPasswords int
|
resetPasswords int
|
||||||
loginError error
|
loginError error
|
||||||
profileError error
|
profileError error
|
||||||
conversation *imclient.Conversation
|
friendError error
|
||||||
ensureP2PCalls int
|
conversation *imclient.Conversation
|
||||||
|
conversationErr error
|
||||||
|
ensureP2PCalls int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *imStub) Ready() bool { return true }
|
func (i *imStub) Ready() bool { return true }
|
||||||
@@ -78,10 +80,16 @@ func (i *imStub) UserProfile(context.Context, string, string) (*imclient.UserPro
|
|||||||
}
|
}
|
||||||
func (i *imStub) CreateFriendRequest(context.Context, string, string, string) (*imclient.FriendRequest, error) {
|
func (i *imStub) CreateFriendRequest(context.Context, string, string, string) (*imclient.FriendRequest, error) {
|
||||||
i.friendRequests++
|
i.friendRequests++
|
||||||
|
if i.friendError != nil {
|
||||||
|
return nil, i.friendError
|
||||||
|
}
|
||||||
return &imclient.FriendRequest{RequestID: "frq_1", Status: "accepted"}, nil
|
return &imclient.FriendRequest{RequestID: "frq_1", Status: "accepted"}, nil
|
||||||
}
|
}
|
||||||
func (i *imStub) EnsureP2P(context.Context, string, string, string) (*imclient.Conversation, error) {
|
func (i *imStub) EnsureP2P(context.Context, string, string, string) (*imclient.Conversation, error) {
|
||||||
i.ensureP2PCalls++
|
i.ensureP2PCalls++
|
||||||
|
if i.conversationErr != nil {
|
||||||
|
return nil, i.conversationErr
|
||||||
|
}
|
||||||
if i.conversation != nil {
|
if i.conversation != nil {
|
||||||
return i.conversation, nil
|
return i.conversation, nil
|
||||||
}
|
}
|
||||||
@@ -132,8 +140,9 @@ func TestOpenSessionReturnsPendingWhenPrivateProfileHidesPendingRelationship(t *
|
|||||||
identity: &store.MemberIMIdentity{TenantID: 0, MemberID: 9, IMTenantCode: "allrich", IMUserID: "usr_member", IMUsername: "member01"},
|
identity: &store.MemberIMIdentity{TenantID: 0, MemberID: 9, IMTenantCode: "allrich", IMUserID: "usr_member", IMUsername: "member01"},
|
||||||
}
|
}
|
||||||
im := &imStub{
|
im := &imStub{
|
||||||
profileError: &imclient.Error{Status: 403, Reason: "PERMISSION_DENIED"},
|
profileError: &imclient.Error{Status: 403, Reason: "PERMISSION_DENIED"},
|
||||||
conversation: &imclient.Conversation{Topic: "p2p-topic", Relationship: "pending_outbound", CanSend: false},
|
friendError: &imclient.Error{Status: 409, Reason: "FRIEND_REQUEST_CONFLICT"},
|
||||||
|
conversationErr: &imclient.Error{Status: 403, Reason: "PERMISSION_DENIED"},
|
||||||
}
|
}
|
||||||
service := New(repository, im, config.AuthConfig{FinanceMasterKey: strings.Repeat("k", 32)})
|
service := New(repository, im, config.AuthConfig{FinanceMasterKey: strings.Repeat("k", 32)})
|
||||||
repository.identity.IMPasswordCipher, _ = service.encryptCredential("password")
|
repository.identity.IMPasswordCipher, _ = service.encryptCredential("password")
|
||||||
@@ -142,8 +151,8 @@ func TestOpenSessionReturnsPendingWhenPrivateProfileHidesPendingRelationship(t *
|
|||||||
if !errors.Is(err, ErrRelationPending) {
|
if !errors.Is(err, ErrRelationPending) {
|
||||||
t.Fatalf("error = %v, want ErrRelationPending", err)
|
t.Fatalf("error = %v, want ErrRelationPending", err)
|
||||||
}
|
}
|
||||||
if im.ensureP2PCalls != 1 || im.friendRequests != 0 {
|
if im.ensureP2PCalls != 0 || im.friendRequests != 1 {
|
||||||
t.Fatalf("ensure p2p calls=%d friend requests=%d, want 1 and 0", im.ensureP2PCalls, im.friendRequests)
|
t.Fatalf("ensure p2p calls=%d friend requests=%d, want 0 and 1", im.ensureP2PCalls, im.friendRequests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user