github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/permission/v1/contract/OrgManager.sol (about)

     1  pragma solidity ^0.5.3;
     2  
     3  import "./PermissionsUpgradable.sol";
     4  /** @title Organization manager contract
     5    * @notice This contract holds implementation logic for all org management
     6      functionality. This can be called only by the implementation
     7      contract only. there are few view functions exposed as public and
     8      can be called directly. these are invoked by quorum for populating
     9      permissions data in cache
    10    * @dev the status of the organization is denoted by a set of integer
    11      values. These are as below:
    12          0 - Not in list,
    13          1 - Org proposed for approval by network admins
    14          2 - Org in Approved status
    15          3 - Org proposed for suspension and pending approval by network admins
    16          4 - Org in Suspended,
    17       Once the node is blacklisted no further activity on the node is
    18       possible.
    19    */
    20  contract OrgManager {
    21      string private adminOrgId;
    22      PermissionsUpgradable private permUpgradable;
    23      // checks if first time network boot up has happened or not
    24      bool private networkBoot = false;
    25  
    26      // variables which control the breadth and depth of the sub org tree
    27      uint private DEPTH_LIMIT = 4;
    28      uint private BREADTH_LIMIT = 4;
    29      struct OrgDetails {
    30          string orgId;
    31          uint status;
    32          string parentId;
    33          string fullOrgId;
    34          string ultParent;
    35          uint pindex;
    36          uint level;
    37          uint [] subOrgIndexList;
    38      }
    39  
    40      OrgDetails [] private orgList;
    41      mapping(bytes32 => uint) private OrgIndex;
    42      uint private orgNum = 0;
    43  
    44      // events related to Master Org add
    45      event OrgApproved(string _orgId, string _porgId, string _ultParent,
    46          uint _level, uint _status);
    47      event OrgPendingApproval(string _orgId, string _porgId, string _ultParent,
    48          uint _level, uint _status);
    49      event OrgSuspended(string _orgId, string _porgId, string _ultParent,
    50          uint _level);
    51      event OrgSuspensionRevoked(string _orgId, string _porgId, string _ultParent,
    52          uint _level);
    53  
    54      /** @notice confirms that the caller is the address of implementation
    55          contract
    56      */
    57      modifier onlyImplementation{
    58          require(msg.sender == permUpgradable.getPermImpl(), "invalid caller");
    59          _;
    60      }
    61  
    62      /** @notice checks if the org id does not exists
    63        * @param _orgId - org id
    64        * @return true if org does not exist
    65        */
    66      modifier orgDoesNotExist(string memory _orgId) {
    67          require(checkOrgExists(_orgId) == false, "org exists");
    68          _;
    69      }
    70  
    71      /** @notice checks if the org id does exists
    72        * @param _orgId - org id
    73        * @return true if org exists
    74        */
    75      modifier orgExists(string memory _orgId) {
    76          require(checkOrgExists(_orgId) == true, "org does not exist");
    77          _;
    78      }
    79  
    80      /** @notice constructor. sets the permissions upgradable address
    81        */
    82      constructor (address _permUpgradable) public {
    83          permUpgradable = PermissionsUpgradable(_permUpgradable);
    84      }
    85  
    86      /** @notice called at the time of network initialization. sets the depth
    87          breadth for sub orgs creation. and creates the default network
    88          admin org as per config file
    89        */
    90      function setUpOrg(string calldata _orgId, uint256 _breadth, uint256 _depth) external
    91      onlyImplementation {
    92          _addNewOrg("", _orgId, 1, 2);
    93          DEPTH_LIMIT = _depth;
    94          BREADTH_LIMIT = _breadth;
    95      }
    96      /** @notice function for adding a new master org to the network
    97        * @param _orgId unique org id to be added
    98        * @dev org will be added if it does exist
    99        */
   100      function addOrg(string calldata _orgId) external
   101      onlyImplementation
   102      orgDoesNotExist(_orgId) {
   103          _addNewOrg("", _orgId, 1, 1);
   104      }
   105  
   106      /** @notice function for adding a new sub org under a parent org
   107        * @param _pOrgId unique org id to be added
   108        * @dev org will be added if it does exist
   109        */
   110      function addSubOrg(string calldata _pOrgId, string calldata _orgId) external
   111      onlyImplementation
   112      orgDoesNotExist(string(abi.encodePacked(_pOrgId, ".", _orgId))) {
   113          _addNewOrg(_pOrgId, _orgId, 2, 2);
   114      }
   115  
   116      /** @notice updates the status of a master org.
   117        * @param _orgId unique org id to be added
   118        * @param _action action being performed
   119        * @dev status cannot be updated for sub orgs.
   120          This function can be called for the following actions:
   121              1 - to suspend an org
   122              2 - to activate the org back
   123        */
   124      function updateOrg(string calldata _orgId, uint256 _action) external
   125      onlyImplementation
   126      orgExists(_orgId)
   127      returns (uint256){
   128          require((_action == 1 || _action == 2), "invalid action. operation not allowed");
   129          uint256 id = _getOrgIndex(_orgId);
   130          require(orgList[id].level == 1, "not a master org. operation not allowed");
   131  
   132          uint256 reqStatus;
   133          uint256 pendingOp;
   134          if (_action == 1) {
   135              reqStatus = 2;
   136              pendingOp = 2;
   137          }
   138          else if (_action == 2) {
   139              reqStatus = 4;
   140              pendingOp = 3;
   141          }
   142          require(checkOrgStatus(_orgId, reqStatus) == true,
   143              "org status does not allow the operation");
   144          if (_action == 1) {
   145              _suspendOrg(_orgId);
   146          }
   147          else {
   148              _revokeOrgSuspension(_orgId);
   149          }
   150          return pendingOp;
   151      }
   152  
   153      /** @notice function to approve org status change for master orgs
   154        * @param _orgId unique org id to be added
   155        * @param _action approval for action
   156        * @dev status cannot be updated for sub orgs.
   157          This function can be called for the following actions:
   158              1 - to suspend an org
   159              2 - to activate the org back
   160        */
   161      function approveOrgStatusUpdate(string calldata _orgId, uint256 _action) external
   162      onlyImplementation
   163      orgExists(_orgId) {
   164          if (_action == 1) {
   165              _approveOrgSuspension(_orgId);
   166          }
   167          else {
   168              _approveOrgRevokeSuspension(_orgId);
   169          }
   170      }
   171  
   172      /** @notice function to approve org status change for master orgs
   173        * @param _orgId unique org id to be added
   174        */
   175      function approveOrg(string calldata _orgId) external
   176      onlyImplementation {
   177          require(checkOrgStatus(_orgId, 1) == true, "nothing to approve");
   178          uint256 id = _getOrgIndex(_orgId);
   179          orgList[id].status = 2;
   180          emit OrgApproved(orgList[id].orgId, orgList[id].parentId,
   181              orgList[id].ultParent, orgList[id].level, 2);
   182      }
   183  
   184      /** @notice returns org info for a given org index
   185        * @param _orgIndex org index
   186        * @return org id
   187        * @return parent org id
   188        * @return ultimate parent id
   189        * @return level in the org tree
   190        * @return status
   191        */
   192      function getOrgInfo(uint256 _orgIndex) external view returns (string memory,
   193          string memory, string memory, uint256, uint256) {
   194          return (orgList[_orgIndex].orgId, orgList[_orgIndex].parentId,
   195          orgList[_orgIndex].ultParent, orgList[_orgIndex].level, orgList[_orgIndex].status);
   196      }
   197  
   198      /** @notice returns org info for a given org id
   199        * @param _orgId org id
   200        * @return org id
   201        * @return parent org id
   202        * @return ultimate parent id
   203        * @return level in the org tree
   204        * @return status
   205        */
   206      function getOrgDetails(string calldata _orgId) external view returns (string memory,
   207          string memory, string memory, uint256, uint256) {
   208          if (!checkOrgExists(_orgId)){
   209              return (_orgId, "", "", 0,0);
   210          }
   211          uint256 _orgIndex = _getOrgIndex(_orgId);
   212          return (orgList[_orgIndex].orgId, orgList[_orgIndex].parentId,
   213          orgList[_orgIndex].ultParent, orgList[_orgIndex].level, orgList[_orgIndex].status);
   214      }
   215  
   216      /** @notice returns the array of sub org indexes for the given org
   217        * @param _orgId org id
   218        * @return array of sub org indexes
   219        */
   220      function getSubOrgIndexes(string calldata _orgId) external view returns (uint[] memory) {
   221          require(checkOrgExists(_orgId) == true, "org does not exist");
   222          uint256 _orgIndex = _getOrgIndex(_orgId);
   223          return (orgList[_orgIndex].subOrgIndexList);
   224      }
   225      /** @notice returns the master org id for the given org or sub org
   226        * @param _orgId org id
   227        * @return master org id
   228        */
   229      function getUltimateParent(string calldata _orgId) external view
   230      onlyImplementation
   231      returns (string memory) {
   232          return orgList[_getOrgIndex(_orgId)].ultParent;
   233      }
   234  
   235      /** @notice returns the total number of orgs in the network
   236        * @return master org id
   237        */
   238      function getNumberOfOrgs() public view returns (uint256) {
   239          return orgList.length;
   240      }
   241  
   242      /** @notice confirms that org status is same as passed status
   243        * @param _orgId org id
   244        * @param _orgStatus org status
   245        * @return true or false
   246        */
   247      function checkOrgStatus(string memory _orgId, uint256 _orgStatus)
   248      public view returns (bool){
   249          if (OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0) {
   250              return false;
   251          }
   252          uint256 id = _getOrgIndex(_orgId);
   253          return ((OrgIndex[keccak256(abi.encodePacked(_orgId))] != 0)
   254          && orgList[id].status == _orgStatus);
   255      }
   256  
   257      /** @notice confirms if the org exists in the network
   258        * @param _orgId org id
   259        * @return true or false
   260        */
   261      function checkOrgExists(string memory _orgId) public view returns (bool) {
   262          return (!(OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0));
   263      }
   264  
   265      /** @notice updates the org status to suspended
   266        * @param _orgId org id
   267        */
   268      function _suspendOrg(string memory _orgId) internal {
   269          require(checkOrgStatus(_orgId, 2) == true,
   270              "org not in approved status. operation cannot be done");
   271          uint256 id = _getOrgIndex(_orgId);
   272          orgList[id].status = 3;
   273          emit OrgPendingApproval(orgList[id].orgId, orgList[id].parentId,
   274              orgList[id].ultParent, orgList[id].level, 3);
   275      }
   276  
   277      /** @notice revokes the suspension of an org
   278        * @param _orgId org id
   279        */
   280      function _revokeOrgSuspension(string memory _orgId) internal {
   281          require(checkOrgStatus(_orgId, 4) == true, "org not in suspended state");
   282          uint256 id = _getOrgIndex(_orgId);
   283          orgList[id].status = 5;
   284          emit OrgPendingApproval(orgList[id].orgId, orgList[id].parentId,
   285              orgList[id].ultParent, orgList[id].level, 5);
   286      }
   287  
   288      /** @notice approval function for org suspension activity
   289        * @param _orgId org id
   290        */
   291      function _approveOrgSuspension(string memory _orgId) internal {
   292          require(checkOrgStatus(_orgId, 3) == true, "nothing to approve");
   293          uint256 id = _getOrgIndex(_orgId);
   294          orgList[id].status = 4;
   295          emit OrgSuspended(orgList[id].orgId, orgList[id].parentId,
   296              orgList[id].ultParent, orgList[id].level);
   297      }
   298  
   299      /** @notice approval function for revoking org suspension
   300        * @param _orgId org id
   301        */
   302      function _approveOrgRevokeSuspension(string memory _orgId) internal {
   303          require(checkOrgStatus(_orgId, 5) == true, "nothing to approve");
   304          uint256 id = _getOrgIndex(_orgId);
   305          orgList[id].status = 2;
   306          emit OrgSuspensionRevoked(orgList[id].orgId, orgList[id].parentId,
   307              orgList[id].ultParent, orgList[id].level);
   308      }
   309  
   310      /** @notice function to add a new organization
   311        * @param _pOrgId parent org id
   312        * @param _orgId org id
   313        * @param _level level in org hierarchy
   314        * @param _status status of the org
   315        */
   316      function _addNewOrg(string memory _pOrgId, string memory _orgId,
   317          uint256 _level, uint _status) internal {
   318          bytes32 pid = "";
   319          bytes32 oid = "";
   320          uint256 parentIndex = 0;
   321  
   322          if (_level == 1) {//root
   323              oid = keccak256(abi.encodePacked(_orgId));
   324          } else {
   325              pid = keccak256(abi.encodePacked(_pOrgId));
   326              oid = keccak256(abi.encodePacked(_pOrgId, ".", _orgId));
   327          }
   328          orgNum++;
   329          OrgIndex[oid] = orgNum;
   330          uint256 id = orgList.length++;
   331          if (_level == 1) {
   332              orgList[id].level = _level;
   333              orgList[id].pindex = 0;
   334              orgList[id].fullOrgId = _orgId;
   335              orgList[id].ultParent = _orgId;
   336          } else {
   337              parentIndex = OrgIndex[pid] - 1;
   338  
   339              require(orgList[parentIndex].subOrgIndexList.length < BREADTH_LIMIT,
   340                  "breadth level exceeded");
   341              require(orgList[parentIndex].level < DEPTH_LIMIT,
   342                  "depth level exceeded");
   343  
   344              orgList[id].level = orgList[parentIndex].level + 1;
   345              orgList[id].pindex = parentIndex;
   346              orgList[id].ultParent = orgList[parentIndex].ultParent;
   347              uint256 subOrgId = orgList[parentIndex].subOrgIndexList.length++;
   348              orgList[parentIndex].subOrgIndexList[subOrgId] = id;
   349              orgList[id].fullOrgId = string(abi.encodePacked(_pOrgId, ".", _orgId));
   350          }
   351          orgList[id].orgId = _orgId;
   352          orgList[id].parentId = _pOrgId;
   353          orgList[id].status = _status;
   354          if (_status == 1) {
   355              emit OrgPendingApproval(orgList[id].orgId, orgList[id].parentId,
   356                  orgList[id].ultParent, orgList[id].level, 1);
   357          }
   358          else {
   359              emit OrgApproved(orgList[id].orgId, orgList[id].parentId,
   360                  orgList[id].ultParent, orgList[id].level, 2);
   361          }
   362      }
   363  
   364      /** @notice returns the org index from the org list for the given org
   365        * @return org index
   366        */
   367      function _getOrgIndex(string memory _orgId) private view returns (uint){
   368          return OrgIndex[keccak256(abi.encodePacked(_orgId))] - 1;
   369      }
   370  
   371  }