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

Add import log messages to Calendar imports

Summary: Ref T10747. When stuff goes wrong (or right) let the user know what happened.

Test Plan: {F1870139}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10747

Differential Revision: https://secure.phabricator.com/D16704
This commit is contained in:
epriestley 2016-10-13 10:45:15 -07:00
parent c71bb0550c
commit 3d98558593
16 changed files with 643 additions and 8 deletions

View file

@ -0,0 +1,8 @@
CREATE TABLE {$NAMESPACE}_calendar.calendar_importlog (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
importPHID VARBINARY(64) NOT NULL,
parameters LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
KEY `key_import` (`importPHID`)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -2104,21 +2104,31 @@ phutil_register_library_map(array(
'PhabricatorCalendarICSWriter' => 'applications/calendar/util/PhabricatorCalendarICSWriter.php', 'PhabricatorCalendarICSWriter' => 'applications/calendar/util/PhabricatorCalendarICSWriter.php',
'PhabricatorCalendarIconSet' => 'applications/calendar/icon/PhabricatorCalendarIconSet.php', 'PhabricatorCalendarIconSet' => 'applications/calendar/icon/PhabricatorCalendarIconSet.php',
'PhabricatorCalendarImport' => 'applications/calendar/storage/PhabricatorCalendarImport.php', 'PhabricatorCalendarImport' => 'applications/calendar/storage/PhabricatorCalendarImport.php',
'PhabricatorCalendarImportDefaultLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportDefaultLogType.php',
'PhabricatorCalendarImportDisableController' => 'applications/calendar/controller/PhabricatorCalendarImportDisableController.php', 'PhabricatorCalendarImportDisableController' => 'applications/calendar/controller/PhabricatorCalendarImportDisableController.php',
'PhabricatorCalendarImportDisableTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php', 'PhabricatorCalendarImportDisableTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php',
'PhabricatorCalendarImportDuplicateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportDuplicateLogType.php',
'PhabricatorCalendarImportEditController' => 'applications/calendar/controller/PhabricatorCalendarImportEditController.php', 'PhabricatorCalendarImportEditController' => 'applications/calendar/controller/PhabricatorCalendarImportEditController.php',
'PhabricatorCalendarImportEditEngine' => 'applications/calendar/editor/PhabricatorCalendarImportEditEngine.php', 'PhabricatorCalendarImportEditEngine' => 'applications/calendar/editor/PhabricatorCalendarImportEditEngine.php',
'PhabricatorCalendarImportEditor' => 'applications/calendar/editor/PhabricatorCalendarImportEditor.php', 'PhabricatorCalendarImportEditor' => 'applications/calendar/editor/PhabricatorCalendarImportEditor.php',
'PhabricatorCalendarImportEmptyLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportEmptyLogType.php',
'PhabricatorCalendarImportEngine' => 'applications/calendar/import/PhabricatorCalendarImportEngine.php', 'PhabricatorCalendarImportEngine' => 'applications/calendar/import/PhabricatorCalendarImportEngine.php',
'PhabricatorCalendarImportICSFileTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php', 'PhabricatorCalendarImportICSFileTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportICSFileTransaction.php',
'PhabricatorCalendarImportIgnoredNodeLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportIgnoredNodeLogType.php',
'PhabricatorCalendarImportListController' => 'applications/calendar/controller/PhabricatorCalendarImportListController.php', 'PhabricatorCalendarImportListController' => 'applications/calendar/controller/PhabricatorCalendarImportListController.php',
'PhabricatorCalendarImportLog' => 'applications/calendar/storage/PhabricatorCalendarImportLog.php',
'PhabricatorCalendarImportLogQuery' => 'applications/calendar/query/PhabricatorCalendarImportLogQuery.php',
'PhabricatorCalendarImportLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportLogType.php',
'PhabricatorCalendarImportNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportNameTransaction.php', 'PhabricatorCalendarImportNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportNameTransaction.php',
'PhabricatorCalendarImportOriginalLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportOriginalLogType.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',
'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',
'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',
'PhabricatorCalendarReplyHandler' => 'applications/calendar/mail/PhabricatorCalendarReplyHandler.php', 'PhabricatorCalendarReplyHandler' => 'applications/calendar/mail/PhabricatorCalendarReplyHandler.php',
@ -6921,21 +6931,35 @@ phutil_register_library_map(array(
'PhabricatorApplicationTransactionInterface', 'PhabricatorApplicationTransactionInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
), ),
'PhabricatorCalendarImportDefaultLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportDisableController' => 'PhabricatorCalendarController', 'PhabricatorCalendarImportDisableController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportDisableTransaction' => 'PhabricatorCalendarImportTransactionType', 'PhabricatorCalendarImportDisableTransaction' => 'PhabricatorCalendarImportTransactionType',
'PhabricatorCalendarImportDuplicateLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarImportEditController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportEditEngine' => 'PhabricatorEditEngine', 'PhabricatorCalendarImportEditEngine' => 'PhabricatorEditEngine',
'PhabricatorCalendarImportEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarImportEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorCalendarImportEmptyLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportEngine' => 'Phobject', 'PhabricatorCalendarImportEngine' => 'Phobject',
'PhabricatorCalendarImportICSFileTransaction' => 'PhabricatorCalendarImportTransactionType', 'PhabricatorCalendarImportICSFileTransaction' => 'PhabricatorCalendarImportTransactionType',
'PhabricatorCalendarImportIgnoredNodeLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportListController' => 'PhabricatorCalendarController', 'PhabricatorCalendarImportListController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportLog' => array(
'PhabricatorCalendarDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'PhabricatorCalendarImportLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarImportLogType' => 'Phobject',
'PhabricatorCalendarImportNameTransaction' => 'PhabricatorCalendarImportTransactionType', 'PhabricatorCalendarImportNameTransaction' => 'PhabricatorCalendarImportTransactionType',
'PhabricatorCalendarImportOriginalLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportOrphanLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarImportPHIDType' => 'PhabricatorPHIDType',
'PhabricatorCalendarImportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarImportQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarImportSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCalendarImportSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorCalendarImportTransaction' => 'PhabricatorModularTransaction', 'PhabricatorCalendarImportTransaction' => 'PhabricatorModularTransaction',
'PhabricatorCalendarImportTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorCalendarImportTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorCalendarImportTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorCalendarImportTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorCalendarImportUpdateLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportViewController' => 'PhabricatorCalendarController', 'PhabricatorCalendarImportViewController' => 'PhabricatorCalendarController',
'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorCalendarReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorCalendarReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',

View file

@ -30,12 +30,14 @@ final class PhabricatorCalendarImportViewController
$curtain = $this->buildCurtain($import); $curtain = $this->buildCurtain($import);
$details = $this->buildPropertySection($import); $details = $this->buildPropertySection($import);
$log_messages = $this->buildLogMessages($import);
$imported_events = $this->buildImportedEvents($import); $imported_events = $this->buildImportedEvents($import);
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())
->setHeader($header) ->setHeader($header)
->setMainColumn( ->setMainColumn(
array( array(
$log_messages,
$imported_events, $imported_events,
$timeline, $timeline,
)) ))
@ -134,8 +136,70 @@ final class PhabricatorCalendarImportViewController
return $properties; return $properties;
} }
private function buildImportedEvents( private function buildLogMessages(PhabricatorCalendarImport $import) {
PhabricatorCalendarImport $import) { $viewer = $this->getViewer();
$logs = id(new PhabricatorCalendarImportLogQuery())
->setViewer($viewer)
->withImportPHIDs(array($import->getPHID()))
->setLimit(25)
->execute();
$rows = array();
foreach ($logs as $log) {
$icon = $log->getDisplayIcon($viewer);
$color = $log->getDisplayColor($viewer);
$name = $log->getDisplayType($viewer);
$description = $log->getDisplayDescription($viewer);
$rows[] = array(
$log->getID(),
id(new PHUIIconView())->setIcon($icon, $color),
$name,
$description,
phabricator_datetime($log->getDateCreated(), $viewer),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('ID'),
null,
pht('Type'),
pht('Mesage'),
pht('Date'),
))
->setColumnClasses(
array(
null,
null,
'pri',
'wide',
null,
));
$all_uri = $this->getApplicationURI('import/log/');
$all_uri = (string)id(new PhutilURI($all_uri))
->setQueryParam('importSourcePHID', $import->getPHID());
$all_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('View All'))
->setIcon('fa-search')
->setHref($all_uri);
$header = id(new PHUIHeaderView())
->setHeader(pht('Log Messages'))
->addActionLink($all_button);
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
}
private function buildImportedEvents(PhabricatorCalendarImport $import) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$engine = id(new PhabricatorCalendarEventSearchEngine()) $engine = id(new PhabricatorCalendarEventSearchEngine())

View file

@ -49,8 +49,13 @@ abstract class PhabricatorCalendarImportEngine
$nodes = array(); $nodes = array();
foreach ($root->getChildren() as $document) { foreach ($root->getChildren() as $document) {
foreach ($document->getChildren() as $node) { foreach ($document->getChildren() as $node) {
if ($node->getNodeType() != $event_type) { $node_type = $node->getNodeType();
// TODO: Warn that we ignored this. if ($node_type != $event_type) {
$import->newLogMessage(
PhabricatorCalendarImportIgnoredNodeLogType::LOGTYPE,
array(
'node.type' => $node_type,
));
continue; continue;
} }
@ -59,16 +64,62 @@ abstract class PhabricatorCalendarImportEngine
} }
$node_map = array(); $node_map = array();
$parent_uids = array();
foreach ($nodes as $node) { foreach ($nodes as $node) {
$full_uid = $this->getFullNodeUID($node); $full_uid = $this->getFullNodeUID($node);
if (isset($node_map[$full_uid])) { if (isset($node_map[$full_uid])) {
// TODO: Warn that we got a duplicate. $import->newLogMessage(
PhabricatorCalendarImportDuplicateLogType::LOGTYPE,
array(
'uid.full' => $full_uid,
));
continue; continue;
} }
$node_map[$full_uid] = $node; $node_map[$full_uid] = $node;
} }
// If we already know about some of these events and they were created
// here, we're not going to import it again. This can happen if a user
// exports an event and then tries to import it again. This is probably
// not what they meant to do and this pathway generally leads to madness.
$likely_phids = array();
foreach ($node_map as $full_uid => $node) {
$uid = $node->getUID();
$matches = null;
if (preg_match('/^(PHID-.*)@(.*)\z/', $uid, $matches)) {
$likely_phids[$full_uid] = $matches[1];
}
}
if ($likely_phids) {
// NOTE: We're using the omnipotent viewer here because we don't want
// to collide with events that already exist, even if you can't see
// them.
$events = id(new PhabricatorCalendarEventQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($likely_phids)
->execute();
$events = mpull($events, null, 'getPHID');
foreach ($node_map as $full_uid => $node) {
$phid = idx($likely_phids, $full_uid);
if (!$phid) {
continue;
}
$event = idx($events, $phid);
if (!$event) {
continue;
}
$import->newLogMessage(
PhabricatorCalendarImportOriginalLogType::LOGTYPE,
array(
'phid' => $event->getPHID(),
));
unset($node_map[$full_uid]);
}
}
if ($node_map) { if ($node_map) {
$events = id(new PhabricatorCalendarEventQuery()) $events = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer) ->setViewer($viewer)
@ -114,7 +165,12 @@ abstract class PhabricatorCalendarImportEngine
// does not exist or we're going to delete it anyway. We just drop // does not exist or we're going to delete it anyway. We just drop
// this node. // this node.
// TODO: Warn that we got rid of an event with no parent. $import->newLogMessage(
PhabricatorCalendarImportOrphanLogType::LOGTYPE,
array(
'uid.full' => $full_uid,
'uid.parent' => $parent_uid,
));
continue; continue;
} }
@ -130,6 +186,10 @@ abstract class PhabricatorCalendarImportEngine
$content_source = PhabricatorContentSource::newForSource( $content_source = PhabricatorContentSource::newForSource(
PhabricatorWebContentSource::SOURCECONST); PhabricatorWebContentSource::SOURCECONST);
// NOTE: We're using the omnipotent user here because imported events are
// otherwise immutable.
$edit_actor = PhabricatorUser::getOmnipotentUser();
$update_map = array_select_keys($update_map, $insert_order); $update_map = array_select_keys($update_map, $insert_order);
foreach ($update_map as $full_uid => $event) { foreach ($update_map as $full_uid => $event) {
$parent_uid = $this->getParentNodeUID($node_map[$full_uid]); $parent_uid = $this->getParentNodeUID($node_map[$full_uid]);
@ -144,13 +204,28 @@ abstract class PhabricatorCalendarImportEngine
$event_xactions = $xactions[$full_uid]; $event_xactions = $xactions[$full_uid];
$editor = id(new PhabricatorCalendarEventEditor()) $editor = id(new PhabricatorCalendarEventEditor())
->setActor($viewer) ->setActor($edit_actor)
->setActingAsPHID($import->getPHID()) ->setActingAsPHID($import->getPHID())
->setContentSource($content_source) ->setContentSource($content_source)
->setContinueOnNoEffect(true) ->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true); ->setContinueOnMissingFields(true);
$is_new = !$event->getID();
$editor->applyTransactions($event, $event_xactions); $editor->applyTransactions($event, $event_xactions);
$import->newLogMessage(
PhabricatorCalendarImportUpdateLogType::LOGTYPE,
array(
'new' => $is_new,
'phid' => $event->getPHID(),
));
}
if (!$update_map) {
$import->newLogMessage(
PhabricatorCalendarImportEmptyLogType::LOGTYPE,
array());
} }
// TODO: When the source is a subscription-based ICS file or some other // TODO: When the source is a subscription-based ICS file or some other

