protected function stickyChanged(Discussion $discussion, User $user, $isSticky) { $post = DiscussionStickiedPost::reply($discussion->id, $user->id, $isSticky); $post = $discussion->mergePost($post); if ($discussion->start_user_id !== $user->id) { $notification = new DiscussionStickiedBlueprint($post); $this->notifications->sync($notification, $post->exists ? [$discussion->startUser] : []); } }
/** * Bootstrap the application events. * * @return void */ public function boot() { Discussion::setValidator($this->app->make('validator')); $events = $this->app->make('events'); $settings = $this->app->make('Flarum\\Core\\Settings\\SettingsRepository'); $events->subscribe('Flarum\\Core\\Discussions\\Listeners\\DiscussionMetadataUpdater'); $events->listen(ModelAllow::class, function (ModelAllow $event) use($settings) { if ($event->model instanceof Discussion) { if ($event->actor->hasPermission('discussion.' . $event->action)) { return true; } if (($event->action === 'rename' || $event->action === 'delete') && $event->model->start_user_id == $event->actor->id) { $allowRenaming = $settings->get('allow_renaming'); if ($allowRenaming === '-1' || $allowRenaming === 'reply' && $event->model->participants_count <= 1 || $event->model->start_time->diffInMinutes(Carbon::now()) < $allowRenaming) { return true; } } } }); $events->listen(ScopeModelVisibility::class, function (ScopeModelVisibility $event) { if ($event->model instanceof Discussion) { $user = $event->actor; if (!$user->hasPermission('discussion.hide')) { $event->query->where(function ($query) use($user) { $query->whereNull('discussions.hide_time')->where('comments_count', '>', 0)->orWhere('start_user_id', $user->id); event(new ScopeHiddenDiscussionVisibility($query, $user, 'discussion.hide')); }); } } }); }
/** * @param StartDiscussion $command * @return mixed */ public function handle(StartDiscussion $command) { $actor = $command->actor; $data = $command->data; $this->forum->assertCan($actor, 'startDiscussion'); // Create a new Discussion entity, persist it, and dispatch domain // events. Before persistance, though, fire an event to give plugins // an opportunity to alter the discussion entity based on data in the // command they may have passed through in the controller. $discussion = Discussion::start(array_get($data, 'attributes.title'), $actor); event(new DiscussionWillBeSaved($discussion, $actor, $data)); $discussion->save(); // Now that the discussion has been created, we can add the first post. // We will do this by running the PostReply command. try { $post = $this->bus->dispatch(new PostReply($discussion->id, $actor, $data)); } catch (Exception $e) { $discussion->delete(); throw $e; } // Before we dispatch events, refresh our discussion instance's // attributes as posting the reply will have changed some of them (e.g. // last_time.) $discussion->setRawAttributes($post->discussion->getAttributes(), true); $discussion->setStartPost($post); $this->dispatchEventsFor($discussion); $discussion->save(); return $discussion; }
/** * {@inheritdoc} */ protected function getDefaultAttributes($discussion) { $attributes = parent::getDefaultAttributes($discussion) + ['commentsCount' => (int) $discussion->comments_count, 'participantsCount' => (int) $discussion->participants_count, 'startTime' => $discussion->start_time->toRFC3339String(), 'lastTime' => $discussion->last_time ? $discussion->last_time->toRFC3339String() : null, 'lastPostNumber' => $discussion->last_post_number, 'canReply' => $discussion->can($this->actor, 'reply'), 'canRename' => $discussion->can($this->actor, 'rename'), 'canDelete' => $discussion->can($this->actor, 'delete')]; Discussion::setStateUser($this->actor); if ($state = $discussion->state) { $attributes += ['readTime' => $state->read_time ? $state->read_time->toRFC3339String() : null, 'readNumber' => (int) $state->read_number]; } return $attributes; }
/** * Bootstrap the application events. * * @return void */ public function boot() { Discussion::setValidator($this->app->make('validator')); $events = $this->app->make('events'); $settings = $this->app->make('Flarum\\Core\\Settings\\SettingsRepository'); $events->subscribe('Flarum\\Core\\Discussions\\Listeners\\DiscussionMetadataUpdater'); $events->listen(ModelAllow::class, function (ModelAllow $event) use($settings) { if ($event->model instanceof Discussion) { if ($event->actor->hasPermission('discussion.' . $event->action)) { return true; } if (($event->action === 'rename' || $event->action === 'delete') && $event->model->start_user_id == $event->actor->id) { $allowRenaming = $settings->get('allow_renaming'); if ($allowRenaming === '-1' || $allowRenaming === 'reply' && $event->model->participants_count == 1 || $event->model->start_time->diffInMinutes(Carbon::now()) < $allowRenaming) { return true; } } } }); }
public function whenDiscussionWillBeSaved(DiscussionWillBeSaved $event) { if (isset($event->data['relationships']['tags']['data'])) { $discussion = $event->discussion; $actor = $event->actor; $linkage = (array) $event->data['relationships']['tags']['data']; $newTagIds = []; foreach ($linkage as $link) { $newTagIds[] = (int) $link['id']; } $newTags = Tag::whereIn('id', $newTagIds)->get(); $primaryCount = 0; $secondaryCount = 0; foreach ($newTags as $tag) { if (!$tag->can($actor, 'startDiscussion')) { throw new PermissionDeniedException(); } if ($tag->position !== null && $tag->parent_id === null) { $primaryCount++; } else { $secondaryCount++; } } $this->validatePrimaryTagCount($primaryCount); $this->validateSecondaryTagCount($secondaryCount); $oldTags = []; if ($discussion->exists) { $oldTags = $discussion->tags()->get(); $oldTagIds = $oldTags->lists('id'); if ($oldTagIds == $newTagIds) { return; } $discussion->raise(new DiscussionWasTagged($discussion, $actor, $oldTags->all())); } Discussion::saved(function ($discussion) use($newTagIds) { $discussion->tags()->sync($newTagIds); }); } }
/** * Get the IDs of discussions which a user has read completely. * * @param User $user * @return array */ public function getReadIds(User $user) { return Discussion::leftJoin('users_discussions', 'users_discussions.discussion_id', '=', 'discussions.id')->where('user_id', $user->id)->where('read_number', '<', 'last_post_number')->lists('id'); }
/** * @param SearchCriteria $criteria * @param int|null $limit * @param int $offset * @param array $load An array of relationships to load on the results. * @return SearchResults */ public function search(SearchCriteria $criteria, $limit = null, $offset = 0, array $load = []) { $actor = $criteria->actor; $query = $this->discussions->query()->whereVisibleTo($actor); // Construct an object which represents this search for discussions. // Apply gambits to it, sort, and paging criteria. Also give extensions // an opportunity to modify it. $search = new DiscussionSearch($query->getQuery(), $actor); $this->gambits->apply($search, $criteria->query); $this->applySort($search, $criteria->sort); $this->applyOffset($search, $offset); $this->applyLimit($search, $limit + 1); event(new DiscussionSearchWillBePerformed($search, $criteria)); // Execute the search query and retrieve the results. We get one more // results than the user asked for, so that we can say if there are more // results. If there are, we will get rid of that extra result. $discussions = $query->get(); if ($areMoreResults = $limit > 0 && $discussions->count() > $limit) { $discussions->pop(); } // The relevant posts relationship isn't a typical Eloquent // relationship; rather, we need to extract that information from our // search object. We will delegate that task and prevent Eloquent // from trying to load it. if (in_array('relevantPosts', $load)) { $this->loadRelevantPosts($discussions, $search); $load = array_diff($load, ['relevantPosts', 'relevantPosts.discussion', 'relevantPosts.user']); } Discussion::setStateUser($actor); $discussions->load($load); return new SearchResults($discussions, $areMoreResults); }
protected function filterDiscussionVisibleTo($ids, User $actor) { // For each post ID, we need to make sure that the discussion it's in // is visible to the user. if ($actor) { $ids = Discussion::join('posts', 'discussions.id', '=', 'posts.discussion_id')->whereIn('posts.id', $ids)->whereVisibleTo($actor)->get(['posts.id'])->lists('id'); } return $ids; }
protected function importDiscussions($from, $to) { $this->info('Importing discussions...'); $to->table('discussions')->truncate(); $to->table('discussions_tags')->truncate(); $to->table('posts')->truncate(); $to->table('notifications')->truncate(); $to->table('users_discussions')->truncate(); $to->table('activity')->truncate(); $to->table('mentions_posts')->truncate(); $to->table('mentions_users')->truncate(); $conversations = $from->table('conversation')->where('private', 0)->get(); $progress = new ProgressBar($this->output, count($conversations)); foreach ($conversations as $c) { $discussion = new Discussion(); $discussion->id = $c->conversationId; $discussion->title = $c->title; $discussion->is_sticky = $c->sticky; $discussion->start_user_id = $c->startMemberId; $discussion->start_time = $c->startTime; $discussion->last_user_id = $c->lastPostMemberId; $discussion->last_time = $c->lastPostTime; $discussion->save(); $discussion->tags()->sync([$c->channelId]); foreach ($from->table('post')->where('conversationId', $c->conversationId)->get() as $p) { $post = new CommentPost(); $post->id = $p->postId; $post->discussion_id = $p->conversationId; $post->user_id = $p->memberId; $post->time = $p->time; $post->edit_user_id = $p->editMemberId; $post->edit_time = $p->editTime; $post->hide_user_id = $p->deleteMemberId; $post->hide_time = $p->deleteTime; $post->content = $p->content; $this->formatPost($post); $post->save(); if (!$post->hide_time) { event(new PostWasPosted($post)); } } $discussion->last_post_id = $p->postId; $discussion->last_post_number = $post->number; $discussion->comments_count = $post->number; $discussion->save(); $states = $from->table('member_conversation')->where('conversationId', $c->conversationId)->where('type', 'member')->get(); foreach ($states as $s) { $state = new DiscussionState(); $state->discussion_id = $s->conversationId; $state->user_id = $s->id; $state->read_time = time(); $state->read_number = $discussion->posts()->orderBy('time', 'asc')->skip(min($discussion->comments_count, $s->lastRead) - 1)->pluck('number'); $state->save(); } $progress->advance(); } $progress->finish(); $this->info("\n"); }