PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/applications/policy/storage/PhabricatorPolicy.php

https://github.com/navyuginfo/phabricator
PHP | 354 lines | 283 code | 49 blank | 22 comment | 32 complexity | 4ea3cb2046f25de5ebea5d517dc0dfa4 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, LGPL-3.0, MIT, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. <?php
  2. final class PhabricatorPolicy
  3. extends PhabricatorPolicyDAO
  4. implements PhabricatorPolicyInterface {
  5. const ACTION_ALLOW = 'allow';
  6. const ACTION_DENY = 'deny';
  7. private $name;
  8. private $shortName;
  9. private $type;
  10. private $href;
  11. private $workflow;
  12. private $icon;
  13. protected $rules = array();
  14. protected $defaultAction = self::ACTION_DENY;
  15. private $ruleObjects = self::ATTACHABLE;
  16. public function getConfiguration() {
  17. return array(
  18. self::CONFIG_AUX_PHID => true,
  19. self::CONFIG_SERIALIZATION => array(
  20. 'rules' => self::SERIALIZATION_JSON,
  21. ),
  22. ) + parent::getConfiguration();
  23. }
  24. public function generatePHID() {
  25. return PhabricatorPHID::generateNewPHID(
  26. PhabricatorPolicyPHIDTypePolicy::TYPECONST);
  27. }
  28. public static function newFromPolicyAndHandle(
  29. $policy_identifier,
  30. PhabricatorObjectHandle $handle = null) {
  31. $is_global = PhabricatorPolicyQuery::isGlobalPolicy($policy_identifier);
  32. if ($is_global) {
  33. return PhabricatorPolicyQuery::getGlobalPolicy($policy_identifier);
  34. }
  35. if (!$handle) {
  36. throw new Exception(
  37. "Policy identifier is an object PHID ('{$policy_identifier}'), but no ".
  38. "object handle was provided. A handle must be provided for object ".
  39. "policies.");
  40. }
  41. $handle_phid = $handle->getPHID();
  42. if ($policy_identifier != $handle_phid) {
  43. throw new Exception(
  44. "Policy identifier is an object PHID ('{$policy_identifier}'), but ".
  45. "the provided handle has a different PHID ('{$handle_phid}'). The ".
  46. "handle must correspond to the policy identifier.");
  47. }
  48. $policy = id(new PhabricatorPolicy())
  49. ->setPHID($policy_identifier)
  50. ->setHref($handle->getURI());
  51. $phid_type = phid_get_type($policy_identifier);
  52. switch ($phid_type) {
  53. case PhabricatorProjectPHIDTypeProject::TYPECONST:
  54. $policy->setType(PhabricatorPolicyType::TYPE_PROJECT);
  55. $policy->setName($handle->getName());
  56. break;
  57. case PhabricatorPeoplePHIDTypeUser::TYPECONST:
  58. $policy->setType(PhabricatorPolicyType::TYPE_USER);
  59. $policy->setName($handle->getFullName());
  60. break;
  61. case PhabricatorPolicyPHIDTypePolicy::TYPECONST:
  62. // TODO: This creates a weird handle-based version of a rule policy.
  63. // It behaves correctly, but can't be applied since it doesn't have
  64. // any rules. It is used to render transactions, and might need some
  65. // cleanup.
  66. break;
  67. default:
  68. $policy->setType(PhabricatorPolicyType::TYPE_MASKED);
  69. $policy->setName($handle->getFullName());
  70. break;
  71. }
  72. $policy->makeEphemeral();
  73. return $policy;
  74. }
  75. public function setType($type) {
  76. $this->type = $type;
  77. return $this;
  78. }
  79. public function getType() {
  80. if (!$this->type) {
  81. return PhabricatorPolicyType::TYPE_CUSTOM;
  82. }
  83. return $this->type;
  84. }
  85. public function setName($name) {
  86. $this->name = $name;
  87. return $this;
  88. }
  89. public function getName() {
  90. if (!$this->name) {
  91. return pht('Custom Policy');
  92. }
  93. return $this->name;
  94. }
  95. public function setShortName($short_name) {
  96. $this->shortName = $short_name;
  97. return $this;
  98. }
  99. public function getShortName() {
  100. if ($this->shortName) {
  101. return $this->shortName;
  102. }
  103. return $this->getName();
  104. }
  105. public function setHref($href) {
  106. $this->href = $href;
  107. return $this;
  108. }
  109. public function getHref() {
  110. return $this->href;
  111. }
  112. public function setWorkflow($workflow) {
  113. $this->workflow = $workflow;
  114. return $this;
  115. }
  116. public function getWorkflow() {
  117. return $this->workflow;
  118. }
  119. public function getIcon() {
  120. switch ($this->getType()) {
  121. case PhabricatorPolicyType::TYPE_GLOBAL:
  122. static $map = array(
  123. PhabricatorPolicies::POLICY_PUBLIC => 'fa-globe',
  124. PhabricatorPolicies::POLICY_USER => 'fa-users',
  125. PhabricatorPolicies::POLICY_ADMIN => 'fa-eye',
  126. PhabricatorPolicies::POLICY_NOONE => 'fa-ban',
  127. );
  128. return idx($map, $this->getPHID(), 'fa-question-circle');
  129. case PhabricatorPolicyType::TYPE_USER:
  130. return 'fa-user';
  131. case PhabricatorPolicyType::TYPE_PROJECT:
  132. return 'fa-briefcase';
  133. case PhabricatorPolicyType::TYPE_CUSTOM:
  134. case PhabricatorPolicyType::TYPE_MASKED:
  135. return 'fa-certificate';
  136. default:
  137. return 'fa-question-circle';
  138. }
  139. }
  140. public function getSortKey() {
  141. return sprintf(
  142. '%02d%s',
  143. PhabricatorPolicyType::getPolicyTypeOrder($this->getType()),
  144. $this->getSortName());
  145. }
  146. private function getSortName() {
  147. if ($this->getType() == PhabricatorPolicyType::TYPE_GLOBAL) {
  148. static $map = array(
  149. PhabricatorPolicies::POLICY_PUBLIC => 0,
  150. PhabricatorPolicies::POLICY_USER => 1,
  151. PhabricatorPolicies::POLICY_ADMIN => 2,
  152. PhabricatorPolicies::POLICY_NOONE => 3,
  153. );
  154. return idx($map, $this->getPHID());
  155. }
  156. return $this->getName();
  157. }
  158. public static function getPolicyExplanation(
  159. PhabricatorUser $viewer,
  160. $policy) {
  161. switch ($policy) {
  162. case PhabricatorPolicies::POLICY_PUBLIC:
  163. return pht('This object is public.');
  164. case PhabricatorPolicies::POLICY_USER:
  165. return pht('Logged in users can take this action.');
  166. case PhabricatorPolicies::POLICY_ADMIN:
  167. return pht('Administrators can take this action.');
  168. case PhabricatorPolicies::POLICY_NOONE:
  169. return pht('By default, no one can take this action.');
  170. default:
  171. $handle = id(new PhabricatorHandleQuery())
  172. ->setViewer($viewer)
  173. ->withPHIDs(array($policy))
  174. ->executeOne();
  175. $type = phid_get_type($policy);
  176. if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) {
  177. return pht(
  178. 'Members of the project "%s" can take this action.',
  179. $handle->getFullName());
  180. } else if ($type == PhabricatorPeoplePHIDTypeUser::TYPECONST) {
  181. return pht(
  182. '%s can take this action.',
  183. $handle->getFullName());
  184. } else if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) {
  185. return pht(
  186. 'This object has a custom policy controlling who can take this '.
  187. 'action.');
  188. } else {
  189. return pht(
  190. 'This object has an unknown or invalid policy setting ("%s").',
  191. $policy);
  192. }
  193. }
  194. }
  195. public function getFullName() {
  196. switch ($this->getType()) {
  197. case PhabricatorPolicyType::TYPE_PROJECT:
  198. return pht('Project: %s', $this->getName());
  199. case PhabricatorPolicyType::TYPE_MASKED:
  200. return pht('Other: %s', $this->getName());
  201. default:
  202. return $this->getName();
  203. }
  204. }
  205. public function renderDescription($icon=false) {
  206. $img = null;
  207. if ($icon) {
  208. $img = id(new PHUIIconView())
  209. ->setIconFont($this->getIcon());
  210. }
  211. if ($this->getHref()) {
  212. $desc = javelin_tag(
  213. 'a',
  214. array(
  215. 'href' => $this->getHref(),
  216. 'class' => 'policy-link',
  217. 'sigil' => $this->getWorkflow() ? 'workflow' : null,
  218. ),
  219. array(
  220. $img,
  221. $this->getName(),
  222. ));
  223. } else {
  224. if ($img) {
  225. $desc = array($img, $this->getName());
  226. } else {
  227. $desc = $this->getName();
  228. }
  229. }
  230. switch ($this->getType()) {
  231. case PhabricatorPolicyType::TYPE_PROJECT:
  232. return pht('%s (Project)', $desc);
  233. case PhabricatorPolicyType::TYPE_CUSTOM:
  234. return $desc;
  235. case PhabricatorPolicyType::TYPE_MASKED:
  236. return pht(
  237. '%s (You do not have permission to view policy details.)',
  238. $desc);
  239. default:
  240. return $desc;
  241. }
  242. }
  243. /**
  244. * Return a list of custom rule classes (concrete subclasses of
  245. * @{class:PhabricatorPolicyRule}) this policy uses.
  246. *
  247. * @return list<string> List of class names.
  248. */
  249. public function getCustomRuleClasses() {
  250. $classes = array();
  251. foreach ($this->getRules() as $rule) {
  252. $class = idx($rule, 'rule');
  253. try {
  254. if (class_exists($class)) {
  255. $classes[$class] = $class;
  256. }
  257. } catch (Exception $ex) {
  258. continue;
  259. }
  260. }
  261. return array_keys($classes);
  262. }
  263. /**
  264. * Return a list of all values used by a given rule class to implement this
  265. * policy. This is used to bulk load data (like project memberships) in order
  266. * to apply policy filters efficiently.
  267. *
  268. * @param string Policy rule classname.
  269. * @return list<wild> List of values used in this policy.
  270. */
  271. public function getCustomRuleValues($rule_class) {
  272. $values = array();
  273. foreach ($this->getRules() as $rule) {
  274. if ($rule['rule'] == $rule_class) {
  275. $values[] = $rule['value'];
  276. }
  277. }
  278. return $values;
  279. }
  280. public function attachRuleObjects(array $objects) {
  281. $this->ruleObjects = $objects;
  282. return $this;
  283. }
  284. public function getRuleObjects() {
  285. return $this->assertAttached($this->ruleObjects);
  286. }
  287. /* -( PhabricatorPolicyInterface )----------------------------------------- */
  288. public function getCapabilities() {
  289. return array(
  290. PhabricatorPolicyCapability::CAN_VIEW,
  291. );
  292. }
  293. public function getPolicy($capability) {
  294. // NOTE: We implement policies only so we can comply with the interface.
  295. // The actual query skips them, as enforcing policies on policies seems
  296. // perilous and isn't currently required by the application.
  297. return PhabricatorPolicies::POLICY_PUBLIC;
  298. }
  299. public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
  300. return false;
  301. }
  302. public function describeAutomaticCapability($capability) {
  303. return null;
  304. }
  305. }