mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 04:42:40 +01:00
Moderize Countdown
Summary: [DRAFT] Ref T8895. Makes a reasonable attempt at: - Project Support - Timeline / History - Better Search - Better ObjectItemLists Test Plan: Needs better testing (I'm sleepy) Reviewers: btrahan, epriestley Reviewed By: epriestley Subscribers: eadler, epriestley, Korvin Maniphest Tasks: T8895 Differential Revision: https://secure.phabricator.com/D13660
This commit is contained in:
parent
1643685e72
commit
fdd6351a64
16 changed files with 630 additions and 130 deletions
36
resources/sql/autopatches/20150719.countdown.1.sql
Normal file
36
resources/sql/autopatches/20150719.countdown.1.sql
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_countdown.countdown_transaction (
|
||||||
|
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
commentPHID VARBINARY(64),
|
||||||
|
commentVersion INT UNSIGNED NOT NULL,
|
||||||
|
transactionType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
oldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
newValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
contentSource LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
metadata LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (phid),
|
||||||
|
KEY `key_object` (objectPHID)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
||||||
|
|
||||||
|
CREATE TABLE {$NAMESPACE}_countdown.edge (
|
||||||
|
src VARBINARY(64) NOT NULL,
|
||||||
|
type INT UNSIGNED NOT NULL,
|
||||||
|
dst VARBINARY(64) NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
seq INT UNSIGNED NOT NULL,
|
||||||
|
dataID INT UNSIGNED,
|
||||||
|
PRIMARY KEY (src, type, dst),
|
||||||
|
KEY `src` (src, type, dateCreated, seq),
|
||||||
|
UNIQUE KEY `key_dst` (dst, type, src)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
||||||
|
|
||||||
|
CREATE TABLE {$NAMESPACE}_countdown.edgedata (
|
||||||
|
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
2
resources/sql/autopatches/20150719.countdown.2.sql
Normal file
2
resources/sql/autopatches/20150719.countdown.2.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_countdown.countdown
|
||||||
|
ADD editPolicy VARBINARY(64) NOT NULL;
|
2
resources/sql/autopatches/20150719.countdown.3.sql
Normal file
2
resources/sql/autopatches/20150719.countdown.3.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
UPDATE {$NAMESPACE}_countdown.countdown
|
||||||
|
SET editPolicy = authorPHID WHERE editPolicy = '';
|
|
@ -1799,13 +1799,19 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php',
|
'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php',
|
||||||
'PhabricatorCountdownCountdownPHIDType' => 'applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php',
|
'PhabricatorCountdownCountdownPHIDType' => 'applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php',
|
||||||
'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php',
|
'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php',
|
||||||
|
'PhabricatorCountdownDefaultEditCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultEditCapability.php',
|
||||||
'PhabricatorCountdownDefaultViewCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultViewCapability.php',
|
'PhabricatorCountdownDefaultViewCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultViewCapability.php',
|
||||||
'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/PhabricatorCountdownDeleteController.php',
|
'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/PhabricatorCountdownDeleteController.php',
|
||||||
'PhabricatorCountdownEditController' => 'applications/countdown/controller/PhabricatorCountdownEditController.php',
|
'PhabricatorCountdownEditController' => 'applications/countdown/controller/PhabricatorCountdownEditController.php',
|
||||||
|
'PhabricatorCountdownEditor' => 'applications/countdown/editor/PhabricatorCountdownEditor.php',
|
||||||
'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php',
|
'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php',
|
||||||
'PhabricatorCountdownQuery' => 'applications/countdown/query/PhabricatorCountdownQuery.php',
|
'PhabricatorCountdownQuery' => 'applications/countdown/query/PhabricatorCountdownQuery.php',
|
||||||
'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php',
|
'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php',
|
||||||
|
'PhabricatorCountdownReplyHandler' => 'applications/countdown/mail/PhabricatorCountdownReplyHandler.php',
|
||||||
|
'PhabricatorCountdownSchemaSpec' => 'applications/countdown/storage/PhabricatorCountdownSchemaSpec.php',
|
||||||
'PhabricatorCountdownSearchEngine' => 'applications/countdown/query/PhabricatorCountdownSearchEngine.php',
|
'PhabricatorCountdownSearchEngine' => 'applications/countdown/query/PhabricatorCountdownSearchEngine.php',
|
||||||
|
'PhabricatorCountdownTransaction' => 'applications/countdown/storage/PhabricatorCountdownTransaction.php',
|
||||||
|
'PhabricatorCountdownTransactionQuery' => 'applications/countdown/query/PhabricatorCountdownTransactionQuery.php',
|
||||||
'PhabricatorCountdownView' => 'applications/countdown/view/PhabricatorCountdownView.php',
|
'PhabricatorCountdownView' => 'applications/countdown/view/PhabricatorCountdownView.php',
|
||||||
'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php',
|
'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php',
|
||||||
'PhabricatorCredentialsUsedByObjectEdgeType' => 'applications/passphrase/edge/PhabricatorCredentialsUsedByObjectEdgeType.php',
|
'PhabricatorCredentialsUsedByObjectEdgeType' => 'applications/passphrase/edge/PhabricatorCredentialsUsedByObjectEdgeType.php',
|
||||||
|
@ -5548,19 +5554,28 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCountdownDAO',
|
'PhabricatorCountdownDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
'PhabricatorFlaggableInterface',
|
'PhabricatorFlaggableInterface',
|
||||||
|
'PhabricatorSubscribableInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
'PhabricatorSpacesInterface',
|
'PhabricatorSpacesInterface',
|
||||||
|
'PhabricatorProjectInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorCountdownApplication' => 'PhabricatorApplication',
|
'PhabricatorCountdownApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorCountdownController' => 'PhabricatorController',
|
'PhabricatorCountdownController' => 'PhabricatorController',
|
||||||
'PhabricatorCountdownCountdownPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorCountdownCountdownPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
|
||||||
|
'PhabricatorCountdownDefaultEditCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PhabricatorCountdownDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
'PhabricatorCountdownDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
|
||||||
'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
|
||||||
|
'PhabricatorCountdownEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
|
||||||
'PhabricatorCountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorCountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorCountdownRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
'PhabricatorCountdownRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||||
|
'PhabricatorCountdownReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||||
|
'PhabricatorCountdownSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
'PhabricatorCountdownSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorCountdownSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'PhabricatorCountdownTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
|
'PhabricatorCountdownTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorCountdownView' => 'AphrontTagView',
|
'PhabricatorCountdownView' => 'AphrontTagView',
|
||||||
'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
|
||||||
'PhabricatorCredentialsUsedByObjectEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorCredentialsUsedByObjectEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
|
|
@ -38,6 +38,7 @@ final class PhabricatorCountdownApplication extends PhabricatorApplication {
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
|
'/C(?P<id>[1-9]\d*)' => 'PhabricatorCountdownViewController',
|
||||||
'/countdown/' => array(
|
'/countdown/' => array(
|
||||||
'(?:query/(?P<queryKey>[^/]+)/)?'
|
'(?:query/(?P<queryKey>[^/]+)/)?'
|
||||||
=> 'PhabricatorCountdownListController',
|
=> 'PhabricatorCountdownListController',
|
||||||
|
@ -55,6 +56,11 @@ final class PhabricatorCountdownApplication extends PhabricatorApplication {
|
||||||
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
|
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
|
||||||
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
),
|
),
|
||||||
|
PhabricatorCountdownDefaultEditCapability::CAPABILITY => array(
|
||||||
|
'caption' => pht('Default edit policy for new countdowns.'),
|
||||||
|
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
|
||||||
|
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownDefaultEditCapability
|
||||||
|
extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'countdown.default.edit';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Default Edit Policy');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,21 +3,15 @@
|
||||||
final class PhabricatorCountdownEditController
|
final class PhabricatorCountdownEditController
|
||||||
extends PhabricatorCountdownController {
|
extends PhabricatorCountdownController {
|
||||||
|
|
||||||
private $id;
|
public function handleRequest(AphrontRequest $request) {
|
||||||
public function willProcessRequest(array $data) {
|
$viewer = $request->getViewer();
|
||||||
$this->id = idx($data, 'id');
|
$id = $request->getURIData('id');
|
||||||
}
|
|
||||||
|
|
||||||
public function processRequest() {
|
if ($id) {
|
||||||
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$user = $request->getUser();
|
|
||||||
|
|
||||||
if ($this->id) {
|
|
||||||
$page_title = pht('Edit Countdown');
|
$page_title = pht('Edit Countdown');
|
||||||
$countdown = id(new PhabricatorCountdownQuery())
|
$countdown = id(new PhabricatorCountdownQuery())
|
||||||
->setViewer($user)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($id))
|
||||||
->requireCapabilities(
|
->requireCapabilities(
|
||||||
array(
|
array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
@ -28,12 +22,18 @@ final class PhabricatorCountdownEditController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
$date_value = AphrontFormDateControlValue::newFromEpoch(
|
$date_value = AphrontFormDateControlValue::newFromEpoch(
|
||||||
$user,
|
$viewer,
|
||||||
$countdown->getEpoch());
|
$countdown->getEpoch());
|
||||||
|
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
|
$countdown->getPHID(),
|
||||||
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||||
|
$v_projects = array_reverse($v_projects);
|
||||||
} else {
|
} else {
|
||||||
$page_title = pht('Create Countdown');
|
$page_title = pht('Create Countdown');
|
||||||
$countdown = PhabricatorCountdown::initializeNewCountdown($user);
|
$countdown = PhabricatorCountdown::initializeNewCountdown($viewer);
|
||||||
$date_value = AphrontFormDateControlValue::newFromEpoch($user, time());
|
$date_value = AphrontFormDateControlValue::newFromEpoch(
|
||||||
|
$viewer, PhabricatorTime::getNow());
|
||||||
|
$v_projects = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
@ -42,6 +42,8 @@ final class PhabricatorCountdownEditController
|
||||||
|
|
||||||
$v_text = $countdown->getTitle();
|
$v_text = $countdown->getTitle();
|
||||||
$v_space = $countdown->getSpacePHID();
|
$v_space = $countdown->getSpacePHID();
|
||||||
|
$v_view = $countdown->getViewPolicy();
|
||||||
|
$v_edit = $countdown->getEditPolicy();
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$v_text = $request->getStr('title');
|
$v_text = $request->getStr('title');
|
||||||
|
@ -49,27 +51,61 @@ final class PhabricatorCountdownEditController
|
||||||
$date_value = AphrontFormDateControlValue::newFromRequest(
|
$date_value = AphrontFormDateControlValue::newFromRequest(
|
||||||
$request,
|
$request,
|
||||||
'epoch');
|
'epoch');
|
||||||
$view_policy = $request->getStr('viewPolicy');
|
$v_view = $request->getStr('viewPolicy');
|
||||||
|
$v_edit = $request->getStr('editPolicy');
|
||||||
|
$v_projects = $request->getArr('projects');
|
||||||
|
|
||||||
$e_text = null;
|
$type_title = PhabricatorCountdownTransaction::TYPE_TITLE;
|
||||||
if (!strlen($v_text)) {
|
$type_epoch = PhabricatorCountdownTransaction::TYPE_EPOCH;
|
||||||
$e_text = pht('Required');
|
$type_space = PhabricatorTransactions::TYPE_SPACE;
|
||||||
$errors[] = pht('You must give the countdown a name.');
|
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
}
|
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
if (!$date_value->isValid()) {
|
|
||||||
$e_epoch = pht('Invalid');
|
$xactions = array();
|
||||||
$errors[] = pht('You must give the countdown a valid end date.');
|
|
||||||
}
|
$xactions[] = id(new PhabricatorCountdownTransaction())
|
||||||
|
->setTransactionType($type_title)
|
||||||
|
->setNewValue($v_text);
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorCountdownTransaction())
|
||||||
|
->setTransactionType($type_epoch)
|
||||||
|
->setNewValue($date_value);
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorCountdownTransaction())
|
||||||
|
->setTransactionType($type_space)
|
||||||
|
->setNewValue($v_space);
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorCountdownTransaction())
|
||||||
|
->setTransactionType($type_view)
|
||||||
|
->setNewValue($v_view);
|
||||||
|
|
||||||
|
$xactions[] = id(new PhabricatorCountdownTransaction())
|
||||||
|
->setTransactionType($type_edit)
|
||||||
|
->setNewValue($v_edit);
|
||||||
|
|
||||||
|
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||||
|
$xactions[] = id(new PhabricatorCountdownTransaction())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||||
|
->setMetadataValue('edge:type', $proj_edge_type)
|
||||||
|
->setNewValue(array('=' => array_fuse($v_projects)));
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorCountdownEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$editor->applyTransactions($countdown, $xactions);
|
||||||
|
|
||||||
if (!count($errors)) {
|
|
||||||
$countdown->setTitle($v_text);
|
|
||||||
$countdown->setEpoch($date_value->getEpoch());
|
|
||||||
$countdown->setViewPolicy($view_policy);
|
|
||||||
$countdown->setSpacePHID($v_space);
|
|
||||||
$countdown->save();
|
|
||||||
return id(new AphrontRedirectResponse())
|
return id(new AphrontRedirectResponse())
|
||||||
->setURI('/countdown/'.$countdown->getID().'/');
|
->setURI('/'.$countdown->getMonogram());
|
||||||
|
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||||
|
$validation_exception = $ex;
|
||||||
|
|
||||||
|
$e_title = $ex->getShortMessage($type_title);
|
||||||
|
$e_epoch = $ex->getShortMessage($type_epoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
@ -86,12 +122,12 @@ final class PhabricatorCountdownEditController
|
||||||
}
|
}
|
||||||
|
|
||||||
$policies = id(new PhabricatorPolicyQuery())
|
$policies = id(new PhabricatorPolicyQuery())
|
||||||
->setViewer($user)
|
->setViewer($viewer)
|
||||||
->setObject($countdown)
|
->setObject($countdown)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($user)
|
->setUser($viewer)
|
||||||
->setAction($request->getRequestURI()->getPath())
|
->setAction($request->getRequestURI()->getPath())
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
|
@ -99,21 +135,33 @@ final class PhabricatorCountdownEditController
|
||||||
->setValue($v_text)
|
->setValue($v_text)
|
||||||
->setName('title')
|
->setName('title')
|
||||||
->setError($e_text))
|
->setError($e_text))
|
||||||
->appendChild(
|
->appendControl(
|
||||||
id(new AphrontFormDateControl())
|
id(new AphrontFormDateControl())
|
||||||
->setUser($user)
|
|
||||||
->setName('epoch')
|
->setName('epoch')
|
||||||
->setLabel(pht('End Date'))
|
->setLabel(pht('End Date'))
|
||||||
->setError($e_epoch)
|
->setError($e_epoch)
|
||||||
->setValue($date_value))
|
->setValue($date_value))
|
||||||
->appendChild(
|
->appendControl(
|
||||||
id(new AphrontFormPolicyControl())
|
id(new AphrontFormPolicyControl())
|
||||||
->setUser($user)
|
|
||||||
->setName('viewPolicy')
|
->setName('viewPolicy')
|
||||||
->setPolicyObject($countdown)
|
->setPolicyObject($countdown)
|
||||||
->setPolicies($policies)
|
->setPolicies($policies)
|
||||||
->setSpacePHID($v_space)
|
->setSpacePHID($v_space)
|
||||||
|
->setValue($v_view)
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW))
|
->setCapability(PhabricatorPolicyCapability::CAN_VIEW))
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormPolicyControl())
|
||||||
|
->setName('editPolicy')
|
||||||
|
->setPolicyObject($countdown)
|
||||||
|
->setPolicies($policies)
|
||||||
|
->setValue($v_edit)
|
||||||
|
->setCapability(PhabricatorPolicyCapability::CAN_EDIT))
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormTokenizerControl())
|
||||||
|
->setLabel(pht('Projects'))
|
||||||
|
->setName('projects')
|
||||||
|
->setValue($v_projects)
|
||||||
|
->setDatasource(new PhabricatorProjectDatasource()))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormSubmitControl())
|
id(new AphrontFormSubmitControl())
|
||||||
->addCancelButton($cancel_uri)
|
->addCancelButton($cancel_uri)
|
||||||
|
|
|
@ -3,31 +3,24 @@
|
||||||
final class PhabricatorCountdownViewController
|
final class PhabricatorCountdownViewController
|
||||||
extends PhabricatorCountdownController {
|
extends PhabricatorCountdownController {
|
||||||
|
|
||||||
private $id;
|
|
||||||
|
|
||||||
public function shouldAllowPublic() {
|
public function shouldAllowPublic() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$this->id = $data['id'];
|
$viewer = $request->getViewer();
|
||||||
}
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$user = $request->getUser();
|
|
||||||
|
|
||||||
$countdown = id(new PhabricatorCountdownQuery())
|
$countdown = id(new PhabricatorCountdownQuery())
|
||||||
->setViewer($user)
|
->setViewer($viewer)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($id))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$countdown) {
|
if (!$countdown) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
$countdown_view = id(new PhabricatorCountdownView())
|
$countdown_view = id(new PhabricatorCountdownView())
|
||||||
->setUser($user)
|
->setUser($viewer)
|
||||||
->setCountdown($countdown)
|
->setCountdown($countdown)
|
||||||
->setHeadless(true);
|
->setHeadless(true);
|
||||||
|
|
||||||
|
@ -38,10 +31,22 @@ final class PhabricatorCountdownViewController
|
||||||
->buildApplicationCrumbs()
|
->buildApplicationCrumbs()
|
||||||
->addTextCrumb("C{$id}");
|
->addTextCrumb("C{$id}");
|
||||||
|
|
||||||
|
$epoch = $countdown->getEpoch();
|
||||||
|
if ($epoch >= PhabricatorTime::getNow()) {
|
||||||
|
$icon = 'fa-clock-o';
|
||||||
|
$color = '';
|
||||||
|
$status = pht('Running');
|
||||||
|
} else {
|
||||||
|
$icon = 'fa-check-square-o';
|
||||||
|
$color = 'dark';
|
||||||
|
$status = pht('Launched');
|
||||||
|
}
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader($title)
|
->setHeader($title)
|
||||||
->setUser($user)
|
->setUser($viewer)
|
||||||
->setPolicyObject($countdown);
|
->setPolicyObject($countdown)
|
||||||
|
->setStatus($icon, $color, $status);
|
||||||
|
|
||||||
$actions = $this->buildActionListView($countdown);
|
$actions = $this->buildActionListView($countdown);
|
||||||
$properties = $this->buildPropertyListView($countdown, $actions);
|
$properties = $this->buildPropertyListView($countdown, $actions);
|
||||||
|
@ -50,10 +55,16 @@ final class PhabricatorCountdownViewController
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->addPropertyList($properties);
|
->addPropertyList($properties);
|
||||||
|
|
||||||
|
$timeline = $this->buildTransactionTimeline(
|
||||||
|
$countdown,
|
||||||
|
new PhabricatorCountdownTransactionQuery());
|
||||||
|
$timeline->setShouldTerminate(true);
|
||||||
|
|
||||||
$content = array(
|
$content = array(
|
||||||
$crumbs,
|
$crumbs,
|
||||||
$object_box,
|
$object_box,
|
||||||
$countdown_view,
|
$countdown_view,
|
||||||
|
$timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->buildApplicationPage(
|
||||||
|
@ -105,6 +116,7 @@ final class PhabricatorCountdownViewController
|
||||||
|
|
||||||
$view = id(new PHUIPropertyListView())
|
$view = id(new PHUIPropertyListView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
|
->setObject($countdown)
|
||||||
->setActionList($actions);
|
->setActionList($actions);
|
||||||
|
|
||||||
$view->addProperty(
|
$view->addProperty(
|
||||||
|
|
193
src/applications/countdown/editor/PhabricatorCountdownEditor.php
Normal file
193
src/applications/countdown/editor/PhabricatorCountdownEditor.php
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorCountdownApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Countdown');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTransactionTypes() {
|
||||||
|
$types = parent::getTransactionTypes();
|
||||||
|
|
||||||
|
$types[] = PhabricatorCountdownTransaction::TYPE_TITLE;
|
||||||
|
$types[] = PhabricatorCountdownTransaction::TYPE_EPOCH;
|
||||||
|
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_SPACE;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
|
|
||||||
|
return $types;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionOldValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_TITLE:
|
||||||
|
return $object->getTitle();
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_EPOCH:
|
||||||
|
return $object->getEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionNewValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_TITLE:
|
||||||
|
return $xaction->getNewValue();
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_EPOCH:
|
||||||
|
return $xaction->getNewValue()->getEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomInternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_TITLE:
|
||||||
|
$object->setTitle($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_EPOCH:
|
||||||
|
$object->setEpoch($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomExternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_TITLE:
|
||||||
|
return;
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_EPOCH:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
$type,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_TITLE:
|
||||||
|
$missing = $this->validateIsEmptyTextField(
|
||||||
|
$object->getTitle(),
|
||||||
|
$xactions);
|
||||||
|
|
||||||
|
if ($missing) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Required'),
|
||||||
|
pht('You must give the countdown a name.'),
|
||||||
|
nonempty(last($xactions), null));
|
||||||
|
|
||||||
|
$error->setIsMissingFieldError(true);
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PhabricatorCountdownTransaction::TYPE_EPOCH:
|
||||||
|
$date_value = AphrontFormDateControlValue::newFromEpoch(
|
||||||
|
$this->requireActor(),
|
||||||
|
$object->getEpoch());
|
||||||
|
if (!$date_value->isValid()) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Invalid'),
|
||||||
|
pht('You must give the countdown a valid end date.'),
|
||||||
|
nonempty(last($xactions), null));
|
||||||
|
|
||||||
|
$error->setIsMissingFieldError(true);
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shouldSendMail(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMailTagsMap() {
|
||||||
|
return array(
|
||||||
|
PhabricatorCountdownTransaction::MAILTAG_TITLE =>
|
||||||
|
pht('Someone changes the countdown title.'),
|
||||||
|
PhabricatorCountdownTransaction::MAILTAG_EPOCH =>
|
||||||
|
pht('Someone changes the countdown end date.'),
|
||||||
|
PhabricatorCountdownTransaction::MAILTAG_OTHER =>
|
||||||
|
pht('Other countdown activity not listed above occurs.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
|
$monogram = $object->getMonogram();
|
||||||
|
$name = $object->getName();
|
||||||
|
|
||||||
|
return id(new PhabricatorMetaMTAMail())
|
||||||
|
->setSubject("{$monogram}: {$name}")
|
||||||
|
->addHeader('Thread-Topic', $monogram);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildMailBody(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$body = parent::buildMailBody($object, $xactions);
|
||||||
|
|
||||||
|
$body->addLinkSection(
|
||||||
|
pht('COUNTDOWN DETAIL'),
|
||||||
|
PhabricatorEnv::getProductionURI('/'.$object->getMonogram()));
|
||||||
|
|
||||||
|
return $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
return array($object->getAuthorPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMailSubjectPrefix() {
|
||||||
|
return 'Countdown';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||||
|
return id(new PhabricatorCountdownReplyHandler())
|
||||||
|
->setMailReceiver($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shouldPublishFeedStory(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function supportsSearch() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownReplyHandler
|
||||||
|
extends PhabricatorApplicationTransactionReplyHandler {
|
||||||
|
|
||||||
|
public function validateMailReceiver($mail_receiver) {
|
||||||
|
if (!($mail_receiver instanceof PhabricatorCountdown)) {
|
||||||
|
throw new Exception(pht('Mail receiver is not a %s!', 'Countdown'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObjectPrefix() {
|
||||||
|
return 'C';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,62 +23,51 @@ final class PhabricatorCountdownQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withUpcoming($upcoming) {
|
public function withUpcoming() {
|
||||||
$this->upcoming = true;
|
$this->upcoming = true;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhabricatorCountdown();
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
$conn_r = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$data = queryfx_all(
|
|
||||||
$conn_r,
|
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn_r),
|
|
||||||
$this->buildOrderClause($conn_r),
|
|
||||||
$this->buildLimitClause($conn_r));
|
|
||||||
|
|
||||||
$countdowns = $table->loadAllFromArray($data);
|
|
||||||
|
|
||||||
return $countdowns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
public function newResultObject() {
|
||||||
$where = array();
|
return new PhabricatorCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
if ($this->ids) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'id IN (%Ld)',
|
'id IN (%Ld)',
|
||||||
$this->ids);
|
$this->ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->phids) {
|
if ($this->phids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'phid IN (%Ls)',
|
'phid IN (%Ls)',
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->authorPHIDs) {
|
if ($this->authorPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'authorPHID in (%Ls)',
|
'authorPHID in (%Ls)',
|
||||||
$this->authorPHIDs);
|
$this->authorPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->upcoming) {
|
if ($this->upcoming !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'epoch >= %d',
|
'epoch >= %d',
|
||||||
time());
|
PhabricatorTime::getNow());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|
|
@ -11,53 +11,39 @@ final class PhabricatorCountdownSearchEngine
|
||||||
return 'PhabricatorCountdownApplication';
|
return 'PhabricatorCountdownApplication';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
public function newQuery() {
|
||||||
$saved = new PhabricatorSavedQuery();
|
return new PhabricatorCountdownQuery();
|
||||||
$saved->setParameter(
|
|
||||||
'authorPHIDs',
|
|
||||||
$this->readUsersFromRequest($request, 'authors'));
|
|
||||||
|
|
||||||
$saved->setParameter('upcoming', $request->getBool('upcoming'));
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
protected function buildQueryFromParameters(array $map) {
|
||||||
$query = id(new PhabricatorCountdownQuery());
|
$query = $this->newQuery();
|
||||||
|
|
||||||
$author_phids = $saved->getParameter('authorPHIDs', array());
|
if ($map['authorPHIDs']) {
|
||||||
if ($author_phids) {
|
$query->withAuthorPHIDs($map['authorPHIDs']);
|
||||||
$query->withAuthorPHIDs($author_phids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($saved->getParameter('upcoming')) {
|
if ($map['upcoming'] && $map['upcoming'][0] == 'upcoming') {
|
||||||
$query->withUpcoming(true);
|
$query->withUpcoming();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSearchForm(
|
protected function buildCustomSearchFields() {
|
||||||
AphrontFormView $form,
|
|
||||||
PhabricatorSavedQuery $saved_query) {
|
|
||||||
|
|
||||||
$author_phids = $saved_query->getParameter('authorPHIDs', array());
|
return array(
|
||||||
$upcoming = $saved_query->getParameter('upcoming');
|
id(new PhabricatorUsersSearchField())
|
||||||
|
|
||||||
$form
|
|
||||||
->appendControl(
|
|
||||||
id(new AphrontFormTokenizerControl())
|
|
||||||
->setDatasource(new PhabricatorPeopleDatasource())
|
|
||||||
->setName('authors')
|
|
||||||
->setLabel(pht('Authors'))
|
->setLabel(pht('Authors'))
|
||||||
->setValue($author_phids))
|
->setKey('authorPHIDs')
|
||||||
->appendChild(
|
->setAliases(array('author', 'authors')),
|
||||||
id(new AphrontFormCheckboxControl())
|
|
||||||
->addCheckbox(
|
id(new PhabricatorSearchCheckboxesField())
|
||||||
'upcoming',
|
->setKey('upcoming')
|
||||||
1,
|
->setOptions(array(
|
||||||
pht('Show only countdowns that are still counting down.'),
|
'upcoming' => pht('Show only upcoming countdowns.'),
|
||||||
$upcoming));
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getURI($path) {
|
protected function getURI($path) {
|
||||||
|
@ -89,7 +75,7 @@ final class PhabricatorCountdownSearchEngine
|
||||||
'authorPHIDs',
|
'authorPHIDs',
|
||||||
array($this->requireViewer()->getPHID()));
|
array($this->requireViewer()->getPHID()));
|
||||||
case 'upcoming':
|
case 'upcoming':
|
||||||
return $query->setParameter('upcoming', true);
|
return $query->setParameter('upcoming', array('upcoming'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
|
@ -115,28 +101,35 @@ final class PhabricatorCountdownSearchEngine
|
||||||
$list->setUser($viewer);
|
$list->setUser($viewer);
|
||||||
foreach ($countdowns as $countdown) {
|
foreach ($countdowns as $countdown) {
|
||||||
$id = $countdown->getID();
|
$id = $countdown->getID();
|
||||||
|
$ended = false;
|
||||||
|
$icon = 'fa-clock-o';
|
||||||
|
$color = 'green';
|
||||||
|
$epoch = $countdown->getEpoch();
|
||||||
|
if ($epoch <= PhabricatorTime::getNow()) {
|
||||||
|
$ended = true;
|
||||||
|
$icon = 'fa-check-square-o';
|
||||||
|
$color = 'grey';
|
||||||
|
}
|
||||||
|
|
||||||
$item = id(new PHUIObjectItemView())
|
$item = id(new PHUIObjectItemView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setObject($countdown)
|
->setObject($countdown)
|
||||||
->setObjectName("C{$id}")
|
->setObjectName("C{$id}")
|
||||||
->setHeader($countdown->getTitle())
|
->setHeader($countdown->getTitle())
|
||||||
|
->setStatusIcon($icon.' '.$color)
|
||||||
->setHref($this->getApplicationURI("{$id}/"))
|
->setHref($this->getApplicationURI("{$id}/"))
|
||||||
->addByline(
|
->addByline(
|
||||||
pht(
|
pht(
|
||||||
'Created by %s',
|
'Created by %s',
|
||||||
$handles[$countdown->getAuthorPHID()]->renderLink()));
|
$handles[$countdown->getAuthorPHID()]->renderLink()));
|
||||||
|
|
||||||
$epoch = $countdown->getEpoch();
|
if ($ended) {
|
||||||
if ($epoch >= time()) {
|
$item->addAttribute(
|
||||||
$item->addIcon(
|
pht('Launched on %s', phabricator_datetime($epoch, $viewer)));
|
||||||
'none',
|
|
||||||
pht('Ends %s', phabricator_datetime($epoch, $viewer)));
|
|
||||||
} else {
|
|
||||||
$item->addIcon(
|
|
||||||
'delete',
|
|
||||||
pht('Ended %s', phabricator_datetime($epoch, $viewer)));
|
|
||||||
$item->setDisabled(true);
|
$item->setDisabled(true);
|
||||||
|
} else {
|
||||||
|
$item->addAttribute(
|
||||||
|
phabricator_datetime($epoch, $viewer));
|
||||||
}
|
}
|
||||||
|
|
||||||
$list->addItem($item);
|
$list->addItem($item);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownTransactionQuery
|
||||||
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
|
public function getTemplateApplicationTransaction() {
|
||||||
|
return new PhabricatorCountdownTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,12 +4,16 @@ final class PhabricatorCountdown extends PhabricatorCountdownDAO
|
||||||
implements
|
implements
|
||||||
PhabricatorPolicyInterface,
|
PhabricatorPolicyInterface,
|
||||||
PhabricatorFlaggableInterface,
|
PhabricatorFlaggableInterface,
|
||||||
PhabricatorSpacesInterface {
|
PhabricatorSubscribableInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface,
|
||||||
|
PhabricatorSpacesInterface,
|
||||||
|
PhabricatorProjectInterface {
|
||||||
|
|
||||||
protected $title;
|
protected $title;
|
||||||
protected $authorPHID;
|
protected $authorPHID;
|
||||||
protected $epoch;
|
protected $epoch;
|
||||||
protected $viewPolicy;
|
protected $viewPolicy;
|
||||||
|
protected $editPolicy;
|
||||||
|
|
||||||
protected $spacePHID;
|
protected $spacePHID;
|
||||||
|
|
||||||
|
@ -43,6 +47,48 @@ final class PhabricatorCountdown extends PhabricatorCountdownDAO
|
||||||
PhabricatorCountdownCountdownPHIDType::TYPECONST);
|
PhabricatorCountdownCountdownPHIDType::TYPECONST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMonogram() {
|
||||||
|
return 'C'.$this->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function isAutomaticallySubscribed($phid) {
|
||||||
|
return ($phid == $this->getAuthorPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldShowSubscribersProperty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldAllowSubscription($phid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new PhabricatorCountdownEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new PhabricatorCountdownTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willRenderTimeline(
|
||||||
|
PhabricatorApplicationTransactionView $timeline,
|
||||||
|
AphrontRequest $request) {
|
||||||
|
|
||||||
|
return $timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
@ -59,16 +105,16 @@ final class PhabricatorCountdown extends PhabricatorCountdownDAO
|
||||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
return $this->getViewPolicy();
|
return $this->getViewPolicy();
|
||||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
return PhabricatorPolicies::POLICY_NOONE;
|
return $this->getEditPolicy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
return ($viewer->getPHID() == $this->getAuthorPHID());
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function describeAutomaticCapability($capability) {
|
public function describeAutomaticCapability($capability) {
|
||||||
return pht('The author of a countdown can always view and edit it.');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -( PhabricatorSpacesInterface )------------------------------------------- */
|
/* -( PhabricatorSpacesInterface )------------------------------------------- */
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownSchemaSpec
|
||||||
|
extends PhabricatorConfigSchemaSpec {
|
||||||
|
|
||||||
|
public function buildSchemata() {
|
||||||
|
$this->buildEdgeSchemata(new PhabricatorCountdown());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownTransaction
|
||||||
|
extends PhabricatorApplicationTransaction {
|
||||||
|
|
||||||
|
const TYPE_TITLE = 'countdown:title';
|
||||||
|
const TYPE_EPOCH = 'countdown:epoch';
|
||||||
|
|
||||||
|
const MAILTAG_TITLE = 'countdown:title';
|
||||||
|
const MAILTAG_EPOCH = 'countdown:epoch';
|
||||||
|
const MAILTAG_OTHER = 'countdown:other';
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'countdown';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return PhabricatorCountdownCountdownPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionCommentObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
$object_phid = $this->getObjectPHID();
|
||||||
|
|
||||||
|
$old = $this->getOldValue();
|
||||||
|
$new = $this->getNewValue();
|
||||||
|
|
||||||
|
$type = $this->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case self::TYPE_TITLE:
|
||||||
|
if ($old === null) {
|
||||||
|
return pht(
|
||||||
|
'%s created this countdown.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s renamed this countdown from "%s" to "%s".',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$old,
|
||||||
|
$new);
|
||||||
|
}
|
||||||
|
case self::TYPE_EPOCH:
|
||||||
|
if ($old === null) {
|
||||||
|
return pht(
|
||||||
|
'%s set this countdown to end on %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
phabricator_datetime($new, $this->getViewer()));
|
||||||
|
} else if ($old != $new) {
|
||||||
|
return pht(
|
||||||
|
'%s updated this countdown to end on %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
phabricator_datetime($new, $this->getViewer()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
$object_phid = $this->getObjectPHID();
|
||||||
|
|
||||||
|
$old = $this->getOldValue();
|
||||||
|
$new = $this->getNewValue();
|
||||||
|
|
||||||
|
$type = $this->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case self::TYPE_TITLE:
|
||||||
|
if ($old === null) {
|
||||||
|
return pht(
|
||||||
|
'%s created %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s renamed %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getTitleForFeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMailTags() {
|
||||||
|
$tags = parent::getMailTags();
|
||||||
|
|
||||||
|
switch ($this->getTransactionType()) {
|
||||||
|
case self::TYPE_TITLE:
|
||||||
|
$tags[] = self::MAILTAG_TITLE;
|
||||||
|
break;
|
||||||
|
case self::TYPE_EPOCH:
|
||||||
|
$tags[] = self::MAILTAG_EPOCH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$tags[] = self::MAILTAG_OTHER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue