github.com/status-im/status-go@v1.1.0/protocol/communities/check_permissions_response.go (about)

     1  package communities
     2  
     3  import (
     4  	"encoding/json"
     5  	"sort"
     6  
     7  	gethcommon "github.com/ethereum/go-ethereum/common"
     8  	"github.com/status-im/status-go/protocol/protobuf"
     9  )
    10  
    11  type CheckPermissionsResponse struct {
    12  	Satisfied            bool                                      `json:"satisfied"`
    13  	Permissions          map[string]*PermissionTokenCriteriaResult `json:"permissions"`
    14  	ValidCombinations    []*AccountChainIDsCombination             `json:"validCombinations"`
    15  	NetworksNotSupported bool                                      `json:"networksNotSupported"`
    16  }
    17  
    18  type CheckPermissionToJoinResponse = CheckPermissionsResponse
    19  
    20  type HighestRoleResponse struct {
    21  	Role      protobuf.CommunityTokenPermission_Type `json:"type"`
    22  	Satisfied bool                                   `json:"satisfied"`
    23  	Criteria  []*PermissionTokenCriteriaResult       `json:"criteria"`
    24  }
    25  
    26  var roleOrders = map[protobuf.CommunityTokenPermission_Type]int{
    27  	protobuf.CommunityTokenPermission_BECOME_MEMBER:             1,
    28  	protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL:          2,
    29  	protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL: 3,
    30  	protobuf.CommunityTokenPermission_BECOME_ADMIN:              4,
    31  	protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER:       5,
    32  	protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER:        6,
    33  }
    34  
    35  type ByRoleDesc []*HighestRoleResponse
    36  
    37  func (a ByRoleDesc) Len() int      { return len(a) }
    38  func (a ByRoleDesc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
    39  func (a ByRoleDesc) Less(i, j int) bool {
    40  	return roleOrders[a[i].Role] > roleOrders[a[j].Role]
    41  }
    42  
    43  type rolesAndHighestRole struct {
    44  	Roles       []*HighestRoleResponse
    45  	HighestRole *HighestRoleResponse
    46  }
    47  
    48  func calculateRolesAndHighestRole(permissions map[string]*PermissionTokenCriteriaResult) *rolesAndHighestRole {
    49  	item := &rolesAndHighestRole{}
    50  	byRoleMap := make(map[protobuf.CommunityTokenPermission_Type]*HighestRoleResponse)
    51  	for _, p := range permissions {
    52  		if roleOrders[p.Role] == 0 {
    53  			continue
    54  		}
    55  		if byRoleMap[p.Role] == nil {
    56  			byRoleMap[p.Role] = &HighestRoleResponse{
    57  				Role: p.Role,
    58  			}
    59  		}
    60  
    61  		satisfied := true
    62  		for _, tr := range p.TokenRequirements {
    63  			if !tr.Satisfied {
    64  				satisfied = false
    65  				break
    66  			}
    67  
    68  		}
    69  
    70  		if satisfied {
    71  			byRoleMap[p.Role].Satisfied = true
    72  			// we prepend
    73  			byRoleMap[p.Role].Criteria = append([]*PermissionTokenCriteriaResult{p}, byRoleMap[p.Role].Criteria...)
    74  		} else {
    75  			// we append then
    76  			byRoleMap[p.Role].Criteria = append(byRoleMap[p.Role].Criteria, p)
    77  		}
    78  	}
    79  	if byRoleMap[protobuf.CommunityTokenPermission_BECOME_MEMBER] == nil {
    80  		byRoleMap[protobuf.CommunityTokenPermission_BECOME_MEMBER] = &HighestRoleResponse{Satisfied: true, Role: protobuf.CommunityTokenPermission_BECOME_MEMBER}
    81  	}
    82  	for _, p := range byRoleMap {
    83  		item.Roles = append(item.Roles, p)
    84  	}
    85  
    86  	sort.Sort(ByRoleDesc(item.Roles))
    87  	for _, r := range item.Roles {
    88  		if r.Satisfied {
    89  			item.HighestRole = r
    90  			break
    91  		}
    92  
    93  	}
    94  	return item
    95  }
    96  
    97  func (c *CheckPermissionsResponse) MarshalJSON() ([]byte, error) {
    98  	type CheckPermissionsTypeAlias struct {
    99  		Satisfied            bool                                      `json:"satisfied"`
   100  		Permissions          map[string]*PermissionTokenCriteriaResult `json:"permissions"`
   101  		ValidCombinations    []*AccountChainIDsCombination             `json:"validCombinations"`
   102  		Roles                []*HighestRoleResponse                    `json:"roles"`
   103  		HighestRole          *HighestRoleResponse                      `json:"highestRole"`
   104  		NetworksNotSupported bool                                      `json:"networksNotSupported"`
   105  	}
   106  	c.calculateSatisfied()
   107  	item := &CheckPermissionsTypeAlias{
   108  		Satisfied:            c.Satisfied,
   109  		Permissions:          c.Permissions,
   110  		ValidCombinations:    c.ValidCombinations,
   111  		NetworksNotSupported: c.NetworksNotSupported,
   112  	}
   113  	rolesAndHighestRole := calculateRolesAndHighestRole(c.Permissions)
   114  
   115  	item.Roles = rolesAndHighestRole.Roles
   116  	item.HighestRole = rolesAndHighestRole.HighestRole
   117  	return json.Marshal(item)
   118  }
   119  
   120  type TokenRequirementResponse struct {
   121  	Satisfied     bool                    `json:"satisfied"`
   122  	TokenCriteria *protobuf.TokenCriteria `json:"criteria"`
   123  }
   124  
   125  type PermissionTokenCriteriaResult struct {
   126  	Role              protobuf.CommunityTokenPermission_Type `json:"roles"`
   127  	TokenRequirements []TokenRequirementResponse             `json:"tokenRequirement"`
   128  	Criteria          []bool                                 `json:"criteria"`
   129  	ID                string                                 `json:"id"`
   130  }
   131  
   132  type AccountChainIDsCombination struct {
   133  	Address  gethcommon.Address `json:"address"`
   134  	ChainIDs []uint64           `json:"chainIds"`
   135  }
   136  
   137  func (c *CheckPermissionsResponse) calculateSatisfied() {
   138  	if len(c.Permissions) == 0 {
   139  		c.Satisfied = true
   140  		return
   141  	}
   142  
   143  	c.Satisfied = false
   144  	for _, p := range c.Permissions {
   145  		satisfied := true
   146  		for _, criteria := range p.Criteria {
   147  			if !criteria {
   148  				satisfied = false
   149  				break
   150  			}
   151  		}
   152  		if satisfied {
   153  			c.Satisfied = true
   154  			return
   155  		}
   156  	}
   157  }