mirror of
https://github.com/status-im/status-go.git
synced 2025-01-21 12:11:44 +00:00
refactor: EventSenders forward RequestToJoin decision to control node
This is a bigger change in how community membership requests are handled among admins, token masters, owners, and control nodes. Prior to this commit, all privileged users, also known as `EventSenders`, were able to accept and reject community membership requests and those changes would be applied by all users. This commit changes this behaviour such that: 1. EventSenders can make a decision (accept, reject), but merely forward their decision to the control node, which ultimately has to confirm it 2. EventSenders are no longer removing or adding members to and from communities 3. When an eventsender signaled a decision, the membership request will enter a pending state (acceptedPending or rejectedPending) 4. Once a decision was made by one eventsender, no other eventsender can override that decision This implementation is covered with a bunch of tests: - Ensure that decision made by event sender is shared with other event senders - `testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders()` - `testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders()` - Ensure memebrship request stays pending, until control node has confirmed decision by event senders - `testAcceptMemberRequestToJoinNotConfirmedByControlNode()` - `testRejectMemberRequestToJoinNotConfirmedByControlNode()` - Ensure that decision made by event sender cannot be overriden by other event senders - `testEventSenderCannotOverrideRequestToJoinState()` These test cases live in three test suites for different event sender types respectively - `OwnerWithoutCommunityKeyCommunityEventsSuite` - `TokenMasterCommunityEventsSuite` - `AdminCommunityEventsSuite` In addition to the changes mentioned above, there's also a smaller changes that ensures membership requests to *not* attached revealed wallet addresses when the requests are sent to event senders (in addition to control nodes). Requests send to a control node will still include revealed addresses as the control node needs them to verify token permissions. This commit does not yet handle the case of event senders attempting to kick and ban members. Similar to accepting and rejecting membership requests, kicking and banning need a new pending state. However, we don't track such state in local databases yet so those two cases will be handled in future commit to not have this commit grow larger.
This commit is contained in:
parent
57e64122a8
commit
248e4a7f24
@ -37,6 +37,8 @@ const (
|
||||
ActivityCenterMembershipStatusPending
|
||||
ActivityCenterMembershipStatusAccepted
|
||||
ActivityCenterMembershipStatusDeclined
|
||||
ActivityCenterMembershipStatusAcceptedPending
|
||||
ActivityCenterMembershipStatusDeclinedPending
|
||||
)
|
||||
|
||||
type ActivityCenterQueryParamsRead uint
|
||||
|
@ -753,7 +753,6 @@ func (o *Community) RemoveUserFromOrg(pk *ecdsa.PublicKey) (*protobuf.CommunityD
|
||||
}
|
||||
|
||||
o.removeMemberFromOrg(pk)
|
||||
|
||||
if isControlNode {
|
||||
o.increaseClock()
|
||||
}
|
||||
@ -1940,31 +1939,14 @@ func (o *Community) AddMemberWithRevealedAccounts(dbRequest *RequestToJoin, role
|
||||
defer o.mutex.Unlock()
|
||||
|
||||
isControlNode := o.IsControlNode()
|
||||
allowedToSendEvents := o.HasPermissionToSendCommunityEvents()
|
||||
|
||||
if !isControlNode && !allowedToSendEvents {
|
||||
if !isControlNode {
|
||||
return nil, ErrNotAdmin
|
||||
}
|
||||
|
||||
changes := o.addMemberWithRevealedAccounts(dbRequest.PublicKey, roles, accounts, dbRequest.Clock)
|
||||
|
||||
if allowedToSendEvents {
|
||||
acceptedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin)
|
||||
acceptedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf()
|
||||
|
||||
adminChanges := &CommunityEventChanges{
|
||||
CommunityChanges: changes,
|
||||
AcceptedRequestsToJoin: acceptedRequestsToJoin,
|
||||
}
|
||||
err := o.addNewCommunityEvent(o.ToCommunityRequestToJoinAcceptCommunityEvent(adminChanges))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if isControlNode {
|
||||
o.increaseClock()
|
||||
}
|
||||
o.increaseClock()
|
||||
|
||||
return changes, nil
|
||||
}
|
||||
@ -2130,16 +2112,6 @@ func (o *Community) deleteChat(chatID string) *CommunityChanges {
|
||||
return changes
|
||||
}
|
||||
|
||||
func (o *Community) addCommunityMember(pk *ecdsa.PublicKey, member *protobuf.CommunityMember) {
|
||||
|
||||
if o.config.CommunityDescription.Members == nil {
|
||||
o.config.CommunityDescription.Members = make(map[string]*protobuf.CommunityMember)
|
||||
}
|
||||
|
||||
memberKey := common.PubkeyToHex(pk)
|
||||
o.config.CommunityDescription.Members[memberKey] = member
|
||||
}
|
||||
|
||||
func (o *Community) addTokenPermission(permission *protobuf.CommunityTokenPermission) (*CommunityChanges, error) {
|
||||
if o.config.CommunityDescription.TokenPermissions == nil {
|
||||
o.config.CommunityDescription.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission)
|
||||
|
@ -160,7 +160,6 @@ func (o *Community) ToCommunityRequestToJoinAcceptCommunityEvent(changes *Commun
|
||||
return &CommunityEvent{
|
||||
CommunityEventClock: o.NewCommunityEventClock(),
|
||||
Type: protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT,
|
||||
MembersAdded: changes.MembersAdded,
|
||||
AcceptedRequestsToJoin: changes.AcceptedRequestsToJoin,
|
||||
}
|
||||
}
|
||||
@ -323,26 +322,6 @@ func (o *Community) updateCommunityDescriptionByCommunityEvent(communityEvent Co
|
||||
return err
|
||||
}
|
||||
|
||||
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
|
||||
for pkString, addedMember := range communityEvent.MembersAdded {
|
||||
pk, err := common.HexToPubkey(pkString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !o.HasMember(pk) {
|
||||
o.addCommunityMember(pk, addedMember)
|
||||
}
|
||||
}
|
||||
|
||||
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
|
||||
for pkString := range communityEvent.RejectedRequestsToJoin {
|
||||
pk, err := common.HexToPubkey(pkString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.removeMemberFromOrg(pk)
|
||||
}
|
||||
|
||||
case protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK:
|
||||
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
|
||||
if err != nil {
|
||||
|
@ -192,7 +192,7 @@ func validateCommunityEvent(communityEvent *CommunityEvent) error {
|
||||
}
|
||||
|
||||
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
|
||||
if len(communityEvent.MembersAdded) == 0 {
|
||||
if communityEvent.AcceptedRequestsToJoin == nil {
|
||||
return errors.New("invalid community request to join accepted event")
|
||||
}
|
||||
|
||||
|
@ -287,6 +287,8 @@ type Subscription struct {
|
||||
DownloadingHistoryArchivesFinishedSignal *signal.DownloadingHistoryArchivesFinishedSignal
|
||||
ImportingHistoryArchiveMessagesSignal *signal.ImportingHistoryArchiveMessagesSignal
|
||||
CommunityEventsMessage *CommunityEventsMessage
|
||||
AcceptedRequestsToJoin []types.HexBytes
|
||||
RejectedRequestsToJoin []types.HexBytes
|
||||
}
|
||||
|
||||
type CommunityResponse struct {
|
||||
@ -1353,42 +1355,8 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
|
||||
|
||||
func (m *Manager) handleAdditionalAdminChanges(community *Community) error {
|
||||
|
||||
saveOrUpdateRequestToJoin := func(signer string, request *protobuf.CommunityRequestToJoin, state RequestToJoinState) error {
|
||||
requestToJoin := &RequestToJoin{
|
||||
PublicKey: signer,
|
||||
Clock: request.Clock,
|
||||
ENSName: request.EnsName,
|
||||
CommunityID: request.CommunityId,
|
||||
State: state,
|
||||
RevealedAccounts: request.RevealedAccounts,
|
||||
}
|
||||
|
||||
requestToJoin.CalculateID()
|
||||
|
||||
existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
if existingRequestToJoin != nil {
|
||||
// node already knows about this request to join, so let's compare clocks
|
||||
// and update it if necessary
|
||||
if existingRequestToJoin.Clock <= requestToJoin.Clock {
|
||||
pk, err := common.HexToPubkey(existingRequestToJoin.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := m.persistence.SaveRequestToJoin(requestToJoin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !(community.IsControlNode() || community.HasPermissionToSendCommunityEvents()) {
|
||||
// we're a normal user/member node, so there's nothing for us to do here
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1396,19 +1364,15 @@ func (m *Manager) handleAdditionalAdminChanges(community *Community) error {
|
||||
communityEvent := &community.config.EventsData.Events[i]
|
||||
switch communityEvent.Type {
|
||||
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
|
||||
for signer, request := range communityEvent.AcceptedRequestsToJoin {
|
||||
err := saveOrUpdateRequestToJoin(signer, request, RequestToJoinStateAccepted)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := m.handleCommunityEventRequestAccepted(community, communityEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
|
||||
for signer, request := range communityEvent.RejectedRequestsToJoin {
|
||||
err := saveOrUpdateRequestToJoin(signer, request, RequestToJoinStateDeclined)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := m.handleCommunityEventRequestRejected(community, communityEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
@ -1417,6 +1381,132 @@ func (m *Manager) handleAdditionalAdminChanges(community *Community) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) saveOrUpdateRequestToJoin(signer string, communityID types.HexBytes, requestToJoin *RequestToJoin) (bool, error) {
|
||||
updated := false
|
||||
|
||||
existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return updated, err
|
||||
}
|
||||
|
||||
if existingRequestToJoin != nil {
|
||||
// node already knows about this request to join, so let's compare clocks
|
||||
// and update it if necessary
|
||||
if existingRequestToJoin.Clock <= requestToJoin.Clock {
|
||||
pk, err := common.HexToPubkey(existingRequestToJoin.PublicKey)
|
||||
if err != nil {
|
||||
return updated, err
|
||||
}
|
||||
err = m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), communityID, requestToJoin.State)
|
||||
if err != nil {
|
||||
return updated, err
|
||||
}
|
||||
updated = true
|
||||
}
|
||||
} else {
|
||||
err := m.persistence.SaveRequestToJoin(requestToJoin)
|
||||
if err != nil {
|
||||
return updated, err
|
||||
}
|
||||
}
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (m *Manager) handleCommunityEventRequestAccepted(community *Community, communityEvent *CommunityEvent) error {
|
||||
requestToJoinState := RequestToJoinStateAccepted
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
// if we're an admin and we receive this admin event, we know the state is `pending`
|
||||
requestToJoinState = RequestToJoinStateAcceptedPending
|
||||
}
|
||||
|
||||
acceptedRequestsToJoin := make([]types.HexBytes, 0)
|
||||
|
||||
for signer, request := range communityEvent.AcceptedRequestsToJoin {
|
||||
requestToJoin := &RequestToJoin{
|
||||
PublicKey: signer,
|
||||
Clock: request.Clock,
|
||||
ENSName: request.EnsName,
|
||||
CommunityID: request.CommunityId,
|
||||
State: requestToJoinState,
|
||||
}
|
||||
requestToJoin.CalculateID()
|
||||
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
if existingRequestToJoin.MarkedAsPendingByPrivilegedAccount() {
|
||||
// the request is already in some pending state so we won't override it again
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
requestUpdated, err := m.saveOrUpdateRequestToJoin(signer, community.ID(), requestToJoin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if community.IsControlNode() && requestUpdated {
|
||||
// We only collect requestToJoinIDs which had a state update.
|
||||
// If there wasn't a state update, it means we've seen the request for the first time,
|
||||
// which means we don't have revealed addresses here (as they aren't propagated by
|
||||
// admin nodes), so we don't want to trigger an `AcceptRequestToJoin` in such cases.
|
||||
acceptedRequestsToJoin = append(acceptedRequestsToJoin, requestToJoin.ID)
|
||||
}
|
||||
}
|
||||
if community.IsControlNode() {
|
||||
m.publish(&Subscription{AcceptedRequestsToJoin: acceptedRequestsToJoin})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) handleCommunityEventRequestRejected(community *Community, communityEvent *CommunityEvent) error {
|
||||
requestToJoinState := RequestToJoinStateDeclined
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
// if we're an admin and we receive this admin event, we want to see the same
|
||||
// state that the other admin has decided for
|
||||
requestToJoinState = RequestToJoinStateDeclinedPending
|
||||
}
|
||||
|
||||
rejectedRequestsToJoin := make([]types.HexBytes, 0)
|
||||
|
||||
for signer, request := range communityEvent.RejectedRequestsToJoin {
|
||||
requestToJoin := &RequestToJoin{
|
||||
PublicKey: signer,
|
||||
Clock: request.Clock,
|
||||
ENSName: request.EnsName,
|
||||
CommunityID: request.CommunityId,
|
||||
State: requestToJoinState,
|
||||
}
|
||||
requestToJoin.CalculateID()
|
||||
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
if existingRequestToJoin.MarkedAsPendingByPrivilegedAccount() {
|
||||
// the request is already in some pending state so we won't override it again
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
requestUpdated, err := m.saveOrUpdateRequestToJoin(signer, community.ID(), requestToJoin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if community.IsControlNode() && requestUpdated {
|
||||
rejectedRequestsToJoin = append(rejectedRequestsToJoin, requestToJoin.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if community.IsControlNode() {
|
||||
m.publish(&Subscription{RejectedRequestsToJoin: rejectedRequestsToJoin})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// markRequestToJoin marks all the pending requests to join as completed
|
||||
// if we are members
|
||||
func (m *Manager) markRequestToJoin(pk *ecdsa.PublicKey, community *Community) error {
|
||||
@ -1430,6 +1520,10 @@ func (m *Manager) markRequestToJoinAsCanceled(pk *ecdsa.PublicKey, community *Co
|
||||
return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateCanceled)
|
||||
}
|
||||
|
||||
func (m *Manager) markRequestToJoinAsAcceptedPending(pk *ecdsa.PublicKey, community *Community) error {
|
||||
return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateAcceptedPending)
|
||||
}
|
||||
|
||||
func (m *Manager) DeletePendingRequestToJoin(request *RequestToJoin) error {
|
||||
community, err := m.GetByID(request.CommunityID)
|
||||
if err != nil {
|
||||
@ -1575,54 +1669,84 @@ func (m *Manager) AcceptRequestToJoin(request *requests.AcceptRequestToJoinCommu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
community, err := m.GetByID(dbRequest.CommunityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
revealedAccounts, err := m.persistence.GetRequestToJoinRevealedAddresses(dbRequest.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissionsSatisfied, role, err := m.accountsSatisfyPermissionsToJoin(community, revealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !permissionsSatisfied {
|
||||
return community, ErrNoPermissionToJoin
|
||||
}
|
||||
|
||||
memberRoles := []protobuf.CommunityMember_Roles{}
|
||||
if role != protobuf.CommunityMember_ROLE_NONE {
|
||||
memberRoles = []protobuf.CommunityMember_Roles{role}
|
||||
}
|
||||
|
||||
pk, err := common.HexToPubkey(dbRequest.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = community.AddMemberWithRevealedAccounts(dbRequest, memberRoles, revealedAccounts)
|
||||
community, err := m.GetByID(dbRequest.CommunityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
channels, err := m.accountsSatisfyPermissionsToJoinChannels(community, revealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
if dbRequest.MarkedAsPendingByPrivilegedAccount() {
|
||||
// if the request is in any pending state, it means our admin node has either
|
||||
// already made a decision in the past, or previously received a decision by
|
||||
// another admin, which in both cases means we're not allowed to override this
|
||||
// state again
|
||||
return nil, errors.New("request to join is already in pending state")
|
||||
}
|
||||
|
||||
for channelID := range channels {
|
||||
_, err = community.AddMemberToChat(channelID, pk, memberRoles)
|
||||
// admins do not perform permission checks, they merely mark the
|
||||
// request as accepted (pending) and forward their decision to the control node
|
||||
acceptedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin)
|
||||
acceptedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf()
|
||||
|
||||
adminChanges := &CommunityEventChanges{
|
||||
AcceptedRequestsToJoin: acceptedRequestsToJoin,
|
||||
}
|
||||
|
||||
err := community.addNewCommunityEvent(community.ToCommunityRequestToJoinAcceptCommunityEvent(adminChanges))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := m.markRequestToJoinAsAcceptedPending(pk, community); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.markRequestToJoin(pk, community); err != nil {
|
||||
return nil, err
|
||||
if community.IsControlNode() {
|
||||
revealedAccounts, err := m.persistence.GetRequestToJoinRevealedAddresses(dbRequest.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissionsSatisfied, role, err := m.accountsSatisfyPermissionsToJoin(community, revealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !permissionsSatisfied {
|
||||
return community, ErrNoPermissionToJoin
|
||||
}
|
||||
|
||||
memberRoles := []protobuf.CommunityMember_Roles{}
|
||||
if role != protobuf.CommunityMember_ROLE_NONE {
|
||||
memberRoles = []protobuf.CommunityMember_Roles{role}
|
||||
}
|
||||
|
||||
_, err = community.AddMemberWithRevealedAccounts(dbRequest, memberRoles, revealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
channels, err := m.accountsSatisfyPermissionsToJoinChannels(community, revealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for channelID := range channels {
|
||||
_, err = community.AddMemberToChat(channelID, pk, memberRoles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.markRequestToJoin(pk, community); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = m.saveAndPublish(community)
|
||||
@ -1648,7 +1772,11 @@ func (m *Manager) DeclineRequestToJoin(request *requests.DeclineRequestToJoinCom
|
||||
return err
|
||||
}
|
||||
|
||||
err = m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, RequestToJoinStateDeclined)
|
||||
requestToJoinState := RequestToJoinStateDeclined
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
requestToJoinState = RequestToJoinStateDeclinedPending
|
||||
}
|
||||
err = m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, requestToJoinState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1727,7 +1855,7 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, request
|
||||
}
|
||||
|
||||
// don't process request as admin if community is configured as auto-accept
|
||||
if community.HasPermissionToSendCommunityEvents() && community.AcceptRequestToJoinAutomatically() {
|
||||
if !community.IsControlNode() && community.AcceptRequestToJoinAutomatically() {
|
||||
return nil, errors.New("ignoring request to join, community is set to auto-accept")
|
||||
}
|
||||
|
||||
@ -1759,11 +1887,29 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, request
|
||||
|
||||
requestToJoin.CalculateID()
|
||||
|
||||
if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil {
|
||||
existingRequestToJoin, err := m.persistence.GetRequestToJoin(requestToJoin.ID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(request.RevealedAccounts) > 0 {
|
||||
if existingRequestToJoin != nil {
|
||||
// request to join was already processed by an admin and waits to get
|
||||
// confirmation for its decision
|
||||
//
|
||||
// we're only interested in immediately declining any declined/pending
|
||||
// requests here, because if it's accepted/pending, we still need to perform
|
||||
// some checks
|
||||
if existingRequestToJoin.State == RequestToJoinStateDeclinedPending {
|
||||
requestToJoin.State = RequestToJoinStateDeclined
|
||||
return requestToJoin, nil
|
||||
}
|
||||
} else {
|
||||
if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(request.RevealedAccounts) > 0 && community.IsControlNode() {
|
||||
// verify if revealed addresses indeed belong to requester
|
||||
for _, revealedAccount := range request.RevealedAccounts {
|
||||
recoverParams := account.RecoverParams{
|
||||
@ -1784,7 +1930,7 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, request
|
||||
}
|
||||
|
||||
// Save revealed addresses + signatures so they can later be added
|
||||
// to the community member list when the request is accepted
|
||||
// to the control node's local table of known revealed addresses
|
||||
err = m.persistence.SaveRequestToJoinRevealedAddresses(requestToJoin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1796,22 +1942,42 @@ func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, request
|
||||
// More specifically, CommunityRequestToLeave may be delivered later than CommunityRequestToJoin, or not delivered at all
|
||||
acceptAutomatically := community.AcceptRequestToJoinAutomatically() || community.HasMember(signer)
|
||||
if acceptAutomatically {
|
||||
err = m.markRequestToJoin(signer, community)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if community.IsControlNode() {
|
||||
err = m.markRequestToJoin(signer, community)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Don't check permissions here,
|
||||
// it will be done further in the processing pipeline.
|
||||
requestToJoin.State = RequestToJoinStateAccepted
|
||||
} else {
|
||||
err = m.markRequestToJoinAsAcceptedPending(signer, community)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requestToJoin.State = RequestToJoinStateAcceptedPending
|
||||
}
|
||||
// Don't check permissions here,
|
||||
// it will be done further in the processing pipeline.
|
||||
requestToJoin.State = RequestToJoinStateAccepted
|
||||
return requestToJoin, nil
|
||||
}
|
||||
|
||||
permissionsSatisfied, _, err := m.accountsSatisfyPermissionsToJoin(community, request.RevealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !permissionsSatisfied {
|
||||
requestToJoin.State = RequestToJoinStateDeclined
|
||||
if community.IsControlNode() && len(request.RevealedAccounts) > 0 {
|
||||
permissionsSatisfied, _, err := m.accountsSatisfyPermissionsToJoin(community, request.RevealedAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !permissionsSatisfied {
|
||||
requestToJoin.State = RequestToJoinStateDeclined
|
||||
}
|
||||
if permissionsSatisfied && existingRequestToJoin.State == RequestToJoinStateAcceptedPending {
|
||||
err = m.markRequestToJoin(signer, community)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if the request to join was already accepted by another admin,
|
||||
// we mark it as accepted so it won't be in pending state, even if the community
|
||||
// is not set to auto-accept
|
||||
requestToJoin.State = RequestToJoinStateAccepted
|
||||
}
|
||||
}
|
||||
|
||||
return requestToJoin, nil
|
||||
@ -2801,6 +2967,14 @@ func (m *Manager) AcceptedRequestsToJoinForCommunity(id types.HexBytes) ([]*Requ
|
||||
return m.persistence.AcceptedRequestsToJoinForCommunity(id)
|
||||
}
|
||||
|
||||
func (m *Manager) AcceptedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
|
||||
return m.persistence.AcceptedPendingRequestsToJoinForCommunity(id)
|
||||
}
|
||||
|
||||
func (m *Manager) DeclinedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
|
||||
return m.persistence.DeclinedPendingRequestsToJoinForCommunity(id)
|
||||
}
|
||||
|
||||
func (m *Manager) CanPost(pk *ecdsa.PublicKey, communityID string, chatID string, grant []byte) (bool, error) {
|
||||
community, err := m.GetByIDString(communityID)
|
||||
if err != nil {
|
||||
|
@ -749,6 +749,14 @@ func (p *Persistence) AcceptedRequestsToJoinForCommunity(id []byte) ([]*RequestT
|
||||
return p.RequestsToJoinForCommunityWithState(id, RequestToJoinStateAccepted)
|
||||
}
|
||||
|
||||
func (p *Persistence) AcceptedPendingRequestsToJoinForCommunity(id []byte) ([]*RequestToJoin, error) {
|
||||
return p.RequestsToJoinForCommunityWithState(id, RequestToJoinStateAcceptedPending)
|
||||
}
|
||||
|
||||
func (p *Persistence) DeclinedPendingRequestsToJoinForCommunity(id []byte) ([]*RequestToJoin, error) {
|
||||
return p.RequestsToJoinForCommunityWithState(id, RequestToJoinStateDeclinedPending)
|
||||
}
|
||||
|
||||
func (p *Persistence) SetRequestToJoinState(pk string, communityID []byte, state RequestToJoinState) error {
|
||||
_, err := p.db.Exec(`UPDATE communities_requests_to_join SET state = ? WHERE community_id = ? AND public_key = ?`, state, communityID, pk)
|
||||
return err
|
||||
|
@ -16,6 +16,8 @@ const (
|
||||
RequestToJoinStateDeclined
|
||||
RequestToJoinStateAccepted
|
||||
RequestToJoinStateCanceled
|
||||
RequestToJoinStateAcceptedPending
|
||||
RequestToJoinStateDeclinedPending
|
||||
)
|
||||
|
||||
type RequestToJoin struct {
|
||||
@ -72,6 +74,10 @@ 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 (r *RequestToJoin) MarkedAsPendingByPrivilegedAccount() bool {
|
||||
return r.State == RequestToJoinStateAcceptedPending || r.State == RequestToJoinStateDeclinedPending
|
||||
}
|
||||
|
||||
func AddTimeoutToRequestToJoinClock(clock uint64) (uint64, error) {
|
||||
requestToJoinClock, err := strconv.ParseInt(fmt.Sprint(clock), 10, 64)
|
||||
if err != nil {
|
||||
|
@ -198,22 +198,70 @@ func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCannotDeleteBeco
|
||||
s.Require().Nil(response)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
||||
additionalOwner := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{additionalOwner})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalOwner)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequestToJoinNotConfirmedByControlNode() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinNotConfirmedByControlNode(s, community, user)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerAcceptMemberRequestToJoin() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoin(s, community, user)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
||||
additionalOwner := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{additionalOwner})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalOwner)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequestToJoinNotConfirmedByControlNode() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoinNotConfirmedByControlNode(s, community, user)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRejectMemberRequestToJoin() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoin(s, community, user)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerRequestToJoinStateCannotBeOverridden() {
|
||||
additionalOwner := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{additionalOwner})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalOwner)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() {
|
||||
additionalOwner := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER, []*Messenger{additionalOwner})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalOwner)
|
||||
}
|
||||
|
||||
func (s *OwnerWithoutCommunityKeyCommunityEventsSuite) TestOwnerCreateEditDeleteCategories() {
|
||||
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_OWNER)
|
||||
testCreateEditDeleteCategories(s, community)
|
||||
|
@ -124,20 +124,68 @@ func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCannotDeleteBecomeAdmin
|
||||
testEventSenderCannotDeleteBecomeAdminPermission(s, community)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterAcceptMemberRequestToJoinNotConfirmedByControlNode() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinNotConfirmedByControlNode(s, community, user)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterAcceptMemberRequestToJoin() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER)
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoin(s, community, user)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
||||
additionalTokenMaster := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalTokenMaster)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
||||
additionalTokenMaster := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalTokenMaster)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJoinNotConfirmedByControlNode() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoinNotConfirmedByControlNode(s, community, user)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRejectMemberRequestToJoin() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER)
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoin(s, community, user)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterRequestToJoinStateCannotBeOverridden() {
|
||||
additionalTokenMaster := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalTokenMaster)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() {
|
||||
additionalTokenMaster := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER, []*Messenger{additionalTokenMaster})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalTokenMaster)
|
||||
}
|
||||
|
||||
func (s *TokenMasterCommunityEventsSuite) TestTokenMasterCreateEditDeleteCategories() {
|
||||
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_TOKEN_MASTER)
|
||||
testCreateEditDeleteCategories(s, community)
|
||||
|
@ -338,7 +338,7 @@ func assertCheckTokenPermissionCreated(s *suite.Suite, community *communities.Co
|
||||
s.Require().Equal(permissions[0].TokenCriteria[0].Decimals, uint64(18))
|
||||
}
|
||||
|
||||
func setUpOnRequestCommunityAndRoles(base CommunityEventsTestsInterface, role protobuf.CommunityMember_Roles) *communities.Community {
|
||||
func setUpOnRequestCommunityAndRoles(base CommunityEventsTestsInterface, role protobuf.CommunityMember_Roles, additionalEventSenders []*Messenger) *communities.Community {
|
||||
tcs2, err := base.GetControlNode().communitiesManager.All()
|
||||
s := base.GetSuite()
|
||||
s.Require().NoError(err, "eventSender.communitiesManager.All")
|
||||
@ -365,9 +365,20 @@ func setUpOnRequestCommunityAndRoles(base CommunityEventsTestsInterface, role pr
|
||||
checkPermissionGranted := func(response *MessengerResponse) error {
|
||||
return checkRolePermissionInResponse(response, base.GetEventSender().IdentityPublicKey(), role)
|
||||
}
|
||||
|
||||
waitOnMessengerResponse(s, WaitCommunityCondition, checkPermissionGranted, base.GetMember())
|
||||
|
||||
for _, eventSender := range additionalEventSenders {
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), eventSender)
|
||||
joinOnRequestCommunity(s, community, base.GetControlNode(), eventSender)
|
||||
|
||||
grantPermission(s, community, base.GetControlNode(), eventSender, role)
|
||||
checkPermissionGranted = func(response *MessengerResponse) error {
|
||||
return checkRolePermissionInResponse(response, eventSender.IdentityPublicKey(), role)
|
||||
}
|
||||
waitOnMessengerResponse(s, WaitCommunityCondition, checkPermissionGranted, base.GetMember())
|
||||
waitOnMessengerResponse(s, WaitCommunityCondition, checkPermissionGranted, base.GetEventSender())
|
||||
}
|
||||
|
||||
return community
|
||||
}
|
||||
|
||||
@ -761,7 +772,8 @@ func testAcceptMemberRequestToJoin(base CommunityEventsTestsInterface, community
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
_ = response.RequestsToJoinCommunity[0]
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
response, err = WaitOnMessengerResponse(
|
||||
@ -772,19 +784,107 @@ func testAcceptMemberRequestToJoin(base CommunityEventsTestsInterface, community
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
receivedRequest := response.RequestsToJoinCommunity[0]
|
||||
// event sender has not accepted request yet
|
||||
eventSenderCommunity, err := base.GetEventSender().GetCommunityByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().False(eventSenderCommunity.HasMember(&user.identity.PublicKey))
|
||||
|
||||
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
response, err = base.GetEventSender().AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
// we don't expect `user` to be a member already, because `eventSender` merely
|
||||
// forwards its accept decision to the control node
|
||||
s.Require().False(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
|
||||
// user receives community admin event without being a member yet
|
||||
response, err = WaitOnMessengerResponse(
|
||||
user,
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"user did not receive community request to join response",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
// `user` should not be part of the community yet, we need to wait for
|
||||
// the control node to confirm `eventSender`s decision
|
||||
s.Require().False(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
|
||||
// control node receives community event with accepted membership request
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetControlNode(),
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"control node did not receive community request to join response",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
|
||||
// at this point, the request to join is marked as accepted by control node
|
||||
acceptedRequests, err := base.GetControlNode().AcceptedRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
// we expect 3 here (1 event senders, 1 member + 1 from user)
|
||||
s.Require().Len(acceptedRequests, 3)
|
||||
s.Require().Equal(acceptedRequests[2].PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
|
||||
|
||||
// user receives updated community
|
||||
_, err = WaitOnMessengerResponse(
|
||||
user,
|
||||
func(r *MessengerResponse) bool {
|
||||
return len(r.Communities()) > 0 && r.Communities()[0].HasMember(&user.identity.PublicKey)
|
||||
},
|
||||
"alice did not receive community request to join response",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func testAcceptMemberRequestToJoinNotConfirmedByControlNode(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger) {
|
||||
// set up additional user that will send request to join
|
||||
_, err := user.Start()
|
||||
|
||||
s := base.GetSuite()
|
||||
|
||||
s.Require().NoError(err)
|
||||
defer user.Shutdown() // nolint: errcheck
|
||||
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), user)
|
||||
|
||||
// user sends request to join
|
||||
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err := user.RequestToJoinCommunity(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// event sender has not accepted request yet
|
||||
eventSenderCommunity, err := base.GetEventSender().GetCommunityByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().False(eventSenderCommunity.HasMember(&user.identity.PublicKey))
|
||||
|
||||
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: receivedRequest.ID}
|
||||
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
response, err = base.GetEventSender().AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
s.Require().True(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
// we don't expect `user` to be a member already, because `eventSender` merely
|
||||
// forwards its accept decision to the control node
|
||||
s.Require().False(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
|
||||
// at this point, the request to join is in accepted/pending state
|
||||
acceptedPendingRequests, err := base.GetEventSender().AcceptedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(acceptedPendingRequests, 1)
|
||||
s.Require().Equal(acceptedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
|
||||
|
||||
// user receives request to join response
|
||||
response, err = WaitOnMessengerResponse(
|
||||
@ -794,32 +894,179 @@ func testAcceptMemberRequestToJoin(base CommunityEventsTestsInterface, community
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
s.Require().True(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
// `user` should not be part of the community yet, because control node
|
||||
// hasn't confirmed the decistion yet
|
||||
s.Require().False(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
}
|
||||
|
||||
// control node receives updated community
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetControlNode(),
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"control node did not receive community request to join response",
|
||||
func testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) {
|
||||
// set up additional user that will send request to join
|
||||
_, err := user.Start()
|
||||
|
||||
s := base.GetSuite()
|
||||
|
||||
s.Require().NoError(err)
|
||||
defer user.Shutdown() // nolint: errcheck
|
||||
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), user)
|
||||
|
||||
// user sends request to join
|
||||
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err := user.RequestToJoinCommunity(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
|
||||
requests, err := base.GetControlNode().AcceptedRequestsToJoinForCommunity(community.ID())
|
||||
// there's now two requests to join (event sender and member) + 1 from user
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(requests, 3)
|
||||
s.Require().True(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
|
||||
// member receives updated community
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetMember(),
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"alice did not receive community request to join response",
|
||||
// event sender 2 receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// event sender 1 accepts request
|
||||
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
response, err = base.GetEventSender().AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.Communities(), 1)
|
||||
s.Require().True(response.Communities()[0].HasMember(&user.identity.PublicKey))
|
||||
|
||||
// event sender 2 receives decision of other event sender
|
||||
_, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// at this point, the request to join is in accepted/pending state for event sender 2
|
||||
acceptedPendingRequests, err := additionalEventSender.AcceptedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(acceptedPendingRequests, 1)
|
||||
s.Require().Equal(acceptedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
|
||||
}
|
||||
|
||||
func testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) {
|
||||
// set up additional user that will send request to join
|
||||
_, err := user.Start()
|
||||
|
||||
s := base.GetSuite()
|
||||
|
||||
s.Require().NoError(err)
|
||||
defer user.Shutdown() // nolint: errcheck
|
||||
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), user)
|
||||
|
||||
// user sends request to join
|
||||
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err := user.RequestToJoinCommunity(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// event sender 2 receives request to join
|
||||
response, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
response, err = base.GetEventSender().DeclineRequestToJoinCommunity(rejectRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
|
||||
// event sender 2 receives decision of other event sender
|
||||
_, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// at this point, the request to join is in declined/pending state for event sender 2
|
||||
rejectedPendingRequests, err := additionalEventSender.DeclinedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(rejectedPendingRequests, 1)
|
||||
s.Require().Equal(rejectedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
|
||||
}
|
||||
|
||||
func testRejectMemberRequestToJoinNotConfirmedByControlNode(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger) {
|
||||
// set up additional user that will send request to join
|
||||
_, err := user.Start()
|
||||
|
||||
s := base.GetSuite()
|
||||
|
||||
s.Require().NoError(err)
|
||||
defer user.Shutdown() // nolint: errcheck
|
||||
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), user)
|
||||
|
||||
// user sends request to join
|
||||
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err := user.RequestToJoinCommunity(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// event sender has not accepted request
|
||||
eventSenderCommunity, err := base.GetEventSender().GetCommunityByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().False(eventSenderCommunity.HasMember(&user.identity.PublicKey))
|
||||
|
||||
declineRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
response, err = base.GetEventSender().DeclineRequestToJoinCommunity(declineRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
|
||||
// at this point, the request to join is in decline/pending state
|
||||
declinedPendingRequests, err := base.GetEventSender().DeclinedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(declinedPendingRequests, 1)
|
||||
s.Require().Equal(declinedPendingRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
|
||||
|
||||
// user won't receive anything
|
||||
_, err = WaitOnMessengerResponse(
|
||||
user,
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) == 0 },
|
||||
"user did not receive community request to join response",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func testRejectMemberRequestToJoin(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger) {
|
||||
@ -838,6 +1085,8 @@ func testRejectMemberRequestToJoin(base CommunityEventsTestsInterface, community
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
response, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
@ -856,15 +1105,13 @@ func testRejectMemberRequestToJoin(base CommunityEventsTestsInterface, community
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
receivedRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender has not accepted request yet
|
||||
eventSenderCommunity, err := base.GetEventSender().GetCommunityByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().False(eventSenderCommunity.HasMember(&user.identity.PublicKey))
|
||||
|
||||
// event sender rejects request to join
|
||||
rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: receivedRequest.ID}
|
||||
rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
_, err = base.GetEventSender().DeclineRequestToJoinCommunity(rejectRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
|
||||
@ -886,6 +1133,168 @@ func testRejectMemberRequestToJoin(base CommunityEventsTestsInterface, community
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func testEventSenderCannotOverrideRequestToJoinState(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) {
|
||||
_, err := user.Start()
|
||||
|
||||
s := base.GetSuite()
|
||||
s.Require().NoError(err)
|
||||
defer user.Shutdown() // nolint: errcheck
|
||||
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), user)
|
||||
|
||||
// user sends request to join
|
||||
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err := user.RequestToJoinCommunity(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// event sender 2 receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
// request is pending for event sener 2
|
||||
pendingRequests, err := additionalEventSender.PendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(pendingRequests)
|
||||
s.Require().Len(pendingRequests, 1)
|
||||
|
||||
// event sender 1 rejects request to join
|
||||
rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
_, err = base.GetEventSender().DeclineRequestToJoinCommunity(rejectRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// request to join is now marked as rejected pending for event sender 1
|
||||
rejectedPendingRequests, err := base.GetEventSender().DeclinedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(rejectedPendingRequests)
|
||||
s.Require().Len(rejectedPendingRequests, 1)
|
||||
|
||||
// event sender 2 receives event sender 1's decision
|
||||
_, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// request to join is now marked as rejected pending for event sender 2
|
||||
rejectedPendingRequests, err = additionalEventSender.DeclinedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(rejectedPendingRequests)
|
||||
s.Require().Len(rejectedPendingRequests, 1)
|
||||
|
||||
// event sender 2 should not be able to override that pending state
|
||||
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
_, err = additionalEventSender.AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||
s.Require().Error(err)
|
||||
}
|
||||
|
||||
func testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(base CommunityEventsTestsInterface, community *communities.Community, user *Messenger, additionalEventSender *Messenger) {
|
||||
_, err := user.Start()
|
||||
|
||||
s := base.GetSuite()
|
||||
s.Require().NoError(err)
|
||||
defer user.Shutdown() // nolint: errcheck
|
||||
|
||||
advertiseCommunityTo(s, community, base.GetControlNode(), user)
|
||||
|
||||
// user sends request to join
|
||||
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||
response, err := user.RequestToJoinCommunity(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(response)
|
||||
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||
|
||||
sentRequest := response.RequestsToJoinCommunity[0]
|
||||
|
||||
// event sender receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
base.GetEventSender(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// event sender 2 receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
additionalEventSender,
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// control node receives request to join
|
||||
_, err = WaitOnMessengerResponse(
|
||||
base.GetControlNode(),
|
||||
func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity) > 0 },
|
||||
"event sender did not receive community request to join",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// event sender 1 rejects request to join
|
||||
rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
_, err = base.GetEventSender().DeclineRequestToJoinCommunity(rejectRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
// request to join is now marked as rejected pending for event sender 1
|
||||
rejectedPendingRequests, err := base.GetEventSender().DeclinedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(rejectedPendingRequests)
|
||||
s.Require().Len(rejectedPendingRequests, 1)
|
||||
|
||||
// control node receives event sender 1's and 2's decision
|
||||
_, err = WaitOnMessengerResponse(
|
||||
base.GetControlNode(),
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"control node did not receive event senders decision",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
// request to join is now marked as rejected
|
||||
rejectedRequests, err := base.GetControlNode().DeclinedRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(rejectedRequests)
|
||||
s.Require().Len(rejectedRequests, 1)
|
||||
|
||||
// event sender 2 accepts request to join
|
||||
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
|
||||
_, err = additionalEventSender.AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||
s.Require().NoError(err)
|
||||
// request to join is now marked as accepted pending for event sender 2
|
||||
acceptedPendingRequests, err := additionalEventSender.AcceptedPendingRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(acceptedPendingRequests)
|
||||
s.Require().Len(acceptedPendingRequests, 1)
|
||||
|
||||
// control node now receives event sender 2's decision
|
||||
_, err = WaitOnMessengerResponse(
|
||||
base.GetControlNode(),
|
||||
func(r *MessengerResponse) bool { return len(r.Communities()) > 0 },
|
||||
"control node did not receive event senders decision",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
rejectedRequests, err = base.GetControlNode().DeclinedRequestsToJoinForCommunity(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(rejectedRequests)
|
||||
s.Require().Len(rejectedRequests, 1)
|
||||
// we expect user's request to join still to be rejected
|
||||
s.Require().Equal(rejectedRequests[0].PublicKey, common.PubkeyToHex(&user.identity.PublicKey))
|
||||
}
|
||||
|
||||
func testCreateEditDeleteCategories(base CommunityEventsTestsInterface, community *communities.Community) {
|
||||
newCategory := &requests.CreateCommunityCategory{
|
||||
CommunityID: community.ID(),
|
||||
|
@ -128,22 +128,71 @@ func (s *AdminCommunityEventsSuite) TestAdminCannotDeleteBecomeAdminPermission()
|
||||
testEventSenderCannotDeleteBecomeAdminPermission(s, community)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
||||
additionalAdmin := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalAdmin)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoinNotConfirmedByControlNode() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoinNotConfirmedByControlNode(s, community, user)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoin() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testAcceptMemberRequestToJoin(s, community, user)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
||||
additionalAdmin := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalAdmin)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoinNotConfirmedByControlNode() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoinNotConfirmedByControlNode(s, community, user)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoin() {
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testRejectMemberRequestToJoin(s, community, user)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminRequestToJoinStateCannotBeOverridden() {
|
||||
additionalAdmin := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testEventSenderCannotOverrideRequestToJoinState(s, community, user, additionalAdmin)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() {
|
||||
additionalAdmin := s.newMessenger()
|
||||
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
||||
|
||||
// set up additional user that will send request to join
|
||||
user := s.newMessenger()
|
||||
testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalAdmin)
|
||||
}
|
||||
|
||||
func (s *AdminCommunityEventsSuite) TestAdminCreateEditDeleteCategories() {
|
||||
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
||||
testCreateEditDeleteCategories(s, community)
|
||||
|
@ -254,6 +254,33 @@ func (m *Messenger) handleCommunitiesSubscription(c chan *communities.Subscripti
|
||||
}
|
||||
}
|
||||
|
||||
if sub.AcceptedRequestsToJoin != nil {
|
||||
for _, requestID := range sub.AcceptedRequestsToJoin {
|
||||
accept := &requests.AcceptRequestToJoinCommunity{
|
||||
ID: requestID,
|
||||
}
|
||||
_, err := m.AcceptRequestToJoinCommunity(accept)
|
||||
if err != nil {
|
||||
m.logger.Warn("failed to accept request to join ", zap.Error(err))
|
||||
}
|
||||
// TODO INFORM ADMINS
|
||||
}
|
||||
}
|
||||
|
||||
if sub.RejectedRequestsToJoin != nil {
|
||||
for _, requestID := range sub.RejectedRequestsToJoin {
|
||||
reject := &requests.DeclineRequestToJoinCommunity{
|
||||
ID: requestID,
|
||||
}
|
||||
_, err := m.DeclineRequestToJoinCommunity(reject)
|
||||
if err != nil {
|
||||
m.logger.Warn("failed to decline request to join ", zap.Error(err))
|
||||
}
|
||||
|
||||
// TODO INFORM ADMINS
|
||||
}
|
||||
}
|
||||
|
||||
case <-ticker.C:
|
||||
// If we are not online, we don't even try
|
||||
if !m.online() {
|
||||
@ -951,7 +978,15 @@ func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommun
|
||||
}
|
||||
|
||||
if !community.AcceptRequestToJoinAutomatically() {
|
||||
// send request to join also to community privileged members
|
||||
// send request to join also to community admins but without revealed addresses
|
||||
requestToJoinProto.RevealedAccounts = make([]*protobuf.RevealedAccount, 0)
|
||||
payload, err = proto.Marshal(requestToJoinProto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawMessage.Payload = payload
|
||||
|
||||
privilegedMembers := community.GetPrivilegedMembers()
|
||||
for _, privilegedMember := range privilegedMembers {
|
||||
_, err := m.sender.SendPrivate(context.Background(), privilegedMember, &rawMessage)
|
||||
@ -1320,6 +1355,9 @@ func (m *Messenger) AcceptRequestToJoinCommunity(request *requests.AcceptRequest
|
||||
|
||||
if notification != nil {
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusAccepted
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusAcceptedPending
|
||||
}
|
||||
notification.Read = true
|
||||
notification.Accepted = true
|
||||
notification.UpdatedAt = m.getCurrentTimeInMillis()
|
||||
@ -1353,7 +1391,19 @@ func (m *Messenger) DeclineRequestToJoinCommunity(request *requests.DeclineReque
|
||||
response := &MessengerResponse{}
|
||||
|
||||
if notification != nil {
|
||||
dbRequest, err := m.communitiesManager.GetRequestToJoin(request.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
community, err := m.communitiesManager.GetByID(dbRequest.CommunityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusDeclined
|
||||
if community.HasPermissionToSendCommunityEvents() {
|
||||
notification.MembershipStatus = ActivityCenterMembershipStatusDeclinedPending
|
||||
}
|
||||
notification.Read = true
|
||||
notification.Dismissed = true
|
||||
notification.UpdatedAt = m.getCurrentTimeInMillis()
|
||||
@ -1972,6 +2022,14 @@ func (m *Messenger) AcceptedRequestsToJoinForCommunity(id types.HexBytes) ([]*co
|
||||
return m.communitiesManager.AcceptedRequestsToJoinForCommunity(id)
|
||||
}
|
||||
|
||||
func (m *Messenger) AcceptedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) {
|
||||
return m.communitiesManager.AcceptedPendingRequestsToJoinForCommunity(id)
|
||||
}
|
||||
|
||||
func (m *Messenger) DeclinedPendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) {
|
||||
return m.communitiesManager.DeclinedPendingRequestsToJoinForCommunity(id)
|
||||
}
|
||||
|
||||
func (m *Messenger) RemoveUserFromCommunity(id types.HexBytes, pkString string) (*MessengerResponse, error) {
|
||||
publicKey, err := common.HexToPubkey(pkString)
|
||||
if err != nil {
|
||||
|
@ -1384,13 +1384,15 @@ func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, si
|
||||
return err
|
||||
}
|
||||
|
||||
if requestToJoin.State == communities.RequestToJoinStateAccepted {
|
||||
if requestToJoin.State == communities.RequestToJoinStateAccepted || requestToJoin.State == communities.RequestToJoinStateAcceptedPending {
|
||||
accept := &requests.AcceptRequestToJoinCommunity{
|
||||
ID: requestToJoin.ID,
|
||||
}
|
||||
_, err = m.AcceptRequestToJoinCommunity(accept)
|
||||
if err != nil {
|
||||
if err == communities.ErrNoPermissionToJoin {
|
||||
// only control node will end up here as it's the only one that
|
||||
// performed token permission checks
|
||||
requestToJoin.State = communities.RequestToJoinStateDeclined
|
||||
} else {
|
||||
return err
|
||||
@ -1398,7 +1400,9 @@ func (m *Messenger) HandleCommunityRequestToJoin(state *ReceivedMessageState, si
|
||||
}
|
||||
}
|
||||
|
||||
if requestToJoin.State == communities.RequestToJoinStateDeclined {
|
||||
declinedOrDeclinedPending := requestToJoin.State == communities.RequestToJoinStateDeclined || requestToJoin.State == communities.RequestToJoinStateDeclinedPending
|
||||
|
||||
if declinedOrDeclinedPending {
|
||||
cancel := &requests.DeclineRequestToJoinCommunity{
|
||||
ID: requestToJoin.ID,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user