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 }