View file

@ -0,0 +1,20 @@
<?php
final class PhabricatorCalendarImportDefaultLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'default';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$type = $log->getParameter('type');
if (strlen($type)) {
return pht('Unknown Message "%s"', $type);
} else {
return pht('Unknown Message');
}
}
}

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorCalendarImportDuplicateLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'duplicate';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return pht('Duplicate Event');
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$duplicate_uid = $log->getParameter('uid.full');
return pht(
'Ignored duplicate event "%s" present in source.',
$duplicate_uid);
}
}

View file

@ -0,0 +1,32 @@
<?php
final class PhabricatorCalendarImportEmptyLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'empty';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return pht('No Events Imported');
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return pht('Found no valid events to import.');
}
public function getDisplayIcon(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return 'fa-ban';
}
public function getDisplayColor(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return 'red';
}
}

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorCalendarImportIgnoredNodeLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'nodetype';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return pht('Ignored Node');
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$node_type = $log->getParameter('node.type');
return pht(
'Ignored unsupported "%s" node present in source.',
$node_type);
}
}

View file

@ -0,0 +1,39 @@
<?php
abstract class PhabricatorCalendarImportLogType
extends Phobject {
final public function getLogTypeConstant() {
return $this->getPhobjectClassConstant('LOGTYPE', 64);
}
final public static function getAllLogTypes() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getLogTypeConstant')
->execute();
}
abstract public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log);
public function getDisplayIcon(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return 'fa-warning';
}
public function getDisplayColor(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return 'yellow';
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return null;
}
}

