Remove product literal strings in "pht()", part 6
[phabricator.git] / src / applications / policy / controller / PhabricatorPolicyEditController.php
blobf211aa754d9b5d6e75a8dcac62f4fcdc11e4024f
1 <?php
3 final class PhabricatorPolicyEditController
4 extends PhabricatorPolicyController {
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $this->getViewer();
9 $object_phid = $request->getURIData('objectPHID');
10 if ($object_phid) {
11 $object = id(new PhabricatorObjectQuery())
12 ->setViewer($viewer)
13 ->withPHIDs(array($object_phid))
14 ->executeOne();
15 if (!$object) {
16 return new Aphront404Response();
18 } else {
19 $object_type = $request->getURIData('objectType');
20 if (!$object_type) {
21 $object_type = $request->getURIData('templateType');
24 $phid_types = PhabricatorPHIDType::getAllInstalledTypes($viewer);
25 if (empty($phid_types[$object_type])) {
26 return new Aphront404Response();
28 $object = $phid_types[$object_type]->newObject();
29 if (!$object) {
30 return new Aphront404Response();
34 $phid = $request->getURIData('phid');
35 switch ($phid) {
36 case AphrontFormPolicyControl::getSelectProjectKey():
37 return $this->handleProjectRequest($request);
38 case AphrontFormPolicyControl::getSelectCustomKey():
39 $phid = null;
40 break;
41 default:
42 break;
45 $action_options = array(
46 PhabricatorPolicy::ACTION_ALLOW => pht('Allow'),
47 PhabricatorPolicy::ACTION_DENY => pht('Deny'),
50 $rules = id(new PhutilClassMapQuery())
51 ->setAncestorClass('PhabricatorPolicyRule')
52 ->execute();
54 foreach ($rules as $key => $rule) {
55 if (!$rule->canApplyToObject($object)) {
56 unset($rules[$key]);
60 $rules = msort($rules, 'getRuleOrder');
62 $default_rule = array(
63 'action' => head_key($action_options),
64 'rule' => head_key($rules),
65 'value' => null,
68 if ($phid) {
69 $policies = id(new PhabricatorPolicyQuery())
70 ->setViewer($viewer)
71 ->withPHIDs(array($phid))
72 ->execute();
73 if (!$policies) {
74 return new Aphront404Response();
76 $policy = head($policies);
77 } else {
78 $policy = id(new PhabricatorPolicy())
79 ->setRules(array($default_rule))
80 ->setDefaultAction(PhabricatorPolicy::ACTION_DENY);
83 $root_id = celerity_generate_unique_node_id();
85 $default_action = $policy->getDefaultAction();
86 $rule_data = $policy->getRules();
88 $errors = array();
89 if ($request->isFormPost()) {
90 $data = $request->getStr('rules');
91 try {
92 $data = phutil_json_decode($data);
93 } catch (PhutilJSONParserException $ex) {
94 throw new PhutilProxyException(
95 pht('Failed to JSON decode rule data!'),
96 $ex);
99 $rule_data = array();
100 foreach ($data as $rule) {
101 $action = idx($rule, 'action');
102 switch ($action) {
103 case 'allow':
104 case 'deny':
105 break;
106 default:
107 throw new Exception(pht("Invalid action '%s'!", $action));
110 $rule_class = idx($rule, 'rule');
111 if (empty($rules[$rule_class])) {
112 throw new Exception(pht("Invalid rule class '%s'!", $rule_class));
115 $rule_obj = $rules[$rule_class];
117 $value = $rule_obj->getValueForStorage(idx($rule, 'value'));
119 $rule_data[] = array(
120 'action' => $action,
121 'rule' => $rule_class,
122 'value' => $value,
126 // Filter out nonsense rules, like a "users" rule without any users
127 // actually specified.
128 $valid_rules = array();
129 foreach ($rule_data as $rule) {
130 $rule_class = $rule['rule'];
131 if ($rules[$rule_class]->ruleHasEffect($rule['value'])) {
132 $valid_rules[] = $rule;
136 if (!$valid_rules) {
137 $errors[] = pht('None of these policy rules have any effect.');
140 // NOTE: Policies are immutable once created, and we always create a new
141 // policy here. If we didn't, we would need to lock this endpoint down,
142 // as users could otherwise just go edit the policies of objects with
143 // custom policies.
145 if (!$errors) {
146 $new_policy = new PhabricatorPolicy();
147 $new_policy->setRules($valid_rules);
148 $new_policy->setDefaultAction($request->getStr('default'));
149 $new_policy->save();
151 $data = array(
152 'phid' => $new_policy->getPHID(),
153 'info' => array(
154 'name' => $new_policy->getName(),
155 'full' => $new_policy->getName(),
156 'icon' => $new_policy->getIcon(),
160 return id(new AphrontAjaxResponse())->setContent($data);
164 // Convert rule values to display format (for example, expanding PHIDs
165 // into tokens).
166 foreach ($rule_data as $key => $rule) {
167 $rule_data[$key]['value'] = $rules[$rule['rule']]->getValueForDisplay(
168 $viewer,
169 $rule['value']);
172 $default_select = AphrontFormSelectControl::renderSelectTag(
173 $default_action,
174 $action_options,
175 array(
176 'name' => 'default',
179 if ($errors) {
180 $errors = id(new PHUIInfoView())
181 ->setErrors($errors);
184 $form = id(new PHUIFormLayoutView())
185 ->appendChild($errors)
186 ->appendChild(
187 javelin_tag(
188 'input',
189 array(
190 'type' => 'hidden',
191 'name' => 'rules',
192 'sigil' => 'rules',
194 ->appendChild(
195 id(new PHUIFormInsetView())
196 ->setTitle(pht('Rules'))
197 ->setRightButton(
198 javelin_tag(
199 'a',
200 array(
201 'href' => '#',
202 'class' => 'button button-green',
203 'sigil' => 'create-rule',
204 'mustcapture' => true,
206 pht('New Rule')))
207 ->setDescription(pht('These rules are processed in order.'))
208 ->setContent(javelin_tag(
209 'table',
210 array(
211 'sigil' => 'rules',
212 'class' => 'policy-rules-table',
214 '')))
215 ->appendChild(
216 id(new AphrontFormMarkupControl())
217 ->setLabel(pht('If No Rules Match'))
218 ->setValue(pht(
219 '%s all other users.',
220 $default_select)));
222 $form = phutil_tag(
223 'div',
224 array(
225 'id' => $root_id,
227 $form);
229 $rule_options = mpull($rules, 'getRuleDescription');
230 $type_map = mpull($rules, 'getValueControlType');
231 $templates = mpull($rules, 'getValueControlTemplate');
233 require_celerity_resource('policy-edit-css');
234 Javelin::initBehavior(
235 'policy-rule-editor',
236 array(
237 'rootID' => $root_id,
238 'actions' => $action_options,
239 'rules' => $rule_options,
240 'types' => $type_map,
241 'templates' => $templates,
242 'data' => $rule_data,
243 'defaultRule' => $default_rule,
246 $title = pht('Custom Policy');
248 $key = $request->getStr('capability');
249 if ($key) {
250 $capability = PhabricatorPolicyCapability::getCapabilityByKey($key);
251 $title = pht('Custom "%s" Policy', $capability->getCapabilityName());
254 $dialog = id(new AphrontDialogView())
255 ->setWidth(AphrontDialogView::WIDTH_FULL)
256 ->setUser($viewer)
257 ->setTitle($title)
258 ->appendChild($form)
259 ->addSubmitButton(pht('Save Policy'))
260 ->addCancelButton('#');
262 return id(new AphrontDialogResponse())->setDialog($dialog);
265 private function handleProjectRequest(AphrontRequest $request) {
266 $viewer = $this->getViewer();
268 $errors = array();
269 $e_project = true;
271 if ($request->isFormPost()) {
272 $project_phids = $request->getArr('projectPHIDs');
273 $project_phid = head($project_phids);
275 $project = id(new PhabricatorObjectQuery())
276 ->setViewer($viewer)
277 ->withPHIDs(array($project_phid))
278 ->executeOne();
280 if ($project) {
281 // Save this project as one of the user's most recently used projects,
282 // so we'll show it by default in future menus.
284 $favorites_key = PhabricatorPolicyFavoritesSetting::SETTINGKEY;
285 $favorites = $viewer->getUserSetting($favorites_key);
286 if (!is_array($favorites)) {
287 $favorites = array();
290 // Add this, or move it to the end of the list.
291 unset($favorites[$project_phid]);
292 $favorites[$project_phid] = true;
294 $preferences = PhabricatorUserPreferences::loadUserPreferences($viewer);
296 $editor = id(new PhabricatorUserPreferencesEditor())
297 ->setActor($viewer)
298 ->setContentSourceFromRequest($request)
299 ->setContinueOnNoEffect(true)
300 ->setContinueOnMissingFields(true);
302 $xactions = array();
303 $xactions[] = $preferences->newTransaction($favorites_key, $favorites);
304 $editor->applyTransactions($preferences, $xactions);
306 $data = array(
307 'phid' => $project->getPHID(),
308 'info' => array(
309 'name' => $project->getName(),
310 'full' => $project->getName(),
311 'icon' => $project->getDisplayIconIcon(),
315 return id(new AphrontAjaxResponse())->setContent($data);
316 } else {
317 $errors[] = pht('You must choose a project.');
318 $e_project = pht('Required');
322 $project_datasource = id(new PhabricatorProjectDatasource())
323 ->setParameters(
324 array(
325 'policy' => 1,
328 $form = id(new AphrontFormView())
329 ->setUser($viewer)
330 ->appendControl(
331 id(new AphrontFormTokenizerControl())
332 ->setLabel(pht('Members Of'))
333 ->setName('projectPHIDs')
334 ->setLimit(1)
335 ->setError($e_project)
336 ->setDatasource($project_datasource));
338 return $this->newDialog()
339 ->setWidth(AphrontDialogView::WIDTH_FORM)
340 ->setErrors($errors)
341 ->setTitle(pht('Select Project'))
342 ->appendForm($form)
343 ->addSubmitButton(pht('Done'))
344 ->addCancelButton('#');