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 }