View file

@ -0,0 +1,26 @@
<?php
final class PhabricatorCalendarImportOriginalLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'original';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return pht('Original Event');
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$phid = $log->getParameter('phid');
return pht(
'Ignored an event (%s) because the original version of this event '.
'was created here.',
$viewer->renderHandle($phid));
}
}

View file

@ -0,0 +1,25 @@
<?php
final class PhabricatorCalendarImportOrphanLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'orphan';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return pht('Orphan');
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$child_uid = $log->getParameter('uid.full');
$parent_uid = $log->getParameter('uid.parent');
return pht(
'Found orphaned child event ("%s") without a parent event ("%s").',
$child_uid,
$parent_uid);
}
}

View file

@ -0,0 +1,38 @@
<?php
final class PhabricatorCalendarImportUpdateLogType
extends PhabricatorCalendarImportLogType {
const LOGTYPE = 'update';
public function getDisplayType(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$is_new = $log->getParameter('new');
if ($is_new) {
return pht('Imported Event');
} else {
return pht('Updated Event');
}
}
public function getDisplayDescription(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
$event_phid = $log->getParameter('phid');
return $viewer->renderHandle($event_phid);
}
public function getDisplayIcon(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return 'fa-upload';
}
public function getDisplayColor(
PhabricatorUser $viewer,
PhabricatorCalendarImportLog $log) {
return 'green';
}
}

View file

@ -0,0 +1,111 @@
<?php
final class PhabricatorCalendarImportLogQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $importPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withImportPHIDs(array $phids) {
$this->importPHIDs = $phids;
return $this;
}
public function newResultObject() {
return new PhabricatorCalendarImportLog();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'log.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'log.phid IN (%Ls)',
$this->phids);
}
if ($this->importPHIDs !== null) {
$where[] = qsprintf(
$conn,
'log.importPHID IN (%Ls)',
$this->importPHIDs);
}
return $where;
}
protected function willFilterPage(array $page) {
$viewer = $this->getViewer();
$type_map = PhabricatorCalendarImportLogType::getAllLogTypes();
foreach ($page as $log) {
$type_constant = $log->getParameter('type');
$type_object = idx($type_map, $type_constant);
if (!$type_object) {
$type_object = new PhabricatorCalendarImportDefaultLogType();
}
$type_object = clone $type_object;
$log->attachLogType($type_object);
}
$import_phids = mpull($page, 'getImportPHID');
if ($import_phids) {
$imports = id(new PhabricatorCalendarImportQuery())
->setViewer($viewer)
->withPHIDs($import_phids)
->execute();
$imports = mpull($imports, null, 'getPHID');
} else {
$imports = array();
}
foreach ($page as $key => $log) {
$import = idx($imports, $log->getImportPHID());
if (!$import) {
$this->didRejectResult($import);
unset($page[$key]);
continue;
}
$log->attachImport($import);
}
return $page;
}
protected function getPrimaryTableAlias() {
return 'log';
}
public function getQueryApplicationClass() {
return 'PhabricatorCalendarApplication';
}
}

