1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Switch Calendar to EditEngine

Summary:
Ref T9275. This throws away the old EditController and switches fully to EditEngine.

There's still some sketchy behavior (particularly, no JS stuff yet) but I think all the basics work properly.

Test Plan: Created and edited events via EditEngine, everything seemed to work alright.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9275

Differential Revision: https://secure.phabricator.com/D16283
This commit is contained in:
epriestley 2016-07-12 13:05:45 -07:00
parent a46a4362db
commit ea813985a2
8 changed files with 18 additions and 632 deletions

View file

@ -2024,7 +2024,6 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php',
'PhabricatorCalendarEventDragController' => 'applications/calendar/controller/PhabricatorCalendarEventDragController.php',
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
'PhabricatorCalendarEventEditProController' => 'applications/calendar/controller/PhabricatorCalendarEventEditProController.php',
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php',
'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php',
@ -6633,7 +6632,6 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventDragController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditProController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand',
'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine',

View file

@ -47,11 +47,7 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
'(?P<month>\d+)/)?(?:(?P<day>\d+)/)?)?'
=> 'PhabricatorCalendarEventListController',
'event/' => array(
$this->getEditRoutePattern('editpro/')
=> 'PhabricatorCalendarEventEditProController',
'create/'
=> 'PhabricatorCalendarEventEditController',
'edit/(?P<id>[1-9]\d*)/'
$this->getEditRoutePattern('edit/')
=> 'PhabricatorCalendarEventEditController',
'drag/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventDragController',
@ -59,8 +55,6 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
=> 'PhabricatorCalendarEventCancelController',
'(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventJoinController',
'comment/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventCommentController',
),
),
);

View file

@ -2,32 +2,4 @@
abstract class PhabricatorCalendarController extends PhabricatorController {
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$actions = id(new PhabricatorActionListView())
->setUser($this->getViewer())
->addAction(
id(new PhabricatorActionView())
->setName(pht('Create Event'))
->setHref('/calendar/event/create/'))
->addAction(
id(new PhabricatorActionView())
->setName(pht('Create Public Event'))
->setHref('/calendar/event/create/?mode=public'))
->addAction(
id(new PhabricatorActionView())
->setName(pht('Create Recurring Event'))
->setHref('/calendar/event/create/?mode=recurring'));
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Create Event'))
->setHref($this->getApplicationURI().'event/create/')
->setIcon('fa-plus-square')
->setDropdownMenu($actions));
return $crumbs;
}
}

View file

