Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F18888227
D15655.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
37 KB
Referenced Files
None
Subscribers
None
D15655.diff
View Options
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
@@ -139,6 +139,7 @@
'AphrontDefaultApplicationConfiguration' => 'aphront/configuration/AphrontDefaultApplicationConfiguration.php',
'AphrontDialogResponse' => 'aphront/response/AphrontDialogResponse.php',
'AphrontDialogView' => 'view/AphrontDialogView.php',
+ 'AphrontEpochHTTPParameterType' => 'aphront/httpparametertype/AphrontEpochHTTPParameterType.php',
'AphrontException' => 'aphront/exception/AphrontException.php',
'AphrontFileResponse' => 'aphront/response/AphrontFileResponse.php',
'AphrontFormCheckboxControl' => 'view/form/control/AphrontFormCheckboxControl.php',
@@ -2100,7 +2101,6 @@
'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php',
'PhabricatorCountdown' => 'applications/countdown/storage/PhabricatorCountdown.php',
'PhabricatorCountdownApplication' => 'applications/countdown/application/PhabricatorCountdownApplication.php',
- 'PhabricatorCountdownCommentController' => 'applications/countdown/controller/PhabricatorCountdownCommentController.php',
'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php',
'PhabricatorCountdownCountdownPHIDType' => 'applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php',
'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php',
@@ -2108,6 +2108,7 @@
'PhabricatorCountdownDefaultViewCapability' => 'applications/countdown/capability/PhabricatorCountdownDefaultViewCapability.php',
'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/PhabricatorCountdownDeleteController.php',
'PhabricatorCountdownEditController' => 'applications/countdown/controller/PhabricatorCountdownEditController.php',
+ 'PhabricatorCountdownEditEngine' => 'applications/countdown/editor/PhabricatorCountdownEditEngine.php',
'PhabricatorCountdownEditor' => 'applications/countdown/editor/PhabricatorCountdownEditor.php',
'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php',
'PhabricatorCountdownMailReceiver' => 'applications/countdown/mail/PhabricatorCountdownMailReceiver.php',
@@ -2325,6 +2326,7 @@
'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php',
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
+ 'PhabricatorEpochEditField' => 'applications/transactions/editfield/PhabricatorEpochEditField.php',
'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php',
'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php',
'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php',
@@ -4261,6 +4263,7 @@
'AphrontView',
'AphrontResponseProducerInterface',
),
+ 'AphrontEpochHTTPParameterType' => 'AphrontHTTPParameterType',
'AphrontException' => 'Exception',
'AphrontFileResponse' => 'AphrontResponse',
'AphrontFormCheckboxControl' => 'AphrontFormControl',
@@ -6525,7 +6528,6 @@
'PhabricatorProjectInterface',
),
'PhabricatorCountdownApplication' => 'PhabricatorApplication',
- 'PhabricatorCountdownCommentController' => 'PhabricatorCountdownController',
'PhabricatorCountdownController' => 'PhabricatorController',
'PhabricatorCountdownCountdownPHIDType' => 'PhabricatorPHIDType',
'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
@@ -6533,6 +6535,7 @@
'PhabricatorCountdownDefaultViewCapability' => 'PhabricatorPolicyCapability',
'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
+ 'PhabricatorCountdownEditEngine' => 'PhabricatorEditEngine',
'PhabricatorCountdownEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
'PhabricatorCountdownMailReceiver' => 'PhabricatorObjectMailReceiver',
@@ -6776,6 +6779,7 @@
'PhabricatorEmptyQueryException' => 'Exception',
'PhabricatorEnv' => 'Phobject',
'PhabricatorEnvTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorEpochEditField' => 'PhabricatorEditField',
'PhabricatorEvent' => 'PhutilEvent',
'PhabricatorEventEngine' => 'Phobject',
'PhabricatorEventListener' => 'PhutilEventListener',
diff --git a/src/aphront/httpparametertype/AphrontEpochHTTPParameterType.php b/src/aphront/httpparametertype/AphrontEpochHTTPParameterType.php
new file mode 100644
--- /dev/null
+++ b/src/aphront/httpparametertype/AphrontEpochHTTPParameterType.php
@@ -0,0 +1,37 @@
+<?php
+
+final class AphrontEpochHTTPParameterType
+ extends AphrontHTTPParameterType {
+
+ protected function getParameterExists(AphrontRequest $request, $key) {
+ return $request->getExists($key) ||
+ $request->getExists($key.'_d');
+ }
+
+ protected function getParameterValue(AphrontRequest $request, $key) {
+ return AphrontFormDateControlValue::newFromRequest($request, $key);
+ }
+
+ protected function getParameterTypeName() {
+ return 'epoch';
+ }
+
+ protected function getParameterFormatDescriptions() {
+ return array(
+ pht('An epoch timestamp, as an integer.'),
+ pht('An absolute date, as a string.'),
+ pht('A relative date, as a string.'),
+ pht('Separate date and time inputs, as strings.'),
+ );
+ }
+
+ protected function getParameterExamples() {
+ return array(
+ 'v=1460050737',
+ 'v=2022-01-01',
+ 'v=yesterday',
+ 'v_d=2022-01-01&v_t=12:34',
+ );
+ }
+
+}
diff --git a/src/applications/countdown/application/PhabricatorCountdownApplication.php b/src/applications/countdown/application/PhabricatorCountdownApplication.php
--- a/src/applications/countdown/application/PhabricatorCountdownApplication.php
+++ b/src/applications/countdown/application/PhabricatorCountdownApplication.php
@@ -46,9 +46,7 @@
=> 'PhabricatorCountdownViewController',
'comment/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCountdownCommentController',
- 'edit/(?:(?P<id>[1-9]\d*)/)?'
- => 'PhabricatorCountdownEditController',
- 'create/'
+ $this->getEditRoutePattern('edit/')
=> 'PhabricatorCountdownEditController',
'delete/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCountdownDeleteController',
diff --git a/src/applications/countdown/controller/PhabricatorCountdownCommentController.php b/src/applications/countdown/controller/PhabricatorCountdownCommentController.php
deleted file mode 100644
--- a/src/applications/countdown/controller/PhabricatorCountdownCommentController.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-final class PhabricatorCountdownCommentController
- extends PhabricatorCountdownController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- if (!$request->isFormPost()) {
- return new Aphront400Response();
- }
-
- $countdown = id(new PhabricatorCountdownQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->executeOne();
- if (!$countdown) {
- return new Aphront404Response();
- }
-
- $is_preview = $request->isPreviewRequest();
- $draft = PhabricatorDraft::buildFromRequest($request);
-
- $view_uri = '/'.$countdown->getMonogram();
-
- $xactions = array();
- $xactions[] = id(new PhabricatorCountdownTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
- ->attachComment(
- id(new PhabricatorCountdownTransactionComment())
- ->setContent($request->getStr('comment')));
-
- $editor = id(new PhabricatorCountdownEditor())
- ->setActor($viewer)
- ->setContinueOnNoEffect($request->isContinueRequest())
- ->setContentSourceFromRequest($request)
- ->setIsPreview($is_preview);
-
- try {
- $xactions = $editor->applyTransactions($countdown, $xactions);
- } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
- return id(new PhabricatorApplicationTransactionNoEffectResponse())
- ->setCancelURI($view_uri)
- ->setException($ex);
- }
-
- if ($draft) {
- $draft->replaceOrDelete();
- }
-
- if ($request->isAjax() && $is_preview) {
- return id(new PhabricatorApplicationTransactionResponse())
- ->setViewer($viewer)
- ->setTransactions($xactions)
- ->setIsPreview($is_preview);
- } else {
- return id(new AphrontRedirectResponse())
- ->setURI($view_uri);
- }
- }
-
-}
diff --git a/src/applications/countdown/controller/PhabricatorCountdownController.php b/src/applications/countdown/controller/PhabricatorCountdownController.php
--- a/src/applications/countdown/controller/PhabricatorCountdownController.php
+++ b/src/applications/countdown/controller/PhabricatorCountdownController.php
@@ -7,16 +7,5 @@
->setSearchEngine(new PhabricatorCountdownSearchEngine());
}
- protected function buildApplicationCrumbs() {
- $crumbs = parent::buildApplicationCrumbs();
-
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Countdown'))
- ->setHref($this->getApplicationURI('create/'))
- ->setIcon('fa-plus-square'));
-
- return $crumbs;
- }
}
diff --git a/src/applications/countdown/controller/PhabricatorCountdownEditController.php b/src/applications/countdown/controller/PhabricatorCountdownEditController.php
--- a/src/applications/countdown/controller/PhabricatorCountdownEditController.php
+++ b/src/applications/countdown/controller/PhabricatorCountdownEditController.php
@@ -4,205 +4,9 @@
extends PhabricatorCountdownController {
public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- if ($id) {
- $countdown = id(new PhabricatorCountdownQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->executeOne();
- if (!$countdown) {
- return new Aphront404Response();
- }
- $date_value = AphrontFormDateControlValue::newFromEpoch(
- $viewer,
- $countdown->getEpoch());
- $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
- $countdown->getPHID(),
- PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
- $v_projects = array_reverse($v_projects);
- $title = pht('Edit Countdown: %s', $countdown->getTitle());
- } else {
- $title = pht('Create Countdown');
- $countdown = PhabricatorCountdown::initializeNewCountdown($viewer);
- $date_value = AphrontFormDateControlValue::newFromEpoch(
- $viewer, PhabricatorTime::getNow());
- $v_projects = array();
- }
-
- $errors = array();
- $e_text = true;
- $e_epoch = null;
-
- $v_text = $countdown->getTitle();
- $v_desc = $countdown->getDescription();
- $v_space = $countdown->getSpacePHID();
- $v_view = $countdown->getViewPolicy();
- $v_edit = $countdown->getEditPolicy();
-
- if ($request->isFormPost()) {
- $v_text = $request->getStr('title');
- $v_desc = $request->getStr('description');
- $v_space = $request->getStr('spacePHID');
- $date_value = AphrontFormDateControlValue::newFromRequest(
- $request,
- 'epoch');
- $v_view = $request->getStr('viewPolicy');
- $v_edit = $request->getStr('editPolicy');
- $v_projects = $request->getArr('projects');
-
- $type_title = PhabricatorCountdownTransaction::TYPE_TITLE;
- $type_epoch = PhabricatorCountdownTransaction::TYPE_EPOCH;
- $type_description = PhabricatorCountdownTransaction::TYPE_DESCRIPTION;
- $type_space = PhabricatorTransactions::TYPE_SPACE;
- $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
- $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
-
- $xactions = array();
-
- $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_description)
- ->setNewValue($v_desc);
-
- $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);
-
- return id(new AphrontRedirectResponse())
- ->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->setBorder(true);
-
- $cancel_uri = '/countdown/';
- if ($countdown->getID()) {
- $cancel_uri = '/countdown/'.$countdown->getID().'/';
- $crumbs->addTextCrumb('C'.$countdown->getID(), $cancel_uri);
- $crumbs->addTextCrumb(pht('Edit'));
- $submit_label = pht('Save Changes');
- $header_icon = 'fa-pencil';
- } else {
- $crumbs->addTextCrumb(pht('Create Countdown'));
- $submit_label = pht('Create Countdown');
- $header_icon = 'fa-plus-square';
- }
-
- $policies = id(new PhabricatorPolicyQuery())
- ->setViewer($viewer)
- ->setObject($countdown)
- ->execute();
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->setAction($request->getRequestURI()->getPath())
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Title'))
- ->setValue($v_text)
- ->setName('title')
- ->setError($e_text))
- ->appendControl(
- id(new AphrontFormDateControl())
- ->setName('epoch')
- ->setLabel(pht('End Date'))
- ->setError($e_epoch)
- ->setValue($date_value))
- ->appendControl(
- id(new PhabricatorRemarkupControl())
- ->setName('description')
- ->setLabel(pht('Description'))
- ->setValue($v_desc))
- ->appendControl(
- id(new AphrontFormPolicyControl())
- ->setName('viewPolicy')
- ->setPolicyObject($countdown)
- ->setPolicies($policies)
- ->setSpacePHID($v_space)
- ->setValue($v_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(
- id(new AphrontFormSubmitControl())
- ->addCancelButton($cancel_uri)
- ->setValue($submit_label));
-
- $form_box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Countdown'))
- ->setFormErrors($errors)
- ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
- ->setForm($form);
-
- $header = id(new PHUIHeaderView())
- ->setHeader($title)
- ->setHeaderIcon($header_icon);
-
- $view = id(new PHUITwoColumnView())
- ->setHeader($header)
- ->setFooter($form_box);
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild(
- array(
- $view,
- ));
+ return id(new PhabricatorCountdownEditEngine())
+ ->setController($this)
+ ->buildResponse();
}
}
diff --git a/src/applications/countdown/controller/PhabricatorCountdownListController.php b/src/applications/countdown/controller/PhabricatorCountdownListController.php
--- a/src/applications/countdown/controller/PhabricatorCountdownListController.php
+++ b/src/applications/countdown/controller/PhabricatorCountdownListController.php
@@ -13,4 +13,14 @@
->buildResponse();
}
+ protected function buildApplicationCrumbs() {
+ $crumbs = parent::buildApplicationCrumbs();
+
+ id(new PhabricatorCountdownEditEngine())
+ ->setViewer($this->getViewer())
+ ->addActionToCrumbs($crumbs);
+
+ return $crumbs;
+ }
+
}
diff --git a/src/applications/countdown/controller/PhabricatorCountdownViewController.php b/src/applications/countdown/controller/PhabricatorCountdownViewController.php
--- a/src/applications/countdown/controller/PhabricatorCountdownViewController.php
+++ b/src/applications/countdown/controller/PhabricatorCountdownViewController.php
@@ -55,12 +55,15 @@
$timeline = $this->buildTransactionTimeline(
$countdown,
new PhabricatorCountdownTransactionQuery());
- $add_comment = $this->buildCommentForm($countdown);
+
+ $comment_view = id(new PhabricatorCountdownEditEngine())
+ ->setViewer($viewer)
+ ->buildEditEngineCommentView($countdown);
$content = array(
$countdown_view,
$timeline,
- $add_comment,
+ $comment_view,
);
$view = id(new PHUITwoColumnView())
@@ -135,25 +138,4 @@
->setContent($content);
}
- private function buildCommentForm(PhabricatorCountdown $countdown) {
- $viewer = $this->getViewer();
-
- $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
-
- $add_comment_header = $is_serious
- ? pht('Add Comment')
- : pht('Last Words');
-
- $draft = PhabricatorDraft::newFromUserAndKey(
- $viewer, $countdown->getPHID());
-
- return id(new PhabricatorApplicationTransactionCommentView())
- ->setUser($viewer)
- ->setObjectPHID($countdown->getPHID())
- ->setDraft($draft)
- ->setHeaderText($add_comment_header)
- ->setAction($this->getApplicationURI('/comment/'.$countdown->getID().'/'))
- ->setSubmitButtonName(pht('Add Comment'));
- }
-
}
diff --git a/src/applications/countdown/editor/PhabricatorCountdownEditEngine.php b/src/applications/countdown/editor/PhabricatorCountdownEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/countdown/editor/PhabricatorCountdownEditEngine.php
@@ -0,0 +1,108 @@
+<?php
+
+final class PhabricatorCountdownEditEngine
+ extends PhabricatorEditEngine {
+
+ const ENGINECONST = 'countdown.countdown';
+
+ public function isEngineConfigurable() {
+ return false;
+ }
+
+ public function getEngineName() {
+ return pht('Countdowns');
+ }
+
+ public function getSummaryHeader() {
+ return pht('Edit Countdowns');
+ }
+
+ public function getSummaryText() {
+ return pht('Creates and edits countdowns.');
+ }
+
+ public function getEngineApplicationClass() {
+ return 'PhabricatorCountdownApplication';
+ }
+
+ protected function newEditableObject() {
+ return PhabricatorCountdown::initializeNewCountdown(
+ $this->getViewer());
+ }
+
+ protected function newObjectQuery() {
+ return id(new PhabricatorCountdownQuery());
+ }
+
+ protected function getObjectCreateTitleText($object) {
+ return pht('Create Countdown');
+ }
+
+ protected function getObjectCreateButtonText($object) {
+ return pht('Create Countdown');
+ }
+
+ protected function getObjectEditTitleText($object) {
+ return pht('Edit Countdown: %s', $object->getTitle());
+ }
+
+ protected function getObjectEditShortText($object) {
+ return pht('Edit Countdown');
+ }
+
+ protected function getObjectCreateShortText() {
+ return pht('Create Countdown');
+ }
+
+ protected function getObjectName() {
+ return pht('Countdown');
+ }
+
+ protected function getCommentViewHeaderText($object) {
+ return pht('Last Words');
+ }
+
+ protected function getCommentViewButtonText($object) {
+ return pht('Contemplate Infinity');
+ }
+
+ protected function getObjectViewURI($object) {
+ return $object->getURI();
+ }
+
+ protected function buildCustomEditFields($object) {
+ $epoch_value = $object->getEpoch();
+ if ($epoch_value === null) {
+ $epoch_value = PhabricatorTime::getNow();
+ }
+
+ return array(
+ id(new PhabricatorTextEditField())
+ ->setKey('name')
+ ->setLabel(pht('Name'))
+ ->setIsRequired(true)
+ ->setTransactionType(PhabricatorCountdownTransaction::TYPE_TITLE)
+ ->setDescription(pht('The countdown name.'))
+ ->setConduitDescription(pht('Rename the countdown.'))
+ ->setConduitTypeDescription(pht('New countdown name.'))
+ ->setValue($object->getTitle()),
+ id(new PhabricatorEpochEditField())
+ ->setKey('epoch')
+ ->setLabel(pht('End Date'))
+ ->setTransactionType(PhabricatorCountdownTransaction::TYPE_EPOCH)
+ ->setDescription(pht('Date when the countdown ends.'))
+ ->setConduitDescription(pht('Change the end date of the countdown.'))
+ ->setConduitTypeDescription(pht('New countdown end date.'))
+ ->setValue($epoch_value),
+ id(new PhabricatorRemarkupEditField())
+ ->setKey('description')
+ ->setLabel(pht('Description'))
+ ->setTransactionType(PhabricatorCountdownTransaction::TYPE_DESCRIPTION)
+ ->setDescription(pht('Description of the countdown.'))
+ ->setConduitDescription(pht('Change the countdown description.'))
+ ->setConduitTypeDescription(pht('New description.'))
+ ->setValue($object->getDescription()),
+ );
+ }
+
+}
diff --git a/src/applications/countdown/editor/PhabricatorCountdownEditor.php b/src/applications/countdown/editor/PhabricatorCountdownEditor.php
--- a/src/applications/countdown/editor/PhabricatorCountdownEditor.php
+++ b/src/applications/countdown/editor/PhabricatorCountdownEditor.php
@@ -120,19 +120,27 @@
}
break;
case PhabricatorCountdownTransaction::TYPE_EPOCH:
- $date_value = AphrontFormDateControlValue::newFromEpoch(
- $this->requireActor(),
- $object->getEpoch());
- if (!$date_value->isValid()) {
+ if (!$object->getEpoch() && !$xactions) {
$error = new PhabricatorApplicationTransactionValidationError(
$type,
- pht('Invalid'),
- pht('You must give the countdown a valid end date.'),
- nonempty(last($xactions), null));
-
+ pht('Required'),
+ pht('You must give the countdown an end date.'),
+ null);
$error->setIsMissingFieldError(true);
$errors[] = $error;
}
+
+ foreach ($xactions as $xaction) {
+ $value = $xaction->getNewValue();
+ if (!$value->isValid()) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht('You must give the countdown a valid end date.'),
+ $xaction);
+ $errors[] = $error;
+ }
+ }
break;
}
diff --git a/src/applications/countdown/storage/PhabricatorCountdown.php b/src/applications/countdown/storage/PhabricatorCountdown.php
--- a/src/applications/countdown/storage/PhabricatorCountdown.php
+++ b/src/applications/countdown/storage/PhabricatorCountdown.php
@@ -28,10 +28,13 @@
$view_policy = $app->getPolicy(
PhabricatorCountdownDefaultViewCapability::CAPABILITY);
+ $edit_policy = $app->getPolicy(
+ PhabricatorCountdownDefaultEditCapability::CAPABILITY);
+
return id(new PhabricatorCountdown())
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
- ->setEpoch(PhabricatorTime::getNow())
+ ->setEditPolicy($edit_policy)
->setSpacePHID($actor->getDefaultSpacePHID());
}
@@ -55,6 +58,10 @@
return 'C'.$this->getID();
}
+ public function getURI() {
+ return '/'.$this->getMonogram();
+ }
+
public function save() {
if (!$this->getMailKey()) {
$this->setMailKey(Filesystem::readRandomCharacters(20));
diff --git a/src/applications/countdown/storage/PhabricatorCountdownTransaction.php b/src/applications/countdown/storage/PhabricatorCountdownTransaction.php
--- a/src/applications/countdown/storage/PhabricatorCountdownTransaction.php
+++ b/src/applications/countdown/storage/PhabricatorCountdownTransaction.php
@@ -33,42 +33,20 @@
$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);
- }
- break;
+ return pht(
+ '%s renamed this countdown from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $old,
+ $new);
case self::TYPE_DESCRIPTION:
- if ($old === null) {
- return pht(
- '%s set the description of this countdown.',
- $this->renderHandleLink($author_phid));
- } else {
- return pht(
- '%s edited the description of this countdown.',
- $this->renderHandleLink($author_phid));
- }
- break;
+ return pht(
+ '%s edited the description of this countdown.',
+ $this->renderHandleLink($author_phid));
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 pht(
+ '%s updated this countdown to end on %s.',
+ $this->renderHandleLink($author_phid),
+ phabricator_datetime($new, $this->getViewer()));
}
return parent::getTitle();
@@ -84,47 +62,20 @@
$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 pht(
+ '%s renamed %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
case self::TYPE_DESCRIPTION:
- if ($old === null) {
- return pht(
- '%s set the description of %s.',
- $this->renderHandleLink($author_phid),
- $this->renderHandleLink($object_phid));
-
- } else {
- return pht(
- '%s edited the description of %s.',
- $this->renderHandleLink($author_phid),
- $this->renderHandleLink($object_phid));
- }
- break;
+ return pht(
+ '%s edited the description of %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
case self::TYPE_EPOCH:
- if ($old === null) {
- return pht(
- '%s set the end date of %s.',
- $this->renderHandleLink($author_phid),
- $this->renderHandleLink($object_phid));
-
- } else {
- return pht(
- '%s edited the end date of %s.',
- $this->renderHandleLink($author_phid),
- $this->renderHandleLink($object_phid));
- }
- break;
+ return pht(
+ '%s edited the end date of %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
}
return parent::getTitleForFeed();
@@ -150,15 +101,6 @@
return $tags;
}
- public function shouldHide() {
- $old = $this->getOldValue();
- switch ($this->getTransactionType()) {
- case self::TYPE_DESCRIPTION:
- return ($old === null);
- }
- return parent::shouldHide();
- }
-
public function hasChangeDetails() {
switch ($this->getTransactionType()) {
case self::TYPE_DESCRIPTION:
diff --git a/src/applications/transactions/editfield/PhabricatorEpochEditField.php b/src/applications/transactions/editfield/PhabricatorEpochEditField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/editfield/PhabricatorEpochEditField.php
@@ -0,0 +1,21 @@
+<?php
+
+final class PhabricatorEpochEditField
+ extends PhabricatorEditField {
+
+ protected function newControl() {
+ return id(new AphrontFormDateControl())
+ ->setViewer($this->getViewer());
+ }
+
+ protected function newHTTPParameterType() {
+ return new AphrontEpochHTTPParameterType();
+ }
+
+ protected function newConduitParameterType() {
+ // TODO: This isn't correct, but we don't have any methods which use this
+ // yet.
+ return new ConduitIntParameterType();
+ }
+
+}
diff --git a/src/view/form/control/AphrontFormDateControl.php b/src/view/form/control/AphrontFormDateControl.php
--- a/src/view/form/control/AphrontFormDateControl.php
+++ b/src/view/form/control/AphrontFormDateControl.php
@@ -130,10 +130,13 @@
$date_format = $this->getDateFormat();
$timezone = $this->getTimezone();
- $datetime = new DateTime($this->valueDate, $timezone);
- $date = $datetime->format($date_format);
+ try {
+ $datetime = new DateTime($this->valueDate, $timezone);
+ } catch (Exception $ex) {
+ return $this->valueDate;
+ }
- return $date;
+ return $datetime->format($date_format);
}
private function getTimeFormat() {
diff --git a/src/view/form/control/AphrontFormDateControlValue.php b/src/view/form/control/AphrontFormDateControlValue.php
--- a/src/view/form/control/AphrontFormDateControlValue.php
+++ b/src/view/form/control/AphrontFormDateControlValue.php
@@ -84,10 +84,33 @@
$value = new AphrontFormDateControlValue();
$value->viewer = $request->getViewer();
- list($value->valueDate, $value->valueTime) =
- $value->getFormattedDateFromDate(
- $request->getStr($key.'_d'),
- $request->getStr($key.'_t'));
+ $datetime = $request->getStr($key);
+ if (strlen($datetime)) {
+ $date = $datetime;
+ $time = null;
+ } else {
+ $date = $request->getStr($key.'_d');
+ $time = $request->getStr($key.'_t');
+ }
+
+ // If this looks like an epoch timestamp, prefix it with "@" so that
+ // DateTime() reads it as one. Assume small numbers are a "Ymd" digit
+ // string instead of an epoch timestamp for a time in 1970.
+ if (ctype_digit($date) && ($date > 30000000)) {
+ $date = '@'.$date;
+ $time = null;
+ }
+
+ $value->valueDate = $date;
+ $value->valueTime = $time;
+
+ $formatted = $value->getFormattedDateFromDate(
+ $value->valueDate,
+ $value->valueTime);
+
+ if ($formatted) {
+ list($value->valueDate, $value->valueTime) = $formatted;
+ }
$value->valueEnabled = $request->getStr($key.'_e');
return $value;
@@ -96,6 +119,11 @@
public static function newFromEpoch(PhabricatorUser $viewer, $epoch) {
$value = new AphrontFormDateControlValue();
$value->viewer = $viewer;
+
+ if (!$epoch) {
+ return $value;
+ }
+
$readable = $value->formatTime($epoch, 'Y!m!d!g:i A');
$readable = explode('!', $readable, 4);
@@ -120,10 +148,16 @@
$value = new AphrontFormDateControlValue();
$value->viewer = $viewer;
- list($value->valueDate, $value->valueTime) =
- $value->getFormattedDateFromDate(
- idx($dictionary, 'd'),
- idx($dictionary, 't'));
+ $value->valueDate = idx($dictionary, 'd');
+ $value->valueTime = idx($dictionary, 't');
+
+ $formatted = $value->getFormattedDateFromDate(
+ $value->valueDate,
+ $value->valueTime);
+
+ if ($formatted) {
+ list($value->valueDate, $value->valueTime) = $formatted;
+ }
$value->valueEnabled = idx($dictionary, 'e');
@@ -170,37 +204,12 @@
return null;
}
- $date = $this->valueDate;
- $time = $this->valueTime;
- $zone = $this->getTimezone();
-
- if (!strlen($time)) {
+ $datetime = $this->newDateTime($this->valueDate, $this->valueTime);
+ if (!$datetime) {
return null;
}
- $colloquial = array(
- 'elevenses' => '11:00 AM',
- 'morning tea' => '11:00 AM',
- 'noon' => '12:00 PM',
- 'high noon' => '12:00 PM',
- 'lunch' => '12:00 PM',
- 'tea time' => '3:00 PM',
- 'witching hour' => '12:00 AM',
- 'midnight' => '12:00 AM',
- );
-
- $normalized = phutil_utf8_strtolower($time);
- if (isset($colloquial[$normalized])) {
- $time = $colloquial[$normalized];
- }
-
- try {
- $datetime = new DateTime("{$date} {$time}", $zone);
- $value = $datetime->format('U');
- } catch (Exception $ex) {
- $value = null;
- }
- return $value;
+ return $datetime->format('U');
}
private function getTimeFormat() {
@@ -214,25 +223,34 @@
}
private function getFormattedDateFromDate($date, $time) {
- $original_input = $date;
- $zone = $this->getTimezone();
- $separator = $this->getFormatSeparator();
- $parts = preg_split('@[,./:-]@', $date);
- $date = implode($separator, $parts);
- $date = id(new DateTime($date, $zone));
-
- if ($date) {
- $date = $date->format($this->getDateFormat());
- } else {
- $date = $original_input;
+ $datetime = $this->newDateTime($date, $time);
+ if (!$datetime) {
+ return null;
}
- $date = id(new DateTime("{$date} {$time}", $zone));
-
return array(
- $date->format($this->getDateFormat()),
- $date->format($this->getTimeFormat()),
+ $datetime->format($this->getDateFormat()),
+ $datetime->format($this->getTimeFormat()),
);
+
+ return array($date, $time);
+ }
+
+ private function newDateTime($date, $time) {
+ $date = $this->getStandardDateFormat($date);
+ $time = $this->getStandardTimeFormat($time);
+ try {
+ $datetime = new DateTime("{$date} {$time}");
+ } catch (Exception $ex) {
+ return null;
+ }
+
+ // Set the timezone explicitly because it is ignored in the constructor
+ // if the date is an epoch timestamp.
+ $zone = $this->getTimezone();
+ $datetime->setTimezone($zone);
+
+ return $datetime;
}
private function getFormattedDateFromParts(
@@ -261,16 +279,7 @@
}
public function getDateTime() {
- $epoch = $this->getEpoch();
- $date = null;
-
- if ($epoch) {
- $zone = $this->getTimezone();
- $date = new DateTime('@'.$epoch);
- $date->setTimeZone($zone);
- }
-
- return $date;
+ return $this->newDateTime();
}
private function getTimezone() {
@@ -283,5 +292,56 @@
return $this->zone;
}
+ private function getStandardDateFormat($date) {
+ $colloquial = array(
+ 'newyear' => 'January 1',
+ 'valentine' => 'February 14',
+ 'pi' => 'March 14',
+ 'christma' => 'December 25',
+ );
+
+ // Lowercase the input, then remove punctuation, a "day" suffix, and an
+ // "s" if one is present. This allows all of these to match. This allows
+ // variations like "New Year's Day" and "New Year" to both match.
+ $normalized = phutil_utf8_strtolower($date);
+ $normalized = preg_replace('/[^a-z]/', '', $normalized);
+ $normalized = preg_replace('/day\z/', '', $normalized);
+ $normalized = preg_replace('/s\z/', '', $normalized);
+
+ if (isset($colloquial[$normalized])) {
+ return $colloquial[$normalized];
+ }
+
+ $separator = $this->getFormatSeparator();
+ $parts = preg_split('@[,./:-]@', $date);
+ return implode($separator, $parts);
+ }
+
+ private function getStandardTimeFormat($time) {
+ $colloquial = array(
+ 'crack of dawn' => '5:00 AM',
+ 'dawn' => '6:00 AM',
+ 'early' => '7:00 AM',
+ 'morning' => '8:00 AM',
+ 'elevenses' => '11:00 AM',
+ 'morning tea' => '11:00 AM',
+ 'noon' => '12:00 PM',
+ 'high noon' => '12:00 PM',
+ 'lunch' => '12:00 PM',
+ 'afternoon' => '2:00 PM',
+ 'tea time' => '3:00 PM',
+ 'evening' => '7:00 PM',
+ 'late' => '11:00 PM',
+ 'witching hour' => '12:00 AM',
+ 'midnight' => '12:00 AM',
+ );
+
+ $normalized = phutil_utf8_strtolower($time);
+ if (isset($colloquial[$normalized])) {
+ $time = $colloquial[$normalized];
+ }
+
+ return $time;
+ }
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Nov 8 2025, 7:07 AM (9 w, 2 h ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/vr/4d/4qfeguci5kao6vzx
Default Alt Text
D15655.diff (37 KB)
Attached To
Mode
D15655: Convert Countdown to EditEngine
Attached
Detach File
Event Timeline
Log In to Comment