mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 05:20:56 +01:00
Rough in most of Calendar exports
Summary: Ref T10747. Rough flow is: - Run a query. - Select a new "Export Events..." action. - This lets you define an "Export", which has a unique URL you can paste into Google Calendar or Calendar.app or whatever. Most of this does nothing yet but here's the boilerplate. Test Plan: Doesn't do anything yet. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10747 Differential Revision: https://secure.phabricator.com/D16675
This commit is contained in:
parent
c5efa3ecb5
commit
49448a87c1
21 changed files with 818 additions and 6 deletions
resources/sql/autopatches
src
__phutil_library_map__.php
applications
calendar
application
controller
editor
phid
query
storage
xaction
maniphest/query
docs/user/userguide
infrastructure/storage/lisk
14
resources/sql/autopatches/20161005.cal.02.export.sql
Normal file
14
resources/sql/autopatches/20161005.cal.02.export.sql
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_calendar.calendar_export (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
name LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
policyMode VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
queryKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
secretKey BINARY(20) NOT NULL,
|
||||||
|
isDisabled BOOL NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
KEY `key_author` (authorPHID),
|
||||||
|
UNIQUE KEY `key_secret` (secretKey)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
19
resources/sql/autopatches/20161005.cal.03.exportxaction.sql
Normal file
19
resources/sql/autopatches/20161005.cal.03.exportxaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_calendar.calendar_exporttransaction (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||||
|
commentVersion INT UNSIGNED NOT NULL,
|
||||||
|
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (`phid`),
|
||||||
|
KEY `key_object` (`objectPHID`)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -2075,6 +2075,20 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEventTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php',
|
'PhabricatorCalendarEventTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php',
|
||||||
'PhabricatorCalendarEventUntilDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventUntilDateTransaction.php',
|
'PhabricatorCalendarEventUntilDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventUntilDateTransaction.php',
|
||||||
'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php',
|
'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php',
|
||||||
|
'PhabricatorCalendarExport' => 'applications/calendar/storage/PhabricatorCalendarExport.php',
|
||||||
|
'PhabricatorCalendarExportDisableTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportDisableTransaction.php',
|
||||||
|
'PhabricatorCalendarExportEditController' => 'applications/calendar/controller/PhabricatorCalendarExportEditController.php',
|
||||||
|
'PhabricatorCalendarExportEditEngine' => 'applications/calendar/editor/PhabricatorCalendarExportEditEngine.php',
|
||||||
|
'PhabricatorCalendarExportEditor' => 'applications/calendar/editor/PhabricatorCalendarExportEditor.php',
|
||||||
|
'PhabricatorCalendarExportListController' => 'applications/calendar/controller/PhabricatorCalendarExportListController.php',
|
||||||
|
'PhabricatorCalendarExportModeTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportModeTransaction.php',
|
||||||
|
'PhabricatorCalendarExportNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportNameTransaction.php',
|
||||||
|
'PhabricatorCalendarExportPHIDType' => 'applications/calendar/phid/PhabricatorCalendarExportPHIDType.php',
|
||||||
|
'PhabricatorCalendarExportQuery' => 'applications/calendar/query/PhabricatorCalendarExportQuery.php',
|
||||||
|
'PhabricatorCalendarExportQueryKeyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarExportQueryKeyTransaction.php',
|
||||||
|
'PhabricatorCalendarExportSearchEngine' => 'applications/calendar/query/PhabricatorCalendarExportSearchEngine.php',
|
||||||
|
'PhabricatorCalendarExportTransaction' => 'applications/calendar/storage/PhabricatorCalendarExportTransaction.php',
|
||||||
|
'PhabricatorCalendarExportTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarExportTransactionType.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',
|
||||||
'PhabricatorCalendarIconSet' => 'applications/calendar/icon/PhabricatorCalendarIconSet.php',
|
'PhabricatorCalendarIconSet' => 'applications/calendar/icon/PhabricatorCalendarIconSet.php',
|
||||||
|
@ -6825,6 +6839,25 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEventTransactionType' => 'PhabricatorModularTransactionType',
|
'PhabricatorCalendarEventTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
'PhabricatorCalendarEventUntilDateTransaction' => 'PhabricatorCalendarEventDateTransaction',
|
'PhabricatorCalendarEventUntilDateTransaction' => 'PhabricatorCalendarEventDateTransaction',
|
||||||
'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController',
|
||||||
|
'PhabricatorCalendarExport' => array(
|
||||||
|
'PhabricatorCalendarDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
'PhabricatorDestructibleInterface',
|
||||||
|
),
|
||||||
|
'PhabricatorCalendarExportDisableTransaction' => 'PhabricatorCalendarExportTransactionType',
|
||||||
|
'PhabricatorCalendarExportEditController' => 'PhabricatorCalendarController',
|
||||||
|
'PhabricatorCalendarExportEditEngine' => 'PhabricatorEditEngine',
|
||||||
|
'PhabricatorCalendarExportEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'PhabricatorCalendarExportListController' => 'PhabricatorCalendarController',
|
||||||
|
'PhabricatorCalendarExportModeTransaction' => 'PhabricatorCalendarExportTransactionType',
|
||||||
|
'PhabricatorCalendarExportNameTransaction' => 'PhabricatorCalendarExportTransactionType',
|
||||||
|
'PhabricatorCalendarExportPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'PhabricatorCalendarExportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorCalendarExportQueryKeyTransaction' => 'PhabricatorCalendarExportTransactionType',
|
||||||
|
'PhabricatorCalendarExportSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'PhabricatorCalendarExportTransaction' => 'PhabricatorModularTransaction',
|
||||||
|
'PhabricatorCalendarExportTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
|
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
|
||||||
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
|
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorCalendarIconSet' => 'PhabricatorIconSet',
|
'PhabricatorCalendarIconSet' => 'PhabricatorIconSet',
|
||||||
|
|
|
@ -62,6 +62,16 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
||||||
'export/(?P<id>[1-9]\d*)/(?P<filename>[^/]*)'
|
'export/(?P<id>[1-9]\d*)/(?P<filename>[^/]*)'
|
||||||
=> 'PhabricatorCalendarEventExportController',
|
=> 'PhabricatorCalendarEventExportController',
|
||||||
),
|
),
|
||||||
|
'export/' => array(
|
||||||
|
$this->getQueryRoutePattern()
|
||||||
|
=> 'PhabricatorCalendarExportListController',
|
||||||
|
$this->getEditRoutePattern('edit/')
|
||||||
|
=> 'PhabricatorCalendarExportEditController',
|
||||||
|
'(?P<id>[1-9]\d*)/'
|
||||||
|
=> 'PhabricatorCalendarExportViewController',
|
||||||
|
'ics/(?P<secretKey>[^/]+)/(?P<filename>[^/]*)'
|
||||||
|
=> 'PhabricatorCalendarExportICSController',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportEditController
|
||||||
|
extends PhabricatorCalendarController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
return id(new PhabricatorCalendarExportEditEngine())
|
||||||
|
->setController($this)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportListController
|
||||||
|
extends PhabricatorCalendarController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
return id(new PhabricatorCalendarExportSearchEngine())
|
||||||
|
->setController($this)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$doc_name = 'Calendar User Guide: Exporting Events';
|
||||||
|
$doc_href = PhabricatorEnv::getDoclink($doc_name);
|
||||||
|
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('Guide: Exporting Events'))
|
||||||
|
->setIcon('fa-book')
|
||||||
|
->setHref($doc_href));
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportEditEngine
|
||||||
|
extends PhabricatorEditEngine {
|
||||||
|
|
||||||
|
const ENGINECONST = 'calendar.export';
|
||||||
|
|
||||||
|
public function getEngineName() {
|
||||||
|
return pht('Calendar Exports');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEngineConfigurable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummaryHeader() {
|
||||||
|
return pht('Configure Calendar Export Forms');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummaryText() {
|
||||||
|
return pht('Configure how users create and edit exports.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEngineApplicationClass() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newEditableObject() {
|
||||||
|
return PhabricatorCalendarExport::initializeNewCalendarExport(
|
||||||
|
$this->getViewer());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newObjectQuery() {
|
||||||
|
return new PhabricatorCalendarExportQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateTitleText($object) {
|
||||||
|
return pht('Create New Export');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectEditTitleText($object) {
|
||||||
|
return pht('Edit Export: %s', $object->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectEditShortText($object) {
|
||||||
|
return $object->getMonogram();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateShortText() {
|
||||||
|
return pht('Create Export');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectName() {
|
||||||
|
return pht('Export');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectViewURI($object) {
|
||||||
|
return $object->getURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getEditorURI() {
|
||||||
|
return $this->getApplication()->getApplicationURI('export/edit/');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildCustomEditFields($object) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$fields = array(
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setDescription(pht('Name of the export.'))
|
||||||
|
->setIsRequired(true)
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorCalendarExportNameTransaction::TRANSACTIONTYPE)
|
||||||
|
->setConduitDescription(pht('Rename the export.'))
|
||||||
|
->setConduitTypeDescription(pht('New export name.'))
|
||||||
|
->setValue($object->getName()),
|
||||||
|
id(new PhabricatorBoolEditField())
|
||||||
|
->setKey('disabled')
|
||||||
|
->setOptions(pht('Active'), pht('Disabled'))
|
||||||
|
->setLabel(pht('Disabled'))
|
||||||
|
->setDescription(pht('Disable the export.'))
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorCalendarExportDisableTransaction::TRANSACTIONTYPE)
|
||||||
|
->setIsConduitOnly(true)
|
||||||
|
->setConduitDescription(pht('Disable or restore the export.'))
|
||||||
|
->setConduitTypeDescription(pht('True to cancel the export.'))
|
||||||
|
->setValue($object->getIsDisabled()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Calendar Exports');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportPHIDType extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'CEXP';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Calendar Export');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new PhabricatorCalendarExport();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDTypeApplicationClass() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new PhabricatorCalendarExportQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$export = $objects[$phid];
|
||||||
|
|
||||||
|
$id = $export->getID();
|
||||||
|
$name = $export->getName();
|
||||||
|
$uri = $export->getURI();
|
||||||
|
|
||||||
|
$handle
|
||||||
|
->setName($name)
|
||||||
|
->setFullName(pht('Calendar Export %s: %s', $id, $name))
|
||||||
|
->setURI($uri);
|
||||||
|
|
||||||
|
if ($export->getIsDisabled()) {
|
||||||
|
$handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $authorPHIDs;
|
||||||
|
private $isDisabled;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withAuthorPHIDs(array $phids) {
|
||||||
|
$this->authorPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withIsDisabled($is_disabled) {
|
||||||
|
$this->isDisabled = $is_disabled;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhabricatorCalendarExport();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
|
if ($this->ids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'export.id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'export.phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->authorPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'export.authorPHID IN (%Ls)',
|
||||||
|
$this->authorPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isDisabled !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'export.isDisabled = %d',
|
||||||
|
(int)$this->isDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPrimaryTableAlias() {
|
||||||
|
return 'export';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportSearchEngine
|
||||||
|
extends PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
|
public function getResultTypeDescription() {
|
||||||
|
return pht('Calendar Exports');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationClassName() {
|
||||||
|
return 'PhabricatorCalendarApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newQuery() {
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
return id(new PhabricatorCalendarExportQuery())
|
||||||
|
->withAuthorPHIDs(array($viewer->getPHID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildCustomSearchFields() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryFromParameters(array $map) {
|
||||||
|
$query = $this->newQuery();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getURI($path) {
|
||||||
|
return '/calendar/export/'.$path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getBuiltinQueryNames() {
|
||||||
|
$names = array(
|
||||||
|
'all' => pht('All Exports'),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSavedQueryFromBuiltin($query_key) {
|
||||||
|
$query = $this->newSavedQuery();
|
||||||
|
$query->setQueryKey($query_key);
|
||||||
|
|
||||||
|
switch ($query_key) {
|
||||||
|
case 'all':
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderResultList(
|
||||||
|
array $exports,
|
||||||
|
PhabricatorSavedQuery $query,
|
||||||
|
array $handles) {
|
||||||
|
|
||||||
|
assert_instances_of($exports, 'PhabricatorCalendarExport');
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$list = new PHUIObjectItemListView();
|
||||||
|
foreach ($exports as $export) {
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setHeader($export->getName())
|
||||||
|
->setHref($export->getURI());
|
||||||
|
|
||||||
|
if ($export->getIsDisabled()) {
|
||||||
|
$item->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = new PhabricatorApplicationSearchResultView();
|
||||||
|
$result->setObjectList($list);
|
||||||
|
$result->setNoDataString(pht('No exports found.'));
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getNewUserBody() {
|
||||||
|
$doc_name = 'Calendar User Guide: Exporting Events';
|
||||||
|
$doc_href = PhabricatorEnv::getDoclink($doc_name);
|
||||||
|
|
||||||
|
$create_button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-book white')
|
||||||
|
->setText($doc_name)
|
||||||
|
->setHref($doc_href)
|
||||||
|
->setColor(PHUIButtonView::GREEN);
|
||||||
|
|
||||||
|
$icon = $this->getApplication()->getIcon();
|
||||||
|
$app_name = $this->getApplication()->getName();
|
||||||
|
$view = id(new PHUIBigInfoView())
|
||||||
|
->setIcon('fa-download')
|
||||||
|
->setTitle(pht('No Exports Configured'))
|
||||||
|
->setDescription(
|
||||||
|
pht(
|
||||||
|
'You have not set up any events for export from Calendar yet. '.
|
||||||
|
'See the documentation for instructions on how to get started.'))
|
||||||
|
->addAction($create_button);
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
144
src/applications/calendar/storage/PhabricatorCalendarExport.php
Normal file
144
src/applications/calendar/storage/PhabricatorCalendarExport.php
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExport extends PhabricatorCalendarDAO
|
||||||
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface,
|
||||||
|
PhabricatorDestructibleInterface {
|
||||||
|
|
||||||
|
protected $name;
|
||||||
|
protected $authorPHID;
|
||||||
|
protected $policyMode;
|
||||||
|
protected $queryKey;
|
||||||
|
protected $secretKey;
|
||||||
|
protected $isDisabled = 0;
|
||||||
|
|
||||||
|
const MODE_PUBLIC = 'public';
|
||||||
|
const MODE_PRIVATE = 'private';
|
||||||
|
|
||||||
|
public static function initializeNewCalendarExport(PhabricatorUser $actor) {
|
||||||
|
return id(new self())
|
||||||
|
->setAuthorPHID($actor->getPHID())
|
||||||
|
->setPolicyMode(self::MODE_PRIVATE)
|
||||||
|
->setIsDisabled(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'name' => 'text',
|
||||||
|
'policyMode' => 'text64',
|
||||||
|
'queryKey' => 'text64',
|
||||||
|
'secretKey' => 'bytes20',
|
||||||
|
'isDisabled' => 'bool',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_author' => array(
|
||||||
|
'columns' => array('authorPHID'),
|
||||||
|
),
|
||||||
|
'key_secret' => array(
|
||||||
|
'columns' => array('secretKey'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDType() {
|
||||||
|
return PhabricatorCalendarExportPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save() {
|
||||||
|
if (!$this->getSecretKey()) {
|
||||||
|
$this->setSecretKey(Filesystem::readRandomCharacters(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
$id = $this->getID();
|
||||||
|
return "/calendar/export/{$id}/";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPolicyModeMap() {
|
||||||
|
return array(
|
||||||
|
self::MODE_PUBLIC => array(
|
||||||
|
'name' => pht('Public'),
|
||||||
|
),
|
||||||
|
self::MODE_PRIVATE => array(
|
||||||
|
'name' => pht('Private'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPolicyModeSpec($const) {
|
||||||
|
return idx(self::getPolicyModeMap(), $const, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPolicyModeName($const) {
|
||||||
|
$map = self::getPolicyModeSpec($const);
|
||||||
|
return idx($map, 'name', $const);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPolicyModes() {
|
||||||
|
return array_keys(self::getPolicyModeMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
return $this->getAuthorPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new PhabricatorCalendarExportEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new PhabricatorCalendarExportTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willRenderTimeline(
|
||||||
|
PhabricatorApplicationTransactionView $timeline,
|
||||||
|
AphrontRequest $request) {
|
||||||
|
|
||||||
|
return $timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function destroyObjectPermanently(
|
||||||
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportTransaction
|
||||||
|
extends PhabricatorModularTransaction {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'calendar';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return PhabricatorCalendarExportPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseTransactionClass() {
|
||||||
|
return 'PhabricatorCalendarExportTransactionType';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportDisableTransaction
|
||||||
|
extends PhabricatorCalendarExportTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'calendar.export.disable';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return (int)$object->getIsDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setIsDisabled((int)$value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
if ($this->getNewValue()) {
|
||||||
|
return pht(
|
||||||
|
'%s disabled this export.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s enabled this export.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportModeTransaction
|
||||||
|
extends PhabricatorCalendarExportTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'calendar.export.mode';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getPolicyMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setPolicyMode($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
$old_value = $this->getOldValue();
|
||||||
|
$new_value = $this->getNewValue();
|
||||||
|
|
||||||
|
$old_name = PhabricatorCalendarExport::getPolicyModeName($old_value);
|
||||||
|
$new_name = PhabricatorCalendarExport::getPolicyModeName($new_value);
|
||||||
|
|
||||||
|
return pht(
|
||||||
|
'%s changed the policy mode for this export from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderValue($old_name),
|
||||||
|
$this->renderValue($new_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$valid = PhabricatorCalendarExport::getPolicyModes();
|
||||||
|
$valid = array_fuse($valid);
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
if (isset($valid[$value])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Mode "%s" is not a valid policy mode. Valid modes are: %s.',
|
||||||
|
$value,
|
||||||
|
implode(', ', $valid)),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportNameTransaction
|
||||||
|
extends PhabricatorCalendarExportTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'calendar.export.name';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setName($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s renamed this export from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
|
||||||
|
$errors[] = $this->newRequiredError(
|
||||||
|
pht('Calendar exports must have a name.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarExportQueryKeyTransaction
|
||||||
|
extends PhabricatorCalendarExportTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'calendar.export.querykey';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getQueryKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setQueryKey($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s changed the query for this export.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
$query = id(new PhabricatorSavedQueryQuery())
|
||||||
|
->withEngineClassNames(array('PhabricatorCalendarEventSearchEngine'))
|
||||||
|
->withQueryKeys(array($value))
|
||||||
|
->executeOne();
|
||||||
|
if ($query) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Query key "%s" does not identify a valid event query.',
|
||||||
|
$value),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isEmptyTextTransaction($object->getQueryKey(), $xactions)) {
|
||||||
|
$errors[] = $this->newRequiredError(
|
||||||
|
pht('Calendar exports must have a query key.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorCalendarExportTransactionType
|
||||||
|
extends PhabricatorModularTransactionType {}
|
|
@ -421,7 +421,7 @@ final class ManiphestTaskSearchEngine
|
||||||
'you need to get done. Tasks assigned to you will appear here.'))
|
'you need to get done. Tasks assigned to you will appear here.'))
|
||||||
->addAction($create_button);
|
->addAction($create_button);
|
||||||
|
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
12
src/docs/user/userguide/calendar_exports.diviner
Normal file
12
src/docs/user/userguide/calendar_exports.diviner
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
@title Calendar User Guide: Exporting Events
|
||||||
|
@group userguide
|
||||||
|
|
||||||
|
Exporting events to other calendars.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
IMPORTANT: Calendar is a prototype application. See
|
||||||
|
@{article:User Guide: Prototype Applications}.
|
||||||
|
|
||||||
|
Coming soon!
|
|
@ -1339,11 +1339,12 @@ abstract class LiskDAO extends Phobject {
|
||||||
* @task hook
|
* @task hook
|
||||||
*/
|
*/
|
||||||
public function generatePHID() {
|
public function generatePHID() {
|
||||||
throw new Exception(
|
$type = $this->getPHIDType();
|
||||||
pht(
|
return PhabricatorPHID::generateNewPHID($type);
|
||||||
'To use %s, you need to overload %s to perform PHID generation.',
|
}
|
||||||
'CONFIG_AUX_PHID',
|
|
||||||
'generatePHID()'));
|
public function getPHIDType() {
|
||||||
|
throw new PhutilMethodNotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue