From e091b037f3410121f88ab49fb164adaf69453ac0 Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Tue, 4 Aug 2015 18:44:22 +0930 Subject: [PATCH] Radically simplify user activity system The activity system we were using was built around a separate table. Whenever the user posted something, or deleted a post, we would sync the table. The advantage of this was that we could aggregate activity of all different types very efficiently. It turns out that it came with a huge disadvantage: there was no efficient way to enforce permissions on activity. If a user posted something in a private tag, everyone could still see it on their activity feed. My stopgap solution was to only sync activity for posts that are viewable by guests, but that was way too limited. It also turns out that aggregating activity of different types is really not that useful, especially considering most of it is the user making posts. So I've gotten rid of that whole overly-complicated system, and just made the user profile display separate lists of posts and discussions, retrieved from those respective APIs. The discussions page is an actual discussion list too, which is pretty cool. It's still technically possible to aggregate different activity types (basically just aggregate API responses together), but we can do that later if there's a need for it. This is probably my favourite commit of the day :) --- js/forum/src/components/Activity.js | 13 +- js/forum/src/components/JoinedActivity.js | 11 -- js/forum/src/components/PostedActivity.js | 16 ++- .../src/components/UserDiscussionsPage.js | 26 ++++ js/forum/src/components/UserPage.js | 16 +-- .../{ActivityPage.js => UserPostsPage.js} | 40 +++--- js/forum/src/initializers/components.js | 4 - js/forum/src/initializers/routes.js | 10 +- js/lib/models/Activity.js | 11 -- less/forum/ActivityPage.less | 4 +- src/Api/Actions/Activity/IndexAction.php | 94 ------------- src/Api/Actions/Posts/GetsPosts.php | 2 +- src/Api/Actions/Posts/IndexAction.php | 5 +- src/Core/Activity/Activity.php | 117 ---------------- src/Core/Activity/ActivityRepository.php | 42 ------ src/Core/Activity/ActivityServiceProvider.php | 58 -------- src/Core/Activity/ActivitySyncer.php | 117 ---------------- src/Core/Activity/Blueprint.php | 37 ----- src/Core/Activity/JoinedBlueprint.php | 59 -------- .../Activity/Listeners/UserActivitySyncer.php | 129 ------------------ src/Core/Activity/PostedBlueprint.php | 59 -------- .../Activity/StartedDiscussionBlueprint.php | 16 --- src/Core/CoreServiceProvider.php | 1 - src/Core/Posts/PostRepository.php | 15 +- 24 files changed, 98 insertions(+), 804 deletions(-) delete mode 100644 js/forum/src/components/JoinedActivity.js create mode 100644 js/forum/src/components/UserDiscussionsPage.js rename js/forum/src/components/{ActivityPage.js => UserPostsPage.js} (71%) delete mode 100644 js/lib/models/Activity.js delete mode 100644 src/Api/Actions/Activity/IndexAction.php delete mode 100644 src/Core/Activity/Activity.php delete mode 100644 src/Core/Activity/ActivityRepository.php delete mode 100644 src/Core/Activity/ActivityServiceProvider.php delete mode 100644 src/Core/Activity/ActivitySyncer.php delete mode 100644 src/Core/Activity/Blueprint.php delete mode 100644 src/Core/Activity/JoinedBlueprint.php delete mode 100755 src/Core/Activity/Listeners/UserActivitySyncer.php delete mode 100644 src/Core/Activity/PostedBlueprint.php delete mode 100644 src/Core/Activity/StartedDiscussionBlueprint.php diff --git a/js/forum/src/components/Activity.js b/js/forum/src/components/Activity.js index 2c397586c..ea5821bdb 100644 --- a/js/forum/src/components/Activity.js +++ b/js/forum/src/components/Activity.js @@ -22,7 +22,7 @@ export default class Activity extends Component {
{this.description()} - {humanTime(activity.time())} + {humanTime(this.time())}
{this.content()} @@ -34,9 +34,18 @@ export default class Activity extends Component { * Get the user whose avatar should be displayed. * * @return {User} + * @abstract */ user() { - return this.props.activity.user(); + } + + /** + * Get the time of the activity. + * + * @return {Date} + * @abstract + */ + time() { } /** diff --git a/js/forum/src/components/JoinedActivity.js b/js/forum/src/components/JoinedActivity.js deleted file mode 100644 index 1b4df8917..000000000 --- a/js/forum/src/components/JoinedActivity.js +++ /dev/null @@ -1,11 +0,0 @@ -import Activity from 'flarum/components/Activity'; - -/** - * The `JoinedActivity` component displays an activity feed item for when a user - * joined the forum. - */ -export default class JoinedActivity extends Activity { - description() { - return app.trans('core.joined_the_forum'); - } -} diff --git a/js/forum/src/components/PostedActivity.js b/js/forum/src/components/PostedActivity.js index 8f3aff34f..69891a1d2 100644 --- a/js/forum/src/components/PostedActivity.js +++ b/js/forum/src/components/PostedActivity.js @@ -12,14 +12,20 @@ import { truncate } from 'flarum/utils/string'; * - All of the props for Activity */ export default class PostedActivity extends Activity { - description() { - const post = this.props.activity.subject(); + user() { + return this.props.post.user(); + } - return app.trans(post.number() === 1 ? 'core.started_a_discussion' : 'core.posted_a_reply'); + time() { + return this.props.post.time(); + } + + description() { + return app.trans(this.props.post.number() === 1 ? 'core.started_a_discussion' : 'core.posted_a_reply'); } content() { - const post = this.props.activity.subject(); + const post = this.props.post; return ( {this.props.activity.subject().discussion().title()}); + items.add('title',

{this.props.post.discussion().title()}

); return items; } diff --git a/js/forum/src/components/UserDiscussionsPage.js b/js/forum/src/components/UserDiscussionsPage.js new file mode 100644 index 000000000..c739615fa --- /dev/null +++ b/js/forum/src/components/UserDiscussionsPage.js @@ -0,0 +1,26 @@ +import UserPage from 'flarum/components/UserPage'; +import DiscussionList from 'flarum/components/DiscussionList'; + +/** + * The `UserDiscussionsPage` component shows a user's activity feed inside of their + * profile. + */ +export default class UserDiscussionsPage extends UserPage { + constructor(...args) { + super(...args); + + this.loadUser(m.route.param('username')); + } + + content() { + return ( +
+ {DiscussionList.component({ + params: { + q: 'author:' + this.user.username() + } + })} +
+ ); + } +} diff --git a/js/forum/src/components/UserPage.js b/js/forum/src/components/UserPage.js index 0554c03fa..0172db42a 100644 --- a/js/forum/src/components/UserPage.js +++ b/js/forum/src/components/UserPage.js @@ -134,11 +134,11 @@ export default class UserPage extends Component { const items = new ItemList(); const user = this.user; - items.add('activity', + items.add('posts', LinkButton.component({ - href: app.route('user.activity', {username: user.username()}), - children: app.trans('core.activity'), - icon: 'user' + href: app.route('user.posts', {username: user.username()}), + children: [app.trans('core.posts'), {user.commentsCount()}], + icon: 'comment-o' }) ); @@ -150,14 +150,6 @@ export default class UserPage extends Component { }) ); - items.add('posts', - LinkButton.component({ - href: app.route('user.posts', {username: user.username()}), - children: [app.trans('core.posts'), {user.commentsCount()}], - icon: 'comment-o' - }) - ); - if (app.session.user === user) { items.add('separator', Separator.component()); items.add('settings', diff --git a/js/forum/src/components/ActivityPage.js b/js/forum/src/components/UserPostsPage.js similarity index 71% rename from js/forum/src/components/ActivityPage.js rename to js/forum/src/components/UserPostsPage.js index 5b2948f37..4209ddfe3 100644 --- a/js/forum/src/components/ActivityPage.js +++ b/js/forum/src/components/UserPostsPage.js @@ -1,12 +1,13 @@ import UserPage from 'flarum/components/UserPage'; import LoadingIndicator from 'flarum/components/LoadingIndicator'; import Button from 'flarum/components/Button'; +import PostedActivity from 'flarum/components/PostedActivity'; /** - * The `ActivityPage` component shows a user's activity feed inside of their + * The `UserPostsPage` component shows a user's activity feed inside of their * profile. */ -export default class ActivityPage extends UserPage { +export default class UserPostsPage extends UserPage { constructor(...args) { super(...args); @@ -25,10 +26,11 @@ export default class ActivityPage extends UserPage { this.moreResults = false; /** - * The Activity models in the feed. - * @type {Activity[]} + * The Post models in the feed. + * + * @type {Post[]} */ - this.activity = []; + this.posts = []; /** * The number of activity items to load per request. @@ -47,7 +49,7 @@ export default class ActivityPage extends UserPage { footer = LoadingIndicator.component(); } else if (this.moreResults) { footer = ( -
+
{Button.component({ children: app.trans('core.load_more'), className: 'Button', @@ -58,11 +60,10 @@ export default class ActivityPage extends UserPage { } return ( -
-
    - {this.activity.map(activity => { - const ActivityComponent = app.activityComponents[activity.contentType()]; - return ActivityComponent ?
  • {ActivityComponent.component({activity})}
  • : ''; +
    +
      + {this.posts.map(post => { + return
    • {PostedActivity.component({post})}
    • ; })}
    {footer} @@ -87,7 +88,7 @@ export default class ActivityPage extends UserPage { */ refresh() { this.loading = true; - this.activity = []; + this.posts = []; // Redraw, but only if we're not in the middle of a route change. m.startComputation(); @@ -104,12 +105,13 @@ export default class ActivityPage extends UserPage { * @protected */ loadResults(offset) { - return app.store.find('activity', { + return app.store.find('posts', { filter: { user: this.user.id(), - type: this.props.filter + type: 'comment' }, - page: {offset, limit: this.loadLimit} + page: {offset, limit: this.loadLimit}, + sort: '-time' }); } @@ -120,19 +122,19 @@ export default class ActivityPage extends UserPage { */ loadMore() { this.loading = true; - this.loadResults(this.activity.length).then(this.parseResults.bind(this)); + this.loadResults(this.posts.length).then(this.parseResults.bind(this)); } /** * Parse results and append them to the activity feed. * - * @param {Activity[]} results - * @return {Activity[]} + * @param {Post[]} results + * @return {Post[]} */ parseResults(results) { this.loading = false; - [].push.apply(this.activity, results); + [].push.apply(this.posts, results); this.moreResults = results.length >= this.loadLimit; m.redraw(); diff --git a/js/forum/src/initializers/components.js b/js/forum/src/initializers/components.js index 896de17dd..d027768df 100644 --- a/js/forum/src/initializers/components.js +++ b/js/forum/src/initializers/components.js @@ -14,9 +14,5 @@ export default function components(app) { app.postComponents.comment = CommentPost; app.postComponents.discussionRenamed = DiscussionRenamedPost; - app.activityComponents.posted = PostedActivity; - app.activityComponents.startedDiscussion = PostedActivity; - app.activityComponents.joined = JoinedActivity; - app.notificationComponents.discussionRenamed = DiscussionRenamedNotification; } diff --git a/js/forum/src/initializers/routes.js b/js/forum/src/initializers/routes.js index 0c5b87e36..517289702 100644 --- a/js/forum/src/initializers/routes.js +++ b/js/forum/src/initializers/routes.js @@ -1,6 +1,7 @@ import IndexPage from 'flarum/components/IndexPage'; import DiscussionPage from 'flarum/components/DiscussionPage'; -import ActivityPage from 'flarum/components/ActivityPage'; +import UserPostsPage from 'flarum/components/UserPostsPage'; +import UserDiscussionsPage from 'flarum/components/UserDiscussionsPage'; import SettingsPage from 'flarum/components/SettingsPage'; import NotificationsPage from 'flarum/components/NotificationsPage'; @@ -18,10 +19,9 @@ export default function(app) { 'discussion': {path: '/d/:id/:slug', component: DiscussionPage.component()}, 'discussion.near': {path: '/d/:id/:slug/:near', component: DiscussionPage.component()}, - 'user': {path: '/u/:username', component: ActivityPage.component()}, - 'user.activity': {path: '/u/:username', component: ActivityPage.component()}, - 'user.discussions': {path: '/u/:username/discussions', component: ActivityPage.component({filter: 'startedDiscussion'})}, - 'user.posts': {path: '/u/:username/posts', component: ActivityPage.component({filter: 'posted'})}, + 'user': {path: '/u/:username', component: UserPostsPage.component()}, + 'user.posts': {path: '/u/:username', component: UserPostsPage.component()}, + 'user.discussions': {path: '/u/:username/discussions', component: UserDiscussionsPage.component()}, 'settings': {path: '/settings', component: SettingsPage.component()}, 'notifications': {path: '/notifications', component: NotificationsPage.component()} diff --git a/js/lib/models/Activity.js b/js/lib/models/Activity.js deleted file mode 100644 index 865fe3715..000000000 --- a/js/lib/models/Activity.js +++ /dev/null @@ -1,11 +0,0 @@ -import Model from 'flarum/Model'; -import mixin from 'flarum/utils/mixin'; - -export default class Activity extends mixin(Model, { - contentType: Model.attribute('contentType'), - content: Model.attribute('content'), - time: Model.attribute('time', Model.transformDate), - - user: Model.hasOne('user'), - subject: Model.hasOne('subject') -}) {} diff --git a/less/forum/ActivityPage.less b/less/forum/ActivityPage.less index 535ba4cc2..a36ca63a9 100644 --- a/less/forum/ActivityPage.less +++ b/less/forum/ActivityPage.less @@ -1,11 +1,11 @@ -.ActivityPage-loadMore { +.UserPostsPage-loadMore { text-align: center; .LoadingIndicator { height: 46px; } } -.ActivityPage-list { +.ActivityList { border-left: 3px solid @control-bg; list-style: none; margin: 0 0 0 16px; diff --git a/src/Api/Actions/Activity/IndexAction.php b/src/Api/Actions/Activity/IndexAction.php deleted file mode 100644 index bae677d43..000000000 --- a/src/Api/Actions/Activity/IndexAction.php +++ /dev/null @@ -1,94 +0,0 @@ - true, - 'subject.user' => true, - 'subject.discussion' => true - ]; - - /** - * @inheritdoc - */ - public $link = ['user']; - - /** - * @inheritdoc - */ - public $limitMax = 50; - - /** - * @inheritdoc - */ - public $limit = 20; - - /** - * @inheritdoc - */ - public $sortFields = []; - - /** - * @inheritdoc - */ - public $sort; - - /** - * @param UserRepository $users - * @param ActivityRepository $activity - */ - public function __construct(UserRepository $users, ActivityRepository $activity) - { - $this->users = $users; - $this->activity = $activity; - } - - /** - * Get the activity results, ready to be serialized and assigned to the - * document response. - * - * @param JsonApiRequest $request - * @param Document $document - * @return \Illuminate\Database\Eloquent\Collection - */ - protected function data(JsonApiRequest $request, Document $document) - { - $userId = $request->get('filter.user'); - $actor = $request->actor; - - $user = $this->users->findOrFail($userId, $actor); - - return $this->activity->findByUser( - $user->id, - $actor, - $request->limit, - $request->offset, - $request->get('filter.type') - ) - ->load($request->include); - } -} diff --git a/src/Api/Actions/Posts/GetsPosts.php b/src/Api/Actions/Posts/GetsPosts.php index 5fb52022c..ae503eaa7 100644 --- a/src/Api/Actions/Posts/GetsPosts.php +++ b/src/Api/Actions/Posts/GetsPosts.php @@ -22,7 +22,7 @@ trait GetsPosts $offset = $this->posts->getIndexForNumber($where['discussion_id'], $near, $actor); $offset = max(0, $offset - $request->limit / 2); } else { - $offset = 0; + $offset = $request->offset; } return $this->posts->findWhere( diff --git a/src/Api/Actions/Posts/IndexAction.php b/src/Api/Actions/Posts/IndexAction.php index dcae21373..7221f3c13 100644 --- a/src/Api/Actions/Posts/IndexAction.php +++ b/src/Api/Actions/Posts/IndexAction.php @@ -43,7 +43,7 @@ class IndexAction extends SerializeCollectionAction /** * @inheritdoc */ - public $sortFields = []; + public $sortFields = ['time']; /** * @inheritdoc @@ -84,6 +84,9 @@ class IndexAction extends SerializeCollectionAction if ($userId = $request->get('filter.user')) { $where['user_id'] = $userId; } + if ($type = $request->get('filter.type')) { + $where['type'] = $type; + } $posts = $this->getPosts($request, $where); } diff --git a/src/Core/Activity/Activity.php b/src/Core/Activity/Activity.php deleted file mode 100644 index 16b5de481..000000000 --- a/src/Core/Activity/Activity.php +++ /dev/null @@ -1,117 +0,0 @@ -attributes['data'] = json_encode($value); - } - - /** - * Get the subject model for this activity record by looking up its type in - * our subject model map. - * - * @return string|null - */ - public function getSubjectModelAttribute() - { - return array_get(static::$subjectModels, $this->type); - } - - /** - * Define the relationship with the activity's recipient. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function user() - { - return $this->belongsTo('Flarum\Core\Users\User', 'user_id'); - } - - /** - * Define the relationship with the activity's subject. - * - * @return \Illuminate\Database\Eloquent\Relations\MorphTo - */ - public function subject() - { - return $this->morphTo('subject', 'subjectModel', 'subject_id'); - } - - /** - * Get the type-to-subject-model map. - * - * @return array - */ - public static function getSubjectModels() - { - return static::$subjectModels; - } - - /** - * Set the subject model for the given activity type. - * - * @param string $type The activity type. - * @param string $subjectModel The class name of the subject model for that - * type. - * @return void - */ - public static function setSubjectModel($type, $subjectModel) - { - static::$subjectModels[$type] = $subjectModel; - } -} diff --git a/src/Core/Activity/ActivityRepository.php b/src/Core/Activity/ActivityRepository.php deleted file mode 100644 index d74135d83..000000000 --- a/src/Core/Activity/ActivityRepository.php +++ /dev/null @@ -1,42 +0,0 @@ -whereIn('type', $this->getRegisteredTypes()) - ->latest('time') - ->skip($offset) - ->take($limit); - - if ($type !== null) { - $query->where('type', $type); - } - - return $query->get(); - } - - /** - * Get a list of activity types that have been registered with the activity - * model. - * - * @return array - */ - protected function getRegisteredTypes() - { - return array_keys(Activity::getSubjectModels()); - } -} diff --git a/src/Core/Activity/ActivityServiceProvider.php b/src/Core/Activity/ActivityServiceProvider.php deleted file mode 100644 index c689ebbff..000000000 --- a/src/Core/Activity/ActivityServiceProvider.php +++ /dev/null @@ -1,58 +0,0 @@ -registerActivityTypes(); - - $events = $this->app->make('events'); - $events->subscribe('Flarum\Core\Activity\Listeners\UserActivitySyncer'); - } - - /** - * Register activity types. - * - * @return void - */ - public function registerActivityTypes() - { - $blueprints = [ - 'Flarum\Core\Activity\PostedBlueprint', - 'Flarum\Core\Activity\StartedDiscussionBlueprint', - 'Flarum\Core\Activity\JoinedBlueprint' - ]; - - event(new RegisterActivityTypes($blueprints)); - - foreach ($blueprints as $blueprint) { - Activity::setSubjectModel( - $blueprint::getType(), - $blueprint::getSubjectModel() - ); - } - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $this->app->bind( - 'Flarum\Core\Activity\ActivityRepositoryInterface', - 'Flarum\Core\Activity\EloquentActivityRepository' - ); - } -} diff --git a/src/Core/Activity/ActivitySyncer.php b/src/Core/Activity/ActivitySyncer.php deleted file mode 100644 index 57eacf98e..000000000 --- a/src/Core/Activity/ActivitySyncer.php +++ /dev/null @@ -1,117 +0,0 @@ -activity = $activity; - } - - /** - * Sync a piece of activity so that it is present for the specified users, - * and not present for anyone else. - * - * @param Blueprint $blueprint - * @param \Flarum\Core\Models\User[] $users - * @return void - */ - public function sync(Blueprint $blueprint, array $users) - { - $attributes = $this->getAttributes($blueprint); - - // Find all existing activity records in the database matching this - // blueprint. We will begin by assuming that they all need to be - // deleted in order to match the provided list of users. - $toDelete = Activity::where($attributes)->get(); - $toInsert = []; - - // For each of the provided users, check to see if they already have - // an activity record in the database. If they do, we can leave it be; - // otherwise, we will need to create a new one for them. - foreach ($users as $user) { - $existing = $toDelete->first(function ($activity) use ($user) { - return $activity->user_id === $user->id; - }); - - if ($existing) { - $toDelete->forget($toDelete->search($existing)); - } else { - $toInsert[] = $attributes + ['user_id' => $user->id]; - } - } - - // Finally, delete all of the remaining activity records which weren't - // removed from this collection by the above loop. Insert the records - // we need to insert as well. - if (count($toDelete)) { - $this->deleteActivity($toDelete->lists('id')); - } - - if (count($toInsert)) { - $this->createActivity($toInsert); - } - } - - /** - * Delete a piece of activity for all users. - * - * @param Blueprint $blueprint - * @return void - */ - public function delete(Blueprint $blueprint) - { - Activity::where($this->getAttributes($blueprint))->delete(); - } - - /** - * Delete a list of activity records. - * - * @param int[] $ids - */ - protected function deleteActivity(array $ids) - { - Activity::whereIn('id', $ids)->delete(); - } - - /** - * Insert a list of activity record into the database. - * - * @param array[] $records An array containing arrays of activity record - * attributes to insert. - */ - protected function createActivity(array $records) - { - Activity::insert($records); - } - - /** - * Construct an array of attributes to be stored in an activity record in - * the database, given an activity blueprint. - * - * @param Blueprint $blueprint - * @return array - */ - protected function getAttributes(Blueprint $blueprint) - { - return [ - 'type' => $blueprint::getType(), - 'subject_id' => $blueprint->getSubject()->id, - 'time' => $blueprint->getTime() - ]; - } -} diff --git a/src/Core/Activity/Blueprint.php b/src/Core/Activity/Blueprint.php deleted file mode 100644 index 1a30fdbb5..000000000 --- a/src/Core/Activity/Blueprint.php +++ /dev/null @@ -1,37 +0,0 @@ -user = $user; - } - - /** - * {@inheritdoc} - */ - public function getSubject() - { - return $this->user; - } - - /** - * {@inheritdoc} - */ - public function getTime() - { - return $this->user->join_time; - } - - /** - * {@inheritdoc} - */ - public static function getType() - { - return 'joined'; - } - - /** - * {@inheritdoc} - */ - public static function getSubjectModel() - { - return 'Flarum\Core\Users\User'; - } -} diff --git a/src/Core/Activity/Listeners/UserActivitySyncer.php b/src/Core/Activity/Listeners/UserActivitySyncer.php deleted file mode 100755 index 707a785f0..000000000 --- a/src/Core/Activity/Listeners/UserActivitySyncer.php +++ /dev/null @@ -1,129 +0,0 @@ -activity = $activity; - } - - /** - * @param \Illuminate\Contracts\Events\Dispatcher $events - * @return void - */ - public function subscribe(Dispatcher $events) - { - $events->listen('Flarum\Events\PostWasPosted', [$this, 'whenPostWasPosted']); - $events->listen('Flarum\Events\PostWasHidden', [$this, 'whenPostWasHidden']); - $events->listen('Flarum\Events\PostWasRestored', [$this, 'whenPostWasRestored']); - $events->listen('Flarum\Events\PostWasDeleted', [$this, 'whenPostWasDeleted']); - $events->listen('Flarum\Events\UserWasRegistered', [$this, 'whenUserWasRegistered']); - } - - /** - * @param \Flarum\Events\PostWasPosted $event - * @return void - */ - public function whenPostWasPosted(PostWasPosted $event) - { - $this->postBecameVisible($event->post); - } - - /** - * @param \Flarum\Events\PostWasHidden $event - * @return void - */ - public function whenPostWasHidden(PostWasHidden $event) - { - $this->postBecameInvisible($event->post); - } - - /** - * @param \Flarum\Events\PostWasRestored $event - * @return void - */ - public function whenPostWasRestored(PostWasRestored $event) - { - $this->postBecameVisible($event->post); - } - - /** - * @param \Flarum\Events\PostWasDeleted $event - * @return void - */ - public function whenPostWasDeleted(PostWasDeleted $event) - { - $this->postBecameInvisible($event->post); - } - - /** - * @param \Flarum\Events\UserWasRegistered $event - * @return void - */ - public function whenUserWasRegistered(UserWasRegistered $event) - { - $blueprint = new JoinedBlueprint($event->user); - - $this->activity->sync($blueprint, [$event->user]); - } - - /** - * Sync activity to a post's author when a post becomes visible. - * - * @param \Flarum\Core\Posts\Post $post - * @return void - */ - protected function postBecameVisible(Post $post) - { - if ($post->isVisibleTo(new Guest)) { - $blueprint = $this->postedBlueprint($post); - - $this->activity->sync($blueprint, [$post->user]); - } - } - - /** - * Delete activity when a post becomes invisible. - * - * @param \Flarum\Core\Posts\Post $post - * @return void - */ - protected function postBecameInvisible(Post $post) - { - $blueprint = $this->postedBlueprint($post); - - $this->activity->delete($blueprint); - } - - /** - * Create the appropriate activity blueprint for a post. - * - * @param \Flarum\Core\Posts\Post $post - * @return \Flarum\Core\Activity\Blueprint - */ - protected function postedBlueprint(Post $post) - { - return $post->number == 1 ? new StartedDiscussionBlueprint($post) : new PostedBlueprint($post); - } -} diff --git a/src/Core/Activity/PostedBlueprint.php b/src/Core/Activity/PostedBlueprint.php deleted file mode 100644 index 6ba2a3874..000000000 --- a/src/Core/Activity/PostedBlueprint.php +++ /dev/null @@ -1,59 +0,0 @@ -post = $post; - } - - /** - * {@inheritdoc} - */ - public function getSubject() - { - return $this->post; - } - - /** - * {@inheritdoc} - */ - public function getTime() - { - return $this->post->time; - } - - /** - * {@inheritdoc} - */ - public static function getType() - { - return 'posted'; - } - - /** - * {@inheritdoc} - */ - public static function getSubjectModel() - { - return 'Flarum\Core\Posts\Post'; - } -} diff --git a/src/Core/Activity/StartedDiscussionBlueprint.php b/src/Core/Activity/StartedDiscussionBlueprint.php deleted file mode 100644 index 08b549021..000000000 --- a/src/Core/Activity/StartedDiscussionBlueprint.php +++ /dev/null @@ -1,16 +0,0 @@ -app->register('Flarum\Core\Activity\ActivityServiceProvider'); $this->app->register('Flarum\Core\Discussions\DiscussionsServiceProvider'); $this->app->register('Flarum\Core\Formatter\FormatterServiceProvider'); $this->app->register('Flarum\Core\Groups\GroupsServiceProvider'); diff --git a/src/Core/Posts/PostRepository.php b/src/Core/Posts/PostRepository.php index 9e48e5495..cba923fbb 100644 --- a/src/Core/Posts/PostRepository.php +++ b/src/Core/Posts/PostRepository.php @@ -85,9 +85,20 @@ class PostRepository */ public function findByIds(array $ids, User $actor = null) { - $ids = $this->filterDiscussionVisibleTo($ids, $actor); + $visibleIds = $this->filterDiscussionVisibleTo($ids, $actor); - $posts = Post::with('discussion')->whereIn('id', (array) $ids)->get(); + $posts = Post::with('discussion')->whereIn('id', $visibleIds)->get(); + + $posts->sort(function ($a, $b) use ($ids) { + $aPos = array_search($a->id, $ids); + $bPos = array_search($b->id, $ids); + + if ($aPos === $bPos) { + return 0; + } + + return $aPos < $bPos ? -1 : 1; + }); return $this->filterVisibleTo($posts, $actor); }