Community member joins the community if he sends a request to join an… (#4321)
This commit is contained in:
parent
71b27394bb
commit
be8568e174
|
@ -66,6 +66,7 @@ func SetValidateInterval(duration time.Duration) {
|
||||||
var (
|
var (
|
||||||
ErrTorrentTimedout = errors.New("torrent has timed out")
|
ErrTorrentTimedout = errors.New("torrent has timed out")
|
||||||
ErrCommunityRequestAlreadyRejected = errors.New("that user was already rejected from the community")
|
ErrCommunityRequestAlreadyRejected = errors.New("that user was already rejected from the community")
|
||||||
|
ErrInvalidClock = errors.New("invalid clock to cancel request to join")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
|
@ -2326,6 +2327,15 @@ func (m *Manager) HandleCommunityCancelRequestToJoin(signer *ecdsa.PublicKey, re
|
||||||
return nil, ErrOrgNotFound
|
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)
|
retainDeclined, err := m.shouldUserRetainDeclined(signer, community, request.Clock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -2344,6 +2354,18 @@ func (m *Manager) HandleCommunityCancelRequestToJoin(signer *ecdsa.PublicKey, re
|
||||||
return nil, err
|
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
|
return requestToJoin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2922,6 +2944,10 @@ func (m *Manager) GetCommunityRequestToJoinClock(pk *ecdsa.PublicKey, communityI
|
||||||
return request.Clock, nil
|
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 {
|
func (m *Manager) UpdateCommunityDescriptionMagnetlinkMessageClock(communityID types.HexBytes, clock uint64) error {
|
||||||
community, err := m.GetByIDString(communityID.String())
|
community, err := m.GetByIDString(communityID.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3272,6 +3298,10 @@ func (m *Manager) CanceledRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*Request
|
||||||
return m.persistence.CanceledRequestsToJoinForUser(common.PubkeyToHex(pk))
|
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) {
|
func (m *Manager) PendingRequestsToJoin() ([]*RequestToJoin, error) {
|
||||||
return m.persistence.PendingRequestsToJoin()
|
return m.persistence.PendingRequestsToJoin()
|
||||||
}
|
}
|
||||||
|
|
|
@ -688,6 +688,26 @@ func (p *Persistence) CanceledRequestsToJoinForUser(pk string) ([]*RequestToJoin
|
||||||
return requests, nil
|
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) {
|
func (p *Persistence) RequestsToJoinForUserByState(pk string, state RequestToJoinState) ([]*RequestToJoin, error) {
|
||||||
var requests []*RequestToJoin
|
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)
|
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)
|
||||||
|
|
|
@ -3774,3 +3774,164 @@ func (s *MessengerCommunitiesSuite) TestRetrieveBigCommunity() {
|
||||||
}, "updated description not received")
|
}, "updated description not received")
|
||||||
s.Require().NoError(err)
|
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))
|
||||||
|
}
|
||||||
|
|
|
@ -2355,6 +2355,10 @@ func (m *Messenger) MyCanceledRequestsToJoin() ([]*communities.RequestToJoin, er
|
||||||
return m.communitiesManager.CanceledRequestsToJoinForUser(&m.identity.PublicKey)
|
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) {
|
func (m *Messenger) MyPendingRequestsToJoin() ([]*communities.RequestToJoin, error) {
|
||||||
return m.communitiesManager.PendingRequestsToJoinForUser(&m.identity.PublicKey)
|
return m.communitiesManager.PendingRequestsToJoinForUser(&m.identity.PublicKey)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1596,6 +1596,16 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
|
||||||
return ErrInvalidCommunityID
|
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)
|
updatedRequest, err := m.communitiesManager.HandleCommunityRequestToJoinResponse(signer, requestToJoinResponseProto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1683,7 +1693,7 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
|
||||||
notification.UpdatedAt = m.GetCurrentTimeInMillis()
|
notification.UpdatedAt = m.GetCurrentTimeInMillis()
|
||||||
err = m.addActivityCenterNotification(state.Response, notification, nil)
|
err = m.addActivityCenterNotification(state.Response, notification, nil)
|
||||||
if err != 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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue