refactor: add phpstan and update code to adhere to level 5
- move and refactor Image.php from Libraries to Entities folder - update some database field names / types - update composer packages
This commit is contained in:
parent
b691b927fe
commit
231d578d64
|
@ -7,13 +7,17 @@
|
|||
"workspaceFolder": "/castopod-host",
|
||||
"postCreateCommand": "cron && php spark serve --host 0.0.0.0",
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash",
|
||||
"terminal.integrated.defaultProfile.linux": "/bin/bash",
|
||||
"editor.formatOnSave": true,
|
||||
"[php]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"phpSniffer.autoDetect": true,
|
||||
"color-highlight.markerType": "dot-before"
|
||||
"color-highlight.markerType": "dot-before",
|
||||
"files.associations": {
|
||||
"*.xml.dist": "xml",
|
||||
"spark": "php"
|
||||
}
|
||||
},
|
||||
"extensions": [
|
||||
"mikestead.dotenv",
|
||||
|
@ -28,6 +32,8 @@
|
|||
"dbaeumer.vscode-eslint",
|
||||
"stylelint.vscode-stylelint",
|
||||
"wongjn.php-sniffer",
|
||||
"eamodio.gitlens"
|
||||
"eamodio.gitlens",
|
||||
"breezelin.phpstan",
|
||||
"kasik96.latte"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,8 +2,19 @@
|
|||
|
||||
namespace App\Authorization;
|
||||
|
||||
class FlatAuthorization extends \Myth\Auth\Authorization\FlatAuthorization
|
||||
use Myth\Auth\Authorization\FlatAuthorization as MythAuthFlatAuthorization;
|
||||
|
||||
class FlatAuthorization extends MythAuthFlatAuthorization
|
||||
{
|
||||
/**
|
||||
* The group model to use. Usually the class noted
|
||||
* below (or an extension thereof) but can be any
|
||||
* compatible CodeIgniter Model.
|
||||
*
|
||||
* @var PermissionModel
|
||||
*/
|
||||
protected $permissionModel;
|
||||
|
||||
/**
|
||||
* Checks a group to see if they have the specified permission.
|
||||
*
|
||||
|
@ -18,7 +29,7 @@ class FlatAuthorization extends \Myth\Auth\Authorization\FlatAuthorization
|
|||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->permissionModel->doesGroupHavePermission(
|
||||
return $this->permissionModel->doesGroupHavePermission(
|
||||
$groupId,
|
||||
$permissionId,
|
||||
);
|
||||
|
@ -27,14 +38,14 @@ class FlatAuthorization extends \Myth\Auth\Authorization\FlatAuthorization
|
|||
/**
|
||||
* Makes user part of given groups.
|
||||
*
|
||||
* @param array $groups Either collection of ID or names
|
||||
* @param array<string, string> $groups Either collection of ID or names
|
||||
*/
|
||||
public function setUserGroups(int $userId, array $groups = []): bool
|
||||
{
|
||||
// remove user from all groups before resetting it in new groups
|
||||
$this->groupModel->removeUserFromAllGroups($userId);
|
||||
|
||||
if ($groups = []) {
|
||||
if ($groups === []) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace App\Authorization;
|
||||
|
||||
class GroupModel extends \Myth\Auth\Authorization\GroupModel
|
||||
use Myth\Auth\Authorization\GroupModel as MythAuthGroupModel;
|
||||
|
||||
class GroupModel extends MythAuthGroupModel
|
||||
{
|
||||
/**
|
||||
* @return mixed[]
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace App\Authorization;
|
||||
|
||||
class PermissionModel extends \Myth\Auth\Authorization\PermissionModel
|
||||
use Myth\Auth\Authorization\PermissionModel as MythAuthPermissionModel;
|
||||
|
||||
class PermissionModel extends MythAuthPermissionModel
|
||||
{
|
||||
/**
|
||||
* Checks to see if a user, or one of their groups,
|
||||
|
|
|
@ -28,8 +28,10 @@ class Analytics extends AnalyticsBase
|
|||
|
||||
/**
|
||||
* get the full audio file url
|
||||
*
|
||||
* @param string|string[] $audioFilePath
|
||||
*/
|
||||
public function getAudioFileUrl(string $audioFilePath): string
|
||||
public function getAudioFileUrl($audioFilePath): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
class Auth extends \Myth\Auth\Config\Auth
|
||||
use Myth\Auth\Config\Auth as MythAuthConfig;
|
||||
|
||||
class Auth extends MythAuthConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use App\Entities\Actor;
|
||||
use App\Entities\Note;
|
||||
use App\Entities\User;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Exceptions\FrameworkException;
|
||||
|
||||
|
@ -23,6 +26,7 @@ use CodeIgniter\Exceptions\FrameworkException;
|
|||
*/
|
||||
|
||||
Events::on('pre_system', function () {
|
||||
// @phpstan-ignore-next-line
|
||||
if (ENVIRONMENT !== 'testing') {
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
throw FrameworkException::forEnabledZlibOutputCompression();
|
||||
|
@ -42,6 +46,8 @@ Events::on('pre_system', function () {
|
|||
* Debug Toolbar Listeners.
|
||||
* --------------------------------------------------------------------
|
||||
* If you delete, they will no longer be collected.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
if (CI_DEBUG) {
|
||||
Events::on(
|
||||
|
@ -52,7 +58,7 @@ Events::on('pre_system', function () {
|
|||
}
|
||||
});
|
||||
|
||||
Events::on('login', function ($user): void {
|
||||
Events::on('login', function (User $user): void {
|
||||
helper('auth');
|
||||
|
||||
// set interact_as_actor_id value
|
||||
|
@ -62,7 +68,7 @@ Events::on('login', function ($user): void {
|
|||
}
|
||||
});
|
||||
|
||||
Events::on('logout', function ($user): void {
|
||||
Events::on('logout', function (User $user): void {
|
||||
helper('auth');
|
||||
|
||||
// remove user's interact_as_actor session
|
||||
|
@ -75,7 +81,7 @@ Events::on('logout', function ($user): void {
|
|||
* --------------------------------------------------------------------
|
||||
* Update episode metadata counts
|
||||
*/
|
||||
Events::on('on_note_add', function ($note): void {
|
||||
Events::on('on_note_add', function (Note $note): void {
|
||||
if ($note->episode_id) {
|
||||
model('EpisodeModel')
|
||||
->where('id', $note->episode_id)
|
||||
|
@ -87,7 +93,7 @@ Events::on('on_note_add', function ($note): void {
|
|||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_note_remove', function ($note): void {
|
||||
Events::on('on_note_remove', function (Note $note): void {
|
||||
if ($note->episode_id) {
|
||||
model('EpisodeModel')
|
||||
->where('id', $note->episode_id)
|
||||
|
@ -106,7 +112,7 @@ Events::on('on_note_remove', function ($note): void {
|
|||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_note_reblog', function ($actor, $note): void {
|
||||
Events::on('on_note_reblog', function (Actor $actor, Note $note): void {
|
||||
if ($episodeId = $note->episode_id) {
|
||||
model('EpisodeModel')
|
||||
->where('id', $episodeId)
|
||||
|
@ -125,7 +131,7 @@ Events::on('on_note_reblog', function ($actor, $note): void {
|
|||
}
|
||||
});
|
||||
|
||||
Events::on('on_note_undo_reblog', function ($reblogNote): void {
|
||||
Events::on('on_note_undo_reblog', function (Note $reblogNote): void {
|
||||
$note = $reblogNote->reblog_of_note;
|
||||
if ($episodeId = $note->episode_id) {
|
||||
model('EpisodeModel')
|
||||
|
@ -147,21 +153,21 @@ Events::on('on_note_undo_reblog', function ($reblogNote): void {
|
|||
}
|
||||
});
|
||||
|
||||
Events::on('on_note_reply', function ($reply): void {
|
||||
Events::on('on_note_reply', function (Note $reply): void {
|
||||
$note = $reply->reply_to_note;
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_reply_remove', function ($reply): void {
|
||||
Events::on('on_reply_remove', function (Note $reply): void {
|
||||
$note = $reply->reply_to_note;
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_note_favourite', function ($actor, $note): void {
|
||||
Events::on('on_note_favourite', function (Actor $actor, Note $note): void {
|
||||
if ($note->episode_id) {
|
||||
model('EpisodeModel')
|
||||
->where('id', $note->episode_id)
|
||||
|
@ -176,7 +182,7 @@ Events::on('on_note_favourite', function ($actor, $note): void {
|
|||
}
|
||||
});
|
||||
|
||||
Events::on('on_note_undo_favourite', function ($actor, $note): void {
|
||||
Events::on('on_note_undo_favourite', function (Actor $actor, Note $note): void {
|
||||
if ($note->episode_id) {
|
||||
model('EpisodeModel')
|
||||
->where('id', $note->episode_id)
|
||||
|
@ -191,22 +197,22 @@ Events::on('on_note_undo_favourite', function ($actor, $note): void {
|
|||
}
|
||||
});
|
||||
|
||||
Events::on('on_block_actor', function ($actorId): void {
|
||||
Events::on('on_block_actor', function (int $actorId): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
});
|
||||
|
||||
Events::on('on_unblock_actor', function ($actorId): void {
|
||||
Events::on('on_unblock_actor', function (int $actorId): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
});
|
||||
|
||||
Events::on('on_block_domain', function ($domainName): void {
|
||||
Events::on('on_block_domain', function (string $domainName): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
});
|
||||
|
||||
Events::on('on_unblock_domain', function ($domainName): void {
|
||||
Events::on('on_unblock_domain', function (string $domainName): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
});
|
||||
|
|
|
@ -80,25 +80,25 @@ class Images extends BaseConfig
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $thumbnailExtension = '_thumbnail';
|
||||
public $thumbnailSuffix = '_thumbnail';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $mediumExtension = '_medium';
|
||||
public $mediumSuffix = '_medium';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $largeExtension = '_large';
|
||||
public $largeSuffix = '_large';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $feedExtension = '_feed';
|
||||
public $feedSuffix = '_feed';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $id3Extension = '_id3';
|
||||
public $id3Suffix = '_id3';
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class Mimes
|
|||
/**
|
||||
* Map of extensions to mime types.
|
||||
*
|
||||
* @var array<string, string>
|
||||
* @var array<string, string|string[]>
|
||||
*/
|
||||
public static $mimes = [
|
||||
'hqx' => [
|
||||
|
@ -350,25 +350,25 @@ class Mimes
|
|||
|
||||
$proposedExtension = trim(strtolower($proposedExtension));
|
||||
|
||||
if ($proposedExtension !== '') {
|
||||
if (
|
||||
array_key_exists($proposedExtension, static::$mimes) &&
|
||||
in_array(
|
||||
$type,
|
||||
is_string(static::$mimes[$proposedExtension])
|
||||
? [static::$mimes[$proposedExtension]]
|
||||
: static::$mimes[$proposedExtension],
|
||||
true,
|
||||
)
|
||||
) {
|
||||
// The detected mime type matches with the proposed extension.
|
||||
return $proposedExtension;
|
||||
}
|
||||
|
||||
if ($proposedExtension === '') {
|
||||
// An extension was proposed, but the media type does not match the mime type list.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
array_key_exists($proposedExtension, static::$mimes) &&
|
||||
in_array(
|
||||
$type,
|
||||
is_string(static::$mimes[$proposedExtension])
|
||||
? [static::$mimes[$proposedExtension]]
|
||||
: static::$mimes[$proposedExtension],
|
||||
true,
|
||||
)
|
||||
) {
|
||||
// The detected mime type matches with the proposed extension.
|
||||
return $proposedExtension;
|
||||
}
|
||||
|
||||
// Reverse check the mime type list if no extension was proposed.
|
||||
// This search is order sensitive!
|
||||
foreach (static::$mimes as $ext => $types) {
|
||||
|
|
|
@ -51,23 +51,35 @@ $routes->addPlaceholder(
|
|||
|
||||
// We get a performance increase by specifying the default
|
||||
// route since we don't have to scan directories.
|
||||
$routes->get('/', 'Home::index', ['as' => 'home']);
|
||||
$routes->get('/', 'HomeController::index', ['as' => 'home']);
|
||||
|
||||
// Install Wizard route
|
||||
$routes->group(config('App')->installGateway, function ($routes): void {
|
||||
$routes->get('/', 'Install', ['as' => 'install']);
|
||||
$routes->post('instance-config', 'Install::attemptInstanceConfig', [
|
||||
'as' => 'instance-config',
|
||||
]);
|
||||
$routes->post('database-config', 'Install::attemptDatabaseConfig', [
|
||||
'as' => 'database-config',
|
||||
]);
|
||||
$routes->post('cache-config', 'Install::attemptCacheConfig', [
|
||||
$routes->get('/', 'InstallController', ['as' => 'install']);
|
||||
$routes->post(
|
||||
'instance-config',
|
||||
'InstallController::attemptInstanceConfig',
|
||||
[
|
||||
'as' => 'instance-config',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'database-config',
|
||||
'InstallController::attemptDatabaseConfig',
|
||||
[
|
||||
'as' => 'database-config',
|
||||
],
|
||||
);
|
||||
$routes->post('cache-config', 'InstallController::attemptCacheConfig', [
|
||||
'as' => 'cache-config',
|
||||
]);
|
||||
$routes->post('create-superadmin', 'Install::attemptCreateSuperAdmin', [
|
||||
'as' => 'create-superadmin',
|
||||
]);
|
||||
$routes->post(
|
||||
'create-superadmin',
|
||||
'InstallController::attemptCreateSuperAdmin',
|
||||
[
|
||||
'as' => 'create-superadmin',
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
$routes->get('.well-known/platforms', 'Platform');
|
||||
|
@ -77,35 +89,35 @@ $routes->group(
|
|||
config('App')->adminGateway,
|
||||
['namespace' => 'App\Controllers\Admin'],
|
||||
function ($routes): void {
|
||||
$routes->get('/', 'Home', [
|
||||
$routes->get('/', 'HomeController', [
|
||||
'as' => 'admin',
|
||||
]);
|
||||
|
||||
$routes->group('persons', function ($routes): void {
|
||||
$routes->get('/', 'Person', [
|
||||
$routes->get('/', 'PersonController', [
|
||||
'as' => 'person-list',
|
||||
'filter' => 'permission:person-list',
|
||||
]);
|
||||
$routes->get('new', 'Person::create', [
|
||||
$routes->get('new', 'PersonController::create', [
|
||||
'as' => 'person-create',
|
||||
'filter' => 'permission:person-create',
|
||||
]);
|
||||
$routes->post('new', 'Person::attemptCreate', [
|
||||
$routes->post('new', 'PersonController::attemptCreate', [
|
||||
'filter' => 'permission:person-create',
|
||||
]);
|
||||
$routes->group('(:num)', function ($routes): void {
|
||||
$routes->get('/', 'Person::view/$1', [
|
||||
$routes->get('/', 'PersonController::view/$1', [
|
||||
'as' => 'person-view',
|
||||
'filter' => 'permission:person-view',
|
||||
]);
|
||||
$routes->get('edit', 'Person::edit/$1', [
|
||||
$routes->get('edit', 'PersonController::edit/$1', [
|
||||
'as' => 'person-edit',
|
||||
'filter' => 'permission:person-edit',
|
||||
]);
|
||||
$routes->post('edit', 'Person::attemptEdit/$1', [
|
||||
$routes->post('edit', 'PersonController::attemptEdit/$1', [
|
||||
'filter' => 'permission:person-edit',
|
||||
]);
|
||||
$routes->add('delete', 'Person::delete/$1', [
|
||||
$routes->add('delete', 'PersonController::delete/$1', [
|
||||
'as' => 'person-delete',
|
||||
'filter' => 'permission:person-delete',
|
||||
]);
|
||||
|
@ -114,55 +126,59 @@ $routes->group(
|
|||
|
||||
// Podcasts
|
||||
$routes->group('podcasts', function ($routes): void {
|
||||
$routes->get('/', 'Podcast::list', [
|
||||
$routes->get('/', 'PodcastController::list', [
|
||||
'as' => 'podcast-list',
|
||||
]);
|
||||
$routes->get('new', 'Podcast::create', [
|
||||
$routes->get('new', 'PodcastController::create', [
|
||||
'as' => 'podcast-create',
|
||||
'filter' => 'permission:podcasts-create',
|
||||
]);
|
||||
$routes->post('new', 'Podcast::attemptCreate', [
|
||||
$routes->post('new', 'PodcastController::attemptCreate', [
|
||||
'filter' => 'permission:podcasts-create',
|
||||
]);
|
||||
$routes->get('import', 'PodcastImport', [
|
||||
$routes->get('import', 'PodcastImportController', [
|
||||
'as' => 'podcast-import',
|
||||
'filter' => 'permission:podcasts-import',
|
||||
]);
|
||||
$routes->post('import', 'PodcastImport::attemptImport', [
|
||||
$routes->post('import', 'PodcastImportController::attemptImport', [
|
||||
'filter' => 'permission:podcasts-import',
|
||||
]);
|
||||
|
||||
// Podcast
|
||||
// Use ids in admin area to help permission and group lookups
|
||||
$routes->group('(:num)', function ($routes): void {
|
||||
$routes->get('/', 'Podcast::view/$1', [
|
||||
$routes->get('/', 'PodcastController::view/$1', [
|
||||
'as' => 'podcast-view',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]);
|
||||
$routes->get('edit', 'Podcast::edit/$1', [
|
||||
$routes->get('edit', 'PodcastController::edit/$1', [
|
||||
'as' => 'podcast-edit',
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]);
|
||||
$routes->post('edit', 'Podcast::attemptEdit/$1', [
|
||||
$routes->post('edit', 'PodcastController::attemptEdit/$1', [
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]);
|
||||
$routes->get('delete', 'Podcast::delete/$1', [
|
||||
$routes->get('delete', 'PodcastController::delete/$1', [
|
||||
'as' => 'podcast-delete',
|
||||
'filter' => 'permission:podcasts-delete',
|
||||
]);
|
||||
|
||||
$routes->group('persons', function ($routes): void {
|
||||
$routes->get('/', 'PodcastPerson/$1', [
|
||||
$routes->get('/', 'PodcastPersonController/$1', [
|
||||
'as' => 'podcast-person-manage',
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]);
|
||||
$routes->post('/', 'PodcastPerson::attemptAdd/$1', [
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]);
|
||||
$routes->post(
|
||||
'/',
|
||||
'PodcastPersonController::attemptAdd/$1',
|
||||
[
|
||||
'filter' => 'permission:podcast-edit',
|
||||
],
|
||||
);
|
||||
|
||||
$routes->get(
|
||||
'(:num)/remove',
|
||||
'PodcastPerson::remove/$1/$2',
|
||||
'PodcastPersonController::remove/$1/$2',
|
||||
[
|
||||
'as' => 'podcast-person-remove',
|
||||
'filter' => 'permission:podcast-edit',
|
||||
|
@ -171,13 +187,13 @@ $routes->group(
|
|||
});
|
||||
|
||||
$routes->group('analytics', function ($routes): void {
|
||||
$routes->get('/', 'Podcast::viewAnalytics/$1', [
|
||||
$routes->get('/', 'PodcastController::viewAnalytics/$1', [
|
||||
'as' => 'podcast-analytics',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]);
|
||||
$routes->get(
|
||||
'webpages',
|
||||
'Podcast::viewAnalyticsWebpages/$1',
|
||||
'PodcastController::viewAnalyticsWebpages/$1',
|
||||
[
|
||||
'as' => 'podcast-analytics-webpages',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
|
@ -185,7 +201,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'locations',
|
||||
'Podcast::viewAnalyticsLocations/$1',
|
||||
'PodcastController::viewAnalyticsLocations/$1',
|
||||
[
|
||||
'as' => 'podcast-analytics-locations',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
|
@ -193,7 +209,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'unique-listeners',
|
||||
'Podcast::viewAnalyticsUniqueListeners/$1',
|
||||
'PodcastController::viewAnalyticsUniqueListeners/$1',
|
||||
[
|
||||
'as' => 'podcast-analytics-unique-listeners',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
|
@ -201,7 +217,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'listening-time',
|
||||
'Podcast::viewAnalyticsListeningTime/$1',
|
||||
'PodcastController::viewAnalyticsListeningTime/$1',
|
||||
[
|
||||
'as' => 'podcast-analytics-listening-time',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
|
@ -209,7 +225,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'time-periods',
|
||||
'Podcast::viewAnalyticsTimePeriods/$1',
|
||||
'PodcastController::viewAnalyticsTimePeriods/$1',
|
||||
[
|
||||
'as' => 'podcast-analytics-time-periods',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
|
@ -217,7 +233,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'players',
|
||||
'Podcast::viewAnalyticsPlayers/$1',
|
||||
'PodcastController::viewAnalyticsPlayers/$1',
|
||||
[
|
||||
'as' => 'podcast-analytics-players',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
|
@ -227,41 +243,53 @@ $routes->group(
|
|||
|
||||
// Podcast episodes
|
||||
$routes->group('episodes', function ($routes): void {
|
||||
$routes->get('/', 'Episode::list/$1', [
|
||||
$routes->get('/', 'EpisodeController::list/$1', [
|
||||
'as' => 'episode-list',
|
||||
'filter' =>
|
||||
'permission:episodes-list,podcast_episodes-list',
|
||||
]);
|
||||
$routes->get('new', 'Episode::create/$1', [
|
||||
$routes->get('new', 'EpisodeController::create/$1', [
|
||||
'as' => 'episode-create',
|
||||
'filter' => 'permission:podcast_episodes-create',
|
||||
]);
|
||||
$routes->post('new', 'Episode::attemptCreate/$1', [
|
||||
'filter' => 'permission:podcast_episodes-create',
|
||||
]);
|
||||
$routes->post(
|
||||
'new',
|
||||
'EpisodeController::attemptCreate/$1',
|
||||
[
|
||||
'filter' => 'permission:podcast_episodes-create',
|
||||
],
|
||||
);
|
||||
|
||||
// Episode
|
||||
$routes->group('(:num)', function ($routes): void {
|
||||
$routes->get('/', 'Episode::view/$1/$2', [
|
||||
$routes->get('/', 'EpisodeController::view/$1/$2', [
|
||||
'as' => 'episode-view',
|
||||
'filter' =>
|
||||
'permission:episodes-view,podcast_episodes-view',
|
||||
]);
|
||||
$routes->get('edit', 'Episode::edit/$1/$2', [
|
||||
$routes->get('edit', 'EpisodeController::edit/$1/$2', [
|
||||
'as' => 'episode-edit',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]);
|
||||
$routes->post('edit', 'Episode::attemptEdit/$1/$2', [
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]);
|
||||
$routes->get('publish', 'Episode::publish/$1/$2', [
|
||||
'as' => 'episode-publish',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
]);
|
||||
$routes->post(
|
||||
'edit',
|
||||
'EpisodeController::attemptEdit/$1/$2',
|
||||
[
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'publish',
|
||||
'EpisodeController::publish/$1/$2',
|
||||
[
|
||||
'as' => 'episode-publish',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'publish',
|
||||
'Episode::attemptPublish/$1/$2',
|
||||
'EpisodeController::attemptPublish/$1/$2',
|
||||
[
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
|
@ -269,7 +297,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'publish-edit',
|
||||
'Episode::publishEdit/$1/$2',
|
||||
'EpisodeController::publishEdit/$1/$2',
|
||||
[
|
||||
'as' => 'episode-publish_edit',
|
||||
'filter' =>
|
||||
|
@ -278,32 +306,41 @@ $routes->group(
|
|||
);
|
||||
$routes->post(
|
||||
'publish-edit',
|
||||
'Episode::attemptPublishEdit/$1/$2',
|
||||
'EpisodeController::attemptPublishEdit/$1/$2',
|
||||
[
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
],
|
||||
);
|
||||
$routes->get('unpublish', 'Episode::unpublish/$1/$2', [
|
||||
'as' => 'episode-unpublish',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
]);
|
||||
$routes->get(
|
||||
'unpublish',
|
||||
'EpisodeController::unpublish/$1/$2',
|
||||
[
|
||||
'as' => 'episode-unpublish',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'unpublish',
|
||||
'Episode::attemptUnpublish/$1/$2',
|
||||
'EpisodeController::attemptUnpublish/$1/$2',
|
||||
[
|
||||
'filter' =>
|
||||
'permission:podcast-manage_publications',
|
||||
],
|
||||
);
|
||||
$routes->get('delete', 'Episode::delete/$1/$2', [
|
||||
'as' => 'episode-delete',
|
||||
'filter' => 'permission:podcast_episodes-delete',
|
||||
]);
|
||||
$routes->get(
|
||||
'delete',
|
||||
'EpisodeController::delete/$1/$2',
|
||||
[
|
||||
'as' => 'episode-delete',
|
||||
'filter' =>
|
||||
'permission:podcast_episodes-delete',
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'transcript-delete',
|
||||
'Episode::transcriptDelete/$1/$2',
|
||||
'EpisodeController::transcriptDelete/$1/$2',
|
||||
[
|
||||
'as' => 'transcript-delete',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
|
@ -311,7 +348,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'chapters-delete',
|
||||
'Episode::chaptersDelete/$1/$2',
|
||||
'EpisodeController::chaptersDelete/$1/$2',
|
||||
[
|
||||
'as' => 'chapters-delete',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
|
@ -319,7 +356,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'soundbites',
|
||||
'Episode::soundbitesEdit/$1/$2',
|
||||
'EpisodeController::soundbitesEdit/$1/$2',
|
||||
[
|
||||
'as' => 'soundbites-edit',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
|
@ -327,14 +364,14 @@ $routes->group(
|
|||
);
|
||||
$routes->post(
|
||||
'soundbites',
|
||||
'Episode::soundbitesAttemptEdit/$1/$2',
|
||||
'EpisodeController::soundbitesAttemptEdit/$1/$2',
|
||||
[
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'soundbites/(:num)/delete',
|
||||
'Episode::soundbiteDelete/$1/$2/$3',
|
||||
'EpisodeController::soundbiteDelete/$1/$2/$3',
|
||||
[
|
||||
'as' => 'soundbite-delete',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
|
@ -342,7 +379,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'embeddable-player',
|
||||
'Episode::embeddablePlayer/$1/$2',
|
||||
'EpisodeController::embeddablePlayer/$1/$2',
|
||||
[
|
||||
'as' => 'embeddable-player-add',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
|
@ -350,13 +387,13 @@ $routes->group(
|
|||
);
|
||||
|
||||
$routes->group('persons', function ($routes): void {
|
||||
$routes->get('/', 'EpisodePerson/$1/$2', [
|
||||
$routes->get('/', 'EpisodePersonController/$1/$2', [
|
||||
'as' => 'episode-person-manage',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]);
|
||||
$routes->post(
|
||||
'/',
|
||||
'EpisodePerson::attemptAdd/$1/$2',
|
||||
'EpisodePersonController::attemptAdd/$1/$2',
|
||||
[
|
||||
'filter' =>
|
||||
'permission:podcast_episodes-edit',
|
||||
|
@ -364,7 +401,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'(:num)/remove',
|
||||
'EpisodePerson::remove/$1/$2/$3',
|
||||
'EpisodePersonController::remove/$1/$2/$3',
|
||||
[
|
||||
'as' => 'episode-person-remove',
|
||||
'filter' =>
|
||||
|
@ -377,51 +414,64 @@ $routes->group(
|
|||
|
||||
// Podcast contributors
|
||||
$routes->group('contributors', function ($routes): void {
|
||||
$routes->get('/', 'Contributor::list/$1', [
|
||||
$routes->get('/', 'ContributorController::list/$1', [
|
||||
'as' => 'contributor-list',
|
||||
'filter' =>
|
||||
'permission:podcasts-view,podcast-manage_contributors',
|
||||
]);
|
||||
$routes->get('add', 'Contributor::add/$1', [
|
||||
$routes->get('add', 'ContributorController::add/$1', [
|
||||
'as' => 'contributor-add',
|
||||
'filter' => 'permission:podcast-manage_contributors',
|
||||
]);
|
||||
$routes->post('add', 'Contributor::attemptAdd/$1', [
|
||||
'filter' => 'permission:podcast-manage_contributors',
|
||||
]);
|
||||
$routes->post(
|
||||
'add',
|
||||
'ContributorController::attemptAdd/$1',
|
||||
[
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
],
|
||||
);
|
||||
|
||||
// Contributor
|
||||
$routes->group('(:num)', function ($routes): void {
|
||||
$routes->get('/', 'Contributor::view/$1/$2', [
|
||||
$routes->get('/', 'ContributorController::view/$1/$2', [
|
||||
'as' => 'contributor-view',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
]);
|
||||
$routes->get('edit', 'Contributor::edit/$1/$2', [
|
||||
'as' => 'contributor-edit',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
]);
|
||||
$routes->get(
|
||||
'edit',
|
||||
'ContributorController::edit/$1/$2',
|
||||
[
|
||||
'as' => 'contributor-edit',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'edit',
|
||||
'Contributor::attemptEdit/$1/$2',
|
||||
'ContributorController::attemptEdit/$1/$2',
|
||||
[
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
],
|
||||
);
|
||||
$routes->get('remove', 'Contributor::remove/$1/$2', [
|
||||
'as' => 'contributor-remove',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
]);
|
||||
$routes->get(
|
||||
'remove',
|
||||
'ContributorController::remove/$1/$2',
|
||||
[
|
||||
'as' => 'contributor-remove',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
$routes->group('platforms', function ($routes): void {
|
||||
$routes->get(
|
||||
'/',
|
||||
'PodcastPlatform::platforms/$1/podcasting',
|
||||
'PodcastPlatformController::platforms/$1/podcasting',
|
||||
[
|
||||
'as' => 'platforms-podcasting',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
|
@ -429,7 +479,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'social',
|
||||
'PodcastPlatform::platforms/$1/social',
|
||||
'PodcastPlatformController::platforms/$1/social',
|
||||
[
|
||||
'as' => 'platforms-social',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
|
@ -437,7 +487,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'funding',
|
||||
'PodcastPlatform::platforms/$1/funding',
|
||||
'PodcastPlatformController::platforms/$1/funding',
|
||||
[
|
||||
'as' => 'platforms-funding',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
|
@ -445,7 +495,7 @@ $routes->group(
|
|||
);
|
||||
$routes->post(
|
||||
'save/(:platformType)',
|
||||
'PodcastPlatform::attemptPlatformsUpdate/$1/$2',
|
||||
'PodcastPlatformController::attemptPlatformsUpdate/$1/$2',
|
||||
[
|
||||
'as' => 'platforms-save',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
|
@ -453,7 +503,7 @@ $routes->group(
|
|||
);
|
||||
$routes->get(
|
||||
'(:slug)/podcast-platform-remove',
|
||||
'PodcastPlatform::removePodcastPlatform/$1/$2',
|
||||
'PodcastPlatformController::removePodcastPlatform/$1/$2',
|
||||
[
|
||||
'as' => 'podcast-platform-remove',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
|
@ -465,41 +515,51 @@ $routes->group(
|
|||
|
||||
// Instance wide Fediverse config
|
||||
$routes->group('fediverse', function ($routes): void {
|
||||
$routes->get('/', 'Fediverse::dashboard', [
|
||||
$routes->get('/', 'FediverseController::dashboard', [
|
||||
'as' => 'fediverse-dashboard',
|
||||
]);
|
||||
$routes->get('blocked-actors', 'Fediverse::blockedActors', [
|
||||
'as' => 'fediverse-blocked-actors',
|
||||
'filter' => 'permission:fediverse-block_actors',
|
||||
]);
|
||||
$routes->get('blocked-domains', 'Fediverse::blockedDomains', [
|
||||
'as' => 'fediverse-blocked-domains',
|
||||
'filter' => 'permission:fediverse-block_domains',
|
||||
]);
|
||||
$routes->get(
|
||||
'blocked-actors',
|
||||
'FediverseController::blockedActors',
|
||||
[
|
||||
'as' => 'fediverse-blocked-actors',
|
||||
'filter' => 'permission:fediverse-block_actors',
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'blocked-domains',
|
||||
'FediverseController::blockedDomains',
|
||||
[
|
||||
'as' => 'fediverse-blocked-domains',
|
||||
'filter' => 'permission:fediverse-block_domains',
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
// Pages
|
||||
$routes->group('pages', function ($routes): void {
|
||||
$routes->get('/', 'Page::list', ['as' => 'page-list']);
|
||||
$routes->get('new', 'Page::create', [
|
||||
$routes->get('/', 'PageController::list', ['as' => 'page-list']);
|
||||
$routes->get('new', 'PageController::create', [
|
||||
'as' => 'page-create',
|
||||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
$routes->post('new', 'Page::attemptCreate', [
|
||||
$routes->post('new', 'PageController::attemptCreate', [
|
||||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
|
||||
$routes->group('(:num)', function ($routes): void {
|
||||
$routes->get('/', 'Page::view/$1', ['as' => 'page-view']);
|
||||
$routes->get('edit', 'Page::edit/$1', [
|
||||
$routes->get('/', 'PageController::view/$1', [
|
||||
'as' => 'page-view',
|
||||
]);
|
||||
$routes->get('edit', 'PageController::edit/$1', [
|
||||
'as' => 'page-edit',
|
||||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
$routes->post('edit', 'Page::attemptEdit/$1', [
|
||||
$routes->post('edit', 'PageController::attemptEdit/$1', [
|
||||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
|
||||
$routes->get('delete', 'Page::delete/$1', [
|
||||
$routes->get('delete', 'PageController::delete/$1', [
|
||||
'as' => 'page-delete',
|
||||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
|
@ -508,44 +568,48 @@ $routes->group(
|
|||
|
||||
// Users
|
||||
$routes->group('users', function ($routes): void {
|
||||
$routes->get('/', 'User::list', [
|
||||
$routes->get('/', 'UserController::list', [
|
||||
'as' => 'user-list',
|
||||
'filter' => 'permission:users-list',
|
||||
]);
|
||||
$routes->get('new', 'User::create', [
|
||||
$routes->get('new', 'UserController::create', [
|
||||
'as' => 'user-create',
|
||||
'filter' => 'permission:users-create',
|
||||
]);
|
||||
$routes->post('new', 'User::attemptCreate', [
|
||||
$routes->post('new', 'UserController::attemptCreate', [
|
||||
'filter' => 'permission:users-create',
|
||||
]);
|
||||
|
||||
// User
|
||||
$routes->group('(:num)', function ($routes): void {
|
||||
$routes->get('/', 'User::view/$1', [
|
||||
$routes->get('/', 'UserController::view/$1', [
|
||||
'as' => 'user-view',
|
||||
'filter' => 'permission:users-view',
|
||||
]);
|
||||
$routes->get('edit', 'User::edit/$1', [
|
||||
$routes->get('edit', 'UserController::edit/$1', [
|
||||
'as' => 'user-edit',
|
||||
'filter' => 'permission:users-manage_authorizations',
|
||||
]);
|
||||
$routes->post('edit', 'User::attemptEdit/$1', [
|
||||
$routes->post('edit', 'UserController::attemptEdit/$1', [
|
||||
'filter' => 'permission:users-manage_authorizations',
|
||||
]);
|
||||
$routes->get('ban', 'User::ban/$1', [
|
||||
$routes->get('ban', 'UserController::ban/$1', [
|
||||
'as' => 'user-ban',
|
||||
'filter' => 'permission:users-manage_bans',
|
||||
]);
|
||||
$routes->get('unban', 'User::unBan/$1', [
|
||||
$routes->get('unban', 'UserController::unBan/$1', [
|
||||
'as' => 'user-unban',
|
||||
'filter' => 'permission:users-manage_bans',
|
||||
]);
|
||||
$routes->get('force-pass-reset', 'User::forcePassReset/$1', [
|
||||
'as' => 'user-force_pass_reset',
|
||||
'filter' => 'permission:users-force_pass_reset',
|
||||
]);
|
||||
$routes->get('delete', 'User::delete/$1', [
|
||||
$routes->get(
|
||||
'force-pass-reset',
|
||||
'UserController::forcePassReset/$1',
|
||||
[
|
||||
'as' => 'user-force_pass_reset',
|
||||
'filter' => 'permission:users-force_pass_reset',
|
||||
],
|
||||
);
|
||||
$routes->get('delete', 'UserController::delete/$1', [
|
||||
'as' => 'user-delete',
|
||||
'filter' => 'permission:users-delete',
|
||||
]);
|
||||
|
@ -554,13 +618,20 @@ $routes->group(
|
|||
|
||||
// My account
|
||||
$routes->group('my-account', function ($routes): void {
|
||||
$routes->get('/', 'MyAccount', [
|
||||
$routes->get('/', 'MyAccountController', [
|
||||
'as' => 'my-account',
|
||||
]);
|
||||
$routes->get('change-password', 'MyAccount::changePassword/$1', [
|
||||
'as' => 'change-password',
|
||||
]);
|
||||
$routes->post('change-password', 'MyAccount::attemptChange/$1');
|
||||
$routes->get(
|
||||
'change-password',
|
||||
'MyAccountController::changePassword/$1',
|
||||
[
|
||||
'as' => 'change-password',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'change-password',
|
||||
'MyAccountController::attemptChange/$1',
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
@ -570,42 +641,48 @@ $routes->group(
|
|||
*/
|
||||
$routes->group(config('App')->authGateway, function ($routes): void {
|
||||
// Login/out
|
||||
$routes->get('login', 'Auth::login', ['as' => 'login']);
|
||||
$routes->post('login', 'Auth::attemptLogin');
|
||||
$routes->get('logout', 'Auth::logout', ['as' => 'logout']);
|
||||
$routes->get('login', 'AuthController::login', ['as' => 'login']);
|
||||
$routes->post('login', 'AuthController::attemptLogin');
|
||||
$routes->get('logout', 'AuthController::logout', [
|
||||
'as' => 'logout',
|
||||
]);
|
||||
|
||||
// Registration
|
||||
$routes->get('register', 'Auth::register', [
|
||||
$routes->get('register', 'AuthController::register', [
|
||||
'as' => 'register',
|
||||
]);
|
||||
$routes->post('register', 'Auth::attemptRegister');
|
||||
$routes->post('register', 'AuthController::attemptRegister');
|
||||
|
||||
// Activation
|
||||
$routes->get('activate-account', 'Auth::activateAccount', [
|
||||
$routes->get('activate-account', 'AuthController::activateAccount', [
|
||||
'as' => 'activate-account',
|
||||
]);
|
||||
$routes->get('resend-activate-account', 'Auth::resendActivateAccount', [
|
||||
'as' => 'resend-activate-account',
|
||||
]);
|
||||
$routes->get(
|
||||
'resend-activate-account',
|
||||
'AuthController::resendActivateAccount',
|
||||
[
|
||||
'as' => 'resend-activate-account',
|
||||
],
|
||||
);
|
||||
|
||||
// Forgot/Resets
|
||||
$routes->get('forgot', 'Auth::forgotPassword', [
|
||||
$routes->get('forgot', 'AuthController::forgotPassword', [
|
||||
'as' => 'forgot',
|
||||
]);
|
||||
$routes->post('forgot', 'Auth::attemptForgot');
|
||||
$routes->get('reset-password', 'Auth::resetPassword', [
|
||||
$routes->post('forgot', 'AuthController::attemptForgot');
|
||||
$routes->get('reset-password', 'AuthController::resetPassword', [
|
||||
'as' => 'reset-password',
|
||||
]);
|
||||
$routes->post('reset-password', 'Auth::attemptReset');
|
||||
$routes->post('reset-password', 'AuthController::attemptReset');
|
||||
});
|
||||
|
||||
// Podcast's Public routes
|
||||
$routes->group('@(:podcastName)', function ($routes): void {
|
||||
$routes->get('/', 'Podcast::activity/$1', [
|
||||
$routes->get('/', 'PodcastController::activity/$1', [
|
||||
'as' => 'podcast-activity',
|
||||
]);
|
||||
// override default ActivityPub Library's actor route
|
||||
$routes->get('/', 'Podcast::activity/$1', [
|
||||
$routes->get('/', 'PodcastController::activity/$1', [
|
||||
'as' => 'actor',
|
||||
'alternate-content' => [
|
||||
'application/activity+json' => [
|
||||
|
@ -618,26 +695,26 @@ $routes->group('@(:podcastName)', function ($routes): void {
|
|||
],
|
||||
],
|
||||
]);
|
||||
$routes->get('episodes', 'Podcast::episodes/$1', [
|
||||
$routes->get('episodes', 'PodcastController::episodes/$1', [
|
||||
'as' => 'podcast-episodes',
|
||||
]);
|
||||
$routes->group('episodes/(:slug)', function ($routes): void {
|
||||
$routes->get('/', 'Episode/$1/$2', [
|
||||
$routes->get('/', 'EpisodeController/$1/$2', [
|
||||
'as' => 'episode',
|
||||
]);
|
||||
$routes->get('oembed.json', 'Episode::oembedJSON/$1/$2', [
|
||||
$routes->get('oembed.json', 'EpisodeController::oembedJSON/$1/$2', [
|
||||
'as' => 'episode-oembed-json',
|
||||
]);
|
||||
$routes->get('oembed.xml', 'Episode::oembedXML/$1/$2', [
|
||||
$routes->get('oembed.xml', 'EpisodeController::oembedXML/$1/$2', [
|
||||
'as' => 'episode-oembed-xml',
|
||||
]);
|
||||
$routes->group('embeddable-player', function ($routes): void {
|
||||
$routes->get('/', 'Episode::embeddablePlayer/$1/$2', [
|
||||
$routes->get('/', 'EpisodeController::embeddablePlayer/$1/$2', [
|
||||
'as' => 'embeddable-player',
|
||||
]);
|
||||
$routes->get(
|
||||
'(:embeddablePlayerTheme)',
|
||||
'Episode::embeddablePlayer/$1/$2/$3',
|
||||
'EpisodeController::embeddablePlayer/$1/$2/$3',
|
||||
[
|
||||
'as' => 'embeddable-player-theme',
|
||||
],
|
||||
|
@ -645,16 +722,16 @@ $routes->group('@(:podcastName)', function ($routes): void {
|
|||
});
|
||||
});
|
||||
|
||||
$routes->head('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
|
||||
$routes->get('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
|
||||
$routes->head('feed.xml', 'FeedController/$1', ['as' => 'podcast_feed']);
|
||||
$routes->get('feed.xml', 'FeedController/$1', ['as' => 'podcast_feed']);
|
||||
});
|
||||
|
||||
// Other pages
|
||||
$routes->get('/credits', 'Page::credits', ['as' => 'credits']);
|
||||
$routes->get('/credits', 'PageController::credits', ['as' => 'credits']);
|
||||
$routes->get('/pages/(:slug)', 'Page/$1', ['as' => 'page']);
|
||||
|
||||
// interacting as an actor
|
||||
$routes->post('interact-as-actor', 'Auth::attemptInteractAsActor', [
|
||||
$routes->post('interact-as-actor', 'AuthController::attemptInteractAsActor', [
|
||||
'as' => 'interact-as-actor',
|
||||
]);
|
||||
|
||||
|
@ -662,13 +739,13 @@ $routes->post('interact-as-actor', 'Auth::attemptInteractAsActor', [
|
|||
* Overwriting ActivityPub routes file
|
||||
*/
|
||||
$routes->group('@(:podcastName)', function ($routes): void {
|
||||
$routes->post('notes/new', 'Note::attemptCreate/$1', [
|
||||
$routes->post('notes/new', 'NoteController::attemptCreate/$1', [
|
||||
'as' => 'note-attempt-create',
|
||||
'filter' => 'permission:podcast-manage_publications',
|
||||
]);
|
||||
// Note
|
||||
$routes->group('notes/(:uuid)', function ($routes): void {
|
||||
$routes->get('/', 'Note/$1/$2', [
|
||||
$routes->get('/', 'NoteController::view/$1/$2', [
|
||||
'as' => 'note',
|
||||
'alternate-content' => [
|
||||
'application/activity+json' => [
|
||||
|
@ -681,7 +758,7 @@ $routes->group('@(:podcastName)', function ($routes): void {
|
|||
],
|
||||
],
|
||||
]);
|
||||
$routes->get('replies', 'Note/$1/$2', [
|
||||
$routes->get('replies', 'NoteController/$1/$2', [
|
||||
'as' => 'note-replies',
|
||||
'alternate-content' => [
|
||||
'application/activity+json' => [
|
||||
|
@ -696,33 +773,45 @@ $routes->group('@(:podcastName)', function ($routes): void {
|
|||
]);
|
||||
|
||||
// Actions
|
||||
$routes->post('action', 'Note::attemptAction/$1/$2', [
|
||||
$routes->post('action', 'NoteController::attemptAction/$1/$2', [
|
||||
'as' => 'note-attempt-action',
|
||||
'filter' => 'permission:podcast-interact_as',
|
||||
]);
|
||||
|
||||
$routes->post('block-actor', 'Note::attemptBlockActor/$1/$2', [
|
||||
'as' => 'note-attempt-block-actor',
|
||||
'filter' => 'permission:fediverse-block_actors',
|
||||
]);
|
||||
$routes->post('block-domain', 'Note::attemptBlockDomain/$1/$2', [
|
||||
'as' => 'note-attempt-block-domain',
|
||||
'filter' => 'permission:fediverse-block_domains',
|
||||
]);
|
||||
$routes->post('delete', 'Note::attemptDelete/$1/$2', [
|
||||
$routes->post(
|
||||
'block-actor',
|
||||
'NoteController::attemptBlockActor/$1/$2',
|
||||
[
|
||||
'as' => 'note-attempt-block-actor',
|
||||
'filter' => 'permission:fediverse-block_actors',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'block-domain',
|
||||
'NoteController::attemptBlockDomain/$1/$2',
|
||||
[
|
||||
'as' => 'note-attempt-block-domain',
|
||||
'filter' => 'permission:fediverse-block_domains',
|
||||
],
|
||||
);
|
||||
$routes->post('delete', 'NoteController::attemptDelete/$1/$2', [
|
||||
'as' => 'note-attempt-delete',
|
||||
'filter' => 'permission:podcast-manage_publications',
|
||||
]);
|
||||
|
||||
$routes->get('remote/(:noteAction)', 'Note::remoteAction/$1/$2/$3', [
|
||||
'as' => 'note-remote-action',
|
||||
]);
|
||||
$routes->get(
|
||||
'remote/(:noteAction)',
|
||||
'NoteController::remoteAction/$1/$2/$3',
|
||||
[
|
||||
'as' => 'note-remote-action',
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
$routes->get('follow', 'Actor::follow/$1', [
|
||||
$routes->get('follow', 'ActorController::follow/$1', [
|
||||
'as' => 'follow',
|
||||
]);
|
||||
$routes->get('outbox', 'Actor::outbox/$1', [
|
||||
$routes->get('outbox', 'ActorController::outbox/$1', [
|
||||
'as' => 'outbox',
|
||||
'filter' => 'activity-pub:verify-activitystream',
|
||||
]);
|
||||
|
|
|
@ -101,11 +101,11 @@ class Services extends BaseService
|
|||
|
||||
$instance = new $class($config);
|
||||
|
||||
if (empty($userModel)) {
|
||||
if ($userModel === null) {
|
||||
$userModel = new UserModel();
|
||||
}
|
||||
|
||||
if (empty($loginModel)) {
|
||||
if ($loginModel === null) {
|
||||
$loginModel = new LoginModel();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use ActivityPub\Controllers\ActorController as ActivityPubActorController;
|
||||
use Analytics\AnalyticsTrait;
|
||||
|
||||
class Actor extends \ActivityPub\Controllers\ActorController
|
||||
class ActorController extends ActivityPubActorController
|
||||
{
|
||||
use AnalyticsTrait;
|
||||
|
|
@ -16,7 +16,7 @@ use App\Authorization\GroupModel;
|
|||
use App\Models\PodcastModel;
|
||||
use App\Models\UserModel;
|
||||
|
||||
class Contributor extends BaseController
|
||||
class ContributorController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast
|
||||
|
@ -172,7 +172,7 @@ class Contributor extends BaseController
|
|||
|
||||
public function remove()
|
||||
{
|
||||
if ($this->podcast->created_by == $this->user->id) {
|
||||
if ($this->podcast->created_by === $this->user->id) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('errors', [
|
|
@ -8,15 +8,16 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Episode as EpisodeEntity;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Note;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\NoteModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\SoundbiteModel;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
class Episode extends BaseController
|
||||
class EpisodeController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast
|
||||
|
@ -28,12 +29,7 @@ class Episode extends BaseController
|
|||
*/
|
||||
protected $episode;
|
||||
|
||||
/**
|
||||
* @var Soundbite|null
|
||||
*/
|
||||
protected $soundbites;
|
||||
|
||||
public function _remap($method, ...$params)
|
||||
public function _remap(string $method, ...$params)
|
||||
{
|
||||
if (
|
||||
!($this->podcast = (new PodcastModel())->getPodcastById($params[0]))
|
||||
|
@ -124,7 +120,7 @@ class Episode extends BaseController
|
|||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$newEpisode = new EpisodeEntity([
|
||||
$newEpisode = new Episode([
|
||||
'podcast_id' => $this->podcast->id,
|
||||
'title' => $this->request->getPost('title'),
|
||||
'slug' => $this->request->getPost('slug'),
|
||||
|
@ -148,8 +144,8 @@ class Episode extends BaseController
|
|||
'type' => $this->request->getPost('type'),
|
||||
'is_blocked' => $this->request->getPost('block') == 'yes',
|
||||
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
'published_at' => null,
|
||||
]);
|
||||
|
||||
|
@ -265,14 +261,15 @@ class Episode extends BaseController
|
|||
'custom_rss',
|
||||
);
|
||||
|
||||
$this->episode->updated_by = user()->id;
|
||||
$this->episode->updated_by = user_id();
|
||||
|
||||
$audioFile = $this->request->getFile('audio_file');
|
||||
if ($audioFile) {
|
||||
if ($audioFile !== null && $audioFile->isValid()) {
|
||||
$this->episode->audio_file = $audioFile;
|
||||
}
|
||||
|
||||
$image = $this->request->getFile('image');
|
||||
if ($image) {
|
||||
if ($image !== null && $image->isValid()) {
|
||||
$this->episode->image = $image;
|
||||
}
|
||||
|
||||
|
@ -291,7 +288,7 @@ class Episode extends BaseController
|
|||
) {
|
||||
if (
|
||||
($transcriptFile = $this->episode->transcript_file) &&
|
||||
!empty($transcriptFile)
|
||||
$transcriptFile !== null
|
||||
) {
|
||||
unlink($transcriptFile);
|
||||
$this->episode->transcript_file_path = null;
|
||||
|
@ -315,7 +312,7 @@ class Episode extends BaseController
|
|||
) {
|
||||
if (
|
||||
($chaptersFile = $this->episode->chapters_file) &&
|
||||
!empty($chaptersFile)
|
||||
$chaptersFile !== null
|
||||
) {
|
||||
unlink($chaptersFile);
|
||||
$this->episode->chapters_file_path = null;
|
||||
|
@ -700,8 +697,8 @@ class Episode extends BaseController
|
|||
|
||||
foreach ($soundbites_array as $soundbite_id => $soundbite) {
|
||||
if (
|
||||
!empty($soundbite['start_time']) &&
|
||||
!empty($soundbite['duration'])
|
||||
$soundbite['start_time'] !== null &&
|
||||
$soundbite['duration'] !== null
|
||||
) {
|
||||
$data = [
|
||||
'podcast_id' => $this->podcast->id,
|
||||
|
@ -709,10 +706,10 @@ class Episode extends BaseController
|
|||
'start_time' => $soundbite['start_time'],
|
||||
'duration' => $soundbite['duration'],
|
||||
'label' => $soundbite['label'],
|
||||
'updated_by' => user()->id,
|
||||
'updated_by' => user_id(),
|
||||
];
|
||||
if ($soundbite_id == 0) {
|
||||
$data += ['created_by' => user()->id];
|
||||
$data += ['created_by' => user_id()];
|
||||
} else {
|
||||
$data += ['id' => $soundbite_id];
|
||||
}
|
|
@ -16,7 +16,7 @@ use App\Models\PodcastModel;
|
|||
use App\Models\EpisodeModel;
|
||||
use App\Models\PersonModel;
|
||||
|
||||
class EpisodePerson extends BaseController
|
||||
class EpisodePersonController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
class Fediverse extends BaseController
|
||||
class FediverseController extends BaseController
|
||||
{
|
||||
public function dashboard()
|
||||
{
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
class Home extends BaseController
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
|
@ -11,7 +11,7 @@ namespace App\Controllers\Admin;
|
|||
use Config\Services;
|
||||
use App\Models\UserModel;
|
||||
|
||||
class MyAccount extends BaseController
|
||||
class MyAccountController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ class MyAccount extends BaseController
|
|||
|
||||
user()->password = $this->request->getPost('new_password');
|
||||
|
||||
if (!$userModel->update(user()->id, user())) {
|
||||
if (!$userModel->update(user_id(), user())) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Page as EntitiesPage;
|
||||
use App\Entities\Page;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PageModel;
|
||||
|
||||
class Page extends BaseController
|
||||
class PageController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Page|null
|
||||
|
@ -55,10 +55,10 @@ class Page extends BaseController
|
|||
|
||||
function attemptCreate()
|
||||
{
|
||||
$page = new EntitiesPage([
|
||||
$page = new Page([
|
||||
'title' => $this->request->getPost('title'),
|
||||
'slug' => $this->request->getPost('slug'),
|
||||
'content' => $this->request->getPost('content'),
|
||||
'content_markdown' => $this->request->getPost('content'),
|
||||
]);
|
||||
|
||||
$pageModel = new PageModel();
|
||||
|
@ -92,7 +92,7 @@ class Page extends BaseController
|
|||
{
|
||||
$this->page->title = $this->request->getPost('title');
|
||||
$this->page->slug = $this->request->getPost('slug');
|
||||
$this->page->content = $this->request->getPost('content');
|
||||
$this->page->content_markdown = $this->request->getPost('content');
|
||||
|
||||
$pageModel = new PageModel();
|
||||
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Person as EntitiesPerson;
|
||||
use App\Entities\Person;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PersonModel;
|
||||
|
||||
class Person extends BaseController
|
||||
class PersonController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Person|null
|
||||
|
@ -68,13 +68,13 @@ class Person extends BaseController
|
|||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$person = new EntitiesPerson([
|
||||
$person = new Person([
|
||||
'full_name' => $this->request->getPost('full_name'),
|
||||
'unique_name' => $this->request->getPost('unique_name'),
|
||||
'information_url' => $this->request->getPost('information_url'),
|
||||
'image' => $this->request->getFile('image'),
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
$personModel = new PersonModel();
|
||||
|
@ -125,7 +125,7 @@ class Person extends BaseController
|
|||
$this->person->image = $image;
|
||||
}
|
||||
|
||||
$this->person->updated_by = user()->id;
|
||||
$this->person->updated_by = user_id();
|
||||
|
||||
$personModel = new PersonModel();
|
||||
if (!$personModel->update($this->person->id, $this->person)) {
|
|
@ -8,23 +8,30 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Podcast as EntitiesPodcast;
|
||||
use App\Entities\Image;
|
||||
use App\Entities\Podcast;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Config\Database;
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\LanguageModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Services;
|
||||
|
||||
class Podcast extends BaseController
|
||||
class PodcastController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast|null
|
||||
* @var Podcast
|
||||
*/
|
||||
protected $podcast;
|
||||
|
||||
public function _remap($method, ...$params)
|
||||
/**
|
||||
*
|
||||
* @param array<string> $params
|
||||
* @return static|string
|
||||
*/
|
||||
public function _remap(string $method, ...$params)
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
|
@ -37,11 +44,13 @@ class Podcast extends BaseController
|
|||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
public function list()
|
||||
public function list(): string
|
||||
{
|
||||
if (!has_permission('podcasts-list')) {
|
||||
$data = [
|
||||
'podcasts' => (new PodcastModel())->getUserPodcasts(user()->id),
|
||||
'podcasts' => (new PodcastModel())->getUserPodcasts(
|
||||
(int) user_id(),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
$data = ['podcasts' => (new PodcastModel())->findAll()];
|
||||
|
@ -50,7 +59,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/list', $data);
|
||||
}
|
||||
|
||||
public function view()
|
||||
public function view(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -58,7 +67,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/view', $data);
|
||||
}
|
||||
|
||||
public function viewAnalytics()
|
||||
public function viewAnalytics(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -66,7 +75,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/index', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsWebpages()
|
||||
public function viewAnalyticsWebpages(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -74,7 +83,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/webpages', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsLocations()
|
||||
public function viewAnalyticsLocations(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -82,7 +91,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/locations', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsUniqueListeners()
|
||||
public function viewAnalyticsUniqueListeners(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -90,7 +99,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/unique_listeners', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsListeningTime()
|
||||
public function viewAnalyticsListeningTime(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -98,7 +107,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/listening_time', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsTimePeriods()
|
||||
public function viewAnalyticsTimePeriods(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -106,7 +115,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/time_periods', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsPlayers()
|
||||
public function viewAnalyticsPlayers(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
|
||||
|
@ -114,7 +123,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/analytics/players', $data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
public function create(): string
|
||||
{
|
||||
helper(['form', 'misc']);
|
||||
|
||||
|
@ -132,7 +141,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/create', $data);
|
||||
}
|
||||
|
||||
public function attemptCreate()
|
||||
public function attemptCreate(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'image' =>
|
||||
|
@ -146,11 +155,11 @@ class Podcast extends BaseController
|
|||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$podcast = new EntitiesPodcast([
|
||||
$podcast = new Podcast([
|
||||
'title' => $this->request->getPost('title'),
|
||||
'name' => $this->request->getPost('name'),
|
||||
'description_markdown' => $this->request->getPost('description'),
|
||||
'image' => $this->request->getFile('image'),
|
||||
'image' => new Image($this->request->getFile('image')),
|
||||
'language_code' => $this->request->getPost('language'),
|
||||
'category_id' => $this->request->getPost('category'),
|
||||
'parental_advisory' =>
|
||||
|
@ -171,8 +180,8 @@ class Podcast extends BaseController
|
|||
'is_blocked' => $this->request->getPost('block') === 'yes',
|
||||
'is_completed' => $this->request->getPost('complete') === 'yes',
|
||||
'is_locked' => $this->request->getPost('lock') === 'yes',
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
$podcastModel = new PodcastModel();
|
||||
|
@ -192,14 +201,14 @@ class Podcast extends BaseController
|
|||
$podcastAdminGroup = $authorize->group('podcast_admin');
|
||||
|
||||
$podcastModel->addPodcastContributor(
|
||||
user()->id,
|
||||
user_id(),
|
||||
$newPodcastId,
|
||||
$podcastAdminGroup->id,
|
||||
);
|
||||
|
||||
// set Podcast categories
|
||||
(new CategoryModel())->setPodcastCategories(
|
||||
$newPodcastId,
|
||||
(int) $newPodcastId,
|
||||
$this->request->getPost('other_categories'),
|
||||
);
|
||||
|
||||
|
@ -212,7 +221,7 @@ class Podcast extends BaseController
|
|||
return redirect()->route('podcast-view', [$newPodcastId]);
|
||||
}
|
||||
|
||||
public function edit()
|
||||
public function edit(): string
|
||||
{
|
||||
helper('form');
|
||||
|
||||
|
@ -229,7 +238,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/edit', $data);
|
||||
}
|
||||
|
||||
public function attemptEdit()
|
||||
public function attemptEdit(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'image' =>
|
||||
|
@ -249,8 +258,8 @@ class Podcast extends BaseController
|
|||
);
|
||||
|
||||
$image = $this->request->getFile('image');
|
||||
if ($image->isValid()) {
|
||||
$this->podcast->image = $image;
|
||||
if ($image !== null && $image->isValid()) {
|
||||
$this->podcast->image = new Image($image);
|
||||
}
|
||||
$this->podcast->language_code = $this->request->getPost('language');
|
||||
$this->podcast->category_id = $this->request->getPost('category');
|
||||
|
@ -281,7 +290,7 @@ class Podcast extends BaseController
|
|||
$this->podcast->is_completed =
|
||||
$this->request->getPost('complete') === 'yes';
|
||||
$this->podcast->is_locked = $this->request->getPost('lock') === 'yes';
|
||||
$this->podcast->updated_by = user()->id;
|
||||
$this->podcast->updated_by = (int) user_id();
|
||||
|
||||
$db = Database::connect();
|
||||
$db->transStart();
|
||||
|
@ -306,7 +315,7 @@ class Podcast extends BaseController
|
|||
return redirect()->route('podcast-view', [$this->podcast->id]);
|
||||
}
|
||||
|
||||
public function latestEpisodes(int $limit, int $podcast_id)
|
||||
public function latestEpisodes(int $limit, int $podcast_id): string
|
||||
{
|
||||
$episodes = (new EpisodeModel())
|
||||
->where('podcast_id', $podcast_id)
|
||||
|
@ -316,7 +325,7 @@ class Podcast extends BaseController
|
|||
return view('admin/podcast/latest_episodes', ['episodes' => $episodes]);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
public function delete(): RedirectResponse
|
||||
{
|
||||
(new PodcastModel())->delete($this->podcast->id);
|
||||
|
|
@ -15,6 +15,7 @@ use Config\Database;
|
|||
use Podlibre\PodcastNamespace\ReversedTaxonomy;
|
||||
use App\Entities\PodcastPerson;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Image;
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\LanguageModel;
|
||||
use App\Models\PodcastModel;
|
||||
|
@ -26,14 +27,14 @@ use App\Models\EpisodePersonModel;
|
|||
use Config\Services;
|
||||
use League\HTMLToMarkdown\HtmlConverter;
|
||||
|
||||
class PodcastImport extends BaseController
|
||||
class PodcastImportController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast|null
|
||||
*/
|
||||
protected $podcast;
|
||||
|
||||
public function _remap($method, ...$params)
|
||||
public function _remap(string $method, string ...$params)
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
|
@ -120,6 +121,19 @@ class PodcastImport extends BaseController
|
|||
$channelDescriptionHtml = (string) $feed->channel[0]->description;
|
||||
|
||||
try {
|
||||
if (
|
||||
$nsItunes->image !== null &&
|
||||
$nsItunes->image->attributes()['href'] !== null
|
||||
) {
|
||||
$imageFile = download_file(
|
||||
(string) $nsItunes->image->attributes()['href'],
|
||||
);
|
||||
} else {
|
||||
$imageFile = download_file(
|
||||
(string) $feed->channel[0]->image->url,
|
||||
);
|
||||
}
|
||||
|
||||
$podcast = new Podcast([
|
||||
'name' => $this->request->getPost('name'),
|
||||
'imported_feed_url' => $this->request->getPost(
|
||||
|
@ -133,50 +147,46 @@ class PodcastImport extends BaseController
|
|||
$channelDescriptionHtml,
|
||||
),
|
||||
'description_html' => $channelDescriptionHtml,
|
||||
'image' =>
|
||||
$nsItunes->image && !empty($nsItunes->image->attributes())
|
||||
? download_file((string) $nsItunes->image->attributes())
|
||||
: ($feed->channel[0]->image &&
|
||||
!empty($feed->channel[0]->image->url)
|
||||
? download_file(
|
||||
(string) $feed->channel[0]->image->url,
|
||||
)
|
||||
: null),
|
||||
'image' => new Image($imageFile),
|
||||
'language_code' => $this->request->getPost('language'),
|
||||
'category_id' => $this->request->getPost('category'),
|
||||
'parental_advisory' => empty($nsItunes->explicit)
|
||||
? null
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
? 'explicit'
|
||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
'parental_advisory' =>
|
||||
$nsItunes->explicit === null
|
||||
? null
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
? 'explicit'
|
||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
'owner_name' => (string) $nsItunes->owner->name,
|
||||
'owner_email' => (string) $nsItunes->owner->email,
|
||||
'publisher' => (string) $nsItunes->author,
|
||||
'type' => empty($nsItunes->type) ? 'episodic' : $nsItunes->type,
|
||||
'type' =>
|
||||
$nsItunes->type === null ? 'episodic' : $nsItunes->type,
|
||||
'copyright' => (string) $feed->channel[0]->copyright,
|
||||
'is_blocked' => empty($nsItunes->block)
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
'is_completed' => empty($nsItunes->complete)
|
||||
? false
|
||||
: $nsItunes->complete === 'yes',
|
||||
'is_blocked' =>
|
||||
$nsItunes->block === null
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
'is_completed' =>
|
||||
$nsItunes->complete === null
|
||||
? false
|
||||
: $nsItunes->complete === 'yes',
|
||||
'location_name' => $nsPodcast->location
|
||||
? (string) $nsPodcast->location
|
||||
: null,
|
||||
'location_geo' =>
|
||||
!$nsPodcast->location ||
|
||||
empty($nsPodcast->location->attributes()['geo'])
|
||||
$nsPodcast->location->attributes()['geo'] === null
|
||||
? null
|
||||
: (string) $nsPodcast->location->attributes()['geo'],
|
||||
'location_osmid' =>
|
||||
'location_osm_id' =>
|
||||
!$nsPodcast->location ||
|
||||
empty($nsPodcast->location->attributes()['osm'])
|
||||
$nsPodcast->location->attributes()['osm'] === null
|
||||
? null
|
||||
: (string) $nsPodcast->location->attributes()['osm'],
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
]);
|
||||
} catch (ErrorException $ex) {
|
||||
return redirect()
|
||||
|
@ -209,7 +219,7 @@ class PodcastImport extends BaseController
|
|||
$podcastAdminGroup = $authorize->group('podcast_admin');
|
||||
|
||||
$podcastModel->addPodcastContributor(
|
||||
user()->id,
|
||||
user_id(),
|
||||
$newPodcastId,
|
||||
$podcastAdminGroup->id,
|
||||
);
|
||||
|
@ -236,6 +246,7 @@ class PodcastImport extends BaseController
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($podcastsPlatformsData) > 1) {
|
||||
$platformModel->createPodcastPlatforms(
|
||||
$newPodcastId,
|
||||
|
@ -261,14 +272,15 @@ class PodcastImport extends BaseController
|
|||
->with('errors', $personModel->errors());
|
||||
}
|
||||
|
||||
$personGroup = empty($podcastPerson->attributes()['group'])
|
||||
? ['slug' => '']
|
||||
: ReversedTaxonomy::$taxonomy[
|
||||
(string) $podcastPerson->attributes()['group']
|
||||
];
|
||||
$personGroup =
|
||||
$podcastPerson->attributes()['group'] === null
|
||||
? ['slug' => '']
|
||||
: ReversedTaxonomy::$taxonomy[
|
||||
(string) $podcastPerson->attributes()['group']
|
||||
];
|
||||
$personRole =
|
||||
empty($podcastPerson->attributes()['role']) ||
|
||||
empty($personGroup)
|
||||
$podcastPerson->attributes()['role'] === null ||
|
||||
$personGroup === null
|
||||
? ['slug' => '']
|
||||
: $personGroup['roles'][
|
||||
strval($podcastPerson->attributes()['role'])
|
||||
|
@ -291,7 +303,7 @@ class PodcastImport extends BaseController
|
|||
|
||||
$numberItems = $feed->channel[0]->item->count();
|
||||
$lastItem =
|
||||
!empty($this->request->getPost('max_episodes')) &&
|
||||
$this->request->getPost('max_episodes') !== null &&
|
||||
$this->request->getPost('max_episodes') < $numberItems
|
||||
? $this->request->getPost('max_episodes')
|
||||
: $numberItems;
|
||||
|
@ -343,63 +355,71 @@ class PodcastImport extends BaseController
|
|||
$itemDescriptionHtml = $item->description;
|
||||
}
|
||||
|
||||
if (
|
||||
$nsItunes->image !== null &&
|
||||
$nsItunes->image->attributes()['href'] !== null
|
||||
) {
|
||||
$episodeImage = new Image(
|
||||
download_file(
|
||||
(string) $nsItunes->image->attributes()['href'],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
$episodeImage = null;
|
||||
}
|
||||
|
||||
$newEpisode = new Episode([
|
||||
'podcast_id' => $newPodcastId,
|
||||
'guid' => empty($item->guid) ? null : $item->guid,
|
||||
'guid' => $item->guid ?? null,
|
||||
'title' => $item->title,
|
||||
'slug' => $slug,
|
||||
'audio_file' => download_file($item->enclosure->attributes()),
|
||||
'audio_file' => download_file(
|
||||
$item->enclosure->attributes()['url'],
|
||||
),
|
||||
'description_markdown' => $converter->convert(
|
||||
$itemDescriptionHtml,
|
||||
),
|
||||
'description_html' => $itemDescriptionHtml,
|
||||
'image' =>
|
||||
!$nsItunes->image || empty($nsItunes->image->attributes())
|
||||
'image' => $episodeImage,
|
||||
'parental_advisory' =>
|
||||
$nsItunes->explicit === null
|
||||
? null
|
||||
: download_file(
|
||||
(string) $nsItunes->image->attributes(),
|
||||
),
|
||||
'parental_advisory' => empty($nsItunes->explicit)
|
||||
? null
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
? 'explicit'
|
||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
? 'explicit'
|
||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
'number' =>
|
||||
$this->request->getPost('force_renumber') === 'yes'
|
||||
? $itemNumber
|
||||
: (empty($nsItunes->episode)
|
||||
? null
|
||||
: $nsItunes->episode),
|
||||
'season_number' => empty(
|
||||
$this->request->getPost('season_number')
|
||||
)
|
||||
? (empty($nsItunes->season)
|
||||
? null
|
||||
: $nsItunes->season)
|
||||
: $this->request->getPost('season_number'),
|
||||
'type' => empty($nsItunes->episodeType)
|
||||
? 'full'
|
||||
: $nsItunes->episodeType,
|
||||
'is_blocked' => empty($nsItunes->block)
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
: $nsItunes->episode,
|
||||
'season_number' =>
|
||||
$this->request->getPost('season_number') === null
|
||||
? $nsItunes->season
|
||||
: $this->request->getPost('season_number'),
|
||||
'type' =>
|
||||
$nsItunes->episodeType === null
|
||||
? 'full'
|
||||
: $nsItunes->episodeType,
|
||||
'is_blocked' =>
|
||||
$nsItunes->block === null
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
'location_name' => $nsPodcast->location
|
||||
? $nsPodcast->location
|
||||
: null,
|
||||
'location_geo' =>
|
||||
!$nsPodcast->location ||
|
||||
empty($nsPodcast->location->attributes()['geo'])
|
||||
$nsPodcast->location->attributes()['geo'] === null
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['geo'],
|
||||
'location_osmid' =>
|
||||
'location_osm_id' =>
|
||||
!$nsPodcast->location ||
|
||||
empty($nsPodcast->location->attributes()['osm'])
|
||||
$nsPodcast->location->attributes()['osm'] === null
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['osm'],
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
'published_at' => strtotime($item->pubDate),
|
||||
]);
|
||||
|
||||
|
@ -431,14 +451,15 @@ class PodcastImport extends BaseController
|
|||
->with('errors', $personModel->errors());
|
||||
}
|
||||
|
||||
$personGroup = empty($episodePerson->attributes()['group'])
|
||||
? ['slug' => '']
|
||||
: ReversedTaxonomy::$taxonomy[
|
||||
strval($episodePerson->attributes()['group'])
|
||||
];
|
||||
$personGroup =
|
||||
$episodePerson->attributes()['group'] === null
|
||||
? ['slug' => '']
|
||||
: ReversedTaxonomy::$taxonomy[
|
||||
strval($episodePerson->attributes()['group'])
|
||||
];
|
||||
$personRole =
|
||||
empty($episodePerson->attributes()['role']) ||
|
||||
empty($personGroup)
|
||||
$episodePerson->attributes()['role'] === null ||
|
||||
$personGroup === null
|
||||
? ['slug' => '']
|
||||
: $personGroup['roles'][
|
||||
strval($episodePerson->attributes()['role'])
|
|
@ -14,7 +14,7 @@ use App\Models\PodcastPersonModel;
|
|||
use App\Models\PodcastModel;
|
||||
use App\Models\PersonModel;
|
||||
|
||||
class PodcastPerson extends BaseController
|
||||
class PodcastPersonController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast
|
|
@ -14,7 +14,7 @@ use App\Models\PlatformModel;
|
|||
use App\Models\PodcastModel;
|
||||
use Config\Services;
|
||||
|
||||
class PodcastPlatform extends BaseController
|
||||
class PodcastPlatformController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast|null
|
||||
|
@ -69,7 +69,7 @@ class PodcastPlatform extends BaseController
|
|||
as $platformSlug => $podcastPlatform
|
||||
) {
|
||||
$podcastPlatformUrl = $podcastPlatform['url'];
|
||||
if (empty($podcastPlatformUrl)) {
|
||||
if ($podcastPlatformUrl === null) {
|
||||
continue;
|
||||
}
|
||||
if (!$validation->check($podcastPlatformUrl, 'validate_url')) {
|
|
@ -10,11 +10,11 @@ namespace App\Controllers\Admin;
|
|||
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Authorization\GroupModel;
|
||||
use App\Entities\User as EntitiesUser;
|
||||
use App\Entities\User;
|
||||
use App\Models\UserModel;
|
||||
use Config\Services;
|
||||
|
||||
class User extends BaseController
|
||||
class UserController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var User|null
|
||||
|
@ -82,7 +82,7 @@ class User extends BaseController
|
|||
}
|
||||
|
||||
// Save the user
|
||||
$user = new EntitiesUser($this->request->getPost());
|
||||
$user = new User($this->request->getPost());
|
||||
|
||||
// Activate user
|
||||
$user->activate();
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Myth\Auth\Controllers\AuthController;
|
||||
use Myth\Auth\Controllers\AuthController as MythAuthController;
|
||||
use App\Entities\User;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class Auth extends AuthController
|
||||
class AuthController extends MythAuthController
|
||||
{
|
||||
/**
|
||||
* An array of helpers to be automatically loaded
|
||||
|
@ -66,7 +66,7 @@ class Auth extends AuthController
|
|||
: $user->activate();
|
||||
|
||||
// Ensure default group gets assigned if set
|
||||
if (!empty($this->config->defaultUserGroup)) {
|
||||
if ($this->config->defaultUserGroup !== null) {
|
||||
$users = $users->withGroup($this->config->defaultUserGroup);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ class Auth extends AuthController
|
|||
|
||||
// Reset token still valid?
|
||||
if (
|
||||
!empty($user->reset_expires) &&
|
||||
$user->reset_expires !== null &&
|
||||
time() > $user->reset_expires->getTimestamp()
|
||||
) {
|
||||
return redirect()
|
|
@ -9,12 +9,14 @@
|
|||
namespace App\Controllers;
|
||||
|
||||
use Analytics\AnalyticsTrait;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class Episode extends BaseController
|
||||
class EpisodeController extends BaseController
|
||||
{
|
||||
use AnalyticsTrait;
|
||||
|
||||
|
@ -162,7 +164,7 @@ class Episode extends BaseController
|
|||
'author_url' => $this->podcast->link,
|
||||
'html' =>
|
||||
'<iframe src="' .
|
||||
$this->episode->embeddable_player .
|
||||
$this->episode->embeddable_player_url .
|
||||
'" width="100%" height="200" frameborder="0" scrolling="no"></iframe>',
|
||||
'width' => 600,
|
||||
'height' => 200,
|
||||
|
@ -192,12 +194,12 @@ class Episode extends BaseController
|
|||
'html',
|
||||
htmlentities(
|
||||
'<iframe src="' .
|
||||
$this->episode->embeddable_player .
|
||||
$this->episode->embeddable_player_url .
|
||||
'" width="100%" height="200" frameborder="0" scrolling="no"></iframe>',
|
||||
),
|
||||
);
|
||||
$oembed->addChild('width', 600);
|
||||
$oembed->addChild('height', 200);
|
||||
$oembed->addChild('width', '600');
|
||||
$oembed->addChild('height', '200');
|
||||
|
||||
return $this->response->setXML($oembed);
|
||||
}
|
|
@ -16,9 +16,9 @@ use App\Models\EpisodeModel;
|
|||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Controller;
|
||||
|
||||
class Feed extends Controller
|
||||
class FeedController extends Controller
|
||||
{
|
||||
public function index($podcastName): ResponseInterface
|
||||
public function index(string $podcastName): ResponseInterface
|
||||
{
|
||||
helper('rss');
|
||||
|
||||
|
@ -27,17 +27,19 @@ class Feed extends Controller
|
|||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
$serviceSlug = '';
|
||||
$service = null;
|
||||
try {
|
||||
$service = UserAgentsRSS::find($_SERVER['HTTP_USER_AGENT']);
|
||||
if ($service) {
|
||||
$serviceSlug = $service['slug'];
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
// If things go wrong the show must go on and the user must be able to download the file
|
||||
log_message('critical', $exception);
|
||||
}
|
||||
|
||||
$serviceSlug = null;
|
||||
if ($service) {
|
||||
$serviceSlug = $service['slug'];
|
||||
}
|
||||
|
||||
$cacheName =
|
||||
"podcast#{$podcast->id}_feed" . ($service ? "_{$serviceSlug}" : '');
|
||||
|
||||
|
@ -57,6 +59,7 @@ class Feed extends Controller
|
|||
: DECADE,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->response->setXML($found);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ namespace App\Controllers;
|
|||
|
||||
use App\Models\PodcastModel;
|
||||
|
||||
class Home extends BaseController
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
|
@ -22,7 +22,7 @@ use CodeIgniter\Controller;
|
|||
use Config\Services;
|
||||
use Dotenv\Dotenv;
|
||||
|
||||
class Install extends Controller
|
||||
class InstallController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
|
@ -50,15 +50,14 @@ class Install extends Controller
|
|||
*/
|
||||
public function index(): string
|
||||
{
|
||||
try {
|
||||
// Check if .env is created and has all required fields
|
||||
$dotenv = Dotenv::createUnsafeImmutable(ROOTPATH);
|
||||
|
||||
$dotenv->load();
|
||||
} catch (Throwable $e) {
|
||||
if (!file_exists(ROOTPATH . '.env')) {
|
||||
$this->createEnv();
|
||||
}
|
||||
|
||||
// Check if .env has all required fields
|
||||
$dotenv = Dotenv::createUnsafeImmutable(ROOTPATH);
|
||||
$dotenv->load();
|
||||
|
||||
// Check if the created .env file is writable to continue install process
|
||||
if (is_really_writable(ROOTPATH . '.env')) {
|
||||
try {
|
||||
|
@ -171,8 +170,9 @@ class Install extends Controller
|
|||
if (!$this->validate($rules)) {
|
||||
return redirect()
|
||||
->to(
|
||||
(empty(host_url()) ? config('App')->baseURL : host_url()) .
|
||||
config('App')->installGateway,
|
||||
(host_url() === null
|
||||
? config('App')->baseURL
|
||||
: host_url()) . config('App')->installGateway,
|
||||
)
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
|
@ -182,9 +182,8 @@ class Install extends Controller
|
|||
$mediaBaseUrl = $this->request->getPost('media_base_url');
|
||||
self::writeEnv([
|
||||
'app.baseURL' => $baseUrl,
|
||||
'app.mediaBaseURL' => empty($mediaBaseUrl)
|
||||
? $baseUrl
|
||||
: $mediaBaseUrl,
|
||||
'app.mediaBaseURL' =>
|
||||
$mediaBaseUrl === null ? $baseUrl : $mediaBaseUrl,
|
||||
'app.adminGateway' => $this->request->getPost('admin_gateway'),
|
||||
'app.authGateway' => $this->request->getPost('auth_gateway'),
|
||||
]);
|
||||
|
@ -192,7 +191,7 @@ class Install extends Controller
|
|||
helper('text');
|
||||
|
||||
// redirect to full install url with new baseUrl input
|
||||
return redirect(0)->to(
|
||||
return redirect()->to(
|
||||
reduce_double_slashes(
|
||||
$baseUrl . '/' . config('App')->installGateway,
|
||||
),
|
||||
|
@ -357,9 +356,9 @@ class Install extends Controller
|
|||
* writes config values in .env file
|
||||
* overwrites any existing key and appends new ones
|
||||
*
|
||||
* @param array $data key/value config pairs
|
||||
* @param array $configData key/value config pairs
|
||||
*/
|
||||
public static function writeEnv($configData): void
|
||||
public static function writeEnv(array $configData): void
|
||||
{
|
||||
$envData = file(ROOTPATH . '.env'); // reads an array of lines
|
||||
|
|
@ -8,17 +8,19 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use ActivityPub\Controllers\NoteController;
|
||||
use ActivityPub\Controllers\NoteController as ActivityPubNoteController;
|
||||
use ActivityPub\Entities\Note as ActivityPubNote;
|
||||
use Analytics\AnalyticsTrait;
|
||||
use App\Entities\Actor;
|
||||
use App\Entities\Note as CastopodNote;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
class Note extends NoteController
|
||||
class NoteController extends ActivityPubNoteController
|
||||
{
|
||||
use AnalyticsTrait;
|
||||
|
||||
|
@ -27,6 +29,11 @@ class Note extends NoteController
|
|||
*/
|
||||
protected $podcast;
|
||||
|
||||
/**
|
||||
* @var Actor
|
||||
*/
|
||||
protected $actor;
|
||||
|
||||
protected $helpers = ['auth', 'activitypub', 'svg', 'components', 'misc'];
|
||||
|
||||
public function _remap($method, ...$params)
|
||||
|
@ -52,7 +59,7 @@ class Note extends NoteController
|
|||
return $this->$method(...$params);
|
||||
}
|
||||
|
||||
public function index(): RedirectResponse
|
||||
public function view(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
|
@ -96,7 +103,7 @@ class Note extends NoteController
|
|||
return $cachedView;
|
||||
}
|
||||
|
||||
public function attemptCreate()
|
||||
public function attemptCreate(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'message' => 'required|max_length[500]',
|
||||
|
@ -153,7 +160,7 @@ class Note extends NoteController
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptReply()
|
||||
public function attemptReply(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'message' => 'required|max_length[500]',
|
||||
|
@ -185,7 +192,7 @@ class Note extends NoteController
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptFavourite()
|
||||
public function attemptFavourite(): RedirectResponse
|
||||
{
|
||||
model('FavouriteModel')->toggleFavourite(
|
||||
interact_as_actor(),
|
||||
|
@ -195,14 +202,14 @@ class Note extends NoteController
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptReblog()
|
||||
public function attemptReblog(): RedirectResponse
|
||||
{
|
||||
model('NoteModel')->toggleReblog(interact_as_actor(), $this->note);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptAction()
|
||||
public function attemptAction(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'action' => 'required|in_list[favourite,reblog,reply]',
|
||||
|
@ -215,17 +222,23 @@ class Note extends NoteController
|
|||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
switch ($this->request->getPost('action')) {
|
||||
$action = $this->request->getPost('action');
|
||||
switch ($action) {
|
||||
case 'favourite':
|
||||
return $this->attemptFavourite();
|
||||
case 'reblog':
|
||||
return $this->attemptReblog();
|
||||
case 'reply':
|
||||
return $this->attemptReply();
|
||||
default:
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
public function remoteAction($action)
|
||||
public function remoteAction(string $action): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
|
@ -258,6 +271,6 @@ class Note extends NoteController
|
|||
]);
|
||||
}
|
||||
|
||||
return $cachedView;
|
||||
return (string) $cachedView;
|
||||
}
|
||||
}
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Entities\Page as PageEntity;
|
||||
use App\Entities\Page;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PageModel;
|
||||
use App\Models\CreditModel;
|
||||
use App\Models\PodcastModel;
|
||||
|
||||
class Page extends BaseController
|
||||
class PageController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Page|null
|
||||
|
@ -60,10 +60,10 @@ class Page extends BaseController
|
|||
|
||||
$cacheName = "page_credits_{$locale}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$page = new PageEntity([
|
||||
$page = new Page([
|
||||
'title' => lang('Person.credits', [], $locale),
|
||||
'slug' => 'credits',
|
||||
'content' => '',
|
||||
'content_markdown' => '',
|
||||
]);
|
||||
|
||||
$allCredits = (new CreditModel())->findAll();
|
|
@ -15,7 +15,7 @@ use CodeIgniter\Controller;
|
|||
/*
|
||||
* Provide public access to all platforms so that they can be exported
|
||||
*/
|
||||
class Platform extends Controller
|
||||
class PlatformController extends Controller
|
||||
{
|
||||
public function index(): ResponseInterface
|
||||
{
|
|
@ -9,11 +9,12 @@
|
|||
namespace App\Controllers;
|
||||
|
||||
use Analytics\AnalyticsTrait;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\NoteModel;
|
||||
|
||||
class Podcast extends BaseController
|
||||
class PodcastController extends BaseController
|
||||
{
|
||||
use AnalyticsTrait;
|
||||
|
|
@ -142,7 +142,7 @@ class AddPodcasts extends Migration
|
|||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'location_osmid' => [
|
||||
'location_osm_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 12,
|
||||
'null' => true,
|
||||
|
@ -194,7 +194,7 @@ class AddPodcasts extends Migration
|
|||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('category_id', 'categories', 'id');
|
||||
|
|
|
@ -44,7 +44,8 @@ class AddEpisodes extends Migration
|
|||
'constraint' => 255,
|
||||
],
|
||||
'audio_file_duration' => [
|
||||
'type' => 'INT',
|
||||
// exact value for duration with max 99999,999 ~ 27.7 hours
|
||||
'type' => 'DECIMAL(8,3)',
|
||||
'unsigned' => true,
|
||||
'comment' => 'Playtime in seconds',
|
||||
],
|
||||
|
@ -136,7 +137,7 @@ class AddEpisodes extends Migration
|
|||
'constraint' => 32,
|
||||
'null' => true,
|
||||
],
|
||||
'location_osmid' => [
|
||||
'location_osm_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 12,
|
||||
'null' => true,
|
||||
|
@ -189,7 +190,7 @@ class AddEpisodes extends Migration
|
|||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||
|
|
|
@ -32,10 +32,10 @@ class AddSoundbites extends Migration
|
|||
'unsigned' => true,
|
||||
],
|
||||
'start_time' => [
|
||||
'type' => 'FLOAT',
|
||||
'type' => 'DECIMAL(8,3)',
|
||||
],
|
||||
'duration' => [
|
||||
'type' => 'FLOAT',
|
||||
'type' => 'DECIMAL(8,3)',
|
||||
],
|
||||
'label' => [
|
||||
'type' => 'VARCHAR',
|
||||
|
@ -67,14 +67,14 @@ class AddSoundbites extends Migration
|
|||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'episode_id',
|
||||
'episodes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||
|
|
|
@ -32,19 +32,19 @@ class AddPodcastsUsers extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['user_id', 'podcast_id']);
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', false, 'CASCADE');
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', '', 'CASCADE');
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'group_id',
|
||||
'auth_groups',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('podcasts_users');
|
||||
|
|
|
@ -32,7 +32,10 @@ class AddPages extends Migration
|
|||
'constraint' => 191,
|
||||
'unique' => true,
|
||||
],
|
||||
'content' => [
|
||||
'content_markdown' => [
|
||||
'type' => 'TEXT',
|
||||
],
|
||||
'content_html' => [
|
||||
'type' => 'TEXT',
|
||||
],
|
||||
'created_at' => [
|
||||
|
|
|
@ -32,14 +32,14 @@ class AddPodcastsCategories extends Migration
|
|||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'category_id',
|
||||
'categories',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('podcasts_categories');
|
||||
|
|
|
@ -51,14 +51,14 @@ class AddPodcastsPersons extends Migration
|
|||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'person_id',
|
||||
'persons',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('podcasts_persons');
|
||||
|
|
|
@ -56,21 +56,21 @@ class AddEpisodesPersons extends Migration
|
|||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'episode_id',
|
||||
'episodes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'person_id',
|
||||
'persons',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('episodes_persons');
|
||||
|
|
|
@ -307,13 +307,14 @@ class AuthSeeder extends Seeder
|
|||
/**
|
||||
* @param array<string, string|int>[] $dataGroups
|
||||
*/
|
||||
static function getGroupIdByName(string $name, array $dataGroups): int
|
||||
static function getGroupIdByName(string $name, array $dataGroups): ?int
|
||||
{
|
||||
foreach ($dataGroups as $group) {
|
||||
if ($group['name'] === $name) {
|
||||
return $group['id'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,14 +69,14 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
|||
$age = floor(
|
||||
($date - strtotime($episode->published_at)) / 86400,
|
||||
);
|
||||
$proba1 = floor(exp(3 - $age / 40)) + 1;
|
||||
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
|
||||
|
||||
for (
|
||||
$num_line = 0;
|
||||
$num_line < rand(1, $proba1);
|
||||
$num_line < rand(1, $probability1);
|
||||
++$num_line
|
||||
) {
|
||||
$proba2 = floor(exp(6 - $age / 20)) + 10;
|
||||
$probability2 = (int) floor(exp(6 - $age / 20)) + 10;
|
||||
|
||||
$player =
|
||||
$jsonUserAgents[
|
||||
|
@ -127,7 +127,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
|||
//Bad luck, bad IP, nothing to do.
|
||||
}
|
||||
|
||||
$hits = rand(0, $proba2);
|
||||
$hits = rand(0, $probability2);
|
||||
|
||||
$analytics_podcasts[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
|
|
|
@ -206,14 +206,14 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
|||
$age = floor(
|
||||
($date - strtotime($episode->published_at)) / 86400,
|
||||
);
|
||||
$proba1 = floor(exp(3 - $age / 40)) + 1;
|
||||
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
|
||||
|
||||
for (
|
||||
$num_line = 0;
|
||||
$num_line < rand(1, $proba1);
|
||||
$num_line < rand(1, $probability1);
|
||||
++$num_line
|
||||
) {
|
||||
$proba2 = floor(exp(6 - $age / 20)) + 10;
|
||||
$probability2 = (int) floor(exp(6 - $age / 20)) + 10;
|
||||
|
||||
$domain =
|
||||
$this->domains[rand(0, count($this->domains) - 1)];
|
||||
|
@ -226,7 +226,7 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
|||
rand(0, count($this->browsers) - 1)
|
||||
];
|
||||
|
||||
$hits = rand(0, $proba2);
|
||||
$hits = rand(0, $probability2);
|
||||
|
||||
$website_by_browser[] = [
|
||||
'podcast_id' => $podcast->id,
|
||||
|
|
|
@ -8,13 +8,18 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use ActivityPub\Entities\Actor as ActivityPubActor;
|
||||
use App\Models\PodcastModel;
|
||||
use RuntimeException;
|
||||
|
||||
class Actor extends \ActivityPub\Entities\Actor
|
||||
/**
|
||||
* @property Podcast|null $podcast
|
||||
* @property boolean $is_podcast
|
||||
*/
|
||||
class Actor extends ActivityPubActor
|
||||
{
|
||||
/**
|
||||
* @var App\Entities\Podcast|null
|
||||
* @var Podcast|null
|
||||
*/
|
||||
protected $podcast;
|
||||
|
||||
|
@ -23,20 +28,20 @@ class Actor extends \ActivityPub\Entities\Actor
|
|||
*/
|
||||
protected $is_podcast;
|
||||
|
||||
public function getIsPodcast()
|
||||
public function getIsPodcast(): bool
|
||||
{
|
||||
return !empty($this->podcast);
|
||||
return $this->podcast !== null;
|
||||
}
|
||||
|
||||
public function getPodcast()
|
||||
public function getPodcast(): ?Podcast
|
||||
{
|
||||
if (empty($this->id)) {
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Actor must be created before getting associated podcast.',
|
||||
'Podcast id must be set before getting associated podcast.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->podcast)) {
|
||||
if ($this->podcast === null) {
|
||||
$this->podcast = (new PodcastModel())->getPodcastByActorId(
|
||||
$this->id,
|
||||
);
|
||||
|
|
|
@ -11,6 +11,14 @@ namespace App\Entities;
|
|||
use App\Models\CategoryModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $parent_id
|
||||
* @property Category|null $parent
|
||||
* @property string $code
|
||||
* @property string $apple_category
|
||||
* @property string $google_category
|
||||
*/
|
||||
class Category extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -23,7 +31,7 @@ class Category extends Entity
|
|||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'parent_id' => 'integer',
|
||||
'parent_id' => '?integer',
|
||||
'code' => 'string',
|
||||
'apple_category' => 'string',
|
||||
'google_category' => 'string',
|
||||
|
|
|
@ -14,6 +14,19 @@ use App\Models\PodcastModel;
|
|||
use App\Models\EpisodeModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $podcast_id
|
||||
* @property Podcast $podcast
|
||||
* @property int|null $episode_id
|
||||
* @property Episode|null $episode
|
||||
* @property string $full_name
|
||||
* @property string $person_group
|
||||
* @property string $group_label
|
||||
* @property string $person_role
|
||||
* @property string $role_label
|
||||
* @property int $person_id
|
||||
* @property Person $person
|
||||
*/
|
||||
class Credit extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -45,30 +58,57 @@ class Credit extends Entity
|
|||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'person_group' => 'string',
|
||||
'person_role' => 'string',
|
||||
'person_id' => 'integer',
|
||||
'full_name' => 'integer',
|
||||
'podcast_id' => 'integer',
|
||||
'episode_id' => '?integer',
|
||||
'person_id' => 'integer',
|
||||
'full_name' => 'string',
|
||||
'person_group' => 'string',
|
||||
'person_role' => 'string',
|
||||
];
|
||||
|
||||
public function getPerson(): Person
|
||||
{
|
||||
if ($this->person_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have person_id before getting person.',
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->person === null) {
|
||||
$this->person = (new PersonModel())->getPersonById(
|
||||
$this->person_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function getPodcast(): Podcast
|
||||
{
|
||||
return (new PodcastModel())->getPodcastById(
|
||||
$this->attributes['podcast_id'],
|
||||
);
|
||||
if ($this->podcast_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have podcast_id before getting podcast.',
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->podcast === null) {
|
||||
$this->podcast = (new PodcastModel())->getPodcastById(
|
||||
$this->podcast_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->podcast;
|
||||
}
|
||||
|
||||
public function getEpisode(): ?Episode
|
||||
{
|
||||
if (empty($this->episode_id)) {
|
||||
if ($this->episode_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have episode_id before getting episode.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->episode)) {
|
||||
if ($this->episode === null) {
|
||||
$this->episode = (new EpisodeModel())->getPublishedEpisodeById(
|
||||
$this->podcast_id,
|
||||
$this->episode_id,
|
||||
|
@ -78,40 +118,23 @@ class Credit extends Entity
|
|||
return $this->episode;
|
||||
}
|
||||
|
||||
public function getPerson(): Person
|
||||
public function getGroupLabel(): string
|
||||
{
|
||||
if (empty($this->person_id)) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have person_id before getting person.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->person)) {
|
||||
$this->person = (new PersonModel())->getPersonById(
|
||||
$this->person_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function getGroupLabel(): ?string
|
||||
{
|
||||
if (empty($this->person_group)) {
|
||||
return null;
|
||||
if ($this->person_group === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return lang("PersonsTaxonomy.persons.{$this->person_group}.label");
|
||||
}
|
||||
|
||||
public function getRoleLabel(): ?string
|
||||
public function getRoleLabel(): string
|
||||
{
|
||||
if (empty($this->person_group)) {
|
||||
return null;
|
||||
if ($this->person_group === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (empty($this->person_role)) {
|
||||
return null;
|
||||
if ($this->person_role === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return lang(
|
||||
|
|
|
@ -8,21 +8,77 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use App\Libraries\Image;
|
||||
use App\Entities\Location;
|
||||
use App\Libraries\SimpleRSSElement;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\SoundbiteModel;
|
||||
use App\Models\EpisodePersonModel;
|
||||
use App\Models\NoteModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use CodeIgniter\Files\Exceptions\FileNotFoundException;
|
||||
use CodeIgniter\Files\File;
|
||||
use CodeIgniter\HTTP\Exceptions\HTTPException;
|
||||
use CodeIgniter\HTTP\Files\UploadedFile;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $podcast_id
|
||||
* @property Podcast $podcast
|
||||
* @property string $link
|
||||
* @property string $guid
|
||||
* @property string $slug
|
||||
* @property string $title
|
||||
* @property File $audio_file
|
||||
* @property string $audio_file_url
|
||||
* @property string $audio_file_analytics_url
|
||||
* @property string $audio_file_web_url
|
||||
* @property string $audio_file_opengraph_url
|
||||
* @property string $audio_file_path
|
||||
* @property double $audio_file_duration
|
||||
* @property string $audio_file_mimetype
|
||||
* @property int $audio_file_size
|
||||
* @property int $audio_file_header_size
|
||||
* @property string $description Holds text only description, striped of any markdown or html special characters
|
||||
* @property string $description_markdown
|
||||
* @property string $description_html
|
||||
* @property Image $image
|
||||
* @property string|null $image_path
|
||||
* @property string|null $image_mimetype
|
||||
* @property File|null $transcript_file
|
||||
* @property string|null $transcript_file_url
|
||||
* @property string|null $transcript_file_path
|
||||
* @property string|null $transcript_file_remote_url
|
||||
* @property File|null $chapters_file
|
||||
* @property string|null $chapters_file_url
|
||||
* @property string|null $chapters_file_path
|
||||
* @property string|null $chapters_file_remote_url
|
||||
* @property string|null $parental_advisory
|
||||
* @property int $number
|
||||
* @property int $season_number
|
||||
* @property string $type
|
||||
* @property bool $is_blocked
|
||||
* @property Location $location
|
||||
* @property string|null $location_name
|
||||
* @property string|null $location_geo
|
||||
* @property string|null $location_osm_id
|
||||
* @property array|null $custom_rss
|
||||
* @property string $custom_rss_string
|
||||
* @property int $favourites_total
|
||||
* @property int $reblogs_total
|
||||
* @property int $notes_total
|
||||
* @property int $created_by
|
||||
* @property int $updated_by
|
||||
* @property string $publication_status;
|
||||
* @property Time|null $published_at;
|
||||
* @property Time $created_at;
|
||||
* @property Time $updated_at;
|
||||
* @property Time|null $deleted_at;
|
||||
*
|
||||
* @property EpisodePerson[] $persons;
|
||||
* @property Soundbite[] $soundbites;
|
||||
* @property string $embeddable_player_url;
|
||||
*/
|
||||
class Episode extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -35,25 +91,10 @@ class Episode extends Entity
|
|||
*/
|
||||
protected $link;
|
||||
|
||||
/**
|
||||
* @var Image
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $audioFile;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $transcript_file;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $chapters_file;
|
||||
protected $audio_file;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@ -75,6 +116,31 @@ class Episode extends Entity
|
|||
*/
|
||||
protected $audio_file_opengraph_url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $embeddable_player_url;
|
||||
|
||||
/**
|
||||
* @var Image
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $transcript_file;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $chapters_file;
|
||||
|
||||
/**
|
||||
* @var EpisodePerson[]
|
||||
*/
|
||||
|
@ -91,18 +157,14 @@ class Episode extends Entity
|
|||
protected $notes;
|
||||
|
||||
/**
|
||||
* Holds text only description, striped of any markdown or html special characters
|
||||
*
|
||||
* @var string
|
||||
* @var Location|null
|
||||
*/
|
||||
protected $description;
|
||||
protected $location;
|
||||
|
||||
/**
|
||||
* The embeddable player URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $embeddable_player;
|
||||
protected $custom_rss_string;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@ -110,12 +172,8 @@ class Episode extends Entity
|
|||
protected $publication_status;
|
||||
|
||||
/**
|
||||
* Return custom rss as string
|
||||
*
|
||||
* @var string
|
||||
* @var string[]
|
||||
*/
|
||||
protected $custom_rss_string;
|
||||
|
||||
protected $dates = [
|
||||
'published_at',
|
||||
'created_at',
|
||||
|
@ -123,6 +181,9 @@ class Episode extends Entity
|
|||
'deleted_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'podcast_id' => 'integer',
|
||||
|
@ -130,7 +191,7 @@ class Episode extends Entity
|
|||
'slug' => 'string',
|
||||
'title' => 'string',
|
||||
'audio_file_path' => 'string',
|
||||
'audio_file_duration' => 'integer',
|
||||
'audio_file_duration' => 'double',
|
||||
'audio_file_mimetype' => 'string',
|
||||
'audio_file_size' => 'integer',
|
||||
'audio_file_header_size' => 'integer',
|
||||
|
@ -149,7 +210,7 @@ class Episode extends Entity
|
|||
'is_blocked' => 'boolean',
|
||||
'location_name' => '?string',
|
||||
'location_geo' => '?string',
|
||||
'location_osmid' => '?string',
|
||||
'location_osm_id' => '?string',
|
||||
'custom_rss' => '?json-array',
|
||||
'favourites_total' => 'integer',
|
||||
'reblogs_total' => 'integer',
|
||||
|
@ -161,96 +222,79 @@ class Episode extends Entity
|
|||
/**
|
||||
* Saves an episode image
|
||||
*
|
||||
* @param UploadedFile|File $image
|
||||
* @param Image|null $image
|
||||
*/
|
||||
public function setImage($image)
|
||||
public function setImage($image = null): self
|
||||
{
|
||||
if (
|
||||
!empty($image) &&
|
||||
(!($image instanceof UploadedFile) || $image->isValid())
|
||||
) {
|
||||
helper('media');
|
||||
|
||||
// check whether the user has inputted an image and store
|
||||
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||
$this->attributes['image_path'] = save_media(
|
||||
$image,
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
$this->image = new Image(
|
||||
$this->attributes['image_path'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
if ($image === null) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Save image
|
||||
$image->saveImage(
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
|
||||
$this->attributes['image_mimetype'] = $image->mimetype;
|
||||
$this->attributes['image_path'] = $image->path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImage(): Image
|
||||
{
|
||||
if ($imagePath = $this->attributes['image_path']) {
|
||||
return new Image($imagePath, $this->attributes['image_mimetype']);
|
||||
return new Image(
|
||||
null,
|
||||
$imagePath,
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
}
|
||||
return $this->getPodcast()->image;
|
||||
|
||||
return $this->podcast->image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an audio file
|
||||
*
|
||||
* @param UploadedFile|File $audioFile
|
||||
*
|
||||
*/
|
||||
public function setAudioFile($audioFile = null)
|
||||
public function setAudioFile($audioFile)
|
||||
{
|
||||
if (
|
||||
!empty($audioFile) &&
|
||||
(!($audioFile instanceof UploadedFile) || $audioFile->isValid())
|
||||
) {
|
||||
helper(['media', 'id3']);
|
||||
helper(['media', 'id3']);
|
||||
|
||||
$audio_metadata = get_file_tags($audioFile);
|
||||
$audio_metadata = get_file_tags($audioFile);
|
||||
|
||||
$this->attributes['audio_file_path'] = save_media(
|
||||
$audioFile,
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
$this->attributes['audio_file_duration'] = round(
|
||||
$audio_metadata['playtime_seconds'],
|
||||
);
|
||||
$this->attributes['audio_file_mimetype'] =
|
||||
$audio_metadata['mime_type'];
|
||||
$this->attributes['audio_file_size'] = $audio_metadata['filesize'];
|
||||
$this->attributes['audio_file_header_size'] =
|
||||
$audio_metadata['avdataoffset'];
|
||||
$this->attributes['audio_file_path'] = save_media(
|
||||
$audioFile,
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
$this->attributes['audio_file_duration'] =
|
||||
$audio_metadata['playtime_seconds'];
|
||||
$this->attributes['audio_file_mimetype'] = $audio_metadata['mime_type'];
|
||||
$this->attributes['audio_file_size'] = $audio_metadata['filesize'];
|
||||
$this->attributes['audio_file_header_size'] =
|
||||
$audio_metadata['avdataoffset'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an episode transcript file
|
||||
*
|
||||
* @param UploadedFile|File $transcriptFile
|
||||
*
|
||||
*/
|
||||
public function setTranscriptFile($transcriptFile)
|
||||
{
|
||||
if (
|
||||
!empty($transcriptFile) &&
|
||||
(!($transcriptFile instanceof UploadedFile) ||
|
||||
$transcriptFile->isValid())
|
||||
) {
|
||||
helper('media');
|
||||
helper('media');
|
||||
|
||||
$this->attributes['transcript_file_path'] = save_media(
|
||||
$transcriptFile,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'] . '-transcript',
|
||||
);
|
||||
}
|
||||
$this->attributes['transcript_file_path'] = save_media(
|
||||
$transcriptFile,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'] . '-transcript',
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -259,35 +303,28 @@ class Episode extends Entity
|
|||
* Saves an episode chapters file
|
||||
*
|
||||
* @param UploadedFile|File $chaptersFile
|
||||
*
|
||||
*/
|
||||
public function setChaptersFile($chaptersFile)
|
||||
{
|
||||
if (
|
||||
!empty($chaptersFile) &&
|
||||
(!($chaptersFile instanceof UploadedFile) ||
|
||||
$chaptersFile->isValid())
|
||||
) {
|
||||
helper('media');
|
||||
helper('media');
|
||||
|
||||
$this->attributes['chapters_file_path'] = save_media(
|
||||
$chaptersFile,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'] . '-chapters',
|
||||
);
|
||||
}
|
||||
$this->attributes['chapters_file_path'] = save_media(
|
||||
$chaptersFile,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'] . '-chapters',
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAudioFile()
|
||||
public function getAudioFile(): File
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return new File(media_path($this->audio_file_path));
|
||||
}
|
||||
|
||||
public function getTranscriptFile()
|
||||
public function getTranscriptFile(): ?File
|
||||
{
|
||||
if ($this->attributes['transcript_file_path']) {
|
||||
helper('media');
|
||||
|
@ -300,7 +337,7 @@ class Episode extends Entity
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getChaptersFile()
|
||||
public function getChaptersFile(): ?File
|
||||
{
|
||||
if ($this->attributes['chapters_file_path']) {
|
||||
helper('media');
|
||||
|
@ -313,14 +350,14 @@ class Episode extends Entity
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getAudioFileUrl()
|
||||
public function getAudioFileUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->audio_file_path);
|
||||
}
|
||||
|
||||
public function getAudioFileAnalyticsUrl()
|
||||
public function getAudioFileAnalyticsUrl(): string
|
||||
{
|
||||
helper('analytics');
|
||||
|
||||
|
@ -335,12 +372,12 @@ class Episode extends Entity
|
|||
);
|
||||
}
|
||||
|
||||
public function getAudioFileWebUrl()
|
||||
public function getAudioFileWebUrl(): string
|
||||
{
|
||||
return $this->getAudioFileAnalyticsUrl() . '?_from=-+Website+-';
|
||||
}
|
||||
|
||||
public function getAudioFileOpengraphUrl()
|
||||
public function getAudioFileOpengraphUrl(): string
|
||||
{
|
||||
return $this->getAudioFileAnalyticsUrl() . '?_from=-+Open+Graph+-';
|
||||
}
|
||||
|
@ -348,12 +385,8 @@ class Episode extends Entity
|
|||
/**
|
||||
* Gets transcript url from transcript file uri if it exists
|
||||
* or returns the transcript_file_remote_url which can be null.
|
||||
*
|
||||
* @return string|null
|
||||
* @throws FileNotFoundException
|
||||
* @throws HTTPException
|
||||
*/
|
||||
public function getTranscriptFileUrl()
|
||||
public function getTranscriptFileUrl(): ?string
|
||||
{
|
||||
if ($this->attributes['transcript_file_path']) {
|
||||
return media_base_url($this->attributes['transcript_file_path']);
|
||||
|
@ -378,9 +411,9 @@ class Episode extends Entity
|
|||
/**
|
||||
* Returns the episode's persons
|
||||
*
|
||||
* @return \App\Entities\EpisodePerson[]
|
||||
* @return EpisodePerson[]
|
||||
*/
|
||||
public function getPersons()
|
||||
public function getPersons(): array
|
||||
{
|
||||
if (empty($this->id)) {
|
||||
throw new RuntimeException(
|
||||
|
@ -401,9 +434,9 @@ class Episode extends Entity
|
|||
/**
|
||||
* Returns the episode’s soundbites
|
||||
*
|
||||
* @return \App\Entities\Episode[]
|
||||
* @return Soundbite[]
|
||||
*/
|
||||
public function getSoundbites()
|
||||
public function getSoundbites(): array
|
||||
{
|
||||
if (empty($this->id)) {
|
||||
throw new RuntimeException(
|
||||
|
@ -421,7 +454,10 @@ class Episode extends Entity
|
|||
return $this->soundbites;
|
||||
}
|
||||
|
||||
public function getNotes()
|
||||
/**
|
||||
* @return Note[]
|
||||
*/
|
||||
public function getNotes(): array
|
||||
{
|
||||
if (empty($this->id)) {
|
||||
throw new RuntimeException(
|
||||
|
@ -436,7 +472,7 @@ class Episode extends Entity
|
|||
return $this->notes;
|
||||
}
|
||||
|
||||
public function getLink()
|
||||
public function getLink(): string
|
||||
{
|
||||
return base_url(
|
||||
route_to(
|
||||
|
@ -447,7 +483,7 @@ class Episode extends Entity
|
|||
);
|
||||
}
|
||||
|
||||
public function getEmbeddablePlayer($theme = null)
|
||||
public function getEmbeddablePlayerUrl($theme = null): string
|
||||
{
|
||||
return base_url(
|
||||
$theme
|
||||
|
@ -465,14 +501,18 @@ class Episode extends Entity
|
|||
);
|
||||
}
|
||||
|
||||
public function setGuid(string $guid)
|
||||
public function setGuid(?string $guid = null)
|
||||
{
|
||||
return $this->attributes['guid'] = empty($guid)
|
||||
? $this->getLink()
|
||||
: $guid;
|
||||
if ($guid === null) {
|
||||
$this->attributes['guid'] = $this->getLink();
|
||||
} else {
|
||||
$this->attributes['guid'] = $guid;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPodcast()
|
||||
public function getPodcast(): Podcast
|
||||
{
|
||||
return (new PodcastModel())->getPodcastById(
|
||||
$this->attributes['podcast_id'],
|
||||
|
@ -494,39 +534,46 @@ class Episode extends Entity
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getDescriptionHtml($serviceSlug = null)
|
||||
public function getDescriptionHtml(?string $serviceSlug = null): string
|
||||
{
|
||||
return (empty($this->getPodcast()->partner_id) ||
|
||||
empty($this->getPodcast()->partner_link_url) ||
|
||||
empty($this->getPodcast()->partner_image_url)
|
||||
? ''
|
||||
: "<div><a href=\"{$this->getPartnerLink(
|
||||
$descriptionHtml = '';
|
||||
if (
|
||||
$this->getPodcast()->partner_id !== null &&
|
||||
$this->getPodcast()->partner_link_url !== null &&
|
||||
$this->getPodcast()->partner_image_url !== null
|
||||
) {
|
||||
$descriptionHtml .= "<div><a href=\"{$this->getPartnerLink(
|
||||
$serviceSlug,
|
||||
)}\" rel=\"sponsored noopener noreferrer\" target=\"_blank\"><img src=\"{$this->getPartnerImage(
|
||||
)}\" rel=\"sponsored noopener noreferrer\" target=\"_blank\"><img src=\"{$this->getPartnerImageUrl(
|
||||
$serviceSlug,
|
||||
)}\" alt=\"Partner image\" /></a></div>") .
|
||||
$this->attributes['description_html'] .
|
||||
(empty($this->getPodcast()->episode_description_footer_html)
|
||||
? ''
|
||||
: "<footer>{$this->getPodcast()->episode_description_footer_html}</footer>");
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
if ($this->description) {
|
||||
return $this->description;
|
||||
)}\" alt=\"Partner image\" /></a></div>";
|
||||
}
|
||||
|
||||
return trim(
|
||||
preg_replace(
|
||||
'/\s+/',
|
||||
' ',
|
||||
strip_tags($this->attributes['description_html']),
|
||||
),
|
||||
);
|
||||
$descriptionHtml .= $this->attributes['description_html'];
|
||||
|
||||
if ($this->getPodcast()->episode_description_footer_html) {
|
||||
$descriptionHtml .= "<footer>{$this->getPodcast()->episode_description_footer_html}</footer>";
|
||||
}
|
||||
|
||||
return $descriptionHtml;
|
||||
}
|
||||
|
||||
public function getPublicationStatus()
|
||||
public function getDescription(): string
|
||||
{
|
||||
if ($this->description === null) {
|
||||
$this->description = trim(
|
||||
preg_replace(
|
||||
'/\s+/',
|
||||
' ',
|
||||
strip_tags($this->attributes['description_html']),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getPublicationStatus(): string
|
||||
{
|
||||
if ($this->publication_status) {
|
||||
return $this->publication_status;
|
||||
|
@ -546,41 +593,57 @@ class Episode extends Entity
|
|||
|
||||
/**
|
||||
* Saves the location name and fetches OpenStreetMap info
|
||||
*
|
||||
* @param string $locationName
|
||||
*
|
||||
*/
|
||||
public function setLocation($locationName = null)
|
||||
public function setLocation(?string $newLocationName = null)
|
||||
{
|
||||
helper('location');
|
||||
|
||||
if (
|
||||
$locationName &&
|
||||
(empty($this->attributes['location_name']) ||
|
||||
$this->attributes['location_name'] != $locationName)
|
||||
) {
|
||||
$this->attributes['location_name'] = $locationName;
|
||||
if ($location = fetch_osm_location($locationName)) {
|
||||
$this->attributes['location_geo'] = $location['geo'];
|
||||
$this->attributes['location_osmid'] = $location['osmid'];
|
||||
}
|
||||
} elseif (empty($locationName)) {
|
||||
if ($newLocationName === null) {
|
||||
$this->attributes['location_name'] = null;
|
||||
$this->attributes['location_geo'] = null;
|
||||
$this->attributes['location_osmid'] = null;
|
||||
$this->attributes['location_osm_id'] = null;
|
||||
}
|
||||
|
||||
helper('location');
|
||||
|
||||
$oldLocationName = $this->attributes['location_name'];
|
||||
|
||||
if (
|
||||
$oldLocationName === null ||
|
||||
$oldLocationName !== $newLocationName
|
||||
) {
|
||||
$this->attributes['location_name'] = $newLocationName;
|
||||
|
||||
if ($location = fetch_osm_location($newLocationName)) {
|
||||
$this->attributes['location_geo'] = $location['geo'];
|
||||
$this->attributes['location_osm_id'] = $location['osm_id'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLocation(): ?Location
|
||||
{
|
||||
if ($this->location_name === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->location === null) {
|
||||
$this->location = new Location([
|
||||
'name' => $this->location_name,
|
||||
'geo' => $this->location_geo,
|
||||
'osm_id' => $this->location_osm_id,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom rss tag as XML String
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
function getCustomRssString()
|
||||
function getCustomRssString(): string
|
||||
{
|
||||
if (empty($this->custom_rss)) {
|
||||
if ($this->custom_rss === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -597,18 +660,16 @@ class Episode extends Entity
|
|||
],
|
||||
$xmlNode,
|
||||
);
|
||||
|
||||
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves custom rss tag into json
|
||||
*
|
||||
* @param string $customRssString
|
||||
*
|
||||
*/
|
||||
function setCustomRssString($customRssString)
|
||||
function setCustomRssString(?string $customRssString = null)
|
||||
{
|
||||
if (empty($customRssString)) {
|
||||
if ($customRssString === null) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -632,23 +693,35 @@ class Episode extends Entity
|
|||
return $this;
|
||||
}
|
||||
|
||||
function getPartnerLink($serviceSlug = null)
|
||||
function getPartnerLink(?string $serviceSlug = null): string
|
||||
{
|
||||
return rtrim($this->getPodcast()->partner_link_url, '/') .
|
||||
$partnerLink =
|
||||
rtrim($this->getPodcast()->partner_link_url, '/') .
|
||||
'?pid=' .
|
||||
$this->getPodcast()->partner_id .
|
||||
'&guid=' .
|
||||
urlencode($this->attributes['guid']) .
|
||||
(empty($serviceSlug) ? '' : '&_from=' . $serviceSlug);
|
||||
urlencode($this->attributes['guid']);
|
||||
|
||||
if ($serviceSlug !== null) {
|
||||
$partnerLink .= '&_from=' . $serviceSlug;
|
||||
}
|
||||
|
||||
return $partnerLink;
|
||||
}
|
||||
|
||||
function getPartnerImage($serviceSlug = null)
|
||||
function getPartnerImageUrl($serviceSlug = null): string
|
||||
{
|
||||
return rtrim($this->getPodcast()->partner_image_url, '/') .
|
||||
$partnerImageUrl =
|
||||
rtrim($this->getPodcast()->partner_image_url, '/') .
|
||||
'?pid=' .
|
||||
$this->getPodcast()->partner_id .
|
||||
'&guid=' .
|
||||
urlencode($this->attributes['guid']) .
|
||||
(empty($serviceSlug) ? '' : '&_from=' . $serviceSlug);
|
||||
urlencode($this->attributes['guid']);
|
||||
|
||||
if ($serviceSlug !== null) {
|
||||
$partnerImageUrl = '&_from=' . $serviceSlug;
|
||||
}
|
||||
|
||||
return $partnerImageUrl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,15 @@ namespace App\Entities;
|
|||
use CodeIgniter\Entity\Entity;
|
||||
use App\Models\PersonModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $podcast_id
|
||||
* @property int $episode_id
|
||||
* @property int $person_id
|
||||
* @property Person $person
|
||||
* @property string|null $person_group
|
||||
* @property string|null $person_role
|
||||
*/
|
||||
class EpisodePerson extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -30,7 +39,7 @@ class EpisodePerson extends Entity
|
|||
'person_role' => '?string',
|
||||
];
|
||||
|
||||
public function getPerson()
|
||||
public function getPerson(): Person
|
||||
{
|
||||
return (new PersonModel())->getPersonById(
|
||||
$this->attributes['person_id'],
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace App\Entities;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use CodeIgniter\Files\File;
|
||||
use Config\Images as ImagesConfig;
|
||||
use Config\Services;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property File|null $file
|
||||
* @property string $dirname
|
||||
* @property string $filename
|
||||
* @property string $extension
|
||||
* @property string $mimetype
|
||||
* @property string $path
|
||||
* @property string $url
|
||||
* @property string $thumbnail_path
|
||||
* @property string $thumbnail_url
|
||||
* @property string $medium_path
|
||||
* @property string $medium_url
|
||||
* @property string $large_path
|
||||
* @property string $large_url
|
||||
* @property string $feed_path
|
||||
* @property string $feed_url
|
||||
* @property string $id3_path
|
||||
* @property string $id3_url
|
||||
*/
|
||||
class Image extends Entity
|
||||
{
|
||||
/**
|
||||
* @var ImagesConfig
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var null|File
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $dirname;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $extension;
|
||||
|
||||
public function __construct(
|
||||
?File $file,
|
||||
string $path = '',
|
||||
string $mimetype = ''
|
||||
) {
|
||||
if ($file === null && $path === '') {
|
||||
throw new RuntimeException(
|
||||
'File or path must be set to create an Image.',
|
||||
);
|
||||
}
|
||||
|
||||
$this->config = config('Images');
|
||||
|
||||
$dirname = '';
|
||||
$filename = '';
|
||||
$extension = '';
|
||||
|
||||
if ($file !== null) {
|
||||
$dirname = $file->getPath();
|
||||
$filename = $file->getBasename();
|
||||
$extension = $file->getExtension();
|
||||
$mimetype = $file->getMimeType();
|
||||
}
|
||||
|
||||
if ($path !== '') {
|
||||
[
|
||||
'filename' => $filename,
|
||||
'dirname' => $dirname,
|
||||
'extension' => $extension,
|
||||
] = pathinfo($path);
|
||||
}
|
||||
|
||||
$this->file = $file;
|
||||
$this->dirname = $dirname;
|
||||
$this->filename = $filename;
|
||||
$this->extension = $extension;
|
||||
$this->mimetype = $mimetype;
|
||||
}
|
||||
|
||||
function getFile(): File
|
||||
{
|
||||
if ($this->file === null) {
|
||||
$this->file = new File($this->path);
|
||||
}
|
||||
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
function getPath(): string
|
||||
{
|
||||
return $this->dirname . '/' . $this->filename . '.' . $this->extension;
|
||||
}
|
||||
|
||||
function getUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->path);
|
||||
}
|
||||
|
||||
function getThumbnailPath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
$this->filename .
|
||||
$this->config->thumbnailSuffix .
|
||||
'.' .
|
||||
$this->extension;
|
||||
}
|
||||
|
||||
function getThumbnailUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->thumbnail_path);
|
||||
}
|
||||
|
||||
function getMediumPath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
$this->filename .
|
||||
$this->config->mediumSuffix .
|
||||
'.' .
|
||||
$this->extension;
|
||||
}
|
||||
|
||||
function getMediumUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->medium_path);
|
||||
}
|
||||
|
||||
function getLargePath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
$this->filename .
|
||||
$this->config->largeSuffix .
|
||||
'.' .
|
||||
$this->extension;
|
||||
}
|
||||
|
||||
function getLargeUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->large_path);
|
||||
}
|
||||
|
||||
function getFeedPath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
$this->filename .
|
||||
$this->config->feedSuffix .
|
||||
'.' .
|
||||
$this->extension;
|
||||
}
|
||||
|
||||
function getFeedUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->feed_path);
|
||||
}
|
||||
|
||||
function getId3Path(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
$this->filename .
|
||||
$this->config->id3Suffix .
|
||||
'.' .
|
||||
$this->extension;
|
||||
}
|
||||
|
||||
function getId3Url(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->id3_path);
|
||||
}
|
||||
|
||||
public function saveImage(string $dirname, string $filename): void
|
||||
{
|
||||
helper('media');
|
||||
|
||||
$this->dirname = $dirname;
|
||||
$this->filename = $filename;
|
||||
|
||||
save_media($this->file, $this->dirname, $this->filename);
|
||||
|
||||
$imageService = Services::image();
|
||||
|
||||
$thumbnailSize = $this->config->thumbnailSize;
|
||||
$mediumSize = $this->config->mediumSize;
|
||||
$largeSize = $this->config->largeSize;
|
||||
$feedSize = $this->config->feedSize;
|
||||
$id3Size = $this->config->id3Size;
|
||||
|
||||
$imageService
|
||||
->withFile(media_path($this->path))
|
||||
->resize($thumbnailSize, $thumbnailSize)
|
||||
->save(media_path($this->thumbnail_path));
|
||||
|
||||
$imageService
|
||||
->withFile(media_path($this->path))
|
||||
->resize($mediumSize, $mediumSize)
|
||||
->save(media_path($this->medium_path));
|
||||
|
||||
$imageService
|
||||
->withFile(media_path($this->path))
|
||||
->resize($largeSize, $largeSize)
|
||||
->save(media_path($this->large_path));
|
||||
|
||||
$imageService
|
||||
->withFile(media_path($this->path))
|
||||
->resize($feedSize, $feedSize)
|
||||
->save(media_path($this->feed_path));
|
||||
|
||||
$imageService
|
||||
->withFile(media_path($this->path))
|
||||
->resize($id3Size, $id3Size)
|
||||
->save(media_path($this->id3_path));
|
||||
}
|
||||
}
|
|
@ -10,6 +10,10 @@ namespace App\Entities;
|
|||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property string $code
|
||||
* @property string $native_name
|
||||
*/
|
||||
class Language extends Entity
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace App\Entities;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property string $url
|
||||
* @property string $name
|
||||
* @property string|null $geo
|
||||
* @property string|null $osm_id
|
||||
*/
|
||||
class Location extends Entity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const OSM_URL = 'https://www.openstreetmap.org/';
|
||||
|
||||
public function getUrl(): string
|
||||
{
|
||||
if ($this->osm_id !== null) {
|
||||
return self::OSM_URL .
|
||||
['N' => 'node', 'W' => 'way', 'R' => 'relation'][
|
||||
substr($this->osm_id, 0, 1)
|
||||
] .
|
||||
'/' .
|
||||
substr($this->osm_id, 1);
|
||||
}
|
||||
|
||||
if ($this->geo !== null) {
|
||||
return self::OSM_URL .
|
||||
'#map=17/' .
|
||||
str_replace(',', '/', substr($this->geo, 4));
|
||||
}
|
||||
|
||||
return self::OSM_URL . 'search?query=' . urlencode($this->name);
|
||||
}
|
||||
}
|
|
@ -8,10 +8,16 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use ActivityPub\Entities\Note as ActivityPubNote;
|
||||
use App\Models\ActorModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use RuntimeException;
|
||||
|
||||
class Note extends \ActivityPub\Entities\Note
|
||||
/**
|
||||
* @property int|null $episode_id
|
||||
* @property Episode|null $episode
|
||||
*/
|
||||
class Note extends ActivityPubNote
|
||||
{
|
||||
/**
|
||||
* @var Episode|null
|
||||
|
@ -40,13 +46,13 @@ class Note extends \ActivityPub\Entities\Note
|
|||
*/
|
||||
public function getEpisode()
|
||||
{
|
||||
if (empty($this->episode_id)) {
|
||||
if ($this->episode_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Note must have an episode_id before getting episode.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->episode)) {
|
||||
if ($this->episode === null) {
|
||||
$this->episode = (new EpisodeModel())->getEpisodeById(
|
||||
$this->episode_id,
|
||||
);
|
||||
|
|
|
@ -9,8 +9,20 @@
|
|||
namespace App\Entities;
|
||||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $title
|
||||
* @property string $link
|
||||
* @property string $slug
|
||||
* @property string $content_markdown
|
||||
* @property string $content_html
|
||||
* @property Time $created_at
|
||||
* @property Time $updated_at
|
||||
* @property Time|null $delete_at
|
||||
*/
|
||||
class Page extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -30,21 +42,27 @@ class Page extends Entity
|
|||
'id' => 'integer',
|
||||
'title' => 'string',
|
||||
'slug' => 'string',
|
||||
'content' => 'string',
|
||||
'content_markdown' => 'string',
|
||||
'content_html' => 'string',
|
||||
];
|
||||
|
||||
public function getLink()
|
||||
public function getLink(): string
|
||||
{
|
||||
return url_to('page', $this->attributes['slug']);
|
||||
}
|
||||
|
||||
public function getContentHtml(): string
|
||||
public function setContentMarkdown(string $contentMarkdown): self
|
||||
{
|
||||
$converter = new CommonMarkConverter([
|
||||
'html_input' => 'strip',
|
||||
'allow_unsafe_links' => false,
|
||||
]);
|
||||
|
||||
return $converter->convertToHtml($this->attributes['content']);
|
||||
$this->attributes['content_markdown'] = $contentMarkdown;
|
||||
$this->attributes['content_html'] = $converter->convertToHtml(
|
||||
$contentMarkdown,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,19 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use App\Libraries\Image;
|
||||
use CodeIgniter\HTTP\Files\UploadedFile;
|
||||
use CodeIgniter\Files\File;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $full_name
|
||||
* @property string $unique_name
|
||||
* @property string|null $information_url
|
||||
* @property Image $image
|
||||
* @property string $image_path
|
||||
* @property string $image_mimetype
|
||||
* @property int $created_by
|
||||
* @property int $updated_by
|
||||
*/
|
||||
class Person extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -36,26 +44,16 @@ class Person extends Entity
|
|||
|
||||
/**
|
||||
* Saves a picture in `public/media/persons/`
|
||||
*
|
||||
* @param UploadedFile|File|null $image
|
||||
*/
|
||||
public function setImage($image = null): self
|
||||
public function setImage(Image $image): self
|
||||
{
|
||||
if ($image !== null) {
|
||||
helper('media');
|
||||
helper('media');
|
||||
|
||||
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||
$this->attributes['image_path'] = save_media(
|
||||
$image,
|
||||
'persons',
|
||||
$this->attributes['unique_name'],
|
||||
);
|
||||
$this->image = new Image(
|
||||
$this->attributes['image_path'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
}
|
||||
// Save image
|
||||
$image->saveImage('persons', $this->attributes['unique_name']);
|
||||
|
||||
$this->attributes['image_mimetype'] = $image->mimetype;
|
||||
$this->attributes['image_path'] = $image->path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -63,6 +61,7 @@ class Person extends Entity
|
|||
public function getImage(): Image
|
||||
{
|
||||
return new Image(
|
||||
null,
|
||||
$this->attributes['image_path'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
|
|
|
@ -10,6 +10,17 @@ namespace App\Entities;
|
|||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property string $slug
|
||||
* @property string $type
|
||||
* @property string $label
|
||||
* @property string $home_url
|
||||
* @property string|null $submit_url
|
||||
* @property string|null $link_url
|
||||
* @property string|null $link_content
|
||||
* @property bool|null $is_visible
|
||||
* @property bool|null $is_on_embeddable_player
|
||||
*/
|
||||
class Platform extends Entity
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use App\Libraries\Image;
|
||||
use App\Libraries\SimpleRSSElement;
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\EpisodeModel;
|
||||
|
@ -16,11 +15,66 @@ use App\Models\PlatformModel;
|
|||
use App\Models\PodcastPersonModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Files\File;
|
||||
use CodeIgniter\HTTP\Files\UploadedFile;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $actor_id
|
||||
* @property Actor $actor
|
||||
* @property string $name
|
||||
* @property string $link
|
||||
* @property string $feed_url
|
||||
* @property string $title
|
||||
* @property string $description Holds text only description, striped of any markdown or html special characters
|
||||
* @property string $description_markdown
|
||||
* @property string $description_html
|
||||
* @property Image $image
|
||||
* @property string $image_path
|
||||
* @property string $image_mimetype
|
||||
* @property string $language_code
|
||||
* @property int $category_id
|
||||
* @property Category $category
|
||||
* @property int[] $other_categories_ids
|
||||
* @property Category[] $other_categories
|
||||
* @property string|null $parental_advisory
|
||||
* @property string|null $publisher
|
||||
* @property string $owner_name
|
||||
* @property string $owner_email
|
||||
* @property string $type
|
||||
* @property string|null $copyright
|
||||
* @property string|null $episode_description_footer_markdown
|
||||
* @property string|null $episode_description_footer_html
|
||||
* @property bool $is_blocked
|
||||
* @property bool $is_completed
|
||||
* @property bool $is_locked
|
||||
* @property string|null $imported_feed_url
|
||||
* @property string|null $new_feed_url
|
||||
* @property Location $location
|
||||
* @property string|null $location_name
|
||||
* @property string|null $location_geo
|
||||
* @property string|null $location_osm_id
|
||||
* @property string|null $payment_pointer
|
||||
* @property array|null $custom_rss
|
||||
* @property string $custom_rss_string
|
||||
* @property string|null $partner_id
|
||||
* @property string|null $partner_link_url
|
||||
* @property string|null $partner_image_url
|
||||
* @property int $created_by
|
||||
* @property int $updated_by
|
||||
* @property Time $created_at;
|
||||
* @property Time $updated_at;
|
||||
* @property Time|null $deleted_at;
|
||||
*
|
||||
* @property Episode[] $episodes
|
||||
* @property PodcastPerson[] $persons
|
||||
* @property User[] $contributors
|
||||
* @property Platform[] $podcasting_platforms
|
||||
* @property Platform[] $social_platforms
|
||||
* @property Platform[] $funding_platforms
|
||||
*
|
||||
*/
|
||||
class Podcast extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -39,14 +93,9 @@ class Podcast extends Entity
|
|||
protected $image;
|
||||
|
||||
/**
|
||||
* @var Episode[]
|
||||
* @var string
|
||||
*/
|
||||
protected $episodes;
|
||||
|
||||
/**
|
||||
* @var PodcastPerson[]
|
||||
*/
|
||||
protected $persons;
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* @var Category
|
||||
|
@ -59,44 +108,53 @@ class Podcast extends Entity
|
|||
protected $other_categories;
|
||||
|
||||
/**
|
||||
* @var integer[]
|
||||
* @var string[]
|
||||
*/
|
||||
protected $other_categories_ids;
|
||||
|
||||
/**
|
||||
* @var Episode[]
|
||||
*/
|
||||
protected $episodes;
|
||||
|
||||
/**
|
||||
* @var PodcastPerson[]
|
||||
*/
|
||||
protected $persons;
|
||||
|
||||
/**
|
||||
* @var User[]
|
||||
*/
|
||||
protected $contributors;
|
||||
|
||||
/**
|
||||
* @var Platform
|
||||
* @var Platform[]
|
||||
*/
|
||||
protected $podcastingPlatforms;
|
||||
protected $podcasting_platforms;
|
||||
|
||||
/**
|
||||
* @var Platform
|
||||
* @var Platform[]
|
||||
*/
|
||||
protected $socialPlatforms;
|
||||
protected $social_platforms;
|
||||
|
||||
/**
|
||||
* @var Platform
|
||||
* @var Platform[]
|
||||
*/
|
||||
protected $fundingPlatforms;
|
||||
protected $funding_platforms;
|
||||
|
||||
/**
|
||||
* Holds text only description, striped of any markdown or html special characters
|
||||
*
|
||||
* @var string
|
||||
* @var Location|null
|
||||
*/
|
||||
protected $description;
|
||||
protected $location;
|
||||
|
||||
/**
|
||||
* Return custom rss as string
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $custom_rss_string;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'actor_id' => 'integer',
|
||||
|
@ -123,7 +181,7 @@ class Podcast extends Entity
|
|||
'new_feed_url' => '?string',
|
||||
'location_name' => '?string',
|
||||
'location_geo' => '?string',
|
||||
'location_osmid' => '?string',
|
||||
'location_osm_id' => '?string',
|
||||
'payment_pointer' => '?string',
|
||||
'custom_rss' => '?json-array',
|
||||
'partner_id' => '?string',
|
||||
|
@ -133,20 +191,15 @@ class Podcast extends Entity
|
|||
'updated_by' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the podcast actor
|
||||
*
|
||||
* @return Actor
|
||||
*/
|
||||
public function getActor(): Actor
|
||||
{
|
||||
if (!$this->attributes['actor_id']) {
|
||||
if (!$this->actor_id) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must have an actor_id before getting actor.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->actor)) {
|
||||
if ($this->actor === null) {
|
||||
$this->actor = model('ActorModel')->getActorById($this->actor_id);
|
||||
}
|
||||
|
||||
|
@ -156,36 +209,22 @@ class Podcast extends Entity
|
|||
/**
|
||||
* Saves a cover image to the corresponding podcast folder in `public/media/podcast_name/`
|
||||
*
|
||||
* @param UploadedFile|File $image
|
||||
* @param Image $image
|
||||
*/
|
||||
public function setImage($image = null): self
|
||||
public function setImage($image): self
|
||||
{
|
||||
if ($image) {
|
||||
helper('media');
|
||||
// Save image
|
||||
$image->saveImage('podcasts/' . $this->attributes['name'], 'cover');
|
||||
|
||||
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||
$this->attributes['image_path'] = save_media(
|
||||
$image,
|
||||
'podcasts/' . $this->attributes['name'],
|
||||
'cover',
|
||||
);
|
||||
|
||||
$this->image = new Image(
|
||||
$this->attributes['image_path'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
}
|
||||
$this->attributes['image_mimetype'] = $image->mimetype;
|
||||
$this->attributes['image_path'] = $image->path;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImage(): Image
|
||||
{
|
||||
return new Image(
|
||||
$this->attributes['image_path'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
return new Image(null, $this->image_path, $this->image_mimetype);
|
||||
}
|
||||
|
||||
public function getLink(): string
|
||||
|
@ -350,14 +389,14 @@ class Podcast extends Entity
|
|||
);
|
||||
}
|
||||
|
||||
if (empty($this->podcastingPlatforms)) {
|
||||
$this->podcastingPlatforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
if (empty($this->podcasting_platforms)) {
|
||||
$this->podcasting_platforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
$this->id,
|
||||
'podcasting',
|
||||
);
|
||||
}
|
||||
|
||||
return $this->podcastingPlatforms;
|
||||
return $this->podcasting_platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -373,14 +412,14 @@ class Podcast extends Entity
|
|||
);
|
||||
}
|
||||
|
||||
if (empty($this->socialPlatforms)) {
|
||||
$this->socialPlatforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
if (empty($this->social_platforms)) {
|
||||
$this->social_platforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
$this->id,
|
||||
'social',
|
||||
);
|
||||
}
|
||||
|
||||
return $this->socialPlatforms;
|
||||
return $this->social_platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -396,14 +435,14 @@ class Podcast extends Entity
|
|||
);
|
||||
}
|
||||
|
||||
if (empty($this->fundingPlatforms)) {
|
||||
$this->fundingPlatforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
if (empty($this->funding_platforms)) {
|
||||
$this->funding_platforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
$this->id,
|
||||
'funding',
|
||||
);
|
||||
}
|
||||
|
||||
return $this->fundingPlatforms;
|
||||
return $this->funding_platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -444,29 +483,50 @@ class Podcast extends Entity
|
|||
/**
|
||||
* Saves the location name and fetches OpenStreetMap info
|
||||
*/
|
||||
public function setLocation(?string $locationName = null): self
|
||||
public function setLocation(?string $newLocationName = null)
|
||||
{
|
||||
helper('location');
|
||||
|
||||
if (
|
||||
$locationName &&
|
||||
(empty($this->attributes['location_name']) ||
|
||||
$this->attributes['location_name'] != $locationName)
|
||||
) {
|
||||
$this->attributes['location_name'] = $locationName;
|
||||
if ($location = fetch_osm_location($locationName)) {
|
||||
$this->attributes['location_geo'] = $location['geo'];
|
||||
$this->attributes['location_osmid'] = $location['osmid'];
|
||||
}
|
||||
} elseif (empty($locationName)) {
|
||||
if ($newLocationName === null) {
|
||||
$this->attributes['location_name'] = null;
|
||||
$this->attributes['location_geo'] = null;
|
||||
$this->attributes['location_osmid'] = null;
|
||||
$this->attributes['location_osm_id'] = null;
|
||||
}
|
||||
|
||||
helper('location');
|
||||
|
||||
$oldLocationName = $this->attributes['location_name'];
|
||||
|
||||
if (
|
||||
$oldLocationName === null ||
|
||||
$oldLocationName !== $newLocationName
|
||||
) {
|
||||
$this->attributes['location_name'] = $newLocationName;
|
||||
|
||||
if ($location = fetch_osm_location($newLocationName)) {
|
||||
$this->attributes['location_geo'] = $location['geo'];
|
||||
$this->attributes['location_osm_id'] = $location['osm_id'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLocation(): ?Location
|
||||
{
|
||||
if ($this->location_name === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->location === null) {
|
||||
$this->location = new Location([
|
||||
'name' => $this->location_name,
|
||||
'geo' => $this->location_geo,
|
||||
'osm_id' => $this->location_osm_id,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom rss tag as XML String
|
||||
*
|
||||
|
|
|
@ -11,6 +11,14 @@ namespace App\Entities;
|
|||
use CodeIgniter\Entity\Entity;
|
||||
use App\Models\PersonModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $podcast_id
|
||||
* @property int $person_id
|
||||
* @property Person $person
|
||||
* @property string|null $person_group
|
||||
* @property string|null $person_role
|
||||
*/
|
||||
class PodcastPerson extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -29,7 +37,7 @@ class PodcastPerson extends Entity
|
|||
'person_role' => '?string',
|
||||
];
|
||||
|
||||
public function getPerson()
|
||||
public function getPerson(): ?Person
|
||||
{
|
||||
return (new PersonModel())->getPersonById(
|
||||
$this->attributes['person_id'],
|
||||
|
|
|
@ -10,6 +10,16 @@ namespace App\Entities;
|
|||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $podcast_id
|
||||
* @property int $episode_id
|
||||
* @property double $start_time
|
||||
* @property double $duration
|
||||
* @property string|null $label
|
||||
* @property int $created_by
|
||||
* @property int $updated_by
|
||||
*/
|
||||
class Soundbite extends Entity
|
||||
{
|
||||
/**
|
||||
|
@ -19,17 +29,10 @@ class Soundbite extends Entity
|
|||
'id' => 'integer',
|
||||
'podcast_id' => 'integer',
|
||||
'episode_id' => 'integer',
|
||||
'start_time' => 'float',
|
||||
'duration' => 'float',
|
||||
'start_time' => 'double',
|
||||
'duration' => 'double',
|
||||
'label' => '?string',
|
||||
'created_by' => 'integer',
|
||||
'updated_by' => 'integer',
|
||||
];
|
||||
|
||||
public function setUpdatedBy(User $user): self
|
||||
{
|
||||
$this->attributes['updated_by'] = $user->id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,22 +10,27 @@ namespace App\Entities;
|
|||
|
||||
use RuntimeException;
|
||||
use App\Models\PodcastModel;
|
||||
use Myth\Auth\Entities\User as MythAuthUser;
|
||||
|
||||
class User extends \Myth\Auth\Entities\User
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $username
|
||||
* @property string $email
|
||||
* @property string $password
|
||||
* @property bool $active
|
||||
* @property bool $force_pass_reset
|
||||
* @property int|null $podcast_id
|
||||
* @property string|null $podcast_role
|
||||
*
|
||||
* @property Podcast[] $podcasts All podcasts the user is contributing to
|
||||
*/
|
||||
class User extends MythAuthUser
|
||||
{
|
||||
/**
|
||||
* Per-user podcasts
|
||||
* @var Podcast[]
|
||||
*/
|
||||
protected $podcasts = [];
|
||||
|
||||
/**
|
||||
* The podcast the user is contributing to
|
||||
*
|
||||
* @var Podcast|null
|
||||
*/
|
||||
protected $podcast;
|
||||
|
||||
/**
|
||||
* Array of field names and the type of value to cast them as
|
||||
* when they are accessed.
|
||||
|
@ -36,8 +41,8 @@ class User extends \Myth\Auth\Entities\User
|
|||
'id' => 'integer',
|
||||
'active' => 'boolean',
|
||||
'force_pass_reset' => 'boolean',
|
||||
'podcast_role' => '?string',
|
||||
'podcast_id' => '?integer',
|
||||
'podcast_role' => '?string',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -47,36 +52,16 @@ class User extends \Myth\Auth\Entities\User
|
|||
*/
|
||||
public function getPodcasts(): array
|
||||
{
|
||||
if (empty($this->id)) {
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Users must be created before getting podcasts.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->podcasts)) {
|
||||
if ($this->podcasts === null) {
|
||||
$this->podcasts = (new PodcastModel())->getUserPodcasts($this->id);
|
||||
}
|
||||
|
||||
return $this->podcasts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a podcast the user is contributing to
|
||||
*/
|
||||
public function getPodcast(): Podcast
|
||||
{
|
||||
if (empty($this->podcast_id)) {
|
||||
throw new RuntimeException(
|
||||
'Podcast_id must be set before getting podcast.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->podcast)) {
|
||||
$this->podcast = (new PodcastModel())->getPodcastById(
|
||||
$this->podcast_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->podcast;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,7 @@ class PermissionFilter implements FilterInterface
|
|||
*/
|
||||
public function before(RequestInterface $request, $params = null)
|
||||
{
|
||||
if (!function_exists('logged_in')) {
|
||||
helper('auth');
|
||||
}
|
||||
helper('auth');
|
||||
|
||||
if (empty($params)) {
|
||||
return;
|
||||
|
|
|
@ -7,9 +7,22 @@
|
|||
*/
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use App\Entities\User;
|
||||
use CodeIgniter\Database\Exceptions\DataException;
|
||||
use Config\Services;
|
||||
|
||||
if (!function_exists('user')) {
|
||||
/**
|
||||
* Returns the User instance for the current logged in user.
|
||||
*/
|
||||
function user(): ?User
|
||||
{
|
||||
$authenticate = Services::authentication();
|
||||
$authenticate->check();
|
||||
return $authenticate->user();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_interact_as_actor')) {
|
||||
/**
|
||||
* Sets the actor id of which the user is acting as
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use App\Entities\Location;
|
||||
use CodeIgniter\View\Table;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
|
@ -127,8 +128,8 @@ if (!function_exists('icon_button')) {
|
|||
*
|
||||
* Abstracts the `button()` helper to create a stylized icon button
|
||||
*
|
||||
* @param string $label The button label
|
||||
* @param string $uri URI string or array of URI segments
|
||||
* @param string $icon The button icon
|
||||
* @param string $title The button label
|
||||
* @param array $customOptions button options: variant, size, iconLeft, iconRight
|
||||
* @param array $customAttributes Additional attributes
|
||||
*
|
||||
|
@ -252,15 +253,11 @@ if (!function_exists('publication_pill')) {
|
|||
*
|
||||
* Shows the stylized publication datetime in regards to current datetime.
|
||||
*
|
||||
* @param Time $publicationDate publication datetime of the episode
|
||||
* @param boolean $isPublished whether or not the episode has been published
|
||||
* @param string $customClass css class to add to the component
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function publication_pill(
|
||||
?Time $publicationDate,
|
||||
$publicationStatus,
|
||||
string $publicationStatus,
|
||||
string $customClass = ''
|
||||
): string {
|
||||
if ($publicationDate === null) {
|
||||
|
@ -336,6 +333,12 @@ if (!function_exists('publication_button')) {
|
|||
$variant = 'danger';
|
||||
$iconLeft = 'cloud-off';
|
||||
break;
|
||||
default:
|
||||
$label = '';
|
||||
$route = '';
|
||||
$variant = '';
|
||||
$iconLeft = '';
|
||||
break;
|
||||
}
|
||||
|
||||
return button($label, $route, [
|
||||
|
@ -351,16 +354,13 @@ if (!function_exists('episode_numbering')) {
|
|||
/**
|
||||
* Returns relevant translated episode numbering.
|
||||
*
|
||||
* @param string $class styling classes
|
||||
* @param string $is_abbr component will show abbreviated numbering if true
|
||||
*
|
||||
* @return string|null
|
||||
* @param bool $isAbbr component will show abbreviated numbering if true
|
||||
*/
|
||||
function episode_numbering(
|
||||
?int $episodeNumber = null,
|
||||
?int $seasonNumber = null,
|
||||
string $class = '',
|
||||
$isAbbr = false
|
||||
bool $isAbbr = false
|
||||
): string {
|
||||
if (!$episodeNumber && !$seasonNumber) {
|
||||
return '';
|
||||
|
@ -368,22 +368,20 @@ if (!function_exists('episode_numbering')) {
|
|||
|
||||
$transKey = '';
|
||||
$args = [];
|
||||
if ($episodeNumber && $seasonNumber) {
|
||||
if ($episodeNumber !== null) {
|
||||
$args['episodeNumber'] = $episodeNumber;
|
||||
}
|
||||
|
||||
if ($seasonNumber !== null) {
|
||||
$args['seasonNumber'] = $seasonNumber;
|
||||
}
|
||||
|
||||
if ($episodeNumber !== null && $seasonNumber !== null) {
|
||||
$transKey = 'Episode.season_episode';
|
||||
$args = [
|
||||
'seasonNumber' => $seasonNumber,
|
||||
'episodeNumber' => $episodeNumber,
|
||||
];
|
||||
} elseif ($episodeNumber && !$seasonNumber) {
|
||||
} elseif ($episodeNumber !== null && $seasonNumber === null) {
|
||||
$transKey = 'Episode.number';
|
||||
$args = [
|
||||
'episodeNumber' => $episodeNumber,
|
||||
];
|
||||
} elseif (!$episodeNumber && $seasonNumber) {
|
||||
} elseif ($episodeNumber === null && $seasonNumber !== null) {
|
||||
$transKey = 'Episode.season';
|
||||
$args = [
|
||||
'seasonNumber' => $seasonNumber,
|
||||
];
|
||||
}
|
||||
|
||||
if ($isAbbr) {
|
||||
|
@ -408,19 +406,15 @@ if (!function_exists('location_link')) {
|
|||
/**
|
||||
* Returns link to display from location info
|
||||
*/
|
||||
function location_link(
|
||||
?string $locationName,
|
||||
?string $locationGeo,
|
||||
?string $locationOsmid,
|
||||
$class = ''
|
||||
): string {
|
||||
if (empty($locationName)) {
|
||||
function location_link(?Location $location, string $class = ''): string
|
||||
{
|
||||
if ($location === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return anchor(
|
||||
location_url($locationName, $locationGeo, $locationOsmid),
|
||||
icon('map-pin', 'mr-2') . $locationName,
|
||||
$location->url,
|
||||
icon('map-pin', 'mr-2') . $location->name,
|
||||
[
|
||||
'class' =>
|
||||
'inline-flex items-baseline hover:underline' .
|
||||
|
|
|
@ -15,9 +15,9 @@ if (!function_exists('get_file_tags')) {
|
|||
/**
|
||||
* Gets audio file metadata and ID3 info
|
||||
*
|
||||
* @param UploadedFile $file
|
||||
* @return array<string, string|double|int>
|
||||
*/
|
||||
function get_file_tags($file): array
|
||||
function get_file_tags(File $file): array
|
||||
{
|
||||
$getID3 = new GetID3();
|
||||
$FileInfo = $getID3->analyze($file);
|
||||
|
@ -34,8 +34,6 @@ if (!function_exists('get_file_tags')) {
|
|||
if (!function_exists('write_audio_file_tags')) {
|
||||
/**
|
||||
* Write audio file metadata / ID3 tags
|
||||
*
|
||||
* @return UploadedFile
|
||||
*/
|
||||
function write_audio_file_tags(Episode $episode): void
|
||||
{
|
||||
|
@ -51,7 +49,7 @@ if (!function_exists('write_audio_file_tags')) {
|
|||
$tagwriter->tagformats = ['id3v2.4'];
|
||||
$tagwriter->tag_encoding = $TextEncoding;
|
||||
|
||||
$cover = new File($episode->image->id3_path);
|
||||
$cover = new File(media_path($episode->image->id3_path));
|
||||
|
||||
$APICdata = file_get_contents($cover->getRealPath());
|
||||
|
||||
|
|
|
@ -11,49 +11,46 @@ use Config\Services;
|
|||
if (!function_exists('fetch_osm_location')) {
|
||||
/**
|
||||
* Fetches places from Nominatim OpenStreetMap
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
function fetch_osm_location(string $locationName): ?array
|
||||
{
|
||||
$osmObject = null;
|
||||
|
||||
if (!empty($locationName)) {
|
||||
try {
|
||||
$client = Services::curlrequest();
|
||||
try {
|
||||
$client = Services::curlrequest();
|
||||
|
||||
$response = $client->request(
|
||||
'GET',
|
||||
'https://nominatim.openstreetmap.org/search.php?q=' .
|
||||
urlencode($locationName) .
|
||||
'&polygon_geojson=1&format=jsonv2',
|
||||
[
|
||||
'headers' => [
|
||||
'User-Agent' => 'Castopod/' . CP_VERSION,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
$response = $client->request(
|
||||
'GET',
|
||||
'https://nominatim.openstreetmap.org/search.php?q=' .
|
||||
urlencode($locationName) .
|
||||
'&polygon_geojson=1&format=jsonv2',
|
||||
[
|
||||
'headers' => [
|
||||
'User-Agent' => 'Castopod/' . CP_VERSION,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
);
|
||||
$places = json_decode(
|
||||
$response->getBody(),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
$osmObject = [
|
||||
'geo' =>
|
||||
empty($places[0]['lat']) || empty($places[0]['lon'])
|
||||
? null
|
||||
: "geo:{$places[0]['lat']},{$places[0]['lon']}",
|
||||
'osmid' => empty($places[0]['osm_type'])
|
||||
],
|
||||
);
|
||||
$places = json_decode(
|
||||
$response->getBody(),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
||||
$osmObject = [
|
||||
'geo' =>
|
||||
empty($places[0]['lat']) || empty($places[0]['lon'])
|
||||
? null
|
||||
: strtoupper(substr($places[0]['osm_type'], 0, 1)) .
|
||||
$places[0]['osm_id'],
|
||||
];
|
||||
} catch (Exception $exception) {
|
||||
//If things go wrong the show must go on
|
||||
log_message('critical', $exception);
|
||||
}
|
||||
: "geo:{$places[0]['lat']},{$places[0]['lon']}",
|
||||
'osm_id' => empty($places[0]['osm_type'])
|
||||
? null
|
||||
: strtoupper(substr($places[0]['osm_type'], 0, 1)) .
|
||||
$places[0]['osm_id'],
|
||||
];
|
||||
} catch (Exception $exception) {
|
||||
//If things go wrong the show must go on
|
||||
log_message('critical', $exception);
|
||||
}
|
||||
|
||||
return $osmObject;
|
||||
|
|
|
@ -15,14 +15,16 @@ if (!function_exists('save_media')) {
|
|||
/**
|
||||
* Saves a file to the corresponding podcast folder in `public/media`
|
||||
*
|
||||
* @param File|UploadedFile $filePath
|
||||
* @param File|UploadedFile $file
|
||||
*/
|
||||
function save_media(
|
||||
File $filePath,
|
||||
string $folder,
|
||||
string $mediaName
|
||||
File $file,
|
||||
string $folder = '',
|
||||
string $filename
|
||||
): string {
|
||||
$fileName = $mediaName . '.' . $filePath->getExtension();
|
||||
if (($extension = $file->getExtension()) !== '') {
|
||||
$filename = $filename . '.' . $extension;
|
||||
}
|
||||
|
||||
$mediaRoot = config('App')->mediaRoot . '/' . $folder;
|
||||
|
||||
|
@ -31,10 +33,10 @@ if (!function_exists('save_media')) {
|
|||
touch($mediaRoot . '/index.html');
|
||||
}
|
||||
|
||||
// move to media folder and overwrite file if already existing
|
||||
$filePath->move($mediaRoot . '/', $fileName, true);
|
||||
// move to media folder, overwrite file if already existing
|
||||
$file->move($mediaRoot . '/', $filename, true);
|
||||
|
||||
return $folder . '/' . $fileName;
|
||||
return $folder . '/' . $filename;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,8 +109,7 @@ if (!function_exists('media_base_url')) {
|
|||
/**
|
||||
* Return the media base URL to use in views
|
||||
*
|
||||
* @param string|array $uri URI string or array of URI segments
|
||||
* @param string $protocol
|
||||
* @param string|string[] $uri URI string or array of URI segments
|
||||
*/
|
||||
function media_base_url($uri = ''): string
|
||||
{
|
||||
|
|
|
@ -127,7 +127,7 @@ if (!function_exists('slugify')) {
|
|||
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
|
||||
|
||||
// remove unwanted characters
|
||||
$text = preg_replace('~[^\\-\w]+~', '', $text);
|
||||
$text = preg_replace('~[^\-\w]+~', '', $text);
|
||||
|
||||
// trim
|
||||
$text = trim($text, '-');
|
||||
|
|
|
@ -6,20 +6,24 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use App\Entities\Person;
|
||||
use App\Entities\EpisodePerson;
|
||||
use App\Entities\PodcastPerson;
|
||||
|
||||
if (!function_exists('construct_person_array')) {
|
||||
/**
|
||||
* Fetches persons from an episode
|
||||
*
|
||||
* @param array &$personsArray
|
||||
* @param Person[]|PodcastPerson[]|EpisodePerson[] $persons
|
||||
*/
|
||||
function construct_person_array(array $persons, &$personsArray): void
|
||||
function construct_person_array(array $persons, array &$personsArray): void
|
||||
{
|
||||
foreach ($persons as $person) {
|
||||
if (array_key_exists($person->person->id, $personsArray)) {
|
||||
$personsArray[$person->person->id]['roles'] .=
|
||||
if (array_key_exists($person->id, $personsArray)) {
|
||||
$personsArray[$person->id]['roles'] .=
|
||||
empty($person->person_group) || empty($person->person_role)
|
||||
? ''
|
||||
: (empty($personsArray[$person->person->id]['roles'])
|
||||
: (empty($personsArray[$person->id]['roles'])
|
||||
? ''
|
||||
: ', ') .
|
||||
lang(
|
||||
|
|
|
@ -16,10 +16,10 @@ if (!function_exists('get_rss_feed')) {
|
|||
/**
|
||||
* Generates the rss feed for a given podcast entity
|
||||
*
|
||||
* @param string $service The name of the service that fetches the RSS feed for future reference when the audio file is eventually downloaded
|
||||
* @param string $serviceSlug The name of the service that fetches the RSS feed for future reference when the audio file is eventually downloaded
|
||||
* @return string rss feed as xml
|
||||
*/
|
||||
function get_rss_feed(Podcast $podcast, $serviceSlug = ''): string
|
||||
function get_rss_feed(Podcast $podcast, ?string $serviceSlug = null): string
|
||||
{
|
||||
$episodes = $podcast->episodes;
|
||||
|
||||
|
@ -43,7 +43,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
$atom_link->addAttribute('rel', 'self');
|
||||
$atom_link->addAttribute('type', 'application/rss+xml');
|
||||
|
||||
if (!empty($podcast->new_feed_url)) {
|
||||
if ($podcast->new_feed_url !== null) {
|
||||
$channel->addChild(
|
||||
'new-feed-url',
|
||||
$podcast->new_feed_url,
|
||||
|
@ -67,23 +67,27 @@ if (!function_exists('get_rss_feed')) {
|
|||
|
||||
$itunes_image = $channel->addChild('image', null, $itunes_namespace);
|
||||
|
||||
$itunes_image->addAttribute('href', $podcast->image->original_url);
|
||||
// FIXME: This should be downsized to 1400x1400
|
||||
$itunes_image->addAttribute('href', $podcast->image->url);
|
||||
|
||||
$channel->addChild('language', $podcast->language_code);
|
||||
if (!empty($podcast->location_name)) {
|
||||
if ($podcast->location !== null) {
|
||||
$locationElement = $channel->addChild(
|
||||
'location',
|
||||
htmlspecialchars($podcast->location_name),
|
||||
htmlspecialchars($podcast->location->name),
|
||||
$podcast_namespace,
|
||||
);
|
||||
if (!empty($podcast->location_geo)) {
|
||||
$locationElement->addAttribute('geo', $podcast->location_geo);
|
||||
if ($podcast->location->geo !== null) {
|
||||
$locationElement->addAttribute('geo', $podcast->location->geo);
|
||||
}
|
||||
if (!empty($podcast->location_osmid)) {
|
||||
$locationElement->addAttribute('osm', $podcast->location_osmid);
|
||||
if ($podcast->location->osm_id !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'osm',
|
||||
$podcast->location->osm_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!empty($podcast->payment_pointer)) {
|
||||
if ($podcast->payment_pointer !== null) {
|
||||
$valueElement = $channel->addChild(
|
||||
'value',
|
||||
null,
|
||||
|
@ -103,7 +107,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
'address',
|
||||
$podcast->payment_pointer,
|
||||
);
|
||||
$recipientElement->addAttribute('split', 100);
|
||||
$recipientElement->addAttribute('split', '100');
|
||||
}
|
||||
$channel
|
||||
->addChild(
|
||||
|
@ -112,7 +116,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
$podcast_namespace,
|
||||
)
|
||||
->addAttribute('owner', $podcast->owner_email);
|
||||
if (!empty($podcast->imported_feed_url)) {
|
||||
if ($podcast->imported_feed_url !== null) {
|
||||
$channel->addChild(
|
||||
'previousUrl',
|
||||
$podcast->imported_feed_url,
|
||||
|
@ -120,7 +124,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
);
|
||||
}
|
||||
|
||||
foreach ($podcast->podcastingPlatforms as $podcastingPlatform) {
|
||||
foreach ($podcast->podcasting_platforms as $podcastingPlatform) {
|
||||
$podcastingPlatformElement = $channel->addChild(
|
||||
'id',
|
||||
null,
|
||||
|
@ -130,13 +134,13 @@ if (!function_exists('get_rss_feed')) {
|
|||
'platform',
|
||||
$podcastingPlatform->slug,
|
||||
);
|
||||
if (!empty($podcastingPlatform->link_content)) {
|
||||
if ($podcastingPlatform->link_content !== null) {
|
||||
$podcastingPlatformElement->addAttribute(
|
||||
'id',
|
||||
$podcastingPlatform->link_content,
|
||||
);
|
||||
}
|
||||
if (!empty($podcastingPlatform->link_url)) {
|
||||
if ($podcastingPlatform->link_url !== null) {
|
||||
$podcastingPlatformElement->addAttribute(
|
||||
'url',
|
||||
htmlspecialchars($podcastingPlatform->link_url),
|
||||
|
@ -144,7 +148,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($podcast->socialPlatforms as $socialPlatform) {
|
||||
foreach ($podcast->social_platforms as $socialPlatform) {
|
||||
$socialPlatformElement = $channel->addChild(
|
||||
'social',
|
||||
$socialPlatform->link_content,
|
||||
|
@ -154,7 +158,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
'platform',
|
||||
$socialPlatform->slug,
|
||||
);
|
||||
if (!empty($socialPlatform->link_url)) {
|
||||
if ($socialPlatform->link_url !== null) {
|
||||
$socialPlatformElement->addAttribute(
|
||||
'url',
|
||||
htmlspecialchars($socialPlatform->link_url),
|
||||
|
@ -162,7 +166,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($podcast->fundingPlatforms as $fundingPlatform) {
|
||||
foreach ($podcast->funding_platforms as $fundingPlatform) {
|
||||
$fundingPlatformElement = $channel->addChild(
|
||||
'funding',
|
||||
$fundingPlatform->link_content,
|
||||
|
@ -172,7 +176,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
'platform',
|
||||
$fundingPlatform->slug,
|
||||
);
|
||||
if (!empty($socialPlatform->link_url)) {
|
||||
if ($fundingPlatform->link_url !== null) {
|
||||
$fundingPlatformElement->addAttribute(
|
||||
'url',
|
||||
htmlspecialchars($fundingPlatform->link_url),
|
||||
|
@ -186,9 +190,10 @@ if (!function_exists('get_rss_feed')) {
|
|||
htmlspecialchars($podcastPerson->person->full_name),
|
||||
$podcast_namespace,
|
||||
);
|
||||
|
||||
if (
|
||||
!empty($podcastPerson->person_role) &&
|
||||
!empty($podcastPerson->person_group)
|
||||
$podcastPerson->person_role !== null &&
|
||||
$podcastPerson->person_group !== null
|
||||
) {
|
||||
$podcastPersonElement->addAttribute(
|
||||
'role',
|
||||
|
@ -201,7 +206,8 @@ if (!function_exists('get_rss_feed')) {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (!empty($podcastPerson->person_group)) {
|
||||
|
||||
if ($podcastPerson->person_group !== null) {
|
||||
$podcastPersonElement->addAttribute(
|
||||
'group',
|
||||
htmlspecialchars(
|
||||
|
@ -217,7 +223,8 @@ if (!function_exists('get_rss_feed')) {
|
|||
'img',
|
||||
$podcastPerson->person->image->large_url,
|
||||
);
|
||||
if (!empty($podcastPerson->person->information_url)) {
|
||||
|
||||
if ($podcastPerson->person->information_url !== null) {
|
||||
$podcastPersonElement->addAttribute(
|
||||
'href',
|
||||
$podcastPerson->person->information_url,
|
||||
|
@ -263,7 +270,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
$image->addChild('title', $podcast->title);
|
||||
$image->addChild('link', $podcast->link);
|
||||
|
||||
if (!empty($podcast->custom_rss)) {
|
||||
if ($podcast->custom_rss !== null) {
|
||||
array_to_rss(
|
||||
[
|
||||
'elements' => $podcast->custom_rss,
|
||||
|
@ -280,7 +287,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
$enclosure->addAttribute(
|
||||
'url',
|
||||
$episode->audio_file_analytics_url .
|
||||
(empty($serviceSlug)
|
||||
($serviceSlug === ''
|
||||
? ''
|
||||
: '?_from=' . urlencode($serviceSlug)),
|
||||
);
|
||||
|
@ -292,22 +299,22 @@ if (!function_exists('get_rss_feed')) {
|
|||
'pubDate',
|
||||
$episode->published_at->format(DATE_RFC1123),
|
||||
);
|
||||
if (!empty($episode->location_name)) {
|
||||
if ($episode->location !== null) {
|
||||
$locationElement = $item->addChild(
|
||||
'location',
|
||||
htmlspecialchars($episode->location_name),
|
||||
htmlspecialchars($episode->location->name),
|
||||
$podcast_namespace,
|
||||
);
|
||||
if (!empty($episode->location_geo)) {
|
||||
if ($episode->location->geo !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'geo',
|
||||
$episode->location_geo,
|
||||
$episode->location->geo,
|
||||
);
|
||||
}
|
||||
if (!empty($episode->location_osmid)) {
|
||||
if ($episode->location->osm_id !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'osm',
|
||||
$episode->location_osmid,
|
||||
$episode->location->osm_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +484,7 @@ if (!function_exists('add_category_tag')) {
|
|||
{
|
||||
$itunes_namespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
|
||||
|
||||
$itunes_category = $node->addChild('category', null, $itunes_namespace);
|
||||
$itunes_category = $node->addChild('category', '', $itunes_namespace);
|
||||
$itunes_category->addAttribute(
|
||||
'text',
|
||||
$category->parent !== null
|
||||
|
@ -488,7 +495,7 @@ if (!function_exists('add_category_tag')) {
|
|||
if ($category->parent !== null) {
|
||||
$itunes_category_child = $itunes_category->addChild(
|
||||
'category',
|
||||
null,
|
||||
'',
|
||||
$itunes_namespace,
|
||||
);
|
||||
$itunes_category_child->addAttribute(
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use CodeIgniter\HTTP\URI;
|
||||
|
||||
if (!function_exists('host_url')) {
|
||||
/**
|
||||
* Return the host URL to use in views
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
function host_url()
|
||||
function host_url(): ?string
|
||||
{
|
||||
if (isset($_SERVER['HTTP_HOST'])) {
|
||||
$protocol =
|
||||
|
@ -23,7 +23,7 @@ if (!function_exists('host_url')) {
|
|||
return $protocol . $_SERVER['HTTP_HOST'] . '/';
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,41 +43,13 @@ if (!function_exists('current_season_url')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('location_url')) {
|
||||
/**
|
||||
* Returns URL to display from location info
|
||||
*/
|
||||
function location_url(
|
||||
string $locationName,
|
||||
?string $locationGeo = null,
|
||||
?string $locationOsmid = null
|
||||
): string {
|
||||
if (!empty($locationOsmid)) {
|
||||
return 'https://www.openstreetmap.org/' .
|
||||
['N' => 'node', 'W' => 'way', 'R' => 'relation'][
|
||||
substr($locationOsmid, 0, 1)
|
||||
] .
|
||||
'/' .
|
||||
substr($locationOsmid, 1);
|
||||
}
|
||||
if (!empty($locationGeo)) {
|
||||
return 'https://www.openstreetmap.org/#map=17/' .
|
||||
str_replace(',', '/', substr($locationGeo, 4));
|
||||
}
|
||||
|
||||
return 'https://www.openstreetmap.org/search?query=' .
|
||||
urlencode($locationName);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('extract_params_from_episode_uri')) {
|
||||
/**
|
||||
* Returns podcast name and episode slug from episode string uri
|
||||
*
|
||||
* @param URI $episodeUri
|
||||
*/
|
||||
function extract_params_from_episode_uri($episodeUri): ?array
|
||||
function extract_params_from_episode_uri(URI $episodeUri): ?array
|
||||
{
|
||||
preg_match(
|
||||
'~@(?P<podcastName>[a-zA-Z0-9\_]{1,32})\/episodes\/(?P<episodeSlug>[a-zA-Z0-9\-]{1,191})~',
|
||||
|
|
|
@ -43,15 +43,11 @@ class ActivityRequest
|
|||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param string $activityPayload
|
||||
*/
|
||||
public function __construct($uri, $activityPayload = null)
|
||||
public function __construct(string $uri, ?string $activityPayload = null)
|
||||
{
|
||||
$this->request = Services::curlrequest();
|
||||
|
||||
if ($activityPayload) {
|
||||
if ($activityPayload !== null) {
|
||||
$this->request->setBody($activityPayload);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,15 +8,14 @@
|
|||
|
||||
namespace ActivityPub\Controllers;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Config\ActivityPub;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ActivityPub\Entities\Note;
|
||||
use CodeIgniter\HTTP\Exceptions\HTTPException;
|
||||
use ActivityPub\Objects\OrderedCollectionObject;
|
||||
use ActivityPub\Objects\OrderedCollectionPage;
|
||||
use App\Entities\Actor;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
|
@ -325,13 +324,10 @@ class ActorController extends Controller
|
|||
// parse activityPub id to get actor and domain
|
||||
// check if actor and domain exist
|
||||
|
||||
try {
|
||||
if ($parts = split_handle($this->request->getPost('handle'))) {
|
||||
extract($parts);
|
||||
|
||||
$data = get_webfinger_data($username, $domain);
|
||||
}
|
||||
} catch (HTTPException $httpException) {
|
||||
if (
|
||||
!($parts = split_handle($this->request->getPost('handle'))) ||
|
||||
!($data = get_webfinger_data($parts['username'], $parts['domain']))
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
@ -33,9 +33,12 @@ class BlockController extends Controller
|
|||
$handle = $this->request->getPost('handle');
|
||||
|
||||
if ($parts = split_handle($handle)) {
|
||||
extract($parts);
|
||||
|
||||
if (($actor = get_or_create_actor($username, $domain)) === null) {
|
||||
if (
|
||||
($actor = get_or_create_actor(
|
||||
$parts['username'],
|
||||
$parts['domain'],
|
||||
)) === null
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
@ -12,8 +12,8 @@ use CodeIgniter\HTTP\RedirectResponse;
|
|||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ActivityPub\Entities\Note;
|
||||
use CodeIgniter\HTTP\Exceptions\HTTPException;
|
||||
use ActivityPub\Config\ActivityPub;
|
||||
use ActivityPub\Models\NoteModel;
|
||||
use ActivityPub\Objects\OrderedCollectionObject;
|
||||
use ActivityPub\Objects\OrderedCollectionPage;
|
||||
use CodeIgniter\Controller;
|
||||
|
@ -27,7 +27,7 @@ class NoteController extends Controller
|
|||
protected $helpers = ['activitypub'];
|
||||
|
||||
/**
|
||||
* @var Note|null
|
||||
* @var Note
|
||||
*/
|
||||
protected $note;
|
||||
|
||||
|
@ -41,7 +41,7 @@ class NoteController extends Controller
|
|||
$this->config = config('ActivityPub');
|
||||
}
|
||||
|
||||
public function _remap($method, ...$params)
|
||||
public function _remap(string $method, string ...$params)
|
||||
{
|
||||
if (!($this->note = model('NoteModel')->getNoteById($params[0]))) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
@ -63,7 +63,8 @@ class NoteController extends Controller
|
|||
|
||||
public function replies(): RedirectResponse
|
||||
{
|
||||
// get note replies
|
||||
/** get note replies
|
||||
* @var NoteModel */
|
||||
$noteReplies = model('NoteModel')
|
||||
->where(
|
||||
'in_reply_to_id',
|
||||
|
@ -90,10 +91,14 @@ class NoteController extends Controller
|
|||
|
||||
$orderedItems = [];
|
||||
$noteObjectClass = $this->config->noteObject;
|
||||
foreach ($paginatedReplies as $reply) {
|
||||
$replyObject = new $noteObjectClass($reply);
|
||||
$orderedItems[] = $replyObject->toJSON();
|
||||
|
||||
if ($paginatedReplies !== null) {
|
||||
foreach ($paginatedReplies as $reply) {
|
||||
$replyObject = new $noteObjectClass($reply);
|
||||
$orderedItems[] = $replyObject->toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
$collection = new OrderedCollectionPage($pager, $orderedItems);
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,7 @@ class NoteController extends Controller
|
|||
->setBody($collection->toJSON());
|
||||
}
|
||||
|
||||
public function attemptCreate()
|
||||
public function attemptCreate(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'actor_id' => 'required|is_natural_no_zero',
|
||||
|
@ -134,7 +139,7 @@ class NoteController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptFavourite()
|
||||
public function attemptFavourite(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'actor_id' => 'required|is_natural_no_zero',
|
||||
|
@ -156,7 +161,7 @@ class NoteController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptReblog()
|
||||
public function attemptReblog(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'actor_id' => 'required|is_natural_no_zero',
|
||||
|
@ -178,7 +183,7 @@ class NoteController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptReply()
|
||||
public function attemptReply(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'actor_id' => 'required|is_natural_no_zero',
|
||||
|
@ -233,13 +238,10 @@ class NoteController extends Controller
|
|||
// get webfinger data from actor
|
||||
// parse activityPub id to get actor and domain
|
||||
// check if actor and domain exist
|
||||
try {
|
||||
if ($parts = split_handle($this->request->getPost('handle'))) {
|
||||
extract($parts);
|
||||
|
||||
$data = get_webfinger_data($username, $domain);
|
||||
}
|
||||
} catch (HTTPException $httpException) {
|
||||
if (
|
||||
!($parts = split_handle($this->request->getPost('handle'))) ||
|
||||
!($data = get_webfinger_data($parts['username'], $parts['domain']))
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
@ -266,21 +268,21 @@ class NoteController extends Controller
|
|||
);
|
||||
}
|
||||
|
||||
public function attemptBlockActor()
|
||||
public function attemptBlockActor(): RedirectResponse
|
||||
{
|
||||
model('ActorModel')->blockActor($this->note->actor->id);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptBlockDomain()
|
||||
public function attemptBlockDomain(): RedirectResponse
|
||||
{
|
||||
model('BlockedDomainModel')->blockDomain($this->note->actor->domain);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptDelete()
|
||||
public function attemptDelete(): RedirectResponse
|
||||
{
|
||||
model('NoteModel', false)->removeNote($this->note);
|
||||
|
||||
|
|
|
@ -15,7 +15,10 @@ namespace ActivityPub\Core;
|
|||
|
||||
abstract class AbstractObject
|
||||
{
|
||||
public function set($property, $value): self
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set(string $property, $value): self
|
||||
{
|
||||
$this->$property = $value;
|
||||
|
||||
|
@ -35,7 +38,7 @@ abstract class AbstractObject
|
|||
}
|
||||
|
||||
$array[$key] =
|
||||
is_object($value) && $value instanceof self
|
||||
is_object($value) && is_subclass_of($value, self::class)
|
||||
? $value->toArray()
|
||||
: $value;
|
||||
}
|
||||
|
|
|
@ -81,21 +81,21 @@ class AddNotes extends Migration
|
|||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'in_reply_to_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'reblog_of_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('activitypub_notes');
|
||||
|
|
|
@ -63,21 +63,21 @@ class AddActivities extends Migration
|
|||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'target_actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'note_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('activitypub_activities');
|
||||
|
|
|
@ -35,14 +35,14 @@ class AddFavourites extends Migration
|
|||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'note_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('activitypub_favourites');
|
||||
|
|
|
@ -37,14 +37,14 @@ class AddFollowers extends Migration
|
|||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'target_actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('activitypub_follows');
|
||||
|
|
|
@ -33,14 +33,14 @@ class AddNotesPreviewCards extends Migration
|
|||
'note_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'preview_card_id',
|
||||
'activitypub_preview_cards',
|
||||
'id',
|
||||
false,
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('activitypub_notes_preview_cards');
|
||||
|
|
|
@ -11,28 +11,42 @@ namespace ActivityPub\Entities;
|
|||
use RuntimeException;
|
||||
use Michalsn\Uuid\UuidEntity;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
* @property int $actor_id
|
||||
* @property Actor $actor
|
||||
* @property int|null $target_actor_id
|
||||
* @property Actor|null $target_actor
|
||||
* @property string|null $note_id
|
||||
* @property Note|null $note
|
||||
* @property string $type
|
||||
* @property object $payload
|
||||
* @property string|null $status
|
||||
* @property Time|null $scheduled_at
|
||||
* @property Time $created_at
|
||||
*/
|
||||
class Activity extends UuidEntity
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $uuids = ['id', 'note_id'];
|
||||
|
||||
/**
|
||||
* @var Actor
|
||||
*/
|
||||
protected $actor;
|
||||
|
||||
/**
|
||||
* @var Actor
|
||||
* @var Actor|null
|
||||
*/
|
||||
protected $target_actor;
|
||||
|
||||
/**
|
||||
* @var Note
|
||||
* @var Note|null
|
||||
*/
|
||||
protected $note;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $uuids = ['id', 'note_id'];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
|
@ -11,12 +11,36 @@ namespace ActivityPub\Entities;
|
|||
use RuntimeException;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $uri
|
||||
* @property string $username
|
||||
* @property string $domain
|
||||
* @property string $display_name
|
||||
* @property string|null $summary
|
||||
* @property string|null $private_key
|
||||
* @property string|null $public_key
|
||||
* @property string|null $public_key_id
|
||||
* @property string|null $avatar_image_url
|
||||
* @property string|null $avatar_image_mimetype
|
||||
* @property string|null $cover_image_url
|
||||
* @property string|null $cover_image_mimetype
|
||||
* @property string $inbox_url
|
||||
* @property string|null $outbox_url
|
||||
* @property string|null $followers_url
|
||||
* @property int $followers_count
|
||||
* @property int $notes_count
|
||||
* @property bool $is_blocked
|
||||
*
|
||||
* @property Actor[] $followers
|
||||
* @property bool $is_local
|
||||
*/
|
||||
class Actor extends Entity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key_id;
|
||||
protected $public_key_id;
|
||||
|
||||
/**
|
||||
* @var Actor[]
|
||||
|
@ -52,7 +76,7 @@ class Actor extends Entity
|
|||
'is_blocked' => 'boolean',
|
||||
];
|
||||
|
||||
public function getKeyId(): string
|
||||
public function getPublicKeyId(): string
|
||||
{
|
||||
return $this->uri . '#main-key';
|
||||
}
|
||||
|
@ -72,7 +96,7 @@ class Actor extends Entity
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Follower[]
|
||||
* @return Actor[]
|
||||
*/
|
||||
public function getFollowers(): array
|
||||
{
|
||||
|
|
|
@ -10,6 +10,9 @@ namespace ActivityPub\Entities;
|
|||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
*/
|
||||
class BlockedDomain extends Entity
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,10 @@ namespace ActivityPub\Entities;
|
|||
|
||||
use Michalsn\Uuid\UuidEntity;
|
||||
|
||||
/**
|
||||
* @property int $actor_id
|
||||
* @property string $note_id
|
||||
*/
|
||||
class Favourite extends UuidEntity
|
||||
{
|
||||
/**
|
||||
|
@ -22,6 +26,6 @@ class Favourite extends UuidEntity
|
|||
*/
|
||||
protected $casts = [
|
||||
'actor_id' => 'integer',
|
||||
'note_id' => 'integer',
|
||||
'note_id' => 'string',
|
||||
];
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ namespace ActivityPub\Entities;
|
|||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $actor_id
|
||||
* @property int $target_actor_id
|
||||
*/
|
||||
class Follow extends Entity
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -8,16 +8,38 @@
|
|||
|
||||
namespace ActivityPub\Entities;
|
||||
|
||||
use CodeIgniter\I18n\Time;
|
||||
use RuntimeException;
|
||||
use Michalsn\Uuid\UuidEntity;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
* @property string $uri
|
||||
* @property int $actor_id
|
||||
* @property Actor $actor
|
||||
* @property string|null $in_reply_to_id
|
||||
* @property bool $is_reply
|
||||
* @property Note|null $reply_to_note
|
||||
* @property string|null $reblog_of_id
|
||||
* @property bool $is_reblog
|
||||
* @property Note|null $reblog_of_note
|
||||
* @property string $message
|
||||
* @property string $message_html
|
||||
* @property int $favourites_count
|
||||
* @property int $reblogs_count
|
||||
* @property int $replies_count
|
||||
* @property Time $published_at
|
||||
* @property Time $created_at
|
||||
*
|
||||
* @property bool $has_preview_card
|
||||
* @property PreviewCard|null $preview_card
|
||||
*
|
||||
* @property bool $has_replies
|
||||
* @property Note[] $replies
|
||||
* @property Note[] $reblogs
|
||||
*/
|
||||
class Note extends UuidEntity
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $uuids = ['id', 'in_reply_to_id', 'reblog_of_id'];
|
||||
|
||||
/**
|
||||
* @var Actor
|
||||
*/
|
||||
|
@ -68,6 +90,11 @@ class Note extends UuidEntity
|
|||
*/
|
||||
protected $reblogs = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $uuids = ['id', 'in_reply_to_id', 'reblog_of_id'];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,20 @@ namespace ActivityPub\Entities;
|
|||
|
||||
use CodeIgniter\Entity\Entity;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $note_id
|
||||
* @property string $url
|
||||
* @property string $title
|
||||
* @property string $description
|
||||
* @property string $type
|
||||
* @property string|null $author_name
|
||||
* @property string|null $author_url
|
||||
* @property string|null $provider_name
|
||||
* @property string|null $provider_url
|
||||
* @property string|null $image
|
||||
* @property string|null $html
|
||||
*/
|
||||
class PreviewCard extends Entity
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,6 @@ if (!function_exists('get_webfinger_data')) {
|
|||
$webfingerUri = new URI();
|
||||
$webfingerUri->setScheme('https');
|
||||
$webfingerUri->setHost($domain);
|
||||
isset($port) && $webfingerUri->setPort((int) $port);
|
||||
$webfingerUri->setPath('/.well-known/webfinger');
|
||||
$webfingerUri->setQuery("resource=acct:{$username}@{$domain}");
|
||||
|
||||
|
@ -35,7 +34,7 @@ if (!function_exists('get_webfinger_data')) {
|
|||
|
||||
return json_decode(
|
||||
$webfingerResponse->getBody(),
|
||||
null,
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
@ -106,7 +105,7 @@ if (!function_exists('accept_follow')) {
|
|||
$targetActor->inbox_url,
|
||||
$acceptActivity->toJSON(),
|
||||
);
|
||||
$acceptRequest->sign($actor->key_id, $actor->private_key);
|
||||
$acceptRequest->sign($actor->public_key_id, $actor->private_key);
|
||||
$acceptRequest->post();
|
||||
} catch (Exception $exception) {
|
||||
$db->transRollback();
|
||||
|
@ -119,18 +118,21 @@ if (!function_exists('accept_follow')) {
|
|||
if (!function_exists('send_activity_to_followers')) {
|
||||
/**
|
||||
* Sends an activity to all actor followers
|
||||
*
|
||||
* @param string $activity
|
||||
*/
|
||||
function send_activity_to_followers(Actor $actor, $activityPayload): void
|
||||
{
|
||||
function send_activity_to_followers(
|
||||
Actor $actor,
|
||||
string $activityPayload
|
||||
): void {
|
||||
foreach ($actor->followers as $follower) {
|
||||
try {
|
||||
$acceptRequest = new ActivityRequest(
|
||||
$follower->inbox_url,
|
||||
$activityPayload,
|
||||
);
|
||||
$acceptRequest->sign($actor->key_id, $actor->private_key);
|
||||
$acceptRequest->sign(
|
||||
$actor->public_key_id,
|
||||
$actor->private_key,
|
||||
);
|
||||
$acceptRequest->post();
|
||||
} catch (Exception $e) {
|
||||
// log error
|
||||
|
@ -299,7 +301,7 @@ if (!function_exists('create_actor_from_uri')) {
|
|||
$actorResponse = $activityRequest->get();
|
||||
$actorPayload = json_decode(
|
||||
$actorResponse->getBody(),
|
||||
null,
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
@ -351,9 +353,9 @@ if (!function_exists('extract_text_from_html')) {
|
|||
/**
|
||||
* Extracts the text from html content
|
||||
*
|
||||
* @return string|string[]|null
|
||||
* @return string|null
|
||||
*/
|
||||
function extract_text_from_html(string $content)
|
||||
function extract_text_from_html(string $content): ?string
|
||||
{
|
||||
return preg_replace('~\s+~', ' ', strip_tags($content));
|
||||
}
|
||||
|
@ -364,12 +366,12 @@ if (!function_exists('linkify')) {
|
|||
* Turn all link elements in clickable links.
|
||||
* Transforms urls and handles
|
||||
*
|
||||
* @param string $value
|
||||
* @param array $protocols http/https, ftp, mail, twitter
|
||||
* @param array $attributes
|
||||
* @param string[] $protocols http/https, twitter
|
||||
*/
|
||||
function linkify($text, array $protocols = ['http', 'handle']): string
|
||||
{
|
||||
function linkify(
|
||||
string $text,
|
||||
array $protocols = ['http', 'handle']
|
||||
): string {
|
||||
$links = [];
|
||||
|
||||
// Extract text links for each protocol
|
||||
|
|
|
@ -97,15 +97,17 @@ class HttpSignature
|
|||
throw new Exception('Malformed signature string.');
|
||||
}
|
||||
|
||||
// extract parts as $keyId, $headers and $signature variables
|
||||
extract($parts);
|
||||
// set $keyId, $headers and $signature variables
|
||||
$keyId = $parts['keyId'];
|
||||
$headers = $parts['headers'];
|
||||
$signature = $parts['signature'];
|
||||
|
||||
// Fetch the public key linked from keyId
|
||||
$actorRequest = new ActivityRequest($keyId);
|
||||
$actorResponse = $actorRequest->get();
|
||||
$actor = json_decode(
|
||||
$actorResponse->getBody(),
|
||||
null,
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
namespace ActivityPub\Models;
|
||||
|
||||
use ActivityPub\Entities\Activity;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use DateTimeInterface;
|
||||
use Michalsn\Uuid\UuidModel;
|
||||
|
@ -76,7 +77,7 @@ class ActivityModel extends UuidModel
|
|||
*
|
||||
* @param Time $scheduledAt
|
||||
*
|
||||
* @return Michalsn\Uuid\BaseResult|int|string|false
|
||||
* @return BaseResult|int|string|false
|
||||
*/
|
||||
public function newActivity(
|
||||
string $type,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
namespace ActivityPub\Models;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use CodeIgniter\Database\Exceptions\DataException;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
|
@ -57,7 +58,7 @@ class ActorModel extends Model
|
|||
*/
|
||||
protected $useTimestamps = true;
|
||||
|
||||
public function getActorById($id)
|
||||
public function getActorById($id): Actor
|
||||
{
|
||||
$cacheName = config('ActivityPub')->cachePrefix . "actor#{$id}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
|
|
|
@ -49,8 +49,6 @@ class BlockedDomainModel extends Model
|
|||
|
||||
/**
|
||||
* Retrieves instance or podcast domain blocks depending on whether or not $podcastId param is set.
|
||||
*
|
||||
* @param integer|null $podcastId
|
||||
*/
|
||||
public function getBlockedDomains()
|
||||
{
|
||||
|
|
|
@ -137,7 +137,8 @@ class FavouriteModel extends UuidModel
|
|||
);
|
||||
}
|
||||
|
||||
$this->table('activitypub_favourites')
|
||||
$this->db
|
||||
->table('activitypub_favourites')
|
||||
->where([
|
||||
'actor_id' => $actor->id,
|
||||
'note_id' => service('uuid')
|
||||
|
|
|
@ -17,6 +17,7 @@ use ActivityPub\Activities\CreateActivity;
|
|||
use ActivityPub\Activities\DeleteActivity;
|
||||
use ActivityPub\Activities\UndoActivity;
|
||||
use ActivityPub\Objects\TombstoneObject;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
@ -489,7 +490,7 @@ class NoteModel extends UuidModel
|
|||
}
|
||||
|
||||
/**
|
||||
* @return ActivityPub\Models\BaseResult|int|string|false
|
||||
* @return BaseResult|int|string|false
|
||||
*/
|
||||
public function reblog(Actor $actor, Note $note, $registerActivity = true)
|
||||
{
|
||||
|
|
|
@ -72,9 +72,9 @@ class ActorObject extends ObjectType
|
|||
protected $icon = [];
|
||||
|
||||
/**
|
||||
* @var object
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $publicKey;
|
||||
protected $publicKey = [];
|
||||
|
||||
public function __construct(Actor $actor)
|
||||
{
|
||||
|
@ -101,10 +101,12 @@ class ActorObject extends ObjectType
|
|||
'url' => $actor->avatar_image_url,
|
||||
];
|
||||
|
||||
$this->publicKey = [
|
||||
'id' => $actor->key_id,
|
||||
'owner' => $actor->uri,
|
||||
'publicKeyPem' => $actor->public_key,
|
||||
];
|
||||
if ($actor->public_key !== null) {
|
||||
$this->publicKey = [
|
||||
'id' => $actor->public_key_id,
|
||||
'owner' => $actor->uri,
|
||||
'publicKeyPem' => $actor->public_key,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ class NoteObject extends ObjectType
|
|||
protected $inReplyTo;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
protected $replies = [];
|
||||
protected $replies;
|
||||
|
||||
/**
|
||||
* @param Note $note
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
namespace ActivityPub\Objects;
|
||||
|
||||
use ActivityPub\Core\Activity;
|
||||
use CodeIgniter\Pager\Pager;
|
||||
use ActivityPub\Core\ObjectType;
|
||||
|
||||
|
@ -28,17 +27,17 @@ class OrderedCollectionObject extends ObjectType
|
|||
protected $totalItems;
|
||||
|
||||
/**
|
||||
* @var integer|null
|
||||
* @var string|null
|
||||
*/
|
||||
protected $first;
|
||||
|
||||
/**
|
||||
* @var integer|null
|
||||
* @var string|null
|
||||
*/
|
||||
protected $current;
|
||||
|
||||
/**
|
||||
* @var integer|null
|
||||
* @var string|null
|
||||
*/
|
||||
protected $last;
|
||||
|
||||
|
|
|
@ -25,12 +25,12 @@ class OrderedCollectionPage extends OrderedCollectionObject
|
|||
protected $partOf;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
* @var string|null
|
||||
*/
|
||||
protected $prev;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
* @var string|null
|
||||
*/
|
||||
protected $next;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue