aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Digitigrade/Model/Actor.php38
-rw-r--r--Digitigrade/Model/BlockRelation.php82
-rw-r--r--Digitigrade/Model/FollowRelation.php2
-rw-r--r--Digitigrade/Model/Notification.php2
-rw-r--r--Digitigrade/Notification/Notifyable.php2
-rw-r--r--Digitigrade/Notification/UnblockNotif.php49
-rw-r--r--Digitigrade/Timeline/HomeTimeline.php11
-rw-r--r--Digitigrade/Timeline/Timeline.php23
-rw-r--r--locale/en_GB.json10
-rw-r--r--migrations/20250123_173501_create_block_relation.php14
-rw-r--r--routes/actor.php24
-rw-r--r--routes/actor_profile_fragment.php14
-rw-r--r--routes/notifications.php2
-rw-r--r--static/icons.css6
-rw-r--r--static/misc.css1
-rw-r--r--static/note.css7
-rw-r--r--static/profile.css6
-rw-r--r--templates/actor_profile.php4
-rw-r--r--templates/actor_profile_block_button.php7
-rw-r--r--templates/actor_profile_page.php2
-rw-r--r--templates/note_hidden.php3
-rw-r--r--templates/notifications_panel.php2
-rw-r--r--templates/thread_page.php8
23 files changed, 309 insertions, 10 deletions
diff --git a/Digitigrade/Model/Actor.php b/Digitigrade/Model/Actor.php
index b4e9392..f2eecae 100644
--- a/Digitigrade/Model/Actor.php
+++ b/Digitigrade/Model/Actor.php
@@ -2,6 +2,7 @@
namespace Digitigrade\Model;
use Digitigrade\Notification\PendingFollowActionedNotif;
+use Digitigrade\Notification\UnblockNotif;
use Digitigrade\Notification\UnfollowNotif;
use Digitigrade\RpcException;
use Digitigrade\RpcReceiver;
@@ -142,6 +143,16 @@ class Actor extends PushableModel implements RpcReceiver {
(new PendingFollowActionedNotif($args[0], $this, 'reject'))->processNotifications();
return;
+ case 'block':
+ $rel = BlockRelation::create($args[0], $this);
+ $rel->processNotifications();
+ return;
+
+ case 'unblock':
+ BlockRelation::findByActors($args[0], $this)->remove();
+ (new UnblockNotif($args[0], $this))->processNotifications();
+ return;
+
default:
throw new \RuntimeException("behaviour for actor rpc method $method not (yet?) implemented");
}
@@ -233,6 +244,31 @@ class Actor extends PushableModel implements RpcReceiver {
return array_intersect($followers, $followees);
}
+ /**
+ * Blocks another actor.
+ * @param Actor $target the actor to block
+ */
+ public function block(self $target) {
+ $target->rpcCall('block', [$this]);
+ }
+
+ /**
+ * Unblocks another actor.
+ * @param Actor $target the actor to unblock
+ */
+ public function unblock(self $target) {
+ $target->rpcCall('unblock', [$this]);
+ }
+
+ /**
+ * @param Actor $target the other actor
+ * @return boolean whether this actor blocks the target actor
+ */
+ public function blocks(Actor $target): bool {
+ $relation = BlockRelation::findByActors($this, $target);
+ return $relation != null;
+ }
+
public function findHomeInstance(): Instance {
if ($this->isLocal) {
// can't do this because we don't keep track of ourself in the instance table
@@ -282,6 +318,8 @@ class Actor extends PushableModel implements RpcReceiver {
'unfollow' => path_to_uri("/actor/$this->id/unfollow"),
'acceptedFollow' => path_to_uri("/actor/$this->id/acceptedFollow"),
'rejectedFollow' => path_to_uri("/actor/$this->id/rejectedFollow"),
+ 'block' => path_to_uri("/actor/$this->id/block"),
+ 'unblock' => path_to_uri("/actor/$this->id/unblock"),
]
];
}
diff --git a/Digitigrade/Model/BlockRelation.php b/Digitigrade/Model/BlockRelation.php
new file mode 100644
index 0000000..ca7166c
--- /dev/null
+++ b/Digitigrade/Model/BlockRelation.php
@@ -0,0 +1,82 @@
+<?php
+namespace Digitigrade\Model;
+
+use Digitigrade\Model;
+use Digitigrade\Notification\Notifyable;
+
+class BlockRelation extends Model implements Notifyable {
+ public Actor $subject;
+ public Actor $object;
+
+ /**
+ * Creates and saves a new blocking relationship
+ * @param Actor $subject the actor who doesn't want to see the other one
+ * @param Actor $object the actor being blocked
+ * @return self
+ */
+ public static function create(Actor $subject, Actor $object): self {
+ $rel = new self();
+ $rel->subject = $subject;
+ $rel->object = $object;
+ $rel->save();
+ return $rel;
+ }
+
+ protected function getUpdateWhereClause(\PDO $db): ?string {
+ if (self::findWhere('subject = ? and object = ?', [$this->subject->id, $this->object->id]) != null) {
+ return 'subject = ' . $this->subject->id . ' and object = ' . $this->object->id;
+ }
+ return null;
+ }
+
+ public static function findByActors(Actor $subject, Actor $object): ?self {
+ return self::findWhere('subject = ? and object = ?', [$subject->id, $object->id]);
+ }
+
+ /**
+ * @return self[]
+ */
+ public static function findAllWithSubject(Actor $subject): array {
+ return self::findAllWhere('subject = ?', [$subject->id]);
+ }
+
+ /**
+ * @return self[]
+ */
+ public static function findAllWithObject(Actor $object): array {
+ return self::findAllWhere('object = ?', [$object->id]);
+ }
+
+ public function toJsonReference(): mixed {
+ return [$this->subject->id, $this->object->id];
+ }
+
+ public static function fromJsonReference(mixed $reference): ?self {
+ return self::findByActors(
+ Actor::find($reference[0]),
+ Actor::find($reference[1])
+ );
+ }
+
+ public function getNotificationTitle(): string {
+ return sprintf(__("notifications.block"), $this->subject->displayName);
+ }
+ public function getNotificationTitleLink(): ?string {
+ return '/@/' . $this->subject->getFullHandle();
+ }
+ public function getNotificationImageUrl(): ?string {
+ return $this->subject->avatar ?? '/static/default-avatar.png';
+ }
+ public function getNotificationImageLink(): ?string {
+ return $this->getNotificationTitleLink();
+ }
+ public function getNotificationBody(): ?string {
+ return null;
+ }
+
+ public function processNotifications() {
+ if (!$this->object->isLocal)
+ return;
+ Notification::fromNotifyable($this, UserAccount::findByLinkedActor($this->object))->send();
+ }
+} \ No newline at end of file
diff --git a/Digitigrade/Model/FollowRelation.php b/Digitigrade/Model/FollowRelation.php
index 7cab761..ecb625a 100644
--- a/Digitigrade/Model/FollowRelation.php
+++ b/Digitigrade/Model/FollowRelation.php
@@ -54,7 +54,7 @@ class FollowRelation extends Model implements Notifyable {
return [$this->subject->id, $this->object->id];
}
- public static function fromJsonReference(mixed $reference): self {
+ public static function fromJsonReference(mixed $reference): ?self {
return self::findByActors(
Actor::find($reference[0]),
Actor::find($reference[1])
diff --git a/Digitigrade/Model/Notification.php b/Digitigrade/Model/Notification.php
index ee9d64a..50e9991 100644
--- a/Digitigrade/Model/Notification.php
+++ b/Digitigrade/Model/Notification.php
@@ -28,7 +28,7 @@ class Notification extends Model {
return $notif;
}
- public function toNotifyable(): Notifyable {
+ public function toNotifyable(): ?Notifyable {
return $this->itemType::fromJsonReference(json_decode($this->itemData));
}
diff --git a/Digitigrade/Notification/Notifyable.php b/Digitigrade/Notification/Notifyable.php
index 510437e..7a7826f 100644
--- a/Digitigrade/Notification/Notifyable.php
+++ b/Digitigrade/Notification/Notifyable.php
@@ -3,7 +3,7 @@ namespace Digitigrade\Notification;
interface Notifyable {
public function toJsonReference(): mixed;
- public static function fromJsonReference(mixed $reference): self;
+ public static function fromJsonReference(mixed $reference): ?self;
public function getNotificationTitle(): string;
public function getNotificationTitleLink(): ?string;
public function getNotificationBody(): ?string;
diff --git a/Digitigrade/Notification/UnblockNotif.php b/Digitigrade/Notification/UnblockNotif.php
new file mode 100644
index 0000000..7f7ac64
--- /dev/null
+++ b/Digitigrade/Notification/UnblockNotif.php
@@ -0,0 +1,49 @@
+<?php
+namespace Digitigrade\Notification;
+
+use Digitigrade\Model\Actor;
+use Digitigrade\Model\Notification;
+use Digitigrade\Model\UserAccount;
+
+class UnblockNotif implements Notifyable {
+ private Actor $subject;
+ private Actor $object;
+
+ public function __construct(Actor $subject, Actor $object) {
+ $this->subject = $subject;
+ $this->object = $object;
+ }
+
+ public function toJsonReference(): mixed {
+ return [$this->subject->id, $this->object->id];
+ }
+
+ public static function fromJsonReference(mixed $reference): self {
+ return new self(
+ Actor::find($reference[0]),
+ Actor::find($reference[1])
+ );
+ }
+
+ public function getNotificationTitle(): string {
+ return sprintf(__('notifications.unblock'), $this->subject->displayName);
+ }
+ public function getNotificationTitleLink(): ?string {
+ return '/@/' . $this->subject->getFullHandle();
+ }
+ public function getNotificationImageUrl(): ?string {
+ return $this->subject->avatar ?? '/static/default-avatar.png';
+ }
+ public function getNotificationImageLink(): ?string {
+ return $this->getNotificationTitleLink();
+ }
+ public function getNotificationBody(): ?string {
+ return null;
+ }
+
+ public function processNotifications() {
+ if (!$this->object->isLocal)
+ return;
+ Notification::fromNotifyable($this, UserAccount::findByLinkedActor($this->object))->send();
+ }
+} \ No newline at end of file
diff --git a/Digitigrade/Timeline/HomeTimeline.php b/Digitigrade/Timeline/HomeTimeline.php
index 0867541..9f420e5 100644
--- a/Digitigrade/Timeline/HomeTimeline.php
+++ b/Digitigrade/Timeline/HomeTimeline.php
@@ -1,6 +1,7 @@
<?php
namespace Digitigrade\Timeline;
+use Digitigrade\Model\Note;
use Digitigrade\Model\UserAccount;
use Digitigrade\Model\HomeTimelineItem;
@@ -19,9 +20,13 @@ class HomeTimeline extends Timeline {
}
public function getItemsSince(\DateTimeInterface $when, ?int $limit = null, int $offset = 0): array {
- return array_map(
- fn(HomeTimelineItem $hti) => $hti->toTimelineItem(),
- HomeTimelineItem::findAllForUser($this->user, $limit, $offset, $when)
+ return array_filter(
+ array_map(
+ fn(HomeTimelineItem $hti) => $hti->toTimelineItem(),
+ HomeTimelineItem::findAllForUser($this->user, $limit, $offset, $when)
+ ),
+ // filter out notes from blocked users
+ fn(TimelineItem $item) => !($item instanceof Note && $this->user->actor->block($item->author))
);
}
} \ No newline at end of file
diff --git a/Digitigrade/Timeline/Timeline.php b/Digitigrade/Timeline/Timeline.php
index b3def28..f53eaa4 100644
--- a/Digitigrade/Timeline/Timeline.php
+++ b/Digitigrade/Timeline/Timeline.php
@@ -1,6 +1,9 @@
<?php
namespace Digitigrade\Timeline;
+use Digitigrade\Model\Note;
+use Digitigrade\Model\UserAccount;
+
abstract class Timeline {
// TODO: currently making this number up. probably should be modifiable somewhere
private const RESULTS_PER_PAGE = 50;
@@ -11,7 +14,25 @@ abstract class Timeline {
* @return TimelineItem[]
*/
public function getPage(int $page = 0): array {
- return $this->getItems(self::RESULTS_PER_PAGE, self::RESULTS_PER_PAGE * $page);
+ return $this->getItemsFiltered(self::RESULTS_PER_PAGE, self::RESULTS_PER_PAGE * $page);
+ }
+
+ /**
+ * @return TimelineItem[]
+ */
+ private function getItemsFiltered(int $limit, int $offset): array {
+ $user = UserAccount::findByCurrentSession();
+ $items = $this->getItems($limit, $offset);
+ if ($user == null)
+ return $items;
+ // filter out notes from blocked users
+ return array_filter($items, function (TimelineItem $item) use ($user) {
+ $obj = $item->getObject();
+ if ($obj instanceof Note && $user->actor->blocks($obj->author)) {
+ return false;
+ }
+ return true;
+ });
}
/**
diff --git a/locale/en_GB.json b/locale/en_GB.json
index 91154b6..ea53419 100644
--- a/locale/en_GB.json
+++ b/locale/en_GB.json
@@ -10,11 +10,16 @@
"user.profile.unfollow.action": "Unfollow",
"user.profile.followsYou": "Follows you",
"user.profile.pendingFollowsYou": "Wants to follow you",
+ "user.profile.block": "Block",
+ "user.profile.block.confirm": "Are you sure you want to block this user?",
+ "user.profile.unblock": "Unblock",
+ "user.profile.unblock.confirm": "Are you sure you want to unblock this user?",
"user.profile.displayName": "Display name",
"user.profile.changeAvatar": "Choose a new avatar image",
"user.profile.resetAvatar": "Reset avatar",
"user.profile.avatarReset": "Avatar reset!",
"user.profile.bio": "Bio",
+ "user.profile.notesHidden": "Notes hidden because you block this user",
"user.notes.placeholder": "This user hasn't posted anything yet.",
"timeline.global": "Global timeline",
"timeline.global.description": "This timeline shows all known public indexable notes.",
@@ -34,10 +39,11 @@
"note.privacy.scope.mutuals": "Mutuals only",
"note.privacy.scope.followers": "Followers only",
"note.privacy.scope.public": "Public",
+ "note.hidden": "Hidden note from a blocked user",
+ "note.resharedBy": "Reshared by %s",
"placeholder": "There's nothing here.",
"placeholder.moreItems": "…and %d more",
"placeholder.noMoreItems": "No more items.",
- "note.resharedBy": "Reshared by %s",
"navigation.login": "Log in",
"navigation.logout": "Log out",
"navigation.logout.confirmation": "Are you sure you want to log out?",
@@ -53,6 +59,8 @@
"notifications.follow.removed": "%s unfollowed you",
"notifications.follow.accept": "%s accepted your follow request",
"notifications.follow.reject": "%s rejected your follow request",
+ "notifications.block": "%s blocked you",
+ "notifications.unblock": "%s unblocked you",
"login.pageTitle": "Log in",
"login.email": "Email address",
"login.password": "Password",
diff --git a/migrations/20250123_173501_create_block_relation.php b/migrations/20250123_173501_create_block_relation.php
new file mode 100644
index 0000000..f9ff266
--- /dev/null
+++ b/migrations/20250123_173501_create_block_relation.php
@@ -0,0 +1,14 @@
+<?php
+
+use \Digitigrade\Db\Migrator;
+
+Migrator::getInstance()->register(20250123_173501, function (PDO $db) {
+ // actors who block each other. makes sense
+ $db->exec(<<<END
+ CREATE TABLE block_relation (
+ subject bigint not null references actor,
+ object bigint not null references actor,
+ unique(subject, object)
+ );
+ END);
+});
diff --git a/routes/actor.php b/routes/actor.php
index a3b69d1..125c733 100644
--- a/routes/actor.php
+++ b/routes/actor.php
@@ -97,4 +97,28 @@ Router::getInstance()->mount('/actor/:id/rejectedFollow', function (array $args)
throw new Unauthorized('please authenticate yourself on behalf of the followed actor');
}
$target->rejectPendingFollowFrom($initiator);
+});
+
+Router::getInstance()->mount('/actor/:id/block', function (array $args) {
+ $target = Actor::find($args['id']);
+ if ($target == null || !$target->isLocal || $target->deleted) {
+ throw new NotFound();
+ }
+ $initiator = Actor::findByRequestHeaders();
+ if ($initiator == null) {
+ throw new Unauthorized('please authenticate yourself on behalf of the initiating actor');
+ }
+ $initiator->block($target);
+});
+
+Router::getInstance()->mount('/actor/:id/unblock', function (array $args) {
+ $target = Actor::find($args['id']);
+ if ($target == null || !$target->isLocal || $target->deleted) {
+ throw new NotFound();
+ }
+ $initiator = Actor::findByRequestHeaders();
+ if ($initiator == null) {
+ throw new Unauthorized('please authenticate yourself on behalf of the initiating actor');
+ }
+ $initiator->unblock($target);
}); \ No newline at end of file
diff --git a/routes/actor_profile_fragment.php b/routes/actor_profile_fragment.php
index 0a2a881..45f4487 100644
--- a/routes/actor_profile_fragment.php
+++ b/routes/actor_profile_fragment.php
@@ -46,6 +46,20 @@ Router::getInstance()->mount('/fragment/actor/:id/rejectPending', function (arra
render_template('actor_profile_pending_follow', ['response' => 'rejected']);
});
+Router::getInstance()->mount('/fragment/actor/:id/blockButton', function (array $args) {
+ $user = UserAccount::requireByCurrentSession();
+ $actor = Actor::find($args['id']);
+
+ if ($user->actor->blocks($actor)) {
+ // already blocking therefore unblock
+ $user->actor->unblock($actor);
+ } else {
+ $user->actor->block($actor);
+ }
+
+ render_template('actor_profile_block_button', ['user' => $user, 'actor' => $actor]);
+});
+
Router::getInstance()->mount('/fragment/profile', function (array $args) {
$user = UserAccount::requireByCurrentSession();
$actor = $user->actor;
diff --git a/routes/notifications.php b/routes/notifications.php
index 05fb89d..c7b9414 100644
--- a/routes/notifications.php
+++ b/routes/notifications.php
@@ -15,6 +15,8 @@ Router::getInstance()->mount('/notifications/partial', function (array $args) {
foreach ($notifs as $notif) {
$notif = $notif->toNotifyable();
+ if ($notif == null)
+ continue;
render_template('notification', [
'title' => $notif->getNotificationTitle(),
'body' => $notif->getNotificationBody(),
diff --git a/static/icons.css b/static/icons.css
index e15e59c..e40c30b 100644
--- a/static/icons.css
+++ b/static/icons.css
@@ -72,4 +72,10 @@
&.close {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M6.4 19L5 17.6l5.6-5.6L5 6.4L6.4 5l5.6 5.6L17.6 5L19 6.4L13.4 12l5.6 5.6l-1.4 1.4l-5.6-5.6z'/%3E%3C/svg%3E");
}
+ &.block {
+ --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 22q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22m0-2q1.35 0 2.6-.437t2.3-1.263L5.7 7.1q-.825 1.05-1.263 2.3T4 12q0 3.35 2.325 5.675T12 20m6.3-3.1q.825-1.05 1.263-2.3T20 12q0-3.35-2.325-5.675T12 4q-1.35 0-2.6.437T7.1 5.7z'/%3E%3C/svg%3E");
+ }
+ &.remove {
+ --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M5 13v-2h14v2z'/%3E%3C/svg%3E");
+ }
}
diff --git a/static/misc.css b/static/misc.css
index 138b0fb..8f37d21 100644
--- a/static/misc.css
+++ b/static/misc.css
@@ -42,6 +42,7 @@ button.material-symbols {
aspect-ratio: 1;
margin: 0;
padding: 0;
+ cursor: pointer;
}
.material-symbols {
diff --git a/static/note.css b/static/note.css
index 7e0f529..3051488 100644
--- a/static/note.css
+++ b/static/note.css
@@ -167,3 +167,10 @@ article.note {
}
}
}
+
+article.note.hidden {
+ padding-top: 0;
+ padding-bottom: 0;
+ display: block;
+ text-align: center;
+}
diff --git a/static/profile.css b/static/profile.css
index 7783206..c2e48ed 100644
--- a/static/profile.css
+++ b/static/profile.css
@@ -34,6 +34,12 @@
}
}
+ .profileMiniActions {
+ display: grid;
+ grid-auto-flow: column;
+ gap: var(--spacing-double);
+ }
+
.profileActions {
display: grid;
justify-content: end;
diff --git a/templates/actor_profile.php b/templates/actor_profile.php
index 2947a72..cfcc510 100644
--- a/templates/actor_profile.php
+++ b/templates/actor_profile.php
@@ -17,7 +17,9 @@ $user = UserAccount::findByCurrentSession();
<div class="handle">@<?= $actor->getFullHandle() ?></div>
<div class="joinedDate"><?= sprintf(__('user.profile.createdAt'), $actor->created->format('Y-m-d')) ?></div>
</div>
- <div>
+ <div class="profileMiniActions">
+ <?php if ($user != null && $user->actor != $actor)
+ call_template('actor_profile_block_button', ['actor' => $actor, 'user' => $user]); ?>
<?php if (!$actor->isLocal): ?>
<a class="material-symbols open-in-new" href="<?= $actor->homepage ?>"
title="<?= __('user.profile.openRemote') ?>" target="_blank"></a>
diff --git a/templates/actor_profile_block_button.php b/templates/actor_profile_block_button.php
new file mode 100644
index 0000000..f82cc9a
--- /dev/null
+++ b/templates/actor_profile_block_button.php
@@ -0,0 +1,7 @@
+<?php
+$blocks = $user->actor->blocks($actor);
+$action = $blocks ? 'unblock' : 'block';
+?>
+<button class="material-symbols <?= $blocks ? 'remove' : 'block' ?>" title="<?= __("user.profile.$action") ?>"
+ hx-confirm="<?= __("user.profile.$action.confirm") ?>" hx-post="/fragment/actor/<?= $actor->id ?>/blockButton"
+ hx-swap="outerHTML"></button> \ No newline at end of file
diff --git a/templates/actor_profile_page.php b/templates/actor_profile_page.php
index eba9d04..3b6eb84 100644
--- a/templates/actor_profile_page.php
+++ b/templates/actor_profile_page.php
@@ -15,6 +15,8 @@ call_template('skeleton', [
$notes = Note::findAllWithAuthor($actor, 20);
if (count($notes) == 0) {
call_template('placeholder_text', ['message' => __('user.notes.placeholder')]);
+ } elseif ($user != null && $user->actor->blocks($actor)) {
+ call_template('placeholder_text', ['message' => __('user.profile.notesHidden')]);
} else {
foreach ($notes as $n) {
if ($n->isViewableBy($user))
diff --git a/templates/note_hidden.php b/templates/note_hidden.php
new file mode 100644
index 0000000..baad0d6
--- /dev/null
+++ b/templates/note_hidden.php
@@ -0,0 +1,3 @@
+<article class="note hidden">
+ <?php call_template('placeholder_text', ['message' => __('note.hidden')]); ?>
+</article> \ No newline at end of file
diff --git a/templates/notifications_panel.php b/templates/notifications_panel.php
index 3ca8faf..98a04e3 100644
--- a/templates/notifications_panel.php
+++ b/templates/notifications_panel.php
@@ -13,6 +13,8 @@ $notifications = Notification::findAllForUser($user, 50);
}
foreach ($notifications as $notif) {
$notif = $notif->toNotifyable();
+ if ($notif == null)
+ continue;
call_template('notification', [
'title' => $notif->getNotificationTitle(),
'body' => $notif->getNotificationBody(),
diff --git a/templates/thread_page.php b/templates/thread_page.php
index e5e5389..d16c6aa 100644
--- a/templates/thread_page.php
+++ b/templates/thread_page.php
@@ -1,5 +1,6 @@
<?php
use Digitigrade\Model\Note;
+use Digitigrade\Model\UserAccount;
call_template('skeleton', [
'pageTitle' => '"' . $note->plainContent . '" - @' . $note->author->getFullHandle(),
@@ -7,7 +8,12 @@ call_template('skeleton', [
], function () {
global $note;
$notes = Note::findAllInThread($note->threadApex ?? $note);
+ $user = UserAccount::findByCurrentSession();
foreach ($notes as $n) {
- call_template('note', ['note' => $n, 'selected' => $n == $note]);
+ if ($user != null && $user->actor->blocks($n->author)) {
+ call_template('note_hidden');
+ } else {
+ call_template('note', ['note' => $n, 'selected' => $n == $note]);
+ }
}
}); \ No newline at end of file