mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-24 06:20:56 +01:00
Conduit APIs to start and stop tracking time in phrequent
Summary: This adds methods to start and stop tracking any arbitrary PHID in phrequent. Currently, this uses copy-pasted code from PhrequentTrackController. I had to do this because the code to start/stop was not abstracted into a common class. Once the code to start/stop working is extracted into a re-usable class, the conduit API can use this as well. Test Plan: I called the functions with a PHID of a task and ensured that the fields in the phrequent database table was being updated correctly. Reviewers: skyronic, #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: maxhodak, erik.fercak, aran, epriestley, Korvin Maniphest Tasks: T3569, T3970 Differential Revision: https://secure.phabricator.com/D7326
This commit is contained in:
parent
9a679bf374
commit
2101c3b689
9 changed files with 273 additions and 42 deletions
|
@ -225,6 +225,10 @@ phutil_register_library_map(array(
|
||||||
'ConduitAPI_phragment_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_Method.php',
|
'ConduitAPI_phragment_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_Method.php',
|
||||||
'ConduitAPI_phragment_getpatch_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_getpatch_Method.php',
|
'ConduitAPI_phragment_getpatch_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_getpatch_Method.php',
|
||||||
'ConduitAPI_phragment_queryfragments_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_queryfragments_Method.php',
|
'ConduitAPI_phragment_queryfragments_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_queryfragments_Method.php',
|
||||||
|
'ConduitAPI_phrequent_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_Method.php',
|
||||||
|
'ConduitAPI_phrequent_pop_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_pop_Method.php',
|
||||||
|
'ConduitAPI_phrequent_push_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_push_Method.php',
|
||||||
|
'ConduitAPI_phrequent_tracking_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_tracking_Method.php',
|
||||||
'ConduitAPI_phriction_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_Method.php',
|
'ConduitAPI_phriction_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_Method.php',
|
||||||
'ConduitAPI_phriction_edit_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_edit_Method.php',
|
'ConduitAPI_phriction_edit_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_edit_Method.php',
|
||||||
'ConduitAPI_phriction_history_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_history_Method.php',
|
'ConduitAPI_phriction_history_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_history_Method.php',
|
||||||
|
@ -2547,6 +2551,7 @@ phutil_register_library_map(array(
|
||||||
'PhrequentTimeBlockTestCase' => 'applications/phrequent/storage/__tests__/PhrequentTimeBlockTestCase.php',
|
'PhrequentTimeBlockTestCase' => 'applications/phrequent/storage/__tests__/PhrequentTimeBlockTestCase.php',
|
||||||
'PhrequentTrackController' => 'applications/phrequent/controller/PhrequentTrackController.php',
|
'PhrequentTrackController' => 'applications/phrequent/controller/PhrequentTrackController.php',
|
||||||
'PhrequentTrackableInterface' => 'applications/phrequent/interface/PhrequentTrackableInterface.php',
|
'PhrequentTrackableInterface' => 'applications/phrequent/interface/PhrequentTrackableInterface.php',
|
||||||
|
'PhrequentTrackingEditor' => 'applications/phrequent/editor/PhrequentTrackingEditor.php',
|
||||||
'PhrequentUIEventListener' => 'applications/phrequent/event/PhrequentUIEventListener.php',
|
'PhrequentUIEventListener' => 'applications/phrequent/event/PhrequentUIEventListener.php',
|
||||||
'PhrequentUserTime' => 'applications/phrequent/storage/PhrequentUserTime.php',
|
'PhrequentUserTime' => 'applications/phrequent/storage/PhrequentUserTime.php',
|
||||||
'PhrequentUserTimeQuery' => 'applications/phrequent/query/PhrequentUserTimeQuery.php',
|
'PhrequentUserTimeQuery' => 'applications/phrequent/query/PhrequentUserTimeQuery.php',
|
||||||
|
@ -2937,6 +2942,10 @@ phutil_register_library_map(array(
|
||||||
'ConduitAPI_phragment_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_phragment_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_phragment_getpatch_Method' => 'ConduitAPI_phragment_Method',
|
'ConduitAPI_phragment_getpatch_Method' => 'ConduitAPI_phragment_Method',
|
||||||
'ConduitAPI_phragment_queryfragments_Method' => 'ConduitAPI_phragment_Method',
|
'ConduitAPI_phragment_queryfragments_Method' => 'ConduitAPI_phragment_Method',
|
||||||
|
'ConduitAPI_phrequent_Method' => 'ConduitAPIMethod',
|
||||||
|
'ConduitAPI_phrequent_pop_Method' => 'ConduitAPI_phrequent_Method',
|
||||||
|
'ConduitAPI_phrequent_push_Method' => 'ConduitAPI_phrequent_Method',
|
||||||
|
'ConduitAPI_phrequent_tracking_Method' => 'ConduitAPI_phrequent_Method',
|
||||||
'ConduitAPI_phriction_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_phriction_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_phriction_edit_Method' => 'ConduitAPI_phriction_Method',
|
'ConduitAPI_phriction_edit_Method' => 'ConduitAPI_phriction_Method',
|
||||||
'ConduitAPI_phriction_history_Method' => 'ConduitAPI_phriction_Method',
|
'ConduitAPI_phriction_history_Method' => 'ConduitAPI_phriction_Method',
|
||||||
|
@ -5517,6 +5526,7 @@ phutil_register_library_map(array(
|
||||||
'PhrequentTimeBlock' => 'Phobject',
|
'PhrequentTimeBlock' => 'Phobject',
|
||||||
'PhrequentTimeBlockTestCase' => 'PhabricatorTestCase',
|
'PhrequentTimeBlockTestCase' => 'PhabricatorTestCase',
|
||||||
'PhrequentTrackController' => 'PhrequentController',
|
'PhrequentTrackController' => 'PhrequentController',
|
||||||
|
'PhrequentTrackingEditor' => 'PhabricatorEditor',
|
||||||
'PhrequentUIEventListener' => 'PhabricatorEventListener',
|
'PhrequentUIEventListener' => 'PhabricatorEventListener',
|
||||||
'PhrequentUserTime' =>
|
'PhrequentUserTime' =>
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class ConduitAPI_phrequent_Method extends ConduitAPIMethod {
|
||||||
|
|
||||||
|
public function getApplication() {
|
||||||
|
return PhabricatorApplication::getByClass(
|
||||||
|
'PhabricatorApplicationPhrequent');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConduitAPI_phrequent_pop_Method
|
||||||
|
extends ConduitAPI_phrequent_Method {
|
||||||
|
|
||||||
|
public function getMethodDescription() {
|
||||||
|
return pht('Stop tracking time on an object by popping it from the stack.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_UNSTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineParamTypes() {
|
||||||
|
return array(
|
||||||
|
'objectPHID' => 'phid',
|
||||||
|
'stopTime' => 'int',
|
||||||
|
'note' => 'string'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineReturnType() {
|
||||||
|
return 'phid';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineErrorTypes() {
|
||||||
|
return array(
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$user = $request->getUser();
|
||||||
|
$object_phid = $request->getValue('objectPHID');
|
||||||
|
$timestamp = $request->getValue('stopTime');
|
||||||
|
$note = $request->getValue('note');
|
||||||
|
if ($timestamp === null) {
|
||||||
|
$timestamp = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$editor = new PhrequentTrackingEditor();
|
||||||
|
|
||||||
|
if (!$object_phid) {
|
||||||
|
return $editor->stopTrackingTop($user, $timestamp, $note);
|
||||||
|
} else {
|
||||||
|
return $editor->stopTracking($user, $object_phid, $timestamp, $note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConduitAPI_phrequent_push_Method
|
||||||
|
extends ConduitAPI_phrequent_Method {
|
||||||
|
|
||||||
|
public function getMethodDescription() {
|
||||||
|
return pht(
|
||||||
|
'Start tracking time on an object by '.
|
||||||
|
'pushing it on the tracking stack.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_UNSTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineParamTypes() {
|
||||||
|
return array(
|
||||||
|
'objectPHID' => 'required phid',
|
||||||
|
'startTime' => 'int'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineReturnType() {
|
||||||
|
return 'phid';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineErrorTypes() {
|
||||||
|
return array(
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$user = $request->getUser();
|
||||||
|
$object_phid = $request->getValue('objectPHID');
|
||||||
|
$timestamp = $request->getValue('startTime');
|
||||||
|
if ($timestamp === null) {
|
||||||
|
$timestamp = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$editor = new PhrequentTrackingEditor();
|
||||||
|
return $editor->startTracking($user, $object_phid, $timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConduitAPI_phrequent_tracking_Method
|
||||||
|
extends ConduitAPI_phrequent_Method {
|
||||||
|
|
||||||
|
public function getMethodDescription() {
|
||||||
|
return pht(
|
||||||
|
'Returns current objects being tracked in Phrequent.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_UNSTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineParamTypes() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineReturnType() {
|
||||||
|
return 'array';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineErrorTypes() {
|
||||||
|
return array(
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$times = id(new PhrequentUserTimeQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->needPreemptingEvents(true)
|
||||||
|
->withUserPHIDs(array($user->getPHID()))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
$results = id(new PhrequentTimeBlock($times))
|
||||||
|
->getCurrentWorkStack($now);
|
||||||
|
|
||||||
|
return array('data' => $results);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ final class PhrequentTrackController
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
|
$editor = new PhrequentTrackingEditor();
|
||||||
|
|
||||||
$phid = $this->phid;
|
$phid = $this->phid;
|
||||||
$handle = id(new PhabricatorHandleQuery())
|
$handle = id(new PhabricatorHandleQuery())
|
||||||
|
@ -61,9 +62,9 @@ final class PhrequentTrackController
|
||||||
|
|
||||||
if (!$err) {
|
if (!$err) {
|
||||||
if ($this->isStartingTracking()) {
|
if ($this->isStartingTracking()) {
|
||||||
$this->startTracking($user, $this->phid, $timestamp);
|
$editor->startTracking($user, $this->phid, $timestamp);
|
||||||
} else if ($this->isStoppingTracking()) {
|
} else if ($this->isStoppingTracking()) {
|
||||||
$this->stopTracking($user, $this->phid, $timestamp, $note);
|
$editor->stopTracking($user, $this->phid, $timestamp, $note);
|
||||||
}
|
}
|
||||||
return id(new AphrontRedirectResponse());
|
return id(new AphrontRedirectResponse());
|
||||||
}
|
}
|
||||||
|
@ -108,39 +109,4 @@ final class PhrequentTrackController
|
||||||
private function isStoppingTracking() {
|
private function isStoppingTracking() {
|
||||||
return $this->verb === 'stop';
|
return $this->verb === 'stop';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function startTracking($user, $phid, $timestamp) {
|
|
||||||
$usertime = new PhrequentUserTime();
|
|
||||||
$usertime->setDateStarted($timestamp);
|
|
||||||
$usertime->setUserPHID($user->getPHID());
|
|
||||||
$usertime->setObjectPHID($phid);
|
|
||||||
$usertime->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function stopTracking($user, $phid, $timestamp, $note) {
|
|
||||||
if (!PhrequentUserTimeQuery::isUserTrackingObject($user, $phid)) {
|
|
||||||
// Don't do anything, it's not being tracked.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$usertime_dao = new PhrequentUserTime();
|
|
||||||
$conn = $usertime_dao->establishConnection('r');
|
|
||||||
|
|
||||||
queryfx(
|
|
||||||
$conn,
|
|
||||||
'UPDATE %T usertime '.
|
|
||||||
'SET usertime.dateEnded = %d, '.
|
|
||||||
'usertime.note = %s '.
|
|
||||||
'WHERE usertime.userPHID = %s '.
|
|
||||||
'AND usertime.objectPHID = %s '.
|
|
||||||
'AND usertime.dateEnded IS NULL '.
|
|
||||||
'ORDER BY usertime.dateStarted, usertime.id DESC '.
|
|
||||||
'LIMIT 1',
|
|
||||||
$usertime_dao->getTableName(),
|
|
||||||
$timestamp,
|
|
||||||
$note,
|
|
||||||
$user->getPHID(),
|
|
||||||
$phid);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhrequentTrackingEditor extends PhabricatorEditor {
|
||||||
|
|
||||||
|
public function startTracking(PhabricatorUser $user, $phid, $timestamp) {
|
||||||
|
$usertime = new PhrequentUserTime();
|
||||||
|
$usertime->setDateStarted($timestamp);
|
||||||
|
$usertime->setUserPHID($user->getPHID());
|
||||||
|
$usertime->setObjectPHID($phid);
|
||||||
|
$usertime->save();
|
||||||
|
|
||||||
|
return $phid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopTracking(
|
||||||
|
PhabricatorUser $user,
|
||||||
|
$phid,
|
||||||
|
$timestamp,
|
||||||
|
$note) {
|
||||||
|
|
||||||
|
if (!PhrequentUserTimeQuery::isUserTrackingObject($user, $phid)) {
|
||||||
|
// Don't do anything, it's not being tracked.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$usertime_dao = new PhrequentUserTime();
|
||||||
|
$conn = $usertime_dao->establishConnection('r');
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T usertime '.
|
||||||
|
'SET usertime.dateEnded = %d, '.
|
||||||
|
'usertime.note = %s '.
|
||||||
|
'WHERE usertime.userPHID = %s '.
|
||||||
|
'AND usertime.objectPHID = %s '.
|
||||||
|
'AND usertime.dateEnded IS NULL '.
|
||||||
|
'ORDER BY usertime.dateStarted, usertime.id DESC '.
|
||||||
|
'LIMIT 1',
|
||||||
|
$usertime_dao->getTableName(),
|
||||||
|
$timestamp,
|
||||||
|
$note,
|
||||||
|
$user->getPHID(),
|
||||||
|
$phid);
|
||||||
|
|
||||||
|
return $phid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stopTrackingTop(PhabricatorUser $user, $timestamp, $note) {
|
||||||
|
$times = id(new PhrequentUserTimeQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->withUserPHIDs(array($user->getPHID()))
|
||||||
|
->withEnded(PhrequentUserTimeQuery::ENDED_NO)
|
||||||
|
->setOrder(PhrequentUserTimeQuery::ORDER_STARTED_DESC)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if (count($times) === 0) {
|
||||||
|
// Nothing to stop tracking.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current = head($times);
|
||||||
|
|
||||||
|
return $this->stopTracking(
|
||||||
|
$user,
|
||||||
|
$current->getObjectPHID(),
|
||||||
|
$timestamp,
|
||||||
|
$note);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -186,7 +186,7 @@ final class PhrequentSearchEngine
|
||||||
$usertime->getUserPHID() === $viewer->getPHID()) {
|
$usertime->getUserPHID() === $viewer->getPHID()) {
|
||||||
$item->addAction(
|
$item->addAction(
|
||||||
id(new PHUIListItemView())
|
id(new PHUIListItemView())
|
||||||
->setIcon('fa-time-o')
|
->setIcon('fa-stop')
|
||||||
->addSigil('phrequent-stop-tracking')
|
->addSigil('phrequent-stop-tracking')
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setRenderNameAsTooltip(true)
|
->setRenderNameAsTooltip(true)
|
||||||
|
|
|
@ -37,12 +37,12 @@ final class PhrequentTimeBlock extends Phobject {
|
||||||
$timeline = array();
|
$timeline = array();
|
||||||
$timeline[] = array(
|
$timeline[] = array(
|
||||||
'event' => $event,
|
'event' => $event,
|
||||||
'at' => $event->getDateStarted(),
|
'at' => (int)$event->getDateStarted(),
|
||||||
'type' => 'start',
|
'type' => 'start',
|
||||||
);
|
);
|
||||||
$timeline[] = array(
|
$timeline[] = array(
|
||||||
'event' => $event,
|
'event' => $event,
|
||||||
'at' => nonempty($event->getDateEnded(), $now),
|
'at' => (int)nonempty($event->getDateEnded(), $now),
|
||||||
'type' => 'end',
|
'type' => 'end',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -54,12 +54,12 @@ final class PhrequentTimeBlock extends Phobject {
|
||||||
$same_object = ($preempt->getObjectPHID() == $base_phid);
|
$same_object = ($preempt->getObjectPHID() == $base_phid);
|
||||||
$timeline[] = array(
|
$timeline[] = array(
|
||||||
'event' => $preempt,
|
'event' => $preempt,
|
||||||
'at' => $preempt->getDateStarted(),
|
'at' => (int)$preempt->getDateStarted(),
|
||||||
'type' => $same_object ? 'start' : 'push',
|
'type' => $same_object ? 'start' : 'push',
|
||||||
);
|
);
|
||||||
$timeline[] = array(
|
$timeline[] = array(
|
||||||
'event' => $preempt,
|
'event' => $preempt,
|
||||||
'at' => nonempty($preempt->getDateEnded(), $now),
|
'at' => (int)nonempty($preempt->getDateEnded(), $now),
|
||||||
'type' => $same_object ? 'end' : 'pop',
|
'type' => $same_object ? 'end' : 'pop',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,42 @@ final class PhrequentTimeBlock extends Phobject {
|
||||||
return $object_ranges;
|
return $object_ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current list of work.
|
||||||
|
*/
|
||||||
|
public function getCurrentWorkStack($now, $include_inactive = false) {
|
||||||
|
$ranges = $this->getObjectTimeRanges($now);
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($ranges as $phid => $blocks) {
|
||||||
|
$total = 0;
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
$total += $block[1] - $block[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = 'inactive';
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
if ($block[1] === $now) {
|
||||||
|
if ($block[0] === $block[1]) {
|
||||||
|
$type = 'suspended';
|
||||||
|
} else {
|
||||||
|
$type = 'active';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($include_inactive || $type !== 'inactive') {
|
||||||
|
$results[] = array(
|
||||||
|
'phid' => $phid,
|
||||||
|
'time' => $total,
|
||||||
|
'type' => $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge a list of time ranges (pairs of `<start, end>` epochs) so that no
|
* Merge a list of time ranges (pairs of `<start, end>` epochs) so that no
|
||||||
|
|
Loading…
Reference in a new issue