status-im/status-go

View on GitHub
protocol/communities/check_permissions_response.go

Summary

Maintainability
A
0 mins
Test Coverage
D
67%
package communities

import (
    "encoding/json"
    "sort"

    gethcommon "github.com/ethereum/go-ethereum/common"
    "github.com/status-im/status-go/protocol/protobuf"
)

type CheckPermissionsResponse struct {
    Satisfied            bool                                      `json:"satisfied"`
    Permissions          map[string]*PermissionTokenCriteriaResult `json:"permissions"`
    ValidCombinations    []*AccountChainIDsCombination             `json:"validCombinations"`
    NetworksNotSupported bool                                      `json:"networksNotSupported"`
}

type CheckPermissionToJoinResponse = CheckPermissionsResponse

type HighestRoleResponse struct {
    Role      protobuf.CommunityTokenPermission_Type `json:"type"`
    Satisfied bool                                   `json:"satisfied"`
    Criteria  []*PermissionTokenCriteriaResult       `json:"criteria"`
}

var roleOrders = map[protobuf.CommunityTokenPermission_Type]int{
    protobuf.CommunityTokenPermission_BECOME_MEMBER:             1,
    protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL:          2,
    protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL: 3,
    protobuf.CommunityTokenPermission_BECOME_ADMIN:              4,
    protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER:       5,
    protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER:        6,
}

type ByRoleDesc []*HighestRoleResponse

func (a ByRoleDesc) Len() int      { return len(a) }
func (a ByRoleDesc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRoleDesc) Less(i, j int) bool {
    return roleOrders[a[i].Role] > roleOrders[a[j].Role]
}

type rolesAndHighestRole struct {
    Roles       []*HighestRoleResponse
    HighestRole *HighestRoleResponse
}

func calculateRolesAndHighestRole(permissions map[string]*PermissionTokenCriteriaResult) *rolesAndHighestRole {
    item := &rolesAndHighestRole{}
    byRoleMap := make(map[protobuf.CommunityTokenPermission_Type]*HighestRoleResponse)
    for _, p := range permissions {
        if roleOrders[p.Role] == 0 {
            continue
        }
        if byRoleMap[p.Role] == nil {
            byRoleMap[p.Role] = &HighestRoleResponse{
                Role: p.Role,
            }
        }

        satisfied := true
        for _, tr := range p.TokenRequirements {
            if !tr.Satisfied {
                satisfied = false
                break
            }

        }

        if satisfied {
            byRoleMap[p.Role].Satisfied = true
            // we prepend
            byRoleMap[p.Role].Criteria = append([]*PermissionTokenCriteriaResult{p}, byRoleMap[p.Role].Criteria...)
        } else {
            // we append then
            byRoleMap[p.Role].Criteria = append(byRoleMap[p.Role].Criteria, p)
        }
    }
    if byRoleMap[protobuf.CommunityTokenPermission_BECOME_MEMBER] == nil {
        byRoleMap[protobuf.CommunityTokenPermission_BECOME_MEMBER] = &HighestRoleResponse{Satisfied: true, Role: protobuf.CommunityTokenPermission_BECOME_MEMBER}
    }
    for _, p := range byRoleMap {
        item.Roles = append(item.Roles, p)
    }

    sort.Sort(ByRoleDesc(item.Roles))
    for _, r := range item.Roles {
        if r.Satisfied {
            item.HighestRole = r
            break
        }

    }
    return item
}

func (c *CheckPermissionsResponse) MarshalJSON() ([]byte, error) {
    type CheckPermissionsTypeAlias struct {
        Satisfied            bool                                      `json:"satisfied"`
        Permissions          map[string]*PermissionTokenCriteriaResult `json:"permissions"`
        ValidCombinations    []*AccountChainIDsCombination             `json:"validCombinations"`
        Roles                []*HighestRoleResponse                    `json:"roles"`
        HighestRole          *HighestRoleResponse                      `json:"highestRole"`
        NetworksNotSupported bool                                      `json:"networksNotSupported"`
    }
    c.calculateSatisfied()
    item := &CheckPermissionsTypeAlias{
        Satisfied:            c.Satisfied,
        Permissions:          c.Permissions,
        ValidCombinations:    c.ValidCombinations,
        NetworksNotSupported: c.NetworksNotSupported,
    }
    rolesAndHighestRole := calculateRolesAndHighestRole(c.Permissions)

    item.Roles = rolesAndHighestRole.Roles
    item.HighestRole = rolesAndHighestRole.HighestRole
    return json.Marshal(item)
}

type TokenRequirementResponse struct {
    Satisfied     bool                    `json:"satisfied"`
    TokenCriteria *protobuf.TokenCriteria `json:"criteria"`
}

type PermissionTokenCriteriaResult struct {
    Role              protobuf.CommunityTokenPermission_Type `json:"roles"`
    TokenRequirements []TokenRequirementResponse             `json:"tokenRequirement"`
    Criteria          []bool                                 `json:"criteria"`
    ID                string                                 `json:"id"`
}

type AccountChainIDsCombination struct {
    Address  gethcommon.Address `json:"address"`
    ChainIDs []uint64           `json:"chainIds"`
}

func (c *CheckPermissionsResponse) calculateSatisfied() {
    if len(c.Permissions) == 0 {
        c.Satisfied = true
        return
    }

    c.Satisfied = false
    for _, p := range c.Permissions {
        satisfied := true
        for _, criteria := range p.Criteria {
            if !criteria {
                satisfied = false
                break
            }
        }
        if satisfied {
            c.Satisfied = true
            return
        }
    }
}