mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-30 18:52:42 +01:00
(stable) Promote 2016 Week 44
This commit is contained in:
commit
bd256e9f3f
37 changed files with 1022 additions and 61 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_phortune.phortune_merchant
|
||||||
|
ADD contactInfo LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL;
|
|
@ -0,0 +1,8 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_calendar.calendar_import
|
||||||
|
ADD triggerPHID VARBINARY(64);
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_calendar.calendar_import
|
||||||
|
ADD triggerFrequency VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT};
|
||||||
|
|
||||||
|
UPDATE {$NAMESPACE}_calendar.calendar_import
|
||||||
|
SET triggerFrequency = 'once' WHERE triggerFrequency = '';
|
|
@ -0,0 +1,12 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_calendar.calendar_externalinvitee (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
name LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
nameIndex BINARY(12) NOT NULL,
|
||||||
|
uri LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
parameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
sourcePHID VARBINARY(64) NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_name` (`nameIndex`)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -2098,6 +2098,9 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarExportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarExportTransactionQuery.php',
|
'PhabricatorCalendarExportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarExportTransactionQuery.php',
|
||||||
'PhabricatorCalendarExportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarExportTransactionType.php',
|
'PhabricatorCalendarExportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarExportTransactionType.php',
|
||||||
'PhabricatorCalendarExportViewController' => 'applications/calendar/controller/PhabricatorCalendarExportViewController.php',
|
'PhabricatorCalendarExportViewController' => 'applications/calendar/controller/PhabricatorCalendarExportViewController.php',
|
||||||
|
'PhabricatorCalendarExternalInvitee' => 'applications/calendar/storage/PhabricatorCalendarExternalInvitee.php',
|
||||||
|
'PhabricatorCalendarExternalInviteePHIDType' => 'applications/calendar/phid/PhabricatorCalendarExternalInviteePHIDType.php',
|
||||||
|
'PhabricatorCalendarExternalInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarExternalInviteeQuery.php',
|
||||||
'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php',
|
'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php',
|
||||||
'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php',
|
'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php',
|
||||||
'PhabricatorCalendarICSFileImportEngine' => 'applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php',
|
'PhabricatorCalendarICSFileImportEngine' => 'applications/calendar/import/PhabricatorCalendarICSFileImportEngine.php',
|
||||||
|
@ -2121,6 +2124,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarImportEpochLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportEpochLogType.php',
|
'PhabricatorCalendarImportEpochLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportEpochLogType.php',
|
||||||
'PhabricatorCalendarImportFetchLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFetchLogType.php',
|
'PhabricatorCalendarImportFetchLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFetchLogType.php',
|
||||||
'PhabricatorCalendarImportFrequencyLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php',
|
'PhabricatorCalendarImportFrequencyLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportFrequencyLogType.php',
|
||||||
|
'PhabricatorCalendarImportFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportFrequencyTransaction.php',
|
||||||
'PhabricatorCalendarImportICSFileTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php',
|
'PhabricatorCalendarImportICSFileTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php',
|
||||||
'PhabricatorCalendarImportICSLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php',
|
'PhabricatorCalendarImportICSLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportICSLogType.php',
|
||||||
'PhabricatorCalendarImportICSURITransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php',
|
'PhabricatorCalendarImportICSURITransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSURITransaction.php',
|
||||||
|
@ -2137,10 +2141,14 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarImportOrphanLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportOrphanLogType.php',
|
'PhabricatorCalendarImportOrphanLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportOrphanLogType.php',
|
||||||
'PhabricatorCalendarImportPHIDType' => 'applications/calendar/phid/PhabricatorCalendarImportPHIDType.php',
|
'PhabricatorCalendarImportPHIDType' => 'applications/calendar/phid/PhabricatorCalendarImportPHIDType.php',
|
||||||
'PhabricatorCalendarImportQuery' => 'applications/calendar/query/PhabricatorCalendarImportQuery.php',
|
'PhabricatorCalendarImportQuery' => 'applications/calendar/query/PhabricatorCalendarImportQuery.php',
|
||||||
|
'PhabricatorCalendarImportReloadController' => 'applications/calendar/controller/PhabricatorCalendarImportReloadController.php',
|
||||||
|
'PhabricatorCalendarImportReloadTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportReloadTransaction.php',
|
||||||
|
'PhabricatorCalendarImportReloadWorker' => 'applications/calendar/worker/PhabricatorCalendarImportReloadWorker.php',
|
||||||
'PhabricatorCalendarImportSearchEngine' => 'applications/calendar/query/PhabricatorCalendarImportSearchEngine.php',
|
'PhabricatorCalendarImportSearchEngine' => 'applications/calendar/query/PhabricatorCalendarImportSearchEngine.php',
|
||||||
'PhabricatorCalendarImportTransaction' => 'applications/calendar/storage/PhabricatorCalendarImportTransaction.php',
|
'PhabricatorCalendarImportTransaction' => 'applications/calendar/storage/PhabricatorCalendarImportTransaction.php',
|
||||||
'PhabricatorCalendarImportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php',
|
'PhabricatorCalendarImportTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarImportTransactionQuery.php',
|
||||||
'PhabricatorCalendarImportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php',
|
'PhabricatorCalendarImportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarImportTransactionType.php',
|
||||||
|
'PhabricatorCalendarImportTriggerLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportTriggerLogType.php',
|
||||||
'PhabricatorCalendarImportUpdateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php',
|
'PhabricatorCalendarImportUpdateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportUpdateLogType.php',
|
||||||
'PhabricatorCalendarImportViewController' => 'applications/calendar/controller/PhabricatorCalendarImportViewController.php',
|
'PhabricatorCalendarImportViewController' => 'applications/calendar/controller/PhabricatorCalendarImportViewController.php',
|
||||||
'PhabricatorCalendarRemarkupRule' => 'applications/calendar/remarkup/PhabricatorCalendarRemarkupRule.php',
|
'PhabricatorCalendarRemarkupRule' => 'applications/calendar/remarkup/PhabricatorCalendarRemarkupRule.php',
|
||||||
|
@ -6934,6 +6942,12 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarExportTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorCalendarExportTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorCalendarExportTransactionType' => 'PhabricatorModularTransactionType',
|
'PhabricatorCalendarExportTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
'PhabricatorCalendarExportViewController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarExportViewController' => 'PhabricatorCalendarController',
|
||||||
|
'PhabricatorCalendarExternalInvitee' => array(
|
||||||
|
'PhabricatorCalendarDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
),
|
||||||
|
'PhabricatorCalendarExternalInviteePHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'PhabricatorCalendarExternalInviteeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
|
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
|
||||||
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
|
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorCalendarICSFileImportEngine' => 'PhabricatorCalendarICSImportEngine',
|
'PhabricatorCalendarICSFileImportEngine' => 'PhabricatorCalendarICSImportEngine',
|
||||||
|
@ -6962,6 +6976,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarImportEpochLogType' => 'PhabricatorCalendarImportLogType',
|
'PhabricatorCalendarImportEpochLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
'PhabricatorCalendarImportFetchLogType' => 'PhabricatorCalendarImportLogType',
|
'PhabricatorCalendarImportFetchLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
'PhabricatorCalendarImportFrequencyLogType' => 'PhabricatorCalendarImportLogType',
|
'PhabricatorCalendarImportFrequencyLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
|
'PhabricatorCalendarImportFrequencyTransaction' => 'PhabricatorCalendarImportTransactionType',
|
||||||
'PhabricatorCalendarImportICSFileTransaction' => 'PhabricatorCalendarImportTransactionType',
|
'PhabricatorCalendarImportICSFileTransaction' => 'PhabricatorCalendarImportTransactionType',
|
||||||
'PhabricatorCalendarImportICSLogType' => 'PhabricatorCalendarImportLogType',
|
'PhabricatorCalendarImportICSLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
'PhabricatorCalendarImportICSURITransaction' => 'PhabricatorCalendarImportTransactionType',
|
'PhabricatorCalendarImportICSURITransaction' => 'PhabricatorCalendarImportTransactionType',
|
||||||
|
@ -6982,10 +6997,14 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarImportOrphanLogType' => 'PhabricatorCalendarImportLogType',
|
'PhabricatorCalendarImportOrphanLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
'PhabricatorCalendarImportPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorCalendarImportPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorCalendarImportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorCalendarImportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorCalendarImportReloadController' => 'PhabricatorCalendarController',
|
||||||
|
'PhabricatorCalendarImportReloadTransaction' => 'PhabricatorCalendarImportTransactionType',
|
||||||
|
'PhabricatorCalendarImportReloadWorker' => 'PhabricatorWorker',
|
||||||
'PhabricatorCalendarImportSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorCalendarImportSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorCalendarImportTransaction' => 'PhabricatorModularTransaction',
|
'PhabricatorCalendarImportTransaction' => 'PhabricatorModularTransaction',
|
||||||
'PhabricatorCalendarImportTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorCalendarImportTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorCalendarImportTransactionType' => 'PhabricatorModularTransactionType',
|
'PhabricatorCalendarImportTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
|
'PhabricatorCalendarImportTriggerLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
'PhabricatorCalendarImportUpdateLogType' => 'PhabricatorCalendarImportLogType',
|
'PhabricatorCalendarImportUpdateLogType' => 'PhabricatorCalendarImportLogType',
|
||||||
'PhabricatorCalendarImportViewController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarImportViewController' => 'PhabricatorCalendarController',
|
||||||
'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||||
|
|
|
@ -85,6 +85,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
||||||
=> 'PhabricatorCalendarImportDisableController',
|
=> 'PhabricatorCalendarImportDisableController',
|
||||||
'delete/(?P<id>[1-9]\d*)/'
|
'delete/(?P<id>[1-9]\d*)/'
|
||||||
=> 'PhabricatorCalendarImportDeleteController',
|
=> 'PhabricatorCalendarImportDeleteController',
|
||||||
|
'reload/(?P<id>[1-9]\d*)/'
|
||||||
|
=> 'PhabricatorCalendarImportReloadController',
|
||||||
'drop/'
|
'drop/'
|
||||||
=> 'PhabricatorCalendarImportDropController',
|
=> 'PhabricatorCalendarImportDropController',
|
||||||
'log/' => array(
|
'log/' => array(
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
final class PhabricatorCalendarEventListController
|
final class PhabricatorCalendarEventListController
|
||||||
extends PhabricatorCalendarController {
|
extends PhabricatorCalendarController {
|
||||||
|
|
||||||
|
private $viewYear;
|
||||||
|
private $viewMonth;
|
||||||
|
private $viewDay;
|
||||||
|
|
||||||
public function shouldAllowPublic() {
|
public function shouldAllowPublic() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +20,10 @@ final class PhabricatorCalendarEventListController
|
||||||
$month = $request->getURIData('month');
|
$month = $request->getURIData('month');
|
||||||
$day = $request->getURIData('day');
|
$day = $request->getURIData('day');
|
||||||
|
|
||||||
|
$this->viewYear = $year;
|
||||||
|
$this->viewMonth = $month;
|
||||||
|
$this->viewDay = $day;
|
||||||
|
|
||||||
$engine = new PhabricatorCalendarEventSearchEngine();
|
$engine = new PhabricatorCalendarEventSearchEngine();
|
||||||
|
|
||||||
if ($month && $year) {
|
if ($month && $year) {
|
||||||
|
@ -33,9 +41,36 @@ final class PhabricatorCalendarEventListController
|
||||||
protected function buildApplicationCrumbs() {
|
protected function buildApplicationCrumbs() {
|
||||||
$crumbs = parent::buildApplicationCrumbs();
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$year = $this->viewYear;
|
||||||
|
$month = $this->viewMonth;
|
||||||
|
$day = $this->viewDay;
|
||||||
|
|
||||||
|
$parameters = array();
|
||||||
|
|
||||||
|
// If the viewer clicks "Create Event" while on a particular day view,
|
||||||
|
// default the times to that day.
|
||||||
|
if ($year && $month && $day) {
|
||||||
|
$datetimes = PhabricatorCalendarEvent::newDefaultEventDateTimes(
|
||||||
|
$viewer,
|
||||||
|
PhabricatorTime::getNow());
|
||||||
|
|
||||||
|
foreach ($datetimes as $datetime) {
|
||||||
|
$datetime
|
||||||
|
->setYear($year)
|
||||||
|
->setMonth($month)
|
||||||
|
->setDay($day);
|
||||||
|
}
|
||||||
|
|
||||||
|
list($start, $end) = $datetimes;
|
||||||
|
$parameters['start'] = $start->getEpoch();
|
||||||
|
$parameters['end'] = $end->getEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
id(new PhabricatorCalendarEventEditEngine())
|
id(new PhabricatorCalendarEventEditEngine())
|
||||||
->setViewer($this->getViewer())
|
->setViewer($this->getViewer())
|
||||||
->addActionToCrumbs($crumbs);
|
->addActionToCrumbs($crumbs, $parameters);
|
||||||
|
|
||||||
return $crumbs;
|
return $crumbs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ final class PhabricatorCalendarImportDropController
|
||||||
->addCancelButton($cancel_uri, pht('Done'));
|
->addCancelButton($cancel_uri, pht('Done'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$engine = new PhabricatorCalendarICSImportEngine();
|
$engine = new PhabricatorCalendarICSFileImportEngine();
|
||||||
$imports = array();
|
$imports = array();
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$import = PhabricatorCalendarImport::initializeNewCalendarImport(
|
$import = PhabricatorCalendarImport::initializeNewCalendarImport(
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarImportReloadController
|
||||||
|
extends PhabricatorCalendarController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$import = id(new PhabricatorCalendarImportQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$import) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$import_uri = $import->getURI();
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
$xactions[] = id(new PhabricatorCalendarImportTransaction())
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorCalendarImportReloadTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue(true);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorCalendarImportEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContentSourceFromRequest($request);
|
||||||
|
|
||||||
|
$editor->applyTransactions($import, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($import_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Reload Events'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Reload this source? Events imported from this source will '.
|
||||||
|
'be updated.'))
|
||||||
|
->addCancelButton($import_uri)
|
||||||
|
->addSubmitButton(pht('Reload Events'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -105,6 +105,17 @@ final class PhabricatorCalendarImportViewController
|
||||||
->setWorkflow(!$can_edit)
|
->setWorkflow(!$can_edit)
|
||||||
->setHref($edit_uri));
|
->setHref($edit_uri));
|
||||||
|
|
||||||
|
$reload_uri = "import/reload/{$id}/";
|
||||||
|
$reload_uri = $this->getApplicationURI($reload_uri);
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Reload Import'))
|
||||||
|
->setIcon('fa-refresh')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($reload_uri));
|
||||||
|
|
||||||
$disable_uri = "import/disable/{$id}/";
|
$disable_uri = "import/disable/{$id}/";
|
||||||
$disable_uri = $this->getApplicationURI($disable_uri);
|
$disable_uri = $this->getApplicationURI($disable_uri);
|
||||||
if ($import->getIsDisabled()) {
|
if ($import->getIsDisabled()) {
|
||||||
|
@ -123,7 +134,6 @@ final class PhabricatorCalendarImportViewController
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref($disable_uri));
|
->setHref($disable_uri));
|
||||||
|
|
||||||
|
|
||||||
if ($can_edit) {
|
if ($can_edit) {
|
||||||
$can_delete = $engine->canDeleteAnyEvents($viewer, $import);
|
$can_delete = $engine->canDeleteAnyEvents($viewer, $import);
|
||||||
} else {
|
} else {
|
||||||
|
@ -157,6 +167,50 @@ final class PhabricatorCalendarImportViewController
|
||||||
pht('Source Type'),
|
pht('Source Type'),
|
||||||
$engine->getImportEngineTypeName());
|
$engine->getImportEngineTypeName());
|
||||||
|
|
||||||
|
if ($import->getIsDisabled()) {
|
||||||
|
$auto_updates = phutil_tag('em', array(), pht('Import Disabled'));
|
||||||
|
$has_trigger = false;
|
||||||
|
} else {
|
||||||
|
$frequency = $import->getTriggerFrequency();
|
||||||
|
$frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap();
|
||||||
|
$frequency_names = ipull($frequency_map, 'name');
|
||||||
|
$auto_updates = idx($frequency_names, $frequency, $frequency);
|
||||||
|
|
||||||
|
if ($frequency == PhabricatorCalendarImport::FREQUENCY_ONCE) {
|
||||||
|
$has_trigger = false;
|
||||||
|
$auto_updates = phutil_tag('em', array(), $auto_updates);
|
||||||
|
} else {
|
||||||
|
$has_trigger = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Automatic Updates'),
|
||||||
|
$auto_updates);
|
||||||
|
|
||||||
|
if ($has_trigger) {
|
||||||
|
$trigger = id(new PhabricatorWorkerTriggerQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($import->getTriggerPHID()))
|
||||||
|
->needEvents(true)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if (!$trigger) {
|
||||||
|
$next_trigger = phutil_tag('em', array(), pht('Invalid Trigger'));
|
||||||
|
} else {
|
||||||
|
$now = PhabricatorTime::getNow();
|
||||||
|
$next_epoch = $trigger->getNextEventPrediction();
|
||||||
|
$next_trigger = pht(
|
||||||
|
'%s (%s)',
|
||||||
|
phabricator_datetime($next_epoch, $viewer),
|
||||||
|
phutil_format_relative_time($next_epoch - $now));
|
||||||
|
}
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Next Update'),
|
||||||
|
$next_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
$engine->appendImportProperties(
|
$engine->appendImportProperties(
|
||||||
$viewer,
|
$viewer,
|
||||||
$import,
|
$import,
|
||||||
|
|
|
@ -164,6 +164,8 @@ final class PhabricatorCalendarEventEditEngine
|
||||||
|
|
||||||
if ($this->getIsCreate() || $object->getIsRecurring()) {
|
if ($this->getIsCreate() || $object->getIsRecurring()) {
|
||||||
$fields[] = id(new PhabricatorEpochEditField())
|
$fields[] = id(new PhabricatorEpochEditField())
|
||||||
|
->setIsLockable(false)
|
||||||
|
->setIsDefaultable(false)
|
||||||
->setAllowNull(true)
|
->setAllowNull(true)
|
||||||
->setKey('until')
|
->setKey('until')
|
||||||
->setLabel(pht('Repeat Until'))
|
->setLabel(pht('Repeat Until'))
|
||||||
|
@ -189,6 +191,8 @@ final class PhabricatorCalendarEventEditEngine
|
||||||
$fields[] = id(new PhabricatorEpochEditField())
|
$fields[] = id(new PhabricatorEpochEditField())
|
||||||
->setKey('start')
|
->setKey('start')
|
||||||
->setLabel(pht('Start'))
|
->setLabel(pht('Start'))
|
||||||
|
->setIsLockable(false)
|
||||||
|
->setIsDefaultable(false)
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE)
|
PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE)
|
||||||
->setDescription(pht('Start time of the event.'))
|
->setDescription(pht('Start time of the event.'))
|
||||||
|
@ -199,6 +203,8 @@ final class PhabricatorCalendarEventEditEngine
|
||||||
$fields[] = id(new PhabricatorEpochEditField())
|
$fields[] = id(new PhabricatorEpochEditField())
|
||||||
->setKey('end')
|
->setKey('end')
|
||||||
->setLabel(pht('End'))
|
->setLabel(pht('End'))
|
||||||
|
->setIsLockable(false)
|
||||||
|
->setIsDefaultable(false)
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE)
|
PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE)
|
||||||
->setDescription(pht('End time of the event.'))
|
->setDescription(pht('End time of the event.'))
|
||||||
|
|
|
@ -34,25 +34,22 @@ final class PhabricatorCalendarEventEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
$actor = $this->getActor();
|
$actor = $this->getActor();
|
||||||
|
|
||||||
|
$invitees = $event->getInvitees();
|
||||||
|
|
||||||
$event->copyFromParent($actor);
|
$event->copyFromParent($actor);
|
||||||
$event->setIsStub(0);
|
$event->setIsStub(0);
|
||||||
|
|
||||||
$invitees = $event->getParentEvent()->getInvitees();
|
$event->openTransaction();
|
||||||
|
$event->save();
|
||||||
|
foreach ($invitees as $invitee) {
|
||||||
|
$invitee
|
||||||
|
->setEventPHID($event->getPHID())
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
$event->saveTransaction();
|
||||||
|
|
||||||
$new_invitees = array();
|
$event->attachInvitees($invitees);
|
||||||
foreach ($invitees as $invitee) {
|
|
||||||
$invitee = id(new PhabricatorCalendarEventInvitee())
|
|
||||||
->setEventPHID($event->getPHID())
|
|
||||||
->setInviteePHID($invitee->getInviteePHID())
|
|
||||||
->setInviterPHID($invitee->getInviterPHID())
|
|
||||||
->setStatus($invitee->getStatus())
|
|
||||||
->save();
|
|
||||||
|
|
||||||
$new_invitees[] = $invitee;
|
|
||||||
}
|
|
||||||
|
|
||||||
$event->save();
|
|
||||||
$event->attachInvitees($new_invitees);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTransactionTypes() {
|
public function getTransactionTypes() {
|
||||||
|
|
|
@ -80,6 +80,9 @@ final class PhabricatorCalendarImportEditEngine
|
||||||
protected function buildCustomEditFields($object) {
|
protected function buildCustomEditFields($object) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$engine = $object->getEngine();
|
||||||
|
$can_trigger = $engine->supportsTriggers($object);
|
||||||
|
|
||||||
$fields = array(
|
$fields = array(
|
||||||
id(new PhabricatorTextEditField())
|
id(new PhabricatorTextEditField())
|
||||||
->setKey('name')
|
->setKey('name')
|
||||||
|
@ -89,6 +92,7 @@ final class PhabricatorCalendarImportEditEngine
|
||||||
PhabricatorCalendarImportNameTransaction::TRANSACTIONTYPE)
|
PhabricatorCalendarImportNameTransaction::TRANSACTIONTYPE)
|
||||||
->setConduitDescription(pht('Rename the import.'))
|
->setConduitDescription(pht('Rename the import.'))
|
||||||
->setConduitTypeDescription(pht('New import name.'))
|
->setConduitTypeDescription(pht('New import name.'))
|
||||||
|
->setPlaceholder($object->getDisplayName())
|
||||||
->setValue($object->getName()),
|
->setValue($object->getName()),
|
||||||
id(new PhabricatorBoolEditField())
|
id(new PhabricatorBoolEditField())
|
||||||
->setKey('disabled')
|
->setKey('disabled')
|
||||||
|
@ -101,8 +105,44 @@ final class PhabricatorCalendarImportEditEngine
|
||||||
->setConduitDescription(pht('Disable or restore the import.'))
|
->setConduitDescription(pht('Disable or restore the import.'))
|
||||||
->setConduitTypeDescription(pht('True to cancel the import.'))
|
->setConduitTypeDescription(pht('True to cancel the import.'))
|
||||||
->setValue($object->getIsDisabled()),
|
->setValue($object->getIsDisabled()),
|
||||||
|
id(new PhabricatorBoolEditField())
|
||||||
|
->setKey('delete')
|
||||||
|
->setLabel(pht('Delete Imported Events'))
|
||||||
|
->setDescription(pht('Delete all events from this source.'))
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE)
|
||||||
|
->setIsConduitOnly(true)
|
||||||
|
->setConduitDescription(pht('Disable or restore the import.'))
|
||||||
|
->setConduitTypeDescription(pht('True to delete imported events.'))
|
||||||
|
->setValue(false),
|
||||||
|
id(new PhabricatorBoolEditField())
|
||||||
|
->setKey('reload')
|
||||||
|
->setLabel(pht('Reload Import'))
|
||||||
|
->setDescription(pht('Reload events imported from this source.'))
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE)
|
||||||
|
->setIsConduitOnly(true)
|
||||||
|
->setConduitDescription(pht('Disable or restore the import.'))
|
||||||
|
->setConduitTypeDescription(pht('True to reload the import.'))
|
||||||
|
->setValue(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($can_trigger) {
|
||||||
|
$frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap();
|
||||||
|
$frequency_options = ipull($frequency_map, 'name');
|
||||||
|
|
||||||
|
$fields[] = id(new PhabricatorSelectEditField())
|
||||||
|
->setKey('frequency')
|
||||||
|
->setLabel(pht('Update Automatically'))
|
||||||
|
->setDescription(pht('Configure an automatic update frequncy.'))
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorCalendarImportFrequencyTransaction::TRANSACTIONTYPE)
|
||||||
|
->setConduitDescription(pht('Set the automatic update frequency.'))
|
||||||
|
->setConduitTypeDescription(pht('Update frequency constant.'))
|
||||||
|
->setValue($object->getTriggerFrequency())
|
||||||
|
->setOptions($frequency_options);
|
||||||
|
}
|
||||||
|
|
||||||
$import_engine = $object->getEngine();
|
$import_engine = $object->getEngine();
|
||||||
foreach ($import_engine->newEditEngineFields($this, $object) as $field) {
|
foreach ($import_engine->newEditEngineFields($this, $object) as $field) {
|
||||||
$fields[] = $field;
|
$fields[] = $field;
|
||||||
|
|
|
@ -27,12 +27,110 @@ final class PhabricatorCalendarImportEditor
|
||||||
protected function applyFinalEffects(
|
protected function applyFinalEffects(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
$actor = $this->getActor();
|
||||||
|
|
||||||
if ($this->getIsNewObject()) {
|
// We import events when you create a source, or if you later reload it
|
||||||
$actor = $this->getActor();
|
// explicitly.
|
||||||
|
$should_reload = $this->getIsNewObject();
|
||||||
|
|
||||||
|
// We adjust the import trigger if you change the import frequency or
|
||||||
|
// disable the import.
|
||||||
|
$should_trigger = false;
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$xaction_type = $xaction->getTransactionType();
|
||||||
|
switch ($xaction_type) {
|
||||||
|
case PhabricatorCalendarImportReloadTransaction::TRANSACTIONTYPE:
|
||||||
|
$should_reload = true;
|
||||||
|
break;
|
||||||
|
case PhabricatorCalendarImportFrequencyTransaction::TRANSACTIONTYPE:
|
||||||
|
$should_trigger = true;
|
||||||
|
break;
|
||||||
|
case PhabricatorCalendarImportDisableTransaction::TRANSACTIONTYPE:
|
||||||
|
$should_trigger = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($should_reload) {
|
||||||
$import_engine = $object->getEngine();
|
$import_engine = $object->getEngine();
|
||||||
$import_engine->didCreateImport($actor, $object);
|
$import_engine->importEventsFromSource($actor, $object);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($should_trigger) {
|
||||||
|
$trigger_phid = $object->getTriggerPHID();
|
||||||
|
if ($trigger_phid) {
|
||||||
|
$trigger = id(new PhabricatorWorkerTriggerQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withPHIDs(array($trigger_phid))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if ($trigger) {
|
||||||
|
$engine = new PhabricatorDestructionEngine();
|
||||||
|
$engine->destroyObject($trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$frequency = $object->getTriggerFrequency();
|
||||||
|
$now = PhabricatorTime::getNow();
|
||||||
|
switch ($frequency) {
|
||||||
|
case PhabricatorCalendarImport::FREQUENCY_ONCE:
|
||||||
|
$clock = null;
|
||||||
|
break;
|
||||||
|
case PhabricatorCalendarImport::FREQUENCY_HOURLY:
|
||||||
|
$clock = new PhabricatorMetronomicTriggerClock(
|
||||||
|
array(
|
||||||
|
'period' => phutil_units('1 hour in seconds'),
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case PhabricatorCalendarImport::FREQUENCY_DAILY:
|
||||||
|
$clock = new PhabricatorDailyRoutineTriggerClock(
|
||||||
|
array(
|
||||||
|
'start' => $now,
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unknown import trigger frequency "%s".',
|
||||||
|
$frequency));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object has been disabled, don't write a new trigger.
|
||||||
|
if ($object->getIsDisabled()) {
|
||||||
|
$clock = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($clock) {
|
||||||
|
$trigger_action = new PhabricatorScheduleTaskTriggerAction(
|
||||||
|
array(
|
||||||
|
'class' => 'PhabricatorCalendarImportReloadWorker',
|
||||||
|
'data' => array(
|
||||||
|
'importPHID' => $object->getPHID(),
|
||||||
|
),
|
||||||
|
'options' => array(
|
||||||
|
'objectPHID' => $object->getPHID(),
|
||||||
|
'priority' => PhabricatorWorker::PRIORITY_BULK,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$trigger_phid = PhabricatorPHID::generateNewPHID(
|
||||||
|
PhabricatorWorkerTriggerPHIDType::TYPECONST);
|
||||||
|
|
||||||
|
$object
|
||||||
|
->setTriggerPHID($trigger_phid)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$trigger = id(new PhabricatorWorkerTrigger())
|
||||||
|
->setClock($clock)
|
||||||
|
->setAction($trigger_action)
|
||||||
|
->setPHID($trigger_phid)
|
||||||
|
->save();
|
||||||
|
} else {
|
||||||
|
$object
|
||||||
|
->setTriggerPHID(null)
|
||||||
|
->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $xactions;
|
return $xactions;
|
||||||
|
|
|
@ -17,6 +17,10 @@ final class PhabricatorCalendarICSFileImportEngine
|
||||||
return pht('Import an event in ".ics" (iCalendar) format.');
|
return pht('Import an event in ".ics" (iCalendar) format.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supportsTriggers(PhabricatorCalendarImport $import) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function appendImportProperties(
|
public function appendImportProperties(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorCalendarImport $import,
|
PhabricatorCalendarImport $import,
|
||||||
|
@ -59,7 +63,7 @@ final class PhabricatorCalendarICSFileImportEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function didCreateImport(
|
public function importEventsFromSource(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorCalendarImport $import) {
|
PhabricatorCalendarImport $import) {
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,10 @@ final class PhabricatorCalendarICSURIImportEngine
|
||||||
return pht('Import or subscribe to a calendar in .ics format by URI.');
|
return pht('Import or subscribe to a calendar in .ics format by URI.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supportsTriggers(PhabricatorCalendarImport $import) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function appendImportProperties(
|
public function appendImportProperties(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorCalendarImport $import,
|
PhabricatorCalendarImport $import,
|
||||||
|
@ -71,7 +75,7 @@ final class PhabricatorCalendarICSURIImportEngine
|
||||||
return pht('ICS URI');
|
return pht('ICS URI');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function didCreateImport(
|
public function importEventsFromSource(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorCalendarImport $import) {
|
PhabricatorCalendarImport $import) {
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ abstract class PhabricatorCalendarImportEngine
|
||||||
|
|
||||||
abstract public function getDisplayName(PhabricatorCalendarImport $import);
|
abstract public function getDisplayName(PhabricatorCalendarImport $import);
|
||||||
|
|
||||||
abstract public function didCreateImport(
|
abstract public function importEventsFromSource(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorCalendarImport $import);
|
PhabricatorCalendarImport $import);
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ abstract class PhabricatorCalendarImportEngine
|
||||||
throw new PhutilMethodNotImplementedException();
|
throw new PhutilMethodNotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract public function supportsTriggers(
|
||||||
|
PhabricatorCalendarImport $import);
|
||||||
|
|
||||||
final public static function getAllImportEngines() {
|
final public static function getAllImportEngines() {
|
||||||
return id(new PhutilClassMapQuery())
|
return id(new PhutilClassMapQuery())
|
||||||
->setAncestorClass(__CLASS__)
|
->setAncestorClass(__CLASS__)
|
||||||
|
@ -204,6 +207,8 @@ abstract class PhabricatorCalendarImportEngine
|
||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
$update_map = array();
|
$update_map = array();
|
||||||
|
$invitee_map = array();
|
||||||
|
$attendee_map = array();
|
||||||
foreach ($node_map as $full_uid => $node) {
|
foreach ($node_map as $full_uid => $node) {
|
||||||
$event = idx($events, $full_uid);
|
$event = idx($events, $full_uid);
|
||||||
if (!$event) {
|
if (!$event) {
|
||||||
|
@ -219,6 +224,66 @@ abstract class PhabricatorCalendarImportEngine
|
||||||
$this->updateEventFromNode($viewer, $event, $node);
|
$this->updateEventFromNode($viewer, $event, $node);
|
||||||
$xactions[$full_uid] = $this->newUpdateTransactions($event, $node);
|
$xactions[$full_uid] = $this->newUpdateTransactions($event, $node);
|
||||||
$update_map[$full_uid] = $event;
|
$update_map[$full_uid] = $event;
|
||||||
|
|
||||||
|
$attendees = $node->getAttendees();
|
||||||
|
$private_index = 1;
|
||||||
|
foreach ($attendees as $attendee) {
|
||||||
|
// Generate a "name" for this attendee which is not an email address.
|
||||||
|
// We avoid disclosing email addresses to be consistent with the rest
|
||||||
|
// of the product.
|
||||||
|
$name = $attendee->getName();
|
||||||
|
if (preg_match('/@/', $name)) {
|
||||||
|
$name = new PhutilEmailAddress($name);
|
||||||
|
$name = $name->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have a name or the name still looks like it's an
|
||||||
|
// email address, give them a dummy placeholder name.
|
||||||
|
if (!strlen($name) || preg_match('/@/', $name)) {
|
||||||
|
$name = pht('Private User %d', $private_index);
|
||||||
|
$private_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attendee_map[$full_uid][$name] = $attendee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$attendee_names = array();
|
||||||
|
foreach ($attendee_map as $full_uid => $event_attendees) {
|
||||||
|
foreach ($event_attendees as $name => $attendee) {
|
||||||
|
$attendee_names[$name] = $attendee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($attendee_names) {
|
||||||
|
$external_invitees = id(new PhabricatorCalendarExternalInviteeQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames($attendee_names)
|
||||||
|
->execute();
|
||||||
|
$external_invitees = mpull($external_invitees, null, 'getName');
|
||||||
|
|
||||||
|
foreach ($attendee_names as $name => $attendee) {
|
||||||
|
if (isset($external_invitees[$name])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$external_invitee = id(new PhabricatorCalendarExternalInvitee())
|
||||||
|
->setName($name)
|
||||||
|
->setURI($attendee->getURI())
|
||||||
|
->setSourcePHID($import->getPHID());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$external_invitee->save();
|
||||||
|
} catch (AphrontDuplicateKeyQueryException $ex) {
|
||||||
|
$external_invitee =
|
||||||
|
id(new PhabricatorCalendarExternalInviteeQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames(array($name))
|
||||||
|
->executeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
$external_invitees[$name] = $external_invitee;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reorder events so we create parents first. This allows us to populate
|
// Reorder events so we create parents first. This allows us to populate
|
||||||
|
@ -285,6 +350,51 @@ abstract class PhabricatorCalendarImportEngine
|
||||||
|
|
||||||
$editor->applyTransactions($event, $event_xactions);
|
$editor->applyTransactions($event, $event_xactions);
|
||||||
|
|
||||||
|
// We're just forcing attendees to the correct values here because
|
||||||
|
// transactions intentionally don't let you RSVP for other users. This
|
||||||
|
// might need to be turned into a special type of transaction eventually.
|
||||||
|
$attendees = $attendee_map[$full_uid];
|
||||||
|
$old_map = $event->getInvitees();
|
||||||
|
$old_map = mpull($old_map, null, 'getInviteePHID');
|
||||||
|
|
||||||
|
$new_map = array();
|
||||||
|
foreach ($attendees as $name => $attendee) {
|
||||||
|
$phid = $external_invitees[$name]->getPHID();
|
||||||
|
|
||||||
|
$invitee = idx($old_map, $phid);
|
||||||
|
if (!$invitee) {
|
||||||
|
$invitee = id(new PhabricatorCalendarEventInvitee())
|
||||||
|
->setEventPHID($event->getPHID())
|
||||||
|
->setInviteePHID($phid)
|
||||||
|
->setInviterPHID($import->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($attendee->getStatus()) {
|
||||||
|
case PhutilCalendarUserNode::STATUS_ACCEPTED:
|
||||||
|
$status = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
|
||||||
|
break;
|
||||||
|
case PhutilCalendarUserNode::STATUS_DECLINED:
|
||||||
|
$status = PhabricatorCalendarEventInvitee::STATUS_DECLINED;
|
||||||
|
break;
|
||||||
|
case PhutilCalendarUserNode::STATUS_INVITED:
|
||||||
|
default:
|
||||||
|
$status = PhabricatorCalendarEventInvitee::STATUS_INVITED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$invitee->setStatus($status);
|
||||||
|
$invitee->save();
|
||||||
|
|
||||||
|
$new_map[$phid] = $invitee;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($old_map as $phid => $invitee) {
|
||||||
|
if (empty($new_map[$phid])) {
|
||||||
|
$invitee->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$event->attachInvitees($new_map);
|
||||||
|
|
||||||
$import->newLogMessage(
|
$import->newLogMessage(
|
||||||
PhabricatorCalendarImportUpdateLogType::LOGTYPE,
|
PhabricatorCalendarImportUpdateLogType::LOGTYPE,
|
||||||
array(
|
array(
|
||||||
|
@ -403,6 +513,9 @@ abstract class PhabricatorCalendarImportEngine
|
||||||
$until_datetime->setViewerTimezone($timezone);
|
$until_datetime->setViewerTimezone($timezone);
|
||||||
$event->setUntilDateTime($until_datetime);
|
$event->setUntilDateTime($until_datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$count = $rrule->getCount();
|
||||||
|
$event->setParameter('recurrenceCount', $count);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $event;
|
return $event;
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarImportTriggerLogType
|
||||||
|
extends PhabricatorCalendarImportLogType {
|
||||||
|
|
||||||
|
const LOGTYPE = 'trigger';
|
||||||
|
|
||||||
|
public function getDisplayType(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorCalendarImportLog $log) {
|
||||||
|
return pht('Import Triggered');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayDescription(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorCalendarImportLog $log) {
|
||||||
|
return pht('Triggered a periodic update.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayIcon(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorCalendarImportLog $log) {
|
||||||
|
return 'fa-clock-o';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayColor(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
PhabricatorCalendarImportLog $log) {
|
||||||
|
return 'blue';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ final class PhabricatorCalendarImportUpdateLogType
|
||||||
public function getDisplayIcon(
|
public function getDisplayIcon(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorCalendarImportLog $log) {
|
PhabricatorCalendarImportLog $log) {
|
||||||
return 'fa-upload';
|
return 'fa-calendar';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayColor(
|
public function getDisplayColor(
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExternalInviteePHIDType
|
||||||
|
extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'CXNV';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('External Invitee');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new PhabricatorCalendarExternalInvitee();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDTypeApplicationClass() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new PhabricatorCalendarExternalInviteeQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$invitee = $objects[$phid];
|
||||||
|
|
||||||
|
$name = $invitee->getName();
|
||||||
|
$handle->setName($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -633,6 +633,11 @@ final class PhabricatorCalendarEventQuery
|
||||||
PhabricatorCalendarEvent $event,
|
PhabricatorCalendarEvent $event,
|
||||||
$raw_limit) {
|
$raw_limit) {
|
||||||
|
|
||||||
|
$count = $event->getRecurrenceCount();
|
||||||
|
if ($count && ($count <= $raw_limit)) {
|
||||||
|
return ($count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
return $raw_limit;
|
return $raw_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExternalInviteeQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $names;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withNames(array $names) {
|
||||||
|
$this->names = $names;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorCalendarExternalInvitee();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
|
if ($this->ids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->names !== null) {
|
||||||
|
$name_indexes = array();
|
||||||
|
foreach ($this->names as $name) {
|
||||||
|
$name_indexes[] = PhabricatorHash::digestForIndex($name);
|
||||||
|
}
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'nameIndex IN (%Ls)',
|
||||||
|
$name_indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -27,7 +27,6 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
|
|
||||||
protected $isRecurring = 0;
|
protected $isRecurring = 0;
|
||||||
|
|
||||||
private $isGhostEvent = false;
|
|
||||||
protected $instanceOfEventPHID;
|
protected $instanceOfEventPHID;
|
||||||
protected $sequenceIndex;
|
protected $sequenceIndex;
|
||||||
|
|
||||||
|
@ -60,6 +59,9 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
protected $recurrenceEndDate;
|
protected $recurrenceEndDate;
|
||||||
protected $recurrenceFrequency = array();
|
protected $recurrenceFrequency = array();
|
||||||
|
|
||||||
|
private $isGhostEvent = false;
|
||||||
|
private $stubInvitees;
|
||||||
|
|
||||||
public static function initializeNewCalendarEvent(PhabricatorUser $actor) {
|
public static function initializeNewCalendarEvent(PhabricatorUser $actor) {
|
||||||
$app = id(new PhabricatorApplicationQuery())
|
$app = id(new PhabricatorApplicationQuery())
|
||||||
->setViewer($actor)
|
->setViewer($actor)
|
||||||
|
@ -75,10 +77,10 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
|
|
||||||
$default_icon = 'fa-calendar';
|
$default_icon = 'fa-calendar';
|
||||||
|
|
||||||
$datetime_start = PhutilCalendarAbsoluteDateTime::newFromEpoch(
|
$datetime_defaults = self::newDefaultEventDateTimes(
|
||||||
$now,
|
$actor,
|
||||||
$actor->getTimezoneIdentifier());
|
$now);
|
||||||
$datetime_end = $datetime_start->newRelativeDateTime('PT1H');
|
list($datetime_start, $datetime_end) = $datetime_defaults;
|
||||||
|
|
||||||
return id(new PhabricatorCalendarEvent())
|
return id(new PhabricatorCalendarEvent())
|
||||||
->setDescription('')
|
->setDescription('')
|
||||||
|
@ -102,6 +104,31 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
->applyViewerTimezone($actor);
|
->applyViewerTimezone($actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function newDefaultEventDateTimes(
|
||||||
|
PhabricatorUser $viewer,
|
||||||
|
$now) {
|
||||||
|
|
||||||
|
$datetime_start = PhutilCalendarAbsoluteDateTime::newFromEpoch(
|
||||||
|
$now,
|
||||||
|
$viewer->getTimezoneIdentifier());
|
||||||
|
|
||||||
|
// Advance the time by an hour, then round downwards to the nearest hour.
|
||||||
|
// For example, if it is currently 3:25 PM, we suggest a default start time
|
||||||
|
// of 4 PM.
|
||||||
|
$datetime_start = $datetime_start
|
||||||
|
->newRelativeDateTime('PT1H')
|
||||||
|
->newAbsoluteDateTime();
|
||||||
|
$datetime_start->setMinute(0);
|
||||||
|
$datetime_start->setSecond(0);
|
||||||
|
|
||||||
|
// Default the end time to an hour after the start time.
|
||||||
|
$datetime_end = $datetime_start
|
||||||
|
->newRelativeDateTime('PT1H')
|
||||||
|
->newAbsoluteDateTime();
|
||||||
|
|
||||||
|
return array($datetime_start, $datetime_end);
|
||||||
|
}
|
||||||
|
|
||||||
private function newChild(
|
private function newChild(
|
||||||
PhabricatorUser $actor,
|
PhabricatorUser $actor,
|
||||||
$sequence,
|
$sequence,
|
||||||
|
@ -226,10 +253,16 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$limit = $sequence + 1;
|
||||||
|
$count = $this->getRecurrenceCount();
|
||||||
|
if ($count && ($count < $limit)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$instances = $set->getEventsBetween(
|
$instances = $set->getEventsBetween(
|
||||||
null,
|
null,
|
||||||
$this->newUntilDateTime(),
|
$this->newUntilDateTime(),
|
||||||
$sequence + 1);
|
$limit);
|
||||||
|
|
||||||
return idx($instances, $sequence, null);
|
return idx($instances, $sequence, null);
|
||||||
}
|
}
|
||||||
|
@ -418,9 +451,34 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInvitees() {
|
public function getInvitees() {
|
||||||
|
if ($this->getIsGhostEvent() || $this->getIsStub()) {
|
||||||
|
if ($this->stubInvitees === null) {
|
||||||
|
$this->stubInvitees = $this->newStubInvitees();
|
||||||
|
}
|
||||||
|
return $this->stubInvitees;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->assertAttached($this->invitees);
|
return $this->assertAttached($this->invitees);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function newStubInvitees() {
|
||||||
|
$parent = $this->getParentEvent();
|
||||||
|
|
||||||
|
$parent_invitees = $parent->getInvitees();
|
||||||
|
$stub_invitees = array();
|
||||||
|
|
||||||
|
foreach ($parent_invitees as $invitee) {
|
||||||
|
$stub_invitee = id(new PhabricatorCalendarEventInvitee())
|
||||||
|
->setInviteePHID($invitee->getInviteePHID())
|
||||||
|
->setInviterPHID($invitee->getInviterPHID())
|
||||||
|
->setStatus(PhabricatorCalendarEventInvitee::STATUS_INVITED);
|
||||||
|
|
||||||
|
$stub_invitees[] = $stub_invitee;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stub_invitees;
|
||||||
|
}
|
||||||
|
|
||||||
public function attachInvitees(array $invitees) {
|
public function attachInvitees(array $invitees) {
|
||||||
$this->invitees = $invitees;
|
$this->invitees = $invitees;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -447,6 +505,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
if (!$invited) {
|
if (!$invited) {
|
||||||
return PhabricatorCalendarEventInvitee::STATUS_UNINVITED;
|
return PhabricatorCalendarEventInvitee::STATUS_UNINVITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invited = $invited->getStatus();
|
$invited = $invited->getStatus();
|
||||||
return $invited;
|
return $invited;
|
||||||
}
|
}
|
||||||
|
@ -907,9 +966,24 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
$rrule->setUntil($until);
|
$rrule->setUntil($until);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$count = $this->getRecurrenceCount();
|
||||||
|
if ($count) {
|
||||||
|
$rrule->setCount($count);
|
||||||
|
}
|
||||||
|
|
||||||
return $rrule;
|
return $rrule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRecurrenceCount() {
|
||||||
|
$count = (int)$this->getParameter('recurrenceCount');
|
||||||
|
|
||||||
|
if (!$count) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
public function newRecurrenceSet() {
|
public function newRecurrenceSet() {
|
||||||
if ($this->isChildEvent()) {
|
if ($this->isChildEvent()) {
|
||||||
return $this->getParentEvent()->newRecurrenceSet();
|
return $this->getParentEvent()->newRecurrenceSet();
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExternalInvitee
|
||||||
|
extends PhabricatorCalendarDAO
|
||||||
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
|
protected $name;
|
||||||
|
protected $nameIndex;
|
||||||
|
protected $uri;
|
||||||
|
protected $parameters = array();
|
||||||
|
protected $sourcePHID;
|
||||||
|
|
||||||
|
public static function initializeNewCalendarEventInvitee(
|
||||||
|
PhabricatorUser $actor, $event) {
|
||||||
|
return id(new PhabricatorCalendarEventInvitee())
|
||||||
|
->setInviterPHID($actor->getPHID())
|
||||||
|
->setStatus(self::STATUS_INVITED)
|
||||||
|
->setEventPHID($event->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'parameters' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'name' => 'text',
|
||||||
|
'nameIndex' => 'bytes12',
|
||||||
|
'uri' => 'text',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_name' => array(
|
||||||
|
'columns' => array('nameIndex'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDType() {
|
||||||
|
return PhabricatorCalendarExternalInviteePHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save() {
|
||||||
|
$this->nameIndex = PhabricatorHash::digestForIndex($this->getName());
|
||||||
|
return parent::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,12 @@ final class PhabricatorCalendarImport
|
||||||
protected $engineType;
|
protected $engineType;
|
||||||
protected $parameters = array();
|
protected $parameters = array();
|
||||||
protected $isDisabled = 0;
|
protected $isDisabled = 0;
|
||||||
|
protected $triggerPHID;
|
||||||
|
protected $triggerFrequency;
|
||||||
|
|
||||||
|
const FREQUENCY_ONCE = 'once';
|
||||||
|
const FREQUENCY_HOURLY = 'hourly';
|
||||||
|
const FREQUENCY_DAILY = 'daily';
|
||||||
|
|
||||||
private $engine = self::ATTACHABLE;
|
private $engine = self::ATTACHABLE;
|
||||||
|
|
||||||
|
@ -27,7 +33,8 @@ final class PhabricatorCalendarImport
|
||||||
->setEditPolicy($actor->getPHID())
|
->setEditPolicy($actor->getPHID())
|
||||||
->setIsDisabled(0)
|
->setIsDisabled(0)
|
||||||
->setEngineType($engine->getImportEngineType())
|
->setEngineType($engine->getImportEngineType())
|
||||||
->attachEngine($engine);
|
->attachEngine($engine)
|
||||||
|
->setTriggerFrequency(self::FREQUENCY_ONCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
|
@ -40,6 +47,8 @@ final class PhabricatorCalendarImport
|
||||||
'name' => 'text',
|
'name' => 'text',
|
||||||
'engineType' => 'text64',
|
'engineType' => 'text64',
|
||||||
'isDisabled' => 'bool',
|
'isDisabled' => 'bool',
|
||||||
|
'triggerPHID' => 'phid?',
|
||||||
|
'triggerFrequency' => 'text64',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_author' => array(
|
'key_author' => array(
|
||||||
|
@ -85,6 +94,21 @@ final class PhabricatorCalendarImport
|
||||||
return $this->getEngine()->getDisplayName($this);
|
return $this->getEngine()->getDisplayName($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getTriggerFrequencyMap() {
|
||||||
|
return array(
|
||||||
|
self::FREQUENCY_ONCE => array(
|
||||||
|
'name' => pht('No Automatic Updates'),
|
||||||
|
),
|
||||||
|
self::FREQUENCY_HOURLY => array(
|
||||||
|
'name' => pht('Update Hourly'),
|
||||||
|
),
|
||||||
|
self::FREQUENCY_DAILY => array(
|
||||||
|
'name' => pht('Update Daily'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,6 +179,17 @@ final class PhabricatorCalendarImport
|
||||||
|
|
||||||
$this->openTransaction();
|
$this->openTransaction();
|
||||||
|
|
||||||
|
$trigger_phid = $this->getTriggerPHID();
|
||||||
|
if ($trigger_phid) {
|
||||||
|
$trigger = id(new PhabricatorWorkerTriggerQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($trigger_phid))
|
||||||
|
->executeOne();
|
||||||
|
if ($trigger) {
|
||||||
|
$engine->destroyObject($trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$events = id(new PhabricatorCalendarEventQuery())
|
$events = id(new PhabricatorCalendarEventQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withImportSourcePHIDs(array($this->getPHID()))
|
->withImportSourcePHIDs(array($this->getPHID()))
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarImportReloadWorker extends PhabricatorWorker {
|
||||||
|
|
||||||
|
protected function doWork() {
|
||||||
|
$import = $this->loadImport();
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
|
if ($import->getIsDisabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$author = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($import->getAuthorPHID()))
|
||||||
|
->needUserSettings(true)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$import_engine = $import->getEngine();
|
||||||
|
|
||||||
|
$import->newLogMessage(
|
||||||
|
PhabricatorCalendarImportTriggerLogType::LOGTYPE,
|
||||||
|
array());
|
||||||
|
|
||||||
|
$import_engine->importEventsFromSource($author, $import);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadImport() {
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
|
$data = $this->getTaskData();
|
||||||
|
$import_phid = idx($data, 'importPHID');
|
||||||
|
|
||||||
|
$import = id(new PhabricatorCalendarImportQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($import_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$import) {
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Failed to load import with PHID "%s".',
|
||||||
|
$import_phid));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $import;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,10 +30,11 @@ final class PhabricatorCalendarEventInviteTransaction
|
||||||
|
|
||||||
$map = array();
|
$map = array();
|
||||||
foreach ($add as $phid) {
|
foreach ($add as $phid) {
|
||||||
$map[$phid] = $status_invited;
|
$map[$phid] = $status_invited;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($rem as $phid) {
|
foreach ($rem as $phid) {
|
||||||
$map[$phid] = $status_uninvited;
|
$map[$phid] = $status_uninvited;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're creating this event and the actor is inviting themselves,
|
// If we're creating this event and the actor is inviting themselves,
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarImportFrequencyTransaction
|
||||||
|
extends PhabricatorCalendarImportTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'calendar.import.frequency';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getTriggerFrequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setTriggerFrequency($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s changed the automatic update frequency for this import.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap();
|
||||||
|
$valid = array_keys($frequency_map);
|
||||||
|
$valid = array_fuse($valid);
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
if (!isset($valid[$value])) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Import frequency "%s" is not valid. Valid frequences are: %s.',
|
||||||
|
$value,
|
||||||
|
implode(', ', $valid)),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarImportReloadTransaction
|
||||||
|
extends PhabricatorCalendarImportTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'calendar.import.reload';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyExternalEffects($object, $value) {
|
||||||
|
// NOTE: This transaction does nothing directly; instead, the Editor
|
||||||
|
// reacts to it and performs the reload.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s reloaded this event source.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ final class PhortuneMerchantEditController
|
||||||
$e_name = true;
|
$e_name = true;
|
||||||
$v_name = $merchant->getName();
|
$v_name = $merchant->getName();
|
||||||
$v_desc = $merchant->getDescription();
|
$v_desc = $merchant->getDescription();
|
||||||
|
$v_cont = $merchant->getContactInfo();
|
||||||
$v_members = $merchant->getMemberPHIDs();
|
$v_members = $merchant->getMemberPHIDs();
|
||||||
$e_members = null;
|
$e_members = null;
|
||||||
|
|
||||||
|
@ -54,12 +55,14 @@ final class PhortuneMerchantEditController
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$v_name = $request->getStr('name');
|
$v_name = $request->getStr('name');
|
||||||
$v_desc = $request->getStr('desc');
|
$v_desc = $request->getStr('desc');
|
||||||
|
$v_cont = $request->getStr('cont');
|
||||||
$v_view = $request->getStr('viewPolicy');
|
$v_view = $request->getStr('viewPolicy');
|
||||||
$v_edit = $request->getStr('editPolicy');
|
$v_edit = $request->getStr('editPolicy');
|
||||||
$v_members = $request->getArr('memberPHIDs');
|
$v_members = $request->getArr('memberPHIDs');
|
||||||
|
|
||||||
$type_name = PhortuneMerchantTransaction::TYPE_NAME;
|
$type_name = PhortuneMerchantTransaction::TYPE_NAME;
|
||||||
$type_desc = PhortuneMerchantTransaction::TYPE_DESCRIPTION;
|
$type_desc = PhortuneMerchantTransaction::TYPE_DESCRIPTION;
|
||||||
|
$type_cont = PhortuneMerchantTransaction::TYPE_CONTACTINFO;
|
||||||
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
$type_edge = PhabricatorTransactions::TYPE_EDGE;
|
||||||
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
|
||||||
|
@ -75,6 +78,10 @@ final class PhortuneMerchantEditController
|
||||||
->setTransactionType($type_desc)
|
->setTransactionType($type_desc)
|
||||||
->setNewValue($v_desc);
|
->setNewValue($v_desc);
|
||||||
|
|
||||||
|
$xactions[] = id(new PhortuneMerchantTransaction())
|
||||||
|
->setTransactionType($type_cont)
|
||||||
|
->setNewValue($v_cont);
|
||||||
|
|
||||||
$xactions[] = id(new PhortuneMerchantTransaction())
|
$xactions[] = id(new PhortuneMerchantTransaction())
|
||||||
->setTransactionType($type_view)
|
->setTransactionType($type_view)
|
||||||
->setNewValue($v_view);
|
->setNewValue($v_view);
|
||||||
|
@ -127,6 +134,12 @@ final class PhortuneMerchantEditController
|
||||||
->setName('desc')
|
->setName('desc')
|
||||||
->setLabel(pht('Description'))
|
->setLabel(pht('Description'))
|
||||||
->setValue($v_desc))
|
->setValue($v_desc))
|
||||||
|
->appendChild(
|
||||||
|
id(new PhabricatorRemarkupControl())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setName('cont')
|
||||||
|
->setLabel(pht('Contact Info'))
|
||||||
|
->setValue($v_cont))
|
||||||
->appendControl(
|
->appendControl(
|
||||||
id(new AphrontFormTokenizerControl())
|
id(new AphrontFormTokenizerControl())
|
||||||
->setDatasource(new PhabricatorPeopleDatasource())
|
->setDatasource(new PhabricatorPeopleDatasource())
|
||||||
|
|
|
@ -36,7 +36,6 @@ final class PhortuneMerchantViewController
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$details = $this->buildDetailsView($merchant, $providers);
|
$details = $this->buildDetailsView($merchant, $providers);
|
||||||
$description = $this->buildDescriptionView($merchant);
|
|
||||||
$curtain = $this->buildCurtainView($merchant);
|
$curtain = $this->buildCurtainView($merchant);
|
||||||
|
|
||||||
$provider_list = $this->buildProviderList(
|
$provider_list = $this->buildProviderList(
|
||||||
|
@ -53,7 +52,6 @@ final class PhortuneMerchantViewController
|
||||||
->setCurtain($curtain)
|
->setCurtain($curtain)
|
||||||
->setMainColumn(array(
|
->setMainColumn(array(
|
||||||
$details,
|
$details,
|
||||||
$description,
|
|
||||||
$provider_list,
|
$provider_list,
|
||||||
$timeline,
|
$timeline,
|
||||||
));
|
));
|
||||||
|
@ -130,30 +128,30 @@ final class PhortuneMerchantViewController
|
||||||
|
|
||||||
$view->addProperty(pht('Status'), $status_view);
|
$view->addProperty(pht('Status'), $status_view);
|
||||||
|
|
||||||
|
$description = $merchant->getDescription();
|
||||||
|
if (strlen($description)) {
|
||||||
|
$description = new PHUIRemarkupView($viewer, $description);
|
||||||
|
$view->addSectionHeader(
|
||||||
|
pht('Description'),
|
||||||
|
PHUIPropertyListView::ICON_SUMMARY);
|
||||||
|
$view->addTextContent($description);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact_info = $merchant->getContactInfo();
|
||||||
|
if (strlen($contact_info)) {
|
||||||
|
$contact_info = new PHUIRemarkupView($viewer, $contact_info);
|
||||||
|
$view->addSectionHeader(
|
||||||
|
pht('Contact Info'),
|
||||||
|
PHUIPropertyListView::ICON_SUMMARY);
|
||||||
|
$view->addTextContent($contact_info);
|
||||||
|
}
|
||||||
|
|
||||||
return id(new PHUIObjectBoxView())
|
return id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Details'))
|
->setHeaderText(pht('Details'))
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
->appendChild($view);
|
->appendChild($view);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildDescriptionView(PhortuneMerchant $merchant) {
|
|
||||||
$viewer = $this->getViewer();
|
|
||||||
$view = id(new PHUIPropertyListView())
|
|
||||||
->setUser($viewer);
|
|
||||||
|
|
||||||
$description = $merchant->getDescription();
|
|
||||||
if (strlen($description)) {
|
|
||||||
$description = new PHUIRemarkupView($viewer, $description);
|
|
||||||
$view->addTextContent($description);
|
|
||||||
return id(new PHUIObjectBoxView())
|
|
||||||
->setHeaderText(pht('Description'))
|
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
|
||||||
->appendChild($view);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildCurtainView(PhortuneMerchant $merchant) {
|
private function buildCurtainView(PhortuneMerchant $merchant) {
|
||||||
$viewer = $this->getRequest()->getUser();
|
$viewer = $this->getRequest()->getUser();
|
||||||
$id = $merchant->getID();
|
$id = $merchant->getID();
|
||||||
|
|
|
@ -16,6 +16,7 @@ final class PhortuneMerchantEditor
|
||||||
|
|
||||||
$types[] = PhortuneMerchantTransaction::TYPE_NAME;
|
$types[] = PhortuneMerchantTransaction::TYPE_NAME;
|
||||||
$types[] = PhortuneMerchantTransaction::TYPE_DESCRIPTION;
|
$types[] = PhortuneMerchantTransaction::TYPE_DESCRIPTION;
|
||||||
|
$types[] = PhortuneMerchantTransaction::TYPE_CONTACTINFO;
|
||||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||||
|
|
||||||
|
@ -30,6 +31,8 @@ final class PhortuneMerchantEditor
|
||||||
return $object->getName();
|
return $object->getName();
|
||||||
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
||||||
return $object->getDescription();
|
return $object->getDescription();
|
||||||
|
case PhortuneMerchantTransaction::TYPE_CONTACTINFO:
|
||||||
|
return $object->getContactInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||||
|
@ -42,6 +45,7 @@ final class PhortuneMerchantEditor
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case PhortuneMerchantTransaction::TYPE_NAME:
|
case PhortuneMerchantTransaction::TYPE_NAME:
|
||||||
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
||||||
|
case PhortuneMerchantTransaction::TYPE_CONTACTINFO:
|
||||||
return $xaction->getNewValue();
|
return $xaction->getNewValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +63,9 @@ final class PhortuneMerchantEditor
|
||||||
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
||||||
$object->setDescription($xaction->getNewValue());
|
$object->setDescription($xaction->getNewValue());
|
||||||
return;
|
return;
|
||||||
|
case PhortuneMerchantTransaction::TYPE_CONTACTINFO:
|
||||||
|
$object->setContactInfo($xaction->getNewValue());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||||
|
@ -71,6 +78,7 @@ final class PhortuneMerchantEditor
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case PhortuneMerchantTransaction::TYPE_NAME:
|
case PhortuneMerchantTransaction::TYPE_NAME:
|
||||||
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
case PhortuneMerchantTransaction::TYPE_DESCRIPTION:
|
||||||
|
case PhortuneMerchantTransaction::TYPE_CONTACTINFO:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ final class PhortuneMerchant extends PhortuneDAO
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $viewPolicy;
|
protected $viewPolicy;
|
||||||
protected $description;
|
protected $description;
|
||||||
|
protected $contactInfo;
|
||||||
|
|
||||||
private $memberPHIDs = self::ATTACHABLE;
|
private $memberPHIDs = self::ATTACHABLE;
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ final class PhortuneMerchant extends PhortuneDAO
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'name' => 'text255',
|
'name' => 'text255',
|
||||||
'description' => 'text',
|
'description' => 'text',
|
||||||
|
'contactInfo' => 'text',
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ final class PhortuneMerchantTransaction
|
||||||
|
|
||||||
const TYPE_NAME = 'merchant:name';
|
const TYPE_NAME = 'merchant:name';
|
||||||
const TYPE_DESCRIPTION = 'merchant:description';
|
const TYPE_DESCRIPTION = 'merchant:description';
|
||||||
|
const TYPE_CONTACTINFO = 'merchant:contactinfo';
|
||||||
|
|
||||||
public function getApplicationName() {
|
public function getApplicationName() {
|
||||||
return 'phortune';
|
return 'phortune';
|
||||||
|
@ -42,6 +43,10 @@ final class PhortuneMerchantTransaction
|
||||||
return pht(
|
return pht(
|
||||||
'%s updated the description for this merchant.',
|
'%s updated the description for this merchant.',
|
||||||
$this->renderHandleLink($author_phid));
|
$this->renderHandleLink($author_phid));
|
||||||
|
case self::TYPE_CONTACTINFO:
|
||||||
|
return pht(
|
||||||
|
'%s updated the contact information for this merchant.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::getTitle();
|
return parent::getTitle();
|
||||||
|
@ -51,6 +56,7 @@ final class PhortuneMerchantTransaction
|
||||||
$old = $this->getOldValue();
|
$old = $this->getOldValue();
|
||||||
switch ($this->getTransactionType()) {
|
switch ($this->getTransactionType()) {
|
||||||
case self::TYPE_DESCRIPTION:
|
case self::TYPE_DESCRIPTION:
|
||||||
|
case self::TYPE_CONTACTINFO:
|
||||||
return ($old === null);
|
return ($old === null);
|
||||||
}
|
}
|
||||||
return parent::shouldHide();
|
return parent::shouldHide();
|
||||||
|
@ -60,6 +66,8 @@ final class PhortuneMerchantTransaction
|
||||||
switch ($this->getTransactionType()) {
|
switch ($this->getTransactionType()) {
|
||||||
case self::TYPE_DESCRIPTION:
|
case self::TYPE_DESCRIPTION:
|
||||||
return ($this->getOldValue() !== null);
|
return ($this->getOldValue() !== null);
|
||||||
|
case self::TYPE_CONTACTINFO:
|
||||||
|
return ($this->getOldValue() !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::hasChangeDetails();
|
return parent::hasChangeDetails();
|
||||||
|
|
|
@ -36,17 +36,32 @@ final class PhortuneSubscriptionWorker extends PhabricatorWorker {
|
||||||
->setSubscription($subscription);
|
->setSubscription($subscription);
|
||||||
|
|
||||||
// TODO: This isn't really ideal. It would be better to use an application
|
// TODO: This isn't really ideal. It would be better to use an application
|
||||||
// actor than the original author of the subscription. In particular, if
|
// actor than a fairly arbitrary account member.
|
||||||
// someone initiates a subscription, adds some other account managers, and
|
|
||||||
// later leaves the company, they'll continue "acting" here indefinitely.
|
|
||||||
// However, for now, some of the stuff later in the pipeline requires a
|
// However, for now, some of the stuff later in the pipeline requires a
|
||||||
// valid actor with a real PHID. The subscription should eventually be
|
// valid actor with a real PHID. The subscription should eventually be
|
||||||
// able to create these invoices "as" the application it is acting on
|
// able to create these invoices "as" the application it is acting on
|
||||||
// behalf of.
|
// behalf of.
|
||||||
$actor = id(new PhabricatorPeopleQuery())
|
|
||||||
|
$members = id(new PhabricatorPeopleQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withPHIDs(array($subscription->getAuthorPHID()))
|
->withPHIDs($account->getMemberPHIDs())
|
||||||
->executeOne();
|
->execute();
|
||||||
|
$actor = null;
|
||||||
|
foreach ($members as $member) {
|
||||||
|
|
||||||
|
// Don't act as a disabled user. If all of the users on the account are
|
||||||
|
// disabled this means we won't charge the subscription, but that's
|
||||||
|
// probably correct since it means no one can cancel or pay it anyway.
|
||||||
|
if ($member->getIsDisabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, just pick the first valid user we encounter as the actor.
|
||||||
|
$actor = $member;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$actor) {
|
if (!$actor) {
|
||||||
throw new Exception(pht('Failed to load actor to bill subscription!'));
|
throw new Exception(pht('Failed to load actor to bill subscription!'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1349,7 +1349,9 @@ abstract class PhabricatorEditEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final public function addActionToCrumbs(PHUICrumbsView $crumbs) {
|
final public function addActionToCrumbs(
|
||||||
|
PHUICrumbsView $crumbs,
|
||||||
|
array $parameters = array()) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$can_create = $this->hasCreateCapability();
|
$can_create = $this->hasCreateCapability();
|
||||||
|
@ -1385,6 +1387,11 @@ abstract class PhabricatorEditEngine
|
||||||
$form_key = $config->getIdentifier();
|
$form_key = $config->getIdentifier();
|
||||||
$create_uri = $this->getEditURI(null, "form/{$form_key}/");
|
$create_uri = $this->getEditURI(null, "form/{$form_key}/");
|
||||||
|
|
||||||
|
if ($parameters) {
|
||||||
|
$create_uri = (string)id(new PhutilURI($create_uri))
|
||||||
|
->setQueryParams($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
if (count($configs) > 1) {
|
if (count($configs) > 1) {
|
||||||
$menu_icon = 'fa-caret-square-o-down';
|
$menu_icon = 'fa-caret-square-o-down';
|
||||||
|
|
||||||
|
@ -1395,6 +1402,11 @@ abstract class PhabricatorEditEngine
|
||||||
$form_key = $config->getIdentifier();
|
$form_key = $config->getIdentifier();
|
||||||
$config_uri = $this->getEditURI(null, "form/{$form_key}/");
|
$config_uri = $this->getEditURI(null, "form/{$form_key}/");
|
||||||
|
|
||||||
|
if ($parameters) {
|
||||||
|
$config_uri = (string)id(new PhutilURI($config_uri))
|
||||||
|
->setQueryParams($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
$item_icon = 'fa-plus';
|
$item_icon = 'fa-plus';
|
||||||
|
|
||||||
$dropdown->addAction(
|
$dropdown->addAction(
|
||||||
|
|
|
@ -128,6 +128,9 @@ final class PhabricatorEditEngineConfiguration
|
||||||
|
|
||||||
$values = $this->getProperty('defaults', array());
|
$values = $this->getProperty('defaults', array());
|
||||||
foreach ($fields as $key => $field) {
|
foreach ($fields as $key => $field) {
|
||||||
|
if (!$field->getIsDefaultable()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if ($is_new) {
|
if ($is_new) {
|
||||||
if (array_key_exists($key, $values)) {
|
if (array_key_exists($key, $values)) {
|
||||||
$field->readDefaultValueFromConfiguration($values[$key]);
|
$field->readDefaultValueFromConfiguration($values[$key]);
|
||||||
|
@ -157,6 +160,11 @@ final class PhabricatorEditEngineConfiguration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the field isn't lockable, remove any lock we applied.
|
||||||
|
if (!$field->getIsLockable()) {
|
||||||
|
$field->setIsLocked(false);
|
||||||
|
}
|
||||||
|
|
||||||
$fields = $this->reorderFields($fields);
|
$fields = $this->reorderFields($fields);
|
||||||
|
|
||||||
$preamble = $this->getPreamble();
|
$preamble = $this->getPreamble();
|
||||||
|
|
6
src/infrastructure/env/PhabricatorEnv.php
vendored
6
src/infrastructure/env/PhabricatorEnv.php
vendored
|
@ -202,6 +202,12 @@ final class PhabricatorEnv extends Phobject {
|
||||||
phutil_load_library($library);
|
phutil_load_library($library);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop any class map caches, since they will have generated without
|
||||||
|
// any classes from libraries. Without this, preflight setup checks can
|
||||||
|
// cause generation of a setup check cache that omits checks defined in
|
||||||
|
// libraries, for example.
|
||||||
|
PhutilClassMapQuery::deleteCaches();
|
||||||
|
|
||||||
// If custom libraries specify config options, they won't get default
|
// If custom libraries specify config options, they won't get default
|
||||||
// values as the Default source has already been loaded, so we get it to
|
// values as the Default source has already been loaded, so we get it to
|
||||||
// pull in all options from non-phabricator libraries now they are loaded.
|
// pull in all options from non-phabricator libraries now they are loaded.
|
||||||
|
|
Loading…
Reference in a new issue