1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-02 19:01:03 +01:00

Generalize Asana-publishable feed story objects

Summary: Ref T2852. Pulls the Differential-specific aspects of the Asana sync out of the worker. Next diff will add a publisher for Audit/Diffusion.

Test Plan: Published events, including state changes. Saw them reflected correctly in Asana.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2852

Differential Revision: https://secure.phabricator.com/D6569
This commit is contained in:
epriestley 2013-07-26 08:56:35 -07:00
parent 63c33eeb5d
commit 8514a3c739
4 changed files with 189 additions and 68 deletions

View file

@ -347,6 +347,7 @@ phutil_register_library_map(array(
'DifferentialDiffTestCase' => 'applications/differential/storage/__tests__/DifferentialDiffTestCase.php',
'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php',
'DifferentialDiffViewPolicyFieldSpecification' => 'applications/differential/field/specification/DifferentialDiffViewPolicyFieldSpecification.php',
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php',
'DifferentialException' => 'applications/differential/exception/DifferentialException.php',
'DifferentialExceptionMail' => 'applications/differential/mail/DifferentialExceptionMail.php',
'DifferentialExportPatchFieldSpecification' => 'applications/differential/field/specification/DifferentialExportPatchFieldSpecification.php',
@ -541,6 +542,7 @@ phutil_register_library_map(array(
'DoorkeeperDAO' => 'applications/doorkeeper/storage/DoorkeeperDAO.php',
'DoorkeeperExternalObject' => 'applications/doorkeeper/storage/DoorkeeperExternalObject.php',
'DoorkeeperExternalObjectQuery' => 'applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php',
'DoorkeeperFeedStoryPublisher' => 'applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php',
'DoorkeeperFeedWorkerAsana' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php',
'DoorkeeperImportEngine' => 'applications/doorkeeper/engine/DoorkeeperImportEngine.php',
'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php',
@ -2335,6 +2337,7 @@ phutil_register_library_map(array(
'DifferentialDiffTestCase' => 'ArcanistPhutilTestCase',
'DifferentialDiffViewController' => 'DifferentialController',
'DifferentialDiffViewPolicyFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
'DifferentialException' => 'Exception',
'DifferentialExceptionMail' => 'DifferentialMail',
'DifferentialExportPatchFieldSpecification' => 'DifferentialFieldSpecification',

View file

@ -0,0 +1,95 @@
<?php
final class DifferentialDoorkeeperRevisionFeedStoryPublisher
extends DoorkeeperFeedStoryPublisher {
public function canPublishStory(PhabricatorFeedStory $story, $object) {
return ($object instanceof DifferentialRevision);
}
public function willPublishStory($object) {
return id(new DifferentialRevisionQuery())
->setViewer($this->getViewer())
->withIDs(array($object->getID()))
->needRelationships(true)
->executeOne();
}
public function getOwnerPHID($object) {
return $object->getAuthorPHID();
}
public function getActiveUserPHIDs($object) {
$status = $object->getStatus();
if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
return $object->getReviewers();
} else {
return array();
}
}
public function getPassiveUserPHIDs($object) {
$status = $object->getStatus();
if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
return array();
} else {
return $object->getReviewers();
}
}
public function getCCUserPHIDs($object) {
return $object->getCCPHIDs();
}
public function getObjectTitle($object) {
$prefix = $this->getTitlePrefix($object);
$lines = new PhutilNumber($object->getLineCount());
$lines = pht('[Request, %d lines]', $lines);
$id = $object->getID();
$title = $object->getTitle();
return "{$prefix} {$lines} D{$id}: {$title}";
}
public function getObjectURI($object) {
return PhabricatorEnv::getProductionURI('/D'.$object->getID());
}
public function getObjectDescription($object) {
return $object->getSummary();
}
public function isObjectClosed($object) {
switch ($object->getStatus()) {
case ArcanistDifferentialRevisionStatus::CLOSED:
case ArcanistDifferentialRevisionStatus::ABANDONED:
return true;
default:
return false;
}
}
public function getResponsibilityTitle($object) {
$prefix = $this->getTitlePrefix($object);
return pht('%s Review Request', $prefix);
}
public function getStoryText($object) {
$story = $this->getFeedStory();
if ($story instanceof PhabricatorFeedStoryDifferential) {
$text = $story->renderForAsanaBridge();
} else {
$text = $story->renderText();
}
return $text;
}
private function getTitlePrefix(DifferentialRevision $revision) {
$prefix_key = 'metamta.differential.subject-prefix';
return PhabricatorEnv::getEnvConfig($prefix_key);
}
}

View file

@ -0,0 +1,49 @@
<?php
abstract class DoorkeeperFeedStoryPublisher {
private $feedStory;
private $viewer;
public function setFeedStory(PhabricatorFeedStory $feed_story) {
$this->feedStory = $feed_story;
return $this;
}
public function getFeedStory() {
return $this->feedStory;
}
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
abstract public function canPublishStory(
PhabricatorFeedStory $story,
$object);
/**
* Hook for publishers to mutate the story object, particularly by loading
* and attaching additional data.
*/
public function willPublishStory($object) {
return $object;
}
abstract public function getOwnerPHID($object);
abstract public function getActiveUserPHIDs($object);
abstract public function getPassiveUserPHIDs($object);
abstract public function getCCUserPHIDs($object);
abstract public function getObjectTitle($object);
abstract public function getObjectURI($object);
abstract public function getObjectDescription($object);
abstract public function isObjectClosed($object);
abstract public function getResponsibilityTitle($object);
abstract public function getStoryText($object);
}

View file

@ -3,6 +3,7 @@
final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
private $provider;
private $publisher;
private $workspaceID;
private $feedStory;
private $storyObject;
@ -43,6 +44,10 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
return PhabricatorUser::getOmnipotentUser();
}
private function getPublisher() {
return $this->publisher;
}
private function getStoryObject() {
if (!$this->storyObject) {
$story = $this->getFeedStory();
@ -57,81 +62,38 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
return $this->storyObject;
}
private function isObjectSupported($object) {
return ($object instanceof DifferentialRevision);
}
private function getRelatedUserPHIDs($object) {
$revision = $object;
$revision->loadRelationships();
$author_phid = $revision->getAuthorPHID();
$reviewer_phids = $revision->getReviewers();
$cc_phids = $revision->getCCPHIDs();
switch ($revision->getStatus()) {
case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
$active_phids = $reviewer_phids;
$passive_phids = array();
break;
default:
$active_phids = array();
$passive_phids = $reviewer_phids;
break;
}
return array(
$author_phid,
$active_phids,
$passive_phids,
$cc_phids);
}
private function getAsanaTaskData($object) {
$revision = $object;
$prefix = $this->getTitlePrefix($object);
$title = $revision->getTitle();
$lines = pht(
'[Request, %d lines]',
new PhutilNumber($object->getLineCount()));
$publisher = $this->getPublisher();
$name = $prefix.' '.$lines.' D'.$revision->getID().': '.$title;
$uri = PhabricatorEnv::getProductionURI('/D'.$revision->getID());
$title = $publisher->getObjectTitle($object);
$uri = $publisher->getObjectURI($object);
$description = $publisher->getObjectDescription($object);
$is_completed = $publisher->isObjectClosed($object);
$notes = array(
$revision->getSummary(),
$description,
$uri,
$this->getSynchronizationWarning(),
);
$notes = implode("\n\n", $notes);
switch ($revision->getStatus()) {
case ArcanistDifferentialRevisionStatus::CLOSED:
case ArcanistDifferentialRevisionStatus::ABANDONED:
$is_completed = true;
break;
default:
$is_completed = false;
break;
}
return array(
'name' => $name,
'name' => $title,
'notes' => $notes,
'completed' => $is_completed,
);
}
private function getAsanaSubtaskData($object) {
$revision = $object;
$prefix = $this->getTitlePrefix($object);
$publisher = $this->getPublisher();
$name = $prefix.' Review Request';
$uri = PhabricatorEnv::getProductionURI('/D'.$revision->getID());
$title = $publisher->getResponsibilityTitle($object);
$uri = $publisher->getObjectURI($object);
$description = $publisher->getObjectDescription($object);
$notes = array(
$revision->getSummary(),
$description,
$uri,
$this->getSynchronizationWarning(),
);
@ -139,7 +101,7 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
$notes = implode("\n\n", $notes);
return array(
'name' => $prefix.' Review Request',
'name' => $title,
'notes' => $notes,
);
}
@ -165,7 +127,25 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
$chronological_key = $story->getChronologicalKey();
if (!$this->isObjectSupported($object)) {
$publishers = id(new PhutilSymbolLoader())
->setAncestorClass('DoorkeeperFeedStoryPublisher')
->loadObjects();
foreach ($publishers as $publisher) {
if ($publisher->canPublishStory($story, $object)) {
$publisher
->setViewer($viewer)
->setFeedStory($story);
$object = $publisher->willPublishStory($object);
$this->storyObject = $object;
$this->publisher = $publisher;
$this->log("Using publisher '%s'.\n", get_class($publisher));
break;
}
}
if (!$this->publisher) {
$this->log("Story is about an unsupported object type.\n");
return;
}
@ -182,8 +162,10 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
// revision.
// - Follow: users who are following the object; generally CCs.
$phids = $this->getRelatedUserPHIDs($object);
list($owner_phid, $active_phids, $passive_phids, $follow_phids) = $phids;
$owner_phid = $publisher->getOwnerPHID($object);
$active_phids = $publisher->getActiveUserPHIDs($object);
$passive_phids = $publisher->getPassiveUserPHIDs($object);
$follow_phids = $publisher->getCCUserPHIDs($object);
$all_phids = array();
$all_phids = array_merge(
@ -499,11 +481,7 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
// because everything else is idempotent, so this is the only effect we
// can't safely run more than once.
if ($story instanceof PhabricatorFeedStoryDifferential) {
$text = $story->renderForAsanaBridge();
} else {
$text = $story->renderText();
}
$text = $publisher->getStoryText($object);
$this->makeAsanaAPICall(
$oauth_token,
@ -642,8 +620,4 @@ final class DoorkeeperFeedWorkerAsana extends FeedPushWorker {
return (5 * 60) * pow(8, $count);
}
public function getTitlePrefix($object) {
return PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix');
}
}