public function getSearchFields($object)
 {
     $fields = array();
     if (PhabricatorSpacesNamespaceQuery::getSpacesExist()) {
         $fields[] = id(new PhabricatorSpacesSearchField())->setKey('spacePHIDs')->setConduitKey('spaces')->setAliases(array('space', 'spaces'))->setLabel(pht('Spaces'))->setDescription(pht('Search for objects in certain spaces.'));
     }
     return $fields;
 }
 public function buildManagementPanelContent()
 {
     $repository = $this->getRepository();
     $viewer = $this->getViewer();
     $view = id(new PHUIPropertyListView())->setViewer($viewer)->setActionList($this->newActions());
     $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions($viewer, $repository);
     $view_parts = array();
     if (PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) {
         $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($repository);
         $view_parts[] = $viewer->renderHandle($space_phid);
     }
     $view_parts[] = $descriptions[PhabricatorPolicyCapability::CAN_VIEW];
     $view->addProperty(pht('Visible To'), phutil_implode_html(" · ", $view_parts));
     $view->addProperty(pht('Editable By'), $descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
     $pushable = $repository->isHosted() ? $descriptions[DiffusionPushCapability::CAPABILITY] : phutil_tag('em', array(), pht('Not a Hosted Repository'));
     $view->addProperty(pht('Pushable By'), $pushable);
     return $this->newBox(pht('Policies'), $view);
 }
 private function appendSpaceInformation(AphrontDialogView $dialog, PhabricatorPolicyInterface $object, PhabricatorPolicy $policy, $capability)
 {
     $viewer = $this->getViewer();
     if (!$object instanceof PhabricatorSpacesInterface) {
         return;
     }
     if (!PhabricatorSpacesNamespaceQuery::getSpacesExist($viewer)) {
         return;
     }
     // NOTE: We're intentionally letting users through here, even if they only
     // have access to one space. The intent is to help users in "space jail"
     // understand who objects they create are visible to:
     $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
     $handles = $viewer->loadHandles(array($space_phid));
     $doc_href = PhabricatorEnv::getDoclink('Spaces User Guide');
     $dialog->appendParagraph(array(pht('This object is in %s, and can only be seen or edited by users with ' . 'access to view objects in the space.', $handles[$space_phid]->renderLink()), ' ', phutil_tag('strong', array(), phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Learn More')))));
     $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
     $space = idx($spaces, $space_phid);
     if (!$space) {
         return;
     }
     $space_policies = PhabricatorPolicyQuery::loadPolicies($viewer, $space);
     $space_policy = idx($space_policies, PhabricatorPolicyCapability::CAN_VIEW);
     if (!$space_policy) {
         return;
     }
     $space_explanation = PhabricatorPolicy::getPolicyExplanation($viewer, $space_policy->getPHID());
     $items = array();
     $items[] = $space_explanation;
     foreach ($items as $key => $item) {
         $items[$key] = phutil_tag('li', array(), $item);
     }
     $dialog->appendParagraph(pht('Users who can see objects in this space:'));
     $dialog->appendChild(phutil_tag('ul', array(), $items));
     $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
     if ($capability == $view_capability) {
         $stronger = $space_policy->isStrongerThan($policy);
         if ($stronger) {
             $dialog->appendParagraph(pht('The space this object is in has a more restrictive view ' . 'policy ("%s") than the object does ("%s"), so the space\'s ' . 'view policy is shown as a hint instead of the object policy.', $space_policy->getShortName(), $policy->getShortName()));
         }
     }
     $dialog->appendParagraph(pht('After a user passes space policy checks, they must still pass ' . 'object policy checks.'));
 }
 public function render()
 {
     $object = $this->getObject();
     $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
     if (!$space_phid) {
         return null;
     }
     // If the viewer can't see spaces, pretend they don't exist.
     $viewer = $this->getUser();
     if (!PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) {
         return null;
     }
     // If this is the default space, don't show a space label.
     $default = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
     if ($default) {
         if ($default->getPHID() == $space_phid) {
             return null;
         }
     }
     return phutil_tag('span', array('class' => 'spaces-name'), array($viewer->renderHandle($space_phid)->setUseShortName(true), ' | '));
 }
 protected final function receiveEmail(PhabricatorMetaMTAReceivedMail $mail)
 {
     $viewer = $this->getActor();
     $object = $this->getMailReceiver();
     $app_email = $this->getApplicationEmail();
     $is_new = !$object->getID();
     // If this is a new object which implements the Spaces interface and was
     // created by sending mail to an ApplicationEmail address, put the object
     // in the same Space the address is in.
     if ($is_new) {
         if ($object instanceof PhabricatorSpacesInterface) {
             if ($app_email) {
                 $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($app_email);
                 $object->setSpacePHID($space_phid);
             }
         }
     }
     $body_data = $mail->parseBody();
     $body = $body_data['body'];
     $body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
     $xactions = $this->didReceiveMail($mail, $body);
     // If this object is subscribable, subscribe all the users who were
     // recipients on the message.
     if ($object instanceof PhabricatorSubscribableInterface) {
         $subscriber_phids = $mail->loadAllRecipientPHIDs();
         if ($subscriber_phids) {
             $xactions[] = $this->newTransaction()->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)->setNewValue(array('+' => $subscriber_phids));
         }
     }
     $command_xactions = $this->processMailCommands($mail, $body_data['commands']);
     foreach ($command_xactions as $xaction) {
         $xactions[] = $xaction;
     }
     if ($this->shouldCreateCommentFromMailBody()) {
         $comment = $this->newTransaction()->getApplicationTransactionCommentObject()->setContent($body);
         $xactions[] = $this->newTransaction()->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment($comment);
     }
     $target = $object->getApplicationTransactionObject();
     $this->newEditor($mail)->setContinueOnNoEffect(true)->applyTransactions($target, $xactions);
 }
 public function buildCustomEditFields(PhabricatorEditEngine $engine, PhabricatorApplicationTransactionInterface $object)
 {
     $viewer = $engine->getViewer();
     $editor = $object->getApplicationTransactionEditor();
     $types = $editor->getTransactionTypesForObject($object);
     $types = array_fuse($types);
     $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($object)->execute();
     $map = array(PhabricatorTransactions::TYPE_VIEW_POLICY => array('key' => 'policy.view', 'aliases' => array('view'), 'capability' => PhabricatorPolicyCapability::CAN_VIEW, 'label' => pht('View Policy'), 'description' => pht('Controls who can view the object.'), 'description.conduit' => pht('Change the view policy of the object.'), 'edit' => 'view'), PhabricatorTransactions::TYPE_EDIT_POLICY => array('key' => 'policy.edit', 'aliases' => array('edit'), 'capability' => PhabricatorPolicyCapability::CAN_EDIT, 'label' => pht('Edit Policy'), 'description' => pht('Controls who can edit the object.'), 'description.conduit' => pht('Change the edit policy of the object.'), 'edit' => 'edit'), PhabricatorTransactions::TYPE_JOIN_POLICY => array('key' => 'policy.join', 'aliases' => array('join'), 'capability' => PhabricatorPolicyCapability::CAN_JOIN, 'label' => pht('Join Policy'), 'description' => pht('Controls who can join the object.'), 'description.conduit' => pht('Change the join policy of the object.'), 'edit' => 'join'));
     $fields = array();
     foreach ($map as $type => $spec) {
         if (empty($types[$type])) {
             continue;
         }
         $capability = $spec['capability'];
         $key = $spec['key'];
         $aliases = $spec['aliases'];
         $label = $spec['label'];
         $description = $spec['description'];
         $conduit_description = $spec['description.conduit'];
         $edit = $spec['edit'];
         $policy_field = id(new PhabricatorPolicyEditField())->setKey($key)->setLabel($label)->setAliases($aliases)->setIsCopyable(true)->setCapability($capability)->setPolicies($policies)->setTransactionType($type)->setEditTypeKey($edit)->setDescription($description)->setConduitDescription($conduit_description)->setConduitTypeDescription(pht('New policy PHID or constant.'))->setValue($object->getPolicy($capability));
         $fields[] = $policy_field;
         if ($object instanceof PhabricatorSpacesInterface) {
             if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
                 $type_space = PhabricatorTransactions::TYPE_SPACE;
                 if (isset($types[$type_space])) {
                     $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
                     $space_field = id(new PhabricatorSpaceEditField())->setKey('spacePHID')->setLabel(pht('Space'))->setEditTypeKey('space')->setIsCopyable(true)->setIsLockable(false)->setIsReorderable(false)->setAliases(array('space', 'policy.space'))->setTransactionType($type_space)->setDescription(pht('Select a space for the object.'))->setConduitDescription(pht('Shift the object between spaces.'))->setConduitTypeDescription(pht('New space PHID.'))->setValue($space_phid);
                     $fields[] = $space_field;
                     $space_field->setPolicyField($policy_field);
                     $policy_field->setSpaceField($space_field);
                 }
             }
         }
     }
     return $fields;
 }
 private function buildSpaceSection(PhabricatorPolicyInterface $object, PhabricatorPolicy $policy, $capability)
 {
     $viewer = $this->getViewer();
     if (!$object instanceof PhabricatorSpacesInterface) {
         return null;
     }
     if (!PhabricatorSpacesNamespaceQuery::getSpacesExist($viewer)) {
         return null;
     }
     $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
     $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
     $space = idx($spaces, $space_phid);
     if (!$space) {
         return null;
     }
     $space_policies = PhabricatorPolicyQuery::loadPolicies($viewer, $space);
     $space_policy = idx($space_policies, PhabricatorPolicyCapability::CAN_VIEW);
     if (!$space_policy) {
         return null;
     }
     $doc_href = PhabricatorEnv::getDoclink('Spaces User Guide');
     $capability_name = $this->getCapabilityName($capability);
     $space_section = id(new PHUIPolicySectionView())->setViewer($viewer)->setIcon('fa-th-large bluegrey')->setHeader(pht('Space'))->setDocumentationLink(pht('Spaces Documentation'), $doc_href)->appendList(array(array(phutil_tag('strong', array(), pht('Space:')), ' ', $viewer->renderHandle($space_phid)->setAsTag(true)), array(phutil_tag('strong', array(), pht('%s:', $capability_name)), ' ', $space_policy->getShortName())))->appendParagraph(pht('This object is in %s and can only be seen or edited by users ' . 'with access to view objects in the space.', $viewer->renderHandle($space_phid)));
     $space_explanation = PhabricatorPolicy::getPolicyExplanation($viewer, $space_policy->getPHID());
     $items = array();
     $items[] = $space_explanation;
     $space_section->appendParagraph(pht('Users who can see objects in this space:'))->appendList($items);
     $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
     if ($capability == $view_capability) {
         $stronger = $space_policy->isStrongerThan($policy);
         if ($stronger) {
             $space_section->appendHint(pht('The space this object is in has a more restrictive view ' . 'policy ("%s") than the object does ("%s"), so the space\'s ' . 'view policy is shown as a hint instead of the object policy.', $space_policy->getShortName(), $policy->getShortName()));
         }
     }
     $space_section->appendHint(pht('After a user passes space policy checks, they must still pass ' . 'object policy checks.'));
     return $space_section;
 }
 private function buildEmailTable($is_edit, $highlight)
 {
     $viewer = $this->getViewer();
     $application = $this->getApplication();
     $uri = new PhutilURI($this->getPanelURI());
     $emails = id(new PhabricatorMetaMTAApplicationEmailQuery())->setViewer($viewer)->withApplicationPHIDs(array($application->getPHID()))->execute();
     $rowc = array();
     $rows = array();
     foreach ($emails as $email) {
         $button_edit = javelin_tag('a', array('class' => 'button small grey', 'href' => $uri->alter('edit', $email->getID()), 'sigil' => 'workflow'), pht('Edit'));
         $button_remove = javelin_tag('a', array('class' => 'button small grey', 'href' => $uri->alter('delete', $email->getID()), 'sigil' => 'workflow'), pht('Delete'));
         if ($highlight == $email->getID()) {
             $rowc[] = 'highlighted';
         } else {
             $rowc[] = null;
         }
         $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($email);
         if ($space_phid) {
             $email_space = $viewer->renderHandle($space_phid);
         } else {
             $email_space = null;
         }
         $rows[] = array($email_space, $email->getAddress(), $button_edit, $button_remove);
     }
     $table = id(new AphrontTableView($rows))->setNoDataString(pht('No application emails created yet.'));
     $table->setHeaders(array(pht('Space'), pht('Email'), pht('Edit'), pht('Delete')));
     $table->setColumnClasses(array('', 'wide', 'action', 'action'));
     $table->setRowClasses($rowc);
     $table->setColumnVisibility(array(PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer), true, $is_edit, $is_edit));
     return $table;
 }
 private function validateSpaceTransactions(PhabricatorLiskDAO $object, array $xactions, $transaction_type)
 {
     $errors = array();
     $actor = $this->getActor();
     $has_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($actor);
     $actor_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($actor);
     $active_spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces($actor);
     foreach ($xactions as $xaction) {
         $space_phid = $xaction->getNewValue();
         if ($space_phid === null) {
             if (!$has_spaces) {
                 // The install doesn't have any spaces, so this is fine.
                 continue;
             }
             // The install has some spaces, so every object needs to be put
             // in a valid space.
             $errors[] = new PhabricatorApplicationTransactionValidationError($transaction_type, pht('Invalid'), pht('You must choose a space for this object.'), $xaction);
             continue;
         }
         // If the PHID isn't `null`, it needs to be a valid space that the
         // viewer can see.
         if (empty($actor_spaces[$space_phid])) {
             $errors[] = new PhabricatorApplicationTransactionValidationError($transaction_type, pht('Invalid'), pht('You can not shift this object in the selected space, because ' . 'the space does not exist or you do not have access to it.'), $xaction);
         } else {
             if (empty($active_spaces[$space_phid])) {
                 // It's OK to edit objects in an archived space, so just move on if
                 // we aren't adjusting the value.
                 $old_space_phid = $this->getTransactionOldValue($object, $xaction);
                 if ($space_phid == $old_space_phid) {
                     continue;
                 }
                 $errors[] = new PhabricatorApplicationTransactionValidationError($transaction_type, pht('Archived'), pht('You can not shift this object into the selected space, because ' . 'the space is archived. Objects can not be created inside (or ' . 'moved into) archived spaces.'), $xaction);
             }
         }
     }
     return $errors;
 }
Exemple #10
0
 public function getDefaultSpacePHID()
 {
     // TODO: We might let the user switch which space they're "in" later on;
     // for now just use the global space if one exists.
     // If the viewer has access to the default space, use that.
     $spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces($this);
     foreach ($spaces as $space) {
         if ($space->getIsDefaultNamespace()) {
             return $space->getPHID();
         }
     }
     // Otherwise, use the space with the lowest ID that they have access to.
     // This just tends to keep the default stable and predictable over time,
     // so adding a new space won't change behavior for users.
     if ($spaces) {
         $spaces = msort($spaces, 'getID');
         return head($spaces)->getPHID();
     }
     return null;
 }
 protected function buildSearchFields()
 {
     $fields = array();
     foreach ($this->buildCustomSearchFields() as $field) {
         $fields[] = $field;
     }
     $object = $this->newResultObject();
     if ($object) {
         if ($object instanceof PhabricatorSubscribableInterface) {
             $fields[] = id(new PhabricatorSearchSubscribersField())->setLabel(pht('Subscribers'))->setKey('subscriberPHIDs')->setAliases(array('subscriber', 'subscribers'));
         }
         if ($object instanceof PhabricatorProjectInterface) {
             $fields[] = id(new PhabricatorProjectSearchField())->setKey('projectPHIDs')->setAliases(array('project', 'projects'))->setLabel(pht('Projects'));
         }
         if ($object instanceof PhabricatorSpacesInterface) {
             if (PhabricatorSpacesNamespaceQuery::getSpacesExist()) {
                 $fields[] = id(new PhabricatorSpacesSearchField())->setKey('spacePHIDs')->setAliases(array('space', 'spaces'))->setLabel(pht('Spaces'));
             }
         }
     }
     foreach ($this->buildCustomFieldSearchFields() as $custom_field) {
         $fields[] = $custom_field;
     }
     $query = $this->newQuery();
     if ($query && $this->shouldShowOrderField()) {
         $orders = $query->getBuiltinOrders();
         $orders = ipull($orders, 'name');
         $fields[] = id(new PhabricatorSearchOrderField())->setLabel(pht('Order By'))->setKey('order')->setOrderAliases($query->getBuiltinOrderAliasMap())->setOptions($orders);
     }
     $field_map = array();
     foreach ($fields as $field) {
         $key = $field->getKey();
         if (isset($field_map[$key])) {
             throw new Exception(pht('Two fields in this SearchEngine use the same key ("%s"), but ' . 'each field must use a unique key.', $key));
         }
         $field_map[$key] = $field;
     }
     return $field_map;
 }
 private function buildTransactions($actions, ManiphestTask $task)
 {
     $value_map = array();
     $type_map = array('add_comment' => PhabricatorTransactions::TYPE_COMMENT, 'assign' => ManiphestTransaction::TYPE_OWNER, 'status' => ManiphestTransaction::TYPE_STATUS, 'priority' => ManiphestTransaction::TYPE_PRIORITY, 'add_project' => PhabricatorTransactions::TYPE_EDGE, 'remove_project' => PhabricatorTransactions::TYPE_EDGE, 'add_ccs' => PhabricatorTransactions::TYPE_SUBSCRIBERS, 'remove_ccs' => PhabricatorTransactions::TYPE_SUBSCRIBERS, 'space' => PhabricatorTransactions::TYPE_SPACE);
     $edge_edit_types = array('add_project' => true, 'remove_project' => true, 'add_ccs' => true, 'remove_ccs' => true);
     $xactions = array();
     foreach ($actions as $action) {
         if (empty($type_map[$action['action']])) {
             throw new Exception(pht("Unknown batch edit action '%s'!", $action));
         }
         $type = $type_map[$action['action']];
         // Figure out the current value, possibly after modifications by other
         // batch actions of the same type. For example, if the user chooses to
         // "Add Comment" twice, we should add both comments. More notably, if the
         // user chooses "Remove Project..." and also "Add Project...", we should
         // avoid restoring the removed project in the second transaction.
         if (array_key_exists($type, $value_map)) {
             $current = $value_map[$type];
         } else {
             switch ($type) {
                 case PhabricatorTransactions::TYPE_COMMENT:
                     $current = null;
                     break;
                 case ManiphestTransaction::TYPE_OWNER:
                     $current = $task->getOwnerPHID();
                     break;
                 case ManiphestTransaction::TYPE_STATUS:
                     $current = $task->getStatus();
                     break;
                 case ManiphestTransaction::TYPE_PRIORITY:
                     $current = $task->getPriority();
                     break;
                 case PhabricatorTransactions::TYPE_EDGE:
                     $current = $task->getProjectPHIDs();
                     break;
                 case PhabricatorTransactions::TYPE_SUBSCRIBERS:
                     $current = $task->getSubscriberPHIDs();
                     break;
                 case PhabricatorTransactions::TYPE_SPACE:
                     $current = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($task);
                     break;
             }
         }
         // Check if the value is meaningful / provided, and normalize it if
         // necessary. This discards, e.g., empty comments and empty owner
         // changes.
         $value = $action['value'];
         switch ($type) {
             case PhabricatorTransactions::TYPE_COMMENT:
                 if (!strlen($value)) {
                     continue 2;
                 }
                 break;
             case PhabricatorTransactions::TYPE_SPACE:
                 if (empty($value)) {
                     continue 2;
                 }
                 $value = head($value);
                 break;
             case ManiphestTransaction::TYPE_OWNER:
                 if (empty($value)) {
                     continue 2;
                 }
                 $value = head($value);
                 $no_owner = PhabricatorPeopleNoOwnerDatasource::FUNCTION_TOKEN;
                 if ($value === $no_owner) {
                     $value = null;
                 }
                 break;
             case PhabricatorTransactions::TYPE_EDGE:
                 if (empty($value)) {
                     continue 2;
                 }
                 break;
             case PhabricatorTransactions::TYPE_SUBSCRIBERS:
                 if (empty($value)) {
                     continue 2;
                 }
                 break;
         }
         // If the edit doesn't change anything, go to the next action. This
         // check is only valid for changes like "owner", "status", etc, not
         // for edge edits, because we should still apply an edit like
         // "Remove Projects: A, B" to a task with projects "A, B".
         if (empty($edge_edit_types[$action['action']])) {
             if ($value == $current) {
                 continue;
             }
         }
         // Apply the value change; for most edits this is just replacement, but
         // some need to merge the current and edited values (add/remove project).
         switch ($type) {
             case PhabricatorTransactions::TYPE_COMMENT:
                 if (strlen($current)) {
                     $value = $current . "\n\n" . $value;
                 }
                 break;
             case PhabricatorTransactions::TYPE_EDGE:
                 $is_remove = $action['action'] == 'remove_project';
                 $current = array_fill_keys($current, true);
                 $value = array_fill_keys($value, true);
                 $new = $current;
                 $did_something = false;
                 if ($is_remove) {
                     foreach ($value as $phid => $ignored) {
                         if (isset($new[$phid])) {
                             unset($new[$phid]);
                             $did_something = true;
                         }
                     }
                 } else {
                     foreach ($value as $phid => $ignored) {
                         if (empty($new[$phid])) {
                             $new[$phid] = true;
                             $did_something = true;
                         }
                     }
                 }
                 if (!$did_something) {
                     continue 2;
                 }
                 $value = array_keys($new);
                 break;
             case PhabricatorTransactions::TYPE_SUBSCRIBERS:
                 $is_remove = $action['action'] == 'remove_ccs';
                 $current = array_fill_keys($current, true);
                 $new = array();
                 $did_something = false;
                 if ($is_remove) {
                     foreach ($value as $phid) {
                         if (isset($current[$phid])) {
                             $new[$phid] = true;
                             $did_something = true;
                         }
                     }
                     if ($new) {
                         $value = array('-' => array_keys($new));
                     }
                 } else {
                     $new = array();
                     foreach ($value as $phid) {
                         $new[$phid] = true;
                         $did_something = true;
                     }
                     if ($new) {
                         $value = array('+' => array_keys($new));
                     }
                 }
                 if (!$did_something) {
                     continue 2;
                 }
                 break;
         }
         $value_map[$type] = $value;
     }
     $template = new ManiphestTransaction();
     foreach ($value_map as $type => $value) {
         $xaction = clone $template;
         $xaction->setTransactionType($type);
         switch ($type) {
             case PhabricatorTransactions::TYPE_COMMENT:
                 $xaction->attachComment(id(new ManiphestTransactionComment())->setContent($value));
                 break;
             case PhabricatorTransactions::TYPE_EDGE:
                 $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
                 $xaction->setMetadataValue('edge:type', $project_type)->setNewValue(array('=' => array_fuse($value)));
                 break;
             default:
                 $xaction->setNewValue($value);
                 break;
         }
         $xactions[] = $xaction;
     }
     return $xactions;
 }
Exemple #13
0
 public function getHeraldField($field_name)
 {
     switch ($field_name) {
         case self::FIELD_RULE:
             return null;
         case self::FIELD_CONTENT_SOURCE:
             return $this->getContentSource()->getSource();
         case self::FIELD_ALWAYS:
             return true;
         case self::FIELD_IS_NEW_OBJECT:
             return $this->getIsNewObject();
         case self::FIELD_CC:
             $object = $this->getObject();
             if (!$object instanceof PhabricatorSubscribableInterface) {
                 throw new Exception(pht('Adapter object (of class "%s") does not implement interface ' . '"%s", so the subscribers field value can not be determined.', get_class($object), 'PhabricatorSubscribableInterface'));
             }
             $phid = $object->getPHID();
             return PhabricatorSubscribersQuery::loadSubscribersForPHID($phid);
         case self::FIELD_APPLICATION_EMAIL:
             $value = array();
             // while there is only one match by implementation, we do set
             // comparisons on phids, so return an array with just the phid
             if ($this->getApplicationEmail()) {
                 $value[] = $this->getApplicationEmail()->getPHID();
             }
             return $value;
         case self::FIELD_SPACE:
             $object = $this->getObject();
             if (!$object instanceof PhabricatorSpacesInterface) {
                 throw new Exception(pht('Adapter object (of class "%s") does not implement interface ' . '"%s", so the Space field value can not be determined.', get_class($object), 'PhabricatorSpacesInterface'));
             }
             return PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
         default:
             if ($this->isHeraldCustomKey($field_name)) {
                 return $this->getCustomFieldValue($field_name);
             }
             throw new Exception(pht("Unknown field '%s'!", $field_name));
     }
 }
 private function destroyAllSpaces()
 {
     PhabricatorSpacesNamespaceQuery::destroySpacesCache();
     $spaces = $this->loadAllSpaces();
     foreach ($spaces as $space) {
         $engine = new PhabricatorDestructionEngine();
         $engine->destroyObject($space);
     }
 }
 public function getHeraldFieldValue($object)
 {
     return PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
 }
 private function renderPolicyProperty(PhabricatorPolicyInterface $object)
 {
     $viewer = $this->getUser();
     $policies = PhabricatorPolicyQuery::loadPolicies($viewer, $object);
     $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
     $policy = idx($policies, $view_capability);
     if (!$policy) {
         return null;
     }
     // If an object is in a Space with a strictly stronger (more restrictive)
     // policy, we show the more restrictive policy. This better aligns the
     // UI hint with the actual behavior.
     // NOTE: We'll do this even if the viewer has access to only one space, and
     // show them information about the existence of spaces if they click
     // through.
     $use_space_policy = false;
     if ($object instanceof PhabricatorSpacesInterface) {
         $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object);
         $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
         $space = idx($spaces, $space_phid);
         if ($space) {
             $space_policies = PhabricatorPolicyQuery::loadPolicies($viewer, $space);
             $space_policy = idx($space_policies, $view_capability);
             if ($space_policy) {
                 if ($space_policy->isStrongerThan($policy)) {
                     $policy = $space_policy;
                     $use_space_policy = true;
                 }
             }
         }
     }
     $container_classes = array();
     $container_classes[] = 'policy-header-callout';
     $phid = $object->getPHID();
     // If we're going to show the object policy, try to determine if the object
     // policy differs from the default policy. If it does, we'll call it out
     // as changed.
     if (!$use_space_policy) {
         $default_policy = PhabricatorPolicyQuery::getDefaultPolicyForObject($viewer, $object, $view_capability);
         if ($default_policy) {
             if ($default_policy->getPHID() != $policy->getPHID()) {
                 $container_classes[] = 'policy-adjusted';
                 if ($default_policy->isStrongerThan($policy)) {
                     // The policy has strictly been weakened. For example, the
                     // default might be "All Users" and the current policy is "Public".
                     $container_classes[] = 'policy-adjusted-weaker';
                 } else {
                     if ($policy->isStrongerThan($default_policy)) {
                         // The policy has strictly been strengthened, and is now more
                         // restrictive than the default. For example, "All Users" has
                         // been replaced with "No One".
                         $container_classes[] = 'policy-adjusted-stronger';
                     } else {
                         // The policy has been adjusted but not strictly strengthened
                         // or weakened. For example, "Members of X" has been replaced with
                         // "Members of Y".
                         $container_classes[] = 'policy-adjusted-different';
                     }
                 }
             }
         }
     }
     $icon = id(new PHUIIconView())->setIcon($policy->getIcon() . ' bluegrey');
     $link = javelin_tag('a', array('class' => 'policy-link', 'href' => '/policy/explain/' . $phid . '/' . $view_capability . '/', 'sigil' => 'workflow'), $policy->getShortName());
     return phutil_tag('span', array('class' => implode(' ', $container_classes)), array($icon, $link));
 }
 private function canViewerSeeObjectsInSpace(PhabricatorUser $viewer, $space_phid)
 {
     $spaces = PhabricatorSpacesNamespaceQuery::getAllSpaces();
     // If there are no spaces, everything exists in an implicit default space
     // with no policy controls. This is the default state.
     if (!$spaces) {
         if ($space_phid !== null) {
             return false;
         } else {
             return true;
         }
     }
     if ($space_phid === null) {
         $space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
     } else {
         $space = idx($spaces, $space_phid);
     }
     if (!$space) {
         return false;
     }
     // This may be more involved later, but for now being able to see the
     // space is equivalent to being able to see everything in it.
     return self::hasCapability($viewer, $space, PhabricatorPolicyCapability::CAN_VIEW);
 }
 /**
  * Constrain the query to include only results in valid Spaces.
  *
  * This method builds part of a WHERE clause which considers the spaces the
  * viewer has access to see with any explicit constraint on spaces added by
  * @{method:withSpacePHIDs}.
  *
  * @param AphrontDatabaseConnection Database connection.
  * @return string Part of a WHERE clause.
  * @task spaces
  */
 private function buildSpacesWhereClause(AphrontDatabaseConnection $conn)
 {
     $object = $this->newResultObject();
     if (!$object) {
         return null;
     }
     if (!$object instanceof PhabricatorSpacesInterface) {
         return null;
     }
     $viewer = $this->getViewer();
     // If we have an omnipotent viewer and no formal space constraints, don't
     // emit a clause. This primarily enables older migrations to run cleanly,
     // without fataling because they try to match a `spacePHID` column which
     // does not exist yet. See T8743, T8746.
     if ($viewer->isOmnipotent()) {
         if ($this->spaceIsArchived === null && $this->spacePHIDs === null) {
             return null;
         }
     }
     $space_phids = array();
     $include_null = false;
     $all = PhabricatorSpacesNamespaceQuery::getAllSpaces();
     if (!$all) {
         // If there are no spaces at all, implicitly give the viewer access to
         // the default space.
         $include_null = true;
     } else {
         // Otherwise, give them access to the spaces they have permission to
         // see.
         $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
         foreach ($viewer_spaces as $viewer_space) {
             if ($this->spaceIsArchived !== null) {
                 if ($viewer_space->getIsArchived() != $this->spaceIsArchived) {
                     continue;
                 }
             }
             $phid = $viewer_space->getPHID();
             $space_phids[$phid] = $phid;
             if ($viewer_space->getIsDefaultNamespace()) {
                 $include_null = true;
             }
         }
     }
     // If we have additional explicit constraints, evaluate them now.
     if ($this->spacePHIDs !== null) {
         $explicit = array();
         $explicit_null = false;
         foreach ($this->spacePHIDs as $phid) {
             if ($phid === null) {
                 $space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
             } else {
                 $space = idx($all, $phid);
             }
             if ($space) {
                 $phid = $space->getPHID();
                 $explicit[$phid] = $phid;
                 if ($space->getIsDefaultNamespace()) {
                     $explicit_null = true;
                 }
             }
         }
         // If the viewer can see the default space but it isn't on the explicit
         // list of spaces to query, don't match it.
         if ($include_null && !$explicit_null) {
             $include_null = false;
         }
         // Include only the spaces common to the viewer and the constraints.
         $space_phids = array_intersect_key($space_phids, $explicit);
     }
     if (!$space_phids && !$include_null) {
         if ($this->spacePHIDs === null) {
             throw new PhabricatorEmptyQueryException(pht('You do not have access to any spaces.'));
         } else {
             throw new PhabricatorEmptyQueryException(pht('You do not have access to any of the spaces this query ' . 'is constrained to.'));
         }
     }
     $alias = $this->getPrimaryTableAlias();
     if ($alias) {
         $col = qsprintf($conn, '%T.spacePHID', $alias);
     } else {
         $col = 'spacePHID';
     }
     if ($space_phids && $include_null) {
         return qsprintf($conn, '(%Q IN (%Ls) OR %Q IS NULL)', $col, $space_phids, $col);
     } else {
         if ($space_phids) {
             return qsprintf($conn, '%Q IN (%Ls)', $col, $space_phids);
         } else {
             return qsprintf($conn, '%Q IS NULL', $col);
         }
     }
 }
 public function willBeginExecution()
 {
     $request = $this->getRequest();
     if ($request->getUser()) {
         // NOTE: Unit tests can set a user explicitly. Normal requests are not
         // permitted to do this.
         PhabricatorTestCase::assertExecutingUnitTests();
         $user = $request->getUser();
     } else {
         $user = new PhabricatorUser();
         $session_engine = new PhabricatorAuthSessionEngine();
         $phsid = $request->getCookie(PhabricatorCookies::COOKIE_SESSION);
         if (strlen($phsid)) {
             $session_user = $session_engine->loadUserForSession(PhabricatorAuthSession::TYPE_WEB, $phsid);
             if ($session_user) {
                 $user = $session_user;
             }
         } else {
             // If the client doesn't have a session token, generate an anonymous
             // session. This is used to provide CSRF protection to logged-out users.
             $phsid = $session_engine->establishSession(PhabricatorAuthSession::TYPE_WEB, null, $partial = false);
             // This may be a resource request, in which case we just don't set
             // the cookie.
             if ($request->canSetCookies()) {
                 $request->setCookie(PhabricatorCookies::COOKIE_SESSION, $phsid);
             }
         }
         if (!$user->isLoggedIn()) {
             $user->attachAlternateCSRFString(PhabricatorHash::digest($phsid));
         }
         $request->setUser($user);
     }
     PhabricatorEnv::setLocaleCode($user->getTranslation());
     $preferences = $user->loadPreferences();
     if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) {
         $dark_console = PhabricatorUserPreferences::PREFERENCE_DARK_CONSOLE;
         if ($preferences->getPreference($dark_console) || PhabricatorEnv::getEnvConfig('darkconsole.always-on')) {
             $console = new DarkConsoleCore();
             $request->getApplicationConfiguration()->setConsole($console);
         }
     }
     // NOTE: We want to set up the user first so we can render a real page
     // here, but fire this before any real logic.
     $restricted = array('code');
     foreach ($restricted as $parameter) {
         if ($request->getExists($parameter)) {
             if (!$this->shouldAllowRestrictedParameter($parameter)) {
                 throw new Exception(pht('Request includes restricted parameter "%s", but this ' . 'controller ("%s") does not whitelist it. Refusing to ' . 'serve this request because it might be part of a redirection ' . 'attack.', $parameter, get_class($this)));
             }
         }
     }
     if ($this->shouldRequireEnabledUser()) {
         if ($user->isLoggedIn() && !$user->getIsApproved()) {
             $controller = new PhabricatorAuthNeedsApprovalController();
             return $this->delegateToController($controller);
         }
         if ($user->getIsDisabled()) {
             $controller = new PhabricatorDisabledUserController();
             return $this->delegateToController($controller);
         }
     }
     $auth_class = 'PhabricatorAuthApplication';
     $auth_application = PhabricatorApplication::getByClass($auth_class);
     // Require partial sessions to finish login before doing anything.
     if (!$this->shouldAllowPartialSessions()) {
         if ($user->hasSession() && $user->getSession()->getIsPartial()) {
             $login_controller = new PhabricatorAuthFinishController();
             $this->setCurrentApplication($auth_application);
             return $this->delegateToController($login_controller);
         }
     }
     // Check if the user needs to configure MFA.
     $need_mfa = $this->shouldRequireMultiFactorEnrollment();
     $have_mfa = $user->getIsEnrolledInMultiFactor();
     if ($need_mfa && !$have_mfa) {
         // Check if the cache is just out of date. Otherwise, roadblock the user
         // and require MFA enrollment.
         $user->updateMultiFactorEnrollment();
         if (!$user->getIsEnrolledInMultiFactor()) {
             $mfa_controller = new PhabricatorAuthNeedsMultiFactorController();
             $this->setCurrentApplication($auth_application);
             return $this->delegateToController($mfa_controller);
         }
     }
     if ($this->shouldRequireLogin()) {
         // This actually means we need either:
         //   - a valid user, or a public controller; and
         //   - permission to see the application; and
         //   - permission to see at least one Space if spaces are configured.
         $allow_public = $this->shouldAllowPublic() && PhabricatorEnv::getEnvConfig('policy.allow-public');
         // If this controller isn't public, and the user isn't logged in, require
         // login.
         if (!$allow_public && !$user->isLoggedIn()) {
             $login_controller = new PhabricatorAuthStartController();
             $this->setCurrentApplication($auth_application);
             return $this->delegateToController($login_controller);
         }
         if ($user->isLoggedIn()) {
             if ($this->shouldRequireEmailVerification()) {
                 if (!$user->getIsEmailVerified()) {
                     $controller = new PhabricatorMustVerifyEmailController();
                     $this->setCurrentApplication($auth_application);
                     return $this->delegateToController($controller);
                 }
             }
         }
         // If Spaces are configured, require that the user have access to at
         // least one. If we don't do this, they'll get confusing error messages
         // later on.
         $spaces = PhabricatorSpacesNamespaceQuery::getSpacesExist();
         if ($spaces) {
             $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($user);
             if (!$viewer_spaces) {
                 $controller = new PhabricatorSpacesNoAccessController();
                 return $this->delegateToController($controller);
             }
         }
         // If the user doesn't have access to the application, don't let them use
         // any of its controllers. We query the application in order to generate
         // a policy exception if the viewer doesn't have permission.
         $application = $this->getCurrentApplication();
         if ($application) {
             id(new PhabricatorApplicationQuery())->setViewer($user)->withPHIDs(array($application->getPHID()))->executeOne();
         }
     }
     if (!$this->shouldAllowLegallyNonCompliantUsers()) {
         $legalpad_class = 'PhabricatorLegalpadApplication';
         $legalpad = id(new PhabricatorApplicationQuery())->setViewer($user)->withClasses(array($legalpad_class))->withInstalled(true)->execute();
         $legalpad = head($legalpad);
         $doc_query = id(new LegalpadDocumentQuery())->setViewer($user)->withSignatureRequired(1)->needViewerSignatures(true);
         if ($user->hasSession() && !$user->getSession()->getIsPartial() && !$user->getSession()->getSignedLegalpadDocuments() && $user->isLoggedIn() && $legalpad) {
             $sign_docs = $doc_query->execute();
             $must_sign_docs = array();
             foreach ($sign_docs as $sign_doc) {
                 if (!$sign_doc->getUserSignature($user->getPHID())) {
                     $must_sign_docs[] = $sign_doc;
                 }
             }
             if ($must_sign_docs) {
                 $controller = new LegalpadDocumentSignController();
                 $this->getRequest()->setURIMap(array('id' => head($must_sign_docs)->getID()));
                 $this->setCurrentApplication($legalpad);
                 return $this->delegateToController($controller);
             } else {
                 $engine = id(new PhabricatorAuthSessionEngine())->signLegalpadDocuments($user, $sign_docs);
             }
         }
     }
     // NOTE: We do this last so that users get a login page instead of a 403
     // if they need to login.
     if ($this->shouldRequireAdmin() && !$user->getIsAdmin()) {
         return new Aphront403Response();
     }
 }
 private function buildSpacesControl()
 {
     if ($this->capability != PhabricatorPolicyCapability::CAN_VIEW) {
         return null;
     }
     if (!$this->object instanceof PhabricatorSpacesInterface) {
         return null;
     }
     $viewer = $this->getUser();
     if (!PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) {
         return null;
     }
     $space_phid = $this->getSpacePHID();
     if ($space_phid === null) {
         $space_phid = $viewer->getDefaultSpacePHID();
     }
     $select = AphrontFormSelectControl::renderSelectTag($space_phid, PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer($viewer, $space_phid), array('disabled' => $this->getDisabled(), 'name' => 'spacePHID', 'class' => 'aphront-space-select-control-knob'));
     return $select;
 }