mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-13 02:12:41 +01:00
Build basic infrastructure for an activity feed
Summary: This defines an extremely basic version of an activity feed, like Facebook's news feed. It doesn't do much of interest yet. Test Plan: Published some feed stories: https://secure.phabricator.com/file/view/PHID-FILE-5061aa72105bbdc05b21/ Reviewed By: tuomaspelkonen Reviewers: jungejason, tuomaspelkonen, aran Commenters: codeblock, jungejason CC: aran, epriestley, codeblock, tuomaspelkonen, jungejason Differential Revision: 593
This commit is contained in:
parent
85b34c23f9
commit
ece9d792b2
28 changed files with 761 additions and 0 deletions
21
resources/sql/patches/053.feed.sql
Normal file
21
resources/sql/patches/053.feed.sql
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
CREATE DATABASE phabricator_feed;
|
||||||
|
|
||||||
|
CREATE TABLE phabricator_feed.feed_storydata (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARCHAR(64) BINARY NOT NULL,
|
||||||
|
UNIQUE KEY (phid),
|
||||||
|
chronologicalKey BIGINT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY (chronologicalKey),
|
||||||
|
storyType varchar(64) NOT NULL,
|
||||||
|
storyData LONGBLOB NOT NULL,
|
||||||
|
authorPHID varchar(64) BINARY NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE phabricator_feed.feed_storyreference (
|
||||||
|
objectPHID varchar(64) BINARY NOT NULL,
|
||||||
|
chronologicalKey BIGINT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY (objectPHID, chronologicalKey),
|
||||||
|
KEY (chronologicalKey)
|
||||||
|
);
|
|
@ -103,6 +103,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitAPI_differential_updateunitresults_Method' => 'applications/conduit/method/differential/updateunitresults',
|
'ConduitAPI_differential_updateunitresults_Method' => 'applications/conduit/method/differential/updateunitresults',
|
||||||
'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
|
'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
|
||||||
'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/conduit/method/diffusion/getrecentcommitsbypath',
|
'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/conduit/method/diffusion/getrecentcommitsbypath',
|
||||||
|
'ConduitAPI_feed_publish_Method' => 'applications/conduit/method/feed/publish',
|
||||||
'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
|
'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
|
||||||
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
|
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
|
||||||
'ConduitAPI_maniphest_info_Method' => 'applications/conduit/method/maniphest/info',
|
'ConduitAPI_maniphest_info_Method' => 'applications/conduit/method/maniphest/info',
|
||||||
|
@ -336,6 +337,17 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
|
'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
|
||||||
'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
|
'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
|
||||||
'PhabricatorEnv' => 'infrastructure/env',
|
'PhabricatorEnv' => 'infrastructure/env',
|
||||||
|
'PhabricatorFeedController' => 'applications/feed/controller/base',
|
||||||
|
'PhabricatorFeedDAO' => 'applications/feed/storage/base',
|
||||||
|
'PhabricatorFeedQuery' => 'applications/feed/query',
|
||||||
|
'PhabricatorFeedStory' => 'applications/feed/story/base',
|
||||||
|
'PhabricatorFeedStoryData' => 'applications/feed/storage/story',
|
||||||
|
'PhabricatorFeedStoryPublisher' => 'applications/feed/publisher',
|
||||||
|
'PhabricatorFeedStoryReference' => 'applications/feed/storage/storyreference',
|
||||||
|
'PhabricatorFeedStoryUnknown' => 'applications/feed/story/unknown',
|
||||||
|
'PhabricatorFeedStoryView' => 'applications/feed/view/story',
|
||||||
|
'PhabricatorFeedStreamController' => 'applications/feed/controller/stream',
|
||||||
|
'PhabricatorFeedView' => 'applications/feed/view/base',
|
||||||
'PhabricatorFile' => 'applications/files/storage/file',
|
'PhabricatorFile' => 'applications/files/storage/file',
|
||||||
'PhabricatorFileController' => 'applications/files/controller/base',
|
'PhabricatorFileController' => 'applications/files/controller/base',
|
||||||
'PhabricatorFileDAO' => 'applications/files/storage/base',
|
'PhabricatorFileDAO' => 'applications/files/storage/base',
|
||||||
|
@ -662,6 +674,7 @@ phutil_register_library_map(array(
|
||||||
'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPIMethod',
|
||||||
|
'ConduitAPI_feed_publish_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
|
||||||
'ConduitAPI_maniphest_info_Method' => 'ConduitAPIMethod',
|
'ConduitAPI_maniphest_info_Method' => 'ConduitAPIMethod',
|
||||||
|
@ -831,6 +844,14 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEditPreferencesController' => 'PhabricatorPreferencesController',
|
'PhabricatorEditPreferencesController' => 'PhabricatorPreferencesController',
|
||||||
'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
|
'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
|
||||||
'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
|
'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
|
||||||
|
'PhabricatorFeedController' => 'PhabricatorController',
|
||||||
|
'PhabricatorFeedDAO' => 'PhabricatorLiskDAO',
|
||||||
|
'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO',
|
||||||
|
'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
|
||||||
|
'PhabricatorFeedStoryUnknown' => 'PhabricatorFeedStory',
|
||||||
|
'PhabricatorFeedStoryView' => 'PhabricatorFeedView',
|
||||||
|
'PhabricatorFeedStreamController' => 'PhabricatorFeedController',
|
||||||
|
'PhabricatorFeedView' => 'AphrontView',
|
||||||
'PhabricatorFile' => 'PhabricatorFileDAO',
|
'PhabricatorFile' => 'PhabricatorFileDAO',
|
||||||
'PhabricatorFileController' => 'PhabricatorController',
|
'PhabricatorFileController' => 'PhabricatorController',
|
||||||
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
|
||||||
|
|
|
@ -330,6 +330,10 @@ class AphrontDefaultApplicationConfiguration
|
||||||
'delete/(?P<id>\d+)/$'
|
'delete/(?P<id>\d+)/$'
|
||||||
=> 'PhabricatorCountdownDeleteController'
|
=> 'PhabricatorCountdownDeleteController'
|
||||||
),
|
),
|
||||||
|
|
||||||
|
'/feed/' => array(
|
||||||
|
'$' => 'PhabricatorFeedStreamController',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group conduit
|
||||||
|
*/
|
||||||
|
class ConduitAPI_feed_publish_Method extends ConduitAPIMethod {
|
||||||
|
|
||||||
|
public function getMethodDescription() {
|
||||||
|
return "(UNSTABLE!!!) Publish a story to the feed.";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineParamTypes() {
|
||||||
|
return array(
|
||||||
|
'type' => 'required string',
|
||||||
|
'data' => 'required dict',
|
||||||
|
'time' => 'optional int',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineErrorTypes() {
|
||||||
|
return array(
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defineReturnType() {
|
||||||
|
return 'nonempty phid';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$type = $request->getValue('type');
|
||||||
|
$data = $request->getValue('data');
|
||||||
|
$time = $request->getValue('time');
|
||||||
|
|
||||||
|
$author_phid = $request->getUser()->getPHID();
|
||||||
|
$phids = array($author_phid);
|
||||||
|
|
||||||
|
$publisher = new PhabricatorFeedStoryPublisher();
|
||||||
|
$publisher->setStoryType($type);
|
||||||
|
$publisher->setStoryData($data);
|
||||||
|
$publisher->setStoryTime($time);
|
||||||
|
$publisher->setRelatedPHIDs($phids);
|
||||||
|
$publisher->setStoryAuthorPHID($author_phid);
|
||||||
|
|
||||||
|
$data = $publisher->publish();
|
||||||
|
|
||||||
|
return $data->getPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/applications/conduit/method/feed/publish/__init__.php
Normal file
13
src/applications/conduit/method/feed/publish/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/conduit/method/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/publisher');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('ConduitAPI_feed_publish_Method.php');
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class PhabricatorFeedController extends PhabricatorController {
|
||||||
|
|
||||||
|
public function buildStandardPageResponse($view, array $data) {
|
||||||
|
$page = $this->buildStandardPageView();
|
||||||
|
|
||||||
|
$page->setApplicationName('Feed');
|
||||||
|
$page->setBaseURI('/feed/');
|
||||||
|
$page->setTitle(idx($data, 'title'));
|
||||||
|
$page->setGlyph("\xE2\x88\x9E");
|
||||||
|
$page->appendChild($view);
|
||||||
|
|
||||||
|
$response = new AphrontWebpageResponse();
|
||||||
|
return $response->setContent($page->render());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
src/applications/feed/controller/base/__init__.php
Normal file
15
src/applications/feed/controller/base/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'aphront/response/webpage');
|
||||||
|
phutil_require_module('phabricator', 'applications/base/controller/base');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedController.php');
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class PhabricatorFeedStreamController extends PhabricatorFeedController {
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
|
||||||
|
$query = new PhabricatorFeedQuery();
|
||||||
|
$stories = $query->execute();
|
||||||
|
|
||||||
|
$views = array();
|
||||||
|
foreach ($stories as $story) {
|
||||||
|
$views[] = $story->renderView();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->buildStandardPageResponse(
|
||||||
|
$views,
|
||||||
|
array(
|
||||||
|
'title' => 'Feed',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
13
src/applications/feed/controller/stream/__init__.php
Normal file
13
src/applications/feed/controller/stream/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/controller/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/query');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStreamController.php');
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class PhabricatorFeedStoryPublisher {
|
||||||
|
|
||||||
|
private $relatedPHIDs;
|
||||||
|
private $storyType;
|
||||||
|
private $storyData;
|
||||||
|
private $storyTime;
|
||||||
|
private $storyAuthorPHID;
|
||||||
|
|
||||||
|
public function setRelatedPHIDs(array $phids) {
|
||||||
|
$this->relatedPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStoryType($story_type) {
|
||||||
|
$this->storyType = $story_type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStoryData(array $data) {
|
||||||
|
$this->storyData = $data;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStoryTime($time) {
|
||||||
|
$this->storyTime = $time;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStoryAuthorPHID($phid) {
|
||||||
|
$this->storyAuthorPHID = $phid;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function publish() {
|
||||||
|
if (!$this->relatedPHIDs) {
|
||||||
|
throw new Exception("There are no PHIDs related to this story!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->storyType) {
|
||||||
|
throw new Exception("Call setStoryType() before publishing!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$chrono_key = $this->generateChronologicalKey();
|
||||||
|
|
||||||
|
$story = new PhabricatorFeedStoryData();
|
||||||
|
$story->setStoryType($this->storyType);
|
||||||
|
$story->setStoryData($this->storyData);
|
||||||
|
$story->setAuthorPHID($this->storyAuthorPHID);
|
||||||
|
$story->setChronologicalKey($chrono_key);
|
||||||
|
$story->save();
|
||||||
|
|
||||||
|
$ref = new PhabricatorFeedStoryReference();
|
||||||
|
|
||||||
|
$sql = array();
|
||||||
|
$conn = $ref->establishConnection('w');
|
||||||
|
foreach ($this->relatedPHIDs as $phid) {
|
||||||
|
$sql[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'(%s, %s)',
|
||||||
|
$phid,
|
||||||
|
$chrono_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'INSERT INTO %T (objectPHID, chronologicalKey) VALUES %Q',
|
||||||
|
$ref->getTableName(),
|
||||||
|
implode(', ', $sql));
|
||||||
|
|
||||||
|
return $story;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We generate a unique chronological key for each story type because we want
|
||||||
|
* to be able to page through the stream with a cursor (i.e., select stories
|
||||||
|
* after ID = X) so we can efficiently perform filtering after selecting data,
|
||||||
|
* and multiple stories with the same ID make this cumbersome without putting
|
||||||
|
* a bunch of logic in the client. We could use the primary key, but that
|
||||||
|
* would prevent publishing stories which happened in the past. Since it's
|
||||||
|
* potentially useful to do that (e.g., if you're importing another data
|
||||||
|
* source) build a unique key for each story which has chronological ordering.
|
||||||
|
*
|
||||||
|
* @return string A unique, time-ordered key which identifies the story.
|
||||||
|
*/
|
||||||
|
private function generateChronologicalKey() {
|
||||||
|
// Use the epoch timestamp for the upper 32 bits of the key. Default to
|
||||||
|
// the current time if the story doesn't have an explicit timestamp.
|
||||||
|
$time = nonempty($this->storyTime, time());
|
||||||
|
|
||||||
|
// Generate a random number for the lower 32 bits of the key.
|
||||||
|
$rand = head(unpack('L', Filesystem::readRandomBytes(4)));
|
||||||
|
|
||||||
|
return ($time << 32) + ($rand);
|
||||||
|
}
|
||||||
|
}
|
18
src/applications/feed/publisher/__init__.php
Normal file
18
src/applications/feed/publisher/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/storage/story');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/storage/storyreference');
|
||||||
|
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||||
|
phutil_require_module('phabricator', 'storage/queryfx');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'filesystem');
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStoryPublisher.php');
|
95
src/applications/feed/query/PhabricatorFeedQuery.php
Normal file
95
src/applications/feed/query/PhabricatorFeedQuery.php
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class PhabricatorFeedQuery {
|
||||||
|
|
||||||
|
private $filterPHIDs;
|
||||||
|
private $limit = 100;
|
||||||
|
private $after;
|
||||||
|
|
||||||
|
public function setFilterPHIDs(array $phids) {
|
||||||
|
$this->filterPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLimit($limit) {
|
||||||
|
$this->limit = $limit;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAfter($after) {
|
||||||
|
$this->after = $after;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute() {
|
||||||
|
|
||||||
|
$ref_table = new PhabricatorFeedStoryReference();
|
||||||
|
$story_table = new PhabricatorFeedStoryData();
|
||||||
|
|
||||||
|
$conn = $story_table->establishConnection('r');
|
||||||
|
|
||||||
|
$where = array();
|
||||||
|
if ($this->filterPHIDs) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'ref.objectPHID IN (%Ls)',
|
||||||
|
$this->filterPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($where) {
|
||||||
|
$where = 'WHERE ('.implode(') AND (', $where).')';
|
||||||
|
} else {
|
||||||
|
$where = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = queryfx_all(
|
||||||
|
$conn,
|
||||||
|
'SELECT story.* FROM %T ref
|
||||||
|
JOIN %T story ON ref.chronologicalKey = story.chronologicalKey
|
||||||
|
%Q
|
||||||
|
GROUP BY story.chronologicalKey
|
||||||
|
ORDER BY story.chronologicalKey DESC
|
||||||
|
LIMIT %d',
|
||||||
|
$ref_table->getTableName(),
|
||||||
|
$story_table->getTableName(),
|
||||||
|
$where,
|
||||||
|
$this->limit);
|
||||||
|
$data = $story_table->loadAllFromArray($data);
|
||||||
|
|
||||||
|
$stories = array();
|
||||||
|
foreach ($data as $story_data) {
|
||||||
|
$class = $story_data->getStoryType();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!class_exists($class) ||
|
||||||
|
!is_subclass_of($class, 'PhabricatorFeedStory')) {
|
||||||
|
$class = 'PhabricatorFeedStoryUnknown';
|
||||||
|
}
|
||||||
|
} catch (PhutilMissingSymbolException $ex) {
|
||||||
|
// If the class can't be loaded, libphutil will throw an exception.
|
||||||
|
// Render the story using the unknown story view.
|
||||||
|
$class = 'PhabricatorFeedStoryUnknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
$stories[] = newv($class, array($story_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stories;
|
||||||
|
}
|
||||||
|
}
|
17
src/applications/feed/query/__init__.php
Normal file
17
src/applications/feed/query/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/storage/story');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/storage/storyreference');
|
||||||
|
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||||
|
phutil_require_module('phabricator', 'storage/queryfx');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedQuery.php');
|
25
src/applications/feed/storage/base/PhabricatorFeedDAO.php
Normal file
25
src/applications/feed/storage/base/PhabricatorFeedDAO.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorFeedDAO extends PhabricatorLiskDAO {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'feed';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/applications/feed/storage/base/__init__.php
Normal file
12
src/applications/feed/storage/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/base/storage/lisk');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedDAO.php');
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorFeedStoryData extends PhabricatorFeedDAO {
|
||||||
|
|
||||||
|
protected $phid;
|
||||||
|
|
||||||
|
protected $storyType;
|
||||||
|
protected $storyData;
|
||||||
|
protected $authorPHID;
|
||||||
|
protected $chronologicalKey;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'storyData' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(
|
||||||
|
PhabricatorPHIDConstants::PHID_TYPE_STRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
src/applications/feed/storage/story/__init__.php
Normal file
14
src/applications/feed/storage/story/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/storage/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||||
|
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStoryData.php');
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorFeedStoryReference extends PhabricatorFeedDAO {
|
||||||
|
|
||||||
|
protected $objectPHID;
|
||||||
|
protected $chronologicalKey;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_IDS => self::IDS_MANUAL,
|
||||||
|
self::CONFIG_TIMESTAMPS => false,
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/applications/feed/storage/storyreference/__init__.php
Normal file
12
src/applications/feed/storage/storyreference/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/storage/base');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStoryReference.php');
|
29
src/applications/feed/story/base/PhabricatorFeedStory.php
Normal file
29
src/applications/feed/story/base/PhabricatorFeedStory.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class PhabricatorFeedStory {
|
||||||
|
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
final public function __construct(PhabricatorFeedStoryData $data) {
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function renderView();
|
||||||
|
|
||||||
|
}
|
10
src/applications/feed/story/base/__init__.php
Normal file
10
src/applications/feed/story/base/__init__.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStory.php');
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorFeedStoryUnknown extends PhabricatorFeedStory {
|
||||||
|
|
||||||
|
public function renderView() {
|
||||||
|
return new PhabricatorFeedStoryView();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/applications/feed/story/unknown/__init__.php
Normal file
13
src/applications/feed/story/unknown/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/story/base');
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/view/story');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStoryUnknown.php');
|
21
src/applications/feed/view/base/PhabricatorFeedView.php
Normal file
21
src/applications/feed/view/base/PhabricatorFeedView.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class PhabricatorFeedView extends AphrontView {
|
||||||
|
|
||||||
|
}
|
12
src/applications/feed/view/base/__init__.php
Normal file
12
src/applications/feed/view/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'view/base');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedView.php');
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PhabricatorFeedStoryView extends PhabricatorFeedView {
|
||||||
|
|
||||||
|
public function render() {
|
||||||
|
return phutil_render_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'style' => 'border: 1px dashed black; '.
|
||||||
|
'padding: 1em; margin: 1em; '.
|
||||||
|
'background: #ffeedd;',
|
||||||
|
),
|
||||||
|
'This is a feed story!');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
src/applications/feed/view/story/__init__.php
Normal file
14
src/applications/feed/view/story/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is automatically generated. Lint this module to rebuild it.
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_module('phabricator', 'applications/feed/view/base');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'markup');
|
||||||
|
|
||||||
|
|
||||||
|
phutil_require_source('PhabricatorFeedStoryView.php');
|
|
@ -30,6 +30,7 @@ final class PhabricatorPHIDConstants {
|
||||||
const PHID_TYPE_CMIT = 'CMIT';
|
const PHID_TYPE_CMIT = 'CMIT';
|
||||||
const PHID_TYPE_OPKG = 'OPKG';
|
const PHID_TYPE_OPKG = 'OPKG';
|
||||||
const PHID_TYPE_PSTE = 'PSTE';
|
const PHID_TYPE_PSTE = 'PSTE';
|
||||||
|
const PHID_TYPE_STRY = 'STRY';
|
||||||
|
|
||||||
public static function getTypes() {
|
public static function getTypes() {
|
||||||
return array(
|
return array(
|
||||||
|
@ -44,6 +45,8 @@ final class PhabricatorPHIDConstants {
|
||||||
self::PHID_TYPE_REPO,
|
self::PHID_TYPE_REPO,
|
||||||
self::PHID_TYPE_CMIT,
|
self::PHID_TYPE_CMIT,
|
||||||
self::PHID_TYPE_PSTE,
|
self::PHID_TYPE_PSTE,
|
||||||
|
self::PHID_TYPE_OPKG,
|
||||||
|
self::PHID_TYPE_STRY,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue