module.itop-profiles-itil.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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. SetupWebPage::AddModule(
  17. __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
  18. 'itop-profiles-itil/1.0.0',
  19. array(
  20. // Identification
  21. //
  22. 'label' => 'Create standard ITIL profiles',
  23. 'category' => 'create_profiles',
  24. // Setup
  25. //
  26. 'dependencies' => array(
  27. ),
  28. 'mandatory' => true,
  29. 'visible' => false,
  30. 'installer' => 'CreateITILProfilesInstaller',
  31. // Components
  32. //
  33. 'datamodel' => array(
  34. //'model.itop-profiles-itil.php',
  35. ),
  36. 'webservice' => array(
  37. //'webservices.itop-profiles-itil.php',
  38. ),
  39. 'dictionary' => array(
  40. //'en.dict.itop-profiles-itil.php',
  41. //'fr.dict.itop-profiles-itil.php',
  42. //'de.dict.itop-profiles-itil.php',
  43. ),
  44. 'data.struct' => array(
  45. //'data.struct.itop-profiles-itil.xml',
  46. ),
  47. 'data.sample' => array(
  48. //'data.sample.itop-profiles-itil.xml',
  49. ),
  50. // Documentation
  51. //
  52. 'doc.manual_setup' => '',
  53. 'doc.more_information' => '',
  54. // Default settings
  55. //
  56. 'settings' => array(
  57. //'some_setting' => 'some value',
  58. ),
  59. )
  60. );
  61. // Module installation handler
  62. //
  63. class CreateITILProfilesInstaller extends ModuleInstallerAPI
  64. {
  65. public static function BeforeWritingConfig(Config $oConfiguration)
  66. {
  67. //$oConfiguration->SetModuleSetting('user-rigths-profile', 'myoption', 'myvalue');
  68. return $oConfiguration;
  69. }
  70. public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
  71. {
  72. self::ComputeITILProfiles();
  73. //self::ComputeBasicProfiles();
  74. $bFirstInstall = empty($sPreviousVersion);
  75. self::DoCreateProfiles($bFirstInstall);
  76. UserRights::FlushPrivileges(true /* reset admin cache */);
  77. }
  78. protected static $m_aActions = array(
  79. UR_ACTION_READ => 'Read',
  80. UR_ACTION_MODIFY => 'Modify',
  81. UR_ACTION_DELETE => 'Delete',
  82. UR_ACTION_BULK_READ => 'Bulk Read',
  83. UR_ACTION_BULK_MODIFY => 'Bulk Modify',
  84. UR_ACTION_BULK_DELETE => 'Bulk Delete',
  85. );
  86. // Note: It is possible to specify the same class in several modules
  87. //
  88. protected static $m_aModules = array();
  89. protected static $m_aProfiles = array();
  90. protected static $m_aCacheActionGrants = null;
  91. protected static $m_aCacheStimulusGrants = null;
  92. protected static $m_aCacheProfiles = null;
  93. protected static function DoCreateActionGrant($iProfile, $iAction, $sClass, $bPermission = true)
  94. {
  95. $sAction = self::$m_aActions[$iAction];
  96. if (is_null(self::$m_aCacheActionGrants))
  97. {
  98. self::$m_aCacheActionGrants = array();
  99. $oFilterAll = new DBObjectSearch('URP_ActionGrant');
  100. $oSet = new DBObjectSet($oFilterAll);
  101. while ($oGrant = $oSet->Fetch())
  102. {
  103. self::$m_aCacheActionGrants[$oGrant->Get('profileid').'-'.$oGrant->Get('action').'-'.$oGrant->Get('class')] = $oGrant->GetKey();
  104. }
  105. }
  106. $sCacheKey = "$iProfile-$sAction-$sClass";
  107. if (isset(self::$m_aCacheActionGrants[$sCacheKey]))
  108. {
  109. return self::$m_aCacheActionGrants[$sCacheKey];
  110. }
  111. $oNewObj = MetaModel::NewObject("URP_ActionGrant");
  112. $oNewObj->Set('profileid', $iProfile);
  113. $oNewObj->Set('permission', $bPermission ? 'yes' : 'no');
  114. $oNewObj->Set('class', $sClass);
  115. $oNewObj->Set('action', $sAction);
  116. $iId = $oNewObj->DBInsertNoReload();
  117. self::$m_aCacheActionGrants[$sCacheKey] = $iId;
  118. return $iId;
  119. }
  120. protected static function DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass)
  121. {
  122. if (is_null(self::$m_aCacheStimulusGrants))
  123. {
  124. self::$m_aCacheStimulusGrants = array();
  125. $oFilterAll = new DBObjectSearch('URP_StimulusGrant');
  126. $oSet = new DBObjectSet($oFilterAll);
  127. while ($oGrant = $oSet->Fetch())
  128. {
  129. self::$m_aCacheStimulusGrants[$oGrant->Get('profileid').'-'.$oGrant->Get('stimulus').'-'.$oGrant->Get('class')] = $oGrant->GetKey();
  130. }
  131. }
  132. $sCacheKey = "$iProfile-$sStimulusCode-$sClass";
  133. if (isset(self::$m_aCacheStimulusGrants[$sCacheKey]))
  134. {
  135. return self::$m_aCacheStimulusGrants[$sCacheKey];
  136. }
  137. $oNewObj = MetaModel::NewObject("URP_StimulusGrant");
  138. $oNewObj->Set('profileid', $iProfile);
  139. $oNewObj->Set('permission', 'yes');
  140. $oNewObj->Set('class', $sClass);
  141. $oNewObj->Set('stimulus', $sStimulusCode);
  142. $iId = $oNewObj->DBInsertNoReload();
  143. self::$m_aCacheStimulusGrants[$sCacheKey] = $iId;
  144. return $iId;
  145. }
  146. protected static function DoCreateProfile($sName, $sDescription)
  147. {
  148. if (is_null(self::$m_aCacheProfiles))
  149. {
  150. self::$m_aCacheProfiles = array();
  151. $oFilterAll = new DBObjectSearch('URP_Profiles');
  152. $oSet = new DBObjectSet($oFilterAll);
  153. while ($oProfile = $oSet->Fetch())
  154. {
  155. self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
  156. }
  157. }
  158. $sCacheKey = $sName;
  159. if (isset(self::$m_aCacheProfiles[$sCacheKey]))
  160. {
  161. return self::$m_aCacheProfiles[$sCacheKey];
  162. }
  163. $oNewObj = MetaModel::NewObject("URP_Profiles");
  164. $oNewObj->Set('name', $sName);
  165. $oNewObj->Set('description', $sDescription);
  166. $iId = $oNewObj->DBInsertNoReload();
  167. self::$m_aCacheProfiles[$sCacheKey] = $iId;
  168. return $iId;
  169. }
  170. protected static function DoSetupProfile($sName, $aProfileData)
  171. {
  172. $sDescription = $aProfileData['description'];
  173. if (strlen(trim($aProfileData['write_modules'])) == 0)
  174. {
  175. $aWriteModules = array();
  176. }
  177. else
  178. {
  179. $aWriteModules = explode(',', trim($aProfileData['write_modules']));
  180. }
  181. if (strlen(trim($aProfileData['delete_modules'])) == 0)
  182. {
  183. $aDeleteModules = array();
  184. }
  185. else
  186. {
  187. $aDeleteModules = explode(',', trim($aProfileData['delete_modules']));
  188. }
  189. $aStimuli = $aProfileData['stimuli'];
  190. $iProfile = self::DoCreateProfile($sName, $sDescription);
  191. // Warning: BulkInsert is working because we will load one single class
  192. // having one single table !
  193. // the benefit is: 10 queries (1 per profile) instead of 1500
  194. // which divides the overall user rights setup process by 5
  195. DBObject::BulkInsertStart();
  196. // Grant read rights for everything
  197. //
  198. foreach (MetaModel::GetClasses('bizmodel') as $sClass)
  199. {
  200. self::DoCreateActionGrant($iProfile, UR_ACTION_READ, $sClass);
  201. self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_READ, $sClass);
  202. }
  203. // Grant write for given modules
  204. // Start by compiling the information, because some modules may overlap
  205. $aWriteableClasses = array();
  206. foreach ($aWriteModules as $sModule)
  207. {
  208. //$oPage->p('Granting write access for the module"'.$sModule.'" - '.count(self::$m_aModules[$sModule]).' classes');
  209. foreach (self::$m_aModules[$sModule] as $sClass)
  210. {
  211. $aWriteableClasses[$sClass] = true;
  212. }
  213. }
  214. foreach ($aWriteableClasses as $sClass => $foo)
  215. {
  216. if (!MetaModel::IsValidClass($sClass))
  217. {
  218. throw new CoreException("Invalid class name '$sClass'");
  219. }
  220. self::DoCreateActionGrant($iProfile, UR_ACTION_MODIFY, $sClass);
  221. self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_MODIFY, $sClass);
  222. }
  223. // Grant delete for given modules
  224. // Start by compiling the information, because some modules may overlap
  225. $aDeletableClasses = array();
  226. foreach ($aDeleteModules as $sModule)
  227. {
  228. //$oPage->p('Granting delete access for the module"'.$sModule.'" - '.count(self::$m_aModules[$sModule]).' classes');
  229. foreach (self::$m_aModules[$sModule] as $sClass)
  230. {
  231. $aDeletableClasses[$sClass] = true;
  232. }
  233. }
  234. foreach ($aDeletableClasses as $sClass => $foo)
  235. {
  236. if (!MetaModel::IsValidClass($sClass))
  237. {
  238. throw new CoreException("Invalid class name '$sClass'");
  239. }
  240. self::DoCreateActionGrant($iProfile, UR_ACTION_DELETE, $sClass);
  241. // By default, do not allow bulk deletion operations for standard users
  242. // self::DoCreateActionGrant($iProfile, UR_ACTION_BULK_DELETE, $sClass);
  243. }
  244. // Grant stimuli for given classes
  245. foreach ($aStimuli as $sClass => $sAllowedStimuli)
  246. {
  247. if (!MetaModel::IsValidClass($sClass))
  248. {
  249. // Could be a class defined in a module that wasn't installed
  250. continue;
  251. //throw new CoreException("Invalid class name '$sClass'");
  252. }
  253. if ($sAllowedStimuli == 'any')
  254. {
  255. $aAllowedStimuli = array_keys(MetaModel::EnumStimuli($sClass));
  256. }
  257. elseif ($sAllowedStimuli == 'none')
  258. {
  259. $aAllowedStimuli = array();
  260. }
  261. else
  262. {
  263. $aAllowedStimuli = explode(',', $sAllowedStimuli);
  264. }
  265. foreach ($aAllowedStimuli as $sStimulusCode)
  266. {
  267. self::DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass);
  268. }
  269. }
  270. // Again: this is working only because action/stimulus grant are classes made of a single table!
  271. DBObject::BulkInsertFlush();
  272. }
  273. public static function DoCreateProfiles($bFirstInstall = true)
  274. {
  275. if ($bFirstInstall)
  276. {
  277. // Make sure we create these special profiles only once
  278. URP_Profiles::DoCreateAdminProfile();
  279. URP_Profiles::DoCreateUserPortalProfile();
  280. }
  281. foreach(self::$m_aProfiles as $sName => $aProfileData)
  282. {
  283. self::DoSetupProfile($sName, $aProfileData);
  284. }
  285. }
  286. public static function ComputeBasicProfiles()
  287. {
  288. // In this profiling scheme, one single module represents all the classes
  289. //
  290. self::$m_aModules = array(
  291. 'UserData' => MetaModel::GetClasses('bizmodel'),
  292. );
  293. self::$m_aProfiles = array(
  294. 'Reader' => array(
  295. 'description' => 'Person having a ready-only access to the data',
  296. 'write_modules' => '',
  297. 'delete_modules' => '',
  298. 'stimuli' => array(
  299. ),
  300. ),
  301. 'Writer' => array(
  302. 'description' => 'Contributor to the contents (read + write access)',
  303. 'write_modules' => 'UserData',
  304. 'delete_modules' => 'UserData',
  305. 'stimuli' => array(
  306. // any class => 'any'
  307. ),
  308. ),
  309. );
  310. }
  311. public static function ComputeITILProfiles()
  312. {
  313. // In this profiling scheme, modules are based on ITIL recommendations
  314. //
  315. self::$m_aModules = array(
  316. 'General' => MetaModel::GetClasses('structure'),
  317. 'Documentation' => MetaModel::GetClasses('documentation'),
  318. 'Configuration' => MetaModel::GetClasses('configmgmt'),
  319. 'Incident' => MetaModel::GetClasses('incidentmgmt'),
  320. 'Problem' => MetaModel::GetClasses('problemmgmt'),
  321. 'Change' => MetaModel::GetClasses('changemgmt'),
  322. 'Service' => MetaModel::GetClasses('servicemgmt'),
  323. 'Call' => MetaModel::GetClasses('requestmgmt'),
  324. 'KnownError' => MetaModel::GetClasses('knownerrormgmt'),
  325. );
  326. self::$m_aProfiles = array(
  327. 'Configuration Manager' => array(
  328. 'description' => 'Person in charge of the documentation of the managed CIs',
  329. 'write_modules' => 'General,Documentation,Configuration',
  330. 'delete_modules' => 'General,Documentation,Configuration',
  331. 'stimuli' => array(
  332. //'Server' => 'none',
  333. //'Contract' => 'none',
  334. //'IncidentTicket' => 'none',
  335. //'ChangeTicket' => 'any',
  336. ),
  337. ),
  338. 'Service Desk Agent' => array(
  339. 'description' => 'Person in charge of creating incident reports',
  340. 'write_modules' => 'Incident,Call',
  341. 'delete_modules' => 'Incident,Call',
  342. 'stimuli' => array(
  343. 'Incident' => 'ev_assign',
  344. 'UserRequest' => 'ev_assign',
  345. ),
  346. ),
  347. 'Support Agent' => array(
  348. 'description' => 'Person analyzing and solving the current incidents',
  349. 'write_modules' => 'Incident',
  350. 'delete_modules' => 'Incident',
  351. 'stimuli' => array(
  352. 'Incident' => 'ev_assign,ev_reassign,ev_resolve,ev_close',
  353. 'UserRequest' => 'ev_assign,ev_reassign,ev_resolve,ev_close,ev_freeze',
  354. ),
  355. ),
  356. 'Problem Manager' => array(
  357. 'description' => 'Person analyzing and solving the current problems',
  358. 'write_modules' => 'Problem,KnownError',
  359. 'delete_modules' => 'Problem,KnownError',
  360. 'stimuli' => array(
  361. 'Problem' => 'ev_assign,ev_reassign,ev_resolve,ev_close',
  362. ),
  363. ),
  364. 'Change Implementor' => array(
  365. 'description' => 'Person executing the changes',
  366. 'write_modules' => 'Change',
  367. 'delete_modules' => 'Change',
  368. 'stimuli' => array(
  369. 'NormalChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
  370. 'EmergencyChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
  371. 'RoutineChange' => 'ev_plan,ev_replan,ev_implement,ev_monitor',
  372. ),
  373. ),
  374. 'Change Supervisor' => array(
  375. 'description' => 'Person responsible for the overall change execution',
  376. 'write_modules' => 'Change',
  377. 'delete_modules' => 'Change',
  378. 'stimuli' => array(
  379. 'NormalChange' => 'ev_validate,ev_reject,ev_assign,ev_reopen,ev_finish',
  380. 'EmergencyChange' => 'ev_assign,ev_reopen,ev_finish',
  381. 'RoutineChange' => 'ev_assign,ev_reopen,ev_finish',
  382. ),
  383. ),
  384. 'Change Approver' => array(
  385. 'description' => 'Person who could be impacted by some changes',
  386. 'write_modules' => 'Change',
  387. 'delete_modules' => 'Change',
  388. 'stimuli' => array(
  389. 'NormalChange' => 'ev_approve,ev_notapprove',
  390. 'EmergencyChange' => 'ev_approve,ev_notapprove',
  391. 'RoutineChange' => 'none',
  392. ),
  393. ),
  394. 'Service Manager' => array(
  395. 'description' => 'Person responsible for the service delivered to the [internal] customer',
  396. 'write_modules' => 'Service',
  397. 'delete_modules' => 'Service',
  398. 'stimuli' => array(
  399. ),
  400. ),
  401. 'Document author' => array(
  402. 'description' => 'Any person who could contribute to documentation',
  403. 'write_modules' => 'Documentation',
  404. 'delete_modules' => 'Documentation',
  405. 'stimuli' => array(
  406. ),
  407. ),
  408. );
  409. }
  410. }
  411. ?>