diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 333d618dae..085d006bec 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2853,6 +2853,7 @@ phutil_register_library_map(array( 'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', + 'PhabricatorProjectLockController' => 'applications/project/controller/PhabricatorProjectLockController.php', 'PhabricatorProjectLogicalAndDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php', 'PhabricatorProjectLogicalDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalDatasource.php', 'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php', @@ -7198,6 +7199,7 @@ phutil_register_library_map(array( 'PhabricatorProjectHeraldAction' => 'HeraldAction', 'PhabricatorProjectIconSet' => 'PhabricatorIconSet', 'PhabricatorProjectListController' => 'PhabricatorProjectController', + 'PhabricatorProjectLockController' => 'PhabricatorProjectController', 'PhabricatorProjectLogicalAndDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource', diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php index b1bfd16f6e..6936faa7fc 100644 --- a/src/applications/project/application/PhabricatorProjectApplication.php +++ b/src/applications/project/application/PhabricatorProjectApplication.php @@ -47,6 +47,8 @@ final class PhabricatorProjectApplication extends PhabricatorApplication { => 'PhabricatorProjectEditDetailsController', 'archive/(?P[1-9]\d*)/' => 'PhabricatorProjectArchiveController', + 'lock/(?P[1-9]\d*)/' + => 'PhabricatorProjectLockController', 'members/(?P[1-9]\d*)/' => 'PhabricatorProjectMembersEditController', 'members/(?P[1-9]\d*)/remove/' diff --git a/src/applications/project/controller/PhabricatorProjectEditDetailsController.php b/src/applications/project/controller/PhabricatorProjectEditDetailsController.php index d3a3fb6374..46287f3801 100644 --- a/src/applications/project/controller/PhabricatorProjectEditDetailsController.php +++ b/src/applications/project/controller/PhabricatorProjectEditDetailsController.php @@ -54,7 +54,6 @@ final class PhabricatorProjectEditDetailsController $v_slugs = $project_slugs; $v_color = $project->getColor(); $v_icon = $project->getIcon(); - $v_locked = $project->getIsMembershipLocked(); $validation_exception = null; @@ -69,14 +68,12 @@ final class PhabricatorProjectEditDetailsController $v_join = $request->getStr('can_join'); $v_color = $request->getStr('color'); $v_icon = $request->getStr('icon'); - $v_locked = $request->getInt('is_membership_locked', 0); $type_name = PhabricatorProjectTransaction::TYPE_NAME; $type_slugs = PhabricatorProjectTransaction::TYPE_SLUGS; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $type_icon = PhabricatorProjectTransaction::TYPE_ICON; $type_color = PhabricatorProjectTransaction::TYPE_COLOR; - $type_locked = PhabricatorProjectTransaction::TYPE_LOCKED; $xactions = array(); @@ -108,10 +105,6 @@ final class PhabricatorProjectEditDetailsController ->setTransactionType($type_color) ->setNewValue($v_color); - $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType($type_locked) - ->setNewValue($v_locked); - $xactions = array_merge( $xactions, $field_list->buildFieldTransactionsFromRequest( @@ -190,11 +183,6 @@ final class PhabricatorProjectEditDetailsController $shades = PhabricatorProjectIconSet::getColorMap(); - list($can_lock, $lock_message) = $this->explainApplicationCapability( - ProjectCanLockProjectsCapability::CAPABILITY, - pht('You can update the Lock Project setting.'), - pht('You can not update the Lock Project setting.')); - $form ->appendChild( id(new PHUIFormIconSetControl()) @@ -249,17 +237,7 @@ final class PhabricatorProjectEditDetailsController pht('Users who can edit a project can always join a project.')) ->setPolicyObject($project) ->setPolicies($policies) - ->setCapability(PhabricatorPolicyCapability::CAN_JOIN)) - ->appendChild( - id(new AphrontFormCheckboxControl()) - ->setLabel(pht('Lock Project')) - ->setDisabled(!$can_lock) - ->addCheckbox( - 'is_membership_locked', - 1, - pht('Prevent members from leaving this project.'), - $v_locked) - ->setCaption($lock_message)); + ->setCapability(PhabricatorPolicyCapability::CAN_JOIN)); if ($request->isAjax()) { $errors = array(); diff --git a/src/applications/project/controller/PhabricatorProjectLockController.php b/src/applications/project/controller/PhabricatorProjectLockController.php new file mode 100644 index 0000000000..744be32f99 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectLockController.php @@ -0,0 +1,76 @@ +getViewer(); + + $this->requireApplicationCapability( + ProjectCanLockProjectsCapability::CAPABILITY); + + $id = $request->getURIData('id'); + $project = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$project) { + return new Aphront404Response(); + } + + $done_uri = $project->getURI(); + $is_locked = $project->getIsMembershipLocked(); + + if ($request->isFormPost()) { + $xactions = array(); + + if ($is_locked) { + $new_value = 0; + } else { + $new_value = 1; + } + + $xactions[] = id(new PhabricatorProjectTransaction()) + ->setTransactionType(PhabricatorProjectTransaction::TYPE_LOCKED) + ->setNewValue($new_value); + + $editor = id(new PhabricatorProjectTransactionEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->applyTransactions($project, $xactions); + + return id(new AphrontRedirectResponse())->setURI($done_uri); + } + + if ($project->getIsMembershipLocked()) { + $title = pht('Unlock Project'); + $body = pht( + 'If you unlock this project, members will be free to leave.'); + $button = pht('Unlock Project'); + } else { + $title = pht('Lock Project'); + $body = pht( + 'If you lock this project, members will be prevented from '. + 'leaving it.'); + $button = pht('Lock Project'); + } + + return $this->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addSubmitbutton($button) + ->addCancelButton($done_uri); + } + +} diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index fa443ebf6e..409fd49202 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -106,6 +106,25 @@ final class PhabricatorProjectProfileController ->setWorkflow(true)); } + $can_lock = $can_edit && $this->hasApplicationCapability( + ProjectCanLockProjectsCapability::CAPABILITY); + + if ($project->getIsMembershipLocked()) { + $lock_name = pht('Unlock Project'); + $lock_icon = 'fa-unlock'; + } else { + $lock_name = pht('Lock Project'); + $lock_icon = 'fa-lock'; + } + + $view->addAction( + id(new PhabricatorActionView()) + ->setName($lock_name) + ->setIcon($lock_icon) + ->setHref($this->getApplicationURI("lock/{$id}/")) + ->setDisabled(!$can_lock) + ->setWorkflow(true)); + $action = null; if (!$project->isUserMember($viewer->getPHID())) { $can_join = PhabricatorPolicyFilter::hasCapability(