From 7ff1dbe9030768074b2fe7c7f570bfb9e7336f62 Mon Sep 17 00:00:00 2001 From: Yassine Doghri Date: Sat, 26 Aug 2023 13:03:01 +0000 Subject: [PATCH] fix: remove fediverse prefix to prevent migration error + load routes during podcast import refactor migration queries to use forge functions --- app/Config/View.php | 6 +- app/Controllers/EpisodeController.php | 2 +- .../2021-05-30-101500_add_podcasts.php | 2 +- .../2021-06-05-170000_add_episodes.php | 6 +- ...2021-08-12-150000_add_episode_comments.php | 5 +- .../2021-08-12-160000_add_likes.php | 5 +- .../2021-12-25-150000_add_credits_view.php | 4 +- ...2-02-23-100000_add_episode_id_to_posts.php | 28 ++-- ...2-03-09-113000_add_created_by_to_posts.php | 28 ++-- ...12-010000_add_full_text_search_indexes.php | 20 +-- app/Entities/Clip/BaseClip.php | 3 +- app/Entities/Episode.php | 3 +- app/Entities/EpisodeComment.php | 3 +- app/Entities/Podcast.php | 3 +- app/Filters/AllowCorsFilter.php | 6 + app/Helpers/components_helper.php | 6 +- app/Libraries/RouteCollection.php | 153 +++++++++++++++++- .../ViewComponents/ComponentRenderer.php | 4 +- app/Libraries/Vite/Vite.php | 8 +- app/Models/CategoryModel.php | 9 +- app/Models/EpisodeCommentModel.php | 2 +- app/Models/EpisodeModel.php | 16 +- app/Models/PersonModel.php | 2 +- app/Models/PlatformModel.php | 4 +- app/Models/PodcastModel.php | 17 +- app/Models/PostModel.php | 4 +- modules/Auth/Commands/RolesDoc.php | 4 +- .../Controllers/ContributorController.php | 6 +- modules/Auth/Controllers/UserController.php | 4 +- modules/Fediverse/Config/Fediverse.php | 2 - .../Fediverse/Controllers/ActorController.php | 9 +- .../2018-01-01-010000_add_actors.php | 4 +- .../2018-01-01-020000_add_posts.php | 13 +- .../2018-01-01-100000_add_activities.php | 13 +- .../2018-01-01-100000_add_favourites.php | 11 +- .../2018-01-01-100000_add_follows.php | 11 +- .../2018-01-01-100000_add_preview_cards.php | 4 +- ...8-01-01-110000_add_posts_preview_cards.php | 11 +- .../2018-01-01-120000_add_blocked_domains.php | 4 +- .../2018-01-01-130000_add_notifications.php | 15 +- .../Fediverse/Helpers/fediverse_helper.php | 4 +- modules/Fediverse/Models/ActivityModel.php | 5 +- modules/Fediverse/Models/ActorModel.php | 39 ++--- modules/Fediverse/Models/BaseModel.php | 26 --- modules/Fediverse/Models/BaseUuidModel.php | 20 --- .../Fediverse/Models/BlockedDomainModel.php | 5 +- modules/Fediverse/Models/FavouriteModel.php | 5 +- modules/Fediverse/Models/FollowModel.php | 5 +- .../Fediverse/Models/NotificationModel.php | 5 +- modules/Fediverse/Models/PostModel.php | 53 +++--- modules/Fediverse/Models/PreviewCardModel.php | 11 +- .../Install/Controllers/InstallController.php | 2 - modules/Media/Helpers/url_helper.php | 2 +- .../PodcastImport/Commands/PodcastImport.php | 6 +- modules/Update/Commands/DatabaseUpdate.php | 2 - ...0_add_is_published_on_hubs_to_podcasts.php | 16 +- ...0_add_is_published_on_hubs_to_episodes.php | 16 +- rector.php | 4 - themes/cp_admin/_partials/_nav_header.php | 20 +-- themes/cp_admin/episode/_card.php | 4 +- themes/cp_admin/episode/list.php | 4 +- themes/cp_admin/podcast/notifications.php | 8 +- themes/cp_app/_admin_navbar.php | 20 +-- 63 files changed, 387 insertions(+), 355 deletions(-) delete mode 100644 modules/Fediverse/Models/BaseModel.php delete mode 100644 modules/Fediverse/Models/BaseUuidModel.php diff --git a/app/Config/View.php b/app/Config/View.php index 104cdd8d..ae4d7475 100644 --- a/app/Config/View.php +++ b/app/Config/View.php @@ -27,7 +27,8 @@ class View extends BaseView * * Examples: { title|esc(js) } { created_on|date(Y-m-d)|esc(attr) } * - * @var string[] + * @var array + * @phpstan-var array */ public $filters = []; @@ -35,7 +36,8 @@ class View extends BaseView * Parser Plugins provide a way to extend the functionality provided by the core Parser by creating aliases that * will be replaced with any callable. Can be single or tag pair. * - * @var string[] + * @var array + * @phpstan-var array */ public $plugins = []; diff --git a/app/Controllers/EpisodeController.php b/app/Controllers/EpisodeController.php index 71f7cc92..46a4f860 100644 --- a/app/Controllers/EpisodeController.php +++ b/app/Controllers/EpisodeController.php @@ -290,7 +290,7 @@ class EpisodeController extends BaseController $episodeComments = model(PostModel::class) ->whereIn('in_reply_to_id', function (BaseBuilder $builder): BaseBuilder { return $builder->select('id') - ->from(config('Fediverse')->tablesPrefix . 'posts') + ->from('fediverse_posts') ->where('episode_id', $this->episode->id); }) ->where('`published_at` <= UTC_TIMESTAMP()', null, false) diff --git a/app/Database/Migrations/2021-05-30-101500_add_podcasts.php b/app/Database/Migrations/2021-05-30-101500_add_podcasts.php index 006d7224..fbf6916b 100644 --- a/app/Database/Migrations/2021-05-30-101500_add_podcasts.php +++ b/app/Database/Migrations/2021-05-30-101500_add_podcasts.php @@ -195,7 +195,7 @@ class AddPodcasts extends BaseMigration $this->forge->addUniqueKey('handle'); $this->forge->addUniqueKey('guid'); $this->forge->addUniqueKey('actor_id'); - $this->forge->addForeignKey('actor_id', config('Fediverse')->tablesPrefix . 'actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('cover_id', 'media', 'id'); $this->forge->addForeignKey('banner_id', 'media', 'id', '', 'SET NULL'); $this->forge->addForeignKey('category_id', 'categories', 'id'); diff --git a/app/Database/Migrations/2021-06-05-170000_add_episodes.php b/app/Database/Migrations/2021-06-05-170000_add_episodes.php index 22641eab..9aa57ba8 100644 --- a/app/Database/Migrations/2021-06-05-170000_add_episodes.php +++ b/app/Database/Migrations/2021-06-05-170000_add_episodes.php @@ -164,10 +164,10 @@ class AddEpisodes extends BaseMigration // Add Full-Text Search index on title and description_markdown $prefix = $this->db->getPrefix(); - $createQuery = <<db->query($createQuery); } diff --git a/app/Database/Migrations/2021-08-12-150000_add_episode_comments.php b/app/Database/Migrations/2021-08-12-150000_add_episode_comments.php index 4c1869ce..54202baa 100644 --- a/app/Database/Migrations/2021-08-12-150000_add_episode_comments.php +++ b/app/Database/Migrations/2021-08-12-150000_add_episode_comments.php @@ -64,12 +64,9 @@ class AddEpisodeComments extends BaseMigration ], ]); - $fediverseTablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addPrimaryKey('id'); $this->forge->addForeignKey('episode_id', 'episodes', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('actor_id', $fediverseTablesPrefix . 'actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('created_by', 'users', 'id'); $this->forge->createTable('episode_comments'); } diff --git a/app/Database/Migrations/2021-08-12-160000_add_likes.php b/app/Database/Migrations/2021-08-12-160000_add_likes.php index 830de1f1..53917ac0 100644 --- a/app/Database/Migrations/2021-08-12-160000_add_likes.php +++ b/app/Database/Migrations/2021-08-12-160000_add_likes.php @@ -27,12 +27,9 @@ class AddLikes extends BaseMigration ], ]); - $fediverseTablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); $this->forge->addPrimaryKey(['actor_id', 'comment_id']); - $this->forge->addForeignKey('actor_id', $fediverseTablesPrefix . 'actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('comment_id', 'episode_comments', 'id', '', 'CASCADE'); $this->forge->createTable('likes'); } diff --git a/app/Database/Migrations/2021-12-25-150000_add_credits_view.php b/app/Database/Migrations/2021-12-25-150000_add_credits_view.php index bef51fa5..9955e3ca 100644 --- a/app/Database/Migrations/2021-12-25-150000_add_credits_view.php +++ b/app/Database/Migrations/2021-12-25-150000_add_credits_view.php @@ -20,7 +20,7 @@ class AddCreditsView extends BaseMigration $podcastPersonsTable = $this->db->prefixTable('podcasts_persons'); $episodePersonsTable = $this->db->prefixTable('episodes_persons'); $episodesTable = $this->db->prefixTable('episodes'); - $createQuery = <<db->query($createQuery); } diff --git a/app/Database/Migrations/2022-02-23-100000_add_episode_id_to_posts.php b/app/Database/Migrations/2022-02-23-100000_add_episode_id_to_posts.php index c22cb5f8..ecceb7e1 100644 --- a/app/Database/Migrations/2022-02-23-100000_add_episode_id_to_posts.php +++ b/app/Database/Migrations/2022-02-23-100000_add_episode_id_to_posts.php @@ -17,10 +17,8 @@ class AddEpisodeIdToPosts extends BaseMigration public function up(): void { $prefix = $this->db->getPrefix(); - $fediverseTablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addColumn("{$fediverseTablesPrefix}posts", [ + $this->forge->addColumn('fediverse_posts', [ 'episode_id' => [ 'type' => 'INT', 'unsigned' => true, @@ -29,22 +27,22 @@ class AddEpisodeIdToPosts extends BaseMigration ], ]); - $alterQuery = <<db->query($alterQuery); + $this->forge->addForeignKey( + 'episode_id', + 'episodes', + 'id', + '', + 'CASCADE', + $prefix . 'fediverse_posts_episode_id_foreign' + ); + $this->forge->processIndexes('fediverse_posts'); } public function down(): void { - $fediverseTablesPrefix = config('Fediverse') - ->tablesPrefix; + $prefix = $this->db->getPrefix(); - $this->forge->dropForeignKey( - $fediverseTablesPrefix . 'posts', - $fediverseTablesPrefix . 'posts_episode_id_foreign' - ); - $this->forge->dropColumn($fediverseTablesPrefix . 'posts', 'episode_id'); + $this->forge->dropForeignKey('fediverse_posts', $prefix . 'fediverse_posts_episode_id_foreign'); + $this->forge->dropColumn('fediverse_posts', 'episode_id'); } } diff --git a/app/Database/Migrations/2022-03-09-113000_add_created_by_to_posts.php b/app/Database/Migrations/2022-03-09-113000_add_created_by_to_posts.php index ccd6de67..93ff2022 100644 --- a/app/Database/Migrations/2022-03-09-113000_add_created_by_to_posts.php +++ b/app/Database/Migrations/2022-03-09-113000_add_created_by_to_posts.php @@ -17,10 +17,8 @@ class AddCreatedByToPosts extends BaseMigration public function up(): void { $prefix = $this->db->getPrefix(); - $fediverseTablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addColumn("{$fediverseTablesPrefix}posts", [ + $this->forge->addColumn('fediverse_posts', [ 'created_by' => [ 'type' => 'INT', 'unsigned' => true, @@ -29,22 +27,22 @@ class AddCreatedByToPosts extends BaseMigration ], ]); - $alterQuery = <<db->query($alterQuery); + $this->forge->addForeignKey( + 'created_by', + 'users', + 'id', + '', + 'CASCADE', + $prefix . 'fediverse_posts_created_by_foreign' + ); + $this->forge->processIndexes('fediverse_posts'); } public function down(): void { - $fediverseTablesPrefix = config('Fediverse') - ->tablesPrefix; + $prefix = $this->db->getPrefix(); - $this->forge->dropForeignKey( - $fediverseTablesPrefix . 'posts', - $fediverseTablesPrefix . 'posts_created_by_foreign' - ); - $this->forge->dropColumn($fediverseTablesPrefix . 'posts', 'created_by'); + $this->forge->dropForeignKey('fediverse_posts', $prefix . 'fediverse_posts_created_by_foreign'); + $this->forge->dropColumn('fediverse_posts', 'created_by'); } } diff --git a/app/Database/Migrations/2023-06-12-010000_add_full_text_search_indexes.php b/app/Database/Migrations/2023-06-12-010000_add_full_text_search_indexes.php index d5051530..310ce8f3 100644 --- a/app/Database/Migrations/2023-06-12-010000_add_full_text_search_indexes.php +++ b/app/Database/Migrations/2023-06-12-010000_add_full_text_search_indexes.php @@ -10,23 +10,23 @@ class AddFullTextSearchIndexes extends BaseMigration { $prefix = $this->db->getPrefix(); - $createQuery = <<db->query($createQuery); - $createQuery = <<db->query($createQuery); - $createQuery = <<db->query($createQuery); } @@ -35,17 +35,17 @@ class AddFullTextSearchIndexes extends BaseMigration { $prefix = $this->db->getPrefix(); - $createQuery = <<db->query($createQuery); - $createQuery = <<db->query($createQuery); } diff --git a/app/Entities/Clip/BaseClip.php b/app/Entities/Clip/BaseClip.php index 3528bfe8..d8eab7bc 100644 --- a/app/Entities/Clip/BaseClip.php +++ b/app/Entities/Clip/BaseClip.php @@ -57,7 +57,8 @@ class BaseClip extends Entity protected ?float $end_time = null; /** - * @var string[] + * @var array + * @phpstan-var list */ protected $dates = ['created_at', 'updated_at', 'job_started_at', 'job_ended_at']; diff --git a/app/Entities/Episode.php b/app/Entities/Episode.php index c7af02d3..c51e1e6d 100644 --- a/app/Entities/Episode.php +++ b/app/Entities/Episode.php @@ -144,7 +144,8 @@ class Episode extends Entity protected ?string $publication_status = null; /** - * @var string[] + * @var array + * @phpstan-var list */ protected $dates = ['published_at', 'created_at', 'updated_at']; diff --git a/app/Entities/EpisodeComment.php b/app/Entities/EpisodeComment.php index 84e20259..5b10d133 100644 --- a/app/Entities/EpisodeComment.php +++ b/app/Entities/EpisodeComment.php @@ -51,7 +51,8 @@ class EpisodeComment extends UuidEntity protected bool $has_replies = false; /** - * @var string[] + * @var array + * @phpstan-var list */ protected $dates = ['created_at']; diff --git a/app/Entities/Podcast.php b/app/Entities/Podcast.php index 0ab77601..d57a1463 100644 --- a/app/Entities/Podcast.php +++ b/app/Entities/Podcast.php @@ -166,7 +166,8 @@ class Podcast extends Entity protected ?string $publication_status = null; /** - * @var string[] + * @var array + * @phpstan-var list */ protected $dates = ['published_at', 'created_at', 'updated_at']; diff --git a/app/Filters/AllowCorsFilter.php b/app/Filters/AllowCorsFilter.php index 7edc2b6e..96d6409b 100644 --- a/app/Filters/AllowCorsFilter.php +++ b/app/Filters/AllowCorsFilter.php @@ -10,11 +10,17 @@ use CodeIgniter\HTTP\ResponseInterface; class AllowCorsFilter implements FilterInterface { + /** + * @param string[]|null $arguments + */ public function before(RequestInterface $request, $arguments = null): void { // Do something here } + /** + * @param string[]|null $arguments + */ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null): void { if (! $response->hasHeader('Cache-Control')) { diff --git a/app/Helpers/components_helper.php b/app/Helpers/components_helper.php index 176e75c7..fdc77f21 100644 --- a/app/Helpers/components_helper.php +++ b/app/Helpers/components_helper.php @@ -206,7 +206,7 @@ if (! function_exists('publication_status_banner')) { $bannerDisclaimer = lang('Podcast.publication_status_banner.draft_mode'); $bannerText = lang('Podcast.publication_status_banner.scheduled', [ 'publication_date' => local_datetime($publicationDate), - ], null, false); + ]); $linkRoute = route_to('podcast-publish_edit', $podcastId); $linkLabel = lang('Podcast.publish_edit'); break; @@ -492,10 +492,10 @@ if (! function_exists('category_label')) { { $categoryLabel = ''; if ($category->parent_id !== null) { - $categoryLabel .= lang('Podcast.category_options.' . $category->parent->code, [], null, false) . ' › '; + $categoryLabel .= lang('Podcast.category_options.' . $category->parent->code) . ' › '; } - return $categoryLabel . lang('Podcast.category_options.' . $category->code, [], null, false); + return $categoryLabel . lang('Podcast.category_options.' . $category->code); } } diff --git a/app/Libraries/RouteCollection.php b/app/Libraries/RouteCollection.php index 87576d34..75ea4757 100644 --- a/app/Libraries/RouteCollection.php +++ b/app/Libraries/RouteCollection.php @@ -14,18 +14,25 @@ declare(strict_types=1); namespace App\Libraries; +use Closure; use CodeIgniter\Router\RouteCollection as CodeIgniterRouteCollection; class RouteCollection extends CodeIgniterRouteCollection { + /** + * The current hostname from $_SERVER['HTTP_HOST'] + */ + private ?string $httpHost = null; + /** * Does the heavy lifting of creating an actual route. You must specify * the request method(s) that this route will work for. They can be separated * by a pipe character "|" if there is more than one. * - * @param array|Closure|string $to + * @param array|Closure|string $to + * @param array $options */ - protected function create(string $verb, string $from, $to, ?array $options = null) + protected function create(string $verb, string $from, $to, ?array $options = null): void { $overwrite = false; $prefix = $this->group === null ? '' : $this->group . '/'; @@ -81,8 +88,8 @@ class RouteCollection extends CodeIgniterRouteCollection // Get a constant string to work with. $to = preg_replace('/(\$\d+)/', '$X', $to); - for ($i = (int) $options['offset'] + 1; $i < (int) $options['offset'] + 7; $i++) { - $to = preg_replace_callback('/\$X/', static fn ($m) => '$' . $i, $to, 1); + for ($i = (int) $options['offset'] + 1; $i < (int) $options['offset'] + 7; ++$i) { + $to = preg_replace_callback('/\$X/', static fn ($m): string => '$' . $i, $to, 1); } } @@ -97,7 +104,7 @@ class RouteCollection extends CodeIgniterRouteCollection // If no namespace found, add the default namespace if (strpos($to, '\\') === false || strpos($to, '\\') > 0) { $namespace = $options['namespace'] ?? $this->defaultNamespace; - $to = trim($namespace, '\\') . '\\' . $to; + $to = trim((string) $namespace, '\\') . '\\' . $to; } // Always ensure that we escape our namespace so we're not pointing to // \CodeIgniter\Routes\Controller::method. @@ -134,4 +141,140 @@ class RouteCollection extends CodeIgniterRouteCollection $this->routes['*'][$name]['redirect'] = $options['redirect']; } } + + /** + * Compares the hostname passed in against the current hostname + * on this page request. + * + * @param string $hostname Hostname in route options + */ + private function checkHostname($hostname): bool + { + // CLI calls can't be on hostname. + if ($this->httpHost === null) { + return false; + } + + return strtolower($this->httpHost) === strtolower($hostname); + } + + /** + * @param array $to + * + * @return string|array + */ + private function processArrayCallableSyntax(string $from, array $to): string | array + { + // [classname, method] + // eg, [Home::class, 'index'] + if (is_callable($to, true, $callableName)) { + // If the route has placeholders, add params automatically. + $params = $this->getMethodParams($from); + + return '\\' . $callableName . $params; + } + + // [[classname, method], params] + // eg, [[Home::class, 'index'], '$1/$2'] + if ( + isset($to[0], $to[1]) + && is_callable($to[0], true, $callableName) + && is_string($to[1]) + ) { + return '\\' . $callableName . '/' . $to[1]; + } + + return $to; + } + + /** + * Compares the subdomain(s) passed in against the current subdomain + * on this page request. + * + * @param string|string[] $subdomains + */ + private function checkSubdomains($subdomains): bool + { + // CLI calls can't be on subdomain. + if ($this->httpHost === null) { + return false; + } + + if ($this->currentSubdomain === null) { + $this->currentSubdomain = $this->determineCurrentSubdomain(); + } + + if (! is_array($subdomains)) { + $subdomains = [$subdomains]; + } + + // Routes can be limited to any sub-domain. In that case, though, + // it does require a sub-domain to be present. + if (! empty($this->currentSubdomain) && in_array('*', $subdomains, true)) { + return true; + } + + return in_array($this->currentSubdomain, $subdomains, true); + } + + /** + * Returns the method param string like `/$1/$2` for placeholders + */ + private function getMethodParams(string $from): string + { + preg_match_all('/\(.+?\)/', $from, $matches); + $count = is_countable($matches[0]) ? count($matches[0]) : 0; + + $params = ''; + + for ($i = 1; $i <= $count; ++$i) { + $params .= '/$' . $i; + } + + return $params; + } + + /** + * Examines the HTTP_HOST to get the best match for the subdomain. It + * won't be perfect, but should work for our needs. + * + * It's especially not perfect since it's possible to register a domain + * with a period (.) as part of the domain name. + * + * @return false|string the subdomain + */ + private function determineCurrentSubdomain() + { + // We have to ensure that a scheme exists + // on the URL else parse_url will mis-interpret + // 'host' as the 'path'. + $url = $this->httpHost; + if (strpos($url, 'http') !== 0) { + $url = 'http://' . $url; + } + + $parsedUrl = parse_url($url); + + $host = explode('.', $parsedUrl['host']); + + if ($host[0] === 'www') { + unset($host[0]); + } + + // Get rid of any domains, which will be the last + unset($host[count($host) - 1]); + + // Account for .co.uk, .co.nz, etc. domains + if (end($host) === 'co') { + $host = array_slice($host, 0, -1); + } + + // If we only have 1 part left, then we don't have a sub-domain. + if (count($host) === 1) { + // Set it to false so we don't make it back here again. + return false; + } + + return array_shift($host); + } } diff --git a/app/Libraries/ViewComponents/ComponentRenderer.php b/app/Libraries/ViewComponents/ComponentRenderer.php index 7eb0984d..f9e916c0 100644 --- a/app/Libraries/ViewComponents/ComponentRenderer.php +++ b/app/Libraries/ViewComponents/ComponentRenderer.php @@ -82,7 +82,7 @@ class ComponentRenderer $matches[name] = tag name $matches[attributes] = array of attribute string (class="foo") */ - return preg_replace_callback($pattern, function ($match): string { + return preg_replace_callback($pattern, function (array $match): string { $view = $this->locateView($match['name']); $attributes = $this->parseAttributes($match['attributes']); @@ -104,7 +104,7 @@ class ComponentRenderer $matches[attributes] = string of tag attributes (class="foo") $matches[slot] = the content inside the tags */ - return preg_replace_callback($pattern, function ($match): string { + return preg_replace_callback($pattern, function (array $match): string { $view = $this->locateView($match['name']); $attributes = $this->parseAttributes($match['attributes']); $attributes['slot'] = $match['slot']; diff --git a/app/Libraries/Vite/Vite.php b/app/Libraries/Vite/Vite.php index 57d7ddc0..64b4202d 100644 --- a/app/Libraries/Vite/Vite.php +++ b/app/Libraries/Vite/Vite.php @@ -94,13 +94,13 @@ class Vite private function getHtmlTag(string $assetUrl, string $type): string { return match ($type) { - 'css' => << << - CODE_SAMPLE + HTML , - 'js' => << << - CODE_SAMPLE + HTML , default => '', }; diff --git a/app/Models/CategoryModel.php b/app/Models/CategoryModel.php index 50ab67fb..235139d9 100644 --- a/app/Models/CategoryModel.php +++ b/app/Models/CategoryModel.php @@ -67,15 +67,10 @@ class CategoryModel extends Model static function (array $result, Category $category): array { $result[$category->id] = ''; if ($category->parent instanceof Category) { - $result[$category->id] = lang( - 'Podcast.category_options.' . $category->parent->code, - [], - null, - false - ) . ' › '; + $result[$category->id] = lang('Podcast.category_options.' . $category->parent->code) . ' › '; } - $result[$category->id] .= lang('Podcast.category_options.' . $category->code, [], null, false); + $result[$category->id] .= lang('Podcast.category_options.' . $category->code); return $result; }, [], diff --git a/app/Models/EpisodeCommentModel.php b/app/Models/EpisodeCommentModel.php index 862177c5..bbceb48f 100644 --- a/app/Models/EpisodeCommentModel.php +++ b/app/Models/EpisodeCommentModel.php @@ -216,7 +216,7 @@ class EpisodeCommentModel extends UuidModel ) ->whereIn('in_reply_to_id', static function (BaseBuilder $builder) use (&$episodeId): BaseBuilder { return $builder->select('id') - ->from(config('Fediverse')->tablesPrefix . 'posts') + ->from('fediverse_posts') ->where([ 'episode_id' => $episodeId, 'in_reply_to_id' => null, diff --git a/app/Models/EpisodeModel.php b/app/Models/EpisodeModel.php index aceddab8..339acfb5 100644 --- a/app/Models/EpisodeModel.php +++ b/app/Models/EpisodeModel.php @@ -382,13 +382,11 @@ class EpisodeModel extends UuidModel ->groupBy('episode_id') ->getCompiledSelect(); - $postsTable = config('Fediverse') - ->tablesPrefix . 'posts'; $episodePostsRepliesCount = (new PostModel())->builder() - ->select($postsTable . '.episode_id as episode_id, COUNT(*) as `comments_count`') - ->join($postsTable . ' as fp', $postsTable . '.id = fp.in_reply_to_id') - ->where($postsTable . '.in_reply_to_id', null) - ->groupBy($postsTable . '.episode_id') + ->select('fediverse_posts.episode_id as episode_id, COUNT(*) as `comments_count`') + ->join('fediverse_posts as fp', 'fediverse_posts.id = fp.in_reply_to_id') + ->where('fediverse_posts.in_reply_to_id', null) + ->groupBy('fediverse_posts.episode_id') ->getCompiledSelect(); /** @var BaseResult $query */ @@ -409,11 +407,7 @@ class EpisodeModel extends UuidModel { $episodePostsCount = $this->builder() ->select('episodes.id, COUNT(*) as `posts_count`') - ->join( - config('Fediverse') - ->tablesPrefix . 'posts', - 'episodes.id = ' . config('Fediverse')->tablesPrefix . 'posts.episode_id' - ) + ->join('fediverse_posts', 'episodes.id = fediverse_posts.episode_id') ->where('in_reply_to_id', null) ->groupBy('episodes.id') ->get() diff --git a/app/Models/PersonModel.php b/app/Models/PersonModel.php index 83dad162..50f1fa4f 100644 --- a/app/Models/PersonModel.php +++ b/app/Models/PersonModel.php @@ -145,7 +145,7 @@ class PersonModel extends Model $this->select('`id`, `full_name`') ->orderBy('`full_name`', 'ASC') ->findAll(), - static function ($result, $person) { + static function (array $result, $person): array { $result[$person->id] = $person->full_name; return $result; }, diff --git a/app/Models/PlatformModel.php b/app/Models/PlatformModel.php index dc9475bf..14219f80 100644 --- a/app/Models/PlatformModel.php +++ b/app/Models/PlatformModel.php @@ -158,12 +158,12 @@ class PlatformModel extends Model $podcastsPlatformsTable = $this->db->prefixTable('podcasts_platforms'); $platformsTable = $this->db->prefixTable('platforms'); - $deleteJoinQuery = <<db->query($deleteJoinQuery, [$podcastId, $platformType]); diff --git a/app/Models/PodcastModel.php b/app/Models/PodcastModel.php index 0e5b732c..f64d7915 100644 --- a/app/Models/PodcastModel.php +++ b/app/Models/PodcastModel.php @@ -84,6 +84,7 @@ class PodcastModel extends Model * @var array */ protected $validationRules = [ + 'id' => 'permit_empty|is_natural_no_zero', 'title' => 'required', 'handle' => 'required|regex_match[/^[a-zA-Z0-9\_]{1,32}$/]|is_unique[podcasts.handle,id,{id}]', 'description_markdown' => 'required', @@ -174,23 +175,15 @@ class PodcastModel extends Model $prefix = $this->db->getPrefix(); if ($orderBy === 'activity') { - $fediverseTablePrefix = $prefix . config('Fediverse') - ->tablesPrefix; $this->builder() - ->select( - 'podcasts.*, MAX(' . $fediverseTablePrefix . 'posts.published_at' . ') as max_published_at' - ) - ->join( - $fediverseTablePrefix . 'posts', - $fediverseTablePrefix . 'posts.actor_id = podcasts.actor_id', - 'left' - ) + ->select('podcasts.*, MAX(`' . $prefix . 'fediverse_posts`.`published_at`) as max_published_at') + ->join('fediverse_posts', 'fediverse_posts.actor_id = podcasts.actor_id', 'left') ->groupStart() ->where( - '`' . $fediverseTablePrefix . 'posts`.`published_at` <= UTC_TIMESTAMP()', + '`' . $prefix . 'fediverse_posts`.`published_at` <= UTC_TIMESTAMP()', null, false - )->orWhere($fediverseTablePrefix . 'posts.published_at', null) + )->orWhere('fediverse_posts.published_at', null) ->groupEnd() ->groupBy('podcasts.actor_id') ->orderBy('max_published_at', 'DESC'); diff --git a/app/Models/PostModel.php b/app/Models/PostModel.php index 32639a9f..ae409903 100644 --- a/app/Models/PostModel.php +++ b/app/Models/PostModel.php @@ -58,8 +58,8 @@ class PostModel extends FediversePostModel public function setEpisodeIdForRepliesOfEpisodePosts(): int | false { // make sure that posts in reply to episode activities have an episode id - $postsToUpdate = $this->db->table(config('Fediverse')->tablesPrefix . 'posts as p1') - ->join(config('Fediverse')->tablesPrefix . 'posts as p2', 'p1.id = p2.in_reply_to_id') + $postsToUpdate = $this->db->table('fediverse_posts as p1') + ->join('fediverse_posts as p2', 'p1.id = p2.in_reply_to_id') ->select('p2.id, p1.episode_id') ->where([ 'p2.in_reply_to_id IS NOT' => null, diff --git a/modules/Auth/Commands/RolesDoc.php b/modules/Auth/Commands/RolesDoc.php index 06e263ae..6e15583e 100644 --- a/modules/Auth/Commands/RolesDoc.php +++ b/modules/Auth/Commands/RolesDoc.php @@ -82,7 +82,7 @@ class RolesDoc extends BaseCommand $pattern, ['role', 'description', 'permissions'], $authGroups->instanceGroups, - static function ($table, $key, $value) use ($instanceMatrix): void { + static function ($table, $key, array $value) use ($instanceMatrix): void { $table->addRow($value['title'], $value['description'], implode(', ', $instanceMatrix[$key])); } ); @@ -109,7 +109,7 @@ class RolesDoc extends BaseCommand $pattern, ['role', 'description', 'permissions'], $authGroups->podcastGroups, - static function ($table, $key, $value) use ($podcastMatrix): void { + static function ($table, $key, array $value) use ($podcastMatrix): void { $table->addRow($value['title'], $value['description'], implode(', ', $podcastMatrix[$key])); } ); diff --git a/modules/Auth/Controllers/ContributorController.php b/modules/Auth/Controllers/ContributorController.php index 2eb6acc7..d976bb41 100644 --- a/modules/Auth/Controllers/ContributorController.php +++ b/modules/Auth/Controllers/ContributorController.php @@ -83,7 +83,7 @@ class ContributorController extends BaseController $users = (new UserModel())->findAll(); $contributorOptions = array_reduce( $users, - static function ($result, $user) { + static function (array $result, $user): array { $result[$user->id] = $user->username; return $result; }, @@ -94,7 +94,7 @@ class ContributorController extends BaseController $roleOptions = []; array_walk( $roles, - static function ($role, $key) use (&$roleOptions): array { + static function (string $role, $key) use (&$roleOptions): array { $roleOptions[$role] = lang('Auth.podcast_groups.' . $role . '.title'); return $roleOptions; }, @@ -137,7 +137,7 @@ class ContributorController extends BaseController $roleOptions = []; array_walk( $roles, - static function ($role) use (&$roleOptions): array { + static function (string $role) use (&$roleOptions): array { $roleOptions[$role] = lang('Auth.podcast_groups.' . $role . '.title'); return $roleOptions; }, diff --git a/modules/Auth/Controllers/UserController.php b/modules/Auth/Controllers/UserController.php index 1a5d059e..9da5d0ed 100644 --- a/modules/Auth/Controllers/UserController.php +++ b/modules/Auth/Controllers/UserController.php @@ -66,7 +66,7 @@ class UserController extends BaseController $roleOptions = []; array_walk( $roles, - static function ($role, $key) use (&$roleOptions): array { + static function (array $role, $key) use (&$roleOptions): array { $roleOptions[$key] = $role['title']; return $roleOptions; }, @@ -172,7 +172,7 @@ class UserController extends BaseController $roleOptions = []; array_walk( $roles, - static function ($role, $key) use (&$roleOptions): array { + static function (array $role, $key) use (&$roleOptions): array { $roleOptions[$key] = $role['title']; return $roleOptions; }, diff --git a/modules/Fediverse/Config/Fediverse.php b/modules/Fediverse/Config/Fediverse.php index f40fec37..835567e0 100644 --- a/modules/Fediverse/Config/Fediverse.php +++ b/modules/Fediverse/Config/Fediverse.php @@ -38,8 +38,6 @@ class Fediverse extends BaseConfig public string $defaultCoverImageMimetype = 'image/jpeg'; - public string $tablesPrefix = 'fediverse_'; - /** * -------------------------------------------------------------------- * Cache options diff --git a/modules/Fediverse/Controllers/ActorController.php b/modules/Fediverse/Controllers/ActorController.php index 6048e7fe..52f35e36 100644 --- a/modules/Fediverse/Controllers/ActorController.php +++ b/modules/Fediverse/Controllers/ActorController.php @@ -291,14 +291,11 @@ class ActorController extends Controller public function followers(): ResponseInterface { - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - // get followers for a specific actor $followers = model('ActorModel', false) - ->join($tablesPrefix . 'follows', $tablesPrefix . 'follows.actor_id = id', 'inner') - ->where($tablesPrefix . 'follows.target_actor_id', $this->actor->id) - ->orderBy($tablesPrefix . 'follows.created_at', 'DESC'); + ->join('fediverse_follows', 'fediverse_follows.actor_id = id', 'inner') + ->where('fediverse_follows.target_actor_id', $this->actor->id) + ->orderBy('fediverse_follows.created_at', 'DESC'); $pageNumber = (int) $this->request->getGet('page'); diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-010000_add_actors.php b/modules/Fediverse/Database/Migrations/2018-01-01-010000_add_actors.php index c2fa15d1..ddf5228c 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-010000_add_actors.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-010000_add_actors.php @@ -113,11 +113,11 @@ class AddActors extends BaseMigration $this->forge->addPrimaryKey('id'); $this->forge->addUniqueKey('uri'); $this->forge->addUniqueKey(['username', 'domain']); - $this->forge->createTable(config('Fediverse')->tablesPrefix . 'actors'); + $this->forge->createTable('fediverse_actors'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'actors'); + $this->forge->dropTable('fediverse_actors'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php b/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php index 1f04ef2a..903f8aec 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php @@ -75,21 +75,18 @@ class AddPosts extends BaseMigration ], ]); - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addPrimaryKey('id'); $this->forge->addUniqueKey('uri'); // FIXME: an actor must reblog a post only once // $this->forge->addUniqueKey(['actor_id', 'reblog_of_id']); - $this->forge->addForeignKey('actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('in_reply_to_id', $tablesPrefix . 'posts', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('reblog_of_id', $tablesPrefix . 'posts', 'id', '', 'CASCADE'); - $this->forge->createTable($tablesPrefix . 'posts'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('in_reply_to_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('reblog_of_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_posts'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'posts'); + $this->forge->dropTable('fediverse_posts'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php index 2baa67c9..18b94cdf 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php @@ -58,18 +58,15 @@ class AddActivities extends BaseMigration ], ]); - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addPrimaryKey('id'); - $this->forge->addForeignKey('actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('target_actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('post_id', $tablesPrefix . 'posts', 'id', '', 'CASCADE'); - $this->forge->createTable($tablesPrefix . 'activities'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('target_actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_activities'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'activities'); + $this->forge->dropTable('fediverse_activities'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php index 33aaa898..75ec8f21 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php @@ -29,18 +29,15 @@ class AddFavourites extends BaseMigration ], ]); - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); $this->forge->addPrimaryKey(['actor_id', 'post_id']); - $this->forge->addForeignKey('actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('post_id', $tablesPrefix . 'posts', 'id', '', 'CASCADE'); - $this->forge->createTable($tablesPrefix . 'favourites'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_favourites'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'favourites'); + $this->forge->dropTable('fediverse_favourites'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php index 9704a7a8..0b0273ba 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php @@ -31,18 +31,15 @@ class AddFollowers extends BaseMigration ], ]); - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); $this->forge->addPrimaryKey(['actor_id', 'target_actor_id']); - $this->forge->addForeignKey('actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('target_actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->createTable($tablesPrefix . 'follows'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('target_actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_follows'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'follows'); + $this->forge->dropTable('fediverse_follows'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php index 9f143184..f0359070 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php @@ -75,11 +75,11 @@ class AddPreviewCards extends BaseMigration $this->forge->addPrimaryKey('id'); $this->forge->addUniqueKey('url'); - $this->forge->createTable(config('Fediverse')->tablesPrefix . 'preview_cards'); + $this->forge->createTable('fediverse_preview_cards'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'preview_cards'); + $this->forge->dropTable('fediverse_preview_cards'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php b/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php index d6719bcc..2bd9d9ba 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php @@ -29,17 +29,14 @@ class AddPostsPreviewCards extends BaseMigration ], ]); - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addPrimaryKey(['post_id', 'preview_card_id']); - $this->forge->addForeignKey('post_id', $tablesPrefix . 'posts', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('preview_card_id', $tablesPrefix . 'preview_cards', 'id', '', 'CASCADE'); - $this->forge->createTable($tablesPrefix . 'posts_preview_cards'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('preview_card_id', 'fediverse_preview_cards', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_posts_preview_cards'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'posts_preview_cards'); + $this->forge->dropTable('fediverse_posts_preview_cards'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php b/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php index df4d15b2..044a0e0b 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php @@ -28,11 +28,11 @@ class AddBlockedDomains extends BaseMigration ], ]); $this->forge->addPrimaryKey('name'); - $this->forge->createTable(config('Fediverse')->tablesPrefix . 'blocked_domains'); + $this->forge->createTable('fediverse_blocked_domains'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'blocked_domains'); + $this->forge->dropTable('fediverse_blocked_domains'); } } diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php b/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php index 78b0ab24..df979192 100644 --- a/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php +++ b/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php @@ -55,19 +55,16 @@ class AddNotifications extends BaseMigration ], ]); - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $this->forge->addPrimaryKey('id'); - $this->forge->addForeignKey('actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('target_actor_id', $tablesPrefix . 'actors', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('post_id', $tablesPrefix . 'posts', 'id', '', 'CASCADE'); - $this->forge->addForeignKey('activity_id', $tablesPrefix . 'activities', 'id', '', 'CASCADE'); - $this->forge->createTable($tablesPrefix . 'notifications'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('target_actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('activity_id', 'fediverse_activities', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_notifications'); } public function down(): void { - $this->forge->dropTable(config('Fediverse')->tablesPrefix . 'notifications'); + $this->forge->dropTable('fediverse_notifications'); } } diff --git a/modules/Fediverse/Helpers/fediverse_helper.php b/modules/Fediverse/Helpers/fediverse_helper.php index ee1d015e..53f662f2 100644 --- a/modules/Fediverse/Helpers/fediverse_helper.php +++ b/modules/Fediverse/Helpers/fediverse_helper.php @@ -408,7 +408,7 @@ if (! function_exists('linkify')) { ), 'handle' => preg_replace_callback( '~(?\w++)(?:@(?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]))?~', - static function ($match) use (&$links) { + static function (array $match) use (&$links) { // check if host is set and look for actor in database if (isset($match['host'])) { if ( @@ -489,7 +489,7 @@ if (! function_exists('linkify')) { // Insert all links return preg_replace_callback( '~<(\d+)>~', - static function ($match) use (&$links) { + static function (array $match) use (&$links): string { return $links[$match[1] - 1]; }, $text, diff --git a/modules/Fediverse/Models/ActivityModel.php b/modules/Fediverse/Models/ActivityModel.php index 86b0c5da..cf9181fe 100644 --- a/modules/Fediverse/Models/ActivityModel.php +++ b/modules/Fediverse/Models/ActivityModel.php @@ -13,14 +13,15 @@ namespace Modules\Fediverse\Models; use CodeIgniter\Database\BaseResult; use CodeIgniter\I18n\Time; use DateTimeInterface; +use Michalsn\Uuid\UuidModel; use Modules\Fediverse\Entities\Activity; -class ActivityModel extends BaseUuidModel +class ActivityModel extends UuidModel { /** * @var string */ - protected $table = 'activities'; + protected $table = 'fediverse_activities'; /** * @var string diff --git a/modules/Fediverse/Models/ActorModel.php b/modules/Fediverse/Models/ActorModel.php index 3b35583c..db07c0be 100644 --- a/modules/Fediverse/Models/ActorModel.php +++ b/modules/Fediverse/Models/ActorModel.php @@ -11,14 +11,15 @@ declare(strict_types=1); namespace Modules\Fediverse\Models; use CodeIgniter\Events\Events; +use CodeIgniter\Model; use Modules\Fediverse\Entities\Actor; -class ActorModel extends BaseModel +class ActorModel extends Model { /** * @var string */ - protected $table = 'actors'; + protected $table = 'fediverse_actors'; /** * @var string[] @@ -119,10 +120,8 @@ class ActorModel extends BaseModel config('Fediverse') ->cachePrefix . "actor#{$actorId}_followers"; if (! ($found = cache($cacheName))) { - $tablesPrefix = config('Fediverse') - ->tablesPrefix; - $found = $this->join($tablesPrefix . 'follows', $tablesPrefix . 'follows.actor_id = id', 'inner') - ->where($tablesPrefix . 'follows.target_actor_id', $actorId) + $found = $this->join('fediverse_follows', 'fediverse_follows.actor_id = id', 'inner') + ->where('fediverse_follows.target_actor_id', $actorId) ->findAll(); cache() @@ -225,28 +224,27 @@ class ActorModel extends BaseModel ->cachePrefix . 'blocked_actors'; if (! ($found = cache($cacheName))) { $tablePrefix = config('Database') - ->default['DBPrefix'] . config('Fediverse') - ->tablesPrefix; + ->default['DBPrefix']; $result = $this->select('COUNT(DISTINCT `cp_fediverse_actors`.`id`) as `total_active_actors`', false) ->join( - $tablePrefix . 'posts', - $tablePrefix . 'actors.id = ' . $tablePrefix . 'posts.actor_id', + $tablePrefix . 'fediverse_posts', + $tablePrefix . 'fediverse_actors.id = ' . $tablePrefix . 'fediverse_posts.actor_id', 'left outer' ) ->join( - $tablePrefix . 'favourites', - $tablePrefix . 'actors.id = ' . $tablePrefix . 'favourites.actor_id', + $tablePrefix . 'fediverse_favourites', + $tablePrefix . 'fediverse_actors.id = ' . $tablePrefix . 'fediverse_favourites.actor_id', 'left outer' ) ->where($tablePrefix . 'actors.domain', get_current_domain()) ->groupStart() ->where( - "`{$tablePrefix}posts`.`created_at` >= UTC_TIMESTAMP() - INTERVAL {$lastNumberOfMonths} month", + "`{$tablePrefix}fediverse_posts`.`created_at` >= UTC_TIMESTAMP() - INTERVAL {$lastNumberOfMonths} month", null, false ) ->orWhere( - "`{$tablePrefix}favourites`.`created_at` >= UTC_TIMESTAMP() - INTERVAL {$lastNumberOfMonths} month", + "`{$tablePrefix}fediverse_favourites`.`created_at` >= UTC_TIMESTAMP() - INTERVAL {$lastNumberOfMonths} month", null, false ) @@ -265,12 +263,8 @@ class ActorModel extends BaseModel public function resetFollowersCount(): int | false { - $tablePrefix = config('Fediverse') - ->tablesPrefix; - - $actorsFollowersCount = $this->db->table($tablePrefix . 'follows')->select( - 'target_actor_id as id, COUNT(*) as `followers_count`' - ) + $actorsFollowersCount = $this->db->table('fediverse_follows') + ->select('target_actor_id as id, COUNT(*) as `followers_count`') ->groupBy('id') ->get() ->getResultArray(); @@ -284,10 +278,7 @@ class ActorModel extends BaseModel public function resetPostsCount(): int | false { - $tablePrefix = config('Fediverse') - ->tablesPrefix; - - $actorsFollowersCount = $this->db->table($tablePrefix . 'posts')->select( + $actorsFollowersCount = $this->db->table($tablePrefix . 'fediverse_posts')->select( 'actor_id as id, COUNT(*) as `posts_count`' ) ->where([ diff --git a/modules/Fediverse/Models/BaseModel.php b/modules/Fediverse/Models/BaseModel.php deleted file mode 100644 index 685f1776..00000000 --- a/modules/Fediverse/Models/BaseModel.php +++ /dev/null @@ -1,26 +0,0 @@ -table = config('Fediverse') - ->tablesPrefix . $this->table; - } -} diff --git a/modules/Fediverse/Models/BaseUuidModel.php b/modules/Fediverse/Models/BaseUuidModel.php deleted file mode 100644 index e2f80ea9..00000000 --- a/modules/Fediverse/Models/BaseUuidModel.php +++ /dev/null @@ -1,20 +0,0 @@ -table = config('Fediverse') - ->tablesPrefix . $this->table; - } -} diff --git a/modules/Fediverse/Models/BlockedDomainModel.php b/modules/Fediverse/Models/BlockedDomainModel.php index 933f6e52..e8e4f514 100644 --- a/modules/Fediverse/Models/BlockedDomainModel.php +++ b/modules/Fediverse/Models/BlockedDomainModel.php @@ -12,14 +12,15 @@ namespace Modules\Fediverse\Models; use CodeIgniter\Database\BaseResult; use CodeIgniter\Events\Events; +use CodeIgniter\Model; use Modules\Fediverse\Entities\BlockedDomain; -class BlockedDomainModel extends BaseModel +class BlockedDomainModel extends Model { /** * @var string */ - protected $table = 'blocked_domains'; + protected $table = 'fediverse_blocked_domains'; /** * @var string diff --git a/modules/Fediverse/Models/FavouriteModel.php b/modules/Fediverse/Models/FavouriteModel.php index 3188dd2d..72afc5a0 100644 --- a/modules/Fediverse/Models/FavouriteModel.php +++ b/modules/Fediverse/Models/FavouriteModel.php @@ -11,18 +11,19 @@ declare(strict_types=1); namespace Modules\Fediverse\Models; use CodeIgniter\Events\Events; +use Michalsn\Uuid\UuidModel; use Modules\Fediverse\Activities\LikeActivity; use Modules\Fediverse\Activities\UndoActivity; use Modules\Fediverse\Entities\Actor; use Modules\Fediverse\Entities\Favourite; use Modules\Fediverse\Entities\Post; -class FavouriteModel extends BaseUuidModel +class FavouriteModel extends UuidModel { /** * @var string */ - protected $table = 'favourites'; + protected $table = 'fediverse_favourites'; /** * @var string[] diff --git a/modules/Fediverse/Models/FollowModel.php b/modules/Fediverse/Models/FollowModel.php index cf0cdcee..e866ba69 100644 --- a/modules/Fediverse/Models/FollowModel.php +++ b/modules/Fediverse/Models/FollowModel.php @@ -12,18 +12,19 @@ namespace Modules\Fediverse\Models; use CodeIgniter\Events\Events; use CodeIgniter\I18n\Time; +use CodeIgniter\Model; use Exception; use Modules\Fediverse\Activities\FollowActivity; use Modules\Fediverse\Activities\UndoActivity; use Modules\Fediverse\Entities\Actor; use Modules\Fediverse\Entities\Follow; -class FollowModel extends BaseModel +class FollowModel extends Model { /** * @var string */ - protected $table = 'follows'; + protected $table = 'fediverse_follows'; /** * @var string[] diff --git a/modules/Fediverse/Models/NotificationModel.php b/modules/Fediverse/Models/NotificationModel.php index 24732d7d..53d4f0eb 100644 --- a/modules/Fediverse/Models/NotificationModel.php +++ b/modules/Fediverse/Models/NotificationModel.php @@ -10,14 +10,15 @@ declare(strict_types=1); namespace Modules\Fediverse\Models; +use Michalsn\Uuid\UuidModel; use Modules\Fediverse\Entities\Notification; -class NotificationModel extends BaseUuidModel +class NotificationModel extends UuidModel { /** * @var string */ - protected $table = 'notifications'; + protected $table = 'fediverse_notifications'; /** * @var string diff --git a/modules/Fediverse/Models/PostModel.php b/modules/Fediverse/Models/PostModel.php index 7a07ea5b..c472a61b 100644 --- a/modules/Fediverse/Models/PostModel.php +++ b/modules/Fediverse/Models/PostModel.php @@ -15,6 +15,7 @@ use CodeIgniter\Events\Events; use CodeIgniter\HTTP\URI; use CodeIgniter\I18n\Time; use Exception; +use Michalsn\Uuid\UuidModel; use Modules\Fediverse\Activities\AnnounceActivity; use Modules\Fediverse\Activities\CreateActivity; use Modules\Fediverse\Activities\DeleteActivity; @@ -23,12 +24,12 @@ use Modules\Fediverse\Entities\Actor; use Modules\Fediverse\Entities\Post; use Modules\Fediverse\Objects\TombstoneObject; -class PostModel extends BaseUuidModel +class PostModel extends UuidModel { /** * @var string */ - protected $table = 'posts'; + protected $table = 'fediverse_posts'; /** * @var string @@ -172,16 +173,10 @@ class PostModel extends BaseUuidModel ($withBlocked ? '_withBlocked' : ''); if (! ($found = cache($cacheName))) { - $tablesPrefix = config('Fediverse') - ->tablesPrefix; if (! $withBlocked) { - $this->select($tablesPrefix . 'posts.*') - ->join( - $tablesPrefix . 'actors', - $tablesPrefix . 'actors.id = ' . $tablesPrefix . 'posts.actor_id', - 'inner' - ) - ->where($tablesPrefix . 'actors.is_blocked', 0); + $this->select('fediverse_posts.*') + ->join('fediverse_actors', 'fediverse_actors.id = fediverse_posts.actor_id', 'inner') + ->where('fediverse_actors.is_blocked', 0); } $this->where('in_reply_to_id', $this->uuid->fromString($postId) ->getBytes()) @@ -222,7 +217,7 @@ class PostModel extends BaseUuidModel public function addPreviewCard(string $postId, int $previewCardId): bool { - return $this->db->table(config('Fediverse')->tablesPrefix . 'posts_preview_cards') + return $this->db->table('fediverse_posts_preview_cards') ->insert([ 'post_id' => $this->uuid->fromString($postId) ->getBytes(), @@ -370,7 +365,7 @@ class PostModel extends BaseUuidModel if ( $post->preview_card && $this->db - ->table(config('Fediverse')->tablesPrefix . 'posts_preview_cards') + ->table('fediverse_posts_preview_cards') ->where('preview_card_id', $post->preview_card->id) ->countAll() <= 1 ) { @@ -599,11 +594,9 @@ class PostModel extends BaseUuidModel $cacheName = config('Fediverse') ->cachePrefix . 'blocked_actors'; if (! ($found = cache($cacheName))) { - $tablePrefix = config('Fediverse') - ->tablesPrefix; $result = $this->select('COUNT(*) as total_local_posts') - ->join($tablePrefix . 'actors', $tablePrefix . 'actors.id = ' . $tablePrefix . 'posts.actor_id') - ->where($tablePrefix . 'actors.domain', get_current_domain()) + ->join('fediverse_actors', 'fediverse_actors.id = fediverse_posts.actor_id') + ->where('fediverse_actors.domain', get_current_domain()) ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->get() ->getResultArray(); @@ -619,12 +612,8 @@ class PostModel extends BaseUuidModel public function resetFavouritesCount(): int | false { - $tablePrefix = config('Fediverse') - ->tablesPrefix; - - $postsFavouritesCount = $this->db->table($tablePrefix . 'favourites')->select( - 'post_id as id, COUNT(*) as `favourites_count`' - ) + $postsFavouritesCount = $this->db->table('fediverse_favourites') + ->select('post_id as id, COUNT(*) as `favourites_count`') ->groupBy('id') ->get() ->getResultArray(); @@ -639,12 +628,9 @@ class PostModel extends BaseUuidModel public function resetReblogsCount(): int | false { - $tablePrefix = config('Fediverse') - ->tablesPrefix; - - $postsReblogsCount = $this->select($tablePrefix . 'posts.id, COUNT(*) as `replies_count`') - ->join($tablePrefix . 'posts as p2', $tablePrefix . 'posts.id = p2.reblog_of_id') - ->groupBy($tablePrefix . 'posts.id') + $postsReblogsCount = $this->select('fediverse_posts.id, COUNT(*) as `replies_count`') + ->join('fediverse_posts as p2', 'fediverse_posts.id = p2.reblog_of_id') + ->groupBy('fediverse_posts.id') ->get() ->getResultArray(); @@ -658,12 +644,9 @@ class PostModel extends BaseUuidModel public function resetRepliesCount(): int | false { - $tablePrefix = config('Fediverse') - ->tablesPrefix; - - $postsRepliesCount = $this->select($tablePrefix . 'posts.id, COUNT(*) as `replies_count`') - ->join($tablePrefix . 'posts as p2', $tablePrefix . 'posts.id = p2.in_reply_to_id') - ->groupBy($tablePrefix . 'posts.id') + $postsRepliesCount = $this->select('fediverse_posts.id, COUNT(*) as `replies_count`') + ->join('fediverse_posts as p2', 'fediverse_posts.id = p2.in_reply_to_id') + ->groupBy('fediverse_posts.id') ->get() ->getResultArray(); diff --git a/modules/Fediverse/Models/PreviewCardModel.php b/modules/Fediverse/Models/PreviewCardModel.php index fb9c028e..deedbe3b 100644 --- a/modules/Fediverse/Models/PreviewCardModel.php +++ b/modules/Fediverse/Models/PreviewCardModel.php @@ -11,14 +11,15 @@ declare(strict_types=1); namespace Modules\Fediverse\Models; use CodeIgniter\Database\BaseResult; +use CodeIgniter\Model; use Modules\Fediverse\Entities\PreviewCard; -class PreviewCardModel extends BaseModel +class PreviewCardModel extends Model { /** * @var string */ - protected $table = 'preview_cards'; + protected $table = 'fediverse_preview_cards'; /** * @var string[] @@ -75,11 +76,9 @@ class PreviewCardModel extends BaseModel config('Fediverse') ->cachePrefix . "post#{$postId}_preview_card"; if (! ($found = cache($cacheName))) { - $tablesPrefix = config('Fediverse') - ->tablesPrefix; $found = $this->join( - $tablesPrefix . 'posts_preview_cards', - $tablesPrefix . 'posts_preview_cards.preview_card_id = id', + 'fediverse_posts_preview_cards', + 'fediverse_posts_preview_cards.preview_card_id = id', 'inner', ) ->where('post_id', service('uuid') ->fromString($postId) ->getBytes()) diff --git a/modules/Install/Controllers/InstallController.php b/modules/Install/Controllers/InstallController.php index b417afd4..54462633 100644 --- a/modules/Install/Controllers/InstallController.php +++ b/modules/Install/Controllers/InstallController.php @@ -243,8 +243,6 @@ class InstallController extends Controller { $migrate = Services::migrations(); - $migrate->setNamespace('CodeIgniter\Settings') - ->latest(); $migrate->setNamespace(null) ->latest(); } diff --git a/modules/Media/Helpers/url_helper.php b/modules/Media/Helpers/url_helper.php index a3e3c9a3..1e96cc96 100644 --- a/modules/Media/Helpers/url_helper.php +++ b/modules/Media/Helpers/url_helper.php @@ -18,7 +18,7 @@ if (! function_exists('media_url')) { $relativePath = implode('/', $relativePath); } - $uri = new URI(rtrim((string) config(Media::class)->baseURL, '/') . '/' . ltrim($relativePath)); + $uri = new URI(rtrim(config(Media::class)->baseURL, '/') . '/' . ltrim($relativePath)); return URI::createURIString( $scheme ?? $uri->getScheme(), diff --git a/modules/PodcastImport/Commands/PodcastImport.php b/modules/PodcastImport/Commands/PodcastImport.php index e2ebba74..fc7ef61e 100644 --- a/modules/PodcastImport/Commands/PodcastImport.php +++ b/modules/PodcastImport/Commands/PodcastImport.php @@ -18,6 +18,7 @@ use CodeIgniter\CLI\BaseCommand; use CodeIgniter\CLI\CLI; use CodeIgniter\I18n\Time; use CodeIgniter\Shield\Entities\User; +use Config\Services; use Exception; use League\HTMLToMarkdown\HtmlConverter; use Modules\Auth\Models\UserModel; @@ -95,6 +96,9 @@ class PodcastImport extends BaseCommand public function run(array $params): void { + // FIXME: getting named routes doesn't work from v4.3 anymore, so loading all routes before importing + Services::routes()->loadRoutes(); + $this->init(); try { @@ -503,7 +507,7 @@ class PodcastImport extends BaseCommand ->get() ->getResultArray(); - return array_map(static function ($element) { + return array_map(static function (array $element) { return $element['guid']; }, $result); } diff --git a/modules/Update/Commands/DatabaseUpdate.php b/modules/Update/Commands/DatabaseUpdate.php index 54bf5db4..1b7b6b39 100644 --- a/modules/Update/Commands/DatabaseUpdate.php +++ b/modules/Update/Commands/DatabaseUpdate.php @@ -28,8 +28,6 @@ class DatabaseUpdate extends BaseCommand { $migrate = Services::migrations(); - $migrate->setNamespace('CodeIgniter\Settings') - ->latest(); $migrate->setNamespace(null) ->latest(); } diff --git a/modules/WebSub/Database/Migrations/2022-03-07-180000_add_is_published_on_hubs_to_podcasts.php b/modules/WebSub/Database/Migrations/2022-03-07-180000_add_is_published_on_hubs_to_podcasts.php index b58a75a0..a5297b65 100644 --- a/modules/WebSub/Database/Migrations/2022-03-07-180000_add_is_published_on_hubs_to_podcasts.php +++ b/modules/WebSub/Database/Migrations/2022-03-07-180000_add_is_published_on_hubs_to_podcasts.php @@ -16,14 +16,14 @@ class AddIsPublishedOnHubsToPodcasts extends BaseMigration { public function up(): void { - $prefix = $this->db->getPrefix(); - - $createQuery = <<db->query($createQuery); + $this->forge->addColumn('podcasts', [ + 'is_published_on_hubs' => [ + 'type' => 'BOOLEAN', + 'null' => false, + 'default' => 0, + 'after' => 'custom_rss', + ], + ]); } public function down(): void diff --git a/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php b/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php index 67a18ab4..05ee0d0b 100644 --- a/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php +++ b/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php @@ -16,14 +16,14 @@ class AddIsPublishedOnHubsToEpisodes extends BaseMigration { public function up(): void { - $prefix = $this->db->getPrefix(); - - $createQuery = <<db->query($createQuery); + $this->forge->addColumn('episodes', [ + 'is_published_on_hubs' => [ + 'type' => 'BOOLEAN', + 'null' => false, + 'default' => 0, + 'after' => 'custom_rss', + ], + ]); } public function down(): void diff --git a/rector.php b/rector.php index 875e5d1e..782fdda8 100644 --- a/rector.php +++ b/rector.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use Rector\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector; use Rector\CodingStyle\Rector\ClassMethod\UnSpreadOperatorRector; use Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector; use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; @@ -13,7 +12,6 @@ use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; use Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector; use Rector\EarlyReturn\Rector\If_\ChangeAndIfToEarlyReturnRector; use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector; -use Rector\EarlyReturn\Rector\If_\ChangeOrIfReturnToEarlyReturnRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; use Rector\Set\ValueObject\SetList; @@ -49,11 +47,9 @@ return static function (RectorConfig $rectorConfig): void { __DIR__ . '/modules/Admin/Language/*/PersonsTaxonomy.php', // skip rules from used sets - ChangeOrIfReturnToEarlyReturnRector::class, ChangeOrIfContinueToMultiContinueRector::class, EncapsedStringsToSprintfRector::class, UnSpreadOperatorRector::class, - ExplicitMethodCallOverMagicGetSetRector::class, RemoveExtraParametersRector::class, UnwrapFutureCompatibleIfPhpVersionRector::class, diff --git a/themes/cp_admin/_partials/_nav_header.php b/themes/cp_admin/_partials/_nav_header.php index 21b7c857..59c92b27 100644 --- a/themes/cp_admin/_partials/_nav_header.php +++ b/themes/cp_admin/_partials/_nav_header.php @@ -31,9 +31,9 @@ $userPodcasts = get_podcasts_user_can_interact_with(auth()->user()); ?> $items = [ [ 'type' => 'html', - 'content' => esc(<< esc(<<{$notificationsTitle} - CODE_SAMPLE), + HTML), ], ]; @@ -45,7 +45,7 @@ if ($userPodcasts !== []) { $items[] = [ 'type' => 'link', - 'title' => << <<
@@ -53,7 +53,7 @@ if ($userPodcasts !== []) {
{$userPodcastTitle} - CODE_SAMPLE + HTML , 'uri' => route_to('notification-list', $userPodcast->id), ]; @@ -62,9 +62,9 @@ if ($userPodcasts !== []) { $noNotificationsText = lang('Notifications.no_notifications'); $items[] = [ 'type' => 'html', - 'content' => esc(<< esc(<<{$noNotificationsText} - CODE_SAMPLE), + HTML), ]; } ?> @@ -90,11 +90,11 @@ foreach ($userPodcasts as $userPodcast) { $checkMark = interact_as_actor_id() === $userPodcast->actor_id ? icon('check', 'ml-2 bg-accent-base text-accent-contrast rounded-full') : ''; $userPodcastTitle = esc($userPodcast->title); - $interactButtons .= <<
{$userPodcastTitle}{$checkMark}
- CODE_SAMPLE; + HTML; } $interactAsText = lang('Common.choose_interact'); @@ -126,7 +126,7 @@ if ($userPodcasts !== []) { $menuItems = array_merge([ [ 'type' => 'html', - 'content' => esc(<< esc(<< {$interactAsText}
@@ -134,7 +134,7 @@ if ($userPodcasts !== []) { {$interactButtons}
- CODE_SAMPLE), + HTML), ], [ 'type' => 'separator', diff --git a/themes/cp_admin/episode/_card.php b/themes/cp_admin/episode/_card.php index b03be73e..dc32213e 100644 --- a/themes/cp_admin/episode/_card.php +++ b/themes/cp_admin/episode/_card.php @@ -66,9 +66,9 @@ if ($episode->published_at === null) { $title = lang('Episode.messages.unpublishBeforeDeleteTip'); $items[] = [ 'type' => 'html', - 'content' => esc(<< esc(<<{$icon}{$label} - CODE_SAMPLE), + HTML), ]; } ?> diff --git a/themes/cp_admin/episode/list.php b/themes/cp_admin/episode/list.php index 2e603a59..2461c18b 100644 --- a/themes/cp_admin/episode/list.php +++ b/themes/cp_admin/episode/list.php @@ -149,9 +149,9 @@ data_table( $title = lang('Episode.messages.unpublishBeforeDeleteTip'); $items[] = [ 'type' => 'html', - 'content' => esc(<< esc(<<{$icon}{$label} - CODE_SAMPLE), + HTML), ]; } return ' - CODE_SAMPLE; + HTML; } } @@ -127,7 +127,7 @@ if ($userPodcasts !== []) { $menuItems = array_merge([ [ 'type' => 'html', - 'content' => esc(<< esc(<< {$interactAsText}
@@ -135,7 +135,7 @@ if ($userPodcasts !== []) { {$interactButtons}
- CODE_SAMPLE), + HTML), ], [ 'type' => 'separator',