userrightsprojection.class.inc.php 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. <?php
  2. // Copyright (C) 2010-2012 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. /**
  19. * UserRightsProjection
  20. * User management Module, basing the right on profiles and a matrix (similar to UserRightsProfile, but enhanced with dimensions and projection of classes and profile over the dimensions)
  21. *
  22. * @copyright Copyright (C) 2010-2012 Combodo SARL
  23. * @license http://opensource.org/licenses/AGPL-3.0
  24. */
  25. define('ADMIN_PROFILE_ID', 1);
  26. class UserRightsBaseClass extends cmdbAbstractObject
  27. {
  28. // Whenever something changes, reload the privileges
  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. function GetGrantAsHtml($oUserRights, $sClass, $sAction)
  72. {
  73. $oGrant = $oUserRights->GetClassActionGrant($this->GetKey(), $sClass, $sAction);
  74. if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
  75. {
  76. return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
  77. }
  78. else
  79. {
  80. return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
  81. }
  82. }
  83. function DoShowGrantSumary($oPage)
  84. {
  85. if ($this->GetRawName() == "Administrator")
  86. {
  87. // Looks dirty, but ok that's THE ONE
  88. $oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
  89. return;
  90. }
  91. // Note: for sure, we assume that the instance is derived from UserRightsProjection
  92. $oUserRights = UserRights::GetModuleInstance();
  93. $aDisplayData = array();
  94. foreach (MetaModel::GetClasses('bizmodel') as $sClass)
  95. {
  96. // Skip non instantiable classes
  97. if (MetaModel::IsAbstract($sClass)) continue;
  98. $aStimuli = array();
  99. foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
  100. {
  101. $oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
  102. if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
  103. {
  104. $aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
  105. }
  106. }
  107. $sStimuli = implode(', ', $aStimuli);
  108. $aDisplayData[] = array(
  109. 'class' => MetaModel::GetName($sClass),
  110. 'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Read'),
  111. 'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Read'),
  112. 'write' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Modify'),
  113. 'bulkwrite' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Modify'),
  114. 'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Delete'),
  115. 'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Delete'),
  116. 'stimuli' => $sStimuli,
  117. );
  118. }
  119. $aDisplayConfig = array();
  120. $aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
  121. $aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
  122. $aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
  123. $aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
  124. $aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
  125. $aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
  126. $aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
  127. $aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
  128. $oPage->table($aDisplayConfig, $aDisplayData);
  129. }
  130. function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
  131. {
  132. parent::DisplayBareRelations($oPage, $bEditMode);
  133. if (!$bEditMode)
  134. {
  135. $oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
  136. $this->DoShowGrantSumary($oPage);
  137. }
  138. }
  139. }
  140. class URP_Dimensions extends UserRightsBaseClass
  141. {
  142. public static function Init()
  143. {
  144. $aParams = array
  145. (
  146. "category" => "addon/userrights",
  147. "key_type" => "autoincrement",
  148. "name_attcode" => "name",
  149. "state_attcode" => "",
  150. "reconc_keys" => array(),
  151. "db_table" => "priv_urp_dimensions",
  152. "db_key_field" => "id",
  153. "db_finalclass_field" => "",
  154. "display_template" => "",
  155. );
  156. MetaModel::Init_Params($aParams);
  157. //MetaModel::Init_InheritAttributes();
  158. MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  159. MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  160. MetaModel::Init_AddAttribute(new AttributeClass("type", array("class_category"=>"bizmodel", "more_values"=>"String,Integer", "sql"=>"type", "default_value"=>'String', "is_null_allowed"=>false, "depends_on"=>array())));
  161. // Display lists
  162. MetaModel::Init_SetZListItems('details', array('name', 'description', 'type')); // Attributes to be displayed for the complete details
  163. MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
  164. // Search criteria
  165. MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
  166. MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
  167. }
  168. public function CheckProjectionSpec($oProjectionSpec, $sProjectedClass)
  169. {
  170. $sExpression = $oProjectionSpec->Get('value');
  171. $sAttribute = $oProjectionSpec->Get('attribute');
  172. // Shortcut: "any value" or "no value" means no projection
  173. if (empty($sExpression)) return;
  174. if ($sExpression == '<any>') return;
  175. // 1st - compute the data type for the dimension
  176. //
  177. $sType = $this->Get('type');
  178. if (MetaModel::IsValidClass($sType))
  179. {
  180. $sExpectedType = $sType;
  181. }
  182. else
  183. {
  184. $sExpectedType = '_scalar_';
  185. }
  186. // 2nd - compute the data type for the projection
  187. //
  188. $sTargetClass = '';
  189. if (($sExpression == '<this>') || ($sExpression == '<user>'))
  190. {
  191. $sTargetClass = $sProjectedClass;
  192. }
  193. elseif ($sExpression == '<any>')
  194. {
  195. $sTargetClass = '';
  196. }
  197. else
  198. {
  199. // Evaluate wether it is a constant or not
  200. try
  201. {
  202. $oObjectSearch = DBObjectSearch::FromOQL_AllData($sExpression);
  203. $sTargetClass = $oObjectSearch->GetClass();
  204. }
  205. catch (OqlException $e)
  206. {
  207. }
  208. }
  209. if (empty($sTargetClass))
  210. {
  211. $sFoundType = '_void_';
  212. }
  213. else
  214. {
  215. if (empty($sAttribute))
  216. {
  217. $sFoundType = $sTargetClass;
  218. }
  219. else
  220. {
  221. if (!MetaModel::IsValidAttCode($sTargetClass, $sAttribute))
  222. {
  223. throw new CoreException('Unkown attribute code in projection specification', array('found' => $sAttribute, 'expecting' => MetaModel::GetAttributesList($sTargetClass), 'class' => $sTargetClass, 'projection' => $oProjectionSpec));
  224. }
  225. $oAttDef = MetaModel::GetAttributeDef($sTargetClass, $sAttribute);
  226. if ($oAttDef->IsExternalKey())
  227. {
  228. $sFoundType = $oAttDef->GetTargetClass();
  229. }
  230. else
  231. {
  232. $sFoundType = '_scalar_';
  233. }
  234. }
  235. }
  236. // Compare the dimension type and projection type
  237. if (($sFoundType != '_void_') && ($sFoundType != $sExpectedType))
  238. {
  239. throw new CoreException('Wrong type in projection specification', array('found' => $sFoundType, 'expecting' => $sExpectedType, 'expression' => $sExpression, 'attribute' => $sAttribute, 'projection' => $oProjectionSpec));
  240. }
  241. }
  242. }
  243. class URP_UserProfile extends UserRightsBaseClass
  244. {
  245. public static function Init()
  246. {
  247. $aParams = array
  248. (
  249. "category" => "addon/userrights",
  250. "key_type" => "autoincrement",
  251. "name_attcode" => "userid",
  252. "state_attcode" => "",
  253. "reconc_keys" => array(),
  254. "db_table" => "priv_urp_userprofile",
  255. "db_key_field" => "id",
  256. "db_finalclass_field" => "",
  257. "display_template" => "",
  258. );
  259. MetaModel::Init_Params($aParams);
  260. //MetaModel::Init_InheritAttributes();
  261. 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())));
  262. MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
  263. 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())));
  264. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  265. MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  266. // Display lists
  267. MetaModel::Init_SetZListItems('details', array('userid', 'profileid', 'reason')); // Attributes to be displayed for the complete details
  268. MetaModel::Init_SetZListItems('list', array('profileid', 'reason')); // Attributes to be displayed for a list
  269. // Search criteria
  270. MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
  271. MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
  272. }
  273. public function GetName()
  274. {
  275. return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
  276. }
  277. }
  278. class URP_ProfileProjection extends UserRightsBaseClass
  279. {
  280. public static function Init()
  281. {
  282. $aParams = array
  283. (
  284. "category" => "addon/userrights",
  285. "key_type" => "autoincrement",
  286. "name_attcode" => "profileid",
  287. "state_attcode" => "",
  288. "reconc_keys" => array(),
  289. "db_table" => "priv_urp_profileprojection",
  290. "db_key_field" => "id",
  291. "db_finalclass_field" => "",
  292. "display_template" => "",
  293. );
  294. MetaModel::Init_Params($aParams);
  295. //MetaModel::Init_InheritAttributes();
  296. MetaModel::Init_AddAttribute(new AttributeExternalKey("dimensionid", array("targetclass"=>"URP_Dimensions", "jointype"=> "", "allowed_values"=>null, "sql"=>"dimensionid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  297. MetaModel::Init_AddAttribute(new AttributeExternalField("dimension", array("allowed_values"=>null, "extkey_attcode"=> 'dimensionid', "target_attcode"=>"name")));
  298. 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())));
  299. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  300. MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>"value", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  301. MetaModel::Init_AddAttribute(new AttributeString("attribute", array("allowed_values"=>null, "sql"=>"attribute", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  302. // Display lists
  303. MetaModel::Init_SetZListItems('details', array('dimensionid', 'profileid', 'value', 'attribute')); // Attributes to be displayed for the complete details
  304. MetaModel::Init_SetZListItems('list', array('profileid', 'value', 'attribute')); // Attributes to be displayed for a list
  305. // Search criteria
  306. MetaModel::Init_SetZListItems('standard_search', array('dimensionid', 'profileid')); // Criteria of the std search form
  307. MetaModel::Init_SetZListItems('advanced_search', array('dimensionid', 'profileid')); // Criteria of the advanced search form
  308. }
  309. protected $m_aUserProjections; // cache
  310. public function ProjectUser(User $oUser)
  311. {
  312. if (is_array($this->m_aUserProjections))
  313. {
  314. // Hit!
  315. return $this->m_aUserProjections;
  316. }
  317. $sExpr = $this->Get('value');
  318. if ($sExpr == '<user>')
  319. {
  320. $sColumn = $this->Get('attribute');
  321. if (empty($sColumn))
  322. {
  323. $aRes = array($oUser->GetKey());
  324. }
  325. else
  326. {
  327. $aRes = array($oUser->Get($sColumn));
  328. }
  329. }
  330. elseif (($sExpr == '<any>') || ($sExpr == ''))
  331. {
  332. $aRes = null;
  333. }
  334. elseif (strtolower(substr($sExpr, 0, 6)) == 'select')
  335. {
  336. $sColumn = $this->Get('attribute');
  337. // SELECT...
  338. $oValueSetDef = new ValueSetObjects($sExpr, $sColumn, array(), true /*allow all data*/);
  339. $aRes = $oValueSetDef->GetValues(array('user' => $oUser), '');
  340. }
  341. else
  342. {
  343. // Constant value(s)
  344. $aRes = explode(';', trim($sExpr));
  345. }
  346. $this->m_aUserProjections = $aRes;
  347. return $aRes;
  348. }
  349. }
  350. class URP_ClassProjection extends UserRightsBaseClass
  351. {
  352. public static function Init()
  353. {
  354. $aParams = array
  355. (
  356. "category" => "addon/userrights",
  357. "key_type" => "autoincrement",
  358. "name_attcode" => "dimensionid",
  359. "state_attcode" => "",
  360. "reconc_keys" => array(),
  361. "db_table" => "priv_urp_classprojection",
  362. "db_key_field" => "id",
  363. "db_finalclass_field" => "",
  364. "display_template" => "",
  365. );
  366. MetaModel::Init_Params($aParams);
  367. //MetaModel::Init_InheritAttributes();
  368. MetaModel::Init_AddAttribute(new AttributeExternalKey("dimensionid", array("targetclass"=>"URP_Dimensions", "jointype"=> "", "allowed_values"=>null, "sql"=>"dimensionid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  369. MetaModel::Init_AddAttribute(new AttributeExternalField("dimension", array("allowed_values"=>null, "extkey_attcode"=> 'dimensionid', "target_attcode"=>"name")));
  370. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  371. MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>"value", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  372. MetaModel::Init_AddAttribute(new AttributeString("attribute", array("allowed_values"=>null, "sql"=>"attribute", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  373. // Display lists
  374. MetaModel::Init_SetZListItems('details', array('dimensionid', 'class', 'value', 'attribute')); // Attributes to be displayed for the complete details
  375. MetaModel::Init_SetZListItems('list', array('class', 'value', 'attribute')); // Attributes to be displayed for a list
  376. // Search criteria
  377. MetaModel::Init_SetZListItems('standard_search', array('dimensionid', 'class')); // Criteria of the std search form
  378. MetaModel::Init_SetZListItems('advanced_search', array('dimensionid', 'class')); // Criteria of the advanced search form
  379. }
  380. public function ProjectObject($oObject)
  381. {
  382. $sExpr = $this->Get('value');
  383. if ($sExpr == '<this>')
  384. {
  385. $sColumn = $this->Get('attribute');
  386. if (empty($sColumn))
  387. {
  388. $aRes = array($oObject->GetKey());
  389. }
  390. else
  391. {
  392. $aRes = array($oObject->Get($sColumn));
  393. }
  394. }
  395. elseif (($sExpr == '<any>') || ($sExpr == ''))
  396. {
  397. $aRes = null;
  398. }
  399. elseif (strtolower(substr($sExpr, 0, 6)) == 'select')
  400. {
  401. $sColumn = $this->Get('attribute');
  402. // SELECT...
  403. $oValueSetDef = new ValueSetObjects($sExpr, $sColumn, array(), true /*allow all data*/);
  404. $aRes = $oValueSetDef->GetValues(array('this' => $oObject), '');
  405. }
  406. else
  407. {
  408. // Constant value(s)
  409. $aRes = explode(';', trim($sExpr));
  410. }
  411. return $aRes;
  412. }
  413. }
  414. class URP_ActionGrant extends UserRightsBaseClass
  415. {
  416. public static function Init()
  417. {
  418. $aParams = array
  419. (
  420. "category" => "addon/userrights",
  421. "key_type" => "autoincrement",
  422. "name_attcode" => "profileid",
  423. "state_attcode" => "",
  424. "reconc_keys" => array(),
  425. "db_table" => "priv_urp_grant_actions",
  426. "db_key_field" => "id",
  427. "db_finalclass_field" => "",
  428. "display_template" => "",
  429. );
  430. MetaModel::Init_Params($aParams);
  431. //MetaModel::Init_InheritAttributes();
  432. // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
  433. 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())));
  434. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  435. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  436. 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())));
  437. MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  438. // Display lists
  439. MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'action')); // Attributes to be displayed for the complete details
  440. MetaModel::Init_SetZListItems('list', array('class', 'permission', 'action')); // Attributes to be displayed for a list
  441. // Search criteria
  442. MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the std search form
  443. MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the advanced search form
  444. }
  445. }
  446. class URP_StimulusGrant extends UserRightsBaseClass
  447. {
  448. public static function Init()
  449. {
  450. $aParams = array
  451. (
  452. "category" => "addon/userrights",
  453. "key_type" => "autoincrement",
  454. "name_attcode" => "profileid",
  455. "state_attcode" => "",
  456. "reconc_keys" => array(),
  457. "db_table" => "priv_urp_grant_stimulus",
  458. "db_key_field" => "id",
  459. "db_finalclass_field" => "",
  460. "display_template" => "",
  461. );
  462. MetaModel::Init_Params($aParams);
  463. //MetaModel::Init_InheritAttributes();
  464. // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
  465. 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())));
  466. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  467. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  468. 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())));
  469. MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  470. // Display lists
  471. MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'stimulus')); // Attributes to be displayed for the complete details
  472. MetaModel::Init_SetZListItems('list', array('class', 'permission', 'stimulus')); // Attributes to be displayed for a list
  473. // Search criteria
  474. MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the std search form
  475. MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the advanced search form
  476. }
  477. }
  478. class URP_AttributeGrant extends UserRightsBaseClass
  479. {
  480. public static function Init()
  481. {
  482. $aParams = array
  483. (
  484. "category" => "addon/userrights",
  485. "key_type" => "autoincrement",
  486. "name_attcode" => "actiongrantid",
  487. "state_attcode" => "",
  488. "reconc_keys" => array(),
  489. "db_table" => "priv_urp_grant_attributes",
  490. "db_key_field" => "id",
  491. "db_finalclass_field" => "",
  492. "display_template" => "",
  493. );
  494. MetaModel::Init_Params($aParams);
  495. //MetaModel::Init_InheritAttributes();
  496. 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())));
  497. MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  498. // Display lists
  499. MetaModel::Init_SetZListItems('details', array('actiongrantid', 'attcode')); // Attributes to be displayed for the complete details
  500. MetaModel::Init_SetZListItems('list', array('attcode')); // Attributes to be displayed for a list
  501. // Search criteria
  502. MetaModel::Init_SetZListItems('standard_search', array('actiongrantid', 'attcode')); // Criteria of the std search form
  503. MetaModel::Init_SetZListItems('advanced_search', array('actiongrantid', 'attcode')); // Criteria of the advanced search form
  504. }
  505. }
  506. class UserRightsProjection extends UserRightsAddOnAPI
  507. {
  508. static public $m_aActionCodes = array(
  509. UR_ACTION_READ => 'read',
  510. UR_ACTION_MODIFY => 'modify',
  511. UR_ACTION_DELETE => 'delete',
  512. UR_ACTION_BULK_READ => 'bulk read',
  513. UR_ACTION_BULK_MODIFY => 'bulk modify',
  514. UR_ACTION_BULK_DELETE => 'bulk delete',
  515. );
  516. // Installation: create the very first user
  517. public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
  518. {
  519. // Create a change to record the history of the User object
  520. $oChange = MetaModel::NewObject("CMDBChange");
  521. $oChange->Set("date", time());
  522. $oChange->Set("userinfo", "Initialization");
  523. $iChangeId = $oChange->DBInsert();
  524. $oOrg = new Organization();
  525. $oOrg->Set('name', 'My Company/Department');
  526. $oOrg->Set('code', 'SOMECODE');
  527. // $oOrg->Set('status', 'implementation');
  528. //$oOrg->Set('parent_id', xxx);
  529. $iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip strong security */);
  530. // Location : optional
  531. //$oLocation = new bizLocation();
  532. //$oLocation->Set('name', 'MyOffice');
  533. //$oLocation->Set('status', 'implementation');
  534. //$oLocation->Set('org_id', $iOrgId);
  535. //$oLocation->Set('severity', 'high');
  536. //$oLocation->Set('address', 'my building in my city');
  537. //$oLocation->Set('country', 'my country');
  538. //$oLocation->Set('parent_location_id', xxx);
  539. //$iLocationId = $oLocation->DBInsertNoReload();
  540. $oContact = new Person();
  541. $oContact->Set('name', 'My last name');
  542. $oContact->Set('first_name', 'My first name');
  543. //$oContact->Set('status', 'available');
  544. $oContact->Set('org_id', $iOrgId);
  545. $oContact->Set('email', 'my.email@foo.org');
  546. //$oContact->Set('phone', '');
  547. //$oContact->Set('location_id', $iLocationId);
  548. //$oContact->Set('employee_number', '');
  549. $iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
  550. $oUser = new UserLocal();
  551. $oUser->Set('login', $sAdminUser);
  552. $oUser->Set('password', $sAdminPwd);
  553. $oUser->Set('contactid', $iContactId);
  554. $oUser->Set('language', $sLanguage); // Language was chosen during the installation
  555. $iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
  556. // Add this user to the very specific 'admin' profile
  557. $oUserProfile = new URP_UserProfile();
  558. $oUserProfile->Set('userid', $iUserId);
  559. $oUserProfile->Set('profileid', ADMIN_PROFILE_ID);
  560. $oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
  561. $oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
  562. return true;
  563. }
  564. public function IsAdministrator($oUser)
  565. {
  566. if (in_array($oUser->GetKey(), $this->m_aAdmins))
  567. {
  568. return true;
  569. }
  570. else
  571. {
  572. return false;
  573. }
  574. }
  575. public function IsPortalUser($oUser)
  576. {
  577. return true;
  578. // See implementation of userrightsprofile
  579. }
  580. public function Init()
  581. {
  582. // CacheData to be invoked in a module extension
  583. //MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData'));
  584. }
  585. protected $m_aDimensions = array(); // id -> object
  586. protected $m_aClassProj = array(); // class,dimensionid -> object
  587. protected $m_aProfiles = array(); // id -> object
  588. protected $m_aUserProfiles = array(); // userid,profileid -> object
  589. protected $m_aProPro = array(); // profileid,dimensionid -> object
  590. protected $m_aAdmins = array(); // id of users being linked to the well-known admin profile
  591. protected $m_aClassActionGrants = array(); // profile, class, action -> permission
  592. protected $m_aClassStimulusGrants = array(); // profile, class, stimulus -> permission
  593. protected $m_aObjectActionGrants = array(); // userid, class, id, action -> permission, list of attributes
  594. public function CacheData()
  595. {
  596. // Could be loaded in a shared memory (?)
  597. $oDimensionSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Dimensions"));
  598. $this->m_aDimensions = array();
  599. while ($oDimension = $oDimensionSet->Fetch())
  600. {
  601. $this->m_aDimensions[$oDimension->GetKey()] = $oDimension;
  602. }
  603. $oClassProjSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_ClassProjection"));
  604. $this->m_aClassProjs = array();
  605. while ($oClassProj = $oClassProjSet->Fetch())
  606. {
  607. $this->m_aClassProjs[$oClassProj->Get('class')][$oClassProj->Get('dimensionid')] = $oClassProj;
  608. }
  609. $oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Profiles"));
  610. $this->m_aProfiles = array();
  611. while ($oProfile = $oProfileSet->Fetch())
  612. {
  613. $this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
  614. }
  615. $oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserProfile"));
  616. $this->m_aUserProfiles = array();
  617. $this->m_aAdmins = array();
  618. while ($oUserProfile = $oUserProfileSet->Fetch())
  619. {
  620. $this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile;
  621. if ($oUserProfile->Get('profileid') == ADMIN_PROFILE_ID)
  622. {
  623. $this->m_aAdmins[] = $oUserProfile->Get('userid');
  624. }
  625. }
  626. $oProProSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_ProfileProjection"));
  627. $this->m_aProPros = array();
  628. while ($oProPro = $oProProSet->Fetch())
  629. {
  630. $this->m_aProPros[$oProPro->Get('profileid')][$oProPro->Get('dimensionid')] = $oProPro;
  631. }
  632. /*
  633. echo "<pre>\n";
  634. print_r($this->m_aDimensions);
  635. print_r($this->m_aClassProjs);
  636. print_r($this->m_aProfiles);
  637. print_r($this->m_aUserProfiles);
  638. print_r($this->m_aProPros);
  639. echo "</pre>\n";
  640. exit;
  641. */
  642. return true;
  643. }
  644. public function GetSelectFilter($oUser, $sClass, $aSettings = array())
  645. {
  646. $aConditions = array();
  647. foreach ($this->m_aDimensions as $iDimension => $oDimension)
  648. {
  649. $oClassProj = @$this->m_aClassProjs[$sClass][$iDimension];
  650. if (is_null($oClassProj))
  651. {
  652. // Authorize any for this dimension, then no additional criteria is required
  653. continue;
  654. }
  655. // 1 - Get class projection info
  656. //
  657. $oExpression = null;
  658. $sExpr = $oClassProj->Get('value');
  659. if ($sExpr == '<this>')
  660. {
  661. $sColumn = $oClassProj->Get('attribute');
  662. if (empty($sColumn))
  663. {
  664. $oExpression = new FieldExpression('id', $sClass);
  665. }
  666. else
  667. {
  668. $oExpression = new FieldExpression($sColumn, $sClass);
  669. }
  670. }
  671. elseif (($sExpr == '<any>') || ($sExpr == ''))
  672. {
  673. // Authorize any for this dimension, then no additional criteria is required
  674. continue;
  675. }
  676. elseif (strtolower(substr($sExpr, 0, 6)) == 'select')
  677. {
  678. throw new CoreException('Sorry, projections by the mean of OQL are not supported currently, please specify an attribute instead', array('class' => $sClass, 'expression' => $sExpr));
  679. }
  680. else
  681. {
  682. // Constant value(s)
  683. // unsupported
  684. throw new CoreException('Sorry, constant projections are not supported currently, please specify an attribute instead', array('class' => $sClass, 'expression' => $sExpr));
  685. // $aRes = explode(';', trim($sExpr));
  686. }
  687. // 2 - Get profile projection info and use it if needed
  688. //
  689. $aProjections = self::GetReadableProjectionsByDim($oUser, $sClass, $oDimension);
  690. if (is_null($aProjections))
  691. {
  692. // Authorize any for this dimension, then no additional criteria is required
  693. continue;
  694. }
  695. elseif (count($aProjections) == 0)
  696. {
  697. // Authorize none, then exit as quickly as possible
  698. return false;
  699. }
  700. else
  701. {
  702. // Authorize the given set of values
  703. $oListExpr = ListExpression::FromScalars($aProjections);
  704. $oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
  705. $aConditions[] = $oCondition;
  706. }
  707. }
  708. if (count($aConditions) == 0)
  709. {
  710. // allow all
  711. return true;
  712. }
  713. else
  714. {
  715. $oFilter = new DBObjectSearch($sClass);
  716. foreach($aConditions as $oCondition)
  717. {
  718. $oFilter->AddConditionExpression($oCondition);
  719. }
  720. //return true;
  721. return $oFilter;
  722. }
  723. }
  724. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  725. public function GetClassActionGrant($iProfile, $sClass, $sAction)
  726. {
  727. if (isset($this->m_aClassActionGrants[$iProfile][$sClass][$sAction]))
  728. {
  729. return $this->m_aClassActionGrants[$iProfile][$sClass][$sAction];
  730. }
  731. // Get the permission for this profile/class/action
  732. $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_ActionGrant WHERE class = :class AND action = :action AND profileid = :profile AND permission = 'yes'");
  733. $oSet = new DBObjectSet($oSearch, array(), array('class'=>$sClass, 'action'=>$sAction, 'profile'=>$iProfile));
  734. if ($oSet->Count() >= 1)
  735. {
  736. $oGrantRecord = $oSet->Fetch();
  737. }
  738. else
  739. {
  740. $sParentClass = MetaModel::GetParentPersistentClass($sClass);
  741. if (empty($sParentClass))
  742. {
  743. $oGrantRecord = null;
  744. }
  745. else
  746. {
  747. $oGrantRecord = $this->GetClassActionGrant($iProfile, $sParentClass, $sAction);
  748. }
  749. }
  750. $this->m_aClassActionGrants[$iProfile][$sClass][$sAction] = $oGrantRecord;
  751. return $oGrantRecord;
  752. }
  753. protected function GetObjectActionGrant($oUser, $sClass, $iActionCode, /*DBObject*/ $oObject = null)
  754. {
  755. if(is_null($oObject))
  756. {
  757. $iObjectRef = -999;
  758. }
  759. else
  760. {
  761. $iObjectRef = $oObject->GetKey();
  762. }
  763. // load and cache permissions for the current user on the given object
  764. //
  765. $aTest = @$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iObjectRef][$iActionCode];
  766. if (is_array($aTest)) return $aTest;
  767. $sAction = self::$m_aActionCodes[$iActionCode];
  768. $iInstancePermission = UR_ALLOWED_NO;
  769. $aAttributes = array();
  770. foreach($this->GetMatchingProfiles($oUser, $sClass, $oObject) as $iProfile)
  771. {
  772. $oGrantRecord = $this->GetClassActionGrant($iProfile, $sClass, $sAction);
  773. if (is_null($oGrantRecord))
  774. {
  775. continue; // loop to the next profile
  776. }
  777. else
  778. {
  779. $iInstancePermission = UR_ALLOWED_YES;
  780. // update the list of attributes with those allowed for this profile
  781. //
  782. $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
  783. $oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $oGrantRecord->GetKey()));
  784. $aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
  785. if (count($aProfileAttributes) == 0)
  786. {
  787. $aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
  788. $aAttributes = array_merge($aAttributes, $aAllAttributes);
  789. }
  790. else
  791. {
  792. $aAttributes = array_merge($aAttributes, $aProfileAttributes);
  793. }
  794. }
  795. }
  796. $aRes = array(
  797. 'permission' => $iInstancePermission,
  798. 'attributes' => $aAttributes,
  799. );
  800. $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iObjectRef][$iActionCode] = $aRes;
  801. return $aRes;
  802. }
  803. public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
  804. {
  805. if (is_null($oInstanceSet))
  806. {
  807. $aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode);
  808. return $aObjectPermissions['permission'];
  809. }
  810. $oInstanceSet->Rewind();
  811. while($oObject = $oInstanceSet->Fetch())
  812. {
  813. $aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject);
  814. $iInstancePermission = $aObjectPermissions['permission'];
  815. if (isset($iGlobalPermission))
  816. {
  817. if ($iInstancePermission != $iGlobalPermission)
  818. {
  819. $iGlobalPermission = UR_ALLOWED_DEPENDS;
  820. break;
  821. }
  822. }
  823. else
  824. {
  825. $iGlobalPermission = $iInstancePermission;
  826. }
  827. }
  828. $oInstanceSet->Rewind();
  829. if (isset($iGlobalPermission))
  830. {
  831. return $iGlobalPermission;
  832. }
  833. else
  834. {
  835. return UR_ALLOWED_NO;
  836. }
  837. }
  838. public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
  839. {
  840. if (is_null($oInstanceSet))
  841. {
  842. $aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode);
  843. $aAttributes = $aObjectPermissions['attributes'];
  844. if (in_array($sAttCode, $aAttributes))
  845. {
  846. return $aObjectPermissions['permission'];
  847. }
  848. else
  849. {
  850. return UR_ALLOWED_NO;
  851. }
  852. }
  853. $oInstanceSet->Rewind();
  854. while($oObject = $oInstanceSet->Fetch())
  855. {
  856. $aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject);
  857. $aAttributes = $aObjectPermissions['attributes'];
  858. if (in_array($sAttCode, $aAttributes))
  859. {
  860. $iInstancePermission = $aObjectPermissions['permission'];
  861. }
  862. else
  863. {
  864. $iInstancePermission = UR_ALLOWED_NO;
  865. }
  866. if (isset($iGlobalPermission))
  867. {
  868. if ($iInstancePermission != $iGlobalPermission)
  869. {
  870. $iGlobalPermission = UR_ALLOWED_DEPENDS;
  871. }
  872. }
  873. else
  874. {
  875. $iGlobalPermission = $iInstancePermission;
  876. }
  877. }
  878. $oInstanceSet->Rewind();
  879. if (isset($iGlobalPermission))
  880. {
  881. return $iGlobalPermission;
  882. }
  883. else
  884. {
  885. return UR_ALLOWED_NO;
  886. }
  887. }
  888. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  889. public function GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode)
  890. {
  891. if (isset($this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode]))
  892. {
  893. return $this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode];
  894. }
  895. // Get the permission for this profile/class/stimulus
  896. $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant WHERE class = :class AND stimulus = :stimulus AND profileid = :profile AND permission = 'yes'");
  897. $oSet = new DBObjectSet($oSearch, array(), array('class'=>$sClass, 'stimulus'=>$sStimulusCode, 'profile'=>$iProfile));
  898. if ($oSet->Count() >= 1)
  899. {
  900. $oGrantRecord = $oSet->Fetch();
  901. }
  902. else
  903. {
  904. $oGrantRecord = null;
  905. }
  906. $this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode] = $oGrantRecord;
  907. return $oGrantRecord;
  908. }
  909. public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
  910. {
  911. // Note: this code is VERY close to the code of IsActionAllowed()
  912. if (is_null($oInstanceSet))
  913. {
  914. $iInstancePermission = UR_ALLOWED_NO;
  915. foreach($this->GetMatchingProfiles($oUser, $sClass) as $iProfile)
  916. {
  917. $oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
  918. if (!is_null($oGrantRecord))
  919. {
  920. // no need to fetch the record, we've requested the records having permission = 'yes'
  921. $iInstancePermission = UR_ALLOWED_YES;
  922. }
  923. }
  924. return $iInstancePermission;
  925. }
  926. $oInstanceSet->Rewind();
  927. while($oObject = $oInstanceSet->Fetch())
  928. {
  929. $iInstancePermission = UR_ALLOWED_NO;
  930. foreach($this->GetMatchingProfiles($oUser, $sClass, $oObject) as $iProfile)
  931. {
  932. $oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
  933. if (!is_null($oGrantRecord))
  934. {
  935. // no need to fetch the record, we've requested the records having permission = 'yes'
  936. $iInstancePermission = UR_ALLOWED_YES;
  937. }
  938. }
  939. if (isset($iGlobalPermission))
  940. {
  941. if ($iInstancePermission != $iGlobalPermission)
  942. {
  943. $iGlobalPermission = UR_ALLOWED_DEPENDS;
  944. }
  945. }
  946. else
  947. {
  948. $iGlobalPermission = $iInstancePermission;
  949. }
  950. }
  951. $oInstanceSet->Rewind();
  952. if (isset($iGlobalPermission))
  953. {
  954. return $iGlobalPermission;
  955. }
  956. else
  957. {
  958. return UR_ALLOWED_NO;
  959. }
  960. }
  961. // Copied from GetMatchingProfilesByDim()
  962. // adapted to the optimized implementation of GetSelectFilter()
  963. // Note: shares the cache m_aProPros with GetMatchingProfilesByDim()
  964. // Returns null if any object is readable
  965. // an array of allowed projections otherwise (could be an empty array if none is allowed)
  966. protected function GetReadableProjectionsByDim($oUser, $sClass, $oDimension)
  967. {
  968. //
  969. // Given a dimension, lists the values for which the user will be allowed to read the objects
  970. //
  971. $iUser = $oUser->GetKey();
  972. $iDimension = $oDimension->GetKey();
  973. $aRes = array();
  974. if (array_key_exists($iUser, $this->m_aUserProfiles))
  975. {
  976. foreach ($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  977. {
  978. // user projection to be cached on a given page !
  979. if (!isset($this->m_aProPros[$iProfile][$iDimension]))
  980. {
  981. // No projection for a given profile: default to 'any'
  982. return null;
  983. }
  984. $aUserProjection = $this->m_aProPros[$iProfile][$iDimension]->ProjectUser($oUser);
  985. if (is_null($aUserProjection))
  986. {
  987. // No projection for a given profile: default to 'any'
  988. return null;
  989. }
  990. $aRes = array_unique(array_merge($aRes, $aUserProjection));
  991. }
  992. }
  993. return $aRes;
  994. }
  995. // Note: shares the cache m_aProPros with GetReadableProjectionsByDim()
  996. protected function GetMatchingProfilesByDim($oUser, $oObject, $oDimension)
  997. {
  998. //
  999. // List profiles for which the user projection overlaps the object projection in the given dimension
  1000. //
  1001. $iUser = $oUser->GetKey();
  1002. $sClass = get_class($oObject);
  1003. $iPKey = $oObject->GetKey();
  1004. $iDimension = $oDimension->GetKey();
  1005. if (isset($this->m_aClassProjs[$sClass][$iDimension]))
  1006. {
  1007. $aObjectProjection = $this->m_aClassProjs[$sClass][$iDimension]->ProjectObject($oObject);
  1008. }
  1009. else
  1010. {
  1011. // No projection for a given class: default to 'any'
  1012. $aObjectProjection = null;
  1013. }
  1014. $aRes = array();
  1015. if (array_key_exists($iUser, $this->m_aUserProfiles))
  1016. {
  1017. foreach ($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  1018. {
  1019. if (is_null($aObjectProjection))
  1020. {
  1021. $aRes[] = $iProfile;
  1022. }
  1023. else
  1024. {
  1025. // user projection to be cached on a given page !
  1026. if (isset($this->m_aProPros[$iProfile][$iDimension]))
  1027. {
  1028. $aUserProjection = $this->m_aProPros[$iProfile][$iDimension]->ProjectUser($oUser);
  1029. }
  1030. else
  1031. {
  1032. // No projection for a given profile: default to 'any'
  1033. $aUserProjection = null;
  1034. }
  1035. if (is_null($aUserProjection))
  1036. {
  1037. $aRes[] = $iProfile;
  1038. }
  1039. else
  1040. {
  1041. $aMatchingValues = array_intersect($aObjectProjection, $aUserProjection);
  1042. if (count($aMatchingValues) > 0)
  1043. {
  1044. $aRes[] = $iProfile;
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }
  1050. return $aRes;
  1051. }
  1052. protected $m_aMatchingProfiles = array(); // cache of the matching profiles for a given user/object
  1053. protected function GetMatchingProfiles($oUser, $sClass, /*DBObject*/ $oObject = null)
  1054. {
  1055. $iUser = $oUser->GetKey();
  1056. if(is_null($oObject))
  1057. {
  1058. $iObjectRef = -999;
  1059. }
  1060. else
  1061. {
  1062. $iObjectRef = $oObject->GetKey();
  1063. }
  1064. //
  1065. // List profiles for which the user projection overlaps the object projection in each and every dimension
  1066. // Caches the result
  1067. //
  1068. $aTest = @$this->m_aMatchingProfiles[$iUser][$sClass][$iObjectRef];
  1069. if (is_array($aTest))
  1070. {
  1071. return $aTest;
  1072. }
  1073. if (is_null($oObject))
  1074. {
  1075. if (array_key_exists($iUser, $this->m_aUserProfiles))
  1076. {
  1077. $aRes = array_keys($this->m_aUserProfiles[$iUser]);
  1078. }
  1079. else
  1080. {
  1081. // no profile has been defined for this user
  1082. $aRes = array();
  1083. }
  1084. }
  1085. else
  1086. {
  1087. $aProfileRes = array();
  1088. foreach ($this->m_aDimensions as $iDimension => $oDimension)
  1089. {
  1090. foreach ($this->GetMatchingProfilesByDim($oUser, $oObject, $oDimension) as $iProfile)
  1091. {
  1092. @$aProfileRes[$iProfile] += 1;
  1093. }
  1094. }
  1095. $aRes = array();
  1096. $iDimCount = count($this->m_aDimensions);
  1097. foreach ($aProfileRes as $iProfile => $iMatches)
  1098. {
  1099. if ($iMatches == $iDimCount)
  1100. {
  1101. $aRes[] = $iProfile;
  1102. }
  1103. }
  1104. }
  1105. // store into the cache
  1106. $this->m_aMatchingProfiles[$iUser][$sClass][$iObjectRef] = $aRes;
  1107. return $aRes;
  1108. }
  1109. public function FlushPrivileges()
  1110. {
  1111. $this->CacheData();
  1112. }
  1113. }
  1114. UserRights::SelectModule('UserRightsProjection');
  1115. ?>