Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • adaures/castopod
  • mkljczk/castopod-host
  • spaetz/castopod-host
  • PatrykMis/castopod
  • jonas/castopod
  • ajeremias/castopod
  • misuzu/castopod
  • KrzysztofDomanczyk/castopod
  • Behel/castopod
  • nebulon/castopod
  • ewen/castopod
  • NeoluxConsulting/castopod
  • nateritter/castopod-og
  • prcutler/castopod
14 results
Show changes
Showing
with 950 additions and 378 deletions
<?php
declare(strict_types=1);
namespace Config;
/**
* Optimization Configuration.
*
* NOTE: This class does not extend BaseConfig for performance reasons.
* So you cannot replace the property values with Environment Variables.
*
* @immutable
*/
class Optimize
{
/**
* --------------------------------------------------------------------------
* Config Caching
* --------------------------------------------------------------------------
*
* @see https://codeigniter.com/user_guide/concepts/factories.html#config-caching
*/
public bool $configCacheEnabled = false;
/**
* --------------------------------------------------------------------------
* Config Caching
* --------------------------------------------------------------------------
*
* @see https://codeigniter.com/user_guide/concepts/autoloader.html#file-locator-caching
*/
public bool $locatorCacheEnabled = false;
}
...@@ -21,13 +21,11 @@ class Pager extends BaseConfig ...@@ -21,13 +21,11 @@ class Pager extends BaseConfig
* and the desired group as $pagerGroup; * and the desired group as $pagerGroup;
* *
* @var array<string, string> * @var array<string, string>
*
* @noRector Rector\Php55\Rector\String_\StringClassNameToClassConstantRector
*/ */
public $templates = [ public array $templates = [
'default_full' => 'App\Views\pager\default_full', 'default_full' => 'App\Views\pager\default_full',
'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
'default_head' => 'CodeIgniter\Pager\Views\default_head', 'default_head' => 'CodeIgniter\Pager\Views\default_head',
]; ];
/** /**
......
...@@ -5,8 +5,6 @@ declare(strict_types=1); ...@@ -5,8 +5,6 @@ declare(strict_types=1);
namespace Config; namespace Config;
/** /**
* Paths
*
* Holds the paths that are used by the system to locate the main directories, app, system, etc. * Holds the paths that are used by the system to locate the main directories, app, system, etc.
* *
* Modifying these allows you to restructure your application, share a system folder between multiple applications, and * Modifying these allows you to restructure your application, share a system folder between multiple applications, and
...@@ -35,8 +33,8 @@ class Paths ...@@ -35,8 +33,8 @@ class Paths
* *
* If you want this front controller to use a different "app" * If you want this front controller to use a different "app"
* folder than the default one you can set its name here. The folder * folder than the default one you can set its name here. The folder
* can also be renamed or relocated anywhere on your getServer. If * can also be renamed or relocated anywhere on your server. If
* you do, use a full getServer path. * you do, use a full server path.
* *
* @see http://codeigniter.com/user_guide/general/managing_apps.html * @see http://codeigniter.com/user_guide/general/managing_apps.html
*/ */
...@@ -72,7 +70,7 @@ class Paths ...@@ -72,7 +70,7 @@ class Paths
* This variable must contain the name of the directory that * This variable must contain the name of the directory that
* contains the view files used by your application. By * contains the view files used by your application. By
* default this is in `app/Views`. This value * default this is in `app/Views`. This value
* is used when no value is provided to `Services::renderer()`. * is used when no value is provided to `service('renderer')`.
*/ */
public string $viewDirectory = __DIR__ . '/../Views'; public string $viewDirectory = __DIR__ . '/../Views';
} }
...@@ -19,10 +19,10 @@ class Publisher extends BasePublisher ...@@ -19,10 +19,10 @@ class Publisher extends BasePublisher
* to directories not in this list will result in a PublisherException. Files that do no fit the pattern will cause * to directories not in this list will result in a PublisherException. Files that do no fit the pattern will cause
* copy/merge to fail. * copy/merge to fail.
* *
* @var array<string,string> * @var array<string, string>
*/ */
public $restrictions = [ public $restrictions = [
ROOTPATH => '*', ROOTPATH => '*',
FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
]; ];
} }
...@@ -2,35 +2,11 @@ ...@@ -2,35 +2,11 @@
declare(strict_types=1); declare(strict_types=1);
namespace Config; use CodeIgniter\Router\RouteCollection;
// Create a new instance of our RouteCollection class.
$routes = Services::routes();
// Load the system's routing file first, so that the app and ENVIRONMENT
// can override as needed.
if (is_file(SYSTEMPATH . 'Config/Routes.php')) {
require SYSTEMPATH . 'Config/Routes.php';
}
/**
* --------------------------------------------------------------------
* Router Setup
* --------------------------------------------------------------------
*/
$routes->setDefaultNamespace('App\Controllers');
$routes->setDefaultController('Home');
$routes->setDefaultMethod('index');
$routes->setTranslateURIDashes(false);
$routes->set404Override();
// The Auto Routing (Legacy) is very dangerous. It is easy to create vulnerable apps
// where controller filters or CSRF protection are bypassed.
// If you don't want to define all routes, please use the Auto Routing (Improved).
// Set `$autoRoutesImproved` to true in `app/Config/Feature.php` and set the following to true.
$routes->setAutoRoute(false);
/** /**
* @var RouteCollection $routes
*
* -------------------------------------------------------------------- * --------------------------------------------------------------------
* Placeholder definitions * Placeholder definitions
* -------------------------------------------------------------------- * --------------------------------------------------------------------
...@@ -39,7 +15,6 @@ $routes->setAutoRoute(false); ...@@ -39,7 +15,6 @@ $routes->setAutoRoute(false);
$routes->addPlaceholder('podcastHandle', '[a-zA-Z0-9\_]{1,32}'); $routes->addPlaceholder('podcastHandle', '[a-zA-Z0-9\_]{1,32}');
$routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,128}'); $routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,128}');
$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('postAction', '\bfavourite|\breblog|\breply'); $routes->addPlaceholder('postAction', '\bfavourite|\breblog|\breply');
$routes->addPlaceholder('embedTheme', '\blight|\bdark|\blight-transparent|\bdark-transparent'); $routes->addPlaceholder('embedTheme', '\blight|\bdark|\blight-transparent|\bdark-transparent');
$routes->addPlaceholder( $routes->addPlaceholder(
...@@ -60,6 +35,11 @@ $routes->get('themes/colors', 'ColorsController', [ ...@@ -60,6 +35,11 @@ $routes->get('themes/colors', 'ColorsController', [
'as' => 'themes-colors-css', 'as' => 'themes-colors-css',
]); ]);
// health check
$routes->get('/health', 'HomeController::health', [
'as' => 'health',
]);
// We get a performance increase by specifying the default // We get a performance increase by specifying the default
// route since we don't have to scan directories. // route since we don't have to scan directories.
$routes->get('/', 'HomeController', [ $routes->get('/', 'HomeController', [
...@@ -68,66 +48,74 @@ $routes->get('/', 'HomeController', [ ...@@ -68,66 +48,74 @@ $routes->get('/', 'HomeController', [
$routes->get('.well-known/platforms', 'Platform'); $routes->get('.well-known/platforms', 'Platform');
// Podcast's Public routes service('auth')
$routes->group('@(:podcastHandle)', function ($routes): void { ->routes($routes);
$routes->get('/', 'PodcastController::activity/$1', [
'as' => 'podcast-activity',
]);
$routes->get('manifest.webmanifest', 'WebmanifestController::podcastManifest/$1', [
'as' => 'podcast-webmanifest',
]);
// Podcast's Public routes
$routes->group('@(:podcastHandle)', static function ($routes): void {
// override default Fediverse Library's actor route // override default Fediverse Library's actor route
$routes->options('/', 'ActivityPubController::preflight'); $routes->options('/', 'ActivityPubController::preflight');
$routes->get('/', 'PodcastController::activity/$1', [ $routes->get('/', 'PodcastController::activity/$1', [
'as' => 'actor', 'as' => 'podcast-activity',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'Modules\Fediverse\Controllers', 'namespace' => 'Modules\Fediverse\Controllers',
'controller-method' => 'ActorController/$1', 'controller-method' => 'ActorController::index/$1',
], ],
'application/podcast-activity+json' => [ 'application/podcast-activity+json' => [
'namespace' => 'App\Controllers', 'namespace' => 'App\Controllers',
'controller-method' => 'PodcastController::podcastActor/$1', 'controller-method' => 'PodcastController::podcastActor/$1',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'Modules\Fediverse\Controllers', 'namespace' => 'Modules\Fediverse\Controllers',
'controller-method' => 'ActorController/$1', 'controller-method' => 'ActorController::index/$1',
], ],
], ],
'filter' => 'allow-cors', 'filter' => 'allow-cors',
]); ]);
$routes->get('manifest.webmanifest', 'WebmanifestController::podcastManifest/$1', [
'as' => 'podcast-webmanifest',
]);
$routes->get('links', 'PodcastController::links/$1', [
'as' => 'podcast-links',
]);
$routes->get('about', 'PodcastController::about/$1', [ $routes->get('about', 'PodcastController::about/$1', [
'as' => 'podcast-about', 'as' => 'podcast-about',
]); ]);
$routes->options('episodes', 'ActivityPubController::preflight'); $routes->options('episodes', 'ActivityPubController::preflight');
$routes->get('episodes', 'PodcastController::episodes/$1', [ $routes->get('episodes', 'PodcastController::episodes/$1', [
'as' => 'podcast-episodes', 'as' => 'podcast-episodes',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'App\Controllers',
'controller-method' => 'PodcastController::episodeCollection/$1', 'controller-method' => 'PodcastController::episodeCollection/$1',
], ],
'application/podcast-activity+json' => [ 'application/podcast-activity+json' => [
'namespace' => 'App\Controllers',
'controller-method' => 'PodcastController::episodeCollection/$1', 'controller-method' => 'PodcastController::episodeCollection/$1',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'App\Controllers',
'controller-method' => 'PodcastController::episodeCollection/$1', 'controller-method' => 'PodcastController::episodeCollection/$1',
], ],
], ],
'filter' => 'allow-cors', 'filter' => 'allow-cors',
]); ]);
$routes->group('episodes/(:slug)', function ($routes): void { $routes->group('episodes/(:slug)', static function ($routes): void {
$routes->options('/', 'ActivityPubController::preflight'); $routes->options('/', 'ActivityPubController::preflight');
$routes->get('/', 'EpisodeController/$1/$2', [ $routes->get('/', 'EpisodeController::index/$1/$2', [
'as' => 'episode', 'as' => 'episode',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'App\Controllers',
'controller-method' => 'EpisodeController::episodeObject/$1/$2', 'controller-method' => 'EpisodeController::episodeObject/$1/$2',
], ],
'application/podcast-activity+json' => [ 'application/podcast-activity+json' => [
'namespace' => 'App\Controllers',
'controller-method' => 'EpisodeController::episodeObject/$1/$2', 'controller-method' => 'EpisodeController::episodeObject/$1/$2',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'App\Controllers',
'controller-method' => 'EpisodeController::episodeObject/$1/$2', 'controller-method' => 'EpisodeController::episodeObject/$1/$2',
], ],
], ],
...@@ -136,9 +124,15 @@ $routes->group('@(:podcastHandle)', function ($routes): void { ...@@ -136,9 +124,15 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
$routes->get('activity', 'EpisodeController::activity/$1/$2', [ $routes->get('activity', 'EpisodeController::activity/$1/$2', [
'as' => 'episode-activity', 'as' => 'episode-activity',
]); ]);
$routes->get('chapters', 'EpisodeController::chapters/$1/$2', [
'as' => 'episode-chapters',
]);
$routes->get('transcript', 'EpisodeController::transcript/$1/$2', [
'as' => 'episode-transcript',
]);
$routes->options('comments', 'ActivityPubController::preflight'); $routes->options('comments', 'ActivityPubController::preflight');
$routes->get('comments', 'EpisodeController::comments/$1/$2', [ $routes->get('comments', 'EpisodeController::comments/$1/$2', [
'as' => 'episode-comments', 'as' => 'episode-comments',
'application/activity+json' => [ 'application/activity+json' => [
'controller-method' => 'EpisodeController::comments/$1/$2', 'controller-method' => 'EpisodeController::comments/$1/$2',
], ],
...@@ -152,7 +146,7 @@ $routes->group('@(:podcastHandle)', function ($routes): void { ...@@ -152,7 +146,7 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
]); ]);
$routes->options('comments/(:uuid)', 'ActivityPubController::preflight'); $routes->options('comments/(:uuid)', 'ActivityPubController::preflight');
$routes->get('comments/(:uuid)', 'EpisodeCommentController::view/$1/$2/$3', [ $routes->get('comments/(:uuid)', 'EpisodeCommentController::view/$1/$2/$3', [
'as' => 'episode-comment', 'as' => 'episode-comment',
'application/activity+json' => [ 'application/activity+json' => [
'controller-method' => 'EpisodeController::commentObject/$1/$2', 'controller-method' => 'EpisodeController::commentObject/$1/$2',
], ],
...@@ -167,7 +161,7 @@ $routes->group('@(:podcastHandle)', function ($routes): void { ...@@ -167,7 +161,7 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
$routes->get('comments/(:uuid)/replies', 'EpisodeCommentController::replies/$1/$2/$3', [ $routes->get('comments/(:uuid)/replies', 'EpisodeCommentController::replies/$1/$2/$3', [
'as' => 'episode-comment-replies', 'as' => 'episode-comment-replies',
]); ]);
$routes->post('comments/(:uuid)/like', 'EpisodeCommentController::attemptLike/$1/$2/$3', [ $routes->post('comments/(:uuid)/like', 'EpisodeCommentController::likeAction/$1/$2/$3', [
'as' => 'episode-comment-attempt-like', 'as' => 'episode-comment-attempt-like',
]); ]);
$routes->get('oembed.json', 'EpisodeController::oembedJSON/$1/$2', [ $routes->get('oembed.json', 'EpisodeController::oembedJSON/$1/$2', [
...@@ -176,7 +170,7 @@ $routes->group('@(:podcastHandle)', function ($routes): void { ...@@ -176,7 +170,7 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
$routes->get('oembed.xml', 'EpisodeController::oembedXML/$1/$2', [ $routes->get('oembed.xml', 'EpisodeController::oembedXML/$1/$2', [
'as' => 'episode-oembed-xml', 'as' => 'episode-oembed-xml',
]); ]);
$routes->group('embed', function ($routes): void { $routes->group('embed', static function ($routes): void {
$routes->get('/', 'EpisodeController::embed/$1/$2', [ $routes->get('/', 'EpisodeController::embed/$1/$2', [
'as' => 'embed', 'as' => 'embed',
]); ]);
...@@ -185,15 +179,38 @@ $routes->group('@(:podcastHandle)', function ($routes): void { ...@@ -185,15 +179,38 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
],); ],);
}); });
}); });
$routes->head('feed.xml', 'FeedController::index/$1', [
$routes->head('feed.xml', 'FeedController/$1', [ 'as' => 'podcast-rss-feed',
'as' => 'podcast_feed',
]); ]);
$routes->get('feed.xml', 'FeedController/$1', [ $routes->get('feed.xml', 'FeedController::index/$1', [
'as' => 'podcast_feed', 'as' => 'podcast-rss-feed',
]); ]);
$routes->head('feed', 'FeedController::index/$1');
$routes->get('feed', 'FeedController::index/$1');
}); });
// audio routes
$routes->head('/audio/@(:podcastHandle)/(:slug).(:alphanum)', 'EpisodeAudioController::index/$1/$2', [
'as' => 'episode-audio',
], );
$routes->get('/audio/@(:podcastHandle)/(:slug).(:alphanum)', 'EpisodeAudioController::index/$1/$2', [
'as' => 'episode-audio',
], );
// episode preview link
$routes->get('/p/(:uuid)', 'EpisodePreviewController::index/$1', [
'as' => 'episode-preview',
]);
$routes->get('/p/(:uuid)/activity', 'EpisodePreviewController::activity/$1', [
'as' => 'episode-preview-activity',
]);
$routes->get('/p/(:uuid)/chapters', 'EpisodePreviewController::chapters/$1', [
'as' => 'episode-preview-chapters',
]);
$routes->get('/p/(:uuid)/transcript', 'EpisodePreviewController::transcript/$1', [
'as' => 'episode-preview-transcript',
]);
// Other pages // Other pages
$routes->get('/credits', 'CreditsController', [ $routes->get('/credits', 'CreditsController', [
'as' => 'credits', 'as' => 'credits',
...@@ -204,110 +221,88 @@ $routes->get('/map', 'MapController', [ ...@@ -204,110 +221,88 @@ $routes->get('/map', 'MapController', [
$routes->get('/episodes-markers', 'MapController::getEpisodesMarkers', [ $routes->get('/episodes-markers', 'MapController::getEpisodesMarkers', [
'as' => 'episodes-markers', 'as' => 'episodes-markers',
]); ]);
$routes->get('/pages/(:slug)', 'PageController/$1', [ $routes->get('/pages/(:slug)', 'PageController::index/$1', [
'as' => 'page', 'as' => 'page',
]); ]);
/** /**
* Overwriting Fediverse routes file * Overwriting Fediverse routes file
*/ */
$routes->group('@(:podcastHandle)', function ($routes): void { $routes->group('@(:podcastHandle)', static function ($routes): void {
$routes->post('posts/new', 'PostController::attemptCreate/$1', [ $routes->post('posts/new', 'PostController::createAction/$1', [
'as' => 'post-attempt-create', 'as' => 'post-attempt-create',
'filter' => 'permission:podcast-manage_publications', 'filter' => 'permission:podcast$1.manage-publications',
]); ]);
// Post // Post
$routes->group('posts/(:uuid)', function ($routes): void { $routes->group('posts/(:uuid)', static function ($routes): void {
$routes->options('/', 'ActivityPubController::preflight'); $routes->options('/', 'ActivityPubController::preflight');
$routes->get('/', 'PostController::view/$1/$2', [ $routes->get('/', 'PostController::view/$1/$2', [
'as' => 'post', 'as' => 'post',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'Modules\Fediverse\Controllers', 'namespace' => 'Modules\Fediverse\Controllers',
'controller-method' => 'PostController/$2', 'controller-method' => 'PostController::index/$2',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'Modules\Fediverse\Controllers', 'namespace' => 'Modules\Fediverse\Controllers',
'controller-method' => 'PostController/$2', 'controller-method' => 'PostController::index/$2',
], ],
], ],
'filter' => 'allow-cors', 'filter' => 'allow-cors',
]); ]);
$routes->options('replies', 'ActivityPubController::preflight'); $routes->options('replies', 'ActivityPubController::preflight');
$routes->get('replies', 'PostController/$1/$2', [ $routes->get('replies', 'PostController::index/$1/$2', [
'as' => 'post-replies', 'as' => 'post-replies',
'alternate-content' => [ 'alternate-content' => [
'application/activity+json' => [ 'application/activity+json' => [
'namespace' => 'Modules\Fediverse\Controllers', 'namespace' => 'Modules\Fediverse\Controllers',
'controller-method' => 'PostController::replies/$2', 'controller-method' => 'PostController::replies/$2',
], ],
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
'namespace' => 'Modules\Fediverse\Controllers', 'namespace' => 'Modules\Fediverse\Controllers',
'controller-method' => 'PostController::replies/$2', 'controller-method' => 'PostController::replies/$2',
], ],
], ],
'filter' => 'allow-cors', 'filter' => 'allow-cors',
]); ]);
// Actions // Actions
$routes->post('action', 'PostController::attemptAction/$1/$2', [ $routes->post('action', 'PostController::action/$1/$2', [
'as' => 'post-attempt-action', 'as' => 'post-attempt-action',
'filter' => 'permission:podcast-interact_as', 'filter' => 'permission:podcast$1.interact-as',
]); ]);
$routes->post( $routes->post(
'block-actor', 'block-actor',
'PostController::attemptBlockActor/$1/$2', 'PostController::blockActorAction/$1/$2',
[ [
'as' => 'post-attempt-block-actor', 'as' => 'post-attempt-block-actor',
'filter' => 'permission:fediverse-block_actors', 'filter' => 'permission:fediverse.manage-blocks',
], ],
); );
$routes->post( $routes->post(
'block-domain', 'block-domain',
'PostController::attemptBlockDomain/$1/$2', 'PostController::blockDomainAction/$1/$2',
[ [
'as' => 'post-attempt-block-domain', 'as' => 'post-attempt-block-domain',
'filter' => 'permission:fediverse-block_domains', 'filter' => 'permission:fediverse.manage-blocks',
], ],
); );
$routes->post('delete', 'PostController::attemptDelete/$1/$2', [ $routes->post('delete', 'PostController::deleteAction/$1/$2', [
'as' => 'post-attempt-delete', 'as' => 'post-attempt-delete',
'filter' => 'permission:podcast-manage_publications', 'filter' => 'permission:podcast$1.manage-publications',
]); ]);
$routes->get( $routes->get(
'remote/(:postAction)', 'remote/(:postAction)',
'PostController::remoteAction/$1/$2/$3', 'PostController::remoteActionAction/$1/$2/$3',
[ [
'as' => 'post-remote-action', 'as' => 'post-remote-action',
], ],
); );
}); });
$routes->get('follow', 'ActorController::followView/$1', [
$routes->get('follow', 'ActorController::follow/$1', [
'as' => 'follow', 'as' => 'follow',
]); ]);
$routes->get('outbox', 'ActorController::outbox/$1', [ $routes->get('outbox', 'ActorController::outbox/$1', [
'as' => 'outbox', 'as' => 'outbox',
'filter' => 'fediverse:verify-activitystream', 'filter' => 'fediverse:verify-activitystream',
]); ]);
}); });
/*
* --------------------------------------------------------------------
* Additional Routing
* --------------------------------------------------------------------
*
* There will often be times that you need additional routing and you
* need it to be able to override any defaults in this file. Environment
* based routes is one such time. require() additional route files here
* to make that happen.
*
* You will have access to the $routes object within that file without
* needing to reload it.
*/
if (is_file(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) {
require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
}
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Config\Routing as BaseRouting;
/**
* Routing configuration
*/
class Routing extends BaseRouting
{
/**
* For Defined Routes.
* An array of files that contain route definitions.
* Route files are read in order, with the first match
* found taking precedence.
*
* Default: APPPATH . 'Config/Routes.php'
*
* @var list<string>
*/
public array $routeFiles = [
APPPATH . 'Config/Routes.php',
ROOTPATH . 'modules/Admin/Config/Routes.php',
ROOTPATH . 'modules/Analytics/Config/Routes.php',
ROOTPATH . 'modules/Api/Rest/V1/Config/Routes.php',
ROOTPATH . 'modules/Auth/Config/Routes.php',
ROOTPATH . 'modules/Fediverse/Config/Routes.php',
ROOTPATH . 'modules/Install/Config/Routes.php',
ROOTPATH . 'modules/Platforms/Config/Routes.php',
ROOTPATH . 'modules/PodcastImport/Config/Routes.php',
ROOTPATH . 'modules/PremiumPodcasts/Config/Routes.php',
];
/**
* For Defined Routes and Auto Routing.
* The default namespace to use for Controllers when no other
* namespace has been specified.
*
* Default: 'App\Controllers'
*/
public string $defaultNamespace = 'App\Controllers';
/**
* For Auto Routing.
* The default controller to use when no other controller has been
* specified.
*
* Default: 'Home'
*/
public string $defaultController = 'HomeController';
/**
* For Defined Routes and Auto Routing.
* The default method to call on the controller when no other
* method has been set in the route.
*
* Default: 'index'
*/
public string $defaultMethod = 'index';
/**
* For Auto Routing.
* Whether to translate dashes in URIs for controller/method to underscores.
* Primarily useful when using the auto-routing.
*
* Default: false
*/
public bool $translateURIDashes = false;
/**
* Sets the class/method that should be called if routing doesn't
* find a match. It can be the controller/method name like: Users::index
*
* This setting is passed to the Router class and handled there.
*
* If you want to use a closure, you will have to set it in the
* routes file by calling:
*
* $routes->set404Override(function() {
* // Do something here
* });
*
* Example:
* public $override404 = 'App\Errors::show404';
*/
public ?string $override404 = null;
/**
* If TRUE, the system will attempt to match the URI against
* Controllers by matching each segment against folders/files
* in APPPATH/Controllers, when a match wasn't found against
* defined routes.
*
* If FALSE, will stop searching and do NO automatic routing.
*/
public bool $autoRoute = false;
/**
* For Defined Routes.
* If TRUE, will enable the use of the 'prioritize' option
* when defining routes.
*
* Default: false
*/
public bool $prioritize = false;
/**
* For Defined Routes.
* If TRUE, matched multiple URI segments will be passed as one parameter.
*
* Default: false
*/
public bool $multipleSegmentsOneParam = false;
/**
* For Auto Routing (Improved).
* Map of URI segments and namespaces.
*
* The key is the first URI segment. The value is the controller namespace.
* E.g.,
* [
* 'blog' => 'Acme\Blog\Controllers',
* ]
*
* @var array<string, string> [ uri_segment => namespace ]
*/
public array $moduleRoutes = [];
/**
* For Auto Routing (Improved).
* Whether to translate dashes in URIs for controller/method to CamelCase.
* E.g., blog-controller -> BlogController
*
* If you enable this, $translateURIDashes is ignored.
*
* Default: false
*/
public bool $translateUriToCamelCase = true;
}
...@@ -17,7 +17,7 @@ class Security extends BaseConfig ...@@ -17,7 +17,7 @@ class Security extends BaseConfig
* *
* @var 'cookie'|'session' * @var 'cookie'|'session'
*/ */
public string $csrfProtection = 'cookie'; public string $csrfProtection = 'session';
/** /**
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
...@@ -80,26 +80,7 @@ class Security extends BaseConfig ...@@ -80,26 +80,7 @@ class Security extends BaseConfig
* CSRF Redirect * CSRF Redirect
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
* *
* Redirect to previous page with error on failure. * @see https://codeigniter4.github.io/userguide/libraries/security.html#redirection-on-failure
*/ */
public bool $redirect = true; public bool $redirect = (ENVIRONMENT === 'production');
/**
* --------------------------------------------------------------------------
* CSRF SameSite
* --------------------------------------------------------------------------
*
* Setting for CSRF SameSite cookie token.
*
* Allowed values are: None - Lax - Strict - ''.
*
* Defaults to `Lax` as recommended in this link:
*
* @see https://portswigger.net/web-security/csrf/samesite-cookies
*
* @var string
*
* @deprecated `Config\Cookie` $samesite property is used.
*/
public $samesite = 'Lax';
} }
...@@ -5,15 +5,13 @@ declare(strict_types=1); ...@@ -5,15 +5,13 @@ declare(strict_types=1);
namespace Config; namespace Config;
use App\Libraries\Breadcrumb; use App\Libraries\Breadcrumb;
use App\Libraries\HtmlHead;
use App\Libraries\Negotiate; use App\Libraries\Negotiate;
use App\Libraries\Router; use App\Libraries\Router;
use App\Libraries\View;
use CodeIgniter\Config\BaseService; use CodeIgniter\Config\BaseService;
use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\Request;
use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\Router\RouteCollectionInterface; use CodeIgniter\Router\RouteCollectionInterface;
use Config\Services as AppServices;
use Config\View as ViewConfig;
/** /**
* Services Configuration file. * Services Configuration file.
...@@ -30,47 +28,25 @@ class Services extends BaseService ...@@ -30,47 +28,25 @@ class Services extends BaseService
/** /**
* The Router class uses a RouteCollection's array of routes, and determines the correct Controller and Method to * The Router class uses a RouteCollection's array of routes, and determines the correct Controller and Method to
* execute. * execute.
*
* @noRector PHPStan\Reflection\MissingMethodFromReflectionException
*/ */
public static function router( public static function router(
?RouteCollectionInterface $routes = null, ?RouteCollectionInterface $routes = null,
?Request $request = null, ?Request $request = null,
bool $getShared = true bool $getShared = true,
): Router { ): Router {
if ($getShared) { if ($getShared) {
return static::getSharedInstance('router', $routes, $request); return static::getSharedInstance('router', $routes, $request);
} }
$routes = $routes ?? static::routes(); $routes ??= static::routes();
$request = $request ?? static::request(); $request ??= static::request();
return new Router($routes, $request); return new Router($routes, $request);
} }
/**
* The Renderer class is the class that actually displays a file to the user. The default View class within
* CodeIgniter is intentionally simple, but this service could easily be replaced by a template engine if the user
* needed to.
*/
public static function renderer(?string $viewPath = null, ?ViewConfig $config = null, bool $getShared = true): View
{
if ($getShared) {
return static::getSharedInstance('renderer', $viewPath, $config);
}
$viewPath = $viewPath ?: config('Paths')
->viewDirectory;
$config = $config ?? config('View');
return new View($config, $viewPath, AppServices::locator(), CI_DEBUG, AppServices::logger());
}
/** /**
* The Negotiate class provides the content negotiation features for working the request to determine correct * The Negotiate class provides the content negotiation features for working the request to determine correct
* language, encoding, charset, and more. * language, encoding, charset, and more.
*
* @noRector PHPStan\Reflection\MissingMethodFromReflectionException
*/ */
public static function negotiator(?RequestInterface $request = null, bool $getShared = true): Negotiate public static function negotiator(?RequestInterface $request = null, bool $getShared = true): Negotiate
{ {
...@@ -78,7 +54,7 @@ class Services extends BaseService ...@@ -78,7 +54,7 @@ class Services extends BaseService
return static::getSharedInstance('negotiator', $request); return static::getSharedInstance('negotiator', $request);
} }
$request = $request ?? static::request(); $request ??= static::request();
return new Negotiate($request); return new Negotiate($request);
} }
...@@ -91,4 +67,13 @@ class Services extends BaseService ...@@ -91,4 +67,13 @@ class Services extends BaseService
return new Breadcrumb(); return new Breadcrumb();
} }
public static function html_head(bool $getShared = true): HtmlHead
{
if ($getShared) {
return self::getSharedInstance('html_head');
}
return new HtmlHead();
}
} }
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Session\Handlers\BaseHandler;
use CodeIgniter\Session\Handlers\FileHandler;
class Session extends BaseConfig
{
/**
* --------------------------------------------------------------------------
* Session Driver
* --------------------------------------------------------------------------
*
* The session storage driver to use:
* - `CodeIgniter\Session\Handlers\FileHandler`
* - `CodeIgniter\Session\Handlers\DatabaseHandler`
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
* - `CodeIgniter\Session\Handlers\RedisHandler`
*
* @var class-string<BaseHandler>
*/
public string $driver = FileHandler::class;
/**
* --------------------------------------------------------------------------
* Session Cookie Name
* --------------------------------------------------------------------------
*
* The session cookie name, must contain only [0-9a-z_-] characters
*/
public string $cookieName = 'ci_session';
/**
* --------------------------------------------------------------------------
* Session Expiration
* --------------------------------------------------------------------------
*
* The number of SECONDS you want the session to last.
* Setting to 0 (zero) means expire when the browser is closed.
*/
public int $expiration = 7200;
/**
* --------------------------------------------------------------------------
* Session Save Path
* --------------------------------------------------------------------------
*
* The location to save sessions to and is driver dependent.
*
* For the 'files' driver, it's a path to a writable directory.
* WARNING: Only absolute paths are supported!
*
* For the 'database' driver, it's a table name.
* Please read up the manual for the format with other session drivers.
*
* IMPORTANT: You are REQUIRED to set a valid save path!
*/
public string $savePath = WRITEPATH . 'session';
/**
* --------------------------------------------------------------------------
* Session Match IP
* --------------------------------------------------------------------------
*
* Whether to match the user's IP address when reading the session data.
*
* WARNING: If you're using the database driver, don't forget to update
* your session table's PRIMARY KEY when changing this setting.
*/
public bool $matchIP = false;
/**
* --------------------------------------------------------------------------
* Session Time to Update
* --------------------------------------------------------------------------
*
* How many seconds between CI regenerating the session ID.
*/
public int $timeToUpdate = 300;
/**
* --------------------------------------------------------------------------
* Session Regenerate Destroy
* --------------------------------------------------------------------------
*
* Whether to destroy session data associated with the old session ID
* when auto-regenerating the session ID. When set to FALSE, the data
* will be later deleted by the garbage collector.
*/
public bool $regenerateDestroy = false;
/**
* --------------------------------------------------------------------------
* Session Database Group
* --------------------------------------------------------------------------
*
* DB Group for the database session.
*/
public ?string $DBGroup = null;
/**
* --------------------------------------------------------------------------
* Lock Retry Interval (microseconds)
* --------------------------------------------------------------------------
*
* This is used for RedisHandler.
*
* Time (microseconds) to wait if lock cannot be acquired.
* The default is 100,000 microseconds (= 0.1 seconds).
*/
public int $lockRetryInterval = 100_000;
/**
* --------------------------------------------------------------------------
* Lock Max Retries
* --------------------------------------------------------------------------
*
* This is used for RedisHandler.
*
* Maximum number of lock acquisition attempts.
* The default is 300 times. That is lock timeout is about 30 (0.1 * 300)
* seconds.
*/
public int $lockMaxRetries = 300;
}
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Tasks\Scheduler;
class Tasks extends BaseConfig
{
/**
* --------------------------------------------------------------------------
* Should performance metrics be logged
* --------------------------------------------------------------------------
*
* If true, will log the time it takes for each task to run.
* Requires the settings table to have been created previously.
*/
public bool $logPerformance = false;
/**
* --------------------------------------------------------------------------
* Maximum performance logs
* --------------------------------------------------------------------------
*
* The maximum number of logs that should be saved per Task.
* Lower numbers reduced the amount of database required to
* store the logs.
*/
public int $maxLogsPerTask = 10;
/**
* Register any tasks within this method for the application.
* Called by the TaskRunner.
*/
public function init(Scheduler $schedule): void
{
$schedule->command('fediverse:broadcast')
->everyMinute()
->named('fediverse-broadcast');
$schedule->command('websub:publish')
->everyMinute()
->named('websub-publish');
$schedule->command('video-clips:generate')
->everyMinute()
->named('video-clips-generate');
$schedule->command('podcast:import')
->everyMinute()
->named('podcast-import');
$schedule->command('episodes:compute-downloads')
->everyHour()
->named('episodes:compute-downloads');
}
}
...@@ -33,7 +33,7 @@ class Toolbar extends BaseConfig ...@@ -33,7 +33,7 @@ class Toolbar extends BaseConfig
* List of toolbar collectors that will be called when Debug Toolbar * List of toolbar collectors that will be called when Debug Toolbar
* fires up and collects data from. * fires up and collects data from.
* *
* @var string[] * @var list<class-string>
*/ */
public array $collectors = [ public array $collectors = [
Timers::class, Timers::class,
...@@ -51,7 +51,7 @@ class Toolbar extends BaseConfig ...@@ -51,7 +51,7 @@ class Toolbar extends BaseConfig
* Collect Var Data * Collect Var Data
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
* *
* If set to false var data from the views will not be colleted. Useful to * If set to false var data from the views will not be collected. Useful to
* avoid high memory usage when there are lots of data passed to the view. * avoid high memory usage when there are lots of data passed to the view.
*/ */
public bool $collectVarData = true; public bool $collectVarData = true;
...@@ -90,4 +90,31 @@ class Toolbar extends BaseConfig ...@@ -90,4 +90,31 @@ class Toolbar extends BaseConfig
* `$maxQueries` defines the maximum amount of queries that will be stored. * `$maxQueries` defines the maximum amount of queries that will be stored.
*/ */
public int $maxQueries = 100; public int $maxQueries = 100;
/**
* --------------------------------------------------------------------------
* Watched Directories
* --------------------------------------------------------------------------
*
* Contains an array of directories that will be watched for changes and
* used to determine if the hot-reload feature should reload the page or not.
* We restrict the values to keep performance as high as possible.
*
* NOTE: The ROOTPATH will be prepended to all values.
*
* @var list<string>
*/
public array $watchedDirectories = ['app', 'modules', 'themes'];
/**
* --------------------------------------------------------------------------
* Watched File Extensions
* --------------------------------------------------------------------------
*
* Contains an array of file extensions that will be watched for changes and
* used to determine if the hot-reload feature should reload the page or not.
*
* @var list<string>
*/
public array $watchedExtensions = ['php', 'css', 'js', 'html', 'svg', 'json', 'env'];
} }
...@@ -27,47 +27,47 @@ class UserAgents extends BaseConfig ...@@ -27,47 +27,47 @@ class UserAgents extends BaseConfig
*/ */
public array $platforms = [ public array $platforms = [
'windows nt 10.0' => 'Windows 10', 'windows nt 10.0' => 'Windows 10',
'windows nt 6.3' => 'Windows 8.1', 'windows nt 6.3' => 'Windows 8.1',
'windows nt 6.2' => 'Windows 8', 'windows nt 6.2' => 'Windows 8',
'windows nt 6.1' => 'Windows 7', 'windows nt 6.1' => 'Windows 7',
'windows nt 6.0' => 'Windows Vista', 'windows nt 6.0' => 'Windows Vista',
'windows nt 5.2' => 'Windows 2003', 'windows nt 5.2' => 'Windows 2003',
'windows nt 5.1' => 'Windows XP', 'windows nt 5.1' => 'Windows XP',
'windows nt 5.0' => 'Windows 2000', 'windows nt 5.0' => 'Windows 2000',
'windows nt 4.0' => 'Windows NT 4.0', 'windows nt 4.0' => 'Windows NT 4.0',
'winnt4.0' => 'Windows NT 4.0', 'winnt4.0' => 'Windows NT 4.0',
'winnt 4.0' => 'Windows NT', 'winnt 4.0' => 'Windows NT',
'winnt' => 'Windows NT', 'winnt' => 'Windows NT',
'windows 98' => 'Windows 98', 'windows 98' => 'Windows 98',
'win98' => 'Windows 98', 'win98' => 'Windows 98',
'windows 95' => 'Windows 95', 'windows 95' => 'Windows 95',
'win95' => 'Windows 95', 'win95' => 'Windows 95',
'windows phone' => 'Windows Phone', 'windows phone' => 'Windows Phone',
'windows' => 'Unknown Windows OS', 'windows' => 'Unknown Windows OS',
'android' => 'Android', 'android' => 'Android',
'blackberry' => 'BlackBerry', 'blackberry' => 'BlackBerry',
'iphone' => 'iOS', 'iphone' => 'iOS',
'ipad' => 'iOS', 'ipad' => 'iOS',
'ipod' => 'iOS', 'ipod' => 'iOS',
'os x' => 'Mac OS X', 'os x' => 'Mac OS X',
'ppc mac' => 'Power PC Mac', 'ppc mac' => 'Power PC Mac',
'freebsd' => 'FreeBSD', 'freebsd' => 'FreeBSD',
'ppc' => 'Macintosh', 'ppc' => 'Macintosh',
'linux' => 'Linux', 'linux' => 'Linux',
'debian' => 'Debian', 'debian' => 'Debian',
'sunos' => 'Sun Solaris', 'sunos' => 'Sun Solaris',
'beos' => 'BeOS', 'beos' => 'BeOS',
'apachebench' => 'ApacheBench', 'apachebench' => 'ApacheBench',
'aix' => 'AIX', 'aix' => 'AIX',
'irix' => 'Irix', 'irix' => 'Irix',
'osf' => 'DEC OSF', 'osf' => 'DEC OSF',
'hp-ux' => 'HP-UX', 'hp-ux' => 'HP-UX',
'netbsd' => 'NetBSD', 'netbsd' => 'NetBSD',
'bsdi' => 'BSDi', 'bsdi' => 'BSDi',
'openbsd' => 'OpenBSD', 'openbsd' => 'OpenBSD',
'gnu' => 'GNU/Linux', 'gnu' => 'GNU/Linux',
'unix' => 'Unknown Unix OS', 'unix' => 'Unknown Unix OS',
'symbian' => 'Symbian OS', 'symbian' => 'Symbian OS',
]; ];
/** /**
...@@ -81,37 +81,37 @@ class UserAgents extends BaseConfig ...@@ -81,37 +81,37 @@ class UserAgents extends BaseConfig
* @var array<string, string> * @var array<string, string>
*/ */
public array $browsers = [ public array $browsers = [
'OPR' => 'Opera', 'OPR' => 'Opera',
'Flock' => 'Flock', 'Flock' => 'Flock',
'Edge' => 'Spartan', 'Edge' => 'Spartan',
'Edg' => 'Edge', 'Edg' => 'Edge',
'Chrome' => 'Chrome', 'Chrome' => 'Chrome',
// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string // Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
'Opera.*?Version' => 'Opera', 'Opera.*?Version' => 'Opera',
'Opera' => 'Opera', 'Opera' => 'Opera',
'MSIE' => 'Internet Explorer', 'MSIE' => 'Internet Explorer',
'Internet Explorer' => 'Internet Explorer', 'Internet Explorer' => 'Internet Explorer',
'Trident.* rv' => 'Internet Explorer', 'Trident.* rv' => 'Internet Explorer',
'Shiira' => 'Shiira', 'Shiira' => 'Shiira',
'Firefox' => 'Firefox', 'Firefox' => 'Firefox',
'Chimera' => 'Chimera', 'Chimera' => 'Chimera',
'Phoenix' => 'Phoenix', 'Phoenix' => 'Phoenix',
'Firebird' => 'Firebird', 'Firebird' => 'Firebird',
'Camino' => 'Camino', 'Camino' => 'Camino',
'Netscape' => 'Netscape', 'Netscape' => 'Netscape',
'OmniWeb' => 'OmniWeb', 'OmniWeb' => 'OmniWeb',
'Safari' => 'Safari', 'Safari' => 'Safari',
'Mozilla' => 'Mozilla', 'Mozilla' => 'Mozilla',
'Konqueror' => 'Konqueror', 'Konqueror' => 'Konqueror',
'icab' => 'iCab', 'icab' => 'iCab',
'Lynx' => 'Lynx', 'Lynx' => 'Lynx',
'Links' => 'Links', 'Links' => 'Links',
'hotjava' => 'HotJava', 'hotjava' => 'HotJava',
'amaya' => 'Amaya', 'amaya' => 'Amaya',
'IBrowse' => 'IBrowse', 'IBrowse' => 'IBrowse',
'Maxthon' => 'Maxthon', 'Maxthon' => 'Maxthon',
'Ubuntu' => 'Ubuntu Web Browser', 'Ubuntu' => 'Ubuntu Web Browser',
'Vivaldi' => 'Vivaldi', 'Vivaldi' => 'Vivaldi',
]; ];
/** /**
...@@ -139,86 +139,86 @@ class UserAgents extends BaseConfig ...@@ -139,86 +139,86 @@ class UserAgents extends BaseConfig
// 'motorola' => 'Motorola' // 'motorola' => 'Motorola'
// Phones and Manufacturers // Phones and Manufacturers
'motorola' => 'Motorola', 'motorola' => 'Motorola',
'nokia' => 'Nokia', 'nokia' => 'Nokia',
'palm' => 'Palm', 'palm' => 'Palm',
'iphone' => 'Apple iPhone', 'iphone' => 'Apple iPhone',
'ipad' => 'iPad', 'ipad' => 'iPad',
'ipod' => 'Apple iPod Touch', 'ipod' => 'Apple iPod Touch',
'sony' => 'Sony Ericsson', 'sony' => 'Sony Ericsson',
'ericsson' => 'Sony Ericsson', 'ericsson' => 'Sony Ericsson',
'blackberry' => 'BlackBerry', 'blackberry' => 'BlackBerry',
'cocoon' => 'O2 Cocoon', 'cocoon' => 'O2 Cocoon',
'blazer' => 'Treo', 'blazer' => 'Treo',
'lg' => 'LG', 'lg' => 'LG',
'amoi' => 'Amoi', 'amoi' => 'Amoi',
'xda' => 'XDA', 'xda' => 'XDA',
'mda' => 'MDA', 'mda' => 'MDA',
'vario' => 'Vario', 'vario' => 'Vario',
'htc' => 'HTC', 'htc' => 'HTC',
'samsung' => 'Samsung', 'samsung' => 'Samsung',
'sharp' => 'Sharp', 'sharp' => 'Sharp',
'sie-' => 'Siemens', 'sie-' => 'Siemens',
'alcatel' => 'Alcatel', 'alcatel' => 'Alcatel',
'benq' => 'BenQ', 'benq' => 'BenQ',
'ipaq' => 'HP iPaq', 'ipaq' => 'HP iPaq',
'mot-' => 'Motorola', 'mot-' => 'Motorola',
'playstation portable' => 'PlayStation Portable', 'playstation portable' => 'PlayStation Portable',
'playstation 3' => 'PlayStation 3', 'playstation 3' => 'PlayStation 3',
'playstation vita' => 'PlayStation Vita', 'playstation vita' => 'PlayStation Vita',
'hiptop' => 'Danger Hiptop', 'hiptop' => 'Danger Hiptop',
'nec-' => 'NEC', 'nec-' => 'NEC',
'panasonic' => 'Panasonic', 'panasonic' => 'Panasonic',
'philips' => 'Philips', 'philips' => 'Philips',
'sagem' => 'Sagem', 'sagem' => 'Sagem',
'sanyo' => 'Sanyo', 'sanyo' => 'Sanyo',
'spv' => 'SPV', 'spv' => 'SPV',
'zte' => 'ZTE', 'zte' => 'ZTE',
'sendo' => 'Sendo', 'sendo' => 'Sendo',
'nintendo dsi' => 'Nintendo DSi', 'nintendo dsi' => 'Nintendo DSi',
'nintendo ds' => 'Nintendo DS', 'nintendo ds' => 'Nintendo DS',
'nintendo 3ds' => 'Nintendo 3DS', 'nintendo 3ds' => 'Nintendo 3DS',
'wii' => 'Nintendo Wii', 'wii' => 'Nintendo Wii',
'open web' => 'Open Web', 'open web' => 'Open Web',
'openweb' => 'OpenWeb', 'openweb' => 'OpenWeb',
// Operating Systems // Operating Systems
'android' => 'Android', 'android' => 'Android',
'symbian' => 'Symbian', 'symbian' => 'Symbian',
'SymbianOS' => 'SymbianOS', 'SymbianOS' => 'SymbianOS',
'elaine' => 'Palm', 'elaine' => 'Palm',
'series60' => 'Symbian S60', 'series60' => 'Symbian S60',
'windows ce' => 'Windows CE', 'windows ce' => 'Windows CE',
// Browsers // Browsers
'obigo' => 'Obigo', 'obigo' => 'Obigo',
'netfront' => 'Netfront Browser', 'netfront' => 'Netfront Browser',
'openwave' => 'Openwave Browser', 'openwave' => 'Openwave Browser',
'mobilexplorer' => 'Mobile Explorer', 'mobilexplorer' => 'Mobile Explorer',
'operamini' => 'Opera Mini', 'operamini' => 'Opera Mini',
'opera mini' => 'Opera Mini', 'opera mini' => 'Opera Mini',
'opera mobi' => 'Opera Mobile', 'opera mobi' => 'Opera Mobile',
'fennec' => 'Firefox Mobile', 'fennec' => 'Firefox Mobile',
// Other // Other
'digital paths' => 'Digital Paths', 'digital paths' => 'Digital Paths',
'avantgo' => 'AvantGo', 'avantgo' => 'AvantGo',
'xiino' => 'Xiino', 'xiino' => 'Xiino',
'novarra' => 'Novarra Transcoder', 'novarra' => 'Novarra Transcoder',
'vodafone' => 'Vodafone', 'vodafone' => 'Vodafone',
'docomo' => 'NTT DoCoMo', 'docomo' => 'NTT DoCoMo',
'o2' => 'O2', 'o2' => 'O2',
// Fallback // Fallback
'mobile' => 'Generic Mobile', 'mobile' => 'Generic Mobile',
'wireless' => 'Generic Mobile', 'wireless' => 'Generic Mobile',
'j2me' => 'Generic Mobile', 'j2me' => 'Generic Mobile',
'midp' => 'Generic Mobile', 'midp' => 'Generic Mobile',
'cldc' => 'Generic Mobile', 'cldc' => 'Generic Mobile',
'up.link' => 'Generic Mobile', 'up.link' => 'Generic Mobile',
'up.browser' => 'Generic Mobile', 'up.browser' => 'Generic Mobile',
'smartphone' => 'Generic Mobile', 'smartphone' => 'Generic Mobile',
'cellphone' => 'Generic Mobile', 'cellphone' => 'Generic Mobile',
]; ];
/** /**
...@@ -231,24 +231,24 @@ class UserAgents extends BaseConfig ...@@ -231,24 +231,24 @@ class UserAgents extends BaseConfig
* @var array<string, string> * @var array<string, string>
*/ */
public array $robots = [ public array $robots = [
'googlebot' => 'Googlebot', 'googlebot' => 'Googlebot',
'msnbot' => 'MSNBot', 'msnbot' => 'MSNBot',
'baiduspider' => 'Baiduspider', 'baiduspider' => 'Baiduspider',
'bingbot' => 'Bing', 'bingbot' => 'Bing',
'slurp' => 'Inktomi Slurp', 'slurp' => 'Inktomi Slurp',
'yahoo' => 'Yahoo', 'yahoo' => 'Yahoo',
'ask jeeves' => 'Ask Jeeves', 'ask jeeves' => 'Ask Jeeves',
'fastcrawler' => 'FastCrawler', 'fastcrawler' => 'FastCrawler',
'infoseek' => 'InfoSeek Robot 1.0', 'infoseek' => 'InfoSeek Robot 1.0',
'lycos' => 'Lycos', 'lycos' => 'Lycos',
'yandex' => 'YandexBot', 'yandex' => 'YandexBot',
'mediapartners-google' => 'MediaPartners Google', 'mediapartners-google' => 'MediaPartners Google',
'CRAZYWEBCRAWLER' => 'Crazy Webcrawler', 'CRAZYWEBCRAWLER' => 'Crazy Webcrawler',
'adsbot-google' => 'AdsBot Google', 'adsbot-google' => 'AdsBot Google',
'feedfetcher-google' => 'Feedfetcher Google', 'feedfetcher-google' => 'Feedfetcher Google',
'curious george' => 'Curious George', 'curious george' => 'Curious George',
'ia_archiver' => 'Alexa Crawler', 'ia_archiver' => 'Alexa Crawler',
'MJ12bot' => 'Majestic-12', 'MJ12bot' => 'Majestic-12',
'Uptimebot' => 'Uptimebot', 'Uptimebot' => 'Uptimebot',
]; ];
} }
...@@ -5,29 +5,27 @@ declare(strict_types=1); ...@@ -5,29 +5,27 @@ declare(strict_types=1);
namespace Config; namespace Config;
use App\Validation\FileRules as AppFileRules; use App\Validation\FileRules as AppFileRules;
use App\Validation\Rules as AppRules; use App\Validation\OtherRules;
use CodeIgniter\Config\BaseConfig; use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Validation\CreditCardRules; use CodeIgniter\Validation\StrictRules\CreditCardRules;
use CodeIgniter\Validation\FileRules; use CodeIgniter\Validation\StrictRules\FileRules;
use CodeIgniter\Validation\FormatRules; use CodeIgniter\Validation\StrictRules\FormatRules;
use CodeIgniter\Validation\Rules; use CodeIgniter\Validation\StrictRules\Rules;
use Myth\Auth\Authentication\Passwords\ValidationRules as PasswordRules;
class Validation extends BaseConfig class Validation extends BaseConfig
{ {
/** /**
* Stores the classes that contain the rules that are available. * Stores the classes that contain the rules that are available.
* *
* @var string[] * @var list<string>
*/ */
public array $ruleSets = [ public array $ruleSets = [
Rules::class, Rules::class,
FormatRules::class, FormatRules::class,
FileRules::class, FileRules::class,
CreditCardRules::class, CreditCardRules::class,
AppRules::class,
AppFileRules::class, AppFileRules::class,
PasswordRules::class, OtherRules::class,
]; ];
/** /**
...@@ -36,7 +34,7 @@ class Validation extends BaseConfig ...@@ -36,7 +34,7 @@ class Validation extends BaseConfig
* @var array<string, string> * @var array<string, string>
*/ */
public array $templates = [ public array $templates = [
'list' => 'CodeIgniter\Validation\Views\list', 'list' => 'CodeIgniter\Validation\Views\list',
'single' => 'CodeIgniter\Validation\Views\single', 'single' => 'CodeIgniter\Validation\Views\single',
]; ];
} }
...@@ -6,7 +6,12 @@ namespace Config; ...@@ -6,7 +6,12 @@ namespace Config;
use CodeIgniter\Config\View as BaseView; use CodeIgniter\Config\View as BaseView;
use CodeIgniter\View\ViewDecoratorInterface; use CodeIgniter\View\ViewDecoratorInterface;
use ViewComponents\Decorator;
/**
* @phpstan-type parser_callable (callable(mixed): mixed)
* @phpstan-type parser_callable_string (callable(mixed): mixed)&string
*/
class View extends BaseView class View extends BaseView
{ {
/** /**
...@@ -26,7 +31,8 @@ class View extends BaseView ...@@ -26,7 +31,8 @@ class View extends BaseView
* *
* Examples: { title|esc(js) } { created_on|date(Y-m-d)|esc(attr) } * Examples: { title|esc(js) } { created_on|date(Y-m-d)|esc(attr) }
* *
* @var string[] * @var array<string, string>
* @phpstan-var array<string, parser_callable_string>
*/ */
public $filters = []; public $filters = [];
...@@ -34,7 +40,8 @@ class View extends BaseView ...@@ -34,7 +40,8 @@ class View extends BaseView
* Parser Plugins provide a way to extend the functionality provided by the core Parser by creating aliases that * 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. * will be replaced with any callable. Can be single or tag pair.
* *
* @var string[] * @var array<string, callable|list<string>|string>
* @phpstan-var array<string, list<parser_callable_string>|parser_callable_string|parser_callable>
*/ */
public $plugins = []; public $plugins = [];
...@@ -44,7 +51,7 @@ class View extends BaseView ...@@ -44,7 +51,7 @@ class View extends BaseView
* *
* All classes must implement CodeIgniter\View\ViewDecoratorInterface * All classes must implement CodeIgniter\View\ViewDecoratorInterface
* *
* @var class-string<ViewDecoratorInterface>[] * @var list<class-string<ViewDecoratorInterface>>
*/ */
public array $decorators = []; public array $decorators = [Decorator::class];
} }
<?php
// app/Config/Vite.php
declare(strict_types=1);
namespace Config;
use CodeIgniterVite\Config\Vite as ViteConfig;
class Vite extends ViteConfig
{
public function __construct()
{
parent::__construct();
$adminGateway = config('Admin')
->gateway;
$installGateway = config('Install')
->gateway;
$this->routesAssets = [
[
'routes' => ['*'],
'exclude' => [$adminGateway . '*', $installGateway . '*'],
'assets' => ['styles/site.css', 'js/app.ts', 'js/podcast.ts', 'js/audio-player.ts'],
],
[
'routes' => ['/map'],
'assets' => ['js/map.ts'],
],
[
'routes' => ['/' . $adminGateway . '*'],
'assets' => ['styles/admin.css', 'js/admin.ts', 'js/admin-audio-player.ts'],
],
[
'routes' => [$installGateway . '*'],
'assets' => ['styles/install.css'],
],
];
}
}
...@@ -18,22 +18,19 @@ class ActorController extends FediverseActorController ...@@ -18,22 +18,19 @@ class ActorController extends FediverseActorController
use AnalyticsTrait; use AnalyticsTrait;
/** /**
* @var string[] * @var list<string>
*/ */
protected $helpers = ['auth', 'svg', 'components', 'misc', 'seo']; protected $helpers = ['svg', 'components', 'misc', 'seo'];
public function follow(): string public function followView(): string
{ {
// Prevent analytics hit when authenticated // @phpstan-ignore-next-line
if (! can_user_interact()) { $this->registerPodcastWebpageHit($this->actor->podcast->id);
// @phpstan-ignore-next-line
$this->registerPodcastWebpageHit($this->actor->podcast->id);
}
helper(['form', 'components', 'svg']); helper(['form', 'components', 'svg']);
// @phpstan-ignore-next-line
set_follow_metatags($this->actor);
$data = [ $data = [
// @phpstan-ignore-next-line
'metatags' => get_follow_metatags($this->actor),
'actor' => $this->actor, 'actor' => $this->actor,
]; ];
......
...@@ -7,12 +7,11 @@ namespace App\Controllers; ...@@ -7,12 +7,11 @@ namespace App\Controllers;
use CodeIgniter\Controller; use CodeIgniter\Controller;
use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\ResponseInterface;
use Override;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use ViewThemes\Theme; use ViewThemes\Theme;
/** /**
* Class BaseController
*
* BaseController provides a convenient place for loading components and performing functions that are needed by all * BaseController provides a convenient place for loading components and performing functions that are needed by all
* your controllers. Extend this class in any new controllers: class Home extends BaseController * your controllers. Extend this class in any new controllers: class Home extends BaseController
* *
...@@ -21,14 +20,27 @@ use ViewThemes\Theme; ...@@ -21,14 +20,27 @@ use ViewThemes\Theme;
abstract class BaseController extends Controller abstract class BaseController extends Controller
{ {
/** /**
* Constructor. * An array of helpers to be loaded automatically upon
* class instantiation. These helpers will be available
* to all other controllers that extend BaseController.
*
* @var list<string>
*/ */
protected $helpers = [];
/**
* Be sure to declare properties for any property fetch you initialized.
* The creation of dynamic property is deprecated in PHP 8.2.
*/
// protected $session;
#[Override]
public function initController( public function initController(
RequestInterface $request, RequestInterface $request,
ResponseInterface $response, ResponseInterface $response,
LoggerInterface $logger LoggerInterface $logger,
): void { ): void {
$this->helpers = array_merge($this->helpers, ['auth', 'svg', 'components', 'misc', 'seo']); $this->helpers = [...$this->helpers, 'svg', 'components', 'misc', 'seo', 'premium_podcasts'];
// Do Not Edit This Line // Do Not Edit This Line
parent::initController($request, $response, $logger); parent::initController($request, $response, $logger);
......
...@@ -11,14 +11,11 @@ declare(strict_types=1); ...@@ -11,14 +11,11 @@ declare(strict_types=1);
namespace App\Controllers; namespace App\Controllers;
use CodeIgniter\Controller; use CodeIgniter\Controller;
use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface;
class ColorsController extends Controller class ColorsController extends Controller
{ {
/** public function index(): ResponseInterface
* @noRector ReturnTypeDeclarationRector
*/
public function index(): Response
{ {
$cacheName = 'colors.css'; $cacheName = 'colors.css';
if ( if (
......
...@@ -23,13 +23,13 @@ class CreditsController extends BaseController ...@@ -23,13 +23,13 @@ class CreditsController extends BaseController
$cacheName = implode( $cacheName = implode(
'_', '_',
array_filter(['page', 'credits', $locale, can_user_interact() ? 'authenticated' : null]), array_filter(['page', 'credits', $locale, auth()->loggedIn() ? 'authenticated' : null]),
); );
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$page = new Page([ $page = new Page([
'title' => lang('Person.credits', [], $locale), 'title' => lang('Person.credits', [], $locale),
'slug' => 'credits', 'slug' => 'credits',
'content_markdown' => '', 'content_markdown' => '',
]); ]);
...@@ -48,17 +48,15 @@ class CreditsController extends BaseController ...@@ -48,17 +48,15 @@ class CreditsController extends BaseController
$personRole = $credit->person_role; $personRole = $credit->person_role;
$credits[$personGroup] = [ $credits[$personGroup] = [
'group_label' => $credit->group_label, 'group_label' => $credit->group_label,
'persons' => [ 'persons' => [
$personId => [ $personId => [
'full_name' => $credit->person->full_name, 'full_name' => $credit->person->full_name,
'thumbnail_url' => 'thumbnail_url' => get_avatar_url($credit->person, 'thumbnail'),
$credit->person->avatar->thumbnail_url, 'information_url' => $credit->person->information_url,
'information_url' => 'roles' => [
$credit->person->information_url,
'roles' => [
$personRole => [ $personRole => [
'role_label' => $credit->role_label, 'role_label' => $credit->role_label,
'is_in' => [ 'is_in' => [
[ [
'link' => $credit->episode_id 'link' => $credit->episode_id
? $credit->episode->link ? $credit->episode->link
...@@ -88,14 +86,13 @@ class CreditsController extends BaseController ...@@ -88,14 +86,13 @@ class CreditsController extends BaseController
$personId = $credit->person_id; $personId = $credit->person_id;
$personRole = $credit->person_role; $personRole = $credit->person_role;
$credits[$personGroup]['persons'][$personId] = [ $credits[$personGroup]['persons'][$personId] = [
'full_name' => $credit->person->full_name, 'full_name' => $credit->person->full_name,
'thumbnail_url' => 'thumbnail_url' => get_avatar_url($credit->person, 'thumbnail'),
$credit->person->avatar->thumbnail_url,
'information_url' => $credit->person->information_url, 'information_url' => $credit->person->information_url,
'roles' => [ 'roles' => [
$personRole => [ $personRole => [
'role_label' => $credit->role_label, 'role_label' => $credit->role_label,
'is_in' => [ 'is_in' => [
[ [
'link' => $credit->episode_id 'link' => $credit->episode_id
? $credit->episode->link ? $credit->episode->link
...@@ -124,7 +121,7 @@ class CreditsController extends BaseController ...@@ -124,7 +121,7 @@ class CreditsController extends BaseController
$personRole $personRole
] = [ ] = [
'role_label' => $credit->role_label, 'role_label' => $credit->role_label,
'is_in' => [ 'is_in' => [
[ [
'link' => $credit->episode_id 'link' => $credit->episode_id
? $credit->episode->link ? $credit->episode->link
...@@ -167,9 +164,9 @@ class CreditsController extends BaseController ...@@ -167,9 +164,9 @@ class CreditsController extends BaseController
} }
} }
set_page_metatags($page);
$data = [ $data = [
'metatags' => get_page_metatags($page), 'page' => $page,
'page' => $page,
'credits' => $credits, 'credits' => $credits,
]; ];
......
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Controllers;
use App\Entities\Episode;
use App\Entities\Podcast;
use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use CodeIgniter\Controller;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\HTTP\URI;
use Modules\Analytics\Config\Analytics;
use Modules\PremiumPodcasts\Entities\Subscription;
use Modules\PremiumPodcasts\Models\SubscriptionModel;
use Override;
use Psr\Log\LoggerInterface;
class EpisodeAudioController extends Controller
{
/**
* An array of helpers to be loaded automatically upon class instantiation. These helpers will be available to all
* other controllers that extend Analytics.
*
* @var list<string>
*/
protected $helpers = ['analytics'];
protected Podcast $podcast;
protected Episode $episode;
protected Analytics $analyticsConfig;
#[Override]
public function initController(
RequestInterface $request,
ResponseInterface $response,
LoggerInterface $logger,
): void {
// Do Not Edit This Line
parent::initController($request, $response, $logger);
set_user_session_deny_list_ip();
set_user_session_location();
set_user_session_player();
$this->analyticsConfig = config('Analytics');
}
public function _remap(string $method, string ...$params): mixed
{
if (count($params) < 2) {
throw PageNotFoundException::forPageNotFound();
}
if (
! ($podcast = (new PodcastModel())->getPodcastByHandle($params[0])) instanceof Podcast
) {
throw PageNotFoundException::forPageNotFound();
}
$this->podcast = $podcast;
if (
! ($episode = (new EpisodeModel())->getEpisodeBySlug($params[0], $params[1])) instanceof Episode
) {
throw PageNotFoundException::forPageNotFound();
}
$this->episode = $episode;
unset($params[1]);
unset($params[0]);
return $this->{$method}(...$params);
}
public function index(): RedirectResponse | ResponseInterface
{
// check if episode is premium?
$subscription = null;
// check if podcast is already unlocked before any token validation
if ($this->episode->is_premium && ! ($subscription = service('premium_podcasts')->subscription(
$this->episode->podcast->handle,
)) instanceof Subscription) {
// look for token as GET parameter
if (($token = $this->request->getGet('token')) === null) {
return $this->response->setStatusCode(401)
->setJSON([
'errors' => [
'status' => 401,
'title' => 'Unauthorized',
'detail' => 'Episode is premium, you must provide a token to unlock it.',
],
]);
}
// check if there's a valid subscription for the provided token
if (! ($subscription = (new SubscriptionModel())->validateSubscription(
$this->episode->podcast->handle,
$token,
)) instanceof Subscription) {
return $this->response->setStatusCode(401, 'Invalid token!')
->setJSON([
'errors' => [
'status' => 401,
'title' => 'Unauthorized',
'detail' => 'Invalid token!',
],
]);
}
}
$session = service('session');
$serviceName = '';
if ($this->request->getGet('_from')) {
$serviceName = $this->request->getGet('_from');
} elseif ($session->get('embed_domain') !== null) {
$serviceName = $session->get('embed_domain');
} elseif ($session->get('referer') !== null && $session->get('referer') !== '- Direct -') {
$serviceName = parse_url((string) $session->get('referer'), PHP_URL_HOST);
}
$audioFileSize = $this->episode->audio->file_size;
$audioFileHeaderSize = $this->episode->audio->header_size;
$audioDuration = $this->episode->audio->duration;
// bytes_threshold: number of bytes that must be downloaded for an episode to be counted in download analytics
// - if audio is less than or equal to 60s, then take the audio file_size
// - if audio is more than 60s, then take the audio file_header_size + 60s
$bytesThreshold = $audioDuration <= 60
? $audioFileSize
: $audioFileHeaderSize +
(int) floor((($audioFileSize - $audioFileHeaderSize) / $audioDuration) * 60);
podcast_hit(
$this->episode->podcast_id,
$this->episode->id,
$bytesThreshold,
$audioFileSize,
$audioDuration,
$this->episode->published_at->getTimestamp(),
$serviceName,
$subscription instanceof Subscription ? $subscription->id : null,
);
$audioFileURI = new URI(service('file_manager')->getUrl($this->episode->audio->file_key));
$queryParams = [];
foreach ($this->request->getGet() as $key => $value) {
// do not include token in query params
if ($key !== 'token') {
$queryParams[$key] = $value;
}
}
$audioFileURI->setQueryArray($queryParams);
return redirect()->to((string) $audioFileURI);
}
}