fix(security): add csrf filter + prevent xss attacks by escaping user input
- update CI4 to v4.1.9's stable production package - update php and js dependencies to latest
This commit is contained in:
parent
a597cf4ecf
commit
cd2e1e1dc3
|
@ -24,7 +24,7 @@ class Database extends Config
|
|||
/**
|
||||
* The default database connection.
|
||||
*
|
||||
* @var array<string, string|bool|int|array>
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public array $default = [
|
||||
'DSN' => '',
|
||||
|
@ -51,7 +51,7 @@ class Database extends Config
|
|||
*
|
||||
* @noRector StringClassNameToClassConstantRector
|
||||
*
|
||||
* @var array<string, string|bool|int|array>
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public array $tests = [
|
||||
'DSN' => '',
|
||||
|
|
|
@ -11,6 +11,7 @@ declare(strict_types=1);
|
|||
namespace Config;
|
||||
|
||||
use App\Libraries\NoteObject;
|
||||
use Exception;
|
||||
use Modules\Fediverse\Config\Fediverse as FediverseBaseConfig;
|
||||
|
||||
class Fediverse extends FediverseBaseConfig
|
||||
|
@ -26,10 +27,15 @@ class Fediverse extends FediverseBaseConfig
|
|||
{
|
||||
parent::__construct();
|
||||
|
||||
$defaultBanner = config('Images')
|
||||
->podcastBannerDefaultPaths[service('settings')->get('App.theme')] ?? config(
|
||||
'Images'
|
||||
)->podcastBannerDefaultPaths['default'];
|
||||
try {
|
||||
$appTheme = service('settings')
|
||||
->get('App.theme');
|
||||
$defaultBanner = config('Images')
|
||||
->podcastBannerDefaultPaths[$appTheme] ?? config('Images')->podcastBannerDefaultPaths['default'];
|
||||
} catch (Exception) {
|
||||
$defaultBanner = config('Images')
|
||||
->podcastBannerDefaultPaths['default'];
|
||||
}
|
||||
|
||||
['dirname' => $dirname, 'extension' => $extension, 'filename' => $filename] = pathinfo(
|
||||
$defaultBanner['path']
|
||||
|
|
|
@ -39,18 +39,19 @@ class Filters extends BaseConfig
|
|||
/**
|
||||
* List of filter aliases that are always applied before and after every request.
|
||||
*
|
||||
* @var array<string, string[]>
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public array $globals = [
|
||||
'before' => [
|
||||
// 'honeypot',
|
||||
// 'csrf',
|
||||
'csrf' => [
|
||||
'except' => ['@[a-zA-Z0-9\_]{1,32}/inbox'],
|
||||
],
|
||||
// 'invalidchars',
|
||||
],
|
||||
'after' => [
|
||||
'toolbar',
|
||||
// 'honeypot',
|
||||
// 'honeypot',
|
||||
// 'secureheaders',
|
||||
],
|
||||
];
|
||||
|
@ -79,7 +80,7 @@ class Filters extends BaseConfig
|
|||
|
||||
$this->filters = [
|
||||
'login' => [
|
||||
'before' => [config('Admin') ->gateway . '*', config('Analytics') ->gateway . '*'],
|
||||
'before' => [config('Admin')->gateway . '*', config('Analytics')->gateway . '*'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class Paths
|
|||
* the path if the folder is not in the same directory as this file.
|
||||
*/
|
||||
public string $systemDirectory =
|
||||
__DIR__ . '/../../vendor/codeigniter4/codeigniter4/system';
|
||||
__DIR__ . '/../../vendor/codeigniter4/framework/system';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
|
|
|
@ -26,7 +26,7 @@ class Security extends BaseConfig
|
|||
*
|
||||
* Randomize the CSRF Token for added security.
|
||||
*/
|
||||
public bool $tokenRandomize = false;
|
||||
public bool $tokenRandomize = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
|
@ -33,6 +33,7 @@ class ColorsController extends Controller
|
|||
foreach ($color as $variable => $value) {
|
||||
$colorsCssBody .= "--color-{$variable}: {$value[0]} {$value[1]}% {$value[2]}%;";
|
||||
}
|
||||
|
||||
$colorsCssBody .= '}';
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ class EpisodeCommentController extends BaseController
|
|||
helper('form');
|
||||
return view('episode/comment', $data);
|
||||
}
|
||||
|
||||
return view('episode/comment', $data, [
|
||||
'cache' => DECADE,
|
||||
'cache_name' => $cacheName,
|
||||
|
|
|
@ -134,6 +134,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
return view('episode/activity', $data);
|
||||
}
|
||||
|
||||
// The page cache is set to a decade so it is deleted manually upon podcast update
|
||||
return view('episode/activity', $data, [
|
||||
'cache' => $secondsToNextUnpublishedEpisode
|
||||
|
|
|
@ -34,6 +34,7 @@ class MapController extends BaseController
|
|||
'cache_name' => $cacheName,
|
||||
]);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -50,19 +51,21 @@ class MapController extends BaseController
|
|||
$found[] = [
|
||||
'latitude' => $episode->location->latitude,
|
||||
'longitude' => $episode->location->longitude,
|
||||
'location_name' => $episode->location->name,
|
||||
'location_name' => esc($episode->location->name),
|
||||
'location_url' => $episode->location->url,
|
||||
'episode_link' => $episode->link,
|
||||
'podcast_link' => $episode->podcast->link,
|
||||
'cover_url' => $episode->cover->thumbnail_url,
|
||||
'podcast_title' => $episode->podcast->title,
|
||||
'episode_title' => $episode->title,
|
||||
'podcast_title' => esc($episode->podcast->title),
|
||||
'episode_title' => esc($episode->title),
|
||||
];
|
||||
}
|
||||
|
||||
// The page cache is set to a decade so it is deleted manually upon episode update
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $this->response->setJSON($found);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ class PostController extends FediversePostController
|
|||
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
// @phpstan-ignore-next-line
|
||||
'metatags' => get_post_metatags($this->post),
|
||||
'post' => $this->post,
|
||||
'podcast' => $this->podcast,
|
||||
|
@ -98,6 +97,7 @@ class PostController extends FediversePostController
|
|||
helper('form');
|
||||
return view('post/post', $data);
|
||||
}
|
||||
|
||||
return view('post/post', $data, [
|
||||
'cache' => DECADE,
|
||||
'cache_name' => $cacheName,
|
||||
|
@ -111,7 +111,7 @@ class PostController extends FediversePostController
|
|||
{
|
||||
$rules = [
|
||||
'message' => 'required|max_length[500]',
|
||||
'episode_url' => 'valid_url|permit_empty',
|
||||
'episode_url' => 'valid_url_strict|permit_empty',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
|
@ -246,7 +246,6 @@ class PostController extends FediversePostController
|
|||
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
// @phpstan-ignore-next-line
|
||||
'metatags' => get_remote_actions_metatags($this->post, $action),
|
||||
'podcast' => $this->podcast,
|
||||
'actor' => $this->actor,
|
||||
|
|
|
@ -18,7 +18,7 @@ use CodeIgniter\HTTP\ResponseInterface;
|
|||
class WebmanifestController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
* @var array<string, array<string, string>>
|
||||
*/
|
||||
public const THEME_COLORS = [
|
||||
'pine' => [
|
||||
|
@ -50,10 +50,8 @@ class WebmanifestController extends Controller
|
|||
public function index(): ResponseInterface
|
||||
{
|
||||
$webmanifest = [
|
||||
'name' => service('settings')
|
||||
->get('App.siteName'),
|
||||
'description' => service('settings')
|
||||
->get('App.siteDescription'),
|
||||
'name' => esc(service('settings') ->get('App.siteName')),
|
||||
'description' => esc(service('settings') ->get('App.siteDescription')),
|
||||
'lang' => service('request')
|
||||
->getLocale(),
|
||||
'start_url' => base_url(),
|
||||
|
@ -89,12 +87,12 @@ class WebmanifestController extends Controller
|
|||
}
|
||||
|
||||
$webmanifest = [
|
||||
'name' => $podcast->title,
|
||||
'short_name' => '@' . $podcast->handle,
|
||||
'name' => esc($podcast->title),
|
||||
'short_name' => '@' . esc($podcast->handle),
|
||||
'description' => $podcast->description,
|
||||
'lang' => $podcast->language_code,
|
||||
'start_url' => $podcast->link,
|
||||
'scope' => '/@' . $podcast->handle,
|
||||
'scope' => '/@' . esc($podcast->handle),
|
||||
'display' => 'standalone',
|
||||
'orientation' => 'portrait',
|
||||
'theme_color' => self::THEME_COLORS[service('settings')->get('App.theme')]['theme'],
|
||||
|
|
|
@ -37,7 +37,7 @@ class AuthSeeder extends Seeder
|
|||
*
|
||||
* ``` context => [ [action, description], [action, description], ... ] ```
|
||||
*
|
||||
* @var array<string, array<string, string|array>[]>
|
||||
* @var array<string, array<string, string|string[]>[]>
|
||||
*/
|
||||
protected array $permissions = [
|
||||
'settings' => [
|
||||
|
@ -302,12 +302,14 @@ class AuthSeeder extends Seeder
|
|||
->ignore(true)
|
||||
->insertBatch($dataPermissions);
|
||||
}
|
||||
|
||||
if ($this->db->table('auth_groups')->countAll() < count($dataGroups)) {
|
||||
$this->db
|
||||
->table('auth_groups')
|
||||
->ignore(true)
|
||||
->insertBatch($dataGroups);
|
||||
}
|
||||
|
||||
if ($this->db->table('auth_groups_permissions')->countAll() < count($dataGroupsPermissions)) {
|
||||
$this->db
|
||||
->table('auth_groups_permissions')
|
||||
|
|
|
@ -169,6 +169,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
|||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->db
|
||||
->table('analytics_podcasts')
|
||||
->ignore(true)
|
||||
|
|
|
@ -248,6 +248,7 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
|||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->db
|
||||
->table('analytics_website_by_browser')
|
||||
->ignore(true)
|
||||
|
|
|
@ -367,6 +367,7 @@ class Episode extends Entity
|
|||
if ($this->transcript !== null) {
|
||||
return $this->transcript->file_url;
|
||||
}
|
||||
|
||||
return $this->transcript_remote_url;
|
||||
}
|
||||
|
||||
|
@ -452,16 +453,14 @@ class Episode extends Entity
|
|||
|
||||
public function getLink(): string
|
||||
{
|
||||
return url_to('episode', $this->getPodcast()->handle, $this->attributes['slug']);
|
||||
return url_to('episode', esc($this->getPodcast()->handle), esc($this->attributes['slug']));
|
||||
}
|
||||
|
||||
public function getEmbedUrl(string $theme = null): string
|
||||
{
|
||||
return base_url(
|
||||
$theme
|
||||
? route_to('embed-theme', $this->getPodcast() ->handle, $this->attributes['slug'], $theme,)
|
||||
: route_to('embed', $this->getPodcast()->handle, $this->attributes['slug']),
|
||||
);
|
||||
return $theme
|
||||
? url_to('embed-theme', esc($this->getPodcast()->handle), esc($this->attributes['slug']), $theme,)
|
||||
: url_to('embed', esc($this->getPodcast()->handle), esc($this->attributes['slug']));
|
||||
}
|
||||
|
||||
public function setGuid(?string $guid = null): static
|
||||
|
@ -611,7 +610,7 @@ class Episode extends Entity
|
|||
'elements' => $this->custom_rss,
|
||||
], $xmlNode);
|
||||
|
||||
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
||||
return (string) str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -102,7 +102,6 @@ class EpisodeComment extends UuidEntity
|
|||
->getActorById($this->actor_id);
|
||||
}
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ class Location extends Entity
|
|||
$latitude = floatval($geoArray[0]);
|
||||
$longitude = floatval($geoArray[1]);
|
||||
}
|
||||
|
||||
parent::__construct([
|
||||
'name' => $name,
|
||||
'geo' => $geo,
|
||||
|
|
|
@ -43,7 +43,6 @@ class Audio extends BaseMedia
|
|||
|
||||
$this->attributes['file_mimetype'] = $audioMetadata['mime_type'];
|
||||
$this->attributes['file_size'] = $audioMetadata['filesize'];
|
||||
// @phpstan-ignore-next-line
|
||||
$this->attributes['description'] = @$audioMetadata['id3v2']['comments']['comment'][0];
|
||||
$this->attributes['file_metadata'] = json_encode($audioMetadata, JSON_INVALID_UTF8_SUBSTITUTE);
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ class Image extends BaseMedia
|
|||
{
|
||||
parent::setFile($file);
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
if ($this->file_mimetype === 'image/jpeg' && $metadata = @exif_read_data(
|
||||
media_path($this->file_path),
|
||||
null,
|
||||
|
|
|
@ -202,7 +202,6 @@ class Podcast extends Entity
|
|||
->getActorById($this->actor_id);
|
||||
}
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
|
@ -517,11 +516,12 @@ class Podcast extends Entity
|
|||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
* @return int[]|string[]
|
||||
*/
|
||||
public function getOtherCategoriesIds(): array
|
||||
{
|
||||
if ($this->other_categories_ids === null) {
|
||||
// @phpstan-ignore-next-line
|
||||
$this->other_categories_ids = array_column($this->getOtherCategories(), 'id');
|
||||
}
|
||||
|
||||
|
@ -586,7 +586,7 @@ class Podcast extends Entity
|
|||
'elements' => $this->custom_rss,
|
||||
], $xmlNode);
|
||||
|
||||
return str_replace(['<channel>', '</channel>'], '', $xmlNode->asXML());
|
||||
return (string) str_replace(['<channel>', '</channel>'], '', $xmlNode->asXML());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,7 +9,6 @@ declare(strict_types=1);
|
|||
*/
|
||||
|
||||
use App\Models\ActorModel;
|
||||
use CodeIgniter\Database\Exceptions\DataException;
|
||||
use Modules\Auth\Entities\User;
|
||||
use Modules\Fediverse\Entities\Actor;
|
||||
|
||||
|
@ -83,9 +82,6 @@ if (! function_exists('interact_as_actor')) {
|
|||
}
|
||||
|
||||
if (! function_exists('can_user_interact')) {
|
||||
/**
|
||||
* @throws DataException
|
||||
*/
|
||||
function can_user_interact(): bool
|
||||
{
|
||||
return (bool) interact_as_actor();
|
||||
|
|
|
@ -31,6 +31,6 @@ if (! function_exists('replace_breadcrumb_params')) {
|
|||
function replace_breadcrumb_params(array $newParams): void
|
||||
{
|
||||
$breadcrumb = Services::breadcrumb();
|
||||
$breadcrumb->replaceParams($newParams);
|
||||
$breadcrumb->replaceParams(esc($newParams));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ if (! function_exists('data_table')) {
|
|||
foreach ($columns as $column) {
|
||||
$rowData[] = $column['cell']($row, ...$rest);
|
||||
}
|
||||
|
||||
$table->addRow($rowData);
|
||||
}
|
||||
} else {
|
||||
|
@ -141,7 +142,6 @@ if (! function_exists('publication_button')) {
|
|||
*/
|
||||
function publication_button(int $podcastId, int $episodeId, string $publicationStatus): string
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
switch ($publicationStatus) {
|
||||
case 'not_published':
|
||||
$label = lang('Episode.publish');
|
||||
|
@ -243,10 +243,10 @@ if (! function_exists('location_link')) {
|
|||
|
||||
return anchor(
|
||||
$location->url,
|
||||
icon('map-pin', 'mr-2') . $location->name,
|
||||
icon('map-pin', 'mr-2 flex-shrink-0') . '<span class="truncate">' . esc($location->name) . '</span>',
|
||||
[
|
||||
'class' =>
|
||||
'inline-flex items-baseline hover:underline focus:ring-accent' .
|
||||
'w-full overflow-hidden inline-flex items-baseline hover:underline focus:ring-accent' .
|
||||
($class === '' ? '' : " {$class}"),
|
||||
'target' => '_blank',
|
||||
'rel' => 'noreferrer noopener',
|
||||
|
|
|
@ -38,13 +38,13 @@ if (! function_exists('write_audio_file_tags')) {
|
|||
|
||||
// populate data array
|
||||
$TagData = [
|
||||
'title' => [$episode->title],
|
||||
'title' => [esc($episode->title)],
|
||||
'artist' => [
|
||||
$episode->podcast->publisher === null
|
||||
? $episode->podcast->owner_name
|
||||
? esc($episode->podcast->owner_name)
|
||||
: $episode->podcast->publisher,
|
||||
],
|
||||
'album' => [$episode->podcast->title],
|
||||
'album' => [esc($episode->podcast->title)],
|
||||
'year' => [$episode->published_at !== null ? $episode->published_at->format('Y') : ''],
|
||||
'genre' => ['Podcast'],
|
||||
'comment' => [$episode->description],
|
||||
|
@ -52,7 +52,7 @@ if (! function_exists('write_audio_file_tags')) {
|
|||
'copyright_message' => [$episode->podcast->copyright],
|
||||
'publisher' => [
|
||||
$episode->podcast->publisher === null
|
||||
? $episode->podcast->owner_name
|
||||
? esc($episode->podcast->owner_name)
|
||||
: $episode->podcast->publisher,
|
||||
],
|
||||
'encoded_by' => ['Castopod'],
|
||||
|
|
|
@ -92,6 +92,7 @@ if (! function_exists('download_file')) {
|
|||
return new File($tmpFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('media_path')) {
|
||||
/**
|
||||
* Prefixes the root media path to a given uri
|
||||
|
@ -104,6 +105,7 @@ if (! function_exists('media_path')) {
|
|||
if (is_array($uri)) {
|
||||
$uri = implode('/', $uri);
|
||||
}
|
||||
|
||||
$uri = trim($uri, '/');
|
||||
|
||||
return config('App')->mediaRoot . '/' . $uri;
|
||||
|
@ -122,6 +124,7 @@ if (! function_exists('media_base_url')) {
|
|||
if (is_array($uri)) {
|
||||
$uri = implode('/', $uri);
|
||||
}
|
||||
|
||||
$uri = trim($uri, '/');
|
||||
|
||||
$appConfig = config('App');
|
||||
|
|
|
@ -151,14 +151,17 @@ if (! function_exists('format_duration')) {
|
|||
if ($seconds < 60) {
|
||||
return '0:' . sprintf('%02d', $seconds);
|
||||
}
|
||||
|
||||
if ($seconds < 3600) {
|
||||
// < 1 hour: returns MM:SS
|
||||
return ltrim(gmdate('i:s', $seconds), '0');
|
||||
}
|
||||
|
||||
if ($seconds < 36000) {
|
||||
// < 10 hours: returns H:MM:SS
|
||||
return ltrim(gmdate('H:i:s', $seconds), '0');
|
||||
}
|
||||
|
||||
return gmdate('H:i:s', $seconds);
|
||||
}
|
||||
}
|
||||
|
@ -177,14 +180,17 @@ if (! function_exists('format_duration_symbol')) {
|
|||
if ($seconds < 60) {
|
||||
return $seconds . 's';
|
||||
}
|
||||
|
||||
if ($seconds < 3600) {
|
||||
// < 1 hour: returns MM:SS
|
||||
return ltrim(gmdate('i\m\i\n s\s', $seconds), '0');
|
||||
}
|
||||
|
||||
if ($seconds < 36000) {
|
||||
// < 10 hours: returns H:MM:SS
|
||||
return ltrim(gmdate('h\h i\m\i\n s\s', $seconds), '0');
|
||||
}
|
||||
|
||||
return gmdate('h\h i\m\i\n s\s', $seconds);
|
||||
}
|
||||
}
|
||||
|
@ -232,6 +238,7 @@ if (! function_exists('file_upload_max_size')) {
|
|||
$max_size = $upload_max;
|
||||
}
|
||||
}
|
||||
|
||||
return $max_size;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ if (! function_exists('render_page_links')) {
|
|||
'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent',
|
||||
]);
|
||||
foreach ($pages as $page) {
|
||||
$links .= anchor($page->link, $page->title, [
|
||||
$links .= anchor($page->link, esc($page->title), [
|
||||
'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent',
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -60,18 +60,16 @@ if (! function_exists('get_rss_feed')) {
|
|||
|
||||
$channel->addChild('language', $podcast->language_code);
|
||||
if ($podcast->location !== null) {
|
||||
$locationElement = $channel->addChild(
|
||||
'location',
|
||||
htmlspecialchars($podcast->location->name),
|
||||
$podcastNamespace,
|
||||
);
|
||||
$locationElement = $channel->addChild('location', $podcast->location->name, $podcastNamespace);
|
||||
if ($podcast->location->geo !== null) {
|
||||
$locationElement->addAttribute('geo', $podcast->location->geo);
|
||||
}
|
||||
|
||||
if ($podcast->location->osm !== null) {
|
||||
$locationElement->addAttribute('osm', $podcast->location->osm);
|
||||
}
|
||||
}
|
||||
|
||||
if ($podcast->payment_pointer !== null) {
|
||||
$valueElement = $channel->addChild('value', null, $podcastNamespace);
|
||||
$valueElement->addAttribute('type', 'webmonetization');
|
||||
|
@ -83,6 +81,7 @@ if (! function_exists('get_rss_feed')) {
|
|||
$recipientElement->addAttribute('address', $podcast->payment_pointer);
|
||||
$recipientElement->addAttribute('split', '100');
|
||||
}
|
||||
|
||||
$channel
|
||||
->addChild('locked', $podcast->is_locked ? 'yes' : 'no', $podcastNamespace)
|
||||
->addAttribute('owner', $podcast->owner_email);
|
||||
|
@ -96,8 +95,9 @@ if (! function_exists('get_rss_feed')) {
|
|||
if ($podcastingPlatform->account_id !== null) {
|
||||
$podcastingPlatformElement->addAttribute('id', $podcastingPlatform->account_id);
|
||||
}
|
||||
|
||||
if ($podcastingPlatform->link_url !== null) {
|
||||
$podcastingPlatformElement->addAttribute('url', htmlspecialchars($podcastingPlatform->link_url));
|
||||
$podcastingPlatformElement->addAttribute('url', $podcastingPlatform->link_url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,7 @@ if (! function_exists('get_rss_feed')) {
|
|||
if ($socialPlatform->account_id !== null) {
|
||||
$socialElement->addAttribute('accountId', esc($socialPlatform->account_id));
|
||||
}
|
||||
|
||||
if ($socialPlatform->link_url !== null) {
|
||||
$socialElement->addAttribute('accountUrl', esc($socialPlatform->link_url));
|
||||
}
|
||||
|
@ -179,17 +180,13 @@ if (! function_exists('get_rss_feed')) {
|
|||
);
|
||||
$fundingPlatformElement->addAttribute('platform', $fundingPlatform->slug);
|
||||
if ($fundingPlatform->link_url !== null) {
|
||||
$fundingPlatformElement->addAttribute('url', htmlspecialchars($fundingPlatform->link_url));
|
||||
$fundingPlatformElement->addAttribute('url', $fundingPlatform->link_url);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($podcast->persons as $person) {
|
||||
foreach ($person->roles as $role) {
|
||||
$personElement = $channel->addChild(
|
||||
'person',
|
||||
htmlspecialchars($person->full_name),
|
||||
$podcastNamespace,
|
||||
);
|
||||
$personElement = $channel->addChild('person', $person->full_name, $podcastNamespace,);
|
||||
|
||||
$personElement->addAttribute('img', $person->avatar->medium_url);
|
||||
|
||||
|
@ -199,14 +196,12 @@ if (! function_exists('get_rss_feed')) {
|
|||
|
||||
$personElement->addAttribute(
|
||||
'role',
|
||||
htmlspecialchars(
|
||||
lang("PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", [], 'en'),
|
||||
),
|
||||
lang("PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", [], 'en'),
|
||||
);
|
||||
|
||||
$personElement->addAttribute(
|
||||
'group',
|
||||
htmlspecialchars(lang("PersonsTaxonomy.persons.{$role->group}.label", [], 'en')),
|
||||
lang("PersonsTaxonomy.persons.{$role->group}.label", [], 'en'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -242,6 +237,7 @@ if (! function_exists('get_rss_feed')) {
|
|||
if ($podcast->is_blocked) {
|
||||
$channel->addChild('block', 'Yes', $itunesNamespace);
|
||||
}
|
||||
|
||||
if ($podcast->is_completed) {
|
||||
$channel->addChild('complete', 'Yes', $itunesNamespace);
|
||||
}
|
||||
|
@ -275,18 +271,16 @@ if (! function_exists('get_rss_feed')) {
|
|||
$item->addChild('guid', $episode->guid);
|
||||
$item->addChild('pubDate', $episode->published_at->format(DATE_RFC1123));
|
||||
if ($episode->location !== null) {
|
||||
$locationElement = $item->addChild(
|
||||
'location',
|
||||
htmlspecialchars($episode->location->name),
|
||||
$podcastNamespace,
|
||||
);
|
||||
$locationElement = $item->addChild('location', $episode->location->name, $podcastNamespace,);
|
||||
if ($episode->location->geo !== null) {
|
||||
$locationElement->addAttribute('geo', $episode->location->geo);
|
||||
}
|
||||
|
||||
if ($episode->location->osm !== null) {
|
||||
$locationElement->addAttribute('osm', $episode->location->osm);
|
||||
}
|
||||
}
|
||||
|
||||
$item->addChildWithCDATA('description', $episode->getDescriptionHtml($serviceSlug));
|
||||
$item->addChild('duration', (string) $episode->audio->duration, $itunesNamespace);
|
||||
$item->addChild('link', $episode->link);
|
||||
|
@ -420,6 +414,7 @@ if (! function_exists('add_category_tag')) {
|
|||
$itunesCategoryChild->addAttribute('text', $category->apple_category);
|
||||
$node->addChild('category', $category->parent->apple_category);
|
||||
}
|
||||
|
||||
$node->addChild('category', $category->apple_category);
|
||||
}
|
||||
}
|
||||
|
@ -445,10 +440,12 @@ if (! function_exists('rss_to_array')) {
|
|||
foreach ($rssNode->attributes() as $key => $value) {
|
||||
$arrayNode['attributes'][$key] = (string) $value;
|
||||
}
|
||||
|
||||
$textcontent = trim((string) $rssNode);
|
||||
if (strlen($textcontent) > 0) {
|
||||
$arrayNode['content'] = $textcontent;
|
||||
}
|
||||
|
||||
foreach ($nameSpaces as $currentNameSpace) {
|
||||
foreach ($rssNode->children($currentNameSpace) as $childXmlNode) {
|
||||
$arrayNode['elements'][] = rss_to_array($childXmlNode);
|
||||
|
@ -485,6 +482,7 @@ if (! function_exists('array_to_rss')) {
|
|||
$childXmlNode->addAttribute($attributeKey, $attributeValue);
|
||||
}
|
||||
}
|
||||
|
||||
array_to_rss($childArrayNode, $childXmlNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@ if (! function_exists('get_podcast_metatags')) {
|
|||
if ($podcast->category->parent_id !== null) {
|
||||
$category .= $podcast->category->parent->apple_category . ' › ';
|
||||
}
|
||||
|
||||
$category .= $podcast->category->apple_category;
|
||||
|
||||
$schema = new Schema(
|
||||
new Thing('PodcastSeries', [
|
||||
'name' => $podcast->title,
|
||||
'headline' => $podcast->title,
|
||||
'name' => esc($podcast->title),
|
||||
'headline' => esc($podcast->title),
|
||||
'url' => current_url(),
|
||||
'sameAs' => $podcast->link,
|
||||
'identifier' => $podcast->guid,
|
||||
|
@ -38,8 +39,8 @@ if (! function_exists('get_podcast_metatags')) {
|
|||
'description' => $podcast->description,
|
||||
'webFeed' => $podcast->feed_url,
|
||||
'accessMode' => 'auditory',
|
||||
'author' => $podcast->owner_name,
|
||||
'creator' => $podcast->owner_name,
|
||||
'author' => esc($podcast->owner_name),
|
||||
'creator' => esc($podcast->owner_name),
|
||||
'publisher' => $podcast->publisher,
|
||||
'inLanguage' => $podcast->language_code,
|
||||
'genre' => $category,
|
||||
|
@ -49,25 +50,27 @@ if (! function_exists('get_podcast_metatags')) {
|
|||
$metatags = new MetaTags();
|
||||
|
||||
$metatags
|
||||
->title(' ' . $podcast->title . " (@{$podcast->handle})" . ' • ' . lang('Podcast.' . $page))
|
||||
->title(esc($podcast->title) . ' (@' . esc($podcast->handle) . ') • ' . lang('Podcast.' . $page))
|
||||
->description(htmlspecialchars($podcast->description))
|
||||
->image((string) $podcast->cover->og_url)
|
||||
->canonical((string) current_url())
|
||||
->og('image:width', (string) config('Images')->podcastCoverSizes['og']['width'])
|
||||
->og('image:height', (string) config('Images')->podcastCoverSizes['og']['height'])
|
||||
->og('locale', $podcast->language_code)
|
||||
->og('site_name', service('settings')->get('App.siteName'))
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')))
|
||||
->push('link', [
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/activity+json',
|
||||
'href' => url_to('podcast-activity', $podcast->handle),
|
||||
'href' => url_to('podcast-activity', esc($podcast->handle)),
|
||||
]);
|
||||
|
||||
if ($podcast->payment_pointer) {
|
||||
$metatags->meta('monetization', $podcast->payment_pointer);
|
||||
}
|
||||
|
||||
return '<link type="application/rss+xml" rel="alternate" title="' . $podcast->title . '" href="' . $podcast->feed_url . '" />' . PHP_EOL . $metatags->__toString() . PHP_EOL . $schema->__toString();
|
||||
return '<link type="application/rss+xml" rel="alternate" title="' . esc(
|
||||
$podcast->title
|
||||
) . '" href="' . $podcast->feed_url . '" />' . PHP_EOL . $metatags->__toString() . PHP_EOL . $schema->__toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,8 +79,8 @@ if (! function_exists('get_episode_metatags')) {
|
|||
{
|
||||
$schema = new Schema(
|
||||
new Thing('PodcastEpisode', [
|
||||
'url' => url_to('episode', $episode->podcast->handle, $episode->slug),
|
||||
'name' => $episode->title,
|
||||
'url' => url_to('episode', esc($episode->podcast->handle), $episode->slug),
|
||||
'name' => esc($episode->title),
|
||||
'image' => $episode->cover->feed_url,
|
||||
'description' => $episode->description,
|
||||
'datePublished' => $episode->published_at->format(DATE_ISO8601),
|
||||
|
@ -87,7 +90,7 @@ if (! function_exists('get_episode_metatags')) {
|
|||
'contentUrl' => $episode->audio->file_url,
|
||||
]),
|
||||
'partOfSeries' => new Thing('PodcastSeries', [
|
||||
'name' => $episode->podcast->title,
|
||||
'name' => esc($episode->podcast->title),
|
||||
'url' => $episode->podcast->link,
|
||||
]),
|
||||
])
|
||||
|
@ -97,10 +100,10 @@ if (! function_exists('get_episode_metatags')) {
|
|||
|
||||
$metatags
|
||||
->title($episode->title)
|
||||
->description(htmlspecialchars($episode->description))
|
||||
->description(esc($episode->description))
|
||||
->image((string) $episode->cover->og_url, 'player')
|
||||
->canonical($episode->link)
|
||||
->og('site_name', service('settings')->get('App.siteName'))
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')))
|
||||
->og('image:width', (string) config('Images')->podcastCoverSizes['og']['width'])
|
||||
->og('image:height', (string) config('Images')->podcastCoverSizes['og']['height'])
|
||||
->og('locale', $episode->podcast->language_code)
|
||||
|
@ -109,7 +112,7 @@ if (! function_exists('get_episode_metatags')) {
|
|||
->meta('article:published_time', $episode->published_at->format(DATE_ISO8601))
|
||||
->meta('article:modified_time', $episode->updated_at->format(DATE_ISO8601))
|
||||
->twitter('audio:partner', $episode->podcast->publisher ?? '')
|
||||
->twitter('audio:artist_name', $episode->podcast->owner_name)
|
||||
->twitter('audio:artist_name', esc($episode->podcast->owner_name))
|
||||
->twitter('player', $episode->getEmbedUrl('light'))
|
||||
->twitter('player:width', (string) config('Embed')->width)
|
||||
->twitter('player:height', (string) config('Embed')->height)
|
||||
|
@ -125,9 +128,11 @@ if (! function_exists('get_episode_metatags')) {
|
|||
|
||||
return $metatags->__toString() . PHP_EOL . '<link rel="alternate" type="application/json+oembed" href="' . base_url(
|
||||
route_to('episode-oembed-json', $episode->podcast->handle, $episode->slug)
|
||||
) . '" title="' . $episode->title . ' oEmbed json" />' . PHP_EOL . '<link rel="alternate" type="text/xml+oembed" href="' . base_url(
|
||||
) . '" title="' . esc(
|
||||
$episode->title
|
||||
) . ' oEmbed json" />' . PHP_EOL . '<link rel="alternate" type="text/xml+oembed" href="' . base_url(
|
||||
route_to('episode-oembed-xml', $episode->podcast->handle, $episode->slug)
|
||||
) . '" title="' . $episode->title . ' oEmbed xml" />' . PHP_EOL . $schema->__toString();
|
||||
) . '" title="' . esc($episode->title) . ' oEmbed xml" />' . PHP_EOL . $schema->__toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +140,7 @@ if (! function_exists('get_post_metatags')) {
|
|||
function get_post_metatags(Post $post): string
|
||||
{
|
||||
$socialMediaPosting = new Thing('SocialMediaPosting', [
|
||||
'@id' => url_to('post', $post->actor->username, $post->id),
|
||||
'@id' => url_to('post', esc($post->actor->username), $post->id),
|
||||
'datePublished' => $post->published_at->format(DATE_ISO8601),
|
||||
'author' => new Thing('Person', [
|
||||
'name' => $post->actor->display_name,
|
||||
|
@ -172,11 +177,11 @@ if (! function_exists('get_post_metatags')) {
|
|||
->description($post->message)
|
||||
->image($post->actor->avatar_image_url)
|
||||
->canonical((string) current_url())
|
||||
->og('site_name', service('settings')->get('App.siteName'))
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')))
|
||||
->push('link', [
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/activity+json',
|
||||
'href' => url_to('post', $post->actor->username, $post->id),
|
||||
'href' => url_to('post', esc($post->actor->username), $post->id),
|
||||
]);
|
||||
|
||||
return $metatags->__toString() . PHP_EOL . $schema->__toString();
|
||||
|
@ -189,7 +194,7 @@ if (! function_exists('get_episode_comment_metatags')) {
|
|||
$schema = new Schema(new Thing('SocialMediaPosting', [
|
||||
'@id' => url_to(
|
||||
'episode-comment',
|
||||
$episodeComment->actor->username,
|
||||
esc($episodeComment->actor->username),
|
||||
$episodeComment->episode->slug,
|
||||
$episodeComment->id
|
||||
),
|
||||
|
@ -211,7 +216,7 @@ if (! function_exists('get_episode_comment_metatags')) {
|
|||
->description($episodeComment->message)
|
||||
->image($episodeComment->actor->avatar_image_url)
|
||||
->canonical((string) current_url())
|
||||
->og('site_name', service('settings')->get('App.siteName'))
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')))
|
||||
->push('link', [
|
||||
'rel' => 'alternate',
|
||||
'type' => 'application/activity+json',
|
||||
|
@ -238,7 +243,7 @@ if (! function_exists('get_follow_metatags')) {
|
|||
->description($actor->summary)
|
||||
->image($actor->avatar_image_url)
|
||||
->canonical((string) current_url())
|
||||
->og('site_name', service('settings')->get('App.siteName'));
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')));
|
||||
|
||||
return $metatags->__toString();
|
||||
}
|
||||
|
@ -255,7 +260,7 @@ if (! function_exists('get_remote_actions_metatags')) {
|
|||
->description($post->message)
|
||||
->image($post->actor->avatar_image_url)
|
||||
->canonical((string) current_url())
|
||||
->og('site_name', service('settings')->get('App.siteName'));
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')));
|
||||
|
||||
return $metatags->__toString();
|
||||
}
|
||||
|
@ -266,11 +271,11 @@ if (! function_exists('get_home_metatags')) {
|
|||
{
|
||||
$metatags = new MetaTags();
|
||||
$metatags
|
||||
->title(service('settings')->get('App.siteName'))
|
||||
->description(service('settings')->get('App.siteDescription'))
|
||||
->title(esc(service('settings')->get('App.siteName')))
|
||||
->description(esc(service('settings')->get('App.siteDescription')))
|
||||
->image(service('settings')->get('App.siteIcon')['512'])
|
||||
->canonical((string) current_url())
|
||||
->og('site_name', service('settings')->get('App.siteName'));
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')));
|
||||
|
||||
return $metatags->__toString();
|
||||
}
|
||||
|
@ -282,14 +287,14 @@ if (! function_exists('get_page_metatags')) {
|
|||
$metatags = new MetaTags();
|
||||
$metatags
|
||||
->title(
|
||||
$page->title . service('settings')->get('App.siteTitleSeparator') . service(
|
||||
esc($page->title) . service('settings')->get('App.siteTitleSeparator') . esc(service(
|
||||
'settings'
|
||||
)->get('App.siteName')
|
||||
)->get('App.siteName'))
|
||||
)
|
||||
->description(service('settings')->get('App.siteDescription'))
|
||||
->description(esc(service('settings')->get('App.siteDescription')))
|
||||
->image(service('settings')->get('App.siteIcon')['512'])
|
||||
->canonical((string) current_url())
|
||||
->og('site_name', service('settings')->get('App.siteName'));
|
||||
->og('site_name', esc(service('settings')->get('App.siteName')));
|
||||
|
||||
return $metatags->__toString();
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ if (! function_exists('svg')) {
|
|||
if ($class) {
|
||||
$svgContents = str_replace('<svg', '<svg class="' . $class . '"', $svgContents);
|
||||
}
|
||||
|
||||
return $svgContents;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class CommentObject extends ObjectType
|
|||
|
||||
$this->replies = url_to(
|
||||
'episode-comment-replies',
|
||||
$comment->actor->username,
|
||||
esc($comment->actor->username),
|
||||
$comment->episode->slug,
|
||||
$comment->id
|
||||
);
|
||||
|
|
|
@ -17,8 +17,6 @@ use GdImage;
|
|||
/**
|
||||
* TODO: refactor this by splitting process modules into different classes (image generation, subtitles clip, video
|
||||
* generation)
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
class VideoClipper
|
||||
{
|
||||
|
@ -299,7 +297,7 @@ class VideoClipper
|
|||
{
|
||||
$background = $this->generateBackground($this->dimensions['width'], $this->dimensions['height']);
|
||||
|
||||
if ($background === null) {
|
||||
if (! $background instanceof \GdImage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -384,6 +382,7 @@ class VideoClipper
|
|||
$this->dimensions['episodeNumbering']['paddingY'],
|
||||
);
|
||||
}
|
||||
|
||||
$this->addParagraphToImage(
|
||||
$background,
|
||||
$this->dimensions['episodeTitle']['x'],
|
||||
|
@ -409,6 +408,7 @@ class VideoClipper
|
|||
if (! $cleanedQuotes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
imagefilter($cleanedQuotes, IMG_FILTER_CONTRAST, 255);
|
||||
imagefilter($cleanedQuotes, IMG_FILTER_COLORIZE, ...$this->colors['quotes']);
|
||||
|
||||
|
@ -526,6 +526,7 @@ class VideoClipper
|
|||
if ($src === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
imagecopy($src, $source, 0, 0, 0, 0, $corner, $corner);
|
||||
imagecopy($src, $source, $corner, 0, $ws - $corner, 0, $corner, $corner);
|
||||
imagecopy($src, $source, $corner, $corner, $ws - $corner, $hs - $corner, $corner, $corner);
|
||||
|
@ -577,6 +578,7 @@ class VideoClipper
|
|||
if ($dest === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
imagealphablending($dest, false);
|
||||
imagefilledrectangle($dest, 0, 0, $s, $s, $alphacolor);
|
||||
imagecopyresampled($dest, $img, 0, 0, 0, 0, $s, $s, $ns, $ns);
|
||||
|
@ -652,7 +654,7 @@ class VideoClipper
|
|||
*
|
||||
* @return array<string, mixed>|false
|
||||
*/
|
||||
private function calculateTextBox(int $fontSize, int $fontAngle, string $fontFile, string $text): array | false
|
||||
private function calculateTextBox(int $fontSize, int $fontAngle, string $fontFile, string $text): array|bool
|
||||
{
|
||||
/************
|
||||
simple function that calculates the *exact* bounding box (single pixel precision).
|
||||
|
@ -664,6 +666,7 @@ class VideoClipper
|
|||
if (! $bbox) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$minX = min([$bbox[0], $bbox[2], $bbox[4], $bbox[6]]);
|
||||
$maxX = max([$bbox[0], $bbox[2], $bbox[4], $bbox[6]]);
|
||||
$minY = min([$bbox[1], $bbox[3], $bbox[5], $bbox[7]]);
|
||||
|
@ -755,7 +758,7 @@ class VideoClipper
|
|||
int $lineWidth,
|
||||
int $numberOfLines,
|
||||
int $paragraphIndent = 0,
|
||||
): array | false {
|
||||
): array|bool {
|
||||
// check length of text
|
||||
$bbox = $this->calculateTextBox($fontsize, 0, $fontPath, $text);
|
||||
if (! $bbox) {
|
||||
|
@ -783,6 +786,7 @@ class VideoClipper
|
|||
if (! $wordBox) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$wordWidth = $wordBox['width'];
|
||||
|
||||
if (($wordWidth + $length) > $lineWidth) {
|
||||
|
@ -791,6 +795,7 @@ class VideoClipper
|
|||
$lines[$numberOfLines - 1] .= '…';
|
||||
break;
|
||||
}
|
||||
|
||||
$lines[$lineNumber] = '';
|
||||
$length = 0;
|
||||
|
||||
|
|
|
@ -39,10 +39,11 @@ class PodcastActor extends ActorObject
|
|||
if ($podcast->category->parent_id !== null) {
|
||||
$category .= $podcast->category->parent->apple_category . ' › ';
|
||||
}
|
||||
|
||||
$category .= $podcast->category->apple_category;
|
||||
|
||||
$this->category = $category;
|
||||
|
||||
$this->episodes = url_to('podcast-episodes', $podcast->handle);
|
||||
$this->episodes = url_to('podcast-episodes', esc($podcast->handle));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class PodcastEpisode extends ObjectType
|
|||
$this->audio = [
|
||||
'id' => $episode->audio->file_url,
|
||||
'type' => 'Audio',
|
||||
'name' => $episode->title,
|
||||
'name' => esc($episode->title),
|
||||
'size' => $episode->audio->file_size,
|
||||
'duration' => $episode->audio->duration,
|
||||
'url' => [
|
||||
|
|
|
@ -27,7 +27,6 @@ class Router extends CodeIgniterRouter
|
|||
* @param string $uri The URI path to compare against the routes
|
||||
*
|
||||
* @return boolean Whether the route was matched or not.
|
||||
* @throws RedirectException
|
||||
*/
|
||||
protected function checkRoutes(string $uri): bool
|
||||
{
|
||||
|
@ -75,6 +74,7 @@ class Router extends CodeIgniterRouter
|
|||
$this->collection->getRedirectCode($key),
|
||||
);
|
||||
}
|
||||
|
||||
// Store our locale so CodeIgniter object can
|
||||
// assign it to the Request.
|
||||
if (isset($localeSegment)) {
|
||||
|
@ -135,6 +135,7 @@ class Router extends CodeIgniterRouter
|
|||
][$available]['namespace'],
|
||||
);
|
||||
}
|
||||
|
||||
$val =
|
||||
$this->collection->getDefaultNamespace() .
|
||||
$this->directory .
|
||||
|
|
|
@ -24,7 +24,7 @@ class SimpleRSSElement extends SimpleXMLElement
|
|||
*
|
||||
* @return static The addChild method returns a SimpleXMLElement object representing the child added to the XML node.
|
||||
*/
|
||||
public function addChildWithCDATA(string $name, string $value = '', ?string $namespace = null)
|
||||
public function addChildWithCDATA(string $name, string $value = '', ?string $namespace = null): static
|
||||
{
|
||||
$newChild = parent::addChild($name, '', $namespace);
|
||||
|
||||
|
@ -52,7 +52,7 @@ class SimpleRSSElement extends SimpleXMLElement
|
|||
*
|
||||
* @return static The addChild method returns a SimpleXMLElement object representing the child added to the XML node.
|
||||
*/
|
||||
public function addChild($name, $value = null, $namespace = null, $escape = true)
|
||||
public function addChild($name, $value = null, $namespace = null, $escape = true): static
|
||||
{
|
||||
$newChild = parent::addChild($name, '', $namespace);
|
||||
|
||||
|
@ -64,9 +64,11 @@ class SimpleRSSElement extends SimpleXMLElement
|
|||
if (! $no instanceof DOMDocument) {
|
||||
return $newChild;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return $newChild;
|
||||
}
|
||||
|
||||
/** @noRector RecastingRemovalRector */
|
||||
$node->appendChild($no->createTextNode((string) $value));
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ class TranscriptParser
|
|||
|
||||
$lines = explode(PHP_EOL, $this->transcriptContent);
|
||||
foreach ($lines as $line) {
|
||||
// @phpstan-ignore-next-line
|
||||
switch ($state) {
|
||||
case SRT_STATE_SUBNUMBER:
|
||||
$subNum = trim($line);
|
||||
|
@ -82,8 +81,10 @@ class TranscriptParser
|
|||
if ($subText !== '') {
|
||||
$subText .= PHP_EOL . $line;
|
||||
}
|
||||
|
||||
$subText .= $line;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
|
|
@ -85,7 +85,6 @@ class View extends CodeIgniterView
|
|||
$renderVars = $this->renderVars;
|
||||
|
||||
$output = (function (): string {
|
||||
/** @phpstan-ignore-next-line */
|
||||
extract($this->tempData);
|
||||
ob_start();
|
||||
include $this->renderVars['file'];
|
||||
|
|
|
@ -228,10 +228,10 @@ class ComponentRenderer
|
|||
if (! file_exists($filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$className = service('locator')
|
||||
->getClassname($filePath);
|
||||
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (! class_exists($className)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -247,7 +247,6 @@ class ComponentRenderer
|
|||
private function renderView(string $view, array $data): string
|
||||
{
|
||||
return (function (string $view, $data): string {
|
||||
/** @phpstan-ignore-next-line */
|
||||
extract($data);
|
||||
ob_start();
|
||||
eval('?>' . file_get_contents($view));
|
||||
|
|
|
@ -52,6 +52,7 @@ class Vite
|
|||
die("Could not load css manifest: <strong>{$manifestCSSPath}</strong> file not found!");
|
||||
}
|
||||
}
|
||||
|
||||
$this->manifestCSSData = $cachedManifestCSS;
|
||||
}
|
||||
|
||||
|
@ -80,6 +81,7 @@ class Vite
|
|||
die("Could not load manifest: <strong>{$manifestPath}</strong> file not found!");
|
||||
}
|
||||
}
|
||||
|
||||
$this->manifestData = $cachedManifest;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ class CategoryModel extends Model
|
|||
if ($category->parent !== null) {
|
||||
$result[$category->id] = lang('Podcast.category_options.' . $category->parent->code) . ' › ';
|
||||
}
|
||||
|
||||
$result[$category->id] .= lang('Podcast.category_options.' . $category->code);
|
||||
return $result;
|
||||
},
|
||||
|
|
|
@ -73,7 +73,6 @@ class ClipModel extends Model
|
|||
ConnectionInterface &$db = null,
|
||||
ValidationInterface $validation = null
|
||||
) {
|
||||
// @phpstan-ignore-next-line
|
||||
switch ($type) {
|
||||
case 'audio':
|
||||
$this->returnType = Soundbite::class;
|
||||
|
@ -226,6 +225,7 @@ class ClipModel extends Model
|
|||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,12 @@ class EpisodeCommentModel extends UuidModel
|
|||
if ($registerActivity) {
|
||||
// set post id and uri to construct NoteObject
|
||||
$comment->id = $newCommentId;
|
||||
$comment->uri = url_to('episode-comment', $comment->actor->username, $comment->episode->slug, $comment->id);
|
||||
$comment->uri = url_to(
|
||||
'episode-comment',
|
||||
esc($comment->actor->username),
|
||||
$comment->episode->slug,
|
||||
$comment->id
|
||||
);
|
||||
|
||||
$createActivity = new CreateActivity();
|
||||
$createActivity
|
||||
|
@ -112,7 +117,7 @@ class EpisodeCommentModel extends UuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$createActivity->set('id', url_to('activity', $comment->actor->username, $activityId));
|
||||
$createActivity->set('id', url_to('activity', esc($comment->actor->username), $activityId));
|
||||
|
||||
model(ActivityModel::class, false)
|
||||
->update($activityId, [
|
||||
|
@ -200,6 +205,7 @@ class EpisodeCommentModel extends UuidModel
|
|||
$this->uuidUseBytes = false;
|
||||
return $this->updateBatch($commentsLikesCount, 'id');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -234,7 +240,7 @@ class EpisodeCommentModel extends UuidModel
|
|||
$episode = model(EpisodeModel::class, false)
|
||||
->find((int) $data['data']['episode_id']);
|
||||
|
||||
$data['data']['uri'] = url_to('episode-comment', $actor->username, $episode->slug, $uuid4->toString());
|
||||
$data['data']['uri'] = url_to('episode-comment', esc($actor->username), $episode->slug, $uuid4->toString());
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
|
|
@ -115,8 +115,8 @@ class EpisodeModel extends Model
|
|||
'number' => 'is_natural_no_zero|permit_empty',
|
||||
'season_number' => 'is_natural_no_zero|permit_empty',
|
||||
'type' => 'required',
|
||||
'transcript_remote_url' => 'valid_url|permit_empty',
|
||||
'chapters_remote_url' => 'valid_url|permit_empty',
|
||||
'transcript_remote_url' => 'valid_url_strict|permit_empty',
|
||||
'chapters_remote_url' => 'valid_url_strict|permit_empty',
|
||||
'published_at' => 'valid_date|permit_empty',
|
||||
'created_by' => 'required',
|
||||
'updated_by' => 'required',
|
||||
|
@ -215,6 +215,7 @@ class EpisodeModel extends Model
|
|||
$where['YEAR(published_at)'] = $year;
|
||||
$where['season_number'] = null;
|
||||
}
|
||||
|
||||
if ($season) {
|
||||
$where['season_number'] = $season;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ class LikeModel extends UuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$likeActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$likeActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
model(ActivityModel::class)
|
||||
->update($activityId, [
|
||||
|
@ -115,7 +115,7 @@ class LikeModel extends UuidModel
|
|||
|
||||
$likeActivity = new LikeActivity();
|
||||
$likeActivity
|
||||
->set('id', url_to('activity', $actor->username, $activity->id))
|
||||
->set('id', url_to('activity', esc($actor->username), $activity->id))
|
||||
->set('actor', $actor->uri)
|
||||
->set('object', $comment->uri);
|
||||
|
||||
|
@ -134,7 +134,7 @@ class LikeModel extends UuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$undoActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$undoActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
model(ActivityModel::class)
|
||||
->update($activityId, [
|
||||
|
|
|
@ -16,6 +16,7 @@ use App\Entities\Media\Document;
|
|||
use App\Entities\Media\Image;
|
||||
use App\Entities\Media\Transcript;
|
||||
use App\Entities\Media\Video;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
use CodeIgniter\Model;
|
||||
use CodeIgniter\Validation\ValidationInterface;
|
||||
|
@ -88,7 +89,6 @@ class MediaModel extends Model
|
|||
ConnectionInterface &$db = null,
|
||||
ValidationInterface $validation = null
|
||||
) {
|
||||
// @phpstan-ignore-next-line
|
||||
switch ($fileType) {
|
||||
case 'audio':
|
||||
$this->returnType = Audio::class;
|
||||
|
@ -113,7 +113,7 @@ class MediaModel extends Model
|
|||
parent::__construct($db, $validation);
|
||||
}
|
||||
|
||||
public function getMediaById(int $mediaId): Document | Audio | Video | Image | Transcript | Chapters
|
||||
public function getMediaById(int $mediaId): mixed
|
||||
{
|
||||
$cacheName = "media#{$mediaId}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
|
@ -172,7 +172,7 @@ class MediaModel extends Model
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function deleteMedia(object $media): bool
|
||||
public function deleteMedia(object $media): bool|BaseResult
|
||||
{
|
||||
$media->deleteFile();
|
||||
|
||||
|
|
|
@ -389,10 +389,12 @@ class PersonModel extends Model
|
|||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->db->table('episodes_persons')
|
||||
->ignore(true)
|
||||
->insertBatch($data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ class PlatformModel extends Model
|
|||
cache()
|
||||
->save('platforms', $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -72,6 +73,7 @@ class PlatformModel extends Model
|
|||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ class PodcastModel extends Model
|
|||
'language_code' => 'required',
|
||||
'category_id' => 'required',
|
||||
'owner_email' => 'required|valid_email',
|
||||
'new_feed_url' => 'valid_url|permit_empty',
|
||||
'new_feed_url' => 'valid_url_strict|permit_empty',
|
||||
'type' => 'required',
|
||||
'created_by' => 'required',
|
||||
'updated_by' => 'required',
|
||||
|
@ -403,6 +403,7 @@ class PodcastModel extends Model
|
|||
$secondsToNextUnpublishedEpisode ? $secondsToNextUnpublishedEpisode : DECADE
|
||||
);
|
||||
}
|
||||
|
||||
return $defaultQuery;
|
||||
}
|
||||
|
||||
|
@ -504,6 +505,7 @@ class PodcastModel extends Model
|
|||
(new ActorModel())->update($podcast->actor_id, $podcastActor);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ class DropdownMenu extends Component
|
|||
{
|
||||
public string $id = '';
|
||||
|
||||
public string $labelledby;
|
||||
|
||||
public string $placement = 'bottom-end';
|
||||
|
||||
public string $offsetX = '0';
|
||||
|
|
|
@ -18,7 +18,10 @@ class FormComponent extends Component
|
|||
|
||||
protected bool $readonly = false;
|
||||
|
||||
public function __construct($attributes)
|
||||
/**
|
||||
* @param array<string, string> $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use ViewComponents\Component;
|
|||
|
||||
class ReadMore extends Component
|
||||
{
|
||||
public string $id;
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$readMoreLabel = lang('Common.read_more');
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
if (session()->has('message')): ?>
|
||||
<div class="px-4 py-2 mb-4 font-semibold text-green-900 bg-green-200 border border-green-700">
|
||||
<?= session('message') ?>
|
||||
</div>
|
||||
<Alert variant="success" class="mb-4"><?= esc(session('message')) ?></Alert>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (session()->has('error')): ?>
|
||||
<div class="px-4 py-2 mb-4 font-semibold text-red-900 bg-red-200 border border-red-700">
|
||||
<?= session('error') ?>
|
||||
</div>
|
||||
<Alert variant="danger" class="mb-4"><?= esc(session('error')) ?></Alert>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (session()->has('errors')): ?>
|
||||
<ul class="px-4 py-2 mb-4 font-semibold text-red-900 bg-red-200 border border-red-700">
|
||||
<?php foreach (session('errors') as $error): ?>
|
||||
<li><?= $error ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif;
|
||||
?>
|
||||
<Alert variant="danger" class="mb-4">
|
||||
<ul>
|
||||
<?php foreach (session('errors') as $error): ?>
|
||||
<li><?= esc($error) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</Alert>
|
||||
<?php endif; ?>
|
||||
|
|
|
@ -6,12 +6,13 @@ use CodeIgniter\CLI\CLI;
|
|||
|
||||
// The main Exception
|
||||
CLI::newLine();
|
||||
CLI::write('[' . $exception::class . ']', 'light_gray', 'red');
|
||||
CLI::write('[' . get_class($exception) . ']', 'light_gray', 'red');
|
||||
CLI::newLine();
|
||||
CLI::write($message);
|
||||
CLI::newLine();
|
||||
CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green', ), );
|
||||
CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green'));
|
||||
CLI::newLine();
|
||||
|
||||
// The backtrace
|
||||
if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
|
||||
$backtraces = $exception->getTrace();
|
||||
|
@ -21,41 +22,42 @@ if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
|
|||
}
|
||||
|
||||
foreach ($backtraces as $i => $error) {
|
||||
$padFile = ' ';
|
||||
$c = str_pad($i + 1, 3, ' ', STR_PAD_LEFT);
|
||||
$padFile = ' '; // 4 spaces
|
||||
$padClass = ' '; // 7 spaces
|
||||
$c = str_pad((string) ($i + 1), 3, ' ', STR_PAD_LEFT);
|
||||
|
||||
if (isset($error['file'])) {
|
||||
$filepath = clean_path($error['file']) . ':' . $error['line'];
|
||||
|
||||
CLI::write($c . $padFile . CLI::color($filepath, 'yellow'));
|
||||
} else {
|
||||
CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow'), );
|
||||
CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow'));
|
||||
}
|
||||
|
||||
$function = '';
|
||||
|
||||
if (isset($error['class'])) {
|
||||
$type =
|
||||
$error['type'] === '->'
|
||||
? '()' . $error['type']
|
||||
: $error['type'];
|
||||
$function .=
|
||||
$padClass . $error['class'] . $type . $error['function'];
|
||||
$type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type'];
|
||||
$function .= $padClass . $error['class'] . $type . $error['function'];
|
||||
} elseif (! isset($error['class']) && isset($error['function'])) {
|
||||
$function .= $padClass . $error['function'];
|
||||
}
|
||||
|
||||
$args = implode(
|
||||
', ',
|
||||
array_map(function ($value) {
|
||||
return match (true) {
|
||||
is_object($value) => 'Object(' . $value::class . ')',
|
||||
is_array($value) => $value !== [] ? '[...]' : '[]',
|
||||
$value === null => 'null',
|
||||
default => var_export($value, true),
|
||||
};
|
||||
}, array_values($error['args'] ?? [])),
|
||||
);
|
||||
$args = implode(', ', array_map(static function ($value) {
|
||||
switch (true) {
|
||||
case is_object($value):
|
||||
return 'Object(' . get_class($value) . ')';
|
||||
|
||||
case is_array($value):
|
||||
return count($value) ? '[...]' : '[]';
|
||||
|
||||
case $value === null:
|
||||
return 'null'; // return the lowercased version
|
||||
|
||||
default:
|
||||
return var_export($value, true);
|
||||
}
|
||||
}, array_values($error['args'] ?? [])));
|
||||
|
||||
$function .= '(' . $args . ')';
|
||||
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use CodeIgniter\CodeIgniter;
|
||||
use Config\Services;
|
||||
|
||||
$errorId = uniqid('error', true); ?>
|
||||
$error_id = uniqid('error', true); ?>
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="noindex">
|
||||
|
||||
<title><?= esc($title) ?></title>
|
||||
<style type="text/css">
|
||||
<?= preg_replace('~[\r\n\t ]+~', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
<?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="init()">
|
||||
|
||||
<!-- Header -->
|
||||
|
@ -29,7 +24,8 @@ $errorId = uniqid('error', true); ?>
|
|||
<h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
|
||||
<p>
|
||||
<?= nl2br(esc($exception->getMessage())) ?>
|
||||
<a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('~\'.*\'|".*"~Us', '', $exception->getMessage())) ?>" rel="noreferrer" target="_blank">search →</a>
|
||||
<a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
|
||||
rel="noreferrer" target="_blank">search →</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,7 +34,7 @@ $errorId = uniqid('error', true); ?>
|
|||
<div class="container">
|
||||
<p><b><?= esc(static::cleanPath($file, $line)) ?></b> at line <b><?= esc($line) ?></b></p>
|
||||
|
||||
<?php if (is_file($file)): ?>
|
||||
<?php if (is_file($file)) : ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($file, $line, 15); ?>
|
||||
</div>
|
||||
|
@ -62,79 +58,79 @@ $errorId = uniqid('error', true); ?>
|
|||
<div class="content" id="backtrace">
|
||||
|
||||
<ol class="trace">
|
||||
<?php foreach ($trace as $index => $row): ?>
|
||||
<?php foreach ($trace as $index => $row) : ?>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
<!-- Trace info -->
|
||||
<?php if (isset($row['file']) && is_file($row['file'])): ?>
|
||||
<?php
|
||||
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
|
||||
echo esc($row['function'] . ' ' . static::cleanPath($row['file']));
|
||||
} else {
|
||||
echo esc(static::cleanPath($row['file']) . ' : ' . $row['line']);
|
||||
}
|
||||
?>
|
||||
<?php else: ?>
|
||||
{PHP internal code}
|
||||
<li>
|
||||
<p>
|
||||
<!-- Trace info -->
|
||||
<?php if (isset($row['file']) && is_file($row['file'])) :?>
|
||||
<?php
|
||||
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
|
||||
echo esc($row['function'] . ' ' . static::cleanPath($row['file']));
|
||||
} else {
|
||||
echo esc(static::cleanPath($row['file']) . ' : ' . $row['line']);
|
||||
}
|
||||
?>
|
||||
<?php else : ?>
|
||||
{PHP internal code}
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Class/Method -->
|
||||
<?php if (isset($row['class'])) : ?>
|
||||
— <?= esc($row['class'] . $row['type'] . $row['function']) ?>
|
||||
<?php if (! empty($row['args'])) : ?>
|
||||
<?php $args_id = $error_id . 'args' . $index ?>
|
||||
( <a href="#" onclick="return toggle('<?= esc($args_id, 'attr') ?>');">arguments</a> )
|
||||
<div class="args" id="<?= esc($args_id, 'attr') ?>">
|
||||
<table cellspacing="0">
|
||||
|
||||
<?php
|
||||
$params = null;
|
||||
// Reflection by name is not available for closure function
|
||||
if (substr($row['function'], -1) !== '}') {
|
||||
$mirror = isset($row['class']) ? new \ReflectionMethod($row['class'], $row['function']) : new \ReflectionFunction($row['function']);
|
||||
$params = $mirror->getParameters();
|
||||
}
|
||||
|
||||
foreach ($row['args'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
|
||||
<td><pre><?= esc(print_r($value, true)) ?></pre></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
()
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Class/Method -->
|
||||
<?php if (isset($row['class'])) : ?>
|
||||
— <?= esc($row['class'] . $row['type'] . $row['function']) ?>
|
||||
<?php if (! empty($row['args'])) : ?>
|
||||
<?php $args_id = $errorId . 'args' . $index ?>
|
||||
( <a href="#" onclick="return toggle('<?= esc($args_id, 'attr') ?>');">arguments</a> )
|
||||
<div class="args" id="<?= esc($args_id, 'attr') ?>">
|
||||
<table cellspacing="0">
|
||||
<?php if (! isset($row['class']) && isset($row['function'])) : ?>
|
||||
— <?= esc($row['function']) ?>()
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
$params = null;
|
||||
// Reflection by name is not available for closure function
|
||||
if (! str_ends_with($row['function'], '}')) {
|
||||
$mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
|
||||
$params = $mirror->getParameters();
|
||||
}
|
||||
foreach ($row['args'] as $key => $value): ?>
|
||||
<tr>
|
||||
<td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
|
||||
<td>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</table>
|
||||
<!-- Source? -->
|
||||
<?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($row['file'], $row['line']) ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
()
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
|
||||
<?php if (! isset($row['class']) && isset($row['function'])): ?>
|
||||
— <?= esc($row['function']) ?>()
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<!-- Source? -->
|
||||
<?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])): ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($row['file'], $row['line']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Server -->
|
||||
<div class="content" id="server">
|
||||
<?php foreach (['_SERVER', '_SESSION'] as $var): ?>
|
||||
<?php if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
<?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
|
||||
<?php
|
||||
if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
|
||||
<h3>$<?= esc($var) ?></h3>
|
||||
|
||||
|
@ -146,26 +142,26 @@ $errorId = uniqid('error', true); ?>
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value): ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)): ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<!-- Constants -->
|
||||
<?php $constants = get_defined_constants(true); ?>
|
||||
<?php if (! empty($constants['user'])): ?>
|
||||
<?php if (! empty($constants['user'])) : ?>
|
||||
<h3>Constants</h3>
|
||||
|
||||
<table>
|
||||
|
@ -176,18 +172,18 @@ $errorId = uniqid('error', true); ?>
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($constants['user'] as $key => $value): ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)): ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($constants['user'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
@ -195,7 +191,7 @@ $errorId = uniqid('error', true); ?>
|
|||
|
||||
<!-- Request -->
|
||||
<div class="content" id="request">
|
||||
<?php $request = Services::request(); ?>
|
||||
<?php $request = \Config\Services::request(); ?>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
|
@ -233,10 +229,11 @@ $errorId = uniqid('error', true); ?>
|
|||
|
||||
|
||||
<?php $empty = true; ?>
|
||||
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var): ?>
|
||||
<?php if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
|
||||
<?php
|
||||
if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
|
||||
<?php $empty = false; ?>
|
||||
|
||||
|
@ -250,24 +247,24 @@ $errorId = uniqid('error', true); ?>
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value): ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)): ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php if ($empty): ?>
|
||||
<?php if ($empty) : ?>
|
||||
|
||||
<div class="alert">
|
||||
No $_GET, $_POST, or $_COOKIE Information to show.
|
||||
|
@ -276,7 +273,7 @@ $errorId = uniqid('error', true); ?>
|
|||
<?php endif; ?>
|
||||
|
||||
<?php $headers = $request->getHeaders(); ?>
|
||||
<?php if (! empty($headers)): ?>
|
||||
<?php if (! empty($headers)) : ?>
|
||||
|
||||
<h3>Headers</h3>
|
||||
|
||||
|
@ -288,20 +285,22 @@ $errorId = uniqid('error', true); ?>
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($headers as $value): ?>
|
||||
<?php if (empty($value)) {
|
||||
continue;
|
||||
} ?>
|
||||
<?php if (! is_array($value)) {
|
||||
$value = [$value];
|
||||
} ?>
|
||||
<?php foreach ($value as $h) : ?>
|
||||
<tr>
|
||||
<td><?= esc($h->getName(), 'html') ?></td>
|
||||
<td><?= esc($h->getValueLine(), 'html') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($headers as $value) : ?>
|
||||
<?php
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
$value = [$value];
|
||||
} ?>
|
||||
<?php foreach ($value as $h) : ?>
|
||||
<tr>
|
||||
<td><?= esc($h->getName(), 'html') ?></td>
|
||||
<td><?= esc($h->getValueLine(), 'html') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -310,9 +309,9 @@ $errorId = uniqid('error', true); ?>
|
|||
|
||||
<!-- Response -->
|
||||
<?php
|
||||
$response = Services::response();
|
||||
$response->setStatusCode(http_response_code());
|
||||
?>
|
||||
$response = \Config\Services::response();
|
||||
$response->setStatusCode(http_response_code());
|
||||
?>
|
||||
<div class="content" id="response">
|
||||
<table>
|
||||
<tr>
|
||||
|
@ -322,8 +321,8 @@ $errorId = uniqid('error', true); ?>
|
|||
</table>
|
||||
|
||||
<?php $headers = $response->getHeaders(); ?>
|
||||
<?php if ($headers !== []): ?>
|
||||
<?php natsort($headers); ?>
|
||||
<?php if (! empty($headers)) : ?>
|
||||
<?php natsort($headers) ?>
|
||||
|
||||
<h3>Headers</h3>
|
||||
|
||||
|
@ -335,12 +334,12 @@ $errorId = uniqid('error', true); ?>
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach (array_keys($headers) as $name): ?>
|
||||
<tr>
|
||||
<td><?= esc($name, 'html') ?></td>
|
||||
<td><?= esc($response->getHeaderLine($name), 'html') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($headers as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($name, 'html') ?></td>
|
||||
<td><?= esc($response->getHeaderLine($name), 'html') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -352,9 +351,9 @@ $errorId = uniqid('error', true); ?>
|
|||
<?php $files = get_included_files(); ?>
|
||||
|
||||
<ol>
|
||||
<?php foreach ($files as $file): ?>
|
||||
<li><?= esc(static::cleanPath($file)) ?></li>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($files as $file) :?>
|
||||
<li><?= esc(static::cleanPath($file)) ?></li>
|
||||
<?php endforeach ?>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
|
@ -389,13 +388,12 @@ $errorId = uniqid('error', true); ?>
|
|||
|
||||
<p>
|
||||
Displayed at <?= esc(date('H:i:sa')) ?> —
|
||||
PHP: <?= esc(PHP_VERSION) ?> —
|
||||
CodeIgniter: <?= esc(CodeIgniter::CI_VERSION) ?>
|
||||
PHP: <?= esc(PHP_VERSION) ?> —
|
||||
CodeIgniter: <?= esc(\CodeIgniter\CodeIgniter::CI_VERSION) ?>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
"license": "AGPL-3.0-or-later",
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"codeigniter4/framework": "^4",
|
||||
"james-heinrich/getid3": "^2.0.x-dev",
|
||||
"whichbrowser/parser": "^v2.1.1",
|
||||
"geoip2/geoip2": "^v2.11.0",
|
||||
"geoip2/geoip2": "^v2.12.2",
|
||||
"myth/auth": "dev-develop",
|
||||
"codeigniter4/codeigniter4": "dev-develop",
|
||||
"league/commonmark": "^2.2",
|
||||
"vlucas/phpdotenv": "^v5.3.0",
|
||||
"league/html-to-markdown": "^v5.0.1",
|
||||
|
@ -21,21 +21,18 @@
|
|||
"phpseclib/phpseclib": "~2.0.30",
|
||||
"michalsn/codeigniter4-uuid": "dev-develop",
|
||||
"essence/essence": "^3.5.4",
|
||||
"codeigniter4/settings": "dev-develop",
|
||||
"codeigniter4/settings": "^v1.0",
|
||||
"chrisjean/php-ico": "^1.0",
|
||||
"melbahja/seo": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "^v1.6.8",
|
||||
"phpunit/phpunit": "^9.5.4",
|
||||
"rector/rector": "^0.11.5",
|
||||
"captainhook/captainhook": "^5.10.0",
|
||||
"phpstan/phpstan": "^0.12.85",
|
||||
"phpstan/extension-installer": "^1.1.0",
|
||||
"rector/rector-phpstan-rules": "^0.2.9",
|
||||
"symplify/phpstan-extensions": "^v9.3.12",
|
||||
"symplify/easy-coding-standard": "^v9.3.12",
|
||||
"symplify/coding-standard": "^v9.3.12"
|
||||
"mikey179/vfsstream": "v1.6.10",
|
||||
"phpunit/phpunit": "^9.5.16",
|
||||
"captainhook/captainhook": "^5.10.7",
|
||||
"symplify/easy-coding-standard": "^10.1",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"rector/rector": "^0.12.16",
|
||||
"symplify/coding-standard": "^10.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@ -80,14 +77,7 @@
|
|||
"source": "https://code.castopod.org/adaures/castopod.git",
|
||||
"discord": "https://castopod.org/discord"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/codeigniter4/codeigniter4"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"phpstan/extension-installer": true
|
||||
|
|
File diff suppressed because it is too large
Load Diff
7
ecs.php
7
ecs.php
|
@ -6,6 +6,7 @@ use Symplify\CodingStandard\Fixer\Naming\StandardizeHereNowDocKeywordFixer;
|
|||
use Symplify\EasyCodingStandard\ValueObject\Option;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
|
||||
use PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\AssignmentInConditionSniff;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
|
@ -19,7 +20,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
__DIR__ . '/public',
|
||||
]);
|
||||
|
||||
$parameters->set(Option::SKIP, [
|
||||
$parameters->set(Option::SKIP, [
|
||||
// skip specific generated files
|
||||
__DIR__ . '/modules/Admin/Language/*/PersonsTaxonomy.php',
|
||||
|
||||
|
@ -39,7 +40,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
__DIR__ . '/app/Views/*',
|
||||
__DIR__ . '/modules/**/Views/*',
|
||||
__DIR__ . '/themes/*',
|
||||
]
|
||||
],
|
||||
|
||||
AssignmentInConditionSniff::class,
|
||||
]);
|
||||
|
||||
$containerConfigurator->import(SetList::PSR_12);
|
||||
|
|
|
@ -63,6 +63,7 @@ class ContributorController extends BaseController
|
|||
public function view(): string
|
||||
{
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'contributor' => (new UserModel())->getPodcastContributor($this->user->id, $this->podcast->id),
|
||||
];
|
||||
|
||||
|
|
|
@ -294,6 +294,7 @@ class EpisodeController extends BaseController
|
|||
) {
|
||||
(new MediaModel())->deleteMedia($this->episode->transcript);
|
||||
}
|
||||
|
||||
$this->episode->transcript_remote_url = $transcriptRemoteUrl === '' ? null : $transcriptRemoteUrl;
|
||||
}
|
||||
|
||||
|
@ -311,6 +312,7 @@ class EpisodeController extends BaseController
|
|||
) {
|
||||
(new MediaModel())->deleteMedia($this->episode->chapters);
|
||||
}
|
||||
|
||||
$this->episode->chapters_remote_url = $chaptersRemoteUrl === '' ? null : $chaptersRemoteUrl;
|
||||
}
|
||||
|
||||
|
|
|
@ -384,6 +384,7 @@ class PodcastController extends BaseController
|
|||
->withInput()
|
||||
->with('errors', $mediaModel->errors());
|
||||
}
|
||||
|
||||
(new PodcastModel())->clearCache([
|
||||
'id' => $this->podcast->id,
|
||||
]);
|
||||
|
|
|
@ -77,6 +77,7 @@ class PodcastImportController extends BaseController
|
|||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
try {
|
||||
ini_set('user_agent', 'Castopod/' . CP_VERSION);
|
||||
$feed = simplexml_load_file($this->request->getPost('imported_feed_url'));
|
||||
|
@ -93,6 +94,7 @@ class PodcastImportController extends BaseController
|
|||
' ⎋</a>',
|
||||
]);
|
||||
}
|
||||
|
||||
$nsItunes = $feed->channel[0]->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
||||
$nsPodcast = $feed->channel[0]->children(
|
||||
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md',
|
||||
|
@ -128,6 +130,7 @@ class PodcastImportController extends BaseController
|
|||
$nsPodcast->location->attributes()['osm'] === null ? null : (string) $nsPodcast->location->attributes()['osm'],
|
||||
);
|
||||
}
|
||||
|
||||
$guid = null;
|
||||
if (property_exists($nsPodcast, 'guid') && $nsPodcast->guid !== null) {
|
||||
$guid = (string) $nsPodcast->guid;
|
||||
|
@ -313,8 +316,10 @@ class PodcastImportController extends BaseController
|
|||
while (in_array($slug . '-' . $slugNumber, $slugs, true)) {
|
||||
++$slugNumber;
|
||||
}
|
||||
|
||||
$slug = $slug . '-' . $slugNumber;
|
||||
}
|
||||
|
||||
$slugs[] = $slug;
|
||||
$itemDescriptionHtml = match ($this->request->getPost('description_field')) {
|
||||
'content' => (string) $nsContent->encoded,
|
||||
|
|
|
@ -74,9 +74,11 @@ class PodcastPlatformController extends BaseController
|
|||
if ($podcastPlatformUrl === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $validation->check($podcastPlatformUrl, 'validate_url')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$podcastsPlatformsData[] = [
|
||||
'platform_slug' => $platformSlug,
|
||||
'podcast_id' => $this->podcast->id,
|
||||
|
|
|
@ -81,6 +81,7 @@ class SchedulerController extends Controller
|
|||
'job_ended_at' => Time::now(),
|
||||
]);
|
||||
}
|
||||
|
||||
$clipModel->clearVideoClipCache($scheduledClip->id);
|
||||
} catch (Exception $exception) {
|
||||
(new ClipModel())->update($scheduledClip->id, [
|
||||
|
|
|
@ -179,6 +179,7 @@ class SettingsController extends BaseController
|
|||
(new EpisodeCommentModel())->resetLikesCount();
|
||||
(new EpisodeCommentModel())->resetRepliesCount();
|
||||
}
|
||||
|
||||
helper('media');
|
||||
|
||||
if ($this->request->getPost('rewrite_media') === 'yes') {
|
||||
|
|
|
@ -144,7 +144,7 @@ class SoundbiteController extends BaseController
|
|||
{
|
||||
$soundbite = (new ClipModel())->getSoundbiteById((int) $soundbiteId);
|
||||
|
||||
if ($soundbite === null) {
|
||||
if (! $soundbite instanceof Soundbite) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ class VideoClipsController extends BaseController
|
|||
{
|
||||
$videoClip = (new ClipModel())->getVideoClipById((int) $videoClipId);
|
||||
|
||||
if ($videoClip === null) {
|
||||
if (! $videoClip instanceof VideoClip) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ class VideoClipsController extends BaseController
|
|||
{
|
||||
$videoClip = (new ClipModel())->getVideoClipById((int) $videoClipId);
|
||||
|
||||
if ($videoClip === null) {
|
||||
if (! $videoClip instanceof VideoClip) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
|
||||
return [
|
||||
'messages' => [
|
||||
'actorNotFound' => 'The account could not be found!',
|
||||
'blockActorSuccess' => '{actor} has been blocked!',
|
||||
'unblockActorSuccess' => 'Actor has been unblocked!',
|
||||
'blockDomainSuccess' => '{domain} has been blocked!',
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
|
||||
return [
|
||||
'messages' => [
|
||||
'actorNotFound' => 'L’utilisateur n’a pu être trouvé !',
|
||||
'blockActorSuccess' => '{actor} a été bloqué !',
|
||||
'unblockActorSuccess' => 'L’utilisateur a été débloqué !',
|
||||
'blockDomainSuccess' => '{domain} a été bloqué !',
|
||||
|
|
|
@ -9,7 +9,6 @@ declare(strict_types=1);
|
|||
*/
|
||||
|
||||
use AdAures\Ipcat\IpDb;
|
||||
use CodeIgniter\Router\Exceptions\RouterException;
|
||||
use Config\Services;
|
||||
use GeoIp2\Database\Reader;
|
||||
use Opawg\UserAgentsPhp\UserAgents;
|
||||
|
@ -38,8 +37,6 @@ if (! function_exists('base64_url_decode')) {
|
|||
if (! function_exists('generate_episode_analytics_url')) {
|
||||
/**
|
||||
* Builds the episode analytics url that redirects to the audio file url after analytics hit.
|
||||
*
|
||||
* @throws RouterException
|
||||
*/
|
||||
function generate_episode_analytics_url(
|
||||
int $podcastId,
|
||||
|
@ -124,6 +121,7 @@ if (! function_exists('set_user_session_location')) {
|
|||
// If things go wrong the show must go on and the user must be able to download the file
|
||||
} catch (Exception) {
|
||||
}
|
||||
|
||||
$session->set('location', $location);
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +145,7 @@ if (! function_exists('set_user_session_player')) {
|
|||
// If things go wrong the show must go on and the user must be able to download the file
|
||||
} catch (Exception) {
|
||||
}
|
||||
|
||||
if ($playerFound) {
|
||||
$session->set('player', $playerFound);
|
||||
} else {
|
||||
|
@ -188,9 +187,11 @@ if (! function_exists('set_user_session_browser')) {
|
|||
} catch (Exception) {
|
||||
$browserName = '- Could not get browser name -';
|
||||
}
|
||||
|
||||
if ($browserName === '') {
|
||||
$browserName = '- Could not get browser name -';
|
||||
}
|
||||
|
||||
$session->set('browser', $browserName);
|
||||
}
|
||||
}
|
||||
|
@ -273,6 +274,7 @@ if (! function_exists('podcast_hit')) {
|
|||
if ($session->get('denyListIp')) {
|
||||
$session->get('player')['bot'] = true;
|
||||
}
|
||||
|
||||
//We get the HTTP header field `Range`:
|
||||
$httpRange = isset($_SERVER['HTTP_RANGE'])
|
||||
? $_SERVER['HTTP_RANGE']
|
||||
|
@ -295,6 +297,7 @@ if (! function_exists('podcast_hit')) {
|
|||
// If it was never downloaded that means that zero byte were downloaded:
|
||||
$downloadedBytes = 0;
|
||||
}
|
||||
|
||||
// If the number of downloaded bytes was previously below the 1mn threshold we go on:
|
||||
// (Otherwise it means that this was already counted, therefore we don't do anything)
|
||||
if ($downloadedBytes < $bytesThreshold) {
|
||||
|
@ -314,6 +317,7 @@ if (! function_exists('podcast_hit')) {
|
|||
(array_key_exists(0, $parts) ? 0 : (int) $parts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// We save the number of downloaded bytes for this user and this episode:
|
||||
cache()
|
||||
->save($episodeHashId, $downloadedBytes, $rollingTTL);
|
||||
|
@ -339,6 +343,7 @@ if (! function_exists('podcast_hit')) {
|
|||
} else {
|
||||
$downloadsByUser = 1;
|
||||
}
|
||||
|
||||
// Listener count is calculated from 00h00 to 23h59:
|
||||
$midnightTTL = strtotime('tomorrow') - time();
|
||||
// We save the download count for this user until midnight:
|
||||
|
|
|
@ -89,6 +89,7 @@ class AnalyticsPodcastByCountryModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_country_yearly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_app_weekly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -90,6 +91,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_app_yearly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -119,6 +121,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_os_weekly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -147,6 +150,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_device_weekly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -175,6 +179,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_bots", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ class AnalyticsPodcastByRegionModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_region_{$locale}", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class AnalyticsPodcastByServiceModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_service_weekly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_day", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -80,6 +81,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_weekday", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -102,6 +104,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_bandwidth", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -125,6 +128,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_month", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -149,6 +153,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_unique_listeners_by_day", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -174,6 +179,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_unique_listeners_by_month", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -200,6 +206,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_listening_time_by_day", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -225,6 +232,7 @@ class AnalyticsPodcastModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_listening_time_by_month", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ class AnalyticsWebsiteByBrowserModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_browser", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ class AnalyticsWebsiteByEntryPageModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_entry_page", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_referer", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -84,6 +85,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_domain_weekly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
@ -110,6 +112,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_domain_yearly", $found, 600);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ class PermissionFilter implements FilterInterface
|
|||
->to($redirectURL)
|
||||
->with('error', lang('Auth.notEnoughPrivilege'));
|
||||
}
|
||||
|
||||
throw new PermissionException(lang('Auth.notEnoughPrivilege'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@ class ActorController extends Controller
|
|||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
}
|
||||
|
||||
// return not handled undo error (501 = not implemented)
|
||||
return $this->response->setStatusCode(501)
|
||||
->setJSON([]);
|
||||
|
@ -286,6 +287,7 @@ class ActorController extends Controller
|
|||
foreach ($paginatedActivity as $activity) {
|
||||
$orderedItems[] = $activity->payload;
|
||||
}
|
||||
|
||||
$collection = new OrderedCollectionPage($pager, $orderedItems);
|
||||
}
|
||||
|
||||
|
@ -322,6 +324,7 @@ class ActorController extends Controller
|
|||
foreach ($paginatedFollowers as $follower) {
|
||||
$orderedItems[] = $follower->uri;
|
||||
}
|
||||
|
||||
$followersCollection = new OrderedCollectionPage($pager, $orderedItems);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Modules\Fediverse\Controllers;
|
|||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Exception;
|
||||
|
||||
class BlockController extends Controller
|
||||
{
|
||||
|
@ -23,7 +24,7 @@ class BlockController extends Controller
|
|||
public function attemptBlockActor(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'handle' => 'required',
|
||||
'handle' => 'required|regex_match[/^@?([\w\.\-]+)@([\w\.\-]+)(:[\d]+)?$/]',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
|
@ -36,9 +37,9 @@ class BlockController extends Controller
|
|||
$handle = $this->request->getPost('handle');
|
||||
|
||||
if ($parts = split_handle($handle)) {
|
||||
if (
|
||||
($actor = get_or_create_actor($parts['username'], $parts['domain'])) === null
|
||||
) {
|
||||
try {
|
||||
$actor = get_or_create_actor($parts['username'], $parts['domain']);
|
||||
} catch (Exception) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
@ -78,7 +79,7 @@ class BlockController extends Controller
|
|||
public function attemptBlockDomain(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'domain' => 'required',
|
||||
'domain' => 'required|regex_match[/^[\w\-\.]+[\w]+(:[\d]+)?/]',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
|
|
|
@ -30,8 +30,7 @@ class NodeInfo2Controller extends Controller
|
|||
'version' => '1.0',
|
||||
'server' => [
|
||||
'baseUrl' => base_url(),
|
||||
'name' => service('settings')
|
||||
->get('App.siteName'),
|
||||
'name' => esc(service('settings') ->get('App.siteName')),
|
||||
'software' => 'Castopod',
|
||||
'version' => CP_VERSION,
|
||||
],
|
||||
|
|
|
@ -79,7 +79,7 @@ if (! function_exists('accept_follow')) {
|
|||
$acceptActivity->toJSON(),
|
||||
);
|
||||
|
||||
$acceptActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$acceptActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
$activityModel->update($activityId, [
|
||||
'payload' => $acceptActivity->toJSON(),
|
||||
|
@ -108,6 +108,7 @@ if (! function_exists('send_activity_to_actor')) {
|
|||
if ($actor->private_key !== null) {
|
||||
$acceptRequest->sign($actor->public_key_id, $actor->private_key);
|
||||
}
|
||||
|
||||
$acceptRequest->post();
|
||||
} catch (Exception $exception) {
|
||||
// log error
|
||||
|
@ -283,6 +284,7 @@ if (! function_exists('create_actor_from_uri')) {
|
|||
$newActor->cover_image_url = $actorPayload->image->url;
|
||||
$newActor->cover_image_mimetype = $actorPayload->image->mediaType;
|
||||
}
|
||||
|
||||
$newActor->inbox_url = $actorPayload->inbox;
|
||||
$newActor->outbox_url = property_exists($actorPayload, 'outbox') ? $actorPayload->outbox : null;
|
||||
$newActor->followers_url = property_exists($actorPayload, 'followers') ? $actorPayload->followers : null;
|
||||
|
@ -299,8 +301,6 @@ if (! function_exists('create_actor_from_uri')) {
|
|||
if (! function_exists('get_current_domain')) {
|
||||
/**
|
||||
* Returns instance's domain name
|
||||
*
|
||||
* @throws HTTPException
|
||||
*/
|
||||
function get_current_domain(): string
|
||||
{
|
||||
|
@ -324,8 +324,6 @@ if (! function_exists('get_message_from_object')) {
|
|||
* Gets the message from content, if no content key is present, checks for content in contentMap
|
||||
*
|
||||
* TODO: store multiple languages, convert markdown
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
function get_message_from_object(stdClass $object): string | false
|
||||
{
|
||||
|
@ -365,9 +363,10 @@ if (! function_exists('linkify')) {
|
|||
'http', 'https' => preg_replace_callback(
|
||||
'~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i',
|
||||
function (array $match) use ($protocol, &$links) {
|
||||
if ($match[1]) {
|
||||
if ($match[1] !== '' && $match[1] !== '0') {
|
||||
$protocol = $match[1];
|
||||
}
|
||||
|
||||
$link = $match[2] ?: $match[3];
|
||||
|
||||
helper('text');
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Modules\Fediverse\Models;
|
|||
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Model;
|
||||
use Modules\Fediverse\Entities\BlockedDomain;
|
||||
|
||||
class BlockedDomainModel extends BaseModel
|
||||
|
@ -64,6 +63,7 @@ class BlockedDomainModel extends BaseModel
|
|||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ class FavouriteModel extends BaseUuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$likeActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$likeActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
@ -122,7 +122,7 @@ class FavouriteModel extends BaseUuidModel
|
|||
|
||||
$likeActivity = new LikeActivity();
|
||||
$likeActivity
|
||||
->set('id', url_to('activity', $actor->username, $activity->id))
|
||||
->set('id', url_to('activity', esc($actor->username), $activity->id))
|
||||
->set('actor', $actor->uri)
|
||||
->set('object', $post->uri);
|
||||
|
||||
|
@ -141,7 +141,7 @@ class FavouriteModel extends BaseUuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$undoActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$undoActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
|
|
@ -10,12 +10,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace Modules\Fediverse\Models;
|
||||
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use CodeIgniter\Model;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Modules\Fediverse\Activities\FollowActivity;
|
||||
use Modules\Fediverse\Activities\UndoActivity;
|
||||
use Modules\Fediverse\Entities\Actor;
|
||||
|
@ -48,7 +45,6 @@ class FollowModel extends BaseModel
|
|||
/**
|
||||
* @param Actor $actor Actor that is following
|
||||
* @param Actor $targetActor Actor that is being followed
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function addFollower(Actor $actor, Actor $targetActor, bool $registerActivity = true): void
|
||||
{
|
||||
|
@ -83,7 +79,7 @@ class FollowModel extends BaseModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$followActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$followActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
@ -105,8 +101,6 @@ class FollowModel extends BaseModel
|
|||
/**
|
||||
* @param Actor $actor Actor that is unfollowing
|
||||
* @param Actor $targetActor Actor that is being unfollowed
|
||||
* @throws InvalidArgumentException
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function removeFollower(Actor $actor, Actor $targetActor, bool $registerActivity = true): void
|
||||
{
|
||||
|
@ -148,7 +142,7 @@ class FollowModel extends BaseModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$undoActivity->set('id', url_to('activity', $actor->username, $activityId));
|
||||
$undoActivity->set('id', url_to('activity', esc($actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
|
|
@ -286,7 +286,7 @@ class PostModel extends BaseUuidModel
|
|||
if ($registerActivity) {
|
||||
// set post id and uri to construct NoteObject
|
||||
$post->id = $newPostId;
|
||||
$post->uri = url_to('post', $post->actor->username, $newPostId);
|
||||
$post->uri = url_to('post', esc($post->actor->username), $newPostId);
|
||||
|
||||
$createActivity = new CreateActivity();
|
||||
$noteObjectClass = config('Fediverse')
|
||||
|
@ -306,7 +306,7 @@ class PostModel extends BaseUuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$createActivity->set('id', url_to('activity', $post->actor->username, $activityId));
|
||||
$createActivity->set('id', url_to('activity', esc($post->actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
@ -419,7 +419,7 @@ class PostModel extends BaseUuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$deleteActivity->set('id', url_to('activity', $post->actor->username, $activityId));
|
||||
$deleteActivity->set('id', url_to('activity', esc($post->actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
@ -506,7 +506,7 @@ class PostModel extends BaseUuidModel
|
|||
'queued',
|
||||
);
|
||||
|
||||
$announceActivity->set('id', url_to('activity', $post->actor->username, $activityId));
|
||||
$announceActivity->set('id', url_to('activity', esc($post->actor->username), $activityId));
|
||||
|
||||
model('ActivityModel', false)
|
||||
->update($activityId, [
|
||||
|
@ -721,7 +721,7 @@ class PostModel extends BaseUuidModel
|
|||
$actor = model('ActorModel', false)
|
||||
->getActorById((int) $data['data']['actor_id']);
|
||||
|
||||
$data['data']['uri'] = url_to('post', $actor->username, $uuid4->toString());
|
||||
$data['data']['uri'] = url_to('post', esc($actor->username), $uuid4->toString());
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
|
|
@ -44,7 +44,7 @@ class NoteObject extends ObjectType
|
|||
$this->inReplyTo = $post->reply_to_post->uri;
|
||||
}
|
||||
|
||||
$this->replies = url_to('post-replies', $post->actor->username, $post->id);
|
||||
$this->replies = url_to('post-replies', esc($post->actor->username), $post->id);
|
||||
|
||||
$this->cc = [$post->actor->followers_url];
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ class OrderedCollectionPage extends OrderedCollectionObject
|
|||
if ($isFirstPage) {
|
||||
$this->first = null;
|
||||
}
|
||||
|
||||
if ($isLastPage) {
|
||||
$this->last = null;
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@ class InstallController extends Controller
|
|||
$replaced = true;
|
||||
return $keyVal;
|
||||
}
|
||||
|
||||
return $line;
|
||||
},
|
||||
$envData
|
||||
|
|
File diff suppressed because it is too large
Load Diff
66
package.json
66
package.json
|
@ -27,71 +27,71 @@
|
|||
"prepare": "is-ci || husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amcharts/amcharts4": "^4.10.23",
|
||||
"@amcharts/amcharts4": "^4.10.24",
|
||||
"@amcharts/amcharts4-geodata": "^4.1.22",
|
||||
"@codemirror/basic-setup": "^0.19.1",
|
||||
"@codemirror/commands": "^0.19.7",
|
||||
"@codemirror/commands": "^0.19.8",
|
||||
"@codemirror/lang-xml": "^0.19.2",
|
||||
"@codemirror/state": "^0.19.6",
|
||||
"@codemirror/view": "^0.19.39",
|
||||
"@floating-ui/dom": "^0.1.10",
|
||||
"@codemirror/state": "^0.19.9",
|
||||
"@codemirror/view": "^0.19.45",
|
||||
"@floating-ui/dom": "^0.3.1",
|
||||
"@github/clipboard-copy-element": "^1.1.2",
|
||||
"@github/hotkey": "^1.6.1",
|
||||
"@github/hotkey": "^2.0.0",
|
||||
"@github/markdown-toolbar-element": "^2.1.0",
|
||||
"@github/time-elements": "^3.1.2",
|
||||
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
||||
"@vime/core": "^5.3.1",
|
||||
"choices.js": "^10.0.0",
|
||||
"choices.js": "^10.1.0",
|
||||
"flatpickr": "^4.6.9",
|
||||
"leaflet": "^1.7.1",
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"lit": "^2.1.1",
|
||||
"marked": "^4.0.10",
|
||||
"wavesurfer.js": "^5.2.0",
|
||||
"xml-formatter": "^2.6.0"
|
||||
"lit": "^2.2.0",
|
||||
"marked": "^4.0.12",
|
||||
"wavesurfer.js": "^6.0.2",
|
||||
"xml-formatter": "^2.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^16.0.2",
|
||||
"@commitlint/config-conventional": "^16.0.0",
|
||||
"@commitlint/cli": "^16.2.1",
|
||||
"@commitlint/config-conventional": "^16.2.1",
|
||||
"@semantic-release/changelog": "^6.0.1",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/gitlab": "^7.0.4",
|
||||
"@tailwindcss/forms": "^0.4.0-alpha.2",
|
||||
"@tailwindcss/line-clamp": "^0.3.1",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"@types/leaflet": "^1.7.8",
|
||||
"@types/marked": "^4.0.1",
|
||||
"@types/wavesurfer.js": "^5.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@types/leaflet": "^1.7.9",
|
||||
"@types/marked": "^4.0.2",
|
||||
"@types/wavesurfer.js": "^6.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^5.0.15",
|
||||
"cssnano": "^5.0.17",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^8.7.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-prettier": "^8.4.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"is-ci": "^3.0.1",
|
||||
"lint-staged": "^12.2.0",
|
||||
"lint-staged": "^12.3.4",
|
||||
"postcss-import": "^14.0.2",
|
||||
"postcss-nesting": "^10.1.2",
|
||||
"postcss-preset-env": "^7.2.3",
|
||||
"postcss-preset-env": "^7.4.1",
|
||||
"postcss-reporter": "^7.0.5",
|
||||
"prettier": "2.5.1",
|
||||
"prettier-plugin-organize-imports": "^2.3.4",
|
||||
"semantic-release": "^19.0.2",
|
||||
"stylelint": "^14.2.0",
|
||||
"stylelint-config-standard": "^24.0.0",
|
||||
"stylelint": "^14.5.3",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
"svgo": "^2.8.0",
|
||||
"tailwindcss": "^3.0.15",
|
||||
"typescript": "^4.5.4",
|
||||
"vite": "^2.7.13",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "^4.6.2",
|
||||
"vite": "^2.8.6",
|
||||
"vite-plugin-pwa": "^0.11.13",
|
||||
"workbox-build": "^6.4.2",
|
||||
"workbox-core": "^6.4.2",
|
||||
"workbox-routing": "^6.4.2",
|
||||
"workbox-strategies": "^6.4.2"
|
||||
"workbox-build": "^6.5.0",
|
||||
"workbox-core": "^6.5.0",
|
||||
"workbox-routing": "^6.5.0",
|
||||
"workbox-strategies": "^6.5.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,css,md,json}": "prettier --write",
|
||||
|
|
23
phpstan.neon
23
phpstan.neon
|
@ -5,35 +5,22 @@ parameters:
|
|||
- app
|
||||
- tests
|
||||
bootstrapFiles:
|
||||
- vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php
|
||||
- vendor/codeigniter4/framework/system/Test/bootstrap.php
|
||||
scanDirectories:
|
||||
- app/Helpers
|
||||
- modules/Analytics/Helpers
|
||||
- modules/Fediverse/Helpers
|
||||
- vendor/codeigniter4/codeigniter4/system/Helpers
|
||||
- vendor/codeigniter4/framework/system/Helpers
|
||||
- vendor/myth/auth/src/Helpers
|
||||
excludes_analyse:
|
||||
excludePaths:
|
||||
- app/Libraries/Router.php
|
||||
- app/Views/*
|
||||
- modules/*/Views/*
|
||||
- themes/*
|
||||
ignoreErrors:
|
||||
- '#This property type might be inlined to PHP. Do you have confidence it is correct\? Put it here#'
|
||||
- '#^Cognitive complexity for#'
|
||||
- '#^Class cognitive complexity#'
|
||||
- '#Do not use chained method calls. Put each on separated lines.#'
|
||||
- '#Do not inherit from abstract class, better use composition#'
|
||||
- '#Cannot access property [\$a-z_]+ on ((array\|)?object)#'
|
||||
- '#^Call to an undefined method CodeIgniter\\Database\\BaseBuilder#'
|
||||
- '#^Call to an undefined method CodeIgniter\\Database\\ConnectionInterface#'
|
||||
- '#Function \"preg_.*\(\)\" cannot be used/left in the code#'
|
||||
- '#Function "property_exists\(\)" cannot be used/left in the code#'
|
||||
- '#Instead of "instanceof/is_a\(\)" use ReflectionProvider service or "\(new ObjectType\(<desired_type\>\)\)\-\>isSuperTypeOf\(<element_type\>\)" for static reflection to work#'
|
||||
- '#^Call to an undefined method CodeIgniter\\Model#'
|
||||
- '#^Access to an undefined property App\\Entities\\Media\\Image#'
|
||||
- '#^Access to an undefined property CodeIgniter\\Database\\BaseBuilder#'
|
||||
-
|
||||
message: '#Function "function_exists\(\)" cannot be used/left in the code#'
|
||||
paths:
|
||||
- app/Helpers
|
||||
- app/Common.php
|
||||
- app/Libraries/ViewComponents/Helpers
|
||||
- '#^Access to an undefined property CodeIgniter\\Database\\BaseBuilder#'
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
bootstrap="vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php"
|
||||
bootstrap="vendor/codeigniter4/framework/system/Test/bootstrap.php"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
|
|
25
rector.php
25
rector.php
|
@ -2,12 +2,11 @@
|
|||
|
||||
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\FuncCall\CallUserFuncArrayToVariadicRector;
|
||||
use Rector\CodingStyle\Rector\FuncCall\ConsistentPregDelimiterRector;
|
||||
use Rector\CodingStyle\Rector\FuncCall\VersionCompareFuncCallToConstantRector;
|
||||
use Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchRector;
|
||||
use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector;
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersion;
|
||||
use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector;
|
||||
|
@ -15,7 +14,6 @@ use Rector\EarlyReturn\Rector\If_\ChangeOrIfReturnToEarlyReturnRector;
|
|||
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
|
||||
use Rector\Php80\Rector\ClassMethod\OptionalParametersAfterRequiredRector;
|
||||
use Rector\Set\ValueObject\SetList;
|
||||
use Rector\Transform\Rector\FuncCall\FuncCallToConstFetchRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
|
@ -24,14 +22,14 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
$parameters->set(Option::PATHS, [
|
||||
__DIR__ . '/app',
|
||||
__DIR__ . '/modules',
|
||||
__DIR__ . '/tests',
|
||||
__DIR__ . '/public',
|
||||
// __DIR__ . '/modules',
|
||||
// __DIR__ . '/tests',
|
||||
// __DIR__ . '/public',
|
||||
]);
|
||||
|
||||
// do you need to include constants, class aliases or custom autoloader? files listed will be executed
|
||||
$parameters->set(Option::BOOTSTRAP_FILES, [
|
||||
__DIR__ . '/vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php',
|
||||
__DIR__ . '/vendor/codeigniter4/framework/system/Test/bootstrap.php',
|
||||
]);
|
||||
|
||||
// Define what rule sets will be applied
|
||||
|
@ -46,10 +44,13 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
// auto import fully qualified class names
|
||||
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
|
||||
// $parameters->set(Option::ENABLE_CACHE, true);
|
||||
// TODO: add parallel
|
||||
// $parameters->set(Option::PARALLEL, true);
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_80);
|
||||
|
||||
$parameters->set(Option::SKIP, [
|
||||
__DIR__ . '/app/Views/errors/*',
|
||||
|
||||
// skip specific generated files
|
||||
__DIR__ . '/modules/Admin/Language/*/PersonsTaxonomy.php',
|
||||
|
||||
|
@ -57,8 +58,8 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
ChangeOrIfReturnToEarlyReturnRector::class,
|
||||
ChangeOrIfContinueToMultiContinueRector::class,
|
||||
EncapsedStringsToSprintfRector::class,
|
||||
SplitStringClassConstantToClassConstFetchRector::class,
|
||||
UnSpreadOperatorRector::class,
|
||||
ExplicitMethodCallOverMagicGetSetRector::class,
|
||||
|
||||
// skip rule in specific directory
|
||||
StringClassNameToClassConstantRector::class => [
|
||||
|
@ -68,6 +69,10 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
OptionalParametersAfterRequiredRector::class => [
|
||||
__DIR__ . '/app/Validation',
|
||||
],
|
||||
|
||||
NewlineAfterStatementRector::class => [
|
||||
__DIR__ . '/app/Views',
|
||||
]
|
||||
]);
|
||||
|
||||
// Path to phpstan with extensions, that PHPStan in Rector uses to determine types
|
||||
|
|
|
@ -24,8 +24,6 @@ declare(strict_types=1);
|
|||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019-2020 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
|
|
|
@ -34,7 +34,7 @@ final class HealthTest extends CIUnitTestCase
|
|||
// So if you set app.baseURL in .env, it takes precedence
|
||||
$config = new App();
|
||||
$this->assertTrue(
|
||||
$validation->check($config->baseURL, 'valid_url'),
|
||||
$validation->check($config->baseURL, 'valid_url_strict'),
|
||||
'baseURL "' . $config->baseURL . '" in .env is not valid URL'
|
||||
);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ final class HealthTest extends CIUnitTestCase
|
|||
|
||||
// BaseURL in app/Config/App.php is a valid URL?
|
||||
$this->assertTrue(
|
||||
$validation->check($reader->baseURL, 'valid_url'),
|
||||
$validation->check($reader->baseURL, 'valid_url_strict'),
|
||||
'baseURL "' . $reader->baseURL . '" in app/Config/App.php is not valid URL'
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
if (session()->has('message')): ?>
|
||||
<Alert variant="success" class="mb-4"><?= session('message') ?></Alert>
|
||||
<Alert variant="success" class="mb-4"><?= esc(session('message')) ?></Alert>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (session()->has('error')): ?>
|
||||
<Alert variant="danger" class="mb-4"><?= session('error') ?></Alert>
|
||||
<Alert variant="danger" class="mb-4"><?= esc(session('error')) ?></Alert>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (session()->has('errors')): ?>
|
||||
<Alert variant="danger" class="mb-4">
|
||||
<ul>
|
||||
<?php foreach (session('errors') as $error): ?>
|
||||
<li><?= $error ?></li>
|
||||
<li><?= esc($error) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</Alert>
|
||||
<?php endif;
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
|
|
@ -27,16 +27,17 @@
|
|||
<?= user()
|
||||
->podcasts === [] ? '' : '<img src="' . interact_as_actor()->avatar_image_url . '" class="absolute bottom-0 w-4 h-4 border rounded-full -right-1 border-navigation-bg" loading="lazy" />' ?>
|
||||
</div>
|
||||
<?= user()->username ?>
|
||||
<?= esc(user()->username) ?>
|
||||
<?= icon('caret-down', 'ml-auto text-2xl') ?></button>
|
||||
<?php
|
||||
$interactButtons = '';
|
||||
foreach (user()->podcasts 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 .= <<<CODE_SAMPLE
|
||||
<button class="inline-flex items-center w-full px-4 py-1 hover:bg-highlight" id="interact-as-actor-{$userPodcast->id}" name="actor_id" value="{$userPodcast->actor_id}">
|
||||
<div class="inline-flex items-center flex-1 text-sm"><img src="{$userPodcast->cover->tiny_url}" class="w-6 h-6 mr-2 rounded-full" loading="lazy" /><span class="truncate">{$userPodcast->title}</span>{$checkMark}</div>
|
||||
<div class="inline-flex items-center flex-1 text-sm"><img src="{$userPodcast->cover->tiny_url}" class="w-6 h-6 mr-2 rounded-full" loading="lazy" /><span class="max-w-xs truncate">{$userPodcastTitle}</span>{$checkMark}</div>
|
||||
</button>
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<?= lang('User.form.username') ?>
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5">
|
||||
<?= $user->username ?>
|
||||
<?= esc($user->username) ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="px-4 py-5">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue