userrightsprofile.class.inc.php 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. <?php
  2. // Copyright (C) 2010 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. /**
  17. * UserRightsProfile
  18. * User management Module, basing the right on profiles and a matrix (similar to UserRightsMatrix, but profiles and other decorations have been added)
  19. *
  20. * @author Erwan Taloc <erwan.taloc@combodo.com>
  21. * @author Romain Quetiez <romain.quetiez@combodo.com>
  22. * @author Denis Flaven <denis.flaven@combodo.com>
  23. * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
  24. */
  25. define('ADMIN_PROFILE_NAME', 'Administrator');
  26. define('PORTAL_PROFILE_NAME', 'Portal user');
  27. class UserRightsBaseClass extends cmdbAbstractObject
  28. {
  29. // Whenever something changes, reload the privileges
  30. protected function AfterInsert()
  31. {
  32. UserRights::FlushPrivileges();
  33. }
  34. protected function AfterUpdate()
  35. {
  36. UserRights::FlushPrivileges();
  37. }
  38. protected function AfterDelete()
  39. {
  40. UserRights::FlushPrivileges();
  41. }
  42. }
  43. class URP_Profiles extends UserRightsBaseClass
  44. {
  45. public static function Init()
  46. {
  47. $aParams = array
  48. (
  49. "category" => "addon/userrights",
  50. "key_type" => "autoincrement",
  51. "name_attcode" => "name",
  52. "state_attcode" => "",
  53. "reconc_keys" => array(),
  54. "db_table" => "priv_urp_profiles",
  55. "db_key_field" => "id",
  56. "db_finalclass_field" => "",
  57. "display_template" => "",
  58. );
  59. MetaModel::Init_Params($aParams);
  60. //MetaModel::Init_InheritAttributes();
  61. MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  62. MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  63. MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", array("linked_class"=>"URP_UserProfile", "ext_key_to_me"=>"profileid", "ext_key_to_remote"=>"userid", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
  64. // Display lists
  65. MetaModel::Init_SetZListItems('details', array('name', 'description', 'user_list')); // Attributes to be displayed for the complete details
  66. MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
  67. // Search criteria
  68. MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
  69. MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
  70. }
  71. protected $m_bCheckReservedNames = true;
  72. protected function DisableCheckOnReservedNames()
  73. {
  74. $this->m_bCheckReservedNames = false;
  75. }
  76. /*
  77. * Create the built-in Administrator profile with its reserved name
  78. */
  79. public static function DoCreateAdminProfile()
  80. {
  81. $oNewObj = MetaModel::NewObject("URP_Profiles");
  82. $oNewObj->Set('name', ADMIN_PROFILE_NAME);
  83. $oNewObj->Set('description', 'Has the rights on everything (bypassing any control)');
  84. $oNewObj->DisableCheckOnReservedNames();
  85. $iNewId = $oNewObj->DBInsertNoReload();
  86. }
  87. /*
  88. * Create the built-in User Portal profile with its reserved name
  89. */
  90. public static function DoCreateUserPortalProfile()
  91. {
  92. $oNewObj = MetaModel::NewObject("URP_Profiles");
  93. $oNewObj->Set('name', PORTAL_PROFILE_NAME);
  94. $oNewObj->Set('description', 'Has the rights to access to the user portal. People having this profile will not be allowed to access the standard application, they will be automatically redirected to the user portal.');
  95. $oNewObj->DisableCheckOnReservedNames();
  96. $iNewId = $oNewObj->DBInsertNoReload();
  97. }
  98. /*
  99. * Overload the standard behavior to preserve reserved names
  100. */
  101. public function DoCheckToWrite()
  102. {
  103. parent::DoCheckToWrite();
  104. if ($this->m_bCheckReservedNames)
  105. {
  106. $aChanges = $this->ListChanges();
  107. if (array_key_exists('name', $aChanges))
  108. {
  109. if ($this->GetOriginal('name') == ADMIN_PROFILE_NAME)
  110. {
  111. $this->m_aCheckIssues[] = "The name of the Administrator profile must not be changed";
  112. }
  113. elseif ($this->Get('name') == ADMIN_PROFILE_NAME)
  114. {
  115. $this->m_aCheckIssues[] = ADMIN_PROFILE_NAME." is a reserved to the built-in Administrator profile";
  116. }
  117. elseif ($this->GetOriginal('name') == PORTAL_PROFILE_NAME)
  118. {
  119. $this->m_aCheckIssues[] = "The name of the User Portal profile must not be changed";
  120. }
  121. elseif ($this->Get('name') == PORTAL_PROFILE_NAME)
  122. {
  123. $this->m_aCheckIssues[] = PORTAL_PROFILE_NAME." is a reserved to the built-in User Portal profile";
  124. }
  125. }
  126. }
  127. }
  128. function GetGrantAsHtml($oUserRights, $sClass, $sAction)
  129. {
  130. $iGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
  131. if (!is_null($iGrant))
  132. {
  133. return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
  134. }
  135. else
  136. {
  137. return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
  138. }
  139. }
  140. function DoShowGrantSumary($oPage)
  141. {
  142. if ($this->GetName() == "Administrator")
  143. {
  144. // Looks dirty, but ok that's THE ONE
  145. $oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
  146. return;
  147. }
  148. // Note: for sure, we assume that the instance is derived from UserRightsProfile
  149. $oUserRights = UserRights::GetModuleInstance();
  150. $aDisplayData = array();
  151. foreach (MetaModel::GetClasses('bizmodel') as $sClass)
  152. {
  153. // Skip non instantiable classes
  154. if (MetaModel::IsAbstract($sClass)) continue;
  155. $aStimuli = array();
  156. foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
  157. {
  158. $oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
  159. if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
  160. {
  161. $aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription()).'">'.htmlentities($oStimulus->GetLabel()).'</span>';
  162. }
  163. }
  164. $sStimuli = implode(', ', $aStimuli);
  165. $aDisplayData[] = array(
  166. 'class' => MetaModel::GetName($sClass),
  167. 'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Read'),
  168. 'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Read'),
  169. 'write' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Modify'),
  170. 'bulkwrite' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Modify'),
  171. 'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Delete'),
  172. 'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Delete'),
  173. 'stimuli' => $sStimuli,
  174. );
  175. }
  176. $aDisplayConfig = array();
  177. $aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
  178. $aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
  179. $aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
  180. $aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
  181. $aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
  182. $aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
  183. $aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
  184. $aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
  185. $oPage->table($aDisplayConfig, $aDisplayData);
  186. }
  187. function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
  188. {
  189. parent::DisplayBareRelations($oPage, $bEditMode);
  190. if (!$bEditMode)
  191. {
  192. $oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
  193. $this->DoShowGrantSumary($oPage);
  194. }
  195. }
  196. }
  197. class URP_UserProfile extends UserRightsBaseClass
  198. {
  199. public static function Init()
  200. {
  201. $aParams = array
  202. (
  203. "category" => "addon/userrights",
  204. "key_type" => "autoincrement",
  205. "name_attcode" => "userid",
  206. "state_attcode" => "",
  207. "reconc_keys" => array(),
  208. "db_table" => "priv_urp_userprofile",
  209. "db_key_field" => "id",
  210. "db_finalclass_field" => "",
  211. "display_template" => "",
  212. );
  213. MetaModel::Init_Params($aParams);
  214. //MetaModel::Init_InheritAttributes();
  215. MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  216. MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
  217. MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  218. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  219. MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  220. // Display lists
  221. MetaModel::Init_SetZListItems('details', array('userid', 'profileid', 'reason')); // Attributes to be displayed for the complete details
  222. MetaModel::Init_SetZListItems('list', array('userid', 'profileid', 'reason')); // Attributes to be displayed for a list
  223. // Search criteria
  224. MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
  225. MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
  226. }
  227. public function GetName()
  228. {
  229. return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
  230. }
  231. }
  232. class URP_UserOrg extends UserRightsBaseClass
  233. {
  234. public static function Init()
  235. {
  236. $aParams = array
  237. (
  238. "category" => "addon/userrights",
  239. "key_type" => "autoincrement",
  240. "name_attcode" => "userid",
  241. "state_attcode" => "",
  242. "reconc_keys" => array(),
  243. "db_table" => "priv_urp_userorg",
  244. "db_key_field" => "id",
  245. "db_finalclass_field" => "",
  246. "display_template" => "",
  247. );
  248. MetaModel::Init_Params($aParams);
  249. //MetaModel::Init_InheritAttributes();
  250. MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  251. MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
  252. MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", array("targetclass"=>"Organization", "jointype"=> "", "allowed_values"=>null, "sql"=>"allowed_org_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  253. MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", array("allowed_values"=>null, "extkey_attcode"=> 'allowed_org_id', "target_attcode"=>"name")));
  254. MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"reason", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  255. // Display lists
  256. MetaModel::Init_SetZListItems('details', array('userid', 'allowed_org_id', 'reason')); // Attributes to be displayed for the complete details
  257. MetaModel::Init_SetZListItems('list', array('allowed_org_id', 'reason')); // Attributes to be displayed for a list
  258. // Search criteria
  259. MetaModel::Init_SetZListItems('standard_search', array('userid', 'allowed_org_id')); // Criteria of the std search form
  260. MetaModel::Init_SetZListItems('advanced_search', array('userid', 'allowed_org_id')); // Criteria of the advanced search form
  261. }
  262. public function GetName()
  263. {
  264. return Dict::Format('UI:UserManagement:LinkBetween_User_And_Org', $this->Get('userlogin'), $this->Get('allowed_org_name'));
  265. }
  266. }
  267. class URP_ActionGrant extends UserRightsBaseClass
  268. {
  269. public static function Init()
  270. {
  271. $aParams = array
  272. (
  273. "category" => "addon/userrights",
  274. "key_type" => "autoincrement",
  275. "name_attcode" => "profileid",
  276. "state_attcode" => "",
  277. "reconc_keys" => array(),
  278. "db_table" => "priv_urp_grant_actions",
  279. "db_key_field" => "id",
  280. "db_finalclass_field" => "",
  281. "display_template" => "",
  282. );
  283. MetaModel::Init_Params($aParams);
  284. //MetaModel::Init_InheritAttributes();
  285. // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
  286. MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  287. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  288. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  289. MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
  290. MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  291. // Display lists
  292. MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'action')); // Attributes to be displayed for the complete details
  293. MetaModel::Init_SetZListItems('list', array('class', 'permission', 'action')); // Attributes to be displayed for a list
  294. // Search criteria
  295. MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the std search form
  296. MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the advanced search form
  297. }
  298. }
  299. class URP_StimulusGrant extends UserRightsBaseClass
  300. {
  301. public static function Init()
  302. {
  303. $aParams = array
  304. (
  305. "category" => "addon/userrights",
  306. "key_type" => "autoincrement",
  307. "name_attcode" => "profileid",
  308. "state_attcode" => "",
  309. "reconc_keys" => array(),
  310. "db_table" => "priv_urp_grant_stimulus",
  311. "db_key_field" => "id",
  312. "db_finalclass_field" => "",
  313. "display_template" => "",
  314. );
  315. MetaModel::Init_Params($aParams);
  316. //MetaModel::Init_InheritAttributes();
  317. // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
  318. MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  319. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  320. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  321. MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
  322. MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  323. // Display lists
  324. MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'stimulus')); // Attributes to be displayed for the complete details
  325. MetaModel::Init_SetZListItems('list', array('class', 'permission', 'stimulus')); // Attributes to be displayed for a list
  326. // Search criteria
  327. MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the std search form
  328. MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the advanced search form
  329. }
  330. }
  331. class URP_AttributeGrant extends UserRightsBaseClass
  332. {
  333. public static function Init()
  334. {
  335. $aParams = array
  336. (
  337. "category" => "addon/userrights",
  338. "key_type" => "autoincrement",
  339. "name_attcode" => "actiongrantid",
  340. "state_attcode" => "",
  341. "reconc_keys" => array(),
  342. "db_table" => "priv_urp_grant_attributes",
  343. "db_key_field" => "id",
  344. "db_finalclass_field" => "",
  345. "display_template" => "",
  346. );
  347. MetaModel::Init_Params($aParams);
  348. //MetaModel::Init_InheritAttributes();
  349. MetaModel::Init_AddAttribute(new AttributeExternalKey("actiongrantid", array("targetclass"=>"URP_ActionGrant", "jointype"=> "", "allowed_values"=>null, "sql"=>"actiongrantid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  350. MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  351. // Display lists
  352. MetaModel::Init_SetZListItems('details', array('actiongrantid', 'attcode')); // Attributes to be displayed for the complete details
  353. MetaModel::Init_SetZListItems('list', array('attcode')); // Attributes to be displayed for a list
  354. // Search criteria
  355. MetaModel::Init_SetZListItems('standard_search', array('actiongrantid', 'attcode')); // Criteria of the std search form
  356. MetaModel::Init_SetZListItems('advanced_search', array('actiongrantid', 'attcode')); // Criteria of the advanced search form
  357. }
  358. }
  359. class UserRightsProfile extends UserRightsAddOnAPI
  360. {
  361. static public $m_aActionCodes = array(
  362. UR_ACTION_READ => 'read',
  363. UR_ACTION_MODIFY => 'modify',
  364. UR_ACTION_DELETE => 'delete',
  365. UR_ACTION_BULK_READ => 'bulk read',
  366. UR_ACTION_BULK_MODIFY => 'bulk modify',
  367. UR_ACTION_BULK_DELETE => 'bulk delete',
  368. );
  369. // Installation: create the very first user
  370. public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
  371. {
  372. // Create a change to record the history of the User object
  373. $oChange = MetaModel::NewObject("CMDBChange");
  374. $oChange->Set("date", time());
  375. $oChange->Set("userinfo", "Initialization");
  376. $iChangeId = $oChange->DBInsert();
  377. $oOrg = new Organization();
  378. $oOrg->Set('name', 'My Company/Department');
  379. $oOrg->Set('code', 'SOMECODE');
  380. // $oOrg->Set('status', 'implementation');
  381. //$oOrg->Set('parent_id', xxx);
  382. $iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
  383. $oContact = new Person();
  384. $oContact->Set('name', 'My last name');
  385. $oContact->Set('first_name', 'My first name');
  386. //$oContact->Set('status', 'available');
  387. $oContact->Set('org_id', $iOrgId);
  388. $oContact->Set('email', 'my.email@foo.org');
  389. //$oContact->Set('phone', '');
  390. //$oContact->Set('location_id', $iLocationId);
  391. //$oContact->Set('employee_number', '');
  392. $iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
  393. $oUser = new UserLocal();
  394. $oUser->Set('login', $sAdminUser);
  395. $oUser->Set('password', $sAdminPwd);
  396. $oUser->Set('contactid', $iContactId);
  397. $oUser->Set('language', $sLanguage); // Language was chosen during the installation
  398. // Add this user to the very specific 'admin' profile
  399. $oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
  400. if (is_object($oAdminProfile))
  401. {
  402. $oUserProfile = new URP_UserProfile();
  403. //$oUserProfile->Set('userid', $iUserId);
  404. $oUserProfile->Set('profileid', $oAdminProfile->GetKey());
  405. $oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
  406. //$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
  407. $oSet = DBObjectSet::FromObject($oUserProfile);
  408. $oUser->Set('profile_list', $oSet);
  409. }
  410. $iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
  411. return true;
  412. }
  413. public function Setup()
  414. {
  415. SetupProfiles::ComputeITILProfiles();
  416. //SetupProfiles::ComputeBasicProfiles();
  417. SetupProfiles::DoCreateProfiles();
  418. return true;
  419. }
  420. public function Init()
  421. {
  422. MetaModel::RegisterPlugin('userrights', 'ACbyProfile');
  423. }
  424. protected $m_aAdmins; // id of users being linked to the well-known admin profile
  425. protected $m_aPortalUsers; // id of users being linked to the well-known admin profile
  426. protected $m_aProfiles; // id -> object
  427. protected $m_aUserProfiles; // userid,profileid -> object
  428. protected $m_aUserOrgs; // userid,orgid -> object
  429. // Those arrays could be completed on demand (inheriting parent permissions)
  430. protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
  431. protected $m_aClassStimulusGrants = array(); // profile, class, stimulus -> permission
  432. // Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
  433. protected $m_aObjectActionGrants = array();
  434. public function ResetCache()
  435. {
  436. // Loaded by Load cache
  437. $this->m_aProfiles = null;
  438. $this->m_aUserProfiles = null;
  439. $this->m_aUserOrgs = null;
  440. $this->m_aAdmins = null;
  441. $this->m_aPortalUsers = null;
  442. // Loaded on demand (time consuming as compared to the others)
  443. $this->m_aClassActionGrants = null;
  444. $this->m_aClassStimulusGrants = null;
  445. $this->m_aObjectActionGrants = array();
  446. }
  447. // Separate load: this cache is much more time consuming while loading
  448. // Thus it is loaded iif required
  449. // Could be improved by specifying the profile id
  450. public function LoadActionGrantCache()
  451. {
  452. if (!is_null($this->m_aClassActionGrants)) return;
  453. $oKPI = new ExecutionKPI();
  454. $oFilter = DBObjectSearch::FromOQL_AllData("SELECT URP_ActionGrant AS p WHERE p.permission = 'yes'");
  455. $aGrants = $oFilter->ToDataArray();
  456. foreach($aGrants as $aGrant)
  457. {
  458. $this->m_aClassActionGrants[$aGrant['profileid']][$aGrant['class']][strtolower($aGrant['action'])] = $aGrant['id'];
  459. }
  460. $oKPI->ComputeAndReport('Load of action grants');
  461. }
  462. public function LoadCache()
  463. {
  464. if (!is_null($this->m_aProfiles)) return;
  465. // Could be loaded in a shared memory (?)
  466. $oKPI = new ExecutionKPI();
  467. $oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Profiles"));
  468. $this->m_aProfiles = array();
  469. while ($oProfile = $oProfileSet->Fetch())
  470. {
  471. $this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
  472. }
  473. $oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserProfile"));
  474. $this->m_aUserProfiles = array();
  475. $this->m_aAdmins = array();
  476. $this->m_aPortalUsers = array();
  477. while ($oUserProfile = $oUserProfileSet->Fetch())
  478. {
  479. $this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile;
  480. if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
  481. {
  482. $this->m_aAdmins[] = $oUserProfile->Get('userid');
  483. }
  484. elseif ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
  485. {
  486. $this->m_aPortalUsers[] = $oUserProfile->Get('userid');
  487. }
  488. }
  489. $oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
  490. $this->m_aUserOrgs = array();
  491. while ($oUserOrg = $oUserOrgSet->Fetch())
  492. {
  493. $this->m_aUserOrgs[$oUserOrg->Get('userid')][$oUserOrg->Get('allowed_org_id')] = $oUserOrg;
  494. }
  495. $this->m_aClassStimulusGrants = array();
  496. $oStimGrantSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant"));
  497. $this->m_aStimGrants = array();
  498. while ($oStimGrant = $oStimGrantSet->Fetch())
  499. {
  500. $this->m_aClassStimulusGrants[$oStimGrant->Get('profileid')][$oStimGrant->Get('class')][$oStimGrant->Get('stimulus')] = $oStimGrant;
  501. }
  502. $oKPI->ComputeAndReport('Load of user management cache (excepted Action Grants)');
  503. /*
  504. echo "<pre>\n";
  505. print_r($this->m_aProfiles);
  506. print_r($this->m_aUserProfiles);
  507. print_r($this->m_aUserOrgs);
  508. print_r($this->m_aClassActionGrants);
  509. print_r($this->m_aClassStimulusGrants);
  510. echo "</pre>\n";
  511. exit;
  512. */
  513. return true;
  514. }
  515. public function IsAdministrator($oUser)
  516. {
  517. $this->LoadCache();
  518. if (in_array($oUser->GetKey(), $this->m_aAdmins))
  519. {
  520. return true;
  521. }
  522. else
  523. {
  524. return false;
  525. }
  526. }
  527. public function IsPortalUser($oUser)
  528. {
  529. $this->LoadCache();
  530. if (in_array($oUser->GetKey(), $this->m_aPortalUsers))
  531. {
  532. return true;
  533. }
  534. else
  535. {
  536. return false;
  537. }
  538. }
  539. public function GetSelectFilter($oUser, $sClass)
  540. {
  541. $this->LoadCache();
  542. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
  543. if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
  544. {
  545. return false;
  546. }
  547. // Determine how to position the objects of this class
  548. //
  549. if ($sClass == 'Organization')
  550. {
  551. $sAttCode = 'id';
  552. }
  553. elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
  554. {
  555. $sAttCode = 'org_id';
  556. }
  557. else
  558. {
  559. // The objects of this class are not positioned in this dimension
  560. // All of them are visible
  561. return true;
  562. }
  563. $oExpression = new FieldExpression($sAttCode, $sClass);
  564. // Position the user
  565. //
  566. @$aUserOrgs = $this->m_aUserOrgs[$oUser->GetKey()];
  567. if (!isset($aUserOrgs) || count($aUserOrgs) == 0)
  568. {
  569. // No position means 'Everywhere'
  570. return true;
  571. }
  572. $aIds = array_keys($aUserOrgs);
  573. $oListExpr = ListExpression::FromScalars($aIds);
  574. $oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
  575. $oFilter = new DBObjectSearch($sClass);
  576. $oFilter->AddConditionExpression($oCondition);
  577. return $oFilter;
  578. }
  579. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  580. public function GetProfileActionGrant($iProfile, $sClass, $sAction)
  581. {
  582. $this->LoadActionGrantCache();
  583. // Note: action is forced lowercase to be more flexible (historical bug)
  584. $sAction = strtolower($sAction);
  585. if (isset($this->m_aClassActionGrants[$iProfile][$sClass][$sAction]))
  586. {
  587. return $this->m_aClassActionGrants[$iProfile][$sClass][$sAction];
  588. }
  589. // Recursively look for the grant record in the class hierarchy
  590. $sParentClass = MetaModel::GetParentPersistentClass($sClass);
  591. if (empty($sParentClass))
  592. {
  593. $iGrant = null;
  594. }
  595. else
  596. {
  597. // Recursively look for the grant record in the class hierarchy
  598. $iGrant = $this->GetProfileActionGrant($iProfile, $sParentClass, $sAction);
  599. }
  600. $this->m_aClassActionGrants[$iProfile][$sClass][$sAction] = $iGrant;
  601. return $iGrant;
  602. }
  603. protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
  604. {
  605. $this->LoadCache();
  606. // load and cache permissions for the current user on the given class
  607. //
  608. $iUser = $oUser->GetKey();
  609. $aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
  610. if (is_array($aTest)) return $aTest;
  611. $sAction = self::$m_aActionCodes[$iActionCode];
  612. $iPermission = UR_ALLOWED_NO;
  613. $aAttributes = array();
  614. if (isset($this->m_aUserProfiles[$iUser]))
  615. {
  616. foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  617. {
  618. $iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
  619. if (is_null($iGrant) || !$iGrant)
  620. {
  621. continue; // loop to the next profile
  622. }
  623. else
  624. {
  625. $iPermission = UR_ALLOWED_YES;
  626. // update the list of attributes with those allowed for this profile
  627. //
  628. $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
  629. $oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $iGrant));
  630. $aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
  631. if (count($aProfileAttributes) == 0)
  632. {
  633. $aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
  634. $aAttributes = array_merge($aAttributes, $aAllAttributes);
  635. }
  636. else
  637. {
  638. $aAttributes = array_merge($aAttributes, $aProfileAttributes);
  639. }
  640. }
  641. }
  642. }
  643. $aRes = array(
  644. 'permission' => $iPermission,
  645. 'attributes' => $aAttributes,
  646. );
  647. $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
  648. return $aRes;
  649. }
  650. public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
  651. {
  652. $this->LoadCache();
  653. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  654. // and acceptable to consider only the root class of the object set
  655. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
  656. return $aObjectPermissions['permission'];
  657. }
  658. public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
  659. {
  660. $this->LoadCache();
  661. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  662. // and acceptable to consider only the root class of the object set
  663. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
  664. $aAttributes = $aObjectPermissions['attributes'];
  665. if (in_array($sAttCode, $aAttributes))
  666. {
  667. return $aObjectPermissions['permission'];
  668. }
  669. else
  670. {
  671. return UR_ALLOWED_NO;
  672. }
  673. }
  674. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  675. public function GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode)
  676. {
  677. $this->LoadCache();
  678. if (isset($this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode]))
  679. {
  680. return $this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode];
  681. }
  682. else
  683. {
  684. return null;
  685. }
  686. }
  687. public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
  688. {
  689. $this->LoadCache();
  690. // Note: this code is VERY close to the code of IsActionAllowed()
  691. $iUser = $oUser->GetKey();
  692. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  693. // and acceptable to consider only the root class of the object set
  694. $iPermission = UR_ALLOWED_NO;
  695. if (isset($this->m_aUserProfiles[$iUser]))
  696. {
  697. foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  698. {
  699. $oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
  700. if (!is_null($oGrantRecord))
  701. {
  702. // no need to fetch the record, we've requested the records having permission = 'yes'
  703. $iPermission = UR_ALLOWED_YES;
  704. }
  705. }
  706. }
  707. return $iPermission;
  708. }
  709. public function FlushPrivileges()
  710. {
  711. $this->ResetCache();
  712. }
  713. }
  714. //
  715. // Create simple profiles into our user management model:
  716. // - administrator
  717. // - readers
  718. // - contributors
  719. //
  720. class SetupProfiles
  721. {
  722. protected static $m_aActions = array(
  723. UR_ACTION_READ => 'Read',
  724. UR_ACTION_MODIFY => 'Modify',
  725. UR_ACTION_DELETE => 'Delete',
  726. UR_ACTION_BULK_READ => 'Bulk Read',
  727. UR_ACTION_BULK_MODIFY => 'Bulk Modify',
  728. UR_ACTION_BULK_DELETE => 'Bulk Delete',
  729. );
  730. // Note: It is possible to specify the same class in several modules
  731. //
  732. protected static $m_aModules = array();
  733. protected static $m_aProfiles = array();
  734. protected static function DoCreateActionGrant($iProfile, $iAction, $sClass, $bPermission = true)
  735. {
  736. $oNewObj = MetaModel::NewObject("URP_ActionGrant");
  737. $oNewObj->Set('profileid', $iProfile);
  738. $oNewObj->Set('permission', $bPermission ? 'yes' : 'no');
  739. $oNewObj->Set('class', $sClass);
  740. $oNewObj->Set('action', self::$m_aActions[$iAction]);
  741. $iId = $oNewObj->DBInsertNoReload();
  742. return $iId;
  743. }
  744. protected static function DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass)
  745. {
  746. $oNewObj = MetaModel::NewObject("URP_StimulusGrant");
  747. $oNewObj->Set('profileid', $iProfile);
  748. $oNewObj->Set('permission', 'yes');
  749. $oNewObj->Set('class', $sClass);
  750. $oNewObj->Set('stimulus', $sStimulusCode);
  751. $iId = $oNewObj->DBInsertNoReload();
  752. return $iId;
  753. }
  754. protected static function DoCreateOneProfile($sName, $aProfileData)
  755. {
  756. $sDescription = $aProfileData['description'];
  757. if (strlen(trim($aProfileData['write_modules'])) == 0)
  758. {
  759. $aWriteModules = array();
  760. }
  761. else
  762. {
  763. $aWriteModules = explode(',', trim($aProfileData['write_modules']));
  764. }
  765. $aStimuli = $aProfileData['stimuli'];
  766. $oNewObj = MetaModel::NewObject("URP_Profiles");
  767. $oNewObj->Set('name', $sName);
  768. $oNewObj->Set('description', $sDescription);
  769. $iProfile = $oNewObj->DBInsertNoReload();
  770. // Grant read rights for everything
  771. //
  772. foreach (MetaModel::GetClasses('bizmodel') as $sClass)
  773. {
  774. self::DoCreateActionGrant($iProfile, UR_ACTION_READ, $sClass);
  775. self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_READ, $sClass);
  776. }
  777. // Grant write for given modules
  778. // Start by compiling the information, because some modules may overlap
  779. $aWriteableClasses = array();
  780. foreach ($aWriteModules as $sModule)
  781. {
  782. //$oPage->p('Granting write access for the module"'.$sModule.'" - '.count(self::$m_aModules[$sModule]).' classes');
  783. foreach (self::$m_aModules[$sModule] as $sClass)
  784. {
  785. $aWriteableClasses[$sClass] = true;
  786. }
  787. }
  788. foreach ($aWriteableClasses as $sClass => $foo)
  789. {
  790. if (!MetaModel::IsValidClass($sClass))
  791. {
  792. throw new CoreException("Invalid class name '$sClass'");
  793. }
  794. self::DoCreateActionGrant($iProfile, UR_ACTION_MODIFY, $sClass);
  795. self::DoCreateActionGrant($iProfile, UR_ACTION_DELETE, $sClass);
  796. self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_MODIFY, $sClass);
  797. // By default, do not allow bulk deletion operations for standard users
  798. // self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_DELETE, $sClass);
  799. }
  800. // Grant stimuli for given classes
  801. foreach ($aStimuli as $sClass => $sAllowedStimuli)
  802. {
  803. if (!MetaModel::IsValidClass($sClass))
  804. {
  805. // Could be a class defined in a module that wasn't installed
  806. continue;
  807. //throw new CoreException("Invalid class name '$sClass'");
  808. }
  809. if ($sAllowedStimuli == 'any')
  810. {
  811. $aAllowedStimuli = array_keys(MetaModel::EnumStimuli($sClass));
  812. }
  813. elseif ($sAllowedStimuli == 'none')
  814. {
  815. $aAllowedStimuli = array();
  816. }
  817. else
  818. {
  819. $aAllowedStimuli = explode(',', $sAllowedStimuli);
  820. }
  821. foreach ($aAllowedStimuli as $sStimulusCode)
  822. {
  823. self::DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass);
  824. }
  825. }
  826. }
  827. public static function DoCreateProfiles()
  828. {
  829. URP_Profiles::DoCreateAdminProfile();
  830. URP_Profiles::DoCreateUserPortalProfile();
  831. foreach(self::$m_aProfiles as $sName => $aProfileData)
  832. {
  833. self::DoCreateOneProfile($sName, $aProfileData);
  834. }
  835. }
  836. public static function ComputeBasicProfiles()
  837. {
  838. // In this profiling scheme, one single module represents all the classes
  839. //
  840. self::$m_aModules = array(
  841. 'UserData' => MetaModel::GetClasses('bizmodel'),
  842. );
  843. self::$m_aProfiles = array(
  844. 'Reader' => array(
  845. 'description' => 'Person having a ready-only access to the data',
  846. 'write_modules' => '',
  847. 'stimuli' => array(
  848. ),
  849. ),
  850. 'Writer' => array(
  851. 'description' => 'Contributor to the contents (read + write access)',
  852. 'write_modules' => 'UserData',
  853. 'stimuli' => array(
  854. // any class => 'any'
  855. ),
  856. ),
  857. );
  858. }
  859. public static function ComputeITILProfiles()
  860. {
  861. // In this profiling scheme, modules are based on ITIL recommendations
  862. //
  863. self::$m_aModules = array(
  864. /*
  865. 'WriteModule' => array(
  866. 'someclass',
  867. 'anotherclass',
  868. ),
  869. */
  870. 'General' => MetaModel::GetClasses('structure'),
  871. 'Documentation' => MetaModel::GetClasses('documentation'),
  872. 'Configuration' => MetaModel::GetClasses('configmgmt'),
  873. 'Incident' => MetaModel::GetClasses('incidentmgmt'),
  874. 'Problem' => MetaModel::GetClasses('problemmgmt'),
  875. 'Change' => MetaModel::GetClasses('changemgmt'),
  876. 'Service' => MetaModel::GetClasses('servicemgmt'),
  877. 'Call' => MetaModel::GetClasses('requestmgmt'),
  878. 'KnownError' => MetaModel::GetClasses('knownerrormgmt'),
  879. );
  880. self::$m_aProfiles = array(
  881. 'Configuration Manager' => array(
  882. 'description' => 'Person in charge of the documentation of the managed CIs',
  883. 'write_modules' => 'General,Documentation,Configuration',
  884. 'stimuli' => array(
  885. //'bizServer' => 'none',
  886. //'bizContract' => 'none',
  887. //'bizIncidentTicket' => 'none',
  888. //'bizChangeTicket' => 'any',
  889. ),
  890. ),
  891. 'Service Desk Agent' => array(
  892. 'description' => 'Person in charge of creating incident reports',
  893. 'write_modules' => 'Incident,Call',
  894. 'stimuli' => array(
  895. 'Incident' => 'ev_assign',
  896. 'UserRequest' => 'ev_assign',
  897. ),
  898. ),
  899. 'Support Agent' => array(
  900. 'description' => 'Person analyzing and solving the current incidents',
  901. 'write_modules' => 'Incident',
  902. 'stimuli' => array(
  903. 'Incident' => 'ev_assign,ev_reassign,ev_resolve,ev_close',
  904. 'UserRequest' => 'ev_assign,ev_reassign,ev_resolve,ev_close,ev_freeze',
  905. ),
  906. ),
  907. 'Problem Manager' => array(
  908. 'description' => 'Person analyzing and solving the current problems',
  909. 'write_modules' => 'Problem,KnownError',
  910. 'stimuli' => array(
  911. 'Problem' => 'ev_assign,ev_reassign,ev_resolve,ev_close',
  912. ),
  913. ),
  914. 'Change Implementor' => array(
  915. 'description' => 'Person executing the changes',
  916. 'write_modules' => 'Change',
  917. 'stimuli' => array(
  918. 'NormalChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
  919. 'EmergencyChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
  920. 'RoutineChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
  921. ),
  922. ),
  923. 'Change Supervisor' => array(
  924. 'description' => 'Person responsible for the overall change execution',
  925. 'write_modules' => 'Change',
  926. 'stimuli' => array(
  927. 'NormalChange' => 'ev_validate,ev_reject,ev_assign,ev_reopen,ev_finish',
  928. 'EmergencyChange' => 'ev_assign,ev_reopen,ev_finish',
  929. 'RoutineChange' => 'ev_assign,ev_reopen,ev_finish',
  930. ),
  931. ),
  932. 'Change Approver' => array(
  933. 'description' => 'Person who could be impacted by some changes',
  934. 'write_modules' => 'Change',
  935. 'stimuli' => array(
  936. 'NormalChange' => 'ev_approve,ev_notapprove',
  937. 'EmergencyChange' => 'ev_approve,ev_notapprove',
  938. 'RoutineChange' => 'none',
  939. ),
  940. ),
  941. 'Service Manager' => array(
  942. 'description' => 'Person responsible for the service delivered to the [internal] customer',
  943. 'write_modules' => 'Service',
  944. 'stimuli' => array(
  945. ),
  946. ),
  947. 'Document author' => array(
  948. 'description' => 'Any person who could contribute to documentation',
  949. 'write_modules' => 'Documentation',
  950. 'stimuli' => array(
  951. ),
  952. ),
  953. );
  954. }
  955. }
  956. UserRights::SelectModule('UserRightsProfile');
  957. ?>