diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index ddefba71f..f33431819 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -2,11 +2,11 @@ namespace Coyote\Http\Controllers; -use Coyote\Http\Resources\ActivityResource; use Coyote\Http\Resources\Api\MicroblogResource; use Coyote\Http\Resources\FlagResource; use Coyote\Http\Resources\MicroblogCollection; use Coyote\Microblog; +use Coyote\Presenter\Homepage\Timeline; use Coyote\Repositories\Contracts\ActivityRepositoryInterface; use Coyote\Repositories\Contracts\ReputationRepositoryInterface; use Coyote\Repositories\Contracts\TopicRepositoryInterface; @@ -35,15 +35,21 @@ public function __construct( public function index(): View { $cache = app(Cache\Repository::class); + $this->topic->pushCriteria(new Topic\OnlyThoseWithAccess()); $this->topic->pushCriteria(new SkipHiddenCategories($this->userId)); + + $this->activity->pushCriteria(new Forum\OnlyThoseWithAccess($this->auth)); + $this->activity->pushCriteria(new SkipHiddenCategories($this->userId)); + $timeline = new Timeline($this->activity->latest(30)); + return $this->view('home', [ 'flags' => $this->flags(), 'microblogs' => $this->getMicroblogs(), 'interesting' => $this->topic->interesting(), 'newest' => $this->topic->newest(), 'viewers' => $this->getViewers(), - 'activities' => $this->getActivities(), + 'timeline' => $timeline, 'reputation' => $cache->remember('homepage:reputation', 30 * 60, fn() => [ 'month' => $this->reputation->monthly(), 'year' => $this->reputation->yearly(), @@ -64,14 +70,6 @@ private function getMicroblogs(): array return (new MicroblogCollection($microblogs))->resolve($this->request); } - private function getActivities(): array - { - $this->activity->pushCriteria(new Forum\OnlyThoseWithAccess($this->auth)); - $this->activity->pushCriteria(new SkipHiddenCategories($this->userId)); - return ActivityResource::collection($this->activity->latest(30)) - ->toArray($this->request); - } - private function getViewers(): View { /** @var Renderer $viewers */ diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 8eb82cbc0..0095f6b54 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -2,8 +2,22 @@ namespace Coyote; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; - +/** + * @property Carbon $created_at + * @property string $content_type + * @property string $excerpt + * @property string $user_name + * + * @property int $user_id + * @property int $content_id + * + * @property User $user + * @property Topic $topic + * @property Forum $forum + * @property Post|Post\Comment $content + */ class Activity extends Model { /** diff --git a/app/Presenter/Homepage/Timeline.php b/app/Presenter/Homepage/Timeline.php new file mode 100644 index 000000000..f2848a16f --- /dev/null +++ b/app/Presenter/Homepage/Timeline.php @@ -0,0 +1,103 @@ +activities = $activities + ->map(fn($activity) => $this->activity($activity)) + ->toArray(); + } + + private function activity(Activity $activity): array + { + return [ + 'excerpt' => $activity->excerpt, + 'created_at' => $activity->created_at, + 'user_id' => $activity->user_id, + 'headline' => $this->headline($activity), + 'object' => $this->objectType($activity), + 'type' => $this->objectType($activity), + 'icon' => $this->icon($activity), + 'user' => [ + 'id' => $activity->user_id, + 'name' => $this->userName($activity), + 'photo' => $this->userPhoto($activity), + 'profile' => route('profile', [$activity->user_id]) + ] + ]; + } + + private function objectType(Activity $activity): string + { + return [Post::class => 'post', Comment::class => 'comment'][$activity->content_type]; + } + + private function icon(Activity $activity): string + { + $icons = [ + Comment::class => 'far fa-comment', + Post::class => 'fas fa-quote-right', + ]; + return $icons[$activity->content_type]; + } + + public function headline(Activity $activity): string + { + return trans("activity.headline.{$this->objectType($activity)}", [ + 'user' => $this->user($activity), + 'topic' => $this->topic($activity) + ]); + } + + public function user(Activity $activity): string + { + if ($activity->user_id) { + return link_to_route('profile', $activity->user->name, ['user_trashed' => $activity->user_id]); + } + return $activity->user_name; + } + + private function userName(Activity $activity): string + { + if ($activity->user_id) { + return $activity->user->name; + } + return 'guest'; + } + + public function topic(Activity $activity): string + { + if ($activity->content_type === Post::class) { + $activity->content->setRelations(['topic' => $activity->topic, 'forum' => $activity->forum]); + return link_to(UrlBuilder::post($activity->content), $activity->topic->title); + } + $post = (new Post) + ->forceFill(['id' => $activity->content->post_id]) + ->setRelations(['topic' => $activity->topic, 'forum' => $activity->forum]); + $activity->content->setRelations(['post' => $post]); + return link_to(UrlBuilder::postComment($activity->content), $post->topic->title); + } + + public function userPhoto(Activity $activity): string + { + if ($activity->user_id) { + if ($activity->user->photo->getFilename()) { + return $activity->user->photo->url(); + } + } + return cdn('img/avatar.png'); + } +} diff --git a/resources/views/home.twig b/resources/views/home.twig index 3feaf9e65..d77656549 100644 --- a/resources/views/home.twig +++ b/resources/views/home.twig @@ -94,7 +94,7 @@
- {% for activity in activities %} + {% for activity in timeline.activities %}