refactor: rename all occurences of notes to statuses

This commit is contained in:
Yassine Doghri 2021-06-21 10:04:18 +00:00
parent ddeabf5665
commit 134a071add
No known key found for this signature in database
GPG Key ID: 3E7F89498B960C9F
71 changed files with 908 additions and 908 deletions

View File

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Config; namespace Config;
use App\Entities\Actor; use App\Entities\Actor;
use App\Entities\Note; use App\Entities\Status;
use App\Entities\User; use App\Entities\User;
use CodeIgniter\Events\Events; use CodeIgniter\Events\Events;
use CodeIgniter\Exceptions\FrameworkException; use CodeIgniter\Exceptions\FrameworkException;
@ -120,82 +120,82 @@ Events::on('on_undo_follow', function ($actor, $targetActor): void {
}); });
/** /**
* @param Note $note * @param Status $status
*/ */
Events::on('on_note_add', function ($note): void { Events::on('on_status_add', function ($status): void {
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
$note = $note->reply_to_note; $status = $status->reply_to_status;
} }
if ($note->episode_id) { if ($status->episode_id) {
model('EpisodeModel') model('EpisodeModel')
->where('id', $note->episode_id) ->where('id', $status->episode_id)
->increment('notes_total'); ->increment('statuses_total');
} }
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
// Removing all of the podcast pages is a bit overkill, but works to avoid caching bugs // Removing all of the podcast pages is a bit overkill, but works to avoid caching bugs
// same for other events below // same for other events below
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
}); });
/** /**
* @param Note $note * @param Status $status
*/ */
Events::on('on_note_remove', function ($note): void { Events::on('on_status_remove', function ($status): void {
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
Events::trigger('on_note_remove', $note->reply_to_note); Events::trigger('on_status_remove', $status->reply_to_status);
} }
if ($episodeId = $note->episode_id) { if ($episodeId = $status->episode_id) {
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->decrement('notes_total', 1 + $note->reblogs_count); ->decrement('statuses_total', 1 + $status->reblogs_count);
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->decrement('reblogs_total', $note->reblogs_count); ->decrement('reblogs_total', $status->reblogs_count);
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->decrement('favourites_total', $note->favourites_count); ->decrement('favourites_total', $status->favourites_count);
} }
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
}); });
/** /**
* @param Actor $actor * @param Actor $actor
* @param Note $note * @param Status $status
*/ */
Events::on('on_note_reblog', function ($actor, $note): void { Events::on('on_status_reblog', function ($actor, $status): void {
if ($episodeId = $note->episode_id) { if ($episodeId = $status->episode_id) {
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->increment('reblogs_total'); ->increment('reblogs_total');
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->increment('notes_total'); ->increment('statuses_total');
} }
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
if ($actor->is_podcast) { if ($actor->is_podcast) {
@ -205,111 +205,111 @@ Events::on('on_note_reblog', function ($actor, $note): void {
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
cache()->deleteMatching("page_note#{$note->in_reply_to_id}"); cache()->deleteMatching("page_status#{$status->in_reply_to_id}");
} }
}); });
/** /**
* @param Note $reblogNote * @param Status $reblogStatus
*/ */
Events::on('on_note_undo_reblog', function ($reblogNote): void { Events::on('on_status_undo_reblog', function ($reblogStatus): void {
$note = $reblogNote->reblog_of_note; $status = $reblogStatus->reblog_of_status;
if ($episodeId = $note->episode_id) { if ($episodeId = $status->episode_id) {
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->decrement('reblogs_total'); ->decrement('reblogs_total');
model('EpisodeModel') model('EpisodeModel')
->where('id', $episodeId) ->where('id', $episodeId)
->decrement('notes_total'); ->decrement('statuses_total');
} }
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
cache() cache()
->deleteMatching("page_note#{$reblogNote->id}*"); ->deleteMatching("page_status#{$reblogStatus->id}*");
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
cache()->deleteMatching("page_note#{$note->in_reply_to_id}"); cache()->deleteMatching("page_status#{$status->in_reply_to_id}");
} }
if ($reblogNote->actor->is_podcast) { if ($reblogStatus->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$reblogNote->actor->podcast->id}*"); ->deleteMatching("podcast#{$reblogStatus->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$reblogNote->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$reblogStatus->actor->podcast->id}*");
} }
}); });
/** /**
* @param Note $reply * @param Status $reply
*/ */
Events::on('on_note_reply', function ($reply): void { Events::on('on_status_reply', function ($reply): void {
$note = $reply->reply_to_note; $status = $reply->reply_to_status;
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
}); });
/** /**
* @param Note $reply * @param Status $reply
*/ */
Events::on('on_reply_remove', function ($reply): void { Events::on('on_reply_remove', function ($reply): void {
$note = $reply->reply_to_note; $status = $reply->reply_to_status;
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
cache() cache()
->deleteMatching("page_note#{$reply->id}*"); ->deleteMatching("page_status#{$reply->id}*");
}); });
/** /**
* @param Actor $actor * @param Actor $actor
* @param Note $note * @param Status $status
*/ */
Events::on('on_note_favourite', function ($actor, $note): void { Events::on('on_status_favourite', function ($actor, $status): void {
if ($note->episode_id) { if ($status->episode_id) {
model('EpisodeModel') model('EpisodeModel')
->where('id', $note->episode_id) ->where('id', $status->episode_id)
->increment('favourites_total'); ->increment('favourites_total');
} }
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
cache()->deleteMatching("page_note#{$note->in_reply_to_id}*"); cache()->deleteMatching("page_status#{$status->in_reply_to_id}*");
} }
if ($actor->is_podcast) { if ($actor->is_podcast) {
@ -321,27 +321,27 @@ Events::on('on_note_favourite', function ($actor, $note): void {
/** /**
* @param Actor $actor * @param Actor $actor
* @param Note $note * @param Status $status
*/ */
Events::on('on_note_undo_favourite', function ($actor, $note): void { Events::on('on_status_undo_favourite', function ($actor, $status): void {
if ($note->episode_id) { if ($status->episode_id) {
model('EpisodeModel') model('EpisodeModel')
->where('id', $note->episode_id) ->where('id', $status->episode_id)
->decrement('favourites_total'); ->decrement('favourites_total');
} }
if ($note->actor->is_podcast) { if ($status->actor->is_podcast) {
cache() cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*"); ->deleteMatching("podcast#{$status->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$status->actor->podcast->id}*");
} }
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_status#{$status->id}*");
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
cache()->deleteMatching("page_note#{$note->in_reply_to_id}*"); cache()->deleteMatching("page_status#{$status->in_reply_to_id}*");
} }
if ($actor->is_podcast) { if ($actor->is_podcast) {
@ -356,7 +356,7 @@ Events::on('on_block_actor', function (int $actorId): void {
cache() cache()
->deleteMatching('podcast*'); ->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_status*');
}); });
Events::on('on_unblock_actor', function (int $actorId): void { Events::on('on_unblock_actor', function (int $actorId): void {
@ -364,7 +364,7 @@ Events::on('on_unblock_actor', function (int $actorId): void {
cache() cache()
->deleteMatching('podcast*'); ->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_status*');
}); });
Events::on('on_block_domain', function (string $domainName): void { Events::on('on_block_domain', function (string $domainName): void {
@ -372,7 +372,7 @@ Events::on('on_block_domain', function (string $domainName): void {
cache() cache()
->deleteMatching('podcast*'); ->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_status*');
}); });
Events::on('on_unblock_domain', function (string $domainName): void { Events::on('on_unblock_domain', function (string $domainName): void {
@ -380,5 +380,5 @@ Events::on('on_unblock_domain', function (string $domainName): void {
cache() cache()
->deleteMatching('podcast*'); ->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_status*');
}); });

View File

@ -35,7 +35,7 @@ $routes->addPlaceholder('podcastName', '[a-zA-Z0-9\_]{1,32}');
$routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}'); $routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}');
$routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}'); $routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}');
$routes->addPlaceholder('platformType', '\bpodcasting|\bsocial|\bfunding'); $routes->addPlaceholder('platformType', '\bpodcasting|\bsocial|\bfunding');
$routes->addPlaceholder('noteAction', '\bfavourite|\breblog|\breply'); $routes->addPlaceholder('statusAction', '\bfavourite|\breblog|\breply');
$routes->addPlaceholder('embeddablePlayerTheme', '\blight|\bdark|\blight-transparent|\bdark-transparent'); $routes->addPlaceholder('embeddablePlayerTheme', '\blight|\bdark|\blight-transparent|\bdark-transparent');
$routes->addPlaceholder( $routes->addPlaceholder(
'uuid', 'uuid',
@ -746,71 +746,71 @@ $routes->post('interact-as-actor', 'AuthController::attemptInteractAsActor', [
* Overwriting ActivityPub routes file * Overwriting ActivityPub routes file
*/ */
$routes->group('@(:podcastName)', function ($routes): void { $routes->group('@(:podcastName)', function ($routes): void {
$routes->post('notes/new', 'NoteController::attemptCreate/$1', [ $routes->post('statuses/new', 'StatusController::attemptCreate/$1', [
'as' => 'note-attempt-create', 'as' => 'status-attempt-create',
'filter' => 'permission:podcast-manage_publications', 'filter' => 'permission:podcast-manage_publications',
]); ]);
// Note // Status
$routes->group('notes/(:uuid)', function ($routes): void { $routes->group('statuses/(:uuid)', function ($routes): void {
$routes->get('/', 'NoteController::view/$1/$2', [ $routes->get('/', 'StatusController::view/$1/$2', [
'as' => 'note', 'as' => 'status',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'ActivityPub\Controllers', 'namespace' => 'ActivityPub\Controllers',
'controller-method' => 'NoteController/$2', 'controller-method' => 'StatusController/$2',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'ActivityPub\Controllers', 'namespace' => 'ActivityPub\Controllers',
'controller-method' => 'NoteController/$2', 'controller-method' => 'StatusController/$2',
], ],
], ],
]); ]);
$routes->get('replies', 'NoteController/$1/$2', [ $routes->get('replies', 'StatusController/$1/$2', [
'as' => 'note-replies', 'as' => 'status-replies',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'ActivityPub\Controllers', 'namespace' => 'ActivityPub\Controllers',
'controller-method' => 'NoteController::replies/$2', 'controller-method' => 'StatusController::replies/$2',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'ActivityPub\Controllers', 'namespace' => 'ActivityPub\Controllers',
'controller-method' => 'NoteController::replies/$2', 'controller-method' => 'StatusController::replies/$2',
], ],
], ],
]); ]);
// Actions // Actions
$routes->post('action', 'NoteController::attemptAction/$1/$2', [ $routes->post('action', 'StatusController::attemptAction/$1/$2', [
'as' => 'note-attempt-action', 'as' => 'status-attempt-action',
'filter' => 'permission:podcast-interact_as', 'filter' => 'permission:podcast-interact_as',
]); ]);
$routes->post( $routes->post(
'block-actor', 'block-actor',
'NoteController::attemptBlockActor/$1/$2', 'StatusController::attemptBlockActor/$1/$2',
[ [
'as' => 'note-attempt-block-actor', 'as' => 'status-attempt-block-actor',
'filter' => 'permission:fediverse-block_actors', 'filter' => 'permission:fediverse-block_actors',
], ],
); );
$routes->post( $routes->post(
'block-domain', 'block-domain',
'NoteController::attemptBlockDomain/$1/$2', 'StatusController::attemptBlockDomain/$1/$2',
[ [
'as' => 'note-attempt-block-domain', 'as' => 'status-attempt-block-domain',
'filter' => 'permission:fediverse-block_domains', 'filter' => 'permission:fediverse-block_domains',
], ],
); );
$routes->post('delete', 'NoteController::attemptDelete/$1/$2', [ $routes->post('delete', 'StatusController::attemptDelete/$1/$2', [
'as' => 'note-attempt-delete', 'as' => 'status-attempt-delete',
'filter' => 'permission:podcast-manage_publications', 'filter' => 'permission:podcast-manage_publications',
]); ]);
$routes->get( $routes->get(
'remote/(:noteAction)', 'remote/(:statusAction)',
'NoteController::remoteAction/$1/$2/$3', 'StatusController::remoteAction/$1/$2/$3',
[ [
'as' => 'note-remote-action', 'as' => 'status-remote-action',
], ],
); );
}); });

View File

@ -13,12 +13,12 @@ namespace App\Controllers\Admin;
use App\Entities\Episode; use App\Entities\Episode;
use App\Entities\Image; use App\Entities\Image;
use App\Entities\Location; use App\Entities\Location;
use App\Entities\Note;
use App\Entities\Podcast; use App\Entities\Podcast;
use App\Entities\Status;
use App\Models\EpisodeModel; use App\Models\EpisodeModel;
use App\Models\NoteModel;
use App\Models\PodcastModel; use App\Models\PodcastModel;
use App\Models\SoundbiteModel; use App\Models\SoundbiteModel;
use App\Models\StatusModel;
use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\I18n\Time; use CodeIgniter\I18n\Time;
@ -426,7 +426,7 @@ class EpisodeController extends BaseController
$db = db_connect(); $db = db_connect();
$db->transStart(); $db->transStart();
$newNote = new Note([ $newStatus = new Status([
'actor_id' => $this->podcast->actor_id, 'actor_id' => $this->podcast->actor_id,
'episode_id' => $this->episode->id, 'episode_id' => $this->episode->id,
'message' => $this->request->getPost('message'), 'message' => $this->request->getPost('message'),
@ -453,15 +453,15 @@ class EpisodeController extends BaseController
$this->episode->published_at = Time::now(); $this->episode->published_at = Time::now();
} }
$newNote->published_at = $this->episode->published_at; $newStatus->published_at = $this->episode->published_at;
$noteModel = new NoteModel(); $statusModel = new StatusModel();
if (! $noteModel->addNote($newNote)) { if (! $statusModel->addStatus($newStatus)) {
$db->transRollback(); $db->transRollback();
return redirect() return redirect()
->back() ->back()
->withInput() ->withInput()
->with('errors', $noteModel->errors()); ->with('errors', $statusModel->errors());
} }
$episodeModel = new EpisodeModel(); $episodeModel = new EpisodeModel();
@ -486,7 +486,7 @@ class EpisodeController extends BaseController
$data = [ $data = [
'podcast' => $this->podcast, 'podcast' => $this->podcast,
'episode' => $this->episode, 'episode' => $this->episode,
'note' => (new NoteModel()) 'status' => (new StatusModel())
->where([ ->where([
'actor_id' => $this->podcast->actor_id, 'actor_id' => $this->podcast->actor_id,
'episode_id' => $this->episode->id, 'episode_id' => $this->episode->id,
@ -506,7 +506,7 @@ class EpisodeController extends BaseController
public function attemptPublishEdit(): RedirectResponse public function attemptPublishEdit(): RedirectResponse
{ {
$rules = [ $rules = [
'note_id' => 'required', 'status_id' => 'required',
'publication_method' => 'required', 'publication_method' => 'required',
'scheduled_publication_date' => 'scheduled_publication_date' =>
'valid_date[Y-m-d H:i]|permit_empty', 'valid_date[Y-m-d H:i]|permit_empty',
@ -542,19 +542,19 @@ class EpisodeController extends BaseController
$this->episode->published_at = Time::now(); $this->episode->published_at = Time::now();
} }
$note = (new NoteModel())->getNoteById($this->request->getPost('note_id')); $status = (new StatusModel())->getStatusById($this->request->getPost('status_id'));
if ($note !== null) { if ($status !== null) {
$note->message = $this->request->getPost('message'); $status->message = $this->request->getPost('message');
$note->published_at = $this->episode->published_at; $status->published_at = $this->episode->published_at;
$noteModel = new NoteModel(); $statusModel = new StatusModel();
if (! $noteModel->editNote($note)) { if (! $statusModel->editStatus($status)) {
$db->transRollback(); $db->transRollback();
return redirect() return redirect()
->back() ->back()
->withInput() ->withInput()
->with('errors', $noteModel->errors()); ->with('errors', $statusModel->errors());
} }
} }
@ -609,13 +609,13 @@ class EpisodeController extends BaseController
$db->transStart(); $db->transStart();
$allNotesLinkedToEpisode = (new NoteModel()) $allStatusesLinkedToEpisode = (new StatusModel())
->where([ ->where([
'episode_id' => $this->episode->id, 'episode_id' => $this->episode->id,
]) ])
->findAll(); ->findAll();
foreach ($allNotesLinkedToEpisode as $note) { foreach ($allStatusesLinkedToEpisode as $status) {
(new NoteModel())->removeNote($note); (new StatusModel())->removeStatus($status);
} }
// set episode published_at to null to unpublish // set episode published_at to null to unpublish

View File

@ -13,8 +13,8 @@ namespace App\Controllers;
use Analytics\AnalyticsTrait; use Analytics\AnalyticsTrait;
use App\Entities\Podcast; use App\Entities\Podcast;
use App\Models\EpisodeModel; use App\Models\EpisodeModel;
use App\Models\NoteModel;
use App\Models\PodcastModel; use App\Models\PodcastModel;
use App\Models\StatusModel;
use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Exceptions\PageNotFoundException;
class PodcastController extends BaseController class PodcastController extends BaseController
@ -64,7 +64,7 @@ class PodcastController extends BaseController
if (! ($cachedView = cache($cacheName))) { if (! ($cachedView = cache($cacheName))) {
$data = [ $data = [
'podcast' => $this->podcast, 'podcast' => $this->podcast,
'notes' => (new NoteModel())->getActorPublishedNotes($this->podcast->actor_id), 'statuses' => (new StatusModel())->getActorPublishedStatuses($this->podcast->actor_id),
]; ];
// if user is logged in then send to the authenticated activity view // if user is logged in then send to the authenticated activity view

View File

@ -10,21 +10,21 @@ declare(strict_types=1);
namespace App\Controllers; namespace App\Controllers;
use ActivityPub\Controllers\NoteController as ActivityPubNoteController; use ActivityPub\Controllers\StatusController as ActivityPubStatusController;
use ActivityPub\Entities\Note as ActivityPubNote; use ActivityPub\Entities\Status as ActivityPubStatus;
use Analytics\AnalyticsTrait; use Analytics\AnalyticsTrait;
use App\Entities\Actor; use App\Entities\Actor;
use App\Entities\Note as CastopodNote;
use App\Entities\Podcast; use App\Entities\Podcast;
use App\Entities\Status as CastopodStatus;
use App\Models\EpisodeModel; use App\Models\EpisodeModel;
use App\Models\NoteModel;
use App\Models\PodcastModel; use App\Models\PodcastModel;
use App\Models\StatusModel;
use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\URI;
use CodeIgniter\I18n\Time; use CodeIgniter\I18n\Time;
class NoteController extends ActivityPubNoteController class StatusController extends ActivityPubStatusController
{ {
use AnalyticsTrait; use AnalyticsTrait;
@ -50,9 +50,9 @@ class NoteController extends ActivityPubNoteController
if ( if (
count($params) > 1 && count($params) > 1 &&
($note = (new NoteModel())->getNoteById($params[1])) !== null ($status = (new StatusModel())->getStatusById($params[1])) !== null
) { ) {
$this->note = $note; $this->status = $status;
unset($params[0]); unset($params[0]);
unset($params[1]); unset($params[1]);
@ -72,7 +72,7 @@ class NoteController extends ActivityPubNoteController
'_', '_',
array_filter([ array_filter([
'page', 'page',
"note#{$this->note->id}", "status#{$this->status->id}",
service('request') service('request')
->getLocale(), ->getLocale(),
can_user_interact() ? '_authenticated' : null, can_user_interact() ? '_authenticated' : null,
@ -83,15 +83,15 @@ class NoteController extends ActivityPubNoteController
$data = [ $data = [
'podcast' => $this->podcast, 'podcast' => $this->podcast,
'actor' => $this->actor, 'actor' => $this->actor,
'note' => $this->note, 'status' => $this->status,
]; ];
// if user is logged in then send to the authenticated activity view // if user is logged in then send to the authenticated activity view
if (can_user_interact()) { if (can_user_interact()) {
helper('form'); helper('form');
return view('podcast/note_authenticated', $data); return view('podcast/status_authenticated', $data);
} }
return view('podcast/note', $data, [ return view('podcast/status', $data, [
'cache' => DECADE, 'cache' => DECADE,
'cache_name' => $cacheName, 'cache_name' => $cacheName,
]); ]);
@ -116,7 +116,7 @@ class NoteController extends ActivityPubNoteController
$message = $this->request->getPost('message'); $message = $this->request->getPost('message');
$newNote = new CastopodNote([ $newStatus = new CastopodStatus([
'actor_id' => interact_as_actor_id(), 'actor_id' => interact_as_actor_id(),
'published_at' => Time::now(), 'published_at' => Time::now(),
'created_by' => user_id(), 'created_by' => user_id(),
@ -129,23 +129,23 @@ class NoteController extends ActivityPubNoteController
($params = extract_params_from_episode_uri(new URI($episodeUri))) && ($params = extract_params_from_episode_uri(new URI($episodeUri))) &&
($episode = (new EpisodeModel())->getEpisodeBySlug($params['podcastName'], $params['episodeSlug'])) ($episode = (new EpisodeModel())->getEpisodeBySlug($params['podcastName'], $params['episodeSlug']))
) { ) {
$newNote->episode_id = $episode->id; $newStatus->episode_id = $episode->id;
} }
$newNote->message = $message; $newStatus->message = $message;
$noteModel = new NoteModel(); $statusModel = new StatusModel();
if ( if (
! $noteModel ! $statusModel
->addNote($newNote, ! (bool) $newNote->episode_id, true) ->addStatus($newStatus, ! (bool) $newStatus->episode_id, true)
) { ) {
return redirect() return redirect()
->back() ->back()
->withInput() ->withInput()
->with('errors', $noteModel->errors()); ->with('errors', $statusModel->errors());
} }
// Note has been successfully created // Status has been successfully created
return redirect()->back(); return redirect()->back();
} }
@ -162,36 +162,36 @@ class NoteController extends ActivityPubNoteController
->with('errors', $this->validator->getErrors()); ->with('errors', $this->validator->getErrors());
} }
$newNote = new ActivityPubNote([ $newStatus = new ActivityPubStatus([
'actor_id' => interact_as_actor_id(), 'actor_id' => interact_as_actor_id(),
'in_reply_to_id' => $this->note->id, 'in_reply_to_id' => $this->status->id,
'message' => $this->request->getPost('message'), 'message' => $this->request->getPost('message'),
'published_at' => Time::now(), 'published_at' => Time::now(),
'created_by' => user_id(), 'created_by' => user_id(),
]); ]);
$noteModel = new NoteModel(); $statusModel = new StatusModel();
if (! $noteModel->addReply($newNote)) { if (! $statusModel->addReply($newStatus)) {
return redirect() return redirect()
->back() ->back()
->withInput() ->withInput()
->with('errors', $noteModel->errors()); ->with('errors', $statusModel->errors());
} }
// Reply note without preview card has been successfully created // Reply status without preview card has been successfully created
return redirect()->back(); return redirect()->back();
} }
public function attemptFavourite(): RedirectResponse public function attemptFavourite(): RedirectResponse
{ {
model('FavouriteModel')->toggleFavourite(interact_as_actor(), $this->note); model('FavouriteModel')->toggleFavourite(interact_as_actor(), $this->status);
return redirect()->back(); return redirect()->back();
} }
public function attemptReblog(): RedirectResponse public function attemptReblog(): RedirectResponse
{ {
(new NoteModel())->toggleReblog(interact_as_actor(), $this->note); (new StatusModel())->toggleReblog(interact_as_actor(), $this->status);
return redirect()->back(); return redirect()->back();
} }
@ -230,20 +230,20 @@ class NoteController extends ActivityPubNoteController
$cacheName = implode( $cacheName = implode(
'_', '_',
array_filter(['page', "note#{$this->note->id}", "remote_{$action}", service('request') ->getLocale()]), array_filter(['page', "status#{$this->status->id}", "remote_{$action}", service('request') ->getLocale()]),
); );
if (! ($cachedView = cache($cacheName))) { if (! ($cachedView = cache($cacheName))) {
$data = [ $data = [
'podcast' => $this->podcast, 'podcast' => $this->podcast,
'actor' => $this->actor, 'actor' => $this->actor,
'note' => $this->note, 'status' => $this->status,
'action' => $action, 'action' => $action,
]; ];
helper('form'); helper('form');
return view('podcast/note_remote_action', $data, [ return view('podcast/status_remote_action', $data, [
'cache' => DECADE, 'cache' => DECADE,
'cache_name' => $cacheName, 'cache_name' => $cacheName,
]); ]);

View File

@ -157,7 +157,7 @@ class AddEpisodes extends Migration
'unsigned' => true, 'unsigned' => true,
'default' => 0, 'default' => 0,
], ],
'notes_total' => [ 'statuses_total' => [
'type' => 'INT', 'type' => 'INT',
'unsigned' => true, 'unsigned' => true,
'default' => 0, 'default' => 0,

View File

@ -3,7 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
/** /**
* Class AddEpisodeIdToNotes Adds episode_id field to activitypub_notes table in database * Class AddEpisodeIdToStatuses Adds episode_id field to activitypub_statuses table in database
* *
* @copyright 2020 Podlibre * @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
@ -14,23 +14,23 @@ namespace App\Database\Migrations;
use CodeIgniter\Database\Migration; use CodeIgniter\Database\Migration;
class AddEpisodeIdToNotes extends Migration class AddEpisodeIdToStatuses extends Migration
{ {
public function up(): void public function up(): void
{ {
$prefix = $this->db->getPrefix(); $prefix = $this->db->getPrefix();
$createQuery = <<<CODE_SAMPLE $createQuery = <<<CODE_SAMPLE
ALTER TABLE {$prefix}activitypub_notes ALTER TABLE {$prefix}activitypub_statuses
ADD COLUMN `episode_id` INT UNSIGNED NULL AFTER `replies_count`, ADD COLUMN `episode_id` INT UNSIGNED NULL AFTER `replies_count`,
ADD FOREIGN KEY {$prefix}activitypub_notes_episode_id_foreign(episode_id) REFERENCES {$prefix}episodes(id) ON DELETE CASCADE; ADD FOREIGN KEY {$prefix}activitypub_statuses_episode_id_foreign(episode_id) REFERENCES {$prefix}episodes(id) ON DELETE CASCADE;
CODE_SAMPLE; CODE_SAMPLE;
$this->db->query($createQuery); $this->db->query($createQuery);
} }
public function down(): void public function down(): void
{ {
$this->forge->dropForeignKey('activitypub_notes', 'activitypub_notes_episode_id_foreign'); $this->forge->dropForeignKey('activitypub_statuses', 'activitypub_statuses_episode_id_foreign');
$this->forge->dropColumn('activitypub_notes', 'episode_id'); $this->forge->dropColumn('activitypub_statuses', 'episode_id');
} }
} }

View File

@ -3,7 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
/** /**
* Class AddCreatedByToNotes Adds created_by field to activitypub_notes table in database * Class AddCreatedByToStatuses Adds created_by field to activitypub_statuses table in database
* *
* @copyright 2020 Podlibre * @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
@ -14,23 +14,23 @@ namespace App\Database\Migrations;
use CodeIgniter\Database\Migration; use CodeIgniter\Database\Migration;
class AddCreatedByToNotes extends Migration class AddCreatedByToStatuses extends Migration
{ {
public function up(): void public function up(): void
{ {
$prefix = $this->db->getPrefix(); $prefix = $this->db->getPrefix();
$createQuery = <<<CODE_SAMPLE $createQuery = <<<CODE_SAMPLE
ALTER TABLE {$prefix}activitypub_notes ALTER TABLE {$prefix}activitypub_statuses
ADD COLUMN `created_by` INT UNSIGNED AFTER `episode_id`, ADD COLUMN `created_by` INT UNSIGNED AFTER `episode_id`,
ADD FOREIGN KEY {$prefix}activitypub_notes_created_by_foreign(created_by) REFERENCES {$prefix}users(id) ON DELETE CASCADE; ADD FOREIGN KEY {$prefix}activitypub_statuses_created_by_foreign(created_by) REFERENCES {$prefix}users(id) ON DELETE CASCADE;
CODE_SAMPLE; CODE_SAMPLE;
$this->db->query($createQuery); $this->db->query($createQuery);
} }
public function down(): void public function down(): void
{ {
$this->forge->dropForeignKey('activitypub_notes', 'activitypub_notes_created_by_foreign'); $this->forge->dropForeignKey('activitypub_statuses', 'activitypub_statuses_created_by_foreign');
$this->forge->dropColumn('activitypub_notes', 'created_by'); $this->forge->dropColumn('activitypub_statuses', 'created_by');
} }
} }

View File

@ -162,13 +162,13 @@ class AuthSeeder extends Seeder
[ [
'name' => 'manage_publications', 'name' => 'manage_publications',
'description' => 'description' =>
'Publish / unpublish episodes & notes of a podcast', 'Publish / unpublish episodes & statuses of a podcast',
'has_permission' => ['podcast_admin'], 'has_permission' => ['podcast_admin'],
], ],
[ [
'name' => 'interact_as', 'name' => 'interact_as',
'description' => 'description' =>
'Interact as the podcast to favourite / share or reply to notes.', 'Interact as the podcast to favourite / share or reply to statuses.',
'has_permission' => ['podcast_admin'], 'has_permission' => ['podcast_admin'],
], ],
], ],

View File

@ -11,10 +11,10 @@ declare(strict_types=1);
namespace App\Entities; namespace App\Entities;
use App\Libraries\SimpleRSSElement; use App\Libraries\SimpleRSSElement;
use App\Models\NoteModel;
use App\Models\PersonModel; use App\Models\PersonModel;
use App\Models\PodcastModel; use App\Models\PodcastModel;
use App\Models\SoundbiteModel; use App\Models\SoundbiteModel;
use App\Models\StatusModel;
use CodeIgniter\Entity\Entity; use CodeIgniter\Entity\Entity;
use CodeIgniter\Files\File; use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Files\UploadedFile; use CodeIgniter\HTTP\Files\UploadedFile;
@ -67,7 +67,7 @@ use RuntimeException;
* @property string $custom_rss_string * @property string $custom_rss_string
* @property int $favourites_total * @property int $favourites_total
* @property int $reblogs_total * @property int $reblogs_total
* @property int $notes_total * @property int $statuses_total
* @property int $created_by * @property int $created_by
* @property int $updated_by * @property int $updated_by
* @property string $publication_status; * @property string $publication_status;
@ -117,9 +117,9 @@ class Episode extends Entity
protected ?array $soundbites = null; protected ?array $soundbites = null;
/** /**
* @var Note[]|null * @var Status[]|null
*/ */
protected ?array $notes = null; protected ?array $statuses = null;
protected ?Location $location = null; protected ?Location $location = null;
@ -165,7 +165,7 @@ class Episode extends Entity
'custom_rss' => '?json-array', 'custom_rss' => '?json-array',
'favourites_total' => 'integer', 'favourites_total' => 'integer',
'reblogs_total' => 'integer', 'reblogs_total' => 'integer',
'notes_total' => 'integer', 'statuses_total' => 'integer',
'created_by' => 'integer', 'created_by' => 'integer',
'updated_by' => 'integer', 'updated_by' => 'integer',
]; ];
@ -382,19 +382,19 @@ class Episode extends Entity
} }
/** /**
* @return Note[] * @return Status[]
*/ */
public function getNotes(): array public function getStatuses(): array
{ {
if ($this->id === null) { if ($this->id === null) {
throw new RuntimeException('Episode must be created before getting soundbites.'); throw new RuntimeException('Episode must be created before getting soundbites.');
} }
if ($this->notes === null) { if ($this->statuses === null) {
$this->notes = (new NoteModel())->getEpisodeNotes($this->id); $this->statuses = (new StatusModel())->getEpisodeStatuses($this->id);
} }
return $this->notes; return $this->statuses;
} }
public function getLink(): string public function getLink(): string

View File

@ -10,7 +10,7 @@ declare(strict_types=1);
namespace App\Entities; namespace App\Entities;
use ActivityPub\Entities\Note as ActivityPubNote; use ActivityPub\Entities\Status as ActivityPubStatus;
use App\Models\EpisodeModel; use App\Models\EpisodeModel;
use RuntimeException; use RuntimeException;
@ -18,7 +18,7 @@ use RuntimeException;
* @property int|null $episode_id * @property int|null $episode_id
* @property Episode|null $episode * @property Episode|null $episode
*/ */
class Note extends ActivityPubNote class Status extends ActivityPubStatus
{ {
protected ?Episode $episode = null; protected ?Episode $episode = null;
@ -41,12 +41,12 @@ class Note extends ActivityPubNote
]; ];
/** /**
* Returns the note's attached episode * Returns the status' attached episode
*/ */
public function getEpisode(): ?Episode public function getEpisode(): ?Episode
{ {
if ($this->episode_id === null) { if ($this->episode_id === null) {
throw new RuntimeException('Note must have an episode_id before getting episode.'); throw new RuntimeException('Status must have an episode_id before getting episode.');
} }
if ($this->episode === null) { if ($this->episode === null) {

View File

@ -26,7 +26,7 @@ return [
one {# total share} one {# total share}
other {# total shares} other {# total shares}
}', }',
'total_notes' => '{numberOfTotalNotes, plural, 'total_statuses' => '{numberOfTotalStatuses, plural,
one {# note} one {# note}
other {# total notes} other {# total notes}
}', }',
@ -112,8 +112,8 @@ return [
'submit_edit' => 'Save episode', 'submit_edit' => 'Save episode',
], ],
'publish_form' => [ 'publish_form' => [
'note' => 'Your note', 'status' => 'Your note',
'note_hint' => 'status_hint' =>
'The message you write will be broadcasted to all your followers in the fediverse.', 'The message you write will be broadcasted to all your followers in the fediverse.',
'publication_date' => 'Publication date', 'publication_date' => 'Publication date',
'publication_method' => [ 'publication_method' => [

View File

@ -223,7 +223,7 @@ return [
one {<span class="font-semibold">#</span> follower} one {<span class="font-semibold">#</span> follower}
other {<span class="font-semibold">#</span> followers} other {<span class="font-semibold">#</span> followers}
}', }',
'notes' => '{numberOfNotes, plural, 'statuses' => '{numberOfStatuses, plural,
one {<span class="font-semibold">#</span> note} one {<span class="font-semibold">#</span> note}
other {<span class="font-semibold">#</span> notes} other {<span class="font-semibold">#</span> notes}
}', }',

View File

@ -10,7 +10,7 @@ declare(strict_types=1);
return [ return [
'title' => "{actorDisplayName}'s Note", 'title' => "{actorDisplayName}'s Note",
'back_to_actor_notes' => 'Back to {actor} notes', 'back_to_actor_statuses' => 'Back to {actor} notes',
'actor_shared' => '{actor} shared', 'actor_shared' => '{actor} shared',
'reply_to' => 'Reply to @{actorUsername}', 'reply_to' => 'Reply to @{actorUsername}',
'form' => [ 'form' => [

View File

@ -26,7 +26,7 @@ return [
one {# partage en tout} one {# partage en tout}
other {# partages en tout} other {# partages en tout}
}', }',
'total_notes' => '{numberOfTotalNotes, plural, 'total_statuses' => '{numberOfTotalStatuses, plural,
one {# note} one {# note}
other {# notes} other {# notes}
}', }',
@ -115,8 +115,8 @@ return [
'submit_edit' => 'Enregistrer lépisode', 'submit_edit' => 'Enregistrer lépisode',
], ],
'publish_form' => [ 'publish_form' => [
'note' => 'Votre note', 'status' => 'Votre note',
'note_hint' => 'status_hint' =>
'Le message que vous écrirez sera diffusé à toutes les personnes qui vous suivent dans le fédiverse.', 'Le message que vous écrirez sera diffusé à toutes les personnes qui vous suivent dans le fédiverse.',
'publication_date' => 'Date de publication', 'publication_date' => 'Date de publication',
'publication_date_clear' => 'Effacer la date de publication', 'publication_date_clear' => 'Effacer la date de publication',

View File

@ -225,7 +225,7 @@ return [
one {<span class="font-semibold">#</span> abonné·e} one {<span class="font-semibold">#</span> abonné·e}
other {<span class="font-semibold">#</span> abonné·e·s} other {<span class="font-semibold">#</span> abonné·e·s}
}', }',
'notes' => '{numberOfNotes, plural, 'notes' => '{numberOfStatuses, plural,
one {<span class="font-semibold">#</span> note} one {<span class="font-semibold">#</span> note}
other {<span class="font-semibold">#</span> notes} other {<span class="font-semibold">#</span> notes}
}', }',

View File

@ -10,7 +10,7 @@ declare(strict_types=1);
return [ return [
'title' => 'Note de {actorDisplayName}', 'title' => 'Note de {actorDisplayName}',
'back_to_actor_notes' => 'Retour aux notes de {actor}', 'back_to_actor_statuses' => 'Retour aux notes de {actor}',
'actor_shared' => '{actor} a partagé', 'actor_shared' => '{actor} a partagé',
'reply_to' => 'Répondre à @{actorUsername}', 'reply_to' => 'Répondre à @{actorUsername}',
'form' => [ 'form' => [

View File

@ -14,19 +14,19 @@ declare(strict_types=1);
namespace ActivityPub\Activities; namespace ActivityPub\Activities;
use ActivityPub\Core\Activity; use ActivityPub\Core\Activity;
use ActivityPub\Entities\Note; use ActivityPub\Entities\Status;
class AnnounceActivity extends Activity class AnnounceActivity extends Activity
{ {
protected string $type = 'Announce'; protected string $type = 'Announce';
public function __construct(Note $reblogNote) public function __construct(Status $reblogStatus)
{ {
$this->actor = $reblogNote->actor->uri; $this->actor = $reblogStatus->actor->uri;
$this->object = $reblogNote->reblog_of_note->uri; $this->object = $reblogStatus->reblog_of_status->uri;
$this->published = $reblogNote->published_at->format(DATE_W3C); $this->published = $reblogStatus->published_at->format(DATE_W3C);
$this->cc = [$reblogNote->actor->uri, $reblogNote->actor->followers_url]; $this->cc = [$reblogStatus->actor->uri, $reblogStatus->actor->followers_url];
} }
} }

View File

@ -13,7 +13,7 @@ $routes->addPlaceholder(
'uuid', 'uuid',
'[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}', '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}',
); );
$routes->addPlaceholder('noteAction', '\bfavourite|\breblog|\breply'); $routes->addPlaceholder('statusAction', '\bfavourite|\breblog|\breply');
/** /**
* ActivityPub routes file * ActivityPub routes file
@ -54,24 +54,24 @@ $routes->group('', [
]); ]);
}); });
// Note // Status
$routes->post('notes/new', 'NoteController::attemptCreate/$1', [ $routes->post('statuses/new', 'StatusController::attemptCreate/$1', [
'as' => 'note-attempt-create', 'as' => 'status-attempt-create',
]); ]);
$routes->get('notes/(:uuid)', 'NoteController/$1', [ $routes->get('statuses/(:uuid)', 'StatusController/$1', [
'as' => 'note', 'as' => 'status',
]); ]);
$routes->get('notes/(:uuid)/replies', 'NoteController/$1', [ $routes->get('statuses/(:uuid)/replies', 'StatusController/$1', [
'as' => 'note-replies', 'as' => 'status-replies',
]); ]);
$routes->post( $routes->post(
'notes/(:uuid)/remote/(:noteAction)', 'statuses/(:uuid)/remote/(:statusAction)',
'NoteController::attemptRemoteAction/$1/$2/$3', 'StatusController::attemptRemoteAction/$1/$2/$3',
[ [
'as' => 'note-attempt-remote-action', 'as' => 'status-attempt-remote-action',
], ],
); );

View File

@ -12,7 +12,7 @@ namespace ActivityPub\Controllers;
use ActivityPub\Config\ActivityPub; use ActivityPub\Config\ActivityPub;
use ActivityPub\Entities\Actor; use ActivityPub\Entities\Actor;
use ActivityPub\Entities\Note; use ActivityPub\Entities\Status;
use ActivityPub\Objects\OrderedCollectionObject; use ActivityPub\Objects\OrderedCollectionObject;
use ActivityPub\Objects\OrderedCollectionPage; use ActivityPub\Objects\OrderedCollectionPage;
use CodeIgniter\Controller; use CodeIgniter\Controller;
@ -101,30 +101,30 @@ class ActorController extends Controller
->setJSON([]); ->setJSON([]);
} }
$replyToNote = model('NoteModel') $replyToStatus = model('StatusModel')
->getNoteByUri($payload->object->inReplyTo); ->getStatusByUri($payload->object->inReplyTo);
$reply = null; $reply = null;
if ($replyToNote !== null) { if ($replyToStatus !== null) {
// TODO: strip content from html to retrieve message // TODO: strip content from html to retrieve message
// remove all html tags and reconstruct message with mentions? // remove all html tags and reconstruct message with mentions?
extract_text_from_html($payload->object->content); extract_text_from_html($payload->object->content);
$reply = new Note([ $reply = new Status([
'uri' => $payload->object->id, 'uri' => $payload->object->id,
'actor_id' => $payloadActor->id, 'actor_id' => $payloadActor->id,
'in_reply_to_id' => $replyToNote->id, 'in_reply_to_id' => $replyToStatus->id,
'message' => $payload->object->content, 'message' => $payload->object->content,
'published_at' => Time::parse($payload->object->published), 'published_at' => Time::parse($payload->object->published),
]); ]);
} }
if ($reply !== null) { if ($reply !== null) {
$noteId = model('NoteModel') $statusId = model('StatusModel')
->addReply($reply, true, false); ->addReply($reply, true, false);
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
'note_id' => $noteId, 'status_id' => $statusId,
]); ]);
} }
@ -135,12 +135,12 @@ class ActorController extends Controller
return $this->response->setStatusCode(501) return $this->response->setStatusCode(501)
->setJSON([]); ->setJSON([]);
case 'Delete': case 'Delete':
$noteToDelete = model('NoteModel') $statusToDelete = model('StatusModel')
->getNoteByUri($payload->object->id); ->getStatusByUri($payload->object->id);
if ($noteToDelete !== null) { if ($statusToDelete !== null) {
model('NoteModel') model('StatusModel')
->removeNote($noteToDelete, false); ->removeStatus($statusToDelete, false);
} }
return $this->response->setStatusCode(200) return $this->response->setStatusCode(200)
@ -158,35 +158,35 @@ class ActorController extends Controller
->setJSON([]); ->setJSON([]);
case 'Like': case 'Like':
// get favourited note // get favourited status
$note = model('NoteModel') $status = model('StatusModel')
->getNoteByUri($payload->object); ->getStatusByUri($payload->object);
if ($note !== null) { if ($status !== null) {
// Like side-effect // Like side-effect
model('FavouriteModel') model('FavouriteModel')
->addFavourite($payloadActor, $note, false); ->addFavourite($payloadActor, $status, false);
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
'note_id' => $note->id, 'status_id' => $status->id,
]); ]);
} }
return $this->response->setStatusCode(200) return $this->response->setStatusCode(200)
->setJSON([]); ->setJSON([]);
case 'Announce': case 'Announce':
$note = model('NoteModel') $status = model('StatusModel')
->getNoteByUri($payload->object); ->getStatusByUri($payload->object);
if ($note !== null) { if ($status !== null) {
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
'note_id' => $note->id, 'status_id' => $status->id,
]); ]);
model('NoteModel') model('StatusModel')
->reblog($payloadActor, $note, false); ->reblog($payloadActor, $status, false);
} }
return $this->response->setStatusCode(200) return $this->response->setStatusCode(200)
@ -204,45 +204,45 @@ class ActorController extends Controller
return $this->response->setStatusCode(202) return $this->response->setStatusCode(202)
->setJSON([]); ->setJSON([]);
case 'Like': case 'Like':
$note = model('NoteModel') $status = model('StatusModel')
->getNoteByUri($payload->object->object); ->getStatusByUri($payload->object->object);
if ($note !== null) { if ($status !== null) {
// revert side-effect by removing favourite from database // revert side-effect by removing favourite from database
model('FavouriteModel') model('FavouriteModel')
->removeFavourite($payloadActor, $note, false); ->removeFavourite($payloadActor, $status, false);
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
'note_id' => $note->id, 'status_id' => $status->id,
]); ]);
} }
return $this->response->setStatusCode(200) return $this->response->setStatusCode(200)
->setJSON([]); ->setJSON([]);
case 'Announce': case 'Announce':
$note = model('NoteModel') $status = model('StatusModel')
->getNoteByUri($payload->object->object); ->getStatusByUri($payload->object->object);
$reblogNote = null; $reblogStatus = null;
if ($note !== null) { if ($status !== null) {
$reblogNote = model('NoteModel') $reblogStatus = model('StatusModel')
->where([ ->where([
'actor_id' => $payloadActor->id, 'actor_id' => $payloadActor->id,
'reblog_of_id' => service('uuid') 'reblog_of_id' => service('uuid')
->fromString($note->id) ->fromString($status->id)
->getBytes(), ->getBytes(),
]) ])
->first(); ->first();
} }
if ($reblogNote !== null) { if ($reblogStatus !== null) {
model('NoteModel') model('StatusModel')
->undoReblog($reblogNote, false); ->undoReblog($reblogStatus, false);
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
'note_id' => $note->id, 'status_id' => $status->id,
]); ]);
} }

View File

@ -36,7 +36,7 @@ class SchedulerController extends Controller
// set activity status to delivered // set activity status to delivered
model('ActivityModel') model('ActivityModel')
->update($scheduledActivity->id, [ ->update($scheduledActivity->id, [
'status' => 'delivered', 'task_status' => 'delivered',
]); ]);
} }
} }

View File

@ -11,7 +11,7 @@ declare(strict_types=1);
namespace ActivityPub\Controllers; namespace ActivityPub\Controllers;
use ActivityPub\Config\ActivityPub; use ActivityPub\Config\ActivityPub;
use ActivityPub\Entities\Note; use ActivityPub\Entities\Status;
use ActivityPub\Objects\OrderedCollectionObject; use ActivityPub\Objects\OrderedCollectionObject;
use ActivityPub\Objects\OrderedCollectionPage; use ActivityPub\Objects\OrderedCollectionPage;
use CodeIgniter\Controller; use CodeIgniter\Controller;
@ -21,14 +21,14 @@ use CodeIgniter\HTTP\Response;
use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\I18n\Time; use CodeIgniter\I18n\Time;
class NoteController extends Controller class StatusController extends Controller
{ {
/** /**
* @var string[] * @var string[]
*/ */
protected $helpers = ['activitypub']; protected $helpers = ['activitypub'];
protected Note $note; protected Status $status;
protected ActivityPub $config; protected ActivityPub $config;
@ -39,11 +39,11 @@ class NoteController extends Controller
public function _remap(string $method, string ...$params): mixed public function _remap(string $method, string ...$params): mixed
{ {
if (($note = model('NoteModel')->getNoteById($params[0])) === null) { if (($status = model('StatusModel')->getStatusById($params[0])) === null) {
throw PageNotFoundException::forPageNotFound(); throw PageNotFoundException::forPageNotFound();
} }
$this->note = $note; $this->status = $status;
unset($params[0]); unset($params[0]);
@ -56,7 +56,7 @@ class NoteController extends Controller
public function index(): Response public function index(): Response
{ {
$noteObjectClass = $this->config->noteObject; $noteObjectClass = $this->config->noteObject;
$noteObject = new $noteObjectClass($this->note); $noteObject = new $noteObjectClass($this->status);
return $this->response return $this->response
->setContentType('application/activity+json') ->setContentType('application/activity+json')
@ -69,22 +69,22 @@ class NoteController extends Controller
public function replies(): Response public function replies(): Response
{ {
/** /**
* get note replies * get status replies
*/ */
$noteReplies = model('NoteModel') $statusReplies = model('StatusModel')
->where('in_reply_to_id', service('uuid') ->fromString($this->note->id) ->getBytes()) ->where('in_reply_to_id', service('uuid') ->fromString($this->status->id) ->getBytes())
->where('`published_at` <= NOW()', null, false) ->where('`published_at` <= NOW()', null, false)
->orderBy('published_at', 'ASC'); ->orderBy('published_at', 'ASC');
$pageNumber = (int) $this->request->getGet('page'); $pageNumber = (int) $this->request->getGet('page');
if ($pageNumber < 1) { if ($pageNumber < 1) {
$noteReplies->paginate(12); $statusReplies->paginate(12);
$pager = $noteReplies->pager; $pager = $statusReplies->pager;
$collection = new OrderedCollectionObject(null, $pager); $collection = new OrderedCollectionObject(null, $pager);
} else { } else {
$paginatedReplies = $noteReplies->paginate(12, 'default', $pageNumber); $paginatedReplies = $statusReplies->paginate(12, 'default', $pageNumber);
$pager = $noteReplies->pager; $pager = $statusReplies->pager;
$orderedItems = []; $orderedItems = [];
$noteObjectClass = $this->config->noteObject; $noteObjectClass = $this->config->noteObject;
@ -118,21 +118,21 @@ class NoteController extends Controller
->with('errors', $this->validator->getErrors()); ->with('errors', $this->validator->getErrors());
} }
$newNote = new Note([ $newStatus = new Status([
'actor_id' => $this->request->getPost('actor_id'), 'actor_id' => $this->request->getPost('actor_id'),
'message' => $this->request->getPost('message'), 'message' => $this->request->getPost('message'),
'published_at' => Time::now(), 'published_at' => Time::now(),
]); ]);
if (! model('NoteModel')->addNote($newNote)) { if (! model('StatusModel')->addStatus($newStatus)) {
return redirect() return redirect()
->back() ->back()
->withInput() ->withInput()
// TODO: translate // TODO: translate
->with('error', "Couldn't create Note"); ->with('error', "Couldn't create Status");
} }
// Note without preview card has been successfully created // Status without preview card has been successfully created
return redirect()->back(); return redirect()->back();
} }
@ -153,7 +153,7 @@ class NoteController extends Controller
->getActorById($this->request->getPost('actor_id')); ->getActorById($this->request->getPost('actor_id'));
model('FavouriteModel') model('FavouriteModel')
->toggleFavourite($actor, $this->note->id); ->toggleFavourite($actor, $this->status->id);
return redirect()->back(); return redirect()->back();
} }
@ -174,8 +174,8 @@ class NoteController extends Controller
$actor = model('ActorModel') $actor = model('ActorModel')
->getActorById($this->request->getPost('actor_id')); ->getActorById($this->request->getPost('actor_id'));
model('NoteModel') model('StatusModel')
->toggleReblog($actor, $this->note); ->toggleReblog($actor, $this->status);
return redirect()->back(); return redirect()->back();
} }
@ -194,14 +194,14 @@ class NoteController extends Controller
->with('errors', $this->validator->getErrors()); ->with('errors', $this->validator->getErrors());
} }
$newReplyNote = new Note([ $newReplyStatus = new Status([
'actor_id' => $this->request->getPost('actor_id'), 'actor_id' => $this->request->getPost('actor_id'),
'in_reply_to_id' => $this->note->id, 'in_reply_to_id' => $this->status->id,
'message' => $this->request->getPost('message'), 'message' => $this->request->getPost('message'),
'published_at' => Time::now(), 'published_at' => Time::now(),
]); ]);
if (! model('NoteModel')->addReply($newReplyNote)) { if (! model('StatusModel')->addReply($newReplyStatus)) {
return redirect() return redirect()
->back() ->back()
->withInput() ->withInput()
@ -209,7 +209,7 @@ class NoteController extends Controller
->with('error', "Couldn't create Reply"); ->with('error', "Couldn't create Reply");
} }
// Reply note without preview card has been successfully created // Reply status without preview card has been successfully created
return redirect()->back(); return redirect()->back();
} }
@ -249,33 +249,33 @@ class NoteController extends Controller
); );
if (! $ostatusKey) { if (! $ostatusKey) {
// TODO: error, couldn't remote favourite/share/reply to note // TODO: error, couldn't remote favourite/share/reply to status
// The instance doesn't allow its users remote actions on notes // The instance doesn't allow its users remote actions on statuses
return $this->response->setJSON([]); return $this->response->setJSON([]);
} }
return redirect()->to( return redirect()->to(
str_replace('{uri}', urlencode($this->note->uri), $data->links[$ostatusKey]->template), str_replace('{uri}', urlencode($this->status->uri), $data->links[$ostatusKey]->template),
); );
} }
public function attemptBlockActor(): RedirectResponse public function attemptBlockActor(): RedirectResponse
{ {
model('ActorModel')->blockActor($this->note->actor->id); model('ActorModel')->blockActor($this->status->actor->id);
return redirect()->back(); return redirect()->back();
} }
public function attemptBlockDomain(): RedirectResponse public function attemptBlockDomain(): RedirectResponse
{ {
model('BlockedDomainModel')->blockDomain($this->note->actor->domain); model('BlockedDomainModel')->blockDomain($this->status->actor->domain);
return redirect()->back(); return redirect()->back();
} }
public function attemptDelete(): RedirectResponse public function attemptDelete(): RedirectResponse
{ {
model('NoteModel', false)->removeNote($this->note); model('StatusModel', false)->removeStatus($this->status);
return redirect()->back(); return redirect()->back();
} }

View File

@ -93,7 +93,7 @@ class AddActors extends Migration
'unsigned' => true, 'unsigned' => true,
'default' => 0, 'default' => 0,
], ],
'notes_count' => [ 'statuses_count' => [
'type' => 'INT', 'type' => 'INT',
'unsigned' => true, 'unsigned' => true,
'default' => 0, 'default' => 0,

View File

@ -3,7 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
/** /**
* Class AddNotes Creates activitypub_notes table in database * Class AddStatuses Creates activitypub_statuses table in database
* *
* @copyright 2021 Podlibre * @copyright 2021 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
@ -14,7 +14,7 @@ namespace ActivityPub\Database\Migrations;
use CodeIgniter\Database\Migration; use CodeIgniter\Database\Migration;
class AddNotes extends Migration class AddStatuses extends Migration
{ {
public function up(): void public function up(): void
{ {
@ -76,16 +76,16 @@ class AddNotes extends Migration
]); ]);
$this->forge->addPrimaryKey('id'); $this->forge->addPrimaryKey('id');
$this->forge->addUniqueKey('uri'); $this->forge->addUniqueKey('uri');
// FIXME: an actor must reblog a note only once // FIXME: an actor must reblog a status only once
// $this->forge->addUniqueKey(['actor_id', 'reblog_of_id']); // $this->forge->addUniqueKey(['actor_id', 'reblog_of_id']);
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('in_reply_to_id', 'activitypub_notes', 'id', '', 'CASCADE'); $this->forge->addForeignKey('in_reply_to_id', 'activitypub_statuses', 'id', '', 'CASCADE');
$this->forge->addForeignKey('reblog_of_id', 'activitypub_notes', 'id', '', 'CASCADE'); $this->forge->addForeignKey('reblog_of_id', 'activitypub_statuses', 'id', '', 'CASCADE');
$this->forge->createTable('activitypub_notes'); $this->forge->createTable('activitypub_statuses');
} }
public function down(): void public function down(): void
{ {
$this->forge->dropTable('activitypub_notes'); $this->forge->dropTable('activitypub_statuses');
} }
} }

View File

@ -32,7 +32,7 @@ class AddActivities extends Migration
'unsigned' => true, 'unsigned' => true,
'null' => true, 'null' => true,
], ],
'note_id' => [ 'status_id' => [
'type' => 'BINARY', 'type' => 'BINARY',
'constraint' => 16, 'constraint' => 16,
'null' => true, 'null' => true,
@ -44,7 +44,7 @@ class AddActivities extends Migration
'payload' => [ 'payload' => [
'type' => 'JSON', 'type' => 'JSON',
], ],
'status' => [ 'task_status' => [
'type' => 'ENUM', 'type' => 'ENUM',
'constraint' => ['queued', 'delivered'], 'constraint' => ['queued', 'delivered'],
'null' => true, 'null' => true,
@ -62,7 +62,7 @@ class AddActivities extends Migration
$this->forge->addPrimaryKey('id'); $this->forge->addPrimaryKey('id');
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('target_actor_id', 'activitypub_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('target_actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('note_id', 'activitypub_notes', 'id', '', 'CASCADE'); $this->forge->addForeignKey('status_id', 'activitypub_statuses', 'id', '', 'CASCADE');
$this->forge->createTable('activitypub_activities'); $this->forge->createTable('activitypub_activities');
} }

View File

@ -23,15 +23,15 @@ class AddFavourites extends Migration
'type' => 'INT', 'type' => 'INT',
'unsigned' => true, 'unsigned' => true,
], ],
'note_id' => [ 'status_id' => [
'type' => 'BINARY', 'type' => 'BINARY',
'constraint' => 16, 'constraint' => 16,
], ],
]); ]);
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()');
$this->forge->addPrimaryKey(['actor_id', 'note_id']); $this->forge->addPrimaryKey(['actor_id', 'status_id']);
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('note_id', 'activitypub_notes', 'id', '', 'CASCADE'); $this->forge->addForeignKey('status_id', 'activitypub_statuses', 'id', '', 'CASCADE');
$this->forge->createTable('activitypub_favourites'); $this->forge->createTable('activitypub_favourites');
} }

View File

@ -3,7 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
/** /**
* Class AddNotePreviewCards Creates activitypub_notes_preview_cards table in database * Class AddStatusesPreviewCards Creates activitypub_statuses_preview_cards table in database
* *
* @copyright 2021 Podlibre * @copyright 2021 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
@ -14,12 +14,12 @@ namespace ActivityPub\Database\Migrations;
use CodeIgniter\Database\Migration; use CodeIgniter\Database\Migration;
class AddNotesPreviewCards extends Migration class AddStatusesPreviewCards extends Migration
{ {
public function up(): void public function up(): void
{ {
$this->forge->addField([ $this->forge->addField([
'note_id' => [ 'status_id' => [
'type' => 'BINARY', 'type' => 'BINARY',
'constraint' => 16, 'constraint' => 16,
], ],
@ -29,14 +29,14 @@ class AddNotesPreviewCards extends Migration
], ],
]); ]);
$this->forge->addPrimaryKey(['note_id', 'preview_card_id']); $this->forge->addPrimaryKey(['status_id', 'preview_card_id']);
$this->forge->addForeignKey('note_id', 'activitypub_notes', 'id', '', 'CASCADE'); $this->forge->addForeignKey('status_id', 'activitypub_statuses', 'id', '', 'CASCADE');
$this->forge->addForeignKey('preview_card_id', 'activitypub_preview_cards', 'id', '', 'CASCADE'); $this->forge->addForeignKey('preview_card_id', 'activitypub_preview_cards', 'id', '', 'CASCADE');
$this->forge->createTable('activitypub_notes_preview_cards'); $this->forge->createTable('activitypub_statuses_preview_cards');
} }
public function down(): void public function down(): void
{ {
$this->forge->dropTable('activitypub_notes_preview_cards'); $this->forge->dropTable('activitypub_statuses_preview_cards');
} }
} }

View File

@ -19,11 +19,11 @@ use RuntimeException;
* @property Actor $actor * @property Actor $actor
* @property int|null $target_actor_id * @property int|null $target_actor_id
* @property Actor $target_actor * @property Actor $target_actor
* @property string|null $note_id * @property string|null $status_id
* @property Note $note * @property Status $status
* @property string $type * @property string $type
* @property object $payload * @property object $payload
* @property string|null $status * @property string|null $task_status
* @property Time|null $scheduled_at * @property Time|null $scheduled_at
* @property Time $created_at * @property Time $created_at
*/ */
@ -33,12 +33,12 @@ class Activity extends UuidEntity
protected ?Actor $target_actor = null; protected ?Actor $target_actor = null;
protected ?Note $note = null; protected ?Status $status = null;
/** /**
* @var string[] * @var string[]
*/ */
protected $uuids = ['id', 'note_id']; protected $uuids = ['id', 'status_id'];
/** /**
* @var string[] * @var string[]
@ -52,10 +52,10 @@ class Activity extends UuidEntity
'id' => 'string', 'id' => 'string',
'actor_id' => 'integer', 'actor_id' => 'integer',
'target_actor_id' => '?integer', 'target_actor_id' => '?integer',
'note_id' => '?string', 'status_id' => '?string',
'type' => 'string', 'type' => 'string',
'payload' => 'json', 'payload' => 'json',
'status' => '?string', 'task_status' => '?string',
]; ];
public function getActor(): Actor public function getActor(): Actor
@ -86,17 +86,17 @@ class Activity extends UuidEntity
return $this->target_actor; return $this->target_actor;
} }
public function getNote(): Note public function getStatus(): Status
{ {
if ($this->note_id === null) { if ($this->status_id === null) {
throw new RuntimeException('Activity must have a note_id before getting note.'); throw new RuntimeException('Activity must have a status_id before getting status.');
} }
if ($this->note === null) { if ($this->status === null) {
$this->note = model('NoteModel', false) $this->status = model('StatusModel', false)
->getNoteById($this->note_id); ->getStatusById($this->status_id);
} }
return $this->note; return $this->status;
} }
} }

View File

@ -31,7 +31,7 @@ use RuntimeException;
* @property string|null $outbox_url * @property string|null $outbox_url
* @property string|null $followers_url * @property string|null $followers_url
* @property int $followers_count * @property int $followers_count
* @property int $notes_count * @property int $statuses_count
* @property bool $is_blocked * @property bool $is_blocked
* *
* @property Actor[] $followers * @property Actor[] $followers
@ -68,7 +68,7 @@ class Actor extends Entity
'outbox_url' => '?string', 'outbox_url' => '?string',
'followers_url' => '?string', 'followers_url' => '?string',
'followers_count' => 'integer', 'followers_count' => 'integer',
'notes_count' => 'integer', 'statuses_count' => 'integer',
'is_blocked' => 'boolean', 'is_blocked' => 'boolean',
]; ];

View File

@ -14,20 +14,20 @@ use Michalsn\Uuid\UuidEntity;
/** /**
* @property int $actor_id * @property int $actor_id
* @property string $note_id * @property string $status_id
*/ */
class Favourite extends UuidEntity class Favourite extends UuidEntity
{ {
/** /**
* @var string[] * @var string[]
*/ */
protected $uuids = ['note_id']; protected $uuids = ['status_id'];
/** /**
* @var array<string, string> * @var array<string, string>
*/ */
protected $casts = [ protected $casts = [
'actor_id' => 'integer', 'actor_id' => 'integer',
'note_id' => 'string', 'status_id' => 'string',
]; ];
} }

View File

@ -14,7 +14,7 @@ use CodeIgniter\Entity\Entity;
/** /**
* @property int $id * @property int $id
* @property string $note_id * @property string $status_id
* @property string $url * @property string $url
* @property string $title * @property string $title
* @property string $description * @property string $description
@ -33,7 +33,7 @@ class PreviewCard extends Entity
*/ */
protected $casts = [ protected $casts = [
'id' => 'integer', 'id' => 'integer',
'note_id' => 'string', 'status_id' => 'string',
'url' => 'string', 'url' => 'string',
'title' => 'string', 'title' => 'string',
'description' => 'string', 'description' => 'string',

View File

@ -20,9 +20,9 @@ use RuntimeException;
* @property int $actor_id * @property int $actor_id
* @property Actor $actor * @property Actor $actor
* @property string|null $in_reply_to_id * @property string|null $in_reply_to_id
* @property Note|null $reply_to_note * @property Status|null $reply_to_status
* @property string|null $reblog_of_id * @property string|null $reblog_of_id
* @property Note|null $reblog_of_note * @property Status|null $reblog_of_status
* @property string $message * @property string $message
* @property string $message_html * @property string $message_html
* @property int $favourites_count * @property int $favourites_count
@ -35,30 +35,30 @@ use RuntimeException;
* @property PreviewCard|null $preview_card * @property PreviewCard|null $preview_card
* *
* @property bool $has_replies * @property bool $has_replies
* @property Note[] $replies * @property Status[] $replies
* @property Note[] $reblogs * @property Status[] $reblogs
*/ */
class Note extends UuidEntity class Status extends UuidEntity
{ {
protected ?Actor $actor = null; protected ?Actor $actor = null;
protected ?Note $reply_to_note = null; protected ?Status $reply_to_status = null;
protected ?Note $reblog_of_note = null; protected ?Status $reblog_of_status = null;
protected ?PreviewCard $preview_card = null; protected ?PreviewCard $preview_card = null;
protected bool $has_preview_card = false; protected bool $has_preview_card = false;
/** /**
* @var Note[]|null * @var Status[]|null
*/ */
protected ?array $replies = null; protected ?array $replies = null;
protected bool $has_replies = false; protected bool $has_replies = false;
/** /**
* @var Note[]|null * @var Status[]|null
*/ */
protected ?array $reblogs = null; protected ?array $reblogs = null;
@ -89,12 +89,12 @@ class Note extends UuidEntity
]; ];
/** /**
* Returns the note's actor * Returns the status's actor
*/ */
public function getActor(): Actor public function getActor(): Actor
{ {
if ($this->actor_id === null) { if ($this->actor_id === null) {
throw new RuntimeException('Note must have an actor_id before getting actor.'); throw new RuntimeException('Status must have an actor_id before getting actor.');
} }
if ($this->actor === null) { if ($this->actor === null) {
@ -108,12 +108,12 @@ class Note extends UuidEntity
public function getPreviewCard(): ?PreviewCard public function getPreviewCard(): ?PreviewCard
{ {
if ($this->id === null) { if ($this->id === null) {
throw new RuntimeException('Note must be created before getting preview_card.'); throw new RuntimeException('Status must be created before getting preview_card.');
} }
if ($this->preview_card === null) { if ($this->preview_card === null) {
$this->preview_card = model('PreviewCardModel', false) $this->preview_card = model('PreviewCardModel', false)
->getNotePreviewCard($this->id); ->getStatusPreviewCard($this->id);
} }
return $this->preview_card; return $this->preview_card;
@ -125,17 +125,17 @@ class Note extends UuidEntity
} }
/** /**
* @return Note[] * @return Status[]
*/ */
public function getReplies(): array public function getReplies(): array
{ {
if ($this->id === null) { if ($this->id === null) {
throw new RuntimeException('Note must be created before getting replies.'); throw new RuntimeException('Status must be created before getting replies.');
} }
if ($this->replies === null) { if ($this->replies === null) {
$this->replies = (array) model('NoteModel', false) $this->replies = (array) model('StatusModel', false)
->getNoteReplies($this->id); ->getStatusReplies($this->id);
} }
return $this->replies; return $this->replies;
@ -146,49 +146,49 @@ class Note extends UuidEntity
return $this->getReplies() !== null; return $this->getReplies() !== null;
} }
public function getReplyToNote(): ?self public function getReplyToStatus(): ?self
{ {
if ($this->in_reply_to_id === null) { if ($this->in_reply_to_id === null) {
throw new RuntimeException('Note is not a reply.'); throw new RuntimeException('Status is not a reply.');
} }
if ($this->reply_to_note === null) { if ($this->reply_to_status === null) {
$this->reply_to_note = model('NoteModel', false) $this->reply_to_status = model('StatusModel', false)
->getNoteById($this->in_reply_to_id); ->getStatusById($this->in_reply_to_id);
} }
return $this->reply_to_note; return $this->reply_to_status;
} }
/** /**
* @return Note[] * @return Status[]
*/ */
public function getReblogs(): array public function getReblogs(): array
{ {
if ($this->id === null) { if ($this->id === null) {
throw new RuntimeException('Note must be created before getting reblogs.'); throw new RuntimeException('Status must be created before getting reblogs.');
} }
if ($this->reblogs === null) { if ($this->reblogs === null) {
$this->reblogs = (array) model('NoteModel', false) $this->reblogs = (array) model('StatusModel', false)
->getNoteReblogs($this->id); ->getStatusReblogs($this->id);
} }
return $this->reblogs; return $this->reblogs;
} }
public function getReblogOfNote(): ?self public function getReblogOfStatus(): ?self
{ {
if ($this->reblog_of_id === null) { if ($this->reblog_of_id === null) {
throw new RuntimeException('Note is not a reblog.'); throw new RuntimeException('Status is not a reblog.');
} }
if ($this->reblog_of_note === null) { if ($this->reblog_of_status === null) {
$this->reblog_of_note = model('NoteModel', false) $this->reblog_of_status = model('StatusModel', false)
->getNoteById($this->reblog_of_id); ->getStatusById($this->reblog_of_id);
} }
return $this->reblog_of_note; return $this->reblog_of_status;
} }
public function setMessage(string $message): static public function setMessage(string $message): static

View File

@ -31,7 +31,7 @@ class ActivityModel extends UuidModel
/** /**
* @var string[] * @var string[]
*/ */
protected $uuidFields = ['id', 'note_id']; protected $uuidFields = ['id', 'status_id'];
/** /**
* @var string[] * @var string[]
@ -40,10 +40,10 @@ class ActivityModel extends UuidModel
'id', 'id',
'actor_id', 'actor_id',
'target_actor_id', 'target_actor_id',
'note_id', 'status_id',
'type', 'type',
'payload', 'payload',
'status', 'task_status',
'scheduled_at', 'scheduled_at',
]; ];
@ -88,20 +88,20 @@ class ActivityModel extends UuidModel
string $type, string $type,
int $actorId, int $actorId,
?int $targetActorId, ?int $targetActorId,
?string $noteId, ?string $statusId,
string $payload, string $payload,
DateTimeInterface $scheduledAt = null, DateTimeInterface $scheduledAt = null,
?string $status = null ?string $taskStatus = null
): BaseResult | int | string | false { ): BaseResult | int | string | false {
return $this->insert( return $this->insert(
[ [
'actor_id' => $actorId, 'actor_id' => $actorId,
'target_actor_id' => $targetActorId, 'target_actor_id' => $targetActorId,
'note_id' => $noteId, 'status_id' => $statusId,
'type' => $type, 'type' => $type,
'payload' => $payload, 'payload' => $payload,
'scheduled_at' => $scheduledAt, 'scheduled_at' => $scheduledAt,
'status' => $status, 'task_status' => $taskStatus,
], ],
true, true,
); );

View File

@ -41,7 +41,7 @@ class ActorModel extends Model
'outbox_url', 'outbox_url',
'followers_url', 'followers_url',
'followers_count', 'followers_count',
'notes_count', 'statuses_count',
'is_blocked', 'is_blocked',
]; ];

View File

@ -14,7 +14,7 @@ use ActivityPub\Activities\LikeActivity;
use ActivityPub\Activities\UndoActivity; use ActivityPub\Activities\UndoActivity;
use ActivityPub\Entities\Actor; use ActivityPub\Entities\Actor;
use ActivityPub\Entities\Favourite; use ActivityPub\Entities\Favourite;
use ActivityPub\Entities\Note; use ActivityPub\Entities\Status;
use CodeIgniter\Events\Events; use CodeIgniter\Events\Events;
use Michalsn\Uuid\UuidModel; use Michalsn\Uuid\UuidModel;
@ -28,12 +28,12 @@ class FavouriteModel extends UuidModel
/** /**
* @var string[] * @var string[]
*/ */
protected $uuidFields = ['note_id']; protected $uuidFields = ['status_id'];
/** /**
* @var string[] * @var string[]
*/ */
protected $allowedFields = ['actor_id', 'note_id']; protected $allowedFields = ['actor_id', 'status_id'];
/** /**
* @var string * @var string
@ -47,32 +47,32 @@ class FavouriteModel extends UuidModel
protected $updatedField; protected $updatedField;
public function addFavourite(Actor $actor, Note $note, bool $registerActivity = true): void public function addFavourite(Actor $actor, Status $status, bool $registerActivity = true): void
{ {
$this->db->transStart(); $this->db->transStart();
$this->insert([ $this->insert([
'actor_id' => $actor->id, 'actor_id' => $actor->id,
'note_id' => $note->id, 'status_id' => $status->id,
]); ]);
model('NoteModel') model('StatusModel')
->where('id', service('uuid') ->fromString($note->id) ->getBytes()) ->where('id', service('uuid') ->fromString($status->id) ->getBytes())
->increment('favourites_count'); ->increment('favourites_count');
if ($registerActivity) { if ($registerActivity) {
$likeActivity = new LikeActivity(); $likeActivity = new LikeActivity();
$likeActivity->set('actor', $actor->uri) $likeActivity->set('actor', $actor->uri)
->set('object', $note->uri); ->set('object', $status->uri);
$activityId = model('ActivityModel') $activityId = model('ActivityModel')
->newActivity( ->newActivity(
'Like', 'Like',
$actor->id, $actor->id,
null, null,
$note->id, $status->id,
$likeActivity->toJSON(), $likeActivity->toJSON(),
$note->published_at, $status->published_at,
'queued', 'queued',
); );
@ -84,28 +84,28 @@ class FavouriteModel extends UuidModel
]); ]);
} }
Events::trigger('on_note_favourite', $actor, $note); Events::trigger('on_status_favourite', $actor, $status);
model('NoteModel') model('StatusModel')
->clearCache($note); ->clearCache($status);
$this->db->transComplete(); $this->db->transComplete();
} }
public function removeFavourite(Actor $actor, Note $note, bool $registerActivity = true): void public function removeFavourite(Actor $actor, Status $status, bool $registerActivity = true): void
{ {
$this->db->transStart(); $this->db->transStart();
model('NoteModel') model('StatusModel')
->where('id', service('uuid') ->fromString($note->id) ->getBytes()) ->where('id', service('uuid') ->fromString($status->id) ->getBytes())
->decrement('favourites_count'); ->decrement('favourites_count');
$this->db $this->db
->table('activitypub_favourites') ->table('activitypub_favourites')
->where([ ->where([
'actor_id' => $actor->id, 'actor_id' => $actor->id,
'note_id' => service('uuid') 'status_id' => service('uuid')
->fromString($note->id) ->fromString($status->id)
->getBytes(), ->getBytes(),
]) ])
->delete(); ->delete();
@ -117,8 +117,8 @@ class FavouriteModel extends UuidModel
->where([ ->where([
'type' => 'Like', 'type' => 'Like',
'actor_id' => $actor->id, 'actor_id' => $actor->id,
'note_id' => service('uuid') 'status_id' => service('uuid')
->fromString($note->id) ->fromString($status->id)
->getBytes(), ->getBytes(),
]) ])
->first(); ->first();
@ -127,7 +127,7 @@ class FavouriteModel extends UuidModel
$likeActivity $likeActivity
->set('id', base_url(route_to('activity', $actor->username, $activity->id))) ->set('id', base_url(route_to('activity', $actor->username, $activity->id)))
->set('actor', $actor->uri) ->set('actor', $actor->uri)
->set('object', $note->uri); ->set('object', $status->uri);
$undoActivity $undoActivity
->set('actor', $actor->uri) ->set('actor', $actor->uri)
@ -138,9 +138,9 @@ class FavouriteModel extends UuidModel
'Undo', 'Undo',
$actor->id, $actor->id,
null, null,
$note->id, $status->id,
$undoActivity->toJSON(), $undoActivity->toJSON(),
$note->published_at, $status->published_at,
'queued', 'queued',
); );
@ -152,10 +152,10 @@ class FavouriteModel extends UuidModel
]); ]);
} }
Events::trigger('on_note_undo_favourite', $actor, $note); Events::trigger('on_status_undo_favourite', $actor, $status);
model('NoteModel') model('StatusModel')
->clearCache($note); ->clearCache($status);
$this->db->transComplete(); $this->db->transComplete();
} }
@ -163,19 +163,19 @@ class FavouriteModel extends UuidModel
/** /**
* Adds or removes favourite from database and increments count * Adds or removes favourite from database and increments count
*/ */
public function toggleFavourite(Actor $actor, Note $note): void public function toggleFavourite(Actor $actor, Status $status): void
{ {
if ( if (
$this->where([ $this->where([
'actor_id' => $actor->id, 'actor_id' => $actor->id,
'note_id' => service('uuid') 'status_id' => service('uuid')
->fromString($note->id) ->fromString($status->id)
->getBytes(), ->getBytes(),
])->first() ])->first()
) { ) {
$this->removeFavourite($actor, $note); $this->removeFavourite($actor, $status);
} else { } else {
$this->addFavourite($actor, $note); $this->addFavourite($actor, $status);
} }
} }
} }

View File

@ -70,18 +70,18 @@ class PreviewCardModel extends Model
return $found; return $found;
} }
public function getNotePreviewCard(string $noteId): ?PreviewCard public function getStatusPreviewCard(string $statusId): ?PreviewCard
{ {
$cacheName = $cacheName =
config('ActivityPub') config('ActivityPub')
->cachePrefix . "note#{$noteId}_preview_card"; ->cachePrefix . "status#{$statusId}_preview_card";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$found = $this->join( $found = $this->join(
'activitypub_notes_preview_cards', 'activitypub_statuses_preview_cards',
'activitypub_notes_preview_cards.preview_card_id = id', 'activitypub_statuses_preview_cards.preview_card_id = id',
'inner', 'inner',
) )
->where('note_id', service('uuid') ->fromString($noteId) ->getBytes()) ->where('status_id', service('uuid') ->fromString($statusId) ->getBytes())
->first(); ->first();
cache() cache()

View File

@ -15,7 +15,7 @@ use ActivityPub\Activities\CreateActivity;
use ActivityPub\Activities\DeleteActivity; use ActivityPub\Activities\DeleteActivity;
use ActivityPub\Activities\UndoActivity; use ActivityPub\Activities\UndoActivity;
use ActivityPub\Entities\Actor; use ActivityPub\Entities\Actor;
use ActivityPub\Entities\Note; use ActivityPub\Entities\Status;
use ActivityPub\Objects\TombstoneObject; use ActivityPub\Objects\TombstoneObject;
use CodeIgniter\Database\BaseResult; use CodeIgniter\Database\BaseResult;
use CodeIgniter\Database\Query; use CodeIgniter\Database\Query;
@ -25,12 +25,12 @@ use CodeIgniter\I18n\Time;
use Exception; use Exception;
use Michalsn\Uuid\UuidModel; use Michalsn\Uuid\UuidModel;
class NoteModel extends UuidModel class StatusModel extends UuidModel
{ {
/** /**
* @var string * @var string
*/ */
protected $table = 'activitypub_notes'; protected $table = 'activitypub_statuses';
/** /**
* @var string * @var string
@ -62,7 +62,7 @@ class NoteModel extends UuidModel
/** /**
* @var string * @var string
*/ */
protected $returnType = Note::class; protected $returnType = Status::class;
/** /**
* @var bool * @var bool
@ -87,14 +87,14 @@ class NoteModel extends UuidModel
/** /**
* @var string[] * @var string[]
*/ */
protected $beforeInsert = ['setNoteId']; protected $beforeInsert = ['setStatusId'];
public function getNoteById(string $noteId): ?Note public function getStatusById(string $statusId): ?Status
{ {
$cacheName = config('ActivityPub') $cacheName = config('ActivityPub')
->cachePrefix . "note#{$noteId}"; ->cachePrefix . "status#{$statusId}";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$found = $this->find($noteId); $found = $this->find($statusId);
cache() cache()
->save($cacheName, $found, DECADE); ->save($cacheName, $found, DECADE);
@ -103,14 +103,14 @@ class NoteModel extends UuidModel
return $found; return $found;
} }
public function getNoteByUri(string $noteUri): ?Note public function getStatusByUri(string $statusUri): ?Status
{ {
$hashedNoteUri = md5($noteUri); $hashedStatusUri = md5($statusUri);
$cacheName = $cacheName =
config('ActivityPub') config('ActivityPub')
->cachePrefix . "note-{$hashedNoteUri}"; ->cachePrefix . "status-{$hashedStatusUri}";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$found = $this->where('uri', $noteUri) $found = $this->where('uri', $statusUri)
->first(); ->first();
cache() cache()
@ -121,16 +121,16 @@ class NoteModel extends UuidModel
} }
/** /**
* Retrieves all published notes for a given actor ordered by publication date * Retrieves all published statuses for a given actor ordered by publication date
* *
* @return Note[] * @return Status[]
*/ */
public function getActorPublishedNotes(int $actorId): array public function getActorPublishedStatuses(int $actorId): array
{ {
$cacheName = $cacheName =
config('ActivityPub') config('ActivityPub')
->cachePrefix . ->cachePrefix .
"actor#{$actorId}_published_notes"; "actor#{$actorId}_published_statuses";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$found = $this->where([ $found = $this->where([
'actor_id' => $actorId, 'actor_id' => $actorId,
@ -140,20 +140,20 @@ class NoteModel extends UuidModel
->orderBy('published_at', 'DESC') ->orderBy('published_at', 'DESC')
->findAll(); ->findAll();
$secondsToNextUnpublishedNote = $this->getSecondsToNextUnpublishedNote($actorId); $secondsToNextUnpublishedStatus = $this->getSecondsToNextUnpublishedStatuses($actorId);
cache() cache()
->save($cacheName, $found, $secondsToNextUnpublishedNote ? $secondsToNextUnpublishedNote : DECADE); ->save($cacheName, $found, $secondsToNextUnpublishedStatus ? $secondsToNextUnpublishedStatus : DECADE);
} }
return $found; return $found;
} }
/** /**
* Returns the timestamp difference in seconds between the next note to publish and the current timestamp. Returns * Returns the timestamp difference in seconds between the next status to publish and the current timestamp. Returns
* false if there's no note to publish * false if there's no status to publish
*/ */
public function getSecondsToNextUnpublishedNote(int $actorId): int | false public function getSecondsToNextUnpublishedStatuses(int $actorId): int | false
{ {
$result = $this->select('TIMESTAMPDIFF(SECOND, NOW(), `published_at`) as timestamp_diff') $result = $this->select('TIMESTAMPDIFF(SECOND, NOW(), `published_at`) as timestamp_diff')
->where([ ->where([
@ -170,26 +170,26 @@ class NoteModel extends UuidModel
} }
/** /**
* Retrieves all published replies for a given note. By default, it does not get replies from blocked actors. * Retrieves all published replies for a given status. By default, it does not get replies from blocked actors.
* *
* @return Note[] * @return Status[]
*/ */
public function getNoteReplies(string $noteId, bool $withBlocked = false): array public function getStatusReplies(string $statusId, bool $withBlocked = false): array
{ {
$cacheName = $cacheName =
config('ActivityPub') config('ActivityPub')
->cachePrefix . ->cachePrefix .
"note#{$noteId}_replies" . "status#{$statusId}_replies" .
($withBlocked ? '_withBlocked' : ''); ($withBlocked ? '_withBlocked' : '');
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
if (! $withBlocked) { if (! $withBlocked) {
$this->select('activitypub_notes.*') $this->select('activitypub_statuses.*')
->join('activitypub_actors', 'activitypub_actors.id = activitypub_notes.actor_id', 'inner') ->join('activitypub_actors', 'activitypub_actors.id = activitypub_statuses.actor_id', 'inner')
->where('activitypub_actors.is_blocked', 0); ->where('activitypub_actors.is_blocked', 0);
} }
$this->where('in_reply_to_id', $this->uuid->fromString($noteId) ->getBytes()) $this->where('in_reply_to_id', $this->uuid->fromString($statusId) ->getBytes())
->where('`published_at` <= NOW()', null, false) ->where('`published_at` <= NOW()', null, false)
->orderBy('published_at', 'ASC'); ->orderBy('published_at', 'ASC');
$found = $this->findAll(); $found = $this->findAll();
@ -202,18 +202,18 @@ class NoteModel extends UuidModel
} }
/** /**
* Retrieves all published reblogs for a given note * Retrieves all published reblogs for a given status
* *
* @return Note[] * @return Status[]
*/ */
public function getNoteReblogs(string $noteId): array public function getStatusReblogs(string $statusId): array
{ {
$cacheName = $cacheName =
config('ActivityPub') config('ActivityPub')
->cachePrefix . "note#{$noteId}_reblogs"; ->cachePrefix . "status#{$statusId}_reblogs";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$found = $this->where('reblog_of_id', $this->uuid->fromString($noteId) ->getBytes()) $found = $this->where('reblog_of_id', $this->uuid->fromString($statusId) ->getBytes())
->where('`published_at` <= NOW()', null, false) ->where('`published_at` <= NOW()', null, false)
->orderBy('published_at', 'ASC') ->orderBy('published_at', 'ASC')
->findAll(); ->findAll();
@ -225,23 +225,23 @@ class NoteModel extends UuidModel
return $found; return $found;
} }
public function addPreviewCard(string $noteId, int $previewCardId): Query | bool public function addPreviewCard(string $statusId, int $previewCardId): Query | bool
{ {
return $this->db->table('activitypub_notes_preview_cards') return $this->db->table('activitypub_statuses_preview_cards')
->insert([ ->insert([
'note_id' => $this->uuid->fromString($noteId) 'status_id' => $this->uuid->fromString($statusId)
->getBytes(), ->getBytes(),
'preview_card_id' => $previewCardId, 'preview_card_id' => $previewCardId,
]); ]);
} }
/** /**
* Adds note in database along preview card if relevant * Adds status in database along preview card if relevant
* *
* @return string|false returns the new note id if success or false otherwise * @return string|false returns the new status id if success or false otherwise
*/ */
public function addNote( public function addStatus(
Note $note, Status $status,
bool $createPreviewCard = true, bool $createPreviewCard = true,
bool $registerActivity = true bool $registerActivity = true
): string | false { ): string | false {
@ -249,56 +249,56 @@ class NoteModel extends UuidModel
$this->db->transStart(); $this->db->transStart();
if (! ($newNoteId = $this->insert($note, true))) { if (! ($newStatusId = $this->insert($status, true))) {
$this->db->transRollback(); $this->db->transRollback();
// Couldn't insert note // Couldn't insert status
return false; return false;
} }
if ($createPreviewCard) { if ($createPreviewCard) {
// parse message // parse message
$messageUrls = extract_urls_from_message($note->message); $messageUrls = extract_urls_from_message($status->message);
if ( if (
$messageUrls !== [] && $messageUrls !== [] &&
($previewCard = get_or_create_preview_card_from_url(new URI($messageUrls[0]))) && ($previewCard = get_or_create_preview_card_from_url(new URI($messageUrls[0]))) &&
! $this->addPreviewCard($newNoteId, $previewCard->id) ! $this->addPreviewCard($newStatusId, $previewCard->id)
) { ) {
$this->db->transRollback(); $this->db->transRollback();
// problem when linking note to preview card // problem when linking status to preview card
return false; return false;
} }
} }
model('ActorModel') model('ActorModel')
->where('id', $note->actor_id) ->where('id', $status->actor_id)
->increment('notes_count'); ->increment('statuses_count');
if ($registerActivity) { if ($registerActivity) {
// set note id and uri to construct NoteObject // set status id and uri to construct NoteObject
$note->id = $newNoteId; $status->id = $newStatusId;
$note->uri = base_url(route_to('note', $note->actor->username, $newNoteId)); $status->uri = base_url(route_to('status', $status->actor->username, $newStatusId));
$createActivity = new CreateActivity(); $createActivity = new CreateActivity();
$noteObjectClass = config('ActivityPub') $noteObjectClass = config('ActivityPub')
->noteObject; ->noteObject;
$createActivity $createActivity
->set('actor', $note->actor->uri) ->set('actor', $status->actor->uri)
->set('object', new $noteObjectClass($note)); ->set('object', new $noteObjectClass($status));
$activityId = model('ActivityModel') $activityId = model('ActivityModel')
->newActivity( ->newActivity(
'Create', 'Create',
$note->actor_id, $status->actor_id,
null, null,
$newNoteId, $newStatusId,
$createActivity->toJSON(), $createActivity->toJSON(),
$note->published_at, $status->published_at,
'queued', 'queued',
); );
$createActivity->set('id', base_url(route_to('activity', $note->actor->username, $activityId))); $createActivity->set('id', base_url(route_to('activity', $status->actor->username, $activityId)));
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
@ -306,44 +306,44 @@ class NoteModel extends UuidModel
]); ]);
} }
Events::trigger('on_note_add', $note); Events::trigger('on_status_add', $status);
$this->clearCache($note); $this->clearCache($status);
$this->db->transComplete(); $this->db->transComplete();
return $newNoteId; return $newStatusId;
} }
public function editNote(Note $updatedNote): bool public function editStatus(Status $updatedStatus): bool
{ {
$this->db->transStart(); $this->db->transStart();
// update note create activity schedule in database // update status create activity schedule in database
$scheduledActivity = model('ActivityModel') $scheduledActivity = model('ActivityModel')
->where([ ->where([
'type' => 'Create', 'type' => 'Create',
'note_id' => $this->uuid 'status_id' => $this->uuid
->fromString($updatedNote->id) ->fromString($updatedStatus->id)
->getBytes(), ->getBytes(),
]) ])
->first(); ->first();
// update published date in payload // update published date in payload
$newPayload = $scheduledActivity->payload; $newPayload = $scheduledActivity->payload;
$newPayload->object->published = $updatedNote->published_at->format(DATE_W3C); $newPayload->object->published = $updatedStatus->published_at->format(DATE_W3C);
model('ActivityModel') model('ActivityModel')
->update($scheduledActivity->id, [ ->update($scheduledActivity->id, [
'payload' => json_encode($newPayload, JSON_THROW_ON_ERROR), 'payload' => json_encode($newPayload, JSON_THROW_ON_ERROR),
'scheduled_at' => $updatedNote->published_at, 'scheduled_at' => $updatedStatus->published_at,
]); ]);
// update note // update status
$updateResult = $this->update($updatedNote->id, $updatedNote); $updateResult = $this->update($updatedStatus->id, $updatedStatus);
Events::trigger('on_note_edit', $updatedNote); Events::trigger('on_status_edit', $updatedStatus);
$this->clearCache($updatedNote); $this->clearCache($updatedStatus);
$this->db->transComplete(); $this->db->transComplete();
@ -351,59 +351,59 @@ class NoteModel extends UuidModel
} }
/** /**
* Removes a note from the database and decrements meta data * Removes a status from the database and decrements meta data
*/ */
public function removeNote(Note $note, bool $registerActivity = true): BaseResult | bool public function removeStatus(Status $status, bool $registerActivity = true): BaseResult | bool
{ {
$this->db->transStart(); $this->db->transStart();
model('ActorModel') model('ActorModel')
->where('id', $note->actor_id) ->where('id', $status->actor_id)
->decrement('notes_count'); ->decrement('statuses_count');
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
// Note to remove is a reply // Status to remove is a reply
model('NoteModel') model('StatusModel')
->where('id', $this->uuid->fromString($note->in_reply_to_id) ->getBytes()) ->where('id', $this->uuid->fromString($status->in_reply_to_id) ->getBytes())
->decrement('replies_count'); ->decrement('replies_count');
Events::trigger('on_reply_remove', $note); Events::trigger('on_reply_remove', $status);
} }
// remove all note reblogs // remove all status reblogs
foreach ($note->reblogs as $reblog) { foreach ($status->reblogs as $reblog) {
// FIXME: issue when actor is not local, can't get actor information // FIXME: issue when actor is not local, can't get actor information
$this->removeNote($reblog); $this->removeStatus($reblog);
} }
// remove all note replies // remove all status replies
foreach ($note->replies as $reply) { foreach ($status->replies as $reply) {
$this->removeNote($reply); $this->removeStatus($reply);
} }
// check that preview card is no longer used elsewhere before deleting it // check that preview card is no longer used elsewhere before deleting it
if ( if (
$note->preview_card && $status->preview_card &&
$this->db $this->db
->table('activitypub_notes_preview_cards') ->table('activitypub_statuses_preview_cards')
->where('preview_card_id', $note->preview_card->id) ->where('preview_card_id', $status->preview_card->id)
->countAll() <= 1 ->countAll() <= 1
) { ) {
model('PreviewCardModel')->deletePreviewCard($note->preview_card->id, $note->preview_card->url); model('PreviewCardModel')->deletePreviewCard($status->preview_card->id, $status->preview_card->url);
} }
if ($registerActivity) { if ($registerActivity) {
$deleteActivity = new DeleteActivity(); $deleteActivity = new DeleteActivity();
$tombstoneObject = new TombstoneObject(); $tombstoneObject = new TombstoneObject();
$tombstoneObject->set('id', $note->uri); $tombstoneObject->set('id', $status->uri);
$deleteActivity $deleteActivity
->set('actor', $note->actor->uri) ->set('actor', $status->actor->uri)
->set('object', $tombstoneObject); ->set('object', $tombstoneObject);
$activityId = model('ActivityModel') $activityId = model('ActivityModel')
->newActivity( ->newActivity(
'Delete', 'Delete',
$note->actor_id, $status->actor_id,
null, null,
null, null,
$deleteActivity->toJSON(), $deleteActivity->toJSON(),
@ -411,7 +411,7 @@ class NoteModel extends UuidModel
'queued', 'queued',
); );
$deleteActivity->set('id', base_url(route_to('activity', $note->actor->username, $activityId))); $deleteActivity->set('id', base_url(route_to('activity', $status->actor->username, $activityId)));
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
@ -419,12 +419,12 @@ class NoteModel extends UuidModel
]); ]);
} }
$result = model('NoteModel', false) $result = model('StatusModel', false)
->delete($note->id); ->delete($status->id);
Events::trigger('on_note_remove', $note); Events::trigger('on_status_remove', $status);
$this->clearCache($note); $this->clearCache($status);
$this->db->transComplete(); $this->db->transComplete();
@ -432,38 +432,38 @@ class NoteModel extends UuidModel
} }
public function addReply( public function addReply(
Note $reply, Status $reply,
bool $createPreviewCard = true, bool $createPreviewCard = true,
bool $registerActivity = true bool $registerActivity = true
): string | false { ): string | false {
if (! $reply->in_reply_to_id) { if (! $reply->in_reply_to_id) {
throw new Exception('Passed note is not a reply!'); throw new Exception('Passed status is not a reply!');
} }
$this->db->transStart(); $this->db->transStart();
$noteId = $this->addNote($reply, $createPreviewCard, $registerActivity); $statusId = $this->addStatus($reply, $createPreviewCard, $registerActivity);
model('NoteModel') model('StatusModel')
->where('id', $this->uuid->fromString($reply->in_reply_to_id) ->getBytes()) ->where('id', $this->uuid->fromString($reply->in_reply_to_id) ->getBytes())
->increment('replies_count'); ->increment('replies_count');
Events::trigger('on_note_reply', $reply); Events::trigger('on_status_reply', $reply);
$this->clearCache($reply); $this->clearCache($reply);
$this->db->transComplete(); $this->db->transComplete();
return $noteId; return $statusId;
} }
public function reblog(Actor $actor, Note $note, bool $registerActivity = true): string | false public function reblog(Actor $actor, Status $status, bool $registerActivity = true): string | false
{ {
$this->db->transStart(); $this->db->transStart();
$reblog = new Note([ $reblog = new Status([
'actor_id' => $actor->id, 'actor_id' => $actor->id,
'reblog_of_id' => $note->id, 'reblog_of_id' => $status->id,
'published_at' => Time::now(), 'published_at' => Time::now(),
]); ]);
@ -472,10 +472,10 @@ class NoteModel extends UuidModel
model('ActorModel') model('ActorModel')
->where('id', $actor->id) ->where('id', $actor->id)
->increment('notes_count'); ->increment('statuses_count');
model('NoteModel') model('StatusModel')
->where('id', $this->uuid->fromString($note->id)->getBytes()) ->where('id', $this->uuid->fromString($status->id)->getBytes())
->increment('reblogs_count'); ->increment('reblogs_count');
if ($registerActivity) { if ($registerActivity) {
@ -486,13 +486,13 @@ class NoteModel extends UuidModel
'Announce', 'Announce',
$actor->id, $actor->id,
null, null,
$note->id, $status->id,
$announceActivity->toJSON(), $announceActivity->toJSON(),
$reblog->published_at, $reblog->published_at,
'queued', 'queued',
); );
$announceActivity->set('id', base_url(route_to('activity', $note->actor->username, $activityId))); $announceActivity->set('id', base_url(route_to('activity', $status->actor->username, $activityId)));
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
@ -500,25 +500,25 @@ class NoteModel extends UuidModel
]); ]);
} }
Events::trigger('on_note_reblog', $actor, $note); Events::trigger('on_status_reblog', $actor, $status);
$this->clearCache($note); $this->clearCache($status);
$this->db->transComplete(); $this->db->transComplete();
return $reblogId; return $reblogId;
} }
public function undoReblog(Note $reblogNote, bool $registerActivity = true): BaseResult | bool public function undoReblog(Status $reblogStatus, bool $registerActivity = true): BaseResult | bool
{ {
$this->db->transStart(); $this->db->transStart();
model('ActorModel') model('ActorModel')
->where('id', $reblogNote->actor_id) ->where('id', $reblogStatus->actor_id)
->decrement('notes_count'); ->decrement('statuses_count');
model('NoteModel') model('StatusModel')
->where('id', $this->uuid->fromString($reblogNote->reblog_of_id) ->getBytes()) ->where('id', $this->uuid->fromString($reblogStatus->reblog_of_id) ->getBytes())
->decrement('reblogs_count'); ->decrement('reblogs_count');
if ($registerActivity) { if ($registerActivity) {
@ -527,35 +527,35 @@ class NoteModel extends UuidModel
$activity = model('ActivityModel') $activity = model('ActivityModel')
->where([ ->where([
'type' => 'Announce', 'type' => 'Announce',
'actor_id' => $reblogNote->actor_id, 'actor_id' => $reblogStatus->actor_id,
'note_id' => $this->uuid 'status_id' => $this->uuid
->fromString($reblogNote->reblog_of_id) ->fromString($reblogStatus->reblog_of_id)
->getBytes(), ->getBytes(),
]) ])
->first(); ->first();
$announceActivity = new AnnounceActivity($reblogNote); $announceActivity = new AnnounceActivity($reblogStatus);
$announceActivity->set( $announceActivity->set(
'id', 'id',
base_url(route_to('activity', $reblogNote->actor->username, $activity->id)), base_url(route_to('activity', $reblogStatus->actor->username, $activity->id)),
); );
$undoActivity $undoActivity
->set('actor', $reblogNote->actor->uri) ->set('actor', $reblogStatus->actor->uri)
->set('object', $announceActivity); ->set('object', $announceActivity);
$activityId = model('ActivityModel') $activityId = model('ActivityModel')
->newActivity( ->newActivity(
'Undo', 'Undo',
$reblogNote->actor_id, $reblogStatus->actor_id,
null, null,
$reblogNote->reblog_of_id, $reblogStatus->reblog_of_id,
$undoActivity->toJSON(), $undoActivity->toJSON(),
Time::now(), Time::now(),
'queued', 'queued',
); );
$undoActivity->set('id', base_url(route_to('activity', $reblogNote->actor->username, $activityId))); $undoActivity->set('id', base_url(route_to('activity', $reblogStatus->actor->username, $activityId)));
model('ActivityModel') model('ActivityModel')
->update($activityId, [ ->update($activityId, [
@ -563,54 +563,54 @@ class NoteModel extends UuidModel
]); ]);
} }
$result = model('NoteModel', false) $result = model('StatusModel', false)
->delete($reblogNote->id); ->delete($reblogStatus->id);
Events::trigger('on_note_undo_reblog', $reblogNote); Events::trigger('on_status_undo_reblog', $reblogStatus);
$this->clearCache($reblogNote); $this->clearCache($reblogStatus);
$this->db->transComplete(); $this->db->transComplete();
return $result; return $result;
} }
public function toggleReblog(Actor $actor, Note $note): void public function toggleReblog(Actor $actor, Status $status): void
{ {
if ( if (
! ($reblogNote = $this->where([ ! ($reblogStatus = $this->where([
'actor_id' => $actor->id, 'actor_id' => $actor->id,
'reblog_of_id' => $this->uuid 'reblog_of_id' => $this->uuid
->fromString($note->id) ->fromString($status->id)
->getBytes(), ->getBytes(),
])->first()) ])->first())
) { ) {
$this->reblog($actor, $note); $this->reblog($actor, $status);
} else { } else {
$this->undoReblog($reblogNote); $this->undoReblog($reblogStatus);
} }
} }
public function clearCache(Note $note): void public function clearCache(Status $status): void
{ {
$cachePrefix = config('ActivityPub') $cachePrefix = config('ActivityPub')
->cachePrefix; ->cachePrefix;
$hashedNoteUri = md5($note->uri); $hashedStatusUri = md5($status->uri);
model('ActorModel') model('ActorModel')
->clearCache($note->actor); ->clearCache($status->actor);
cache() cache()
->deleteMatching($cachePrefix . "note#{$note->id}*"); ->deleteMatching($cachePrefix . "status#{$status->id}*");
cache() cache()
->deleteMatching($cachePrefix . "note-{$hashedNoteUri}*"); ->deleteMatching($cachePrefix . "status-{$hashedStatusUri}*");
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
$this->clearCache($note->reply_to_note); $this->clearCache($status->reply_to_status);
} }
if ($note->reblog_of_id !== null) { if ($status->reblog_of_id !== null) {
$this->clearCache($note->reblog_of_note); $this->clearCache($status->reblog_of_status);
} }
} }
@ -618,7 +618,7 @@ class NoteModel extends UuidModel
* @param array<string, array<string|int, mixed>> $data * @param array<string, array<string|int, mixed>> $data
* @return array<string, array<string|int, mixed>> * @return array<string, array<string|int, mixed>>
*/ */
protected function setNoteId(array $data): array protected function setStatusId(array $data): array
{ {
$uuid4 = $this->uuid->{$this->uuidVersion}(); $uuid4 = $this->uuid->{$this->uuidVersion}();
$data['data']['id'] = $uuid4->toString(); $data['data']['id'] = $uuid4->toString();
@ -627,7 +627,7 @@ class NoteModel extends UuidModel
$actor = model('ActorModel') $actor = model('ActorModel')
->getActorById((int) $data['data']['actor_id']); ->getActorById((int) $data['data']['actor_id']);
$data['data']['uri'] = base_url(route_to('note', $actor->username, $uuid4->toString())); $data['data']['uri'] = base_url(route_to('status', $actor->username, $uuid4->toString()));
} }
return $data; return $data;

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
namespace ActivityPub\Objects; namespace ActivityPub\Objects;
use ActivityPub\Core\ObjectType; use ActivityPub\Core\ObjectType;
use ActivityPub\Entities\Note; use ActivityPub\Entities\Status;
class NoteObject extends ObjectType class NoteObject extends ObjectType
{ {
@ -27,20 +27,20 @@ class NoteObject extends ObjectType
protected string $replies; protected string $replies;
public function __construct(Note $note) public function __construct(Status $status)
{ {
$this->id = $note->uri; $this->id = $status->uri;
$this->content = $note->message_html; $this->content = $status->message_html;
$this->published = $note->published_at->format(DATE_W3C); $this->published = $status->published_at->format(DATE_W3C);
$this->attributedTo = $note->actor->uri; $this->attributedTo = $status->actor->uri;
if ($note->in_reply_to_id !== null) { if ($status->in_reply_to_id !== null) {
$this->inReplyTo = $note->reply_to_note->uri; $this->inReplyTo = $status->reply_to_status->uri;
} }
$this->replies = base_url(route_to('note-replies', $note->actor->username, $note->id)); $this->replies = base_url(route_to('status-replies', $status->actor->username, $status->id));
$this->cc = [$note->actor->followers_url]; $this->cc = [$status->actor->followers_url];
} }
} }

View File

@ -11,25 +11,25 @@ declare(strict_types=1);
namespace App\Libraries; namespace App\Libraries;
use ActivityPub\Objects\NoteObject as ActivityPubNoteObject; use ActivityPub\Objects\NoteObject as ActivityPubNoteObject;
use App\Entities\Note; use App\Entities\Status;
class NoteObject extends ActivityPubNoteObject class NoteObject extends ActivityPubNoteObject
{ {
/** /**
* @param Note $note * @param Status $status
*/ */
public function __construct($note) public function __construct($status)
{ {
parent::__construct($note); parent::__construct($status);
if ($note->episode_id) { if ($status->episode_id) {
$this->content = $this->content =
'<a href="' . '<a href="' .
$note->episode->link . $status->episode->link .
'" target="_blank" rel="noopener noreferrer">' . '" target="_blank" rel="noopener noreferrer">' .
$note->episode->title . $status->episode->title .
'</a><br/>' . '</a><br/>' .
$note->message_html; $status->message_html;
} }
} }
} }

View File

@ -92,7 +92,7 @@ class EpisodeModel extends Model
'custom_rss', 'custom_rss',
'favourites_total', 'favourites_total',
'reblogs_total', 'reblogs_total',
'notes_total', 'statuses_total',
'published_at', 'published_at',
'created_by', 'created_by',
'updated_by', 'updated_by',

View File

@ -10,15 +10,15 @@ declare(strict_types=1);
namespace App\Models; namespace App\Models;
use ActivityPub\Models\NoteModel as ActivityPubNoteModel; use ActivityPub\Models\StatusModel as ActivityPubStatusModel;
use App\Entities\Note; use App\Entities\Status;
class NoteModel extends ActivityPubNoteModel class StatusModel extends ActivityPubStatusModel
{ {
/** /**
* @var string * @var string
*/ */
protected $returnType = Note::class; protected $returnType = Status::class;
/** /**
* @var string[] * @var string[]
@ -40,11 +40,11 @@ class NoteModel extends ActivityPubNoteModel
]; ];
/** /**
* Retrieves all published notes for a given episode ordered by publication date * Retrieves all published statuses for a given episode ordered by publication date
* *
* @return Note[] * @return Status[]
*/ */
public function getEpisodeNotes(int $episodeId): array public function getEpisodeStatuses(int $episodeId): array
{ {
return $this->where([ return $this->where([
'episode_id' => $episodeId, 'episode_id' => $episodeId,

View File

@ -7,7 +7,7 @@
@import "./radioBtn.css"; @import "./radioBtn.css";
@import "./switch.css"; @import "./switch.css";
@import "./charts.css"; @import "./charts.css";
@import "./note.css"; @import "./status.css";
@import "./tabs.css"; @import "./tabs.css";
@import "./radioToggler.css"; @import "./radioToggler.css";
@import "./formInputTabs.css"; @import "./formInputTabs.css";

View File

@ -1,11 +1,11 @@
@layer components { @layer components {
.note-content { .status-content {
& a { & a {
@apply text-sm font-semibold text-pine-600 hover:underline; @apply text-sm font-semibold text-pine-600 hover:underline;
} }
} }
.note-replies > * { .status-replies > * {
@apply relative; @apply relative;
& img { & img {

View File

@ -20,8 +20,8 @@
<label for="message" class="text-lg font-semibold"><?= lang( <label for="message" class="text-lg font-semibold"><?= lang(
'Episode.publish_form.note', 'Episode.publish_form.status',
) . hint_tooltip(lang('Episode.publish_form.note_hint'), 'ml-1') ?></label> ) . hint_tooltip(lang('Episode.publish_form.status_hint'), 'ml-1') ?></label>
<div class="mb-8 overflow-hidden bg-white shadow-md rounded-xl"> <div class="mb-8 overflow-hidden bg-white shadow-md rounded-xl">
<div class="flex px-4 py-3"> <div class="flex px-4 py-3">
<img src="<?= $podcast->actor->avatar_image_url ?>" alt="<?= $podcast <img src="<?= $podcast->actor->avatar_image_url ?>" alt="<?= $podcast

View File

@ -17,12 +17,12 @@
]) ?> ]) ?>
<?= csrf_field() ?> <?= csrf_field() ?>
<?= form_hidden('client_timezone', 'UTC') ?> <?= form_hidden('client_timezone', 'UTC') ?>
<?= form_hidden('note_id', $note->id) ?> <?= form_hidden('status_id', $status->id) ?>
<label for="message" class="text-lg font-semibold"><?= lang( <label for="message" class="text-lg font-semibold"><?= lang(
'Episode.publish_form.note', 'Episode.publish_form.status',
) . hint_tooltip(lang('Episode.publish_form.note_hint'), 'ml-1') ?></label> ) . hint_tooltip(lang('Episode.publish_form.status_hint'), 'ml-1') ?></label>
<div class="mb-8 overflow-hidden bg-white shadow-md rounded-xl"> <div class="mb-8 overflow-hidden bg-white shadow-md rounded-xl">
<div class="flex px-4 py-3"> <div class="flex px-4 py-3">
<img src="<?= $podcast->actor->avatar_image_url ?>" alt="<?= $podcast->actor <img src="<?= $podcast->actor->avatar_image_url ?>" alt="<?= $podcast->actor
@ -34,11 +34,11 @@
<span class="text-sm text-gray-500 truncate">@<?= $podcast <span class="text-sm text-gray-500 truncate">@<?= $podcast
->actor->username ?></span> ->actor->username ?></span>
</p> </p>
<time class="text-xs text-gray-500" itemprop="published" datetime="<?= $note->published_at->format( <time class="text-xs text-gray-500" itemprop="published" datetime="<?= $status->published_at->format(
DateTime::ATOM, DateTime::ATOM,
) ?>" title="<?= $note->published_at ?>"><?= lang( ) ?>" title="<?= $status->published_at ?>"><?= lang(
'Common.mediumDate', 'Common.mediumDate',
[$note->published_at], [$status->published_at],
) ?></time> ) ?></time>
</div> </div>
</div> </div>
@ -51,7 +51,7 @@
'required' => 'required', 'required' => 'required',
'placeholder' => 'Write your message...', 'placeholder' => 'Write your message...',
], ],
old('message', $note->message, false), old('message', $status->message, false),
['rows' => 2], ['rows' => 2],
) ?> ) ?>
</div> </div>

View File

@ -50,8 +50,8 @@
<a href="<?= route_to( <a href="<?= route_to(
'podcast-activity', 'podcast-activity',
$podcast->name, $podcast->name,
) ?>" class="hover:underline"><?= lang('Podcast.notes', [ ) ?>" class="hover:underline"><?= lang('Podcast.statuses', [
'numberOfNotes' => $podcast->actor->notes_count, 'numberOfStatuses' => $podcast->actor->statuses_count,
]) ?></a> ]) ?></a>
</div> </div>
</div> </div>

View File

@ -1,40 +0,0 @@
<article class="relative z-10 w-full bg-white shadow-md rounded-2xl">
<header class="flex px-6 py-4">
<img src="<?= $note->actor
->avatar_image_url ?>" alt="<?= $note->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0">
<a href="<?= $note->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $note
->actor->is_local
? ''
: 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $note->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $note->actor
->username .
($note->actor->is_local
? ''
: '@' . $note->actor->domain) ?></span>
</a>
<a href="<?= route_to('note', $podcast->name, $note->id) ?>"
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time>
</a>
</div>
</header>
<div class="px-6 mb-4 note-content"><?= $note->message_html ?></div>
<?php if ($note->episode_id): ?>
<?= view('podcast/_partials/episode_card', [
'episode' => $note->episode,
]) ?>
<?php elseif ($note->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [
'preview_card' => $note->preview_card,
]) ?>
<?php endif; ?>
<?= $this->include('podcast/_partials/note_actions') ?>
</article>

View File

@ -1,36 +0,0 @@
<footer class="flex justify-around px-6 py-3">
<?= anchor(
route_to('note', $podcast->name, $note->id),
icon('chat', 'text-2xl mr-1 text-gray-400') . $note->replies_count,
[
'class' => 'inline-flex items-center hover:underline',
'title' => lang('Note.replies', [
'numberOfReplies' => $note->replies_count,
]),
],
) ?>
<?= anchor_popup(
route_to('note-remote-action', $podcast->name, $note->id, 'reblog'),
icon('repeat', 'text-2xl mr-1 text-gray-400') . $note->reblogs_count,
[
'class' => 'inline-flex items-center hover:underline',
'width' => 420,
'height' => 620,
'title' => lang('Note.reblogs', [
'numberOfReblogs' => $note->reblogs_count,
]),
],
) ?>
<?= anchor_popup(
route_to('note-remote-action', $podcast->name, $note->id, 'favourite'),
icon('heart', 'text-2xl mr-1 text-gray-400') . $note->favourites_count,
[
'class' => 'inline-flex items-center hover:underline',
'width' => 420,
'height' => 620,
'title' => lang('Note.favourites', [
'numberOfFavourites' => $note->favourites_count,
]),
],
) ?>
</footer>

View File

@ -1,40 +0,0 @@
<article class="relative z-10 w-full bg-white shadow-md rounded-2xl">
<header class="flex px-6 py-4">
<img src="<?= $note->actor
->avatar_image_url ?>" alt="<?= $note->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0">
<a href="<?= $note->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $note
->actor->is_local
? ''
: 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $note->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $note->actor
->username .
($note->actor->is_local
? ''
: '@' . $note->actor->domain) ?></span>
</a>
<a href="<?= route_to('note', $podcast->name, $note->id) ?>"
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time>
</a>
</div>
</header>
<div class="px-6 mb-4 note-content"><?= $note->message_html ?></div>
<?php if ($note->episode_id): ?>
<?= view('podcast/_partials/episode_card', [
'episode' => $note->episode,
]) ?>
<?php elseif ($note->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [
'preview_card' => $note->preview_card,
]) ?>
<?php endif; ?>
<?= $this->include('podcast/_partials/note_actions_authenticated') ?>
</article>

View File

@ -3,45 +3,45 @@
'repeat', 'repeat',
'text-lg mr-2 text-gray-400', 'text-lg mr-2 text-gray-400',
) . ) .
lang('Note.actor_shared', [ lang('Status.actor_shared', [
'actor' => $note->actor->display_name, 'actor' => $status->actor->display_name,
]) ?></p> ]) ?></p>
<header class="flex px-6 py-4"> <header class="flex px-6 py-4">
<img src="<?= $note->actor <img src="<?= $status->actor
->avatar_image_url ?>" alt="<?= $note->display_name ?>" class="w-12 h-12 mr-4 rounded-full" /> ->avatar_image_url ?>" alt="<?= $status->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0"> <div class="flex flex-col min-w-0">
<a href="<?= $note->actor <a href="<?= $status->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $note ->uri ?>" class="flex items-baseline hover:underline" <?= $status
->actor->is_local ->actor->is_local
? '' ? ''
: 'target="_blank" rel="noopener noreferrer"' ?>> : 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $note->actor <span class="mr-2 font-semibold truncate"><?= $status->actor
->display_name ?></span> ->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $note->actor <span class="text-sm text-gray-500 truncate">@<?= $status->actor
->username . ->username .
($note->actor->is_local ($status->actor->is_local
? '' ? ''
: '@' . $note->actor->domain) ?></span> : '@' . $status->actor->domain) ?></span>
</a> </a>
<a href="<?= route_to('note', $podcast->name, $note->id) ?>" <a href="<?= route_to('status', $podcast->name, $status->id) ?>"
class="text-xs text-gray-500"> class="text-xs text-gray-500">
<time <time
itemprop="published" itemprop="published"
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>" datetime="<?= $status->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>" title="<?= $status->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time> ><?= lang('Common.mediumDate', [$status->published_at]) ?></time>
</a> </a>
</div> </div>
</header> </header>
<div class="px-6 mb-4 note-content"><?= $note->message_html ?></div> <div class="px-6 mb-4 status-content"><?= $status->message_html ?></div>
<?php if ($note->episode_id): ?> <?php if ($status->episode_id): ?>
<?= view('podcast/_partials/episode_card', [ <?= view('podcast/_partials/episode_card', [
'episode' => $note->episode, 'episode' => $status->episode,
]) ?> ]) ?>
<?php elseif ($note->has_preview_card): ?> <?php elseif ($status->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [ <?= view('podcast/_partials/preview_card', [
'preview_card' => $note->preview_card, 'preview_card' => $status->preview_card,
]) ?> ]) ?>
<?php endif; ?> <?php endif; ?>
<?= $this->include('podcast/_partials/note_actions') ?> <?= $this->include('podcast/_partials/status_actions') ?>
</article> </article>

View File

@ -3,45 +3,45 @@
'repeat', 'repeat',
'text-lg mr-2 text-gray-400', 'text-lg mr-2 text-gray-400',
) . ) .
lang('Note.actor_shared', [ lang('Status.actor_shared', [
'actor' => $note->actor->display_name, 'actor' => $status->actor->display_name,
]) ?></p> ]) ?></p>
<header class="flex px-6 py-4"> <header class="flex px-6 py-4">
<img src="<?= $note->actor <img src="<?= $status->actor
->avatar_image_url ?>" alt="<?= $note->display_name ?>" class="w-12 h-12 mr-4 rounded-full" /> ->avatar_image_url ?>" alt="<?= $status->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0"> <div class="flex flex-col min-w-0">
<a href="<?= $note->actor <a href="<?= $status->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $note ->uri ?>" class="flex items-baseline hover:underline" <?= $status
->actor->is_local ->actor->is_local
? '' ? ''
: 'target="_blank" rel="noopener noreferrer"' ?>> : 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $note->actor <span class="mr-2 font-semibold truncate"><?= $status->actor
->display_name ?></span> ->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $note->actor <span class="text-sm text-gray-500 truncate">@<?= $status->actor
->username . ->username .
($note->actor->is_local ($status->actor->is_local
? '' ? ''
: '@' . $note->actor->domain) ?></span> : '@' . $status->actor->domain) ?></span>
</a> </a>
<a href="<?= route_to('note', $podcast->name, $note->id) ?>" <a href="<?= route_to('status', $podcast->name, $status->id) ?>"
class="text-xs text-gray-500"> class="text-xs text-gray-500">
<time <time
itemprop="published" itemprop="published"
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>" datetime="<?= $status->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>" title="<?= $status->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time> ><?= lang('Common.mediumDate', [$status->published_at]) ?></time>
</a> </a>
</div> </div>
</header> </header>
<div class="px-6 mb-4 note-content"><?= $note->message_html ?></div> <div class="px-6 mb-4 status-content"><?= $status->message_html ?></div>
<?php if ($note->episode_id): ?> <?php if ($status->episode_id): ?>
<?= view('podcast/_partials/episode_card', [ <?= view('podcast/_partials/episode_card', [
'episode' => $note->episode, 'episode' => $status->episode,
]) ?> ]) ?>
<?php elseif ($note->has_preview_card): ?> <?php elseif ($status->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [ <?= view('podcast/_partials/preview_card', [
'preview_card' => $note->preview_card, 'preview_card' => $status->preview_card,
]) ?> ]) ?>
<?php endif; ?> <?php endif; ?>
<?= $this->include('podcast/_partials/note_actions_authenticated') ?> <?= $this->include('podcast/_partials/status_actions_authenticated') ?>
</article> </article>

View File

@ -18,7 +18,7 @@
title="<?= $reply->published_at ?>" title="<?= $reply->published_at ?>"
><?= lang('Common.mediumDate', [$reply->published_at]) ?></time> ><?= lang('Common.mediumDate', [$reply->published_at]) ?></time>
</header> </header>
<p class="mb-2 note-content"><?= $reply->message_html ?></p> <p class="mb-2 status-content"><?= $reply->message_html ?></p>
<?php if ($reply->has_preview_card): ?> <?php if ($reply->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [ <?= view('podcast/_partials/preview_card', [
'preview_card' => $reply->preview_card, 'preview_card' => $reply->preview_card,

View File

@ -1,34 +1,34 @@
<footer class="mt-2 space-x-6 text-sm"> <footer class="mt-2 space-x-6 text-sm">
<?= anchor( <?= anchor(
route_to('note', $podcast->name, $reply->id), route_to('status', $podcast->name, $reply->id),
icon('chat', 'text-xl mr-1 text-gray-400') . $reply->replies_count, icon('chat', 'text-xl mr-1 text-gray-400') . $reply->replies_count,
[ [
'class' => 'inline-flex items-center hover:underline', 'class' => 'inline-flex items-center hover:underline',
'title' => lang('Note.replies', [ 'title' => lang('Status.replies', [
'numberOfReplies' => $reply->replies_count, 'numberOfReplies' => $reply->replies_count,
]), ]),
], ],
) ?> ) ?>
<?= anchor_popup( <?= anchor_popup(
route_to('note-remote-action', $podcast->name, $reply->id, 'reblog'), route_to('status-remote-action', $podcast->name, $reply->id, 'reblog'),
icon('repeat', 'text-xl mr-1 text-gray-400') . $reply->reblogs_count, icon('repeat', 'text-xl mr-1 text-gray-400') . $reply->reblogs_count,
[ [
'class' => 'inline-flex items-center hover:underline', 'class' => 'inline-flex items-center hover:underline',
'width' => 420, 'width' => 420,
'height' => 620, 'height' => 620,
'title' => lang('Note.reblogs', [ 'title' => lang('Status.reblogs', [
'numberOfReblogs' => $reply->reblogs_count, 'numberOfReblogs' => $reply->reblogs_count,
]), ]),
], ],
) ?> ) ?>
<?= anchor_popup( <?= anchor_popup(
route_to('note-remote-action', $podcast->name, $reply->id, 'favourite'), route_to('status-remote-action', $podcast->name, $reply->id, 'favourite'),
icon('heart', 'text-xl mr-1 text-gray-400') . $reply->favourites_count, icon('heart', 'text-xl mr-1 text-gray-400') . $reply->favourites_count,
[ [
'class' => 'inline-flex items-center hover:underline', 'class' => 'inline-flex items-center hover:underline',
'width' => 420, 'width' => 420,
'height' => 620, 'height' => 620,
'title' => lang('Note.favourites', [ 'title' => lang('Status.favourites', [
'numberOfFavourites' => $reply->favourites_count, 'numberOfFavourites' => $reply->favourites_count,
]), ]),
], ],

View File

@ -1,29 +1,29 @@
<footer class="mt-2 text-sm"> <footer class="mt-2 text-sm">
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-action', 'status-attempt-action',
interact_as_actor()->username, interact_as_actor()->username,
$reply->id, $reply->id,
) ?>" method="POST" class="flex items-start"> ) ?>" method="POST" class="flex items-start">
<?= csrf_field() ?> <?= csrf_field() ?>
<?= anchor( <?= anchor(
route_to('note', $podcast->name, $reply->id), route_to('status', $podcast->name, $reply->id),
icon('chat', 'text-xl mr-1 text-gray-400') . $reply->replies_count, icon('chat', 'text-xl mr-1 text-gray-400') . $reply->replies_count,
[ [
'class' => 'inline-flex items-center mr-6 hover:underline', 'class' => 'inline-flex items-center mr-6 hover:underline',
'title' => lang('Note.replies', [ 'title' => lang('Status.replies', [
'numberOfReplies' => $reply->replies_count, 'numberOfReplies' => $reply->replies_count,
]), ]),
], ],
) ?> ) ?>
<button type="submit" name="action" value="reblog" class="inline-flex items-center mr-6 hover:underline" title="<?= lang( <button type="submit" name="action" value="reblog" class="inline-flex items-center mr-6 hover:underline" title="<?= lang(
'Note.reblogs', 'Status.reblogs',
[ [
'numberOfReblogs' => $reply->reblogs_count, 'numberOfReblogs' => $reply->reblogs_count,
], ],
) ?>"><?= icon('repeat', 'text-xl mr-1 text-gray-400') . ) ?>"><?= icon('repeat', 'text-xl mr-1 text-gray-400') .
$reply->reblogs_count ?></button> $reply->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center mr-6 hover:underline" title="<?= lang( <button type="submit" name="action" value="favourite" class="inline-flex items-center mr-6 hover:underline" title="<?= lang(
'Note.favourites', 'Status.favourites',
[ [
'numberOfFavourites' => $reply->favourites_count, 'numberOfFavourites' => $reply->favourites_count,
], ],
@ -40,33 +40,33 @@
'-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm bg-white border rounded-lg shadow" aria-labelledby="<?= $reply->id . '-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm bg-white border rounded-lg shadow" aria-labelledby="<?= $reply->id .
'-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom"> '-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom">
<?= anchor( <?= anchor(
route_to('note', $podcast->name, $reply->id), route_to('status', $podcast->name, $reply->id),
lang('Note.expand'), lang('Status.expand'),
[ [
'class' => 'px-4 py-1 hover:bg-gray-100', 'class' => 'px-4 py-1 hover:bg-gray-100',
], ],
) ?> ) ?>
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-block-actor', 'status-attempt-block-actor',
interact_as_actor()->username, interact_as_actor()->username,
$reply->id, $reply->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>
<button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang( <button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang(
'Note.block_actor', 'Status.block_actor',
[ [
'actorUsername' => $reply->actor->username, 'actorUsername' => $reply->actor->username,
], ],
) ?></button> ) ?></button>
</form> </form>
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-block-domain', 'status-attempt-block-domain',
interact_as_actor()->username, interact_as_actor()->username,
$reply->id, $reply->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>
<button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang( <button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang(
'Note.block_domain', 'Status.block_domain',
[ [
'actorDomain' => $reply->actor->domain, 'actorDomain' => $reply->actor->domain,
], ],
@ -75,13 +75,13 @@
<?php if ($reply->actor->is_local): ?> <?php if ($reply->actor->is_local): ?>
<hr class="my-2" /> <hr class="my-2" />
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-delete', 'status-attempt-delete',
$reply->actor->username, $reply->actor->username,
$reply->id, $reply->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>
<button class="w-full px-4 py-1 font-semibold text-left text-red-600 hover:bg-gray-100"><?= lang( <button class="w-full px-4 py-1 font-semibold text-left text-red-600 hover:bg-gray-100"><?= lang(
'Note.delete', 'Status.delete',
) ?></button> ) ?></button>
</form> </form>
<?php endif; ?> <?php endif; ?>

View File

@ -18,7 +18,7 @@
title="<?= $reply->published_at ?>" title="<?= $reply->published_at ?>"
><?= lang('Common.mediumDate', [$reply->published_at]) ?></time> ><?= lang('Common.mediumDate', [$reply->published_at]) ?></time>
</header> </header>
<p class="mb-2 note-content"><?= $reply->message_html ?></p> <p class="mb-2 status-content"><?= $reply->message_html ?></p>
<?php if ($reply->has_preview_card): ?> <?php if ($reply->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [ <?= view('podcast/_partials/preview_card', [
'preview_card' => $reply->preview_card, 'preview_card' => $reply->preview_card,

View File

@ -0,0 +1,40 @@
<article class="relative z-10 w-full bg-white shadow-md rounded-2xl">
<header class="flex px-6 py-4">
<img src="<?= $status->actor
->avatar_image_url ?>" alt="<?= $status->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0">
<a href="<?= $status->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $status
->actor->is_local
? ''
: 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $status->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $status->actor
->username .
($status->actor->is_local
? ''
: '@' . $status->actor->domain) ?></span>
</a>
<a href="<?= route_to('status', $podcast->name, $status->id) ?>"
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $status->published_at->format(DateTime::ATOM) ?>"
title="<?= $status->published_at ?>"
><?= lang('Common.mediumDate', [$status->published_at]) ?></time>
</a>
</div>
</header>
<div class="px-6 mb-4 status-content"><?= $status->message_html ?></div>
<?php if ($status->episode_id): ?>
<?= view('podcast/_partials/episode_card', [
'episode' => $status->episode,
]) ?>
<?php elseif ($status->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [
'preview_card' => $status->preview_card,
]) ?>
<?php endif; ?>
<?= $this->include('podcast/_partials/status_actions') ?>
</article>

View File

@ -0,0 +1,36 @@
<footer class="flex justify-around px-6 py-3">
<?= anchor(
route_to('status', $podcast->name, $status->id),
icon('chat', 'text-2xl mr-1 text-gray-400') . $status->replies_count,
[
'class' => 'inline-flex items-center hover:underline',
'title' => lang('Status.replies', [
'numberOfReplies' => $status->replies_count,
]),
],
) ?>
<?= anchor_popup(
route_to('status-remote-action', $podcast->name, $status->id, 'reblog'),
icon('repeat', 'text-2xl mr-1 text-gray-400') . $status->reblogs_count,
[
'class' => 'inline-flex items-center hover:underline',
'width' => 420,
'height' => 620,
'title' => lang('Status.reblogs', [
'numberOfReblogs' => $status->reblogs_count,
]),
],
) ?>
<?= anchor_popup(
route_to('status-remote-action', $podcast->name, $status->id, 'favourite'),
icon('heart', 'text-2xl mr-1 text-gray-400') . $status->favourites_count,
[
'class' => 'inline-flex items-center hover:underline',
'width' => 420,
'height' => 620,
'title' => lang('Status.favourites', [
'numberOfFavourites' => $status->favourites_count,
]),
],
) ?>
</footer>

View File

@ -1,87 +1,87 @@
<footer class="px-6 py-3"> <footer class="px-6 py-3">
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-action', 'status-attempt-action',
interact_as_actor()->username, interact_as_actor()->username,
$note->id, $status->id,
) ?>" method="POST" class="flex justify-around"> ) ?>" method="POST" class="flex justify-around">
<?= csrf_field() ?> <?= csrf_field() ?>
<?= anchor( <?= anchor(
route_to('note', $podcast->name, $note->id), route_to('status', $podcast->name, $status->id),
icon('chat', 'text-2xl mr-1 text-gray-400') . $note->replies_count, icon('chat', 'text-2xl mr-1 text-gray-400') . $status->replies_count,
[ [
'class' => 'inline-flex items-center hover:underline', 'class' => 'inline-flex items-center hover:underline',
'title' => lang('Note.replies', [ 'title' => lang('Status.replies', [
'numberOfReplies' => $note->replies_count, 'numberOfReplies' => $status->replies_count,
]), ]),
], ],
) ?> ) ?>
<button type="submit" name="action" value="reblog" class="inline-flex items-center hover:underline" title="<?= lang( <button type="submit" name="action" value="reblog" class="inline-flex items-center hover:underline" title="<?= lang(
'Note.reblogs', 'Status.reblogs',
[ [
'numberOfReblogs' => $note->reblogs_count, 'numberOfReblogs' => $status->reblogs_count,
], ],
) ?>"><?= icon('repeat', 'text-2xl mr-1 text-gray-400') . ) ?>"><?= icon('repeat', 'text-2xl mr-1 text-gray-400') .
$note->reblogs_count ?></button> $status->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center hover:underline" title="<?= lang( <button type="submit" name="action" value="favourite" class="inline-flex items-center hover:underline" title="<?= lang(
'Note.favourites', 'Status.favourites',
[ [
'numberOfFavourites' => $note->favourites_count, 'numberOfFavourites' => $status->favourites_count,
], ],
) ?>"><?= icon('heart', 'text-2xl mr-1 text-gray-400') . ) ?>"><?= icon('heart', 'text-2xl mr-1 text-gray-400') .
$note->favourites_count ?></button> $status->favourites_count ?></button>
<button id="<?= $note->id . <button id="<?= $status->id .
'-more-dropdown' ?>" type="button" class="px-2 py-1 text-2xl text-gray-500 outline-none focus:ring" data-dropdown="button" data-dropdown-target="<?= $note->id . '-more-dropdown' ?>" type="button" class="px-2 py-1 text-2xl text-gray-500 outline-none focus:ring" data-dropdown="button" data-dropdown-target="<?= $status->id .
'-more-dropdown-menu' ?>" aria-label="<?= lang( '-more-dropdown-menu' ?>" aria-label="<?= lang(
'Common.more', 'Common.more',
) ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?> ) ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?>
</button> </button>
</form> </form>
<nav id="<?= $note->id . <nav id="<?= $status->id .
'-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm bg-white border rounded-lg shadow" aria-labelledby="<?= $note->id . '-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm bg-white border rounded-lg shadow" aria-labelledby="<?= $status->id .
'-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom"> '-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom">
<?= anchor( <?= anchor(
route_to('note', $podcast->name, $note->id), route_to('status', $podcast->name, $status->id),
lang('Note.expand'), lang('Status.expand'),
[ [
'class' => 'px-4 py-1 hover:bg-gray-100', 'class' => 'px-4 py-1 hover:bg-gray-100',
], ],
) ?> ) ?>
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-block-actor', 'status-attempt-block-actor',
interact_as_actor()->username, interact_as_actor()->username,
$note->id, $status->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>
<button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang( <button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang(
'Note.block_actor', 'Status.block_actor',
[ [
'actorUsername' => $note->actor->username, 'actorUsername' => $status->actor->username,
], ],
) ?></button> ) ?></button>
</form> </form>
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-block-domain', 'status-attempt-block-domain',
interact_as_actor()->username, interact_as_actor()->username,
$note->id, $status->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>
<button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang( <button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang(
'Note.block_domain', 'Status.block_domain',
[ [
'actorDomain' => $note->actor->domain, 'actorDomain' => $status->actor->domain,
], ],
) ?></button> ) ?></button>
</form> </form>
<?php if ($note->actor->is_local): ?> <?php if ($status->actor->is_local): ?>
<hr class="my-2" /> <hr class="my-2" />
<form action="<?= route_to( <form action="<?= route_to(
'note-attempt-delete', 'status-attempt-delete',
$note->actor->username, $status->actor->username,
$note->id, $status->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>
<button class="w-full px-4 py-1 font-semibold text-left text-red-600 hover:bg-gray-100"><?= lang( <button class="w-full px-4 py-1 font-semibold text-left text-red-600 hover:bg-gray-100"><?= lang(
'Note.delete', 'Status.delete',
) ?></button> ) ?></button>
</form> </form>
<?php endif; ?> <?php endif; ?>

View File

@ -0,0 +1,40 @@
<article class="relative z-10 w-full bg-white shadow-md rounded-2xl">
<header class="flex px-6 py-4">
<img src="<?= $status->actor
->avatar_image_url ?>" alt="<?= $status->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0">
<a href="<?= $status->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $status
->actor->is_local
? ''
: 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $status->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $status->actor
->username .
($status->actor->is_local
? ''
: '@' . $status->actor->domain) ?></span>
</a>
<a href="<?= route_to('status', $podcast->name, $status->id) ?>"
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $status->published_at->format(DateTime::ATOM) ?>"
title="<?= $status->published_at ?>"
><?= lang('Common.mediumDate', [$status->published_at]) ?></time>
</a>
</div>
</header>
<div class="px-6 mb-4 status-content"><?= $status->message_html ?></div>
<?php if ($status->episode_id): ?>
<?= view('podcast/_partials/episode_card', [
'episode' => $status->episode,
]) ?>
<?php elseif ($status->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [
'preview_card' => $status->preview_card,
]) ?>
<?php endif; ?>
<?= $this->include('podcast/_partials/status_actions_authenticated') ?>
</article>

View File

@ -1,10 +1,10 @@
<?= $this->include('podcast/_partials/note') ?> <?= $this->include('podcast/_partials/status') ?>
<div class="-mt-2 overflow-hidden border-b border-l border-r note-replies rounded-b-xl"> <div class="-mt-2 overflow-hidden border-b border-l border-r status-replies rounded-b-xl">
<div class="px-6 pt-8 pb-4 bg-gray-50"> <div class="px-6 pt-8 pb-4 bg-gray-50">
<?= anchor_popup( <?= anchor_popup(
route_to('note-remote-action', $podcast->name, $note->id, 'reply'), route_to('status-remote-action', $podcast->name, $status->id, 'reply'),
lang('Note.reply_to', ['actorUsername' => $note->actor->username]), lang('Status.reply_to', ['actorUsername' => $status->actor->username]),
[ [
'class' => 'class' =>
'text-center justify-center font-semibold rounded-full shadow relative z-10 px-4 py-2 w-full bg-rose-600 text-white inline-flex items-center hover:bg-rose-700', 'text-center justify-center font-semibold rounded-full shadow relative z-10 px-4 py-2 w-full bg-rose-600 text-white inline-flex items-center hover:bg-rose-700',
@ -15,8 +15,8 @@
</div> </div>
<?php if ($note->has_replies): ?> <?php if ($status->has_replies): ?>
<?php foreach ($note->replies as $reply): ?> <?php foreach ($status->replies as $reply): ?>
<?= view('podcast/_partials/reply', ['reply' => $reply]) ?> <?= view('podcast/_partials/reply', ['reply' => $reply]) ?>
<?php endforeach; ?> <?php endforeach; ?>
<?php endif; ?> <?php endif; ?>

View File

@ -1,7 +1,7 @@
<?= $this->include('podcast/_partials/note_authenticated') ?> <?= $this->include('podcast/_partials/status_authenticated') ?>
<div class="-mt-2 overflow-hidden border-b border-l border-r note-replies rounded-b-xl"> <div class="-mt-2 overflow-hidden border-b border-l border-r status-replies rounded-b-xl">
<?= form_open( <?= form_open(
route_to('note-attempt-action', interact_as_actor()->username, $note->id), route_to('status-attempt-action', interact_as_actor()->username, $status->id),
[ [
'class' => 'bg-gray-50 flex px-6 pt-8 pb-4', 'class' => 'bg-gray-50 flex px-6 pt-8 pb-4',
], ],
@ -16,8 +16,8 @@
'name' => 'message', 'name' => 'message',
'class' => 'form-textarea mb-4 w-full', 'class' => 'form-textarea mb-4 w-full',
'required' => 'required', 'required' => 'required',
'placeholder' => lang('Note.form.reply_to_placeholder', [ 'placeholder' => lang('Status.form.reply_to_placeholder', [
'actorUsername' => $note->actor->username, 'actorUsername' => $status->actor->username,
]), ]),
], ],
old('message', '', false), old('message', '', false),
@ -26,7 +26,7 @@
], ],
) ?> ) ?>
<?= button( <?= button(
lang('Note.form.submit_reply'), lang('Status.form.submit_reply'),
'', '',
['variant' => 'primary', 'size' => 'small'], ['variant' => 'primary', 'size' => 'small'],
[ [
@ -39,8 +39,8 @@
</div> </div>
<?= form_close() ?> <?= form_close() ?>
<?php if ($note->has_replies): ?> <?php if ($status->has_replies): ?>
<?php foreach ($note->replies as $reply): ?> <?php foreach ($status->replies as $reply): ?>
<?= view('podcast/_partials/reply_authenticated', [ <?= view('podcast/_partials/reply_authenticated', [
'reply' => $reply, 'reply' => $reply,
]) ?> ]) ?>

View File

@ -39,13 +39,13 @@
</nav> </nav>
<section class="max-w-2xl px-6 py-8 mx-auto space-y-8"> <section class="max-w-2xl px-6 py-8 mx-auto space-y-8">
<?php foreach ($notes as $note): ?> <?php foreach ($statuses as $status): ?>
<?php if ($note->reblog_of_id !== null): ?> <?php if ($status->reblog_of_id !== null): ?>
<?= view('podcast/_partials/reblog', [ <?= view('podcast/_partials/reblog', [
'note' => $note->reblog_of_note, 'status' => $status->reblog_of_status,
]) ?> ]) ?>
<?php else: ?> <?php else: ?>
<?= view('podcast/_partials/note', ['note' => $note]) ?> <?= view('podcast/_partials/status', ['status' => $status]) ?>
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
</section> </section>

View File

@ -39,7 +39,7 @@
</nav> </nav>
<section class="max-w-2xl px-6 py-8 mx-auto"> <section class="max-w-2xl px-6 py-8 mx-auto">
<?= form_open(route_to('note-attempt-create', interact_as_actor()->username), [ <?= form_open(route_to('status-attempt-create', interact_as_actor()->username), [
'class' => 'flex p-4 bg-white shadow rounded-xl', 'class' => 'flex p-4 bg-white shadow rounded-xl',
]) ?> ]) ?>
<?= csrf_field() ?> <?= csrf_field() ?>
@ -56,7 +56,7 @@
'name' => 'message', 'name' => 'message',
'class' => 'form-textarea', 'class' => 'form-textarea',
'required' => 'required', 'required' => 'required',
'placeholder' => lang('Note.form.message_placeholder'), 'placeholder' => lang('Status.form.message_placeholder'),
], ],
old('message', '', false), old('message', '', false),
['rows' => 2], ['rows' => 2],
@ -66,7 +66,7 @@
'name' => 'episode_url', 'name' => 'episode_url',
'class' => 'form-input mb-2', 'class' => 'form-input mb-2',
'placeholder' => 'placeholder' =>
lang('Note.form.episode_url_placeholder') . lang('Status.form.episode_url_placeholder') .
' (' . ' (' .
lang('Common.optional') . lang('Common.optional') .
')', ')',
@ -74,7 +74,7 @@
]) ?> ]) ?>
<?= button( <?= button(
lang('Note.form.submit'), lang('Status.form.submit'),
'', '',
['variant' => 'primary', 'size' => 'small'], ['variant' => 'primary', 'size' => 'small'],
['type' => 'submit', 'class' => 'self-end'], ['type' => 'submit', 'class' => 'self-end'],
@ -84,13 +84,13 @@
<hr class="my-4 border-2 border-pine-100"> <hr class="my-4 border-2 border-pine-100">
<div class="space-y-8"> <div class="space-y-8">
<?php foreach ($notes as $note): ?> <?php foreach ($statuses as $status): ?>
<?php if ($note->reblog_of_id !== null): ?> <?php if ($status->reblog_of_id !== null): ?>
<?= view('podcast/_partials/reblog_authenticated', [ <?= view('podcast/_partials/reblog_authenticated', [
'note' => $note->reblog_of_note, 'status' => $status->reblog_of_status,
]) ?> ]) ?>
<?php else: ?> <?php else: ?>
<?= view('podcast/_partials/note_authenticated', ['note' => $note]) ?> <?= view('podcast/_partials/status_authenticated', ['status' => $status]) ?>
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>

View File

@ -75,12 +75,12 @@
<?= anchor( <?= anchor(
route_to('episode', $podcast->name, $episode->slug), route_to('episode', $podcast->name, $episode->slug),
icon('chat', 'text-xl mr-1 text-gray-400') . icon('chat', 'text-xl mr-1 text-gray-400') .
$episode->notes_total, $episode->statuses_total,
[ [
'class' => 'class' =>
'inline-flex items-center hover:underline', 'inline-flex items-center hover:underline',
'title' => lang('Episode.total_notes', [ 'title' => lang('Episode.total_statuses', [
'numberOfTotalNotes' => $episode->notes_total, 'numberOfTotalStatuses' => $episode->statuses_total,
]), ]),
], ],
) ?> ) ?>
@ -122,24 +122,24 @@
</header> </header>
<div class="tabset"> <div class="tabset">
<?php if ($episode->notes): ?> <?php if ($episode->statuses): ?>
<input type="radio" name="tabset" id="activity" aria-controls="activity" checked="checked" /> <input type="radio" name="tabset" id="activity" aria-controls="activity" checked="checked" />
<label for="activity"><?= lang('Episode.activity') ?></label> <label for="activity"><?= lang('Episode.activity') ?></label>
<?php endif; ?> <?php endif; ?>
<input type="radio" name="tabset" id="description" aria-controls="description" <?= $episode->notes <input type="radio" name="tabset" id="description" aria-controls="description" <?= $episode->statuses
? '' ? ''
: 'checked="checked"' ?> /> : 'checked="checked"' ?> />
<label for="description" class="<?= $episode->notes <label for="description" class="<?= $episode->statuses
? '' ? ''
: 'col-span-2' ?>"><?= lang('Episode.description') ?></label> : 'col-span-2' ?>"><?= lang('Episode.description') ?></label>
<div class="tab-panels"> <div class="tab-panels">
<?php if ($episode->notes): ?> <?php if ($episode->statuses): ?>
<section id="activity" class="space-y-8 tab-panel"> <section id="activity" class="space-y-8 tab-panel">
<?php foreach ($episode->notes as $note): ?> <?php foreach ($episode->statuses as $status): ?>
<?= view('podcast/_partials/note', ['note' => $note]) ?> <?= view('podcast/_partials/status', ['status' => $status]) ?>
<?php endforeach; ?> <?php endforeach; ?>
</section> </section>
<?php endif; ?> <?php endif; ?>

View File

@ -75,12 +75,12 @@
<?= anchor( <?= anchor(
route_to('episode', $podcast->name, $episode->slug), route_to('episode', $podcast->name, $episode->slug),
icon('chat', 'text-xl mr-1 text-gray-400') . icon('chat', 'text-xl mr-1 text-gray-400') .
$episode->notes_total, $episode->statuses_total,
[ [
'class' => 'class' =>
'inline-flex items-center hover:underline', 'inline-flex items-center hover:underline',
'title' => lang('Episode.total_notes', [ 'title' => lang('Episode.total_statuses', [
'numberOfTotalNotes' => $episode->notes_total, 'numberOfTotalStatuses' => $episode->statuses_total,
]), ]),
], ],
) ?> ) ?>
@ -130,7 +130,7 @@
<div class="tab-panels"> <div class="tab-panels">
<section id="activity" class="space-y-8 tab-panel"> <section id="activity" class="space-y-8 tab-panel">
<?= form_open(route_to('note-attempt-create', $podcast->name), [ <?= form_open(route_to('status-attempt-create', $podcast->name), [
'class' => 'flex p-4 bg-white shadow rounded-xl', 'class' => 'flex p-4 bg-white shadow rounded-xl',
]) ?> ]) ?>
<?= csrf_field() ?> <?= csrf_field() ?>
@ -148,7 +148,7 @@
'class' => 'form-textarea mb-2', 'class' => 'form-textarea mb-2',
'required' => 'required', 'required' => 'required',
'placeholder' => lang( 'placeholder' => lang(
'Note.form.episode_message_placeholder', 'Status.form.episode_message_placeholder',
), ),
], ],
old('message', '', false), old('message', '', false),
@ -163,7 +163,7 @@
'type' => 'hidden', 'type' => 'hidden',
]) ?> ]) ?>
<?= button( <?= button(
lang('Note.form.submit'), lang('Status.form.submit'),
'', '',
['variant' => 'primary', 'size' => 'small'], ['variant' => 'primary', 'size' => 'small'],
['type' => 'submit', 'class' => 'self-end'], ['type' => 'submit', 'class' => 'self-end'],
@ -171,9 +171,9 @@
</div> </div>
<?= form_close() ?> <?= form_close() ?>
<hr class="my-4 border border-pine-100"> <hr class="my-4 border border-pine-100">
<?php foreach ($episode->notes as $note): ?> <?php foreach ($episode->statuses as $status): ?>
<?= view('podcast/_partials/note_authenticated', [ <?= view('podcast/_partials/status_authenticated', [
'note' => $note, 'status' => $status,
]) ?> ]) ?>
<?php endforeach; ?> <?php endforeach; ?>
</section> </section>

View File

@ -121,12 +121,12 @@
<?= anchor( <?= anchor(
route_to('episode', $podcast->name, $episode->slug), route_to('episode', $podcast->name, $episode->slug),
icon('chat', 'text-xl mr-1 text-gray-400') . icon('chat', 'text-xl mr-1 text-gray-400') .
$episode->notes_total, $episode->statuses_total,
[ [
'class' => 'class' =>
'inline-flex items-center hover:underline', 'inline-flex items-center hover:underline',
'title' => lang('Episode.total_notes', [ 'title' => lang('Episode.total_statuses', [
'numberOfTotalNotes' => $episode->notes_total, 'numberOfTotalStatuses' => $episode->statuses_total,
]), ]),
], ],
) ?> ) ?>

View File

@ -121,12 +121,12 @@
<?= anchor( <?= anchor(
route_to('episode', $podcast->name, $episode->slug), route_to('episode', $podcast->name, $episode->slug),
icon('chat', 'text-xl mr-1 text-gray-400') . icon('chat', 'text-xl mr-1 text-gray-400') .
$episode->notes_total, $episode->statuses_total,
[ [
'class' => 'class' =>
'inline-flex items-center hover:underline', 'inline-flex items-center hover:underline',
'title' => lang('Episode.total_notes', [ 'title' => lang('Episode.total_statuses', [
'numberOfTotalNotes' => $episode->notes_total, 'numberOfTotalStatuses' => $episode->statuses_total,
]), ]),
], ],
) ?> ) ?>

View File

@ -1,38 +0,0 @@
<?= $this->extend('podcast/_layout') ?>
<?= $this->section('meta-tags') ?>
<title><?= lang('Note.title', [
'actorDisplayName' => $note->actor->display_name,
]) ?></title>
<meta name="description" content="<?= $note->message ?>"/>
<meta property="og:title" content="<?= lang('Note.title', [
'actorDisplayName' => $note->actor->display_name,
]) ?>"/>
<meta property="og:locale" content="<?= service(
'request',
)->getLocale() ?>" />
<meta property="og:site_name" content="<?= $note->actor->display_name ?>" />
<meta property="og:url" content="<?= current_url() ?>" />
<meta property="og:image" content="<?= $note->actor->avatar_image_url ?>" />
<meta property="og:description" content="<?= $note->message ?>" />
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="max-w-2xl px-6 mx-auto">
<nav class="py-3">
<a href="<?= route_to('podcast-activity', $podcast->name) ?>"
class="inline-flex items-center px-4 py-2 text-sm"><?= icon(
'arrow-left',
'mr-2 text-lg',
) .
lang('Note.back_to_actor_notes', [
'actor' => $note->actor->display_name,
]) ?></a>
</nav>
<div class="pb-12">
<?= $this->include('podcast/_partials/note_with_replies') ?>
</div>
</div>
<?= $this->endSection()
?>

View File

@ -0,0 +1,38 @@
<?= $this->extend('podcast/_layout') ?>
<?= $this->section('meta-tags') ?>
<title><?= lang('Status.title', [
'actorDisplayName' => $status->actor->display_name,
]) ?></title>
<meta name="description" content="<?= $status->message ?>"/>
<meta property="og:title" content="<?= lang('Status.title', [
'actorDisplayName' => $status->actor->display_name,
]) ?>"/>
<meta property="og:locale" content="<?= service(
'request',
)->getLocale() ?>" />
<meta property="og:site_name" content="<?= $status->actor->display_name ?>" />
<meta property="og:url" content="<?= current_url() ?>" />
<meta property="og:image" content="<?= $status->actor->avatar_image_url ?>" />
<meta property="og:description" content="<?= $status->message ?>" />
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="max-w-2xl px-6 mx-auto">
<nav class="py-3">
<a href="<?= route_to('podcast-activity', $podcast->name) ?>"
class="inline-flex items-center px-4 py-2 text-sm"><?= icon(
'arrow-left',
'mr-2 text-lg',
) .
lang('Status.back_to_actor_statuses', [
'actor' => $status->actor->display_name,
]) ?></a>
</nav>
<div class="pb-12">
<?= $this->include('podcast/_partials/status_with_replies') ?>
</div>
</div>
<?= $this->endSection()
?>

View File

@ -1,20 +1,20 @@
<?= $this->extend('podcast/_layout_authenticated') ?> <?= $this->extend('podcast/_layout_authenticated') ?>
<?= $this->section('meta-tags') ?> <?= $this->section('meta-tags') ?>
<title><?= lang('Note.title', [ <title><?= lang('Status.title', [
'actorDisplayName' => $note->actor->display_name, 'actorDisplayName' => $status->actor->display_name,
]) ?></title> ]) ?></title>
<meta name="description" content="<?= $note->message ?>"/> <meta name="description" content="<?= $status->message ?>"/>
<meta property="og:title" content="<?= lang('Note.title', [ <meta property="og:title" content="<?= lang('Status.title', [
'actorDisplayName' => $note->actor->display_name, 'actorDisplayName' => $status->actor->display_name,
]) ?>"/> ]) ?>"/>
<meta property="og:locale" content="<?= service( <meta property="og:locale" content="<?= service(
'request', 'request',
)->getLocale() ?>" /> )->getLocale() ?>" />
<meta property="og:site_name" content="<?= $note->actor->display_name ?>" /> <meta property="og:site_name" content="<?= $status->actor->display_name ?>" />
<meta property="og:url" content="<?= current_url() ?>" /> <meta property="og:url" content="<?= current_url() ?>" />
<meta property="og:image" content="<?= $note->actor->avatar_image_url ?>" /> <meta property="og:image" content="<?= $status->actor->avatar_image_url ?>" />
<meta property="og:description" content="<?= $note->message ?>" /> <meta property="og:description" content="<?= $status->message ?>" />
<?= $this->endSection() ?> <?= $this->endSection() ?>
<?= $this->section('content') ?> <?= $this->section('content') ?>
@ -25,13 +25,13 @@
'arrow-left', 'arrow-left',
'mr-2 text-lg', 'mr-2 text-lg',
) . ) .
lang('Note.back_to_actor_notes', [ lang('Status.back_to_actor_statuses', [
'actor' => $note->actor->display_name, 'actor' => $status->actor->display_name,
]) ?></a> ]) ?></a>
</nav> </nav>
<div class="pb-12"> <div class="pb-12">
<?= $this->include( <?= $this->include(
'podcast/_partials/note_with_replies_authenticated', 'podcast/_partials/status_with_replies_authenticated',
) ?> ) ?>
</div> </div>
</div> </div>

View File

@ -7,22 +7,22 @@
<link rel="shortcut icon" type="image/png" href="/favicon.ico" /> <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
<title><?= lang('ActivityPub.' . $action . '.title', [ <title><?= lang('ActivityPub.' . $action . '.title', [
'actorDisplayName' => $note->actor->display_name, 'actorDisplayName' => $status->actor->display_name,
]) ?></title> ]) ?></title>
<meta name="description" content="<?= $note->message ?>"/> <meta name="description" content="<?= $status->message ?>"/>
<meta property="og:title" content="<?= lang( <meta property="og:title" content="<?= lang(
'ActivityPub.' . $action . '.title', 'ActivityPub.' . $action . '.title',
[ [
'actorDisplayName' => $note->actor->display_name, 'actorDisplayName' => $status->actor->display_name,
], ],
) ?>"/> ) ?>"/>
<meta property="og:locale" content="<?= service( <meta property="og:locale" content="<?= service(
'request', 'request',
)->getLocale() ?>" /> )->getLocale() ?>" />
<meta property="og:site_name" content="<?= $note->actor->display_name ?>" /> <meta property="og:site_name" content="<?= $status->actor->display_name ?>" />
<meta property="og:url" content="<?= current_url() ?>" /> <meta property="og:url" content="<?= current_url() ?>" />
<meta property="og:image" content="<?= $note->actor->avatar_image_url ?>" /> <meta property="og:image" content="<?= $status->actor->avatar_image_url ?>" />
<meta property="og:description" content="<?= $note->message ?>" /> <meta property="og:description" content="<?= $status->message ?>" />
<link rel="stylesheet" href="/assets/index.css"/> <link rel="stylesheet" href="/assets/index.css"/>
<script src="/assets/podcast.js" type="module"></script> <script src="/assets/podcast.js" type="module"></script>
@ -35,10 +35,10 @@
) ?></h1> ) ?></h1>
</header> </header>
<main class="flex-1 max-w-xl px-4 pb-8 mx-auto -mt-24"> <main class="flex-1 max-w-xl px-4 pb-8 mx-auto -mt-24">
<?= $this->include('podcast/_partials/note') ?> <?= $this->include('podcast/_partials/status') ?>
<?= form_open( <?= form_open(
route_to('note-attempt-remote-action', $note->id, $action), route_to('status-attempt-remote-action', $status->id, $action),
['method' => 'post', 'class' => 'flex flex-col mt-8'], ['method' => 'post', 'class' => 'flex flex-col mt-8'],
) ?> ) ?>
<?= csrf_field() ?> <?= csrf_field() ?>