mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 01:02:42 +01:00
Allow task statuses to "lock" them, preventing additional comments and interactions
Summary: Ref T12335. See that task for discussion. Here are the behavioral changes: - Statuses can be flagged with `locked`, which means that tasks in that status are locked to further discussion and interaction. - A new "CAN_INTERACT" permission facilitates this. For most objects, "CAN_INTERACT" is just the same as "CAN_VIEW". - For tasks, "CAN_INTERACT" is everyone if the status is a normal status, and no one if the status is a locked status. - If a user doesn't have "Interact" permission: - They can not submit the comment form. - The comment form is replaced with text indicating "This thing is locked.". - The "Edit" workflow prompts them. This is a mixture of advisory and hard policy checks but sholuld represent a reasonable starting point. Test Plan: Created a new "Locked" status, locked a task. Couldn't comment, saw lock warning, saw lock prompt on edit. Unlocked a task. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12335 Differential Revision: https://secure.phabricator.com/D17453
This commit is contained in:
parent
0a0ac1302f
commit
0e7a5623e3
15 changed files with 272 additions and 17 deletions
|
@ -1487,6 +1487,7 @@ phutil_register_library_map(array(
|
||||||
'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php',
|
'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php',
|
||||||
'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php',
|
'ManiphestTaskEditBulkJobType' => 'applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php',
|
||||||
'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php',
|
'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php',
|
||||||
|
'ManiphestTaskEditEngineLock' => 'applications/maniphest/editor/ManiphestTaskEditEngineLock.php',
|
||||||
'ManiphestTaskFulltextEngine' => 'applications/maniphest/search/ManiphestTaskFulltextEngine.php',
|
'ManiphestTaskFulltextEngine' => 'applications/maniphest/search/ManiphestTaskFulltextEngine.php',
|
||||||
'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php',
|
'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php',
|
||||||
'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php',
|
'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php',
|
||||||
|
@ -2617,9 +2618,12 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php',
|
'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php',
|
||||||
'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php',
|
'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php',
|
||||||
'PhabricatorEditEngineDatasource' => 'applications/transactions/typeahead/PhabricatorEditEngineDatasource.php',
|
'PhabricatorEditEngineDatasource' => 'applications/transactions/typeahead/PhabricatorEditEngineDatasource.php',
|
||||||
|
'PhabricatorEditEngineDefaultLock' => 'applications/transactions/editengine/PhabricatorEditEngineDefaultLock.php',
|
||||||
'PhabricatorEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditEngineExtension.php',
|
'PhabricatorEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditEngineExtension.php',
|
||||||
'PhabricatorEditEngineExtensionModule' => 'applications/transactions/engineextension/PhabricatorEditEngineExtensionModule.php',
|
'PhabricatorEditEngineExtensionModule' => 'applications/transactions/engineextension/PhabricatorEditEngineExtensionModule.php',
|
||||||
'PhabricatorEditEngineListController' => 'applications/transactions/controller/PhabricatorEditEngineListController.php',
|
'PhabricatorEditEngineListController' => 'applications/transactions/controller/PhabricatorEditEngineListController.php',
|
||||||
|
'PhabricatorEditEngineLock' => 'applications/transactions/editengine/PhabricatorEditEngineLock.php',
|
||||||
|
'PhabricatorEditEngineLockableInterface' => 'applications/transactions/editengine/PhabricatorEditEngineLockableInterface.php',
|
||||||
'PhabricatorEditEnginePointsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEnginePointsCommentAction.php',
|
'PhabricatorEditEnginePointsCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEnginePointsCommentAction.php',
|
||||||
'PhabricatorEditEngineProfileMenuItem' => 'applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php',
|
'PhabricatorEditEngineProfileMenuItem' => 'applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php',
|
||||||
'PhabricatorEditEngineQuery' => 'applications/transactions/query/PhabricatorEditEngineQuery.php',
|
'PhabricatorEditEngineQuery' => 'applications/transactions/query/PhabricatorEditEngineQuery.php',
|
||||||
|
@ -6372,6 +6376,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFulltextInterface',
|
'PhabricatorFulltextInterface',
|
||||||
'DoorkeeperBridgedObjectInterface',
|
'DoorkeeperBridgedObjectInterface',
|
||||||
'PhabricatorEditEngineSubtypeInterface',
|
'PhabricatorEditEngineSubtypeInterface',
|
||||||
|
'PhabricatorEditEngineLockableInterface',
|
||||||
),
|
),
|
||||||
'ManiphestTaskAssignHeraldAction' => 'HeraldAction',
|
'ManiphestTaskAssignHeraldAction' => 'HeraldAction',
|
||||||
'ManiphestTaskAssignOtherHeraldAction' => 'ManiphestTaskAssignHeraldAction',
|
'ManiphestTaskAssignOtherHeraldAction' => 'ManiphestTaskAssignHeraldAction',
|
||||||
|
@ -6387,6 +6392,7 @@ phutil_register_library_map(array(
|
||||||
'ManiphestTaskDetailController' => 'ManiphestController',
|
'ManiphestTaskDetailController' => 'ManiphestController',
|
||||||
'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType',
|
'ManiphestTaskEditBulkJobType' => 'PhabricatorWorkerBulkJobType',
|
||||||
'ManiphestTaskEditController' => 'ManiphestController',
|
'ManiphestTaskEditController' => 'ManiphestController',
|
||||||
|
'ManiphestTaskEditEngineLock' => 'PhabricatorEditEngineLock',
|
||||||
'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine',
|
'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||||
'ManiphestTaskGraph' => 'PhabricatorObjectGraph',
|
'ManiphestTaskGraph' => 'PhabricatorObjectGraph',
|
||||||
'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType',
|
'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
@ -7679,9 +7685,11 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController',
|
'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController',
|
||||||
'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController',
|
'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController',
|
||||||
'PhabricatorEditEngineDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorEditEngineDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
|
'PhabricatorEditEngineDefaultLock' => 'PhabricatorEditEngineLock',
|
||||||
'PhabricatorEditEngineExtension' => 'Phobject',
|
'PhabricatorEditEngineExtension' => 'Phobject',
|
||||||
'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule',
|
'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule',
|
||||||
'PhabricatorEditEngineListController' => 'PhabricatorEditEngineController',
|
'PhabricatorEditEngineListController' => 'PhabricatorEditEngineController',
|
||||||
|
'PhabricatorEditEngineLock' => 'Phobject',
|
||||||
'PhabricatorEditEnginePointsCommentAction' => 'PhabricatorEditEngineCommentAction',
|
'PhabricatorEditEnginePointsCommentAction' => 'PhabricatorEditEngineCommentAction',
|
||||||
'PhabricatorEditEngineProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
'PhabricatorEditEngineProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||||
'PhabricatorEditEngineQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorEditEngineQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
|
|
@ -210,6 +210,8 @@ The keys you can provide in a specification are:
|
||||||
- `claim` //Optional bool.// By default, closing an unassigned task claims
|
- `claim` //Optional bool.// By default, closing an unassigned task claims
|
||||||
it. You can set this to `false` to disable this behavior for a particular
|
it. You can set this to `false` to disable this behavior for a particular
|
||||||
status.
|
status.
|
||||||
|
- `locked` //Optional bool.// Lock tasks in this status, preventing users
|
||||||
|
from commenting.
|
||||||
|
|
||||||
Statuses will appear in the UI in the order specified. Note the status marked
|
Statuses will appear in the UI in the order specified. Note the status marked
|
||||||
`special` as `duplicate` is not settable directly and will not appear in UI
|
`special` as `duplicate` is not settable directly and will not appear in UI
|
||||||
|
|
|
@ -156,6 +156,10 @@ final class ManiphestTaskStatus extends ManiphestConstants {
|
||||||
return !self::isOpenStatus($status);
|
return !self::isOpenStatus($status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isLockedStatus($status) {
|
||||||
|
return self::getStatusAttribute($status, 'locked', false);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getStatusActionName($status) {
|
public static function getStatusActionName($status) {
|
||||||
return self::getStatusAttribute($status, 'name.action');
|
return self::getStatusAttribute($status, 'name.action');
|
||||||
}
|
}
|
||||||
|
@ -277,6 +281,7 @@ final class ManiphestTaskStatus extends ManiphestConstants {
|
||||||
'keywords' => 'optional list<string>',
|
'keywords' => 'optional list<string>',
|
||||||
'disabled' => 'optional bool',
|
'disabled' => 'optional bool',
|
||||||
'claim' => 'optional bool',
|
'claim' => 'optional bool',
|
||||||
|
'locked' => 'optional bool',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -257,6 +257,12 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||||
$task,
|
$task,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$can_interact = PhabricatorPolicyFilter::canInteract($viewer, $task);
|
||||||
|
|
||||||
|
// We expect a policy dialog if you can't edit the task, and expect a
|
||||||
|
// lock override dialog if you can't interact with it.
|
||||||
|
$workflow_edit = (!$can_edit || !$can_interact);
|
||||||
|
|
||||||
$curtain = $this->newCurtainView($task);
|
$curtain = $this->newCurtainView($task);
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
|
@ -265,7 +271,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||||
->setIcon('fa-pencil')
|
->setIcon('fa-pencil')
|
||||||
->setHref($this->getApplicationURI("/task/edit/{$id}/"))
|
->setHref($this->getApplicationURI("/task/edit/{$id}/"))
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
->setWorkflow(!$can_edit));
|
->setWorkflow($workflow_edit));
|
||||||
|
|
||||||
$edit_config = $edit_engine->loadDefaultEditConfiguration($task);
|
$edit_config = $edit_engine->loadDefaultEditConfiguration($task);
|
||||||
$can_create = (bool)$edit_config;
|
$can_create = (bool)$edit_config;
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ManiphestTaskEditEngineLock
|
||||||
|
extends PhabricatorEditEngineLock {
|
||||||
|
|
||||||
|
public function willPromptUserForLockOverrideWithDialog(
|
||||||
|
AphrontDialogView $dialog) {
|
||||||
|
|
||||||
|
return $dialog
|
||||||
|
->setTitle(pht('Edit Locked Task'))
|
||||||
|
->appendParagraph(pht('This task is locked. Edit it anyway?'))
|
||||||
|
->addSubmitButton(pht('Override Task Lock'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willBlockUserInteractionWithDialog(
|
||||||
|
AphrontDialogView $dialog) {
|
||||||
|
|
||||||
|
return $dialog
|
||||||
|
->setTitle(pht('Task Locked'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht('You can not interact with this task because it is locked.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLockedObjectDisplayText() {
|
||||||
|
return pht('This task has been locked.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,8 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
PhabricatorConduitResultInterface,
|
PhabricatorConduitResultInterface,
|
||||||
PhabricatorFulltextInterface,
|
PhabricatorFulltextInterface,
|
||||||
DoorkeeperBridgedObjectInterface,
|
DoorkeeperBridgedObjectInterface,
|
||||||
PhabricatorEditEngineSubtypeInterface {
|
PhabricatorEditEngineSubtypeInterface,
|
||||||
|
PhabricatorEditEngineLockableInterface {
|
||||||
|
|
||||||
const MARKUP_FIELD_DESCRIPTION = 'markup:desc';
|
const MARKUP_FIELD_DESCRIPTION = 'markup:desc';
|
||||||
|
|
||||||
|
@ -213,6 +214,10 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
return ManiphestTaskStatus::isClosedStatus($this->getStatus());
|
return ManiphestTaskStatus::isClosedStatus($this->getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isLocked() {
|
||||||
|
return ManiphestTaskStatus::isLockedStatus($this->getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
public function setProperty($key, $value) {
|
public function setProperty($key, $value) {
|
||||||
$this->properties[$key] = $value;
|
$this->properties[$key] = $value;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -343,6 +348,7 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
return array(
|
return array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_INTERACT,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -351,6 +357,12 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
switch ($capability) {
|
switch ($capability) {
|
||||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
return $this->getViewPolicy();
|
return $this->getViewPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_INTERACT:
|
||||||
|
if ($this->isLocked()) {
|
||||||
|
return PhabricatorPolicies::POLICY_NOONE;
|
||||||
|
} else {
|
||||||
|
return PhabricatorPolicies::POLICY_USER;
|
||||||
|
}
|
||||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
return $this->getEditPolicy();
|
return $this->getEditPolicy();
|
||||||
}
|
}
|
||||||
|
@ -562,4 +574,12 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
return PhabricatorEditEngineSubtype::newSubtypeMap($config);
|
return PhabricatorEditEngineSubtype::newSubtypeMap($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorEditEngineLockableInterface )----------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function newEditEngineLock() {
|
||||||
|
return new ManiphestTaskEditEngineLock();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ abstract class PhabricatorPolicyCapability extends Phobject {
|
||||||
const CAN_VIEW = 'view';
|
const CAN_VIEW = 'view';
|
||||||
const CAN_EDIT = 'edit';
|
const CAN_EDIT = 'edit';
|
||||||
const CAN_JOIN = 'join';
|
const CAN_JOIN = 'join';
|
||||||
|
const CAN_INTERACT = 'interact';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the unique key identifying this capability. This key must be globally
|
* Get the unique key identifying this capability. This key must be globally
|
||||||
|
|
|
@ -86,6 +86,36 @@ final class PhabricatorPolicyFilter extends Phobject {
|
||||||
return (count($result) == 1);
|
return (count($result) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function canInteract(
|
||||||
|
PhabricatorUser $user,
|
||||||
|
PhabricatorPolicyInterface $object) {
|
||||||
|
|
||||||
|
$capabilities = $object->getCapabilities();
|
||||||
|
$capabilities = array_fuse($capabilities);
|
||||||
|
|
||||||
|
$can_interact = PhabricatorPolicyCapability::CAN_INTERACT;
|
||||||
|
$can_view = PhabricatorPolicyCapability::CAN_VIEW;
|
||||||
|
|
||||||
|
$require = array();
|
||||||
|
|
||||||
|
// If the object doesn't support a separate "Interact" capability, we
|
||||||
|
// only use the "View" capability: for most objects, you can interact
|
||||||
|
// with them if you can see them.
|
||||||
|
$require[] = $can_view;
|
||||||
|
|
||||||
|
if (isset($capabilities[$can_interact])) {
|
||||||
|
$require[] = $can_interact;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($require as $capability) {
|
||||||
|
if (!self::hasCapability($user, $object, $capability)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function setViewer(PhabricatorUser $user) {
|
public function setViewer(PhabricatorUser $user) {
|
||||||
$this->viewer = $user;
|
$this->viewer = $user;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -47,6 +47,15 @@ final class PhabricatorSubscriptionsEditController
|
||||||
$handle->getURI());
|
$handle->getURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!PhabricatorPolicyFilter::canInteract($viewer, $object)) {
|
||||||
|
$lock = PhabricatorEditEngineLock::newForObject($viewer, $object);
|
||||||
|
|
||||||
|
$dialog = $this->newDialog()
|
||||||
|
->addCancelButton($handle->getURI());
|
||||||
|
|
||||||
|
return $lock->willBlockUserInteractionWithDialog($dialog);
|
||||||
|
}
|
||||||
|
|
||||||
if ($object instanceof PhabricatorApplicationTransactionInterface) {
|
if ($object instanceof PhabricatorApplicationTransactionInterface) {
|
||||||
if ($is_add) {
|
if ($is_add) {
|
||||||
$xaction_value = array(
|
$xaction_value = array(
|
||||||
|
|
|
@ -56,20 +56,24 @@ final class PhabricatorSubscriptionsUIEventListener
|
||||||
$subscribed = isset($edges[$src_phid][$edge_type][$user_phid]);
|
$subscribed = isset($edges[$src_phid][$edge_type][$user_phid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$can_interact = PhabricatorPolicyFilter::canInteract($user, $object);
|
||||||
|
|
||||||
if ($subscribed) {
|
if ($subscribed) {
|
||||||
$sub_action = id(new PhabricatorActionView())
|
$sub_action = id(new PhabricatorActionView())
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setRenderAsForm(true)
|
->setRenderAsForm(true)
|
||||||
->setHref('/subscriptions/delete/'.$object->getPHID().'/')
|
->setHref('/subscriptions/delete/'.$object->getPHID().'/')
|
||||||
->setName(pht('Unsubscribe'))
|
->setName(pht('Unsubscribe'))
|
||||||
->setIcon('fa-minus-circle');
|
->setIcon('fa-minus-circle')
|
||||||
|
->setDisabled(!$can_interact);
|
||||||
} else {
|
} else {
|
||||||
$sub_action = id(new PhabricatorActionView())
|
$sub_action = id(new PhabricatorActionView())
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setRenderAsForm(true)
|
->setRenderAsForm(true)
|
||||||
->setHref('/subscriptions/add/'.$object->getPHID().'/')
|
->setHref('/subscriptions/add/'.$object->getPHID().'/')
|
||||||
->setName(pht('Subscribe'))
|
->setName(pht('Subscribe'))
|
||||||
->setIcon('fa-plus-circle');
|
->setIcon('fa-plus-circle')
|
||||||
|
->setDisabled(!$can_interact);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$user->isLoggedIn()) {
|
if (!$user->isLoggedIn()) {
|
||||||
|
|
|
@ -985,9 +985,33 @@ abstract class PhabricatorEditEngine
|
||||||
$fields = $this->buildEditFields($object);
|
$fields = $this->buildEditFields($object);
|
||||||
$template = $object->getApplicationTransactionTemplate();
|
$template = $object->getApplicationTransactionTemplate();
|
||||||
|
|
||||||
|
if ($this->getIsCreate()) {
|
||||||
|
$cancel_uri = $this->getObjectCreateCancelURI($object);
|
||||||
|
$submit_button = $this->getObjectCreateButtonText($object);
|
||||||
|
} else {
|
||||||
|
$cancel_uri = $this->getEffectiveObjectEditCancelURI($object);
|
||||||
|
$submit_button = $this->getObjectEditButtonText($object);
|
||||||
|
}
|
||||||
|
|
||||||
$config = $this->getEditEngineConfiguration()
|
$config = $this->getEditEngineConfiguration()
|
||||||
->attachEngine($this);
|
->attachEngine($this);
|
||||||
|
|
||||||
|
$can_interact = PhabricatorPolicyFilter::canInteract($viewer, $object);
|
||||||
|
if (!$can_interact &&
|
||||||
|
!$request->getBool('editEngine') &&
|
||||||
|
!$request->getBool('overrideLock')) {
|
||||||
|
|
||||||
|
$lock = PhabricatorEditEngineLock::newForObject($viewer, $object);
|
||||||
|
|
||||||
|
$dialog = $this->getController()
|
||||||
|
->newDialog()
|
||||||
|
->addHiddenInput('overrideLock', true)
|
||||||
|
->setDisableWorkflowOnSubmit(true)
|
||||||
|
->addCancelButton($cancel_uri);
|
||||||
|
|
||||||
|
return $lock->willPromptUserForLockOverrideWithDialog($dialog);
|
||||||
|
}
|
||||||
|
|
||||||
$validation_exception = null;
|
$validation_exception = null;
|
||||||
if ($request->isFormPost() && $request->getBool('editEngine')) {
|
if ($request->isFormPost() && $request->getBool('editEngine')) {
|
||||||
$submit_fields = $fields;
|
$submit_fields = $fields;
|
||||||
|
@ -1154,14 +1178,6 @@ abstract class PhabricatorEditEngine
|
||||||
$form = $this->buildEditForm($object, $fields);
|
$form = $this->buildEditForm($object, $fields);
|
||||||
|
|
||||||
if ($request->isAjax()) {
|
if ($request->isAjax()) {
|
||||||
if ($this->getIsCreate()) {
|
|
||||||
$cancel_uri = $this->getObjectCreateCancelURI($object);
|
|
||||||
$submit_button = $this->getObjectCreateButtonText($object);
|
|
||||||
} else {
|
|
||||||
$cancel_uri = $this->getEffectiveObjectEditCancelURI($object);
|
|
||||||
$submit_button = $this->getObjectEditButtonText($object);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->getController()
|
return $this->getController()
|
||||||
->newDialog()
|
->newDialog()
|
||||||
->setWidth(AphrontDialogView::WIDTH_FULL)
|
->setWidth(AphrontDialogView::WIDTH_FULL)
|
||||||
|
@ -1554,8 +1570,16 @@ abstract class PhabricatorEditEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$object_phid = $object->getPHID();
|
|
||||||
|
|
||||||
|
$can_interact = PhabricatorPolicyFilter::canInteract($viewer, $object);
|
||||||
|
if (!$can_interact) {
|
||||||
|
$lock = PhabricatorEditEngineLock::newForObject($viewer, $object);
|
||||||
|
|
||||||
|
return id(new PhabricatorApplicationTransactionCommentView())
|
||||||
|
->setEditEngineLock($lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
$object_phid = $object->getPHID();
|
||||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||||
|
|
||||||
if ($is_serious) {
|
if ($is_serious) {
|
||||||
|
@ -1700,11 +1724,19 @@ abstract class PhabricatorEditEngine
|
||||||
private function buildError($object, $title, $body) {
|
private function buildError($object, $title, $body) {
|
||||||
$cancel_uri = $this->getObjectCreateCancelURI($object);
|
$cancel_uri = $this->getObjectCreateCancelURI($object);
|
||||||
|
|
||||||
return $this->getController()
|
$dialog = $this->getController()
|
||||||
->newDialog()
|
->newDialog()
|
||||||
->setTitle($title)
|
|
||||||
->appendParagraph($body)
|
|
||||||
->addCancelButton($cancel_uri);
|
->addCancelButton($cancel_uri);
|
||||||
|
|
||||||
|
if ($title !== null) {
|
||||||
|
$dialog->setTitle($title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($body !== null) {
|
||||||
|
$dialog->appendParagraph($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1761,6 +1793,14 @@ abstract class PhabricatorEditEngine
|
||||||
$config->getName()));
|
$config->getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildLockedObjectResponse($object) {
|
||||||
|
$dialog = $this->buildError($object, null, null);
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$lock = PhabricatorEditEngineLock::newForObject($viewer, $object);
|
||||||
|
return $lock->willBlockUserInteractionWithDialog($dialog);
|
||||||
|
}
|
||||||
|
|
||||||
private function buildCommentResponse($object) {
|
private function buildCommentResponse($object) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
@ -1775,6 +1815,11 @@ abstract class PhabricatorEditEngine
|
||||||
return new Aphront400Response();
|
return new Aphront400Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$can_interact = PhabricatorPolicyFilter::canInteract($viewer, $object);
|
||||||
|
if (!$can_interact) {
|
||||||
|
return $this->buildLockedObjectResponse($object);
|
||||||
|
}
|
||||||
|
|
||||||
$config = $this->loadDefaultEditConfiguration($object);
|
$config = $this->loadDefaultEditConfiguration($object);
|
||||||
if (!$config) {
|
if (!$config) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorEditEngineDefaultLock
|
||||||
|
extends PhabricatorEditEngineLock {}
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorEditEngineLock
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
private $object;
|
||||||
|
|
||||||
|
final public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setObject($object) {
|
||||||
|
$this->object = $object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getObject() {
|
||||||
|
return $this->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willPromptUserForLockOverrideWithDialog(
|
||||||
|
AphrontDialogView $dialog) {
|
||||||
|
|
||||||
|
return $dialog
|
||||||
|
->setTitle(pht('Edit Locked Object'))
|
||||||
|
->appendParagraph(pht('This object is locked. Edit it anyway?'))
|
||||||
|
->addSubmitButton(pht('Override Lock'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willBlockUserInteractionWithDialog(
|
||||||
|
AphrontDialogView $dialog) {
|
||||||
|
|
||||||
|
return $dialog
|
||||||
|
->setTitle(pht('Object Locked'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht('You can not interact with this object because it is locked.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLockedObjectDisplayText() {
|
||||||
|
return pht('This object has been locked.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function newForObject(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
$object) {
|
||||||
|
|
||||||
|
if ($object instanceof PhabricatorEditEngineLockableInterface) {
|
||||||
|
$lock = $object->newEditEngineLock();
|
||||||
|
} else {
|
||||||
|
$lock = new PhabricatorEditEngineDefaultLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lock
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setObject($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface PhabricatorEditEngineLockableInterface {
|
||||||
|
|
||||||
|
public function newEditEngineLock();
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
||||||
private $noPermission;
|
private $noPermission;
|
||||||
private $fullWidth;
|
private $fullWidth;
|
||||||
private $infoView;
|
private $infoView;
|
||||||
|
private $editEngineLock;
|
||||||
|
|
||||||
private $currentVersion;
|
private $currentVersion;
|
||||||
private $versionedDraft;
|
private $versionedDraft;
|
||||||
|
@ -149,11 +150,20 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
||||||
return $this->noPermission;
|
return $this->noPermission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setEditEngineLock(PhabricatorEditEngineLock $lock) {
|
||||||
|
$this->editEngineLock = $lock;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditEngineLock() {
|
||||||
|
return $this->editEngineLock;
|
||||||
|
}
|
||||||
|
|
||||||
public function setTransactionTimeline(
|
public function setTransactionTimeline(
|
||||||
PhabricatorApplicationTransactionView $timeline) {
|
PhabricatorApplicationTransactionView $timeline) {
|
||||||
|
|
||||||
$timeline->setQuoteTargetID($this->getCommentID());
|
$timeline->setQuoteTargetID($this->getCommentID());
|
||||||
if ($this->getNoPermission()) {
|
if ($this->getNoPermission() || $this->getEditEngineLock()) {
|
||||||
$timeline->setShouldTerminate(true);
|
$timeline->setShouldTerminate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +176,16 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$lock = $this->getEditEngineLock();
|
||||||
|
if ($lock) {
|
||||||
|
return id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||||
|
->setErrors(
|
||||||
|
array(
|
||||||
|
$lock->getLockedObjectDisplayText(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
if (!$user->isLoggedIn()) {
|
if (!$user->isLoggedIn()) {
|
||||||
$uri = id(new PhutilURI('/login/'))
|
$uri = id(new PhutilURI('/login/'))
|
||||||
|
|
Loading…
Reference in a new issue