diff --git a/resources/sql/autopatches/20141011.phortunemerchedit.sql b/resources/sql/autopatches/20141011.phortunemerchedit.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20141011.phortunemerchedit.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_phortune.phortune_merchant + DROP editPolicy; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2582,11 +2582,13 @@ 'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php', 'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php', 'PhortuneMemberHasAccountEdgeType' => 'applications/phortune/edge/PhortuneMemberHasAccountEdgeType.php', + 'PhortuneMemberHasMerchantEdgeType' => 'applications/phortune/edge/PhortuneMemberHasMerchantEdgeType.php', 'PhortuneMerchant' => 'applications/phortune/storage/PhortuneMerchant.php', 'PhortuneMerchantCapability' => 'applications/phortune/capability/PhortuneMerchantCapability.php', 'PhortuneMerchantController' => 'applications/phortune/controller/PhortuneMerchantController.php', 'PhortuneMerchantEditController' => 'applications/phortune/controller/PhortuneMerchantEditController.php', 'PhortuneMerchantEditor' => 'applications/phortune/editor/PhortuneMerchantEditor.php', + 'PhortuneMerchantHasMemberEdgeType' => 'applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php', 'PhortuneMerchantListController' => 'applications/phortune/controller/PhortuneMerchantListController.php', 'PhortuneMerchantPHIDType' => 'applications/phortune/phid/PhortuneMerchantPHIDType.php', 'PhortuneMerchantQuery' => 'applications/phortune/query/PhortuneMerchantQuery.php', @@ -5644,6 +5646,7 @@ 'PhortuneErrCode' => 'PhortuneConstants', 'PhortuneLandingController' => 'PhortuneController', 'PhortuneMemberHasAccountEdgeType' => 'PhabricatorEdgeType', + 'PhortuneMemberHasMerchantEdgeType' => 'PhabricatorEdgeType', 'PhortuneMerchant' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', @@ -5652,6 +5655,7 @@ 'PhortuneMerchantController' => 'PhortuneController', 'PhortuneMerchantEditController' => 'PhortuneMerchantController', 'PhortuneMerchantEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhortuneMerchantHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhortuneMerchantListController' => 'PhortuneMerchantController', 'PhortuneMerchantPHIDType' => 'PhabricatorPHIDType', 'PhortuneMerchantQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', diff --git a/src/applications/phortune/controller/PhortuneAccountListController.php b/src/applications/phortune/controller/PhortuneAccountListController.php --- a/src/applications/phortune/controller/PhortuneAccountListController.php +++ b/src/applications/phortune/controller/PhortuneAccountListController.php @@ -18,11 +18,7 @@ $merchants = id(new PhortuneMerchantQuery()) ->setViewer($viewer) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) + ->withMemberPHIDs(array($viewer->getPHID())) ->execute(); $title = pht('Accounts'); diff --git a/src/applications/phortune/controller/PhortuneMerchantEditController.php b/src/applications/phortune/controller/PhortuneMerchantEditController.php --- a/src/applications/phortune/controller/PhortuneMerchantEditController.php +++ b/src/applications/phortune/controller/PhortuneMerchantEditController.php @@ -32,6 +32,7 @@ PhortuneMerchantCapability::CAPABILITY); $merchant = PhortuneMerchant::initializeNewMerchant($viewer); + $merchant->attachMemberPHIDs(array($viewer->getPHID())); $is_new = true; } @@ -52,6 +53,8 @@ $e_name = true; $v_name = $merchant->getName(); $v_desc = $merchant->getDescription(); + $v_members = $merchant->getMemberPHIDs(); + $e_members = null; $validation_exception = null; if ($request->isFormPost()) { @@ -59,11 +62,14 @@ $v_desc = $request->getStr('desc'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); + $v_members = $request->getArr('memberPHIDs'); $type_name = PhortuneMerchantTransaction::TYPE_NAME; $type_desc = PhortuneMerchantTransaction::TYPE_DESCRIPTION; + $type_edge = PhabricatorTransactions::TYPE_EDGE; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; - $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; + + $edge_members = PhortuneMerchantHasMemberEdgeType::EDGECONST; $xactions = array(); @@ -80,8 +86,12 @@ ->setNewValue($v_view); $xactions[] = id(new PhortuneMerchantTransaction()) - ->setTransactionType($type_edit) - ->setNewValue($v_edit); + ->setTransactionType($type_edge) + ->setMetadataValue('edge:type', $edge_members) + ->setNewValue( + array( + '=' => array_fuse($v_members), + )); $editor = id(new PhortuneMerchantEditor()) ->setActor($viewer) @@ -98,9 +108,9 @@ $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); + $e_mbmers = $ex->getShortMessage($type_edge); $merchant->setViewPolicy($v_view); - $merchant->setEditPolicy($v_edit); } } @@ -109,6 +119,8 @@ ->setObject($merchant) ->execute(); + $member_handles = $this->loadViewerHandles($v_members); + $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( @@ -123,18 +135,19 @@ ->setLabel(pht('Description')) ->setValue($v_desc)) ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setDatasource(new PhabricatorPeopleDatasource()) + ->setLabel(pht('Members')) + ->setName('memberPHIDs') + ->setValue($member_handles) + ->setError($e_members)) + ->appendChild( id(new AphrontFormPolicyControl()) ->setName('viewPolicy') ->setPolicyObject($merchant) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicies($policies)) ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('editPolicy') - ->setPolicyObject($merchant) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) - ->setPolicies($policies)) - ->appendChild( id(new AphrontFormSubmitControl()) ->setValue($button_text) ->addCancelButton($cancel_uri)); diff --git a/src/applications/phortune/controller/PhortuneMerchantViewController.php b/src/applications/phortune/controller/PhortuneMerchantViewController.php --- a/src/applications/phortune/controller/PhortuneMerchantViewController.php +++ b/src/applications/phortune/controller/PhortuneMerchantViewController.php @@ -140,6 +140,12 @@ $view->addProperty(pht('Status'), $status_view); + $this->loadHandles($merchant->getMemberPHIDs()); + + $view->addProperty( + pht('Members'), + $this->renderHandlesForPHIDs($merchant->getMemberPHIDs())); + $view->invokeWillRenderEvent(); $description = $merchant->getDescription(); diff --git a/src/applications/phortune/edge/PhortuneMemberHasMerchantEdgeType.php b/src/applications/phortune/edge/PhortuneMemberHasMerchantEdgeType.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/edge/PhortuneMemberHasMerchantEdgeType.php @@ -0,0 +1,12 @@ +setDescription($xaction->getNewValue()); return; + case PhabricatorTransactions::TYPE_EDGE: + return; } return parent::applyCustomInternalTransaction($object, $xaction); @@ -71,6 +73,7 @@ switch ($xaction->getTransactionType()) { case PhortuneMerchantTransaction::TYPE_NAME: case PhortuneMerchantTransaction::TYPE_DESCRIPTION: + case PhabricatorTransactions::TYPE_EDGE: return; } diff --git a/src/applications/phortune/query/PhortuneMerchantQuery.php b/src/applications/phortune/query/PhortuneMerchantQuery.php --- a/src/applications/phortune/query/PhortuneMerchantQuery.php +++ b/src/applications/phortune/query/PhortuneMerchantQuery.php @@ -5,6 +5,7 @@ private $ids; private $phids; + private $memberPHIDs; public function withIDs(array $ids) { $this->ids = $ids; @@ -16,14 +17,20 @@ return $this; } + public function withMemberPHIDs(array $member_phids) { + $this->memberPHIDs = $member_phids; + return $this; + } + protected function loadPage() { $table = new PhortuneMerchant(); $conn = $table->establishConnection('r'); $rows = queryfx_all( $conn, - 'SELECT * FROM %T %Q %Q %Q', + 'SELECT m.* FROM %T m %Q %Q %Q %Q', $table->getTableName(), + $this->buildJoinClause($conn), $this->buildWhereClause($conn), $this->buildOrderClause($conn), $this->buildLimitClause($conn)); @@ -31,6 +38,21 @@ return $table->loadAllFromArray($rows); } + protected function willFilterPage(array $merchants) { + $query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(mpull($merchants, 'getPHID')) + ->withEdgeTypes(array(PhortuneMerchantHasMemberEdgeType::EDGECONST)); + $query->execute(); + + foreach ($merchants as $merchant) { + $member_phids = $query->getDestinationPHIDs(array($merchant->getPHID())); + $member_phids = array_reverse($member_phids); + $merchant->attachMemberPHIDs($member_phids); + } + + return $merchants; + } + private function buildWhereClause(AphrontDatabaseConnection $conn) { $where = array(); @@ -48,11 +70,32 @@ $this->phids); } + if ($this->memberPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'e.dst IN (%Ls)', + $this->memberPHIDs); + } + $where[] = $this->buildPagingClause($conn); return $this->formatWhereClause($where); } + private function buildJoinClause(AphrontDatabaseConnection $conn) { + $joins = array(); + + if ($this->memberPHIDs !== null) { + $joins[] = qsprintf( + $conn, + 'LEFT JOIN %T e ON m.phid = e.src AND e.type = %d', + PhabricatorEdgeConfig::TABLE_NAME_EDGE, + PhortuneMerchantHasMemberEdgeType::EDGECONST); + } + + return implode(' ', $joins); + } + public function getQueryApplicationClass() { return 'PhabricatorPhortuneApplication'; } diff --git a/src/applications/phortune/storage/PhortuneMerchant.php b/src/applications/phortune/storage/PhortuneMerchant.php --- a/src/applications/phortune/storage/PhortuneMerchant.php +++ b/src/applications/phortune/storage/PhortuneMerchant.php @@ -5,13 +5,14 @@ protected $name; protected $viewPolicy; - protected $editPolicy; protected $description; + private $memberPHIDs = self::ATTACHABLE; + public static function initializeNewMerchant(PhabricatorUser $actor) { return id(new PhortuneMerchant()) ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) - ->setEditPolicy($actor->getPHID()); + ->attachMemberPHIDs(array()); } public function getConfiguration() { @@ -29,6 +30,15 @@ PhortuneMerchantPHIDType::TYPECONST); } + public function getMemberPHIDs() { + return $this->assertAttached($this->memberPHIDs); + } + + public function attachMemberPHIDs(array $member_phids) { + $this->memberPHIDs = $member_phids; + return $this; + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ @@ -45,16 +55,21 @@ case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: - return $this->getEditPolicy(); + return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + $members = array_fuse($this->getMemberPHIDs()); + if (isset($members[$viewer->getPHID()])) { + return true; + } + return false; } public function describeAutomaticCapability($capability) { - return null; + return pht("A merchant's members an always view and edit it."); } }