Community request to join changes for pending and declined states (#3387)
* Community request to join changes * Fix read state for request to join notification * Bring back deleted notification when updated with response * Update Request timeout to 7 days * Update VERSION
This commit is contained in:
parent
1fe4a898b6
commit
0eff61c57a
|
@ -1184,6 +1184,30 @@ func (m *Manager) markRequestToJoinAsCanceled(pk *ecdsa.PublicKey, community *Co
|
|||
return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateCanceled)
|
||||
}
|
||||
|
||||
func (m *Manager) DeletePendingRequestToJoin(request *RequestToJoin) error {
|
||||
community, err := m.GetByID(request.CommunityID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = m.persistence.DeletePendingRequestToJoin(request.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = m.persistence.SaveCommunity(community)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateClockInRequestToJoin method is used for testing
|
||||
func (m *Manager) UpdateClockInRequestToJoin(id types.HexBytes, clock uint64) error {
|
||||
return m.persistence.UpdateClockInRequestToJoin(id, clock)
|
||||
}
|
||||
|
||||
func (m *Manager) SetMuted(id types.HexBytes, muted bool) error {
|
||||
return m.persistence.SetMuted(id, muted)
|
||||
}
|
||||
|
@ -1296,7 +1320,7 @@ func (m *Manager) DeclineRequestToJoin(request *requests.DeclineRequestToJoinCom
|
|||
return m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, RequestToJoinStateDeclined)
|
||||
}
|
||||
|
||||
func (m *Manager) isUserRejectedFromCommunity(signer *ecdsa.PublicKey, community *Community) (bool, error) {
|
||||
func (m *Manager) isUserRejectedFromCommunity(signer *ecdsa.PublicKey, community *Community, requestClock uint64) (bool, error) {
|
||||
declinedRequestsToJoin, err := m.persistence.DeclinedRequestsToJoinForCommunity(community.ID())
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -1304,7 +1328,14 @@ func (m *Manager) isUserRejectedFromCommunity(signer *ecdsa.PublicKey, community
|
|||
|
||||
for _, req := range declinedRequestsToJoin {
|
||||
if req.PublicKey == common.PubkeyToHex(signer) {
|
||||
return true, nil
|
||||
dbRequestTimeOutClock, err := AddTimeoutToRequestToJoinClock(req.Clock)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if requestClock < dbRequestTimeOutClock {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
|
@ -1319,7 +1350,7 @@ func (m *Manager) HandleCommunityCancelRequestToJoin(signer *ecdsa.PublicKey, re
|
|||
return nil, ErrOrgNotFound
|
||||
}
|
||||
|
||||
isUserRejected, err := m.isUserRejectedFromCommunity(signer, community)
|
||||
isUserRejected, err := m.isUserRejectedFromCommunity(signer, community, request.Clock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1349,7 +1380,7 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, request
|
|||
return nil, ErrOrgNotFound
|
||||
}
|
||||
|
||||
isUserRejected, err := m.isUserRejectedFromCommunity(signer, community)
|
||||
isUserRejected, err := m.isUserRejectedFromCommunity(signer, community, request.Clock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2121,6 +2152,10 @@ func (m *Manager) CanceledRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*Request
|
|||
return m.persistence.CanceledRequestsToJoinForUser(common.PubkeyToHex(pk))
|
||||
}
|
||||
|
||||
func (m *Manager) PendingRequestsToJoin() ([]*RequestToJoin, error) {
|
||||
return m.persistence.PendingRequestsToJoin()
|
||||
}
|
||||
|
||||
func (m *Manager) PendingRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*RequestToJoin, error) {
|
||||
return m.persistence.PendingRequestsToJoinForUser(common.PubkeyToHex(pk))
|
||||
}
|
||||
|
|
|
@ -470,6 +470,25 @@ func (p *Persistence) RequestsToJoinForCommunityWithState(id []byte, state Reque
|
|||
return requests, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) PendingRequestsToJoin() ([]*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 = ?`, RequestToJoinStatePending)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
request := &RequestToJoin{}
|
||||
err := rows.Scan(&request.ID, &request.PublicKey, &request.Clock, &request.ENSName, &request.ChatID, &request.CommunityID, &request.State)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requests = append(requests, request)
|
||||
}
|
||||
return requests, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) PendingRequestsToJoinForCommunity(id []byte) ([]*RequestToJoin, error) {
|
||||
return p.RequestsToJoinForCommunityWithState(id, RequestToJoinStatePending)
|
||||
}
|
||||
|
@ -487,6 +506,17 @@ func (p *Persistence) SetRequestToJoinState(pk string, communityID []byte, state
|
|||
return err
|
||||
}
|
||||
|
||||
func (p *Persistence) DeletePendingRequestToJoin(id []byte) error {
|
||||
_, err := p.db.Exec(`DELETE FROM communities_requests_to_join WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateClockInRequestToJoin method is used for testing
|
||||
func (p *Persistence) UpdateClockInRequestToJoin(id []byte, clock uint64) error {
|
||||
_, err := p.db.Exec(`UPDATE communities_requests_to_join SET clock = ? WHERE id = ?`, clock, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Persistence) SetMuted(communityID []byte, muted bool) error {
|
||||
_, err := p.db.Exec(`UPDATE communities_communities SET muted = ? WHERE id = ?`, muted, communityID)
|
||||
return err
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package communities
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
@ -24,6 +28,7 @@ type RequestToJoin struct {
|
|||
State RequestToJoinState `json:"state"`
|
||||
Our bool `json:"our"`
|
||||
RevealedAddresses map[string][]byte `json:"revealedAddresses,omitempty"`
|
||||
Deleted bool `json:"deleted"`
|
||||
}
|
||||
|
||||
func (r *RequestToJoin) CalculateID() {
|
||||
|
@ -57,3 +62,15 @@ func (r *RequestToJoin) InitFromSyncProtobuf(proto *protobuf.SyncCommunityReques
|
|||
func (r *RequestToJoin) Empty() bool {
|
||||
return len(r.ID)+len(r.PublicKey)+int(r.Clock)+len(r.ENSName)+len(r.ChatID)+len(r.CommunityID)+int(r.State) == 0
|
||||
}
|
||||
|
||||
func AddTimeoutToRequestToJoinClock(clock uint64) (uint64, error) {
|
||||
requestToJoinClock, err := strconv.ParseInt(fmt.Sprint(clock), 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Adding 7 days to the request clock
|
||||
requestTimeOutClock := uint64(time.Unix(requestToJoinClock, 0).AddDate(0, 0, 7).Unix())
|
||||
|
||||
return requestTimeOutClock, nil
|
||||
}
|
||||
|
|
|
@ -1055,7 +1055,7 @@ func (s *MessengerCommunitiesSuite) TestRequestAccess() {
|
|||
s.Require().NotNil(notification)
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusAccepted)
|
||||
s.Require().Equal(notification.Read, true)
|
||||
s.Require().Equal(notification.Read, false)
|
||||
s.Require().Equal(notification.Accepted, false)
|
||||
s.Require().Equal(notification.Dismissed, false)
|
||||
|
||||
|
@ -1079,6 +1079,446 @@ func (s *MessengerCommunitiesSuite) TestRequestAccess() {
|
|||
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSuite) TestDeletePendingRequestAccess() {
|
||||
ctx := context.Background()
|
||||
|
||||
description := &requests.CreateCommunity{
|
||||
Membership: protobuf.CommunityPermissions_ON_REQUEST,
|
||||
Name: "status",
|
||||
Color: "#ffffff",
|
||||
Description: "status community description",
|
||||
}
|
||||
|
||||
// Bob creates a community
|
||||
response, err := s.bob.CreateCommunity(description, true)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
|
||||
community := response.Communities()[0]
|
||||
|
||||
chat := CreateOneToOneChat(common.PubkeyToHex(&s.alice.identity.PublicKey), &s.alice.identity.PublicKey, s.alice.transport)
|
||||
|
||||
s.Require().NoError(s.bob.SaveChat(chat))
|
||||
|
||||
message := buildTestMessage(*chat)
|
||||
message.CommunityID = community.IDString()
|
||||
|
||||
// Bob sends the community link to Alice
|
||||
response, err = s.bob.SendChatMessage(ctx, message)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
|
||||
// Retrieve community link & community for Alice
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
response, err = s.alice.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(response.Communities()) == 0 {
|
||||
return errors.New("message not received")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Alice request to join community
|
||||
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err = s.alice.RequestToJoinCommunity(request)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
requestToJoin := response.RequestsToJoinCommunity[0]
|
||||
s.Require().NotNil(requestToJoin)
|
||||
s.Require().Equal(community.ID(), requestToJoin.CommunityID)
|
||||
s.Require().NotEmpty(requestToJoin.ID)
|
||||
s.Require().NotEmpty(requestToJoin.Clock)
|
||||
s.Require().Equal(requestToJoin.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin.State)
|
||||
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
s.Require().Equal(response.Communities()[0].RequestedToJoinAt(), requestToJoin.Clock)
|
||||
|
||||
// updating request clock by 8 days back
|
||||
requestTime := uint64(time.Now().AddDate(0, 0, -8).Unix())
|
||||
err = s.alice.communitiesManager.UpdateClockInRequestToJoin(requestToJoin.ID, requestTime)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// pull to make sure it has been saved
|
||||
requestsToJoin, err := s.alice.MyPendingRequestsToJoin()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requestsToJoin, 1)
|
||||
|
||||
requestToJoin = requestsToJoin[0]
|
||||
s.Require().Equal(requestToJoin.Clock, requestTime)
|
||||
|
||||
// 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)
|
||||
|
||||
// Retrieve request to join
|
||||
bobRetrieveAll := func() (*MessengerResponse, error) {
|
||||
return s.bob.RetrieveAll()
|
||||
}
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
response, err = bobRetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(response.RequestsToJoinCommunity) == 0 {
|
||||
return errors.New("request to join community not received")
|
||||
}
|
||||
|
||||
// updating request clock by 8 days back
|
||||
requestToJoin := response.RequestsToJoinCommunity[0]
|
||||
err = s.bob.communitiesManager.UpdateClockInRequestToJoin(requestToJoin.ID, requestTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(response.ActivityCenterNotifications()) == 0 {
|
||||
return errors.New("request to join community notification not added in activity center")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// Check activity center notification for Bob
|
||||
fetchActivityCenterNotificationsForAdmin := func() (*ActivityCenterPaginationResponse, error) {
|
||||
return s.bob.ActivityCenterNotifications(ActivityCenterNotificationsRequest{
|
||||
Cursor: "",
|
||||
Limit: 10,
|
||||
ActivityTypes: []ActivityCenterType{},
|
||||
ReadType: ActivityCenterQueryParamsReadUnread,
|
||||
})
|
||||
}
|
||||
notifications, err := fetchActivityCenterNotificationsForAdmin()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(notifications.Notifications, 1)
|
||||
|
||||
notification := notifications.Notifications[0]
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityMembershipRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusPending)
|
||||
|
||||
// Delete pending request to join
|
||||
response, err = s.alice.CheckAndDeletePendingRequestToJoinCommunity(true)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
s.Require().Len(response.ActivityCenterNotifications(), 1)
|
||||
|
||||
requestToJoin = response.RequestsToJoinCommunity[0]
|
||||
s.Require().True(requestToJoin.Deleted)
|
||||
|
||||
notification = response.ActivityCenterNotifications()[0]
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusIdle)
|
||||
|
||||
response, err = s.bob.CheckAndDeletePendingRequestToJoinCommunity(true)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
s.Require().Len(response.ActivityCenterNotifications(), 1)
|
||||
|
||||
requestToJoin = response.RequestsToJoinCommunity[0]
|
||||
s.Require().True(requestToJoin.Deleted)
|
||||
|
||||
notification = response.ActivityCenterNotifications()[0]
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityMembershipRequest)
|
||||
s.Require().True(notification.Deleted)
|
||||
|
||||
// Alice request to join community
|
||||
request = &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err = s.alice.RequestToJoinCommunity(request)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// Retrieve request to join and Check activity center notification for Bob
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
response, err = bobRetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(response.RequestsToJoinCommunity) == 0 {
|
||||
return errors.New("request to join community not received")
|
||||
}
|
||||
|
||||
if len(response.ActivityCenterNotifications()) == 0 {
|
||||
return errors.New("request to join community notification not added in activity center")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// Check activity center notification for Bob
|
||||
notifications, err = fetchActivityCenterNotificationsForAdmin()
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(notifications.Notifications, 1)
|
||||
|
||||
notification = notifications.Notifications[0]
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityMembershipRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusPending)
|
||||
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSuite) TestDeletePendingRequestAccessWithDeclinedState() {
|
||||
ctx := context.Background()
|
||||
|
||||
description := &requests.CreateCommunity{
|
||||
Membership: protobuf.CommunityPermissions_ON_REQUEST,
|
||||
Name: "status",
|
||||
Color: "#ffffff",
|
||||
Description: "status community description",
|
||||
}
|
||||
|
||||
// Bob creates a community
|
||||
response, err := s.bob.CreateCommunity(description, true)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
|
||||
community := response.Communities()[0]
|
||||
|
||||
chat := CreateOneToOneChat(common.PubkeyToHex(&s.alice.identity.PublicKey), &s.alice.identity.PublicKey, s.alice.transport)
|
||||
|
||||
s.Require().NoError(s.bob.SaveChat(chat))
|
||||
|
||||
message := buildTestMessage(*chat)
|
||||
message.CommunityID = community.IDString()
|
||||
|
||||
// Bob sends the community link to Alice
|
||||
response, err = s.bob.SendChatMessage(ctx, message)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
|
||||
// Retrieve community link & community for Alice
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
response, err = s.alice.RetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(response.Communities()) == 0 {
|
||||
return errors.New("message not received")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Alice request to join community
|
||||
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err = s.alice.RequestToJoinCommunity(request)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
notification := response.ActivityCenterNotifications()[0]
|
||||
s.Require().NotNil(notification)
|
||||
s.Require().NotEmpty(notification.ID)
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusPending)
|
||||
s.Require().Equal(notification.Deleted, false)
|
||||
s.Require().Equal(notification.Read, true)
|
||||
|
||||
requestToJoin := response.RequestsToJoinCommunity[0]
|
||||
s.Require().NotNil(requestToJoin)
|
||||
s.Require().Equal(community.ID(), requestToJoin.CommunityID)
|
||||
s.Require().NotEmpty(requestToJoin.ID)
|
||||
s.Require().NotEmpty(requestToJoin.Clock)
|
||||
s.Require().Equal(requestToJoin.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin.State)
|
||||
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
s.Require().Equal(response.Communities()[0].RequestedToJoinAt(), requestToJoin.Clock)
|
||||
|
||||
// Alice deletes activity center notification
|
||||
err = s.alice.DeleteActivityCenterNotifications(ctx, []types.HexBytes{notification.ID}, false)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Check activity center notification for Bob after deleting
|
||||
notifications, err := s.alice.ActivityCenterNotifications(ActivityCenterNotificationsRequest{
|
||||
Cursor: "",
|
||||
Limit: 10,
|
||||
ActivityTypes: []ActivityCenterType{},
|
||||
ReadType: ActivityCenterQueryParamsReadUnread,
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(notifications.Notifications, 0)
|
||||
|
||||
// updating request clock by 8 days back
|
||||
requestTime := uint64(time.Now().AddDate(0, 0, -8).Unix())
|
||||
err = s.alice.communitiesManager.UpdateClockInRequestToJoin(requestToJoin.ID, requestTime)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// pull to make sure it has been saved
|
||||
requestsToJoin, err := s.alice.MyPendingRequestsToJoin()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requestsToJoin, 1)
|
||||
|
||||
requestToJoin = requestsToJoin[0]
|
||||
s.Require().Equal(requestToJoin.Clock, requestTime)
|
||||
|
||||
// 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)
|
||||
|
||||
bobRetrieveAll := func() (*MessengerResponse, error) {
|
||||
return s.bob.RetrieveAll()
|
||||
}
|
||||
|
||||
// Retrieve request to join
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
response, err = bobRetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(response.RequestsToJoinCommunity) == 0 {
|
||||
return errors.New("request to join community not received")
|
||||
}
|
||||
|
||||
// updating request clock by 8 days back
|
||||
requestToJoin := response.RequestsToJoinCommunity[0]
|
||||
err = s.bob.communitiesManager.UpdateClockInRequestToJoin(requestToJoin.ID, requestTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(response.ActivityCenterNotifications()) == 0 {
|
||||
return errors.New("request to join community notification not added in activity center")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// Check activity center notification for Bob
|
||||
fetchActivityCenterNotificationsForAdmin := func() (*ActivityCenterPaginationResponse, error) {
|
||||
return s.bob.ActivityCenterNotifications(ActivityCenterNotificationsRequest{
|
||||
Cursor: "",
|
||||
Limit: 10,
|
||||
ActivityTypes: []ActivityCenterType{},
|
||||
ReadType: ActivityCenterQueryParamsReadUnread,
|
||||
})
|
||||
}
|
||||
|
||||
notifications, err = fetchActivityCenterNotificationsForAdmin()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(notifications.Notifications, 1)
|
||||
|
||||
notification = notifications.Notifications[0]
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityMembershipRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusPending)
|
||||
|
||||
// Check if admin sees requests correctly
|
||||
requestsToJoin, err = s.bob.PendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requestsToJoin, 1)
|
||||
|
||||
requestsToJoin, err = s.bob.DeclinedRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requestsToJoin, 0)
|
||||
|
||||
// Decline request
|
||||
declinedRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: requestToJoin.ID}
|
||||
response, err = s.bob.DeclineRequestToJoinCommunity(declinedRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.ActivityCenterNotifications(), 1)
|
||||
|
||||
notification = response.ActivityCenterNotifications()[0]
|
||||
s.Require().NotNil(notification)
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityMembershipRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusDeclined)
|
||||
s.Require().Equal(notification.Read, true)
|
||||
s.Require().Equal(notification.Accepted, false)
|
||||
s.Require().Equal(notification.Dismissed, true)
|
||||
|
||||
// Check if admin sees requests correctly
|
||||
requestsToJoin, err = s.bob.PendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requestsToJoin, 0)
|
||||
|
||||
requestsToJoin, err = s.bob.DeclinedRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requestsToJoin, 1)
|
||||
|
||||
// Bob deletes activity center notification
|
||||
err = s.bob.DeleteActivityCenterNotifications(ctx, []types.HexBytes{notification.ID}, false)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Check activity center notification for Bob after deleting
|
||||
notifications, err = fetchActivityCenterNotificationsForAdmin()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(notifications.Notifications, 0)
|
||||
|
||||
// Delete pending request to join
|
||||
response, err = s.alice.CheckAndDeletePendingRequestToJoinCommunity(true)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
requestToJoin = response.RequestsToJoinCommunity[0]
|
||||
s.Require().True(requestToJoin.Deleted)
|
||||
|
||||
notification = response.ActivityCenterNotifications()[0]
|
||||
s.Require().NotNil(notification)
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusIdle)
|
||||
s.Require().Equal(notification.Read, false)
|
||||
s.Require().Equal(notification.Deleted, false)
|
||||
|
||||
notificationState := response.ActivityCenterState()
|
||||
s.Require().False(notificationState.HasSeen)
|
||||
|
||||
// Alice request to join community
|
||||
request = &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err = s.alice.RequestToJoinCommunity(request)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// Retrieve request to join and Check activity center notification for Bob
|
||||
err = tt.RetryWithBackOff(func() error {
|
||||
response, err = bobRetrieveAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(response.RequestsToJoinCommunity) == 0 {
|
||||
return errors.New("request to join community not received")
|
||||
}
|
||||
|
||||
if len(response.ActivityCenterNotifications()) == 0 {
|
||||
return errors.New("request to join community notification not added in activity center")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// Check activity center notification for Bob
|
||||
notifications, err = fetchActivityCenterNotificationsForAdmin()
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(notifications.Notifications, 1)
|
||||
|
||||
notification = notifications.Notifications[0]
|
||||
s.Require().Equal(notification.Type, ActivityCenterNotificationTypeCommunityMembershipRequest)
|
||||
s.Require().Equal(notification.MembershipStatus, ActivityCenterMembershipStatusPending)
|
||||
s.Require().False(notification.Deleted)
|
||||
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSuite) TestCancelRequestAccess() {
|
||||
ctx := context.Background()
|
||||
|
||||
|
|
|
@ -711,6 +711,7 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
|
|||
m.watchUnmutedChats()
|
||||
m.watchExpiredMessages()
|
||||
m.watchIdentityImageChanges()
|
||||
m.watchPendingCommunityRequestToJoin()
|
||||
m.broadcastLatestUserStatus()
|
||||
m.timeoutAutomaticStatusUpdates()
|
||||
m.startBackupLoop()
|
||||
|
@ -1430,6 +1431,24 @@ func (m *Messenger) watchIdentityImageChanges() {
|
|||
}()
|
||||
}
|
||||
|
||||
func (m *Messenger) watchPendingCommunityRequestToJoin() {
|
||||
m.logger.Debug("watching community request to join")
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Minute * 10):
|
||||
_, err := m.CheckAndDeletePendingRequestToJoinCommunity(false)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to check and delete pending request to join community", zap.Error(err))
|
||||
}
|
||||
case <-m.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *Messenger) PublishIdentityImage() error {
|
||||
// Reset last published time for ChatIdentity so new contact can receive data
|
||||
err := m.resetLastPublishedTimeForChatIdentity()
|
||||
|
|
|
@ -646,6 +646,7 @@ func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommun
|
|||
CommunityID: community.IDString(),
|
||||
MembershipStatus: ActivityCenterMembershipStatusPending,
|
||||
Read: true,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
err = m.addActivityCenterNotification(response, notification)
|
||||
|
@ -780,6 +781,24 @@ func (m *Messenger) CancelRequestToJoinCommunity(request *requests.CancelRequest
|
|||
response.AddCommunity(community)
|
||||
response.RequestsToJoinCommunity = append(response.RequestsToJoinCommunity, requestToJoin)
|
||||
|
||||
// delete activity center notification
|
||||
notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if notification != nil {
|
||||
err = m.persistence.DeleteActivityCenterNotification(types.FromHex(requestToJoin.ID.String()))
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete notification from Activity Center", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set notification as deleted, so that the client will remove the activity center notification from UI
|
||||
notification.Deleted = true
|
||||
response.AddActivityCenterNotification(notification)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
@ -992,6 +1011,83 @@ func (m *Messenger) leaveCommunity(communityID types.HexBytes) (*MessengerRespon
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (m *Messenger) CheckAndDeletePendingRequestToJoinCommunity(sendResponse bool) (*MessengerResponse, error) {
|
||||
sendSignal := false
|
||||
|
||||
pendingRequestsToJoin, err := m.communitiesManager.PendingRequestsToJoin()
|
||||
if err != nil {
|
||||
m.logger.Error("failed to fetch pending request to join", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pendingRequestsToJoin) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
response := &MessengerResponse{}
|
||||
timeNow := uint64(time.Now().Unix())
|
||||
|
||||
for _, requestToJoin := range pendingRequestsToJoin {
|
||||
requestTimeOutClock, err := communities.AddTimeoutToRequestToJoinClock(requestToJoin.Clock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if timeNow >= requestTimeOutClock {
|
||||
err := m.communitiesManager.DeletePendingRequestToJoin(requestToJoin)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete pending request to join", zap.String("req-id", requestToJoin.ID.String()), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requestToJoin.Deleted = true
|
||||
response.AddRequestToJoinCommunity(requestToJoin)
|
||||
|
||||
notification, err := m.persistence.GetActivityCenterNotificationByID(requestToJoin.ID)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to fetch pending request to join", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if notification != nil {
|
||||
// Delete activity centre notification for community admin
|
||||
if notification.Type == ActivityCenterNotificationTypeCommunityMembershipRequest {
|
||||
err = m.persistence.DeleteActivityCenterNotification(types.FromHex(requestToJoin.ID.String()))
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete notification from activity center", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
notification.Deleted = true
|
||||
response.AddActivityCenterNotification(notification)
|
||||
}
|
||||
// Update activity centre notification for requester
|
||||
if notification.Type == ActivityCenterNotificationTypeCommunityRequest {
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusIdle
|
||||
notification.Read = false
|
||||
notification.Deleted = false
|
||||
err = m.addActivityCenterNotification(response, notification)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to update notification in activity center", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendSignal = true
|
||||
}
|
||||
}
|
||||
|
||||
if sendSignal && !sendResponse {
|
||||
signal.SendNewMessages(response)
|
||||
}
|
||||
|
||||
if sendResponse {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *Messenger) CreateCommunityChat(communityID types.HexBytes, c *protobuf.CommunityChat) (*MessengerResponse, error) {
|
||||
var response MessengerResponse
|
||||
|
||||
|
|
|
@ -1262,6 +1262,17 @@ func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, si
|
|||
return errors.New("invalid community id")
|
||||
}
|
||||
|
||||
timeNow := uint64(time.Now().Unix())
|
||||
|
||||
requestTimeOutClock, err := communities.AddTimeoutToRequestToJoinClock(requestToJoinProto.Clock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if timeNow >= requestTimeOutClock {
|
||||
return errors.New("request is expired")
|
||||
}
|
||||
|
||||
requestToJoin, err := m.communitiesManager.HandleCommunityRequestToJoin(signer, &requestToJoinProto)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1317,6 +1328,7 @@ func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, si
|
|||
Author: contact.ID,
|
||||
CommunityID: community.IDString(),
|
||||
MembershipStatus: ActivityCenterMembershipStatusPending,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
err = m.addActivityCenterNotification(state.Response, notification)
|
||||
|
@ -1417,6 +1429,8 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
|
|||
if notification != nil {
|
||||
if requestToJoinResponseProto.Accepted {
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusAccepted
|
||||
notification.Read = false
|
||||
notification.Deleted = false
|
||||
} else {
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusDeclined
|
||||
}
|
||||
|
|
|
@ -340,6 +340,10 @@ func (r *MessengerResponse) AddCommunitySettings(c *communities.CommunitySetting
|
|||
r.communitiesSettings[c.CommunityID] = c
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) AddRequestToJoinCommunity(requestToJoin *communities.RequestToJoin) {
|
||||
r.RequestsToJoinCommunity = append(r.RequestsToJoinCommunity, requestToJoin)
|
||||
}
|
||||
|
||||
func (r *MessengerResponse) AddSetting(s *settings.SyncSettingField) {
|
||||
r.Settings = append(r.Settings, s)
|
||||
}
|
||||
|
|
|
@ -554,6 +554,11 @@ func (api *PublicAPI) RequestToJoinCommunity(request *requests.RequestToJoinComm
|
|||
return api.service.messenger.RequestToJoinCommunity(request)
|
||||
}
|
||||
|
||||
// CheckAndClearPendingRequestToJoinCommunity to delete pending request to join a community which are older than 7 days
|
||||
func (api *PublicAPI) CheckAndDeletePendingRequestToJoinCommunity() (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.CheckAndDeletePendingRequestToJoinCommunity(true)
|
||||
}
|
||||
|
||||
// CreateCommunityCategory creates a category within a particular community
|
||||
func (api *PublicAPI) CreateCommunityCategory(request *requests.CreateCommunityCategory) (*protocol.MessengerResponse, error) {
|
||||
return api.service.messenger.CreateCommunityCategory(request)
|
||||
|
|
Loading…
Reference in New Issue