@ -3,576 +3,10 @@
final class PhabricatorCalendarEventEditController
extends PhabricatorCalendarController {
private $id;
public function isCreate() {
return !$this->id;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$user_phid = $viewer->getPHID();
$this->id = $request->getURIData('id');
$error_name = true;
$error_recurrence_end_date = null;
$error_start_date = true;
$error_end_date = true;
$validation_exception = null;
$is_recurring_id = celerity_generate_unique_node_id();
$recurrence_end_date_id = celerity_generate_unique_node_id();
$frequency_id = celerity_generate_unique_node_id();
$all_day_id = celerity_generate_unique_node_id();
$start_date_id = celerity_generate_unique_node_id();
$end_date_id = celerity_generate_unique_node_id();
$next_workflow = $request->getStr('next');
$uri_query = $request->getStr('query');
if ($this->isCreate()) {
$mode = $request->getStr('mode');
$event = PhabricatorCalendarEvent::initializeNewCalendarEvent(
$viewer,
$mode);
$create_start_year = $request->getInt('year');
$create_start_month = $request->getInt('month');
$create_start_day = $request->getInt('day');
$create_start_time = $request->getStr('time');
if ($create_start_year) {
$start = AphrontFormDateControlValue::newFromParts(
$viewer,
$create_start_year,
$create_start_month,
$create_start_day,
$create_start_time);
if (!$start->isValid()) {
return new Aphront400Response();
}
$start_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$start->getEpoch());
$end = clone $start_value->getDateTime();
$end->modify('+1 hour');
$end_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$end->format('U'));
} else {
list($start_value, $end_value) = $this->getDefaultTimeValues($viewer);
}
$recurrence_end_date_value = clone $end_value;
$recurrence_end_date_value->setOptional(true);
$submit_label = pht('Create');
$title = pht('Create Event');
$header_icon = 'fa-plus-square';
$redirect = 'created';
$subscribers = array();
$invitees = array($user_phid);
$cancel_uri = $this->getApplicationURI();
} else {
$event = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer)
->withIDs(array($this->id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$event) {
return new Aphront404Response();
}
$end_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$event->getViewerDateTo());
$start_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$event->getViewerDateFrom());
$recurrence_end_date_value = id(clone $end_value)
->setOptional(true);
$submit_label = pht('Update');
$title = pht('Edit Event: %s', $event->getName());
$header_icon = 'fa-pencil';
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$event->getPHID());
$invitees = $event->getInviteePHIDsForEdit();
$cancel_uri = $event->getURI();
}
if ($this->isCreate()) {
$projects = array();
} else {
$projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
$event->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
$projects = array_reverse($projects);
}
$name = $event->getName();
$description = $event->getDescription();
$is_all_day = $event->getIsAllDay();
$is_recurring = $event->getIsRecurring();
$is_parent = $event->isParentEvent();
$frequency = idx($event->getRecurrenceFrequency(), 'rule');
$icon = $event->getIcon();
$edit_policy = $event->getEditPolicy();
$view_policy = $event->getViewPolicy();
$space = $event->getSpacePHID();
if ($request->isFormPost()) {
$is_all_day = $request->getStr('isAllDay');
if ($is_all_day) {
// TODO: This is a very gross temporary hack to get this working
// reasonably: if this is an all day event, force the viewer's
// timezone to UTC so the date controls get interpreted as UTC.
$viewer->overrideTimezoneIdentifier('UTC');
}
$xactions = array();
$name = $request->getStr('name');
$start_value = AphrontFormDateControlValue::newFromRequest(
$request,
'start');
$end_value = AphrontFormDateControlValue::newFromRequest(
$request,
'end');
$recurrence_end_date_value = AphrontFormDateControlValue::newFromRequest(
$request,
'recurrenceEndDate');
$recurrence_end_date_value->setOptional(true);
$projects = $request->getArr('projects');
$description = $request->getStr('description');
$subscribers = $request->getArr('subscribers');
$edit_policy = $request->getStr('editPolicy');
$view_policy = $request->getStr('viewPolicy');
$space = $request->getStr('spacePHID');
$is_recurring = $request->getStr('isRecurring') ? 1 : 0;
$frequency = $request->getStr('frequency');
$icon = $request->getStr('icon');
$invitees = $request->getArr('invitees');
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_NAME)
->setNewValue($name);
if ($is_recurring && $this->isCreate()) {
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_RECURRING)
->setNewValue($is_recurring);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_FREQUENCY)
->setNewValue(array('rule' => $frequency));
if (!$recurrence_end_date_value->isDisabled()) {
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE)
->setNewValue($recurrence_end_date_value);
}
}
if (($is_recurring && $this->isCreate()) || !$is_parent) {
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_ALL_DAY)
->setNewValue($is_all_day);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_ICON)
->setNewValue($icon);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_START_DATE)
->setNewValue($start_value);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_END_DATE)
->setNewValue($end_value);
}
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorTransactions::TYPE_SUBSCRIBERS)
->setNewValue(array('=' => array_fuse($subscribers)));
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_INVITE)
->setNewValue($invitees);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION)
->setNewValue($description);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
->setNewValue($request->getStr('viewPolicy'));
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
->setNewValue($request->getStr('editPolicy'));
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
->setNewValue($space);
$editor = id(new PhabricatorCalendarEventEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true);
try {
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $proj_edge_type)
->setNewValue(array('=' => array_fuse($projects)));
$xactions = $editor->applyTransactions($event, $xactions);
$response = id(new AphrontRedirectResponse());
switch ($next_workflow) {
case 'day':
if (!$uri_query) {
$uri_query = 'month';
}
$year = $start_value->getDateTime()->format('Y');
$month = $start_value->getDateTime()->format('m');
$day = $start_value->getDateTime()->format('d');
$response->setURI(
'/calendar/query/'.$uri_query.'/'.$year.'/'.$month.'/'.$day.'/');
break;
default:
$response->setURI('/E'.$event->getID());
break;
}
return $response;
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$error_name = $ex->getShortMessage(
PhabricatorCalendarEventTransaction::TYPE_NAME);
$error_start_date = $ex->getShortMessage(
PhabricatorCalendarEventTransaction::TYPE_START_DATE);
$error_end_date = $ex->getShortMessage(
PhabricatorCalendarEventTransaction::TYPE_END_DATE);
$error_recurrence_end_date = $ex->getShortMessage(
PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE);
}
}
$is_recurring_checkbox = null;
$recurrence_end_date_control = null;
$recurrence_frequency_select = null;
$all_day_checkbox = null;
$start_control = null;
$end_control = null;
$recurring_date_edit_label = null;
$current_policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($event)
->execute();
$name = id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setValue($name)
->setError($error_name);
if ($this->isCreate()) {
Javelin::initBehavior('recurring-edit', array(
'isRecurring' => $is_recurring_id,
'frequency' => $frequency_id,
'recurrenceEndDate' => $recurrence_end_date_id,
));
$is_recurring_checkbox = id(new AphrontFormCheckboxControl())
->addCheckbox(
'isRecurring',
1,
pht('Recurring Event'),
$is_recurring,
$is_recurring_id);
$recurrence_end_date_control = id(new AphrontFormDateControl())
->setUser($viewer)
->setName('recurrenceEndDate')
->setLabel(pht('Recurrence End Date'))
->setError($error_recurrence_end_date)
->setValue($recurrence_end_date_value)
->setID($recurrence_end_date_id)
->setIsTimeDisabled(true)
->setIsDisabled($recurrence_end_date_value->isDisabled())
->setAllowNull(true);
$recurrence_frequency_select = id(new AphrontFormSelectControl())
->setName('frequency')
->setOptions(array(
PhabricatorCalendarEvent::FREQUENCY_DAILY => pht('Daily'),
PhabricatorCalendarEvent::FREQUENCY_WEEKLY => pht('Weekly'),
PhabricatorCalendarEvent::FREQUENCY_MONTHLY => pht('Monthly'),
PhabricatorCalendarEvent::FREQUENCY_YEARLY => pht('Yearly'),
))
->setValue($frequency)
->setLabel(pht('Recurring Event Frequency'))
->setID($frequency_id)
->setDisabled(!$is_recurring);
}
if ($this->isCreate() || (!$is_parent && !$this->isCreate())) {
Javelin::initBehavior('event-all-day', array(
'allDayID' => $all_day_id,
'startDateID' => $start_date_id,
'endDateID' => $end_date_id,
));
$all_day_checkbox = id(new AphrontFormCheckboxControl())
->addCheckbox(
'isAllDay',
1,
pht('All Day Event'),
$is_all_day,
$all_day_id);
$start_control = id(new AphrontFormDateControl())
->setUser($viewer)
->setName('start')
->setLabel(pht('Start'))
->setError($error_start_date)
->setValue($start_value)
->setID($start_date_id)
->setIsTimeDisabled($is_all_day)
->setEndDateID($end_date_id);
$end_control = id(new AphrontFormDateControl())
->setUser($viewer)
->setName('end')
->setLabel(pht('End'))
->setError($error_end_date)
->setValue($end_value)
->setID($end_date_id)
->setIsTimeDisabled($is_all_day);
} else if ($is_parent) {
$recurring_date_edit_label = id(new AphrontFormStaticControl())
->setUser($viewer)
->setValue(pht('Date and time of recurring event cannot be edited.'));
if (!$recurrence_end_date_value->isDisabled()) {
$disabled_recurrence_end_date_value =
$recurrence_end_date_value->getValueAsFormat('M d, Y');
$recurrence_end_date_control = id(new AphrontFormStaticControl())
->setUser($viewer)
->setLabel(pht('Recurrence End Date'))
->setValue($disabled_recurrence_end_date_value)
->setDisabled(true);
}
$recurrence_frequency_select = id(new AphrontFormSelectControl())
->setName('frequency')
->setOptions(array(
'daily' => pht('Daily'),
'weekly' => pht('Weekly'),
'monthly' => pht('Monthly'),
'yearly' => pht('Yearly'),
))
->setValue($frequency)
->setLabel(pht('Recurring Event Frequency'))
->setID($frequency_id)
->setDisabled(true);
$all_day_checkbox = id(new AphrontFormCheckboxControl())
->addCheckbox(
'isAllDay',
1,
pht('All Day Event'),
$is_all_day,
$all_day_id)
->setDisabled(true);
$start_disabled = $start_value->getValueAsFormat('M d, Y, g:i A');
$end_disabled = $end_value->getValueAsFormat('M d, Y, g:i A');
$start_control = id(new AphrontFormStaticControl())
->setUser($viewer)
->setLabel(pht('Start'))
->setValue($start_disabled)
->setDisabled(true);
$end_control = id(new AphrontFormStaticControl())
->setUser($viewer)
->setLabel(pht('End'))
->setValue($end_disabled);
}
$projects = id(new AphrontFormTokenizerControl())
->setLabel(pht('Tags'))
->setName('projects')
->setValue($projects)
->setUser($viewer)
->setDatasource(new PhabricatorProjectDatasource());
$description = id(new PhabricatorRemarkupControl())
->setLabel(pht('Description'))
->setName('description')
->setValue($description)
->setUser($viewer);
$view_policies = id(new AphrontFormPolicyControl())
->setUser($viewer)
->setValue($view_policy)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($event)
->setPolicies($current_policies)
->setSpacePHID($space)
->setName('viewPolicy');
$edit_policies = id(new AphrontFormPolicyControl())
->setUser($viewer)
->setValue($edit_policy)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($event)
->setPolicies($current_policies)
->setName('editPolicy');
$subscribers = id(new AphrontFormTokenizerControl())
->setLabel(pht('Subscribers'))
->setName('subscribers')
->setValue($subscribers)
->setUser($viewer)
->setDatasource(new PhabricatorMetaMTAMailableDatasource());
$invitees = id(new AphrontFormTokenizerControl())
->setLabel(pht('Invitees'))
->setName('invitees')
->setValue($invitees)
->setUser($viewer)
->setDatasource(new PhabricatorMetaMTAMailableDatasource());
$icon = id(new PHUIFormIconSetControl())
->setLabel(pht('Icon'))
->setName('icon')
->setIconSet(new PhabricatorCalendarIconSet())
->setValue($icon);
$form = id(new AphrontFormView())
->addHiddenInput('next', $next_workflow)
->addHiddenInput('query', $uri_query)
->setUser($viewer)
->appendChild($name);
if ($recurring_date_edit_label) {
$form->appendControl($recurring_date_edit_label);
}
if ($is_recurring_checkbox) {
$form->appendChild($is_recurring_checkbox);
}
if ($recurrence_end_date_control) {
$form->appendChild($recurrence_end_date_control);
}
if ($recurrence_frequency_select) {
$form->appendControl($recurrence_frequency_select);
}
$form
->appendChild($all_day_checkbox)
->appendChild($start_control)
->appendChild($end_control)
->appendControl($view_policies)
->appendControl($edit_policies)
->appendControl($subscribers)
->appendControl($invitees)
->appendChild($projects)
->appendChild($description)
->appendChild($icon);
if ($request->isAjax()) {
return $this->newDialog()
->setTitle($title)
->setWidth(AphrontDialogView::WIDTH_FULL)
->appendForm($form)
->addCancelButton($cancel_uri)
->addSubmitButton($submit_label);
}
$submit = id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue($submit_label);
$form->appendChild($submit);
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Event'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setValidationException($validation_exception)
->setForm($form);
$crumbs = $this->buildApplicationCrumbs();
if (!$this->isCreate()) {
$crumbs->addTextCrumb('E'.$event->getId(), '/E'.$event->getId());
$crumb_title = pht('Edit Event');
} else {
$crumb_title = pht('Create Event');
}
$crumbs->addTextCrumb($crumb_title);
$crumbs->setBorder(true);
$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($view);
}
private function getDefaultTimeValues($viewer) {
$start = new DateTime('@'.time());
$start->setTimeZone($viewer->getTimeZone());
$start->setTime($start->format('H'), 0, 0);
$start->modify('+1 hour');
$end = id(clone $start)->modify('+1 hour');
$start_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$start->format('U'));
$end_value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
$end->format('U'));
return array($start_value, $end_value);
return id(new PhabricatorCalendarEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -1,12 +0,0 @@
<?php
final class PhabricatorCalendarEventEditProController
extends PhabricatorCalendarController {
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorCalendarEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -19,24 +19,19 @@ final class PhabricatorCalendarEventListController
$controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($request->getURIData('queryKey'))
->setSearchEngine($engine)
->setNavigation($this->buildSideNav());
->setSearchEngine($engine);
return $this->delegateToController($controller);
}
public function buildSideNav() {
$user = $this->getRequest()->getUser();
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
id(new PhabricatorCalendarEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
id(new PhabricatorCalendarEventSearchEngine())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
return $nav;
return $crumbs;
}
}

View file

@ -56,7 +56,7 @@ final class PhabricatorCalendarEditEngine
}
protected function getEditorURI() {
return $this->getApplication()->getApplicationURI('event/editpro/');
return $this->getApplication()->getApplicationURI('event/edit/');
}
protected function buildCustomEditFields($object) {

View file

@ -410,6 +410,11 @@ final class PhabricatorPeopleQuery
}
}
// We need to load these users' timezone settings to figure out their
// availability if they're attending all-day events.
$this->needUserSettings(true);
$this->fillUserCaches($rebuild);
foreach ($rebuild as $phid => $user) {
$events = idx($map, $phid, array());