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