Skip to content

Commit

Permalink
Timeline, version 5
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Oct 6, 2023
1 parent 0773443 commit 1a6ec32
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 15 deletions.
18 changes: 8 additions & 10 deletions app/Http/Controllers/HomeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand All @@ -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 */
Expand Down
16 changes: 15 additions & 1 deletion app/Models/Activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/**
Expand Down
103 changes: 103 additions & 0 deletions app/Presenter/Homepage/Timeline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php
namespace Coyote\Presenter\Homepage;

use Coyote\Activity;
use Coyote\Post;
use Coyote\Post\Comment;
use Coyote\Services\Media\MediaInterface;
use Coyote\Services\UrlBuilder;
use Illuminate\Database\Eloquent;
use function cdn;

class Timeline
{
/** @var array[] */
public array $activities;

public function __construct(Eloquent\Collection $activities)
{
$this->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');
}
}
8 changes: 4 additions & 4 deletions resources/views/home.twig
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,19 @@
</h2>
<div>
<div class="activities">
{% for activity in activities %}
{% for activity in timeline.activities %}
<div class="activity">
<span class="icon {{ activity.type }}" title="{{ activity.headline|striptags|unescape }}">
<i class="{{ activity.icon }}"></i>
</span>
<div class="item {{ activity.type }}">
<div class="body">
<div class="d-none d-sm-block mr-2">
<a href="{{ route('profile', [activity.user_id]) }}">
<a href="{{ activity.user.profile }}">
<img
class="user-avatar"
src="{{ user_photo(activity.user.photo) }}"
alt="activity.user.name"/>
src="{{ activity.user.photo }}"
alt="{{ activity.user.name }}"/>
</a>
</div>
<div>
Expand Down

0 comments on commit 1a6ec32

Please sign in to comment.