Community member joins the community if he sends a request to join an… (#4321)

This commit is contained in:
Ibrahem Khalil 2023-12-09 14:46:30 +02:00 committed by GitHub
parent 71b27394bb
commit be8568e174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 226 additions and 1 deletions

View File

@ -66,6 +66,7 @@ func SetValidateInterval(duration time.Duration) {
var (
ErrTorrentTimedout = errors.New("torrent has timed out")
ErrCommunityRequestAlreadyRejected = errors.New("that user was already rejected from the community")
ErrInvalidClock = errors.New("invalid clock to cancel request to join")
)
type Manager struct {
@ -2326,6 +2327,15 @@ func (m *Manager) HandleCommunityCancelRequestToJoin(signer *ecdsa.PublicKey, re
return nil, ErrOrgNotFound
}
previousRequestToJoin, err := m.GetRequestToJoinByPkAndCommunityID(signer, community.ID())
if err != nil {
return nil, err
}
if request.Clock <= previousRequestToJoin.Clock {
return nil, ErrInvalidClock
}
retainDeclined, err := m.shouldUserRetainDeclined(signer, community, request.Clock)
if err != nil {
return nil, err
@ -2344,6 +2354,18 @@ func (m *Manager) HandleCommunityCancelRequestToJoin(signer *ecdsa.PublicKey, re
return nil, err
}
if community.HasMember(signer) {
_, err = community.RemoveUserFromOrg(signer)
if err != nil {
return nil, err
}
err = m.saveAndPublish(community)
if err != nil {
return nil, err
}
}
return requestToJoin, nil
}
@ -2922,6 +2944,10 @@ func (m *Manager) GetCommunityRequestToJoinClock(pk *ecdsa.PublicKey, communityI
return request.Clock, nil
}
func (m *Manager) GetRequestToJoinByPkAndCommunityID(pk *ecdsa.PublicKey, communityID []byte) (*RequestToJoin, error) {
return m.persistence.GetRequestToJoinByPkAndCommunityID(common.PubkeyToHex(pk), communityID)
}
func (m *Manager) UpdateCommunityDescriptionMagnetlinkMessageClock(communityID types.HexBytes, clock uint64) error {
community, err := m.GetByIDString(communityID.String())
if err != nil {
@ -3272,6 +3298,10 @@ func (m *Manager) CanceledRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*Request
return m.persistence.CanceledRequestsToJoinForUser(common.PubkeyToHex(pk))
}
func (m *Manager) CanceledRequestToJoinForUserForCommunityID(pk *ecdsa.PublicKey, communityID []byte) (*RequestToJoin, error) {
return m.persistence.CanceledRequestToJoinForUserForCommunityID(common.PubkeyToHex(pk), communityID)
}
func (m *Manager) PendingRequestsToJoin() ([]*RequestToJoin, error) {
return m.persistence.PendingRequestsToJoin()
}

View File

@ -688,6 +688,26 @@ func (p *Persistence) CanceledRequestsToJoinForUser(pk string) ([]*RequestToJoin
return requests, nil
}
func (p *Persistence) CanceledRequestToJoinForUserForCommunityID(pk string, communityID []byte) (*RequestToJoin, error) {
row := p.db.QueryRow(`SELECT id,public_key,clock,ens_name,chat_id,community_id,state
FROM
communities_requests_to_join
WHERE
state = ? AND public_key = ? AND community_id = ?`,
RequestToJoinStateCanceled, pk, communityID)
request := &RequestToJoin{}
err := row.Scan(&request.ID, &request.PublicKey, &request.Clock, &request.ENSName, &request.ChatID, &request.CommunityID, &request.State)
if err == sql.ErrNoRows {
return nil, nil
} else if err != nil {
return nil, err
}
return request, nil
}
func (p *Persistence) RequestsToJoinForUserByState(pk string, state RequestToJoinState) ([]*RequestToJoin, error) {
var requests []*RequestToJoin
rows, err := p.db.Query(`SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE state = ? AND public_key = ?`, state, pk)

View File

@ -3774,3 +3774,164 @@ func (s *MessengerCommunitiesSuite) TestRetrieveBigCommunity() {
}, "updated description not received")
s.Require().NoError(err)
}
func (s *MessengerCommunitiesSuite) TestRequestAndCancelCommunityAdminOffline() {
ctx := context.Background()
community, _ := s.createCommunity()
s.advertiseCommunityTo(community, s.owner, s.alice)
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
// We try to join the org
response, err := s.alice.RequestToJoinCommunity(request)
s.Require().NoError(err)
s.Require().NotNil(response)
s.Require().Len(response.RequestsToJoinCommunity, 1)
requestToJoin1 := response.RequestsToJoinCommunity[0]
s.Require().NotNil(requestToJoin1)
s.Require().Equal(community.ID(), requestToJoin1.CommunityID)
s.Require().True(requestToJoin1.Our)
s.Require().NotEmpty(requestToJoin1.ID)
s.Require().NotEmpty(requestToJoin1.Clock)
s.Require().Equal(requestToJoin1.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin1.State)
messageState := s.alice.buildMessageState()
messageState.CurrentMessageState = &CurrentMessageState{}
messageState.CurrentMessageState.PublicKey = &s.alice.identity.PublicKey
statusMessage := v1protocol.StatusMessage{}
statusMessage.TransportLayer.Dst = community.PublicKey()
requestToJoinProto := &protobuf.CommunityRequestToJoin{
Clock: requestToJoin1.Clock,
EnsName: requestToJoin1.ENSName,
DisplayName: "Alice",
CommunityId: community.ID(),
}
err = s.owner.HandleCommunityRequestToJoin(messageState, requestToJoinProto, &statusMessage)
s.Require().NoError(err)
ownerCommunity, err := s.owner.GetCommunityByID(community.ID())
// Check Alice has successfully joined at owner side, Because message order was correct
s.Require().True(ownerCommunity.HasMember(s.alice.IdentityPublicKey()))
s.Require().NoError(err)
s.Require().Len(response.Communities(), 1)
s.Require().Equal(response.Communities()[0].RequestedToJoinAt(), requestToJoin1.Clock)
// pull all communities to make sure we set RequestedToJoinAt
allCommunities, err := s.alice.Communities()
s.Require().NoError(err)
s.Require().Len(allCommunities, 2)
if bytes.Equal(allCommunities[0].ID(), community.ID()) {
s.Require().Equal(allCommunities[0].RequestedToJoinAt(), requestToJoin1.Clock)
} else {
s.Require().Equal(allCommunities[1].RequestedToJoinAt(), requestToJoin1.Clock)
}
// pull to make sure it has been saved
requestsToJoin, err := s.alice.MyPendingRequestsToJoin()
s.Require().NoError(err)
s.Require().Len(requestsToJoin, 1)
// Make sure the requests are fetched also by community
requestsToJoin, err = s.alice.PendingRequestsToJoinForCommunity(community.ID())
s.Require().NoError(err)
s.Require().Len(requestsToJoin, 1)
requestToJoin2 := response.RequestsToJoinCommunity[0]
s.Require().NotNil(requestToJoin2)
s.Require().Equal(community.ID(), requestToJoin2.CommunityID)
s.Require().NotEmpty(requestToJoin2.ID)
s.Require().NotEmpty(requestToJoin2.Clock)
s.Require().Equal(requestToJoin2.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin2.State)
s.Require().Equal(requestToJoin1.ID, requestToJoin2.ID)
requestToCancel := &requests.CancelRequestToJoinCommunity{ID: requestToJoin1.ID}
response, err = s.alice.CancelRequestToJoinCommunity(ctx, requestToCancel)
s.Require().NoError(err)
s.Require().NotNil(response)
s.Require().Len(response.RequestsToJoinCommunity, 1)
s.Require().Equal(communities.RequestToJoinStateCanceled, response.RequestsToJoinCommunity[0].State)
messageState = s.alice.buildMessageState()
messageState.CurrentMessageState = &CurrentMessageState{}
messageState.CurrentMessageState.PublicKey = &s.alice.identity.PublicKey
statusMessage.TransportLayer.Dst = community.PublicKey()
requestToJoinCancelProto := &protobuf.CommunityRequestToJoinResponse{
CommunityId: community.ID(),
Clock: requestToJoin1.Clock + 1,
Accepted: true,
}
err = s.alice.HandleCommunityRequestToJoinResponse(messageState, requestToJoinCancelProto, &statusMessage)
s.Require().NoError(err)
aliceJoinedCommunities, err := s.alice.JoinedCommunities()
s.Require().NoError(err)
// Make sure on Alice side she hasn't joined any communities
s.Require().Empty(aliceJoinedCommunities)
// pull to make sure it has been saved
cancelRequestsToJoin, err := s.alice.MyCanceledRequestToJoinForCommunityID(community.ID())
s.Require().NoError(err)
s.Require().NotNil(cancelRequestsToJoin)
s.Require().Equal(cancelRequestsToJoin.State, communities.RequestToJoinStateCanceled)
s.Require().NoError(err)
messageState = s.alice.buildMessageState()
messageState.CurrentMessageState = &CurrentMessageState{}
messageState.CurrentMessageState.PublicKey = &s.alice.identity.PublicKey
statusMessage.TransportLayer.Dst = community.PublicKey()
requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{
Clock: cancelRequestsToJoin.Clock,
CommunityId: community.ID(),
Accepted: true,
}
err = s.alice.HandleCommunityRequestToJoinResponse(messageState, requestToJoinResponseProto, &statusMessage)
s.Require().NoError(err)
// Make sure alice is NOT a member of the community that she cancelled her request to join to
s.Require().False(community.HasMember(s.alice.IdentityPublicKey()))
// Make sure there are no AC notifications for Alice
aliceNotifications, err := s.alice.ActivityCenterNotifications(ActivityCenterNotificationsRequest{
Cursor: "",
Limit: 10,
ActivityTypes: []ActivityCenterType{},
ReadType: ActivityCenterQueryParamsReadUnread,
})
s.Require().NoError(err)
s.Require().Len(aliceNotifications.Notifications, 0)
// Retrieve activity center notifications for admin to make sure the request notification is deleted
notifications, err := s.owner.ActivityCenterNotifications(ActivityCenterNotificationsRequest{
Cursor: "",
Limit: 10,
ActivityTypes: []ActivityCenterType{},
ReadType: ActivityCenterQueryParamsReadUnread,
})
s.Require().NoError(err)
s.Require().Len(notifications.Notifications, 0)
cancelRequestToJoin2 := response.RequestsToJoinCommunity[0]
s.Require().NotNil(cancelRequestToJoin2)
s.Require().Equal(community.ID(), cancelRequestToJoin2.CommunityID)
s.Require().False(cancelRequestToJoin2.Our)
s.Require().NotEmpty(cancelRequestToJoin2.ID)
s.Require().NotEmpty(cancelRequestToJoin2.Clock)
s.Require().Equal(cancelRequestToJoin2.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
}

View File

@ -2355,6 +2355,10 @@ func (m *Messenger) MyCanceledRequestsToJoin() ([]*communities.RequestToJoin, er
return m.communitiesManager.CanceledRequestsToJoinForUser(&m.identity.PublicKey)
}
func (m *Messenger) MyCanceledRequestToJoinForCommunityID(communityID []byte) (*communities.RequestToJoin, error) {
return m.communitiesManager.CanceledRequestToJoinForUserForCommunityID(&m.identity.PublicKey, communityID)
}
func (m *Messenger) MyPendingRequestsToJoin() ([]*communities.RequestToJoin, error) {
return m.communitiesManager.PendingRequestsToJoinForUser(&m.identity.PublicKey)
}

View File

@ -1596,6 +1596,16 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
return ErrInvalidCommunityID
}
myCancelledRequestToJoin, err := m.MyCanceledRequestToJoinForCommunityID(requestToJoinResponseProto.CommunityId)
if err != nil {
return err
}
if myCancelledRequestToJoin != nil {
return nil
}
updatedRequest, err := m.communitiesManager.HandleCommunityRequestToJoinResponse(signer, requestToJoinResponseProto)
if err != nil {
return err
@ -1683,7 +1693,7 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
notification.UpdatedAt = m.GetCurrentTimeInMillis()
err = m.addActivityCenterNotification(state.Response, notification, nil)
if err != nil {
m.logger.Warn("failed to update notification", zap.Error(err))
m.logger.Error("failed to update notification", zap.Error(err))
return err
}
}