View file

@ -907,6 +907,10 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
return $set; return $set;
} }
public function isImportedEvent() {
return (bool)$this->getImportSourcePHID();
}
public function getImportSource() { public function getImportSource() {
return $this->assertAttached($this->importSource); return $this->assertAttached($this->importSource);
} }

View file

@ -133,6 +133,17 @@ final class PhabricatorCalendarImport
return $timeline; return $timeline;
} }
public function newLogMessage($type, array $parameters) {
$parameters = array(
'type' => $type,
) + $parameters;
return id(new PhabricatorCalendarImportLog())
->setImportPHID($this->getPHID())
->setParameters($parameters)
->save();
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */ /* -( PhabricatorDestructibleInterface )----------------------------------- */
@ -144,12 +155,21 @@ final class PhabricatorCalendarImport
$this->openTransaction(); $this->openTransaction();
$events = id(new PhabricatorCalendarEventQuery()) $events = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer)
->withImportSourcePHIDs(array($this->getPHID())) ->withImportSourcePHIDs(array($this->getPHID()))
->execute(); ->execute();
foreach ($events as $event) { foreach ($events as $event) {
$engine->destroyObject($event); $engine->destroyObject($event);
} }
$logs = id(new PhabricatorCalendarImportLogQuery())
->setViewer($viewer)
->withImportPHIDs(array($this->getPHID()))
->execute();
foreach ($logs as $log) {
$engine->destroyObject($log);
}
$this->delete(); $this->delete();
$this->saveTransaction(); $this->saveTransaction();
} }

View file

@ -0,0 +1,103 @@
<?php
final class PhabricatorCalendarImportLog
extends PhabricatorCalendarDAO
implements
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface {
protected $importPHID;
protected $parameters = array();
private $import = self::ATTACHABLE;
private $logType = self::ATTACHABLE;
protected function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
'parameters' => self::SERIALIZATION_JSON,
),
self::CONFIG_KEY_SCHEMA => array(
'key_import' => array(
'columns' => array('importPHID'),
),
),
) + parent::getConfiguration();
}
public function getParameter($key, $default = null) {
return idx($this->parameters, $key, $default);
}
public function setParameter($key, $value) {
$this->parameters[$key] = $value;
return $this;
}
public function getImport() {
return $this->assertAttached($this->import);
}
public function attachImport(PhabricatorCalendarImport $import) {
$this->import = $import;
return $this;
}
public function getDisplayIcon(PhabricatorUser $viewer) {
return $this->getLogType()->getDisplayIcon($viewer, $this);
}
public function getDisplayColor(PhabricatorUser $viewer) {
return $this->getLogType()->getDisplayColor($viewer, $this);
}
public function getDisplayType(PhabricatorUser $viewer) {
return $this->getLogType()->getDisplayType($viewer, $this);
}
public function getDisplayDescription(PhabricatorUser $viewer) {
return $this->getLogType()->getDisplayDescription($viewer, $this);
}
public function getLogType() {
return $this->assertAttached($this->logType);
}
public function attachLogType(PhabricatorCalendarImportLogType $type) {
$this->logType = $type;
return $this;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
);
}
public function getPolicy($capability) {
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$viewer = $engine->getViewer();
$this->delete();
}
}