mirror of
https://github.com/ad-aures/castopod.git
synced 2026-04-16 13:07:46 +02:00
style(ecs): add easy-coding-standard to enforce coding style rules for php
- update .devcontainer settings: remove auto-formatting for php + set intelephense as default formatter - remove prettier php plugin as it lacks php 8 support - add captain hook action for checking style pre-commit - fix style with ecs on all files except views
This commit is contained in:
parent
fb3593f828
commit
aa1612342e
230 changed files with 3420 additions and 5884 deletions
|
|
@ -10,9 +10,9 @@
|
|||
"terminal.integrated.defaultProfile.linux": "/bin/bash",
|
||||
"editor.formatOnSave": true,
|
||||
"[php]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client",
|
||||
"editor.formatOnSave": false
|
||||
},
|
||||
"phpSniffer.autoDetect": true,
|
||||
"color-highlight.markerType": "dot-before",
|
||||
"files.associations": {
|
||||
"*.xml.dist": "xml",
|
||||
|
|
@ -31,7 +31,6 @@
|
|||
"jamesbirtles.svelte-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"stylelint.vscode-stylelint",
|
||||
"wongjn.php-sniffer",
|
||||
"eamodio.gitlens",
|
||||
"breezelin.phpstan",
|
||||
"kasik96.latte"
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Castopod">
|
||||
<description>Castopod Host's coding standard based on the PSR-1 standard.</description>
|
||||
|
||||
<!-- Include the whole PSR-1 standard -->
|
||||
<rule ref="PSR1"/>
|
||||
</ruleset>
|
||||
|
|
@ -1,13 +1,6 @@
|
|||
{
|
||||
"trailingComma": "es5",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.php",
|
||||
"options": {
|
||||
"phpVersion": "7.4",
|
||||
"singleQuote": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.md",
|
||||
"options": {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ 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.
|
||||
* The group model to use. Usually the class noted below (or an extension thereof) but can be any compatible
|
||||
* CodeIgniter Model.
|
||||
*
|
||||
* @var PermissionModel
|
||||
*/
|
||||
|
|
@ -18,19 +17,16 @@ class FlatAuthorization extends MythAuthFlatAuthorization
|
|||
/**
|
||||
* Checks a group to see if they have the specified permission.
|
||||
*/
|
||||
public function groupHasPermission(int|string $permission, int $groupId): bool
|
||||
public function groupHasPermission(int | string $permission, int $groupId): bool
|
||||
{
|
||||
// Get the Permission ID
|
||||
$permissionId = $this->getPermissionID($permission);
|
||||
|
||||
if (!is_numeric($permissionId)) {
|
||||
if (! is_numeric($permissionId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->permissionModel->doesGroupHavePermission(
|
||||
$groupId,
|
||||
$permissionId,
|
||||
);
|
||||
return $this->permissionModel->doesGroupHavePermission($groupId, $permissionId,);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,13 +7,10 @@ use Myth\Auth\Authorization\PermissionModel as MythAuthPermissionModel;
|
|||
class PermissionModel extends MythAuthPermissionModel
|
||||
{
|
||||
/**
|
||||
* Checks to see if a user, or one of their groups,
|
||||
* has a specific permission.
|
||||
* Checks to see if a user, or one of their groups, has a specific permission.
|
||||
*/
|
||||
public function doesGroupHavePermission(
|
||||
int $groupId,
|
||||
int $permissionId
|
||||
): bool {
|
||||
public function doesGroupHavePermission(int $groupId, int $permissionId): bool
|
||||
{
|
||||
// Check group permissions and take advantage of caching
|
||||
$groupPerms = $this->getPermissionsForGroup($groupId);
|
||||
|
||||
|
|
@ -22,28 +19,20 @@ class PermissionModel extends MythAuthPermissionModel
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets all permissions for a group in a way that can be
|
||||
* easily used to check against:
|
||||
* Gets all permissions for a group in a way that can be easily used to check against:
|
||||
*
|
||||
* [
|
||||
* id => name,
|
||||
* id => name
|
||||
* ]
|
||||
* [ id => name, id => name ]
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function getPermissionsForGroup(int $groupId): array
|
||||
{
|
||||
$cacheName = "group{$groupId}_permissions";
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$groupPermissions = $this->db
|
||||
->table('auth_groups_permissions')
|
||||
->select('id, auth_permissions.name')
|
||||
->join(
|
||||
'auth_permissions',
|
||||
'auth_permissions.id = permission_id',
|
||||
'inner',
|
||||
)
|
||||
->join('auth_permissions', 'auth_permissions.id = permission_id', 'inner',)
|
||||
->where('group_id', $groupId)
|
||||
->get()
|
||||
->getResultObject();
|
||||
|
|
@ -53,7 +42,8 @@ class PermissionModel extends MythAuthPermissionModel
|
|||
$found[$row->id] = strtolower($row->name);
|
||||
}
|
||||
|
||||
cache()->save($cacheName, $found, 300);
|
||||
cache()
|
||||
->save($cacheName, $found, 300);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The goal of this file is to allow developers a location
|
||||
* where they can overwrite core procedural functions and
|
||||
* replace them with their own. This file is loaded during
|
||||
* the bootstrap process and is called during the frameworks
|
||||
* The goal of this file is to allow developers a location where they can overwrite core procedural functions and
|
||||
* replace them with their own. This file is loaded during the bootstrap process and is called during the frameworks
|
||||
* execution.
|
||||
*
|
||||
* This can be looked at as a `master helper` file that is
|
||||
* loaded early on, and may also contain additional functions
|
||||
* This can be looked at as a `master helper` file that is loaded early on, and may also contain additional functions
|
||||
* that you'd like to use throughout your entire application
|
||||
*
|
||||
* @link: https://codeigniter4.github.io/CodeIgniter4/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<?php namespace Config;
|
||||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use App\Libraries\PodcastActor;
|
||||
use App\Libraries\NoteObject;
|
||||
use ActivityPub\Config\ActivityPub as ActivityPubBase;
|
||||
use App\Libraries\NoteObject;
|
||||
use App\Libraries\PodcastActor;
|
||||
|
||||
class ActivityPub extends ActivityPubBase
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ class Analytics extends AnalyticsBase
|
|||
|
||||
// set the analytics gateway behind the admin gateway.
|
||||
// Only logged in users should be able to view analytics
|
||||
$this->gateway = config('App')->adminGateway . '/analytics';
|
||||
$this->gateway = config('App')
|
||||
->adminGateway . '/analytics';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Session\Handlers\FileHandler;
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Session\Handlers\FileHandler;
|
||||
|
||||
class App extends BaseConfig
|
||||
{
|
||||
|
|
@ -21,7 +21,6 @@ class App extends BaseConfig
|
|||
* and path to your installation. However, you should always configure this
|
||||
* explicitly and never rely on auto-guessing, especially in production
|
||||
* environments.
|
||||
*
|
||||
*/
|
||||
public string $baseURL = 'http://localhost:8080/';
|
||||
|
||||
|
|
@ -34,7 +33,6 @@ class App extends BaseConfig
|
|||
* WITH a trailing slash:
|
||||
*
|
||||
* http://cdn.example.com/
|
||||
*
|
||||
*/
|
||||
public string $mediaBaseURL = 'http://127.0.0.2:8080/';
|
||||
|
||||
|
|
@ -46,7 +44,6 @@ class App extends BaseConfig
|
|||
* Typically this will be your index.php file, unless you've renamed it to
|
||||
* something else. If you are using mod_rewrite to remove the page set this
|
||||
* variable so that it is blank.
|
||||
*
|
||||
*/
|
||||
public string $indexPage = '';
|
||||
|
||||
|
|
@ -64,7 +61,6 @@ class App extends BaseConfig
|
|||
* 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
||||
*
|
||||
* WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||
*
|
||||
*/
|
||||
public string $uriProtocol = 'REQUEST_URI';
|
||||
|
||||
|
|
@ -77,7 +73,6 @@ class App extends BaseConfig
|
|||
* is viewing the site from. It affects the language strings and other
|
||||
* strings (like currency markers, numbers, etc), that your program
|
||||
* should run under for this request.
|
||||
*
|
||||
*/
|
||||
public string $defaultLocale = 'en';
|
||||
|
||||
|
|
@ -113,7 +108,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* The default timezone that will be used in your application to display
|
||||
* dates with the date helper, and can be retrieved through app_timezone()
|
||||
*
|
||||
*/
|
||||
public string $appTimezone = 'UTC';
|
||||
|
||||
|
|
@ -126,7 +120,6 @@ class App extends BaseConfig
|
|||
* that require a character set to be provided.
|
||||
*
|
||||
* @see http://php.net/htmlspecialchars for a list of supported charsets.
|
||||
*
|
||||
*/
|
||||
public string $charset = 'UTF-8';
|
||||
|
||||
|
|
@ -139,7 +132,6 @@ class App extends BaseConfig
|
|||
* made via a secure connection (HTTPS). If the incoming request is not
|
||||
* secure, the user will be redirected to a secure version of the page
|
||||
* and the HTTP Strict Transport Security header will be set.
|
||||
*
|
||||
*/
|
||||
public bool $forceGlobalSecureRequests = true;
|
||||
|
||||
|
|
@ -153,7 +145,6 @@ class App extends BaseConfig
|
|||
* - `CodeIgniter\Session\Handlers\DatabaseHandler`
|
||||
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
|
||||
* - `CodeIgniter\Session\Handlers\RedisHandler`
|
||||
*
|
||||
*/
|
||||
public string $sessionDriver = FileHandler::class;
|
||||
|
||||
|
|
@ -163,7 +154,6 @@ class App extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The session cookie name, must contain only [0-9a-z_-] characters
|
||||
*
|
||||
*/
|
||||
public string $sessionCookieName = 'ci_session';
|
||||
|
||||
|
|
@ -174,7 +164,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* The number of SECONDS you want the session to last.
|
||||
* Setting to 0 (zero) means expire when the browser is closed.
|
||||
*
|
||||
*/
|
||||
public int $sessionExpiration = 7200;
|
||||
|
||||
|
|
@ -192,7 +181,6 @@ class App extends BaseConfig
|
|||
* Please read up the manual for the format with other session drivers.
|
||||
*
|
||||
* IMPORTANT: You are REQUIRED to set a valid save path!
|
||||
*
|
||||
*/
|
||||
public string $sessionSavePath = WRITEPATH . 'session';
|
||||
|
||||
|
|
@ -205,7 +193,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* WARNING: If you're using the database driver, don't forget to update
|
||||
* your session table's PRIMARY KEY when changing this setting.
|
||||
*
|
||||
*/
|
||||
public bool $sessionMatchIP = false;
|
||||
|
||||
|
|
@ -215,7 +202,6 @@ class App extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* How many seconds between CI regenerating the session ID.
|
||||
*
|
||||
*/
|
||||
public int $sessionTimeToUpdate = 300;
|
||||
|
||||
|
|
@ -227,7 +213,6 @@ class App extends BaseConfig
|
|||
* Whether to destroy session data associated with the old session ID
|
||||
* when auto-regenerating the session ID. When set to FALSE, the data
|
||||
* will be later deleted by the garbage collector.
|
||||
*
|
||||
*/
|
||||
public bool $sessionRegenerateDestroy = false;
|
||||
|
||||
|
|
@ -238,8 +223,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* Set a cookie name prefix if you need to avoid collisions.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @deprecated use Config\Cookie::$prefix property instead.
|
||||
*/
|
||||
public string $cookiePrefix = '';
|
||||
|
|
@ -251,8 +234,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* Set to `.your-domain.com` for site-wide cookies.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @deprecated use Config\Cookie::$domain property instead.
|
||||
*/
|
||||
public string $cookieDomain = '';
|
||||
|
|
@ -264,8 +245,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* Typically will be a forward slash.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @deprecated use Config\Cookie::$path property instead.
|
||||
*/
|
||||
public string $cookiePath = '/';
|
||||
|
|
@ -277,8 +256,6 @@ class App extends BaseConfig
|
|||
*
|
||||
* Cookie will only be set if a secure HTTPS connection exists.
|
||||
*
|
||||
* @var bool
|
||||
*
|
||||
* @deprecated use Config\Cookie::$secure property instead.
|
||||
*/
|
||||
public bool $cookieSecure = false;
|
||||
|
|
@ -316,8 +293,6 @@ class App extends BaseConfig
|
|||
* (empty string) means default SameSite attribute set by browsers (`Lax`)
|
||||
* will be set on cookies. If set to `None`, `$cookieSecure` must also be set.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @deprecated use Config\Cookie::$samesite property instead.
|
||||
*/
|
||||
public string $cookieSameSite = 'Lax';
|
||||
|
|
@ -340,7 +315,7 @@ class App extends BaseConfig
|
|||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $proxyIPs = '';
|
||||
public string | array $proxyIPs = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class Autoload extends AutoloadConfig
|
|||
* @var array<string, string>
|
||||
*/
|
||||
public $psr4 = [
|
||||
APP_NAMESPACE => APPPATH, // For custom app namespace
|
||||
APP_NAMESPACE => APPPATH,
|
||||
'Config' => APPPATH . 'Config',
|
||||
'ActivityPub' => APPPATH . 'Libraries/ActivityPub',
|
||||
'Analytics' => APPPATH . 'Libraries/Analytics',
|
||||
|
|
|
|||
|
|
@ -8,14 +8,7 @@
|
|||
* it and display a generic error message.
|
||||
*/
|
||||
ini_set('display_errors', '0');
|
||||
error_reporting(
|
||||
E_ALL &
|
||||
~E_NOTICE &
|
||||
~E_DEPRECATED &
|
||||
~E_STRICT &
|
||||
~E_USER_NOTICE &
|
||||
~E_USER_DEPRECATED,
|
||||
);
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED,);
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ class Cache extends BaseConfig
|
|||
*
|
||||
* The name of the preferred handler that should be used. If for some reason
|
||||
* it is not available, the $backupHandler will be used in its place.
|
||||
*
|
||||
*/
|
||||
public string $handler = 'file';
|
||||
|
||||
|
|
@ -31,7 +30,6 @@ class Cache extends BaseConfig
|
|||
* The name of the handler that will be used in case the first one is
|
||||
* unreachable. Often, 'file' is used here since the filesystem is
|
||||
* always available, though that's not always practical for the app.
|
||||
*
|
||||
*/
|
||||
public string $backupHandler = 'dummy';
|
||||
|
||||
|
|
@ -64,7 +62,7 @@ class Cache extends BaseConfig
|
|||
*
|
||||
* @var boolean|string[]
|
||||
*/
|
||||
public bool|array $cacheQueryString = false;
|
||||
public bool | array $cacheQueryString = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
@ -73,7 +71,6 @@ class Cache extends BaseConfig
|
|||
*
|
||||
* This string is added to all cache item names to help avoid collisions
|
||||
* if you run multiple applications with the same cache engine.
|
||||
*
|
||||
*/
|
||||
public string $prefix = '';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ namespace Config;
|
|||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Stores the default settings for the ContentSecurityPolicy, if you
|
||||
* choose to use it. The values here will be read in and set as defaults
|
||||
* for the site. If needed, they can be overridden on a page-by-page basis.
|
||||
* Stores the default settings for the ContentSecurityPolicy, if you choose to use it. The values here will be read in
|
||||
* and set as defaults for the site. If needed, they can be overridden on a page-by-page basis.
|
||||
*
|
||||
* Suggested reference for explanations:
|
||||
*
|
||||
|
|
@ -15,64 +14,49 @@ use CodeIgniter\Config\BaseConfig;
|
|||
*/
|
||||
class ContentSecurityPolicy extends BaseConfig
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// Broadbrush CSP management
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default CSP report context
|
||||
*
|
||||
*/
|
||||
public bool $reportOnly = false;
|
||||
|
||||
/**
|
||||
* Specifies a URL where a browser will send reports
|
||||
* when a content security policy is violated.
|
||||
*
|
||||
* @var string|null
|
||||
* Specifies a URL where a browser will send reports when a content security policy is violated.
|
||||
*/
|
||||
public ?string $reportURI = null;
|
||||
|
||||
/**
|
||||
* Instructs user agents to rewrite URL schemes, changing
|
||||
* HTTP to HTTPS. This directive is for websites with
|
||||
* large numbers of old URLs that need to be rewritten.
|
||||
*
|
||||
* Instructs user agents to rewrite URL schemes, changing HTTP to HTTPS. This directive is for websites with large
|
||||
* numbers of old URLs that need to be rewritten.
|
||||
*/
|
||||
public bool $upgradeInsecureRequests = false;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Sources allowed
|
||||
// Note: once you set a policy to 'none', it cannot be further restricted
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Will default to self if not overridden
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $defaultSrc;
|
||||
public string | array | null $defaultSrc;
|
||||
|
||||
/**
|
||||
* Lists allowed scripts' URLs.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $scriptSrc = 'self';
|
||||
public string | array $scriptSrc = 'self';
|
||||
|
||||
/**
|
||||
* Lists allowed stylesheets' URLs.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $styleSrc = 'self';
|
||||
public string | array $styleSrc = 'self';
|
||||
|
||||
/**
|
||||
* Defines the origins from which images can be loaded.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $imageSrc = 'self';
|
||||
public string | array $imageSrc = 'self';
|
||||
|
||||
/**
|
||||
* Restricts the URLs that can appear in a page's `<base>` element.
|
||||
|
|
@ -81,77 +65,75 @@ class ContentSecurityPolicy extends BaseConfig
|
|||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $baseURI;
|
||||
public string | array | null $baseURI;
|
||||
|
||||
/**
|
||||
* Lists the URLs for workers and embedded frame contents
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $childSrc = 'self';
|
||||
public string | array $childSrc = 'self';
|
||||
|
||||
/**
|
||||
* Limits the origins that you can connect to (via XHR,
|
||||
* WebSockets, and EventSource).
|
||||
* Limits the origins that you can connect to (via XHR, WebSockets, and EventSource).
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $connectSrc = 'self';
|
||||
public string | array $connectSrc = 'self';
|
||||
|
||||
/**
|
||||
* Specifies the origins that can serve web fonts.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $fontSrc;
|
||||
public string | array $fontSrc;
|
||||
|
||||
/**
|
||||
* Lists valid endpoints for submission from `<form>` tags.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $formAction = 'self';
|
||||
public string | array $formAction = 'self';
|
||||
|
||||
/**
|
||||
* Specifies the sources that can embed the current page.
|
||||
* This directive applies to `<frame>`, `<iframe>`, `<embed>`,
|
||||
* and `<applet>` tags. This directive can't be used in
|
||||
* `<meta>` tags and applies only to non-HTML resources.
|
||||
* Specifies the sources that can embed the current page. This directive applies to `<frame>`, `<iframe>`,
|
||||
* `<embed>`, and `<applet>` tags. This directive can't be used in `<meta>` tags and applies only to non-HTML
|
||||
* resources.
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $frameAncestors;
|
||||
public string | array | null $frameAncestors;
|
||||
|
||||
/**
|
||||
* Restricts the origins allowed to deliver video and audio.
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $mediaSrc;
|
||||
public string | array | null $mediaSrc;
|
||||
|
||||
/**
|
||||
* Allows control over Flash and other plugins.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public string|array $objectSrc = 'self';
|
||||
public string | array $objectSrc = 'self';
|
||||
|
||||
/**
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $manifestSrc;
|
||||
public string | array | null $manifestSrc;
|
||||
|
||||
/**
|
||||
* Limits the kinds of plugins a page may invoke.
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $pluginTypes;
|
||||
public string | array | null $pluginTypes;
|
||||
|
||||
/**
|
||||
* List of actions allowed.
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public string|array|null $sandbox;
|
||||
public string | array | null $sandbox;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ class Cookie extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Set a cookie name prefix if you need to avoid collisions.
|
||||
*
|
||||
*/
|
||||
public string $prefix = '';
|
||||
|
||||
|
|
@ -25,9 +24,8 @@ class Cookie extends BaseConfig
|
|||
* Default expires timestamp for cookies. Setting this to `0` will mean the
|
||||
* cookie will not have the `Expires` attribute and will behave as a session
|
||||
* cookie.
|
||||
*
|
||||
*/
|
||||
public DateTimeInterface|int|string $expires = 0;
|
||||
public DateTimeInterface | int | string $expires = 0;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
@ -35,7 +33,6 @@ class Cookie extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Typically will be a forward slash.
|
||||
*
|
||||
*/
|
||||
public string $path = '/';
|
||||
|
||||
|
|
@ -45,7 +42,6 @@ class Cookie extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Set to `.your-domain.com` for site-wide cookies.
|
||||
*
|
||||
*/
|
||||
public string $domain = '';
|
||||
|
||||
|
|
@ -55,7 +51,6 @@ class Cookie extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie will only be set if a secure HTTPS connection exists.
|
||||
*
|
||||
*/
|
||||
public bool $secure = false;
|
||||
|
||||
|
|
@ -65,7 +60,6 @@ class Cookie extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie will only be accessible via HTTP(S) (no JavaScript).
|
||||
*
|
||||
*/
|
||||
public bool $httponly = true;
|
||||
|
||||
|
|
@ -88,7 +82,6 @@ class Cookie extends BaseConfig
|
|||
* Defaults to `Lax` for compatibility with modern browsers. Setting `''`
|
||||
* (empty string) means default SameSite attribute set by browsers (`Lax`)
|
||||
* will be set on cookies. If set to `None`, `$secure` must also be set.
|
||||
*
|
||||
*/
|
||||
public string $samesite = 'Lax';
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,12 @@ use CodeIgniter\Database\Config;
|
|||
class Database extends Config
|
||||
{
|
||||
/**
|
||||
* The directory that holds the Migrations
|
||||
* and Seeds directories.
|
||||
* The directory that holds the Migrations and Seeds directories.
|
||||
*/
|
||||
public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Lets you choose which connection group to
|
||||
* use if no other is specified.
|
||||
* Lets you choose which connection group to use if no other is specified.
|
||||
*/
|
||||
public string $defaultGroup = 'default';
|
||||
|
||||
|
|
@ -47,8 +45,7 @@ class Database extends Config
|
|||
];
|
||||
|
||||
/**
|
||||
* This database connection is used when
|
||||
* running PHPUnit database tests.
|
||||
* This database connection is used when running PHPUnit database tests.
|
||||
*
|
||||
* @noRector StringClassNameToClassConstantRector
|
||||
*
|
||||
|
|
@ -61,7 +58,7 @@ class Database extends Config
|
|||
'password' => '',
|
||||
'database' => ':memory:',
|
||||
'DBDriver' => 'SQLite3',
|
||||
'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
|
||||
'DBPrefix' => 'db_',
|
||||
'pConnect' => false,
|
||||
'DBDebug' => ENVIRONMENT !== 'production',
|
||||
'charset' => 'utf8',
|
||||
|
|
|
|||
|
|
@ -14,127 +14,106 @@ class Email extends BaseConfig
|
|||
|
||||
/**
|
||||
* The "user agent"
|
||||
*
|
||||
*/
|
||||
public string $userAgent = 'CodeIgniter';
|
||||
|
||||
/**
|
||||
* The mail sending protocol: mail, sendmail, smtp
|
||||
*
|
||||
*/
|
||||
public string $protocol = 'mail';
|
||||
|
||||
/**
|
||||
* The server path to Sendmail.
|
||||
*
|
||||
*/
|
||||
public string $mailPath = '/usr/sbin/sendmail';
|
||||
|
||||
/**
|
||||
* SMTP Server Address
|
||||
*
|
||||
*/
|
||||
public string $SMTPHost;
|
||||
|
||||
/**
|
||||
* SMTP Username
|
||||
*
|
||||
*/
|
||||
public string $SMTPUser;
|
||||
|
||||
/**
|
||||
* SMTP Password
|
||||
*
|
||||
*/
|
||||
public string $SMTPPass;
|
||||
|
||||
/**
|
||||
* SMTP Port
|
||||
*
|
||||
*/
|
||||
public int $SMTPPort = 25;
|
||||
|
||||
/**
|
||||
* SMTP Timeout (in seconds)
|
||||
*
|
||||
*/
|
||||
public int $SMTPTimeout = 5;
|
||||
|
||||
/**
|
||||
* Enable persistent SMTP connections
|
||||
*
|
||||
*/
|
||||
public bool $SMTPKeepAlive = false;
|
||||
|
||||
/**
|
||||
* SMTP Encryption. Either tls or ssl
|
||||
*
|
||||
*/
|
||||
public string $SMTPCrypto = 'tls';
|
||||
|
||||
/**
|
||||
* Enable word-wrap
|
||||
*
|
||||
*/
|
||||
public bool $wordWrap = true;
|
||||
|
||||
/**
|
||||
* Character count to wrap at
|
||||
*
|
||||
*/
|
||||
public int $wrapChars = 76;
|
||||
|
||||
/**
|
||||
* Type of mail, either 'text' or 'html'
|
||||
*
|
||||
*/
|
||||
public string $mailType = 'text';
|
||||
|
||||
/**
|
||||
* Character set (utf-8, iso-8859-1, etc.)
|
||||
*
|
||||
*/
|
||||
public string $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* Whether to validate the email address
|
||||
*
|
||||
*/
|
||||
public bool $validate = false;
|
||||
|
||||
/**
|
||||
* Email Priority. 1 = highest. 5 = lowest. 3 = normal
|
||||
*
|
||||
*/
|
||||
public int $priority = 3;
|
||||
|
||||
/**
|
||||
* Newline character. (Use “\r\n” to comply with RFC 822)
|
||||
*
|
||||
*/
|
||||
public string $CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Newline character. (Use “\r\n” to comply with RFC 822)
|
||||
*
|
||||
*/
|
||||
public string $newline = "\r\n";
|
||||
|
||||
/**
|
||||
* Enable BCC Batch Mode.
|
||||
*
|
||||
*/
|
||||
public bool $BCCBatchMode = false;
|
||||
|
||||
/**
|
||||
* Number of emails in each BCC batch
|
||||
*
|
||||
*/
|
||||
public int $BCCBatchSize = 200;
|
||||
|
||||
/**
|
||||
* Enable notify message from server
|
||||
*
|
||||
*/
|
||||
public bool $DSN = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use CodeIgniter\Config\BaseConfig;
|
|||
/**
|
||||
* Encryption configuration.
|
||||
*
|
||||
* These are the settings used for encryption, if you don't pass a parameter
|
||||
* array to the encrypter for creation/initialization.
|
||||
* These are the settings used for encryption, if you don't pass a parameter array to the encrypter for
|
||||
* creation/initialization.
|
||||
*/
|
||||
class Encryption extends BaseConfig
|
||||
{
|
||||
|
|
@ -20,7 +20,6 @@ class Encryption extends BaseConfig
|
|||
* If you use the Encryption class you must set an encryption key (seed).
|
||||
* You need to ensure it is long enough for the cipher and mode you plan to use.
|
||||
* See the user guide for more info.
|
||||
*
|
||||
*/
|
||||
public string $key = '';
|
||||
|
||||
|
|
@ -34,7 +33,6 @@ class Encryption extends BaseConfig
|
|||
* Available drivers:
|
||||
* - OpenSSL
|
||||
* - Sodium
|
||||
*
|
||||
*/
|
||||
public string $driver = 'OpenSSL';
|
||||
|
||||
|
|
@ -47,7 +45,6 @@ class Encryption extends BaseConfig
|
|||
* before it is encrypted. This value should be greater than zero.
|
||||
*
|
||||
* See the user guide for more information on padding.
|
||||
*
|
||||
*/
|
||||
public int $blockSize = 16;
|
||||
|
||||
|
|
@ -57,7 +54,6 @@ class Encryption extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
|
||||
*
|
||||
*/
|
||||
public string $digest = 'SHA512';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,7 @@ Events::on('pre_system', function () {
|
|||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
if (CI_DEBUG) {
|
||||
Events::on(
|
||||
'DBQuery',
|
||||
'CodeIgniter\Debug\Toolbar\Collectors\Database::collect',
|
||||
);
|
||||
Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect',);
|
||||
Services::toolbar()->respond();
|
||||
}
|
||||
});
|
||||
|
|
@ -90,7 +87,8 @@ Events::on('on_note_add', function (Note $note): void {
|
|||
|
||||
// Removing all of the podcast pages is a bit overkill, but works perfectly
|
||||
// same for other events below
|
||||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_note_remove', function (Note $note): void {
|
||||
|
|
@ -108,8 +106,10 @@ Events::on('on_note_remove', function (Note $note): void {
|
|||
->decrement('favourites_total', $note->favourites_count);
|
||||
}
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_note_reblog', function (Actor $actor, Note $note): void {
|
||||
|
|
@ -123,8 +123,10 @@ Events::on('on_note_reblog', function (Actor $actor, Note $note): void {
|
|||
->increment('notes_total');
|
||||
}
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
|
||||
if ($actor->is_podcast) {
|
||||
cache()->deleteMatching("page_podcast#{$actor->podcast->id}*");
|
||||
|
|
@ -143,28 +145,32 @@ Events::on('on_note_undo_reblog', function (Note $reblogNote): void {
|
|||
->decrement('notes_total');
|
||||
}
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
|
||||
if ($reblogNote->actor->is_podcast) {
|
||||
cache()->deleteMatching(
|
||||
"page_podcast#{$reblogNote->actor->podcast->id}*",
|
||||
);
|
||||
cache()->deleteMatching("page_podcast#{$reblogNote->actor->podcast->id}*",);
|
||||
}
|
||||
});
|
||||
|
||||
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}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
});
|
||||
|
||||
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}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
});
|
||||
|
||||
Events::on('on_note_favourite', function (Actor $actor, Note $note): void {
|
||||
|
|
@ -174,8 +180,10 @@ Events::on('on_note_favourite', function (Actor $actor, Note $note): void {
|
|||
->increment('favourites_total');
|
||||
}
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
|
||||
if ($note->in_reply_to_id) {
|
||||
cache()->deleteMatching("page_note#{$note->in_reply_to_id}*");
|
||||
|
|
@ -189,8 +197,10 @@ Events::on('on_note_undo_favourite', function (Actor $actor, Note $note): void {
|
|||
->decrement('favourites_total');
|
||||
}
|
||||
|
||||
cache()->deleteMatching("page_podcast#{$actor->podcast->id}*");
|
||||
cache()->deleteMatching("page_note#{$note->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_podcast#{$actor->podcast->id}*");
|
||||
cache()
|
||||
->deleteMatching("page_note#{$note->id}*");
|
||||
|
||||
if ($note->in_reply_to_id) {
|
||||
cache()->deleteMatching("page_note#{$note->in_reply_to_id}*");
|
||||
|
|
@ -199,20 +209,24 @@ Events::on('on_note_undo_favourite', function (Actor $actor, Note $note): void {
|
|||
|
||||
Events::on('on_block_actor', function (int $actorId): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
cache()
|
||||
->deleteMatching('page_note*');
|
||||
});
|
||||
|
||||
Events::on('on_unblock_actor', function (int $actorId): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
cache()
|
||||
->deleteMatching('page_note*');
|
||||
});
|
||||
|
||||
Events::on('on_block_domain', function (string $domainName): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
cache()
|
||||
->deleteMatching('page_note*');
|
||||
});
|
||||
|
||||
Events::on('on_unblock_domain', function (string $domainName): void {
|
||||
cache()->deleteMatching('page_podcast*');
|
||||
cache()->deleteMatching('page_note*');
|
||||
cache()
|
||||
->deleteMatching('page_note*');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class Exceptions extends BaseConfig
|
|||
* through Services::Log.
|
||||
*
|
||||
* Default: true
|
||||
*
|
||||
*/
|
||||
public bool $log = true;
|
||||
|
||||
|
|
@ -40,7 +39,6 @@ class Exceptions extends BaseConfig
|
|||
* directories that hold the views used to generate errors.
|
||||
*
|
||||
* Default: APPPATH.'Views/errors'
|
||||
*
|
||||
*/
|
||||
public string $errorViewPath = APPPATH . 'Views/errors';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,20 +2,19 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use Myth\Auth\Filters\LoginFilter;
|
||||
use Myth\Auth\Filters\RoleFilter;
|
||||
use App\Filters\PermissionFilter;
|
||||
use ActivityPub\Filters\ActivityPubFilter;
|
||||
use App\Filters\PermissionFilter;
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Filters\CSRF;
|
||||
use CodeIgniter\Filters\DebugToolbar;
|
||||
use CodeIgniter\Filters\Honeypot;
|
||||
use Myth\Auth\Filters\LoginFilter;
|
||||
use Myth\Auth\Filters\RoleFilter;
|
||||
|
||||
class Filters extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Configures aliases for Filter classes to
|
||||
* make reading things nicer and simpler.
|
||||
* Configures aliases for Filter classes to make reading things nicer and simpler.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
|
|
@ -30,8 +29,7 @@ class Filters extends BaseConfig
|
|||
];
|
||||
|
||||
/**
|
||||
* List of filter aliases that are always
|
||||
* applied before and after every request.
|
||||
* List of filter aliases that are always applied before and after every request.
|
||||
*
|
||||
* @var array<string, string[]>
|
||||
*/
|
||||
|
|
@ -47,22 +45,18 @@ class Filters extends BaseConfig
|
|||
];
|
||||
|
||||
/**
|
||||
* List of filter aliases that works on a
|
||||
* particular HTTP method (GET, POST, etc.).
|
||||
* List of filter aliases that works on a particular HTTP method (GET, POST, etc.).
|
||||
*
|
||||
* Example:
|
||||
* 'post' => ['csrf', 'throttle']
|
||||
* Example: 'post' => ['csrf', 'throttle']
|
||||
*
|
||||
* @var array<string, string[]>
|
||||
*/
|
||||
public array $methods = [];
|
||||
|
||||
/**
|
||||
* List of filter aliases that should run on any
|
||||
* before or after URI patterns.
|
||||
* List of filter aliases that should run on any before or after URI patterns.
|
||||
*
|
||||
* Example:
|
||||
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
* Example: 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
*
|
||||
* @var array<string, array<string, string[]>>
|
||||
*/
|
||||
|
|
@ -73,7 +67,9 @@ class Filters extends BaseConfig
|
|||
parent::__construct();
|
||||
|
||||
$this->filters = [
|
||||
'login' => ['before' => [config('App')->adminGateway . '*']],
|
||||
'login' => [
|
||||
'before' => [config('App')->adminGateway . '*'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Format\JSONFormatter;
|
||||
use CodeIgniter\Format\XMLFormatter;
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Format\FormatterInterface;
|
||||
use CodeIgniter\Format\JSONFormatter;
|
||||
use CodeIgniter\Format\XMLFormatter;
|
||||
|
||||
class Format extends BaseConfig
|
||||
{
|
||||
|
|
@ -64,6 +64,7 @@ class Format extends BaseConfig
|
|||
];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A Factory method to return the appropriate formatter for the given mime type.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -8,31 +8,26 @@ class Honeypot extends BaseConfig
|
|||
{
|
||||
/**
|
||||
* Makes Honeypot visible or not to human
|
||||
*
|
||||
*/
|
||||
public bool $hidden = true;
|
||||
|
||||
/**
|
||||
* Honeypot Label Content
|
||||
*
|
||||
*/
|
||||
public string $label = 'Fill This Field';
|
||||
|
||||
/**
|
||||
* Honeypot Field Name
|
||||
*
|
||||
*/
|
||||
public string $name = 'honeypot';
|
||||
|
||||
/**
|
||||
* Honeypot HTML Template
|
||||
*
|
||||
*/
|
||||
public string $template = '<label>{label}</label><input type="text" name="{name}" value=""/>';
|
||||
|
||||
/**
|
||||
* Honeypot container
|
||||
*
|
||||
*/
|
||||
public string $container = '<div style="display:none">{template}</div>';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,11 @@ class Images extends BaseConfig
|
|||
{
|
||||
/**
|
||||
* Default handler used if no other handler is specified.
|
||||
*
|
||||
*/
|
||||
public string $defaultHandler = 'gd';
|
||||
|
||||
/**
|
||||
* The path to the image library.
|
||||
* Required for ImageMagick, GraphicsMagick, or NetPBM.
|
||||
*
|
||||
* The path to the image library. Required for ImageMagick, GraphicsMagick, or NetPBM.
|
||||
*/
|
||||
public string $libraryPath = '/usr/local/bin/convert';
|
||||
|
||||
|
|
@ -32,15 +29,17 @@ class Images extends BaseConfig
|
|||
];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Uploaded images resizing sizes (in px)
|
||||
|--------------------------------------------------------------------------
|
||||
| Uploaded images resizing sizes (in px)
|
||||
|--------------------------------------------------------------------------
|
||||
| The sizes listed below determine the resizing of images when uploaded.
|
||||
| All uploaded images are of 1:1 ratio (width and height are the same).
|
||||
*/
|
||||
*/
|
||||
|
||||
public int $thumbnailSize = 150;
|
||||
|
||||
public int $mediumSize = 320;
|
||||
|
||||
public int $largeSize = 1024;
|
||||
|
||||
/**
|
||||
|
|
@ -54,11 +53,11 @@ class Images extends BaseConfig
|
|||
public int $id3Size = 500;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Uploaded images naming extensions
|
||||
|--------------------------------------------------------------------------
|
||||
| Uploaded images naming extensions
|
||||
|--------------------------------------------------------------------------
|
||||
| The properties listed below set the name extensions for the resized images
|
||||
*/
|
||||
*/
|
||||
|
||||
public string $thumbnailSuffix = '_thumbnail';
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ use Kint\Renderer\Renderer;
|
|||
class Kint extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Log\Handlers\FileHandler;
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Log\Handlers\FileHandler;
|
||||
|
||||
class Logger extends BaseConfig
|
||||
{
|
||||
|
|
@ -38,7 +38,7 @@ class Logger extends BaseConfig
|
|||
*
|
||||
* @var int|int[]
|
||||
*/
|
||||
public int|array $threshold = 4;
|
||||
public int | array $threshold = 4;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
|
@ -47,8 +47,6 @@ class Logger extends BaseConfig
|
|||
*
|
||||
* Each item that is logged has an associated date. You can use PHP date
|
||||
* codes to set your own date formatting
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $dateFormat = 'Y-m-d H:i:s';
|
||||
|
||||
|
|
@ -87,16 +85,7 @@ class Logger extends BaseConfig
|
|||
/*
|
||||
* The log levels that this handler will handle.
|
||||
*/
|
||||
'handles' => [
|
||||
'critical',
|
||||
'alert',
|
||||
'emergency',
|
||||
'debug',
|
||||
'error',
|
||||
'info',
|
||||
'notice',
|
||||
'warning',
|
||||
],
|
||||
'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'],
|
||||
|
||||
/*
|
||||
* The default filename extension for log files.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ class Migrations extends BaseConfig
|
|||
*
|
||||
* You should enable migrations whenever you intend to do a schema migration
|
||||
* and disable it back when you're done.
|
||||
*
|
||||
*/
|
||||
public bool $enabled = true;
|
||||
|
||||
|
|
@ -29,7 +28,6 @@ class Migrations extends BaseConfig
|
|||
* level the system is at. It then compares the migration level in this
|
||||
* table to the $config['migration_version'] if they are not the same it
|
||||
* will migrate up. This must be set.
|
||||
*
|
||||
*/
|
||||
public string $table = 'migrations';
|
||||
|
||||
|
|
@ -46,7 +44,6 @@ class Migrations extends BaseConfig
|
|||
* - YmdHis_
|
||||
* - Y-m-d-His_
|
||||
* - Y_m_d_His_
|
||||
*
|
||||
*/
|
||||
public string $timestampFormat = 'Y-m-d-His_';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,16 +5,13 @@ namespace Config;
|
|||
/**
|
||||
* Mimes
|
||||
*
|
||||
* This file contains an array of mime types. It is used by the
|
||||
* Upload class to help identify allowed file types.
|
||||
* This file contains an array of mime types. It is used by the Upload class to help identify allowed file types.
|
||||
*
|
||||
* When more than one variation for an extension exist (like jpg, jpeg, etc)
|
||||
* the most common one should be first in the array to aid the guess*
|
||||
* methods. The same applies when more than one mime-type exists for a
|
||||
* single extension.
|
||||
* When more than one variation for an extension exist (like jpg, jpeg, etc) the most common one should be first in the
|
||||
* array to aid the guess* methods. The same applies when more than one mime-type exists for a single extension.
|
||||
*
|
||||
* When working with mime types, please make sure you have the ´fileinfo´
|
||||
* extension enabled to reliably detect the media types.
|
||||
* When working with mime types, please make sure you have the ´fileinfo´ extension enabled to reliably detect the
|
||||
* media types.
|
||||
*/
|
||||
|
||||
class Mimes
|
||||
|
|
@ -61,11 +58,7 @@ class Mimes
|
|||
'sea' => 'application/octet-stream',
|
||||
'dll' => 'application/octet-stream',
|
||||
'oda' => 'application/oda',
|
||||
'pdf' => [
|
||||
'application/pdf',
|
||||
'application/force-download',
|
||||
'application/x-download',
|
||||
],
|
||||
'pdf' => ['application/pdf', 'application/force-download', 'application/x-download'],
|
||||
'ai' => ['application/pdf', 'application/postscript'],
|
||||
'eps' => 'application/postscript',
|
||||
'ps' => 'application/postscript',
|
||||
|
|
@ -133,12 +126,7 @@ class Mimes
|
|||
'application/s-compressed',
|
||||
'multipart/x-zip',
|
||||
],
|
||||
'rar' => [
|
||||
'application/vnd.rar',
|
||||
'application/x-rar',
|
||||
'application/rar',
|
||||
'application/x-rar-compressed',
|
||||
],
|
||||
'rar' => ['application/vnd.rar', 'application/x-rar', 'application/rar', 'application/x-rar-compressed'],
|
||||
'mid' => 'audio/midi',
|
||||
'midi' => 'audio/midi',
|
||||
'mpga' => 'audio/mpeg',
|
||||
|
|
@ -197,12 +185,7 @@ class Mimes
|
|||
'mpe' => 'video/mpeg',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
'avi' => [
|
||||
'video/x-msvideo',
|
||||
'video/msvideo',
|
||||
'video/avi',
|
||||
'application/x-troff-msvideo',
|
||||
],
|
||||
'avi' => ['video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'],
|
||||
'movie' => 'video/x-sgi-movie',
|
||||
'doc' => ['application/msword', 'application/vnd.ms-office'],
|
||||
'docx' => [
|
||||
|
|
@ -228,11 +211,7 @@ class Mimes
|
|||
'xl' => 'application/excel',
|
||||
'eml' => 'message/rfc822',
|
||||
'json' => ['application/json', 'text/json'],
|
||||
'pem' => [
|
||||
'application/x-x509-user-cert',
|
||||
'application/x-pem-file',
|
||||
'application/octet-stream',
|
||||
],
|
||||
'pem' => ['application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'],
|
||||
'p10' => ['application/x-pkcs10', 'application/pkcs10'],
|
||||
'p12' => 'application/x-pkcs12',
|
||||
'p7a' => 'application/x-pkcs7-signature',
|
||||
|
|
@ -240,11 +219,7 @@ class Mimes
|
|||
'p7m' => ['application/pkcs7-mime', 'application/x-pkcs7-mime'],
|
||||
'p7r' => 'application/x-pkcs7-certreqresp',
|
||||
'p7s' => 'application/pkcs7-signature',
|
||||
'crt' => [
|
||||
'application/x-x509-ca-cert',
|
||||
'application/x-x509-user-cert',
|
||||
'application/pkix-cert',
|
||||
],
|
||||
'crt' => ['application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'],
|
||||
'crl' => ['application/pkix-crl', 'application/pkcs-crl'],
|
||||
'der' => 'application/x-x509-ca-cert',
|
||||
'kdb' => 'application/octet-stream',
|
||||
|
|
@ -271,16 +246,8 @@ class Mimes
|
|||
'ac3' => 'audio/ac3',
|
||||
'flac' => 'audio/x-flac',
|
||||
'ogg' => ['audio/ogg', 'video/ogg', 'application/ogg'],
|
||||
'kmz' => [
|
||||
'application/vnd.google-earth.kmz',
|
||||
'application/zip',
|
||||
'application/x-zip',
|
||||
],
|
||||
'kml' => [
|
||||
'application/vnd.google-earth.kml+xml',
|
||||
'application/xml',
|
||||
'text/xml',
|
||||
],
|
||||
'kmz' => ['application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'],
|
||||
'kml' => ['application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'],
|
||||
'ics' => 'text/calendar',
|
||||
'ical' => 'text/calendar',
|
||||
'zsh' => 'text/x-scriptzsh',
|
||||
|
|
@ -311,11 +278,7 @@ class Mimes
|
|||
'srt' => ['text/srt', 'text/plain', 'application/octet-stream'],
|
||||
'vtt' => ['text/vtt', 'text/plain'],
|
||||
'ico' => ['image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon'],
|
||||
'stl' => [
|
||||
'application/sla',
|
||||
'application/vnd.ms-pki.stl',
|
||||
'application/x-navistyle',
|
||||
],
|
||||
'stl' => ['application/sla', 'application/vnd.ms-pki.stl', 'application/x-navistyle'],
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -327,7 +290,7 @@ class Mimes
|
|||
{
|
||||
$extension = trim(strtolower($extension), '. ');
|
||||
|
||||
if (!array_key_exists($extension, static::$mimes)) {
|
||||
if (! array_key_exists($extension, static::$mimes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -342,10 +305,8 @@ class Mimes
|
|||
* @param string|null $proposedExtension - default extension (in case there is more than one with the same mime type)
|
||||
* @return string|null The extension determined, or null if unable to match.
|
||||
*/
|
||||
public static function guessExtensionFromType(
|
||||
string $type,
|
||||
string $proposedExtension = null
|
||||
): ?string {
|
||||
public static function guessExtensionFromType(string $type, string $proposedExtension = null): ?string
|
||||
{
|
||||
$type = trim(strtolower($type), '. ');
|
||||
|
||||
$proposedExtension = trim(strtolower($proposedExtension));
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ class Pager extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The default number of results shown in a single page.
|
||||
*
|
||||
*/
|
||||
public int $perPage = 20;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ namespace Config;
|
|||
/**
|
||||
* Paths
|
||||
*
|
||||
* Holds the paths that are used by the system to
|
||||
* locate the main directories, app, system, etc.
|
||||
* Holds the paths that are used by the system to locate the main directories, app, system, etc.
|
||||
*
|
||||
* Modifying these allows you to restructure your application,
|
||||
* share a system folder between multiple applications, and more.
|
||||
* Modifying these allows you to restructure your application, share a system folder between multiple applications, and
|
||||
* more.
|
||||
*
|
||||
* All paths are relative to the project's root folder.
|
||||
*/
|
||||
|
|
@ -23,10 +22,10 @@ class Paths
|
|||
*
|
||||
* This must contain the name of your "system" folder. Include
|
||||
* the path if the folder is not in the same directory as this file.
|
||||
*
|
||||
*/
|
||||
public string $systemDirectory =
|
||||
__DIR__ . '/../../vendor/codeigniter4/codeigniter4/system';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* APPLICATION FOLDER NAME
|
||||
|
|
@ -38,7 +37,6 @@ class Paths
|
|||
* you do, use a full getServer path.
|
||||
*
|
||||
* @see http://codeigniter.com/user_guide/general/managing_apps.html
|
||||
*
|
||||
*/
|
||||
public string $appDirectory = __DIR__ . '/..';
|
||||
|
||||
|
|
@ -52,7 +50,6 @@ class Paths
|
|||
* need write permission to a single place that can be tucked away
|
||||
* for maximum security, keeping it out of the app and/or
|
||||
* system directories.
|
||||
*
|
||||
*/
|
||||
public string $writableDirectory = __DIR__ . '/../../writable';
|
||||
|
||||
|
|
@ -62,7 +59,6 @@ class Paths
|
|||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This variable must contain the name of your "tests" directory.
|
||||
*
|
||||
*/
|
||||
public string $testsDirectory = __DIR__ . '/../../tests';
|
||||
|
||||
|
|
@ -75,7 +71,6 @@ class Paths
|
|||
* contains the view files used by your application. By
|
||||
* default this is in `app/Views`. This value
|
||||
* is used when no value is provided to `Services::renderer()`.
|
||||
*
|
||||
*/
|
||||
public string $viewDirectory = __DIR__ . '/../Views';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ $routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}');
|
|||
$routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}');
|
||||
$routes->addPlaceholder('platformType', '\bpodcasting|\bsocial|\bfunding');
|
||||
$routes->addPlaceholder('noteAction', '\bfavourite|\breblog|\breply');
|
||||
$routes->addPlaceholder(
|
||||
'embeddablePlayerTheme',
|
||||
'\blight|\bdark|\blight-transparent|\bdark-transparent',
|
||||
);
|
||||
$routes->addPlaceholder('embeddablePlayerTheme', '\blight|\bdark|\blight-transparent|\bdark-transparent',);
|
||||
$routes->addPlaceholder(
|
||||
'uuid',
|
||||
'[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}',
|
||||
|
|
@ -51,25 +48,21 @@ $routes->addPlaceholder(
|
|||
|
||||
// We get a performance increase by specifying the default
|
||||
// route since we don't have to scan directories.
|
||||
$routes->get('/', 'HomeController::index', ['as' => 'home']);
|
||||
$routes->get('/', 'HomeController::index', [
|
||||
'as' => 'home',
|
||||
]);
|
||||
|
||||
// Install Wizard route
|
||||
$routes->group(config('App')->installGateway, function ($routes): void {
|
||||
$routes->get('/', 'InstallController', ['as' => 'install']);
|
||||
$routes->post(
|
||||
'instance-config',
|
||||
'InstallController::attemptInstanceConfig',
|
||||
[
|
||||
'as' => 'instance-config',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'database-config',
|
||||
'InstallController::attemptDatabaseConfig',
|
||||
[
|
||||
'as' => 'database-config',
|
||||
],
|
||||
);
|
||||
$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',
|
||||
]);
|
||||
|
|
@ -86,8 +79,11 @@ $routes->get('.well-known/platforms', 'Platform');
|
|||
|
||||
// Admin area
|
||||
$routes->group(
|
||||
config('App')->adminGateway,
|
||||
['namespace' => 'App\Controllers\Admin'],
|
||||
config('App')
|
||||
->adminGateway,
|
||||
[
|
||||
'namespace' => 'App\Controllers\Admin',
|
||||
],
|
||||
function ($routes): void {
|
||||
$routes->get('/', 'HomeController', [
|
||||
'as' => 'admin',
|
||||
|
|
@ -538,7 +534,9 @@ $routes->group(
|
|||
|
||||
// Pages
|
||||
$routes->group('pages', function ($routes): void {
|
||||
$routes->get('/', 'PageController::list', ['as' => 'page-list']);
|
||||
$routes->get('/', 'PageController::list', [
|
||||
'as' => 'page-list',
|
||||
]);
|
||||
$routes->get('new', 'PageController::create', [
|
||||
'as' => 'page-create',
|
||||
'filter' => 'permission:pages-manage',
|
||||
|
|
@ -628,10 +626,7 @@ $routes->group(
|
|||
'as' => 'change-password',
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'change-password',
|
||||
'MyAccountController::attemptChange/$1',
|
||||
);
|
||||
$routes->post('change-password', 'MyAccountController::attemptChange/$1',);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
@ -641,7 +636,9 @@ $routes->group(
|
|||
*/
|
||||
$routes->group(config('App')->authGateway, function ($routes): void {
|
||||
// Login/out
|
||||
$routes->get('login', 'AuthController::login', ['as' => 'login']);
|
||||
$routes->get('login', 'AuthController::login', [
|
||||
'as' => 'login',
|
||||
]);
|
||||
$routes->post('login', 'AuthController::attemptLogin');
|
||||
$routes->get('logout', 'AuthController::logout', [
|
||||
'as' => 'logout',
|
||||
|
|
@ -722,13 +719,21 @@ $routes->group('@(:podcastName)', function ($routes): void {
|
|||
});
|
||||
});
|
||||
|
||||
$routes->head('feed.xml', 'FeedController/$1', ['as' => 'podcast_feed']);
|
||||
$routes->get('feed.xml', 'FeedController/$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', 'PageController::credits', ['as' => 'credits']);
|
||||
$routes->get('/pages/(:slug)', 'Page/$1', ['as' => 'page']);
|
||||
$routes->get('/credits', 'CreditsController', [
|
||||
'as' => 'credits',
|
||||
]);
|
||||
$routes->get('/pages/(:slug)', 'PageController/$1', [
|
||||
'as' => 'page',
|
||||
]);
|
||||
|
||||
// interacting as an actor
|
||||
$routes->post('interact-as-actor', 'AuthController::attemptInteractAsActor', [
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ class Security extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Token name for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
*/
|
||||
public string $tokenName = 'csrf_test_name';
|
||||
|
||||
|
|
@ -22,7 +21,6 @@ class Security extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Token name for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
*/
|
||||
public string $headerName = 'X-CSRF-TOKEN';
|
||||
|
||||
|
|
@ -32,7 +30,6 @@ class Security extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie name for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
*/
|
||||
public string $cookieName = 'csrf_cookie_name';
|
||||
|
||||
|
|
@ -44,7 +41,6 @@ class Security extends BaseConfig
|
|||
* Expiration time for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
* Defaults to two hours (in seconds).
|
||||
*
|
||||
*/
|
||||
public int $expires = 7200;
|
||||
|
||||
|
|
@ -54,7 +50,6 @@ class Security extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Regenerate CSRF Token on every request.
|
||||
*
|
||||
*/
|
||||
public bool $regenerate = true;
|
||||
|
||||
|
|
@ -64,7 +59,6 @@ class Security extends BaseConfig
|
|||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Redirect to previous page with error on failure.
|
||||
*
|
||||
*/
|
||||
public bool $redirect = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,38 +2,35 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseService;
|
||||
use CodeIgniter\Model;
|
||||
use App\Authorization\FlatAuthorization;
|
||||
use App\Authorization\PermissionModel;
|
||||
use App\Authorization\GroupModel;
|
||||
use App\Authorization\PermissionModel;
|
||||
use App\Libraries\Breadcrumb;
|
||||
use App\Libraries\Negotiate;
|
||||
use App\Libraries\Router;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Config\BaseService;
|
||||
use CodeIgniter\HTTP\Request;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\Model;
|
||||
use CodeIgniter\Router\RouteCollectionInterface;
|
||||
use Myth\Auth\Models\LoginModel;
|
||||
|
||||
/**
|
||||
* Services Configuration file.
|
||||
*
|
||||
* Services are simply other classes/libraries that the system uses
|
||||
* to do its job. This is used by CodeIgniter to allow the core of the
|
||||
* framework to be swapped out easily without affecting the usage within
|
||||
* the rest of your application.
|
||||
* Services are simply other classes/libraries that the system uses to do its job. This is used by CodeIgniter to allow
|
||||
* the core of the framework to be swapped out easily without affecting the usage within the rest of your application.
|
||||
*
|
||||
* This file holds any application-specific services, or service overrides
|
||||
* that you might need. An example has been included with the general
|
||||
* method format you should use for your service methods. For more examples,
|
||||
* see the core Services file at system/Config/Services.php.
|
||||
* This file holds any application-specific services, or service overrides that you might need. An example has been
|
||||
* included with the general method format you should use for your service methods. For more examples, see the core
|
||||
* Services file at system/Config/Services.php.
|
||||
*/
|
||||
class Services extends BaseService
|
||||
{
|
||||
/**
|
||||
* The Router class uses a RouteCollection's array of routes, and determines
|
||||
* the correct Controller and Method to execute.
|
||||
* The Router class uses a RouteCollection's array of routes, and determines the correct Controller and Method to
|
||||
* execute.
|
||||
*/
|
||||
public static function router(
|
||||
?RouteCollectionInterface $routes = null,
|
||||
|
|
@ -51,14 +48,11 @@ class Services extends BaseService
|
|||
}
|
||||
|
||||
/**
|
||||
* The Negotiate class provides the content negotiation features for
|
||||
* working the request to determine correct language, encoding, charset,
|
||||
* and more.
|
||||
* The Negotiate class provides the content negotiation features for working the request to determine correct
|
||||
* language, encoding, charset, and more.
|
||||
*/
|
||||
public static function negotiator(
|
||||
?RequestInterface $request = null,
|
||||
bool $getShared = true
|
||||
): Negotiate {
|
||||
public static function negotiator(?RequestInterface $request = null, bool $getShared = true): Negotiate
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('negotiator', $request);
|
||||
}
|
||||
|
|
@ -78,12 +72,7 @@ class Services extends BaseService
|
|||
bool $getShared = true
|
||||
) {
|
||||
if ($getShared) {
|
||||
return self::getSharedInstance(
|
||||
'authentication',
|
||||
$lib,
|
||||
$userModel,
|
||||
$loginModel,
|
||||
);
|
||||
return self::getSharedInstance('authentication', $lib, $userModel, $loginModel,);
|
||||
}
|
||||
|
||||
// config() checks first in app/Config
|
||||
|
|
@ -101,7 +90,8 @@ class Services extends BaseService
|
|||
$loginModel = new LoginModel();
|
||||
}
|
||||
|
||||
return $instance->setUserModel($userModel)->setLoginModel($loginModel);
|
||||
return $instance->setUserModel($userModel)
|
||||
->setLoginModel($loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -114,25 +104,20 @@ class Services extends BaseService
|
|||
bool $getShared = true
|
||||
) {
|
||||
if ($getShared) {
|
||||
return self::getSharedInstance(
|
||||
'authorization',
|
||||
$groupModel,
|
||||
$permissionModel,
|
||||
$userModel,
|
||||
);
|
||||
return self::getSharedInstance('authorization', $groupModel, $permissionModel, $userModel,);
|
||||
}
|
||||
|
||||
if (is_null($groupModel)) {
|
||||
if ($groupModel === null) {
|
||||
$groupModel = new GroupModel();
|
||||
}
|
||||
|
||||
if (is_null($permissionModel)) {
|
||||
if ($permissionModel === null) {
|
||||
$permissionModel = new PermissionModel();
|
||||
}
|
||||
|
||||
$instance = new FlatAuthorization($groupModel, $permissionModel);
|
||||
|
||||
if (is_null($userModel)) {
|
||||
if ($userModel === null) {
|
||||
$userModel = new UserModel();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ class Toolbar extends BaseConfig
|
|||
* `$maxHistory` sets a limit on the number of past requests that are stored,
|
||||
* helping to conserve file space used to store them. You can set it to
|
||||
* 0 (zero) to not have any history stored, or -1 for unlimited history.
|
||||
*
|
||||
*/
|
||||
public int $maxHistory = 20;
|
||||
|
||||
|
|
@ -63,7 +62,6 @@ class Toolbar extends BaseConfig
|
|||
*
|
||||
* The full path to the the views that are used by the toolbar.
|
||||
* This MUST have a trailing slash.
|
||||
*
|
||||
*/
|
||||
public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
|
||||
|
||||
|
|
@ -78,7 +76,6 @@ class Toolbar extends BaseConfig
|
|||
* with hundreds of queries.
|
||||
*
|
||||
* `$maxQueries` defines the maximum amount of queries that will be stored.
|
||||
*
|
||||
*/
|
||||
public int $maxQueries = 100;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
|
|
|||
|
|
@ -12,13 +12,8 @@ use Myth\Auth\Authentication\Passwords\ValidationRules as PasswordRules;
|
|||
|
||||
class Validation
|
||||
{
|
||||
//--------------------------------------------------------------------
|
||||
// Setup
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Stores the classes that contain the
|
||||
* rules that are available.
|
||||
* Stores the classes that contain the rules that are available.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
@ -33,8 +28,7 @@ class Validation
|
|||
];
|
||||
|
||||
/**
|
||||
* Specifies the views that are used to display the
|
||||
* errors.
|
||||
* Specifies the views that are used to display the errors.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
|
|
@ -42,8 +36,4 @@ class Validation
|
|||
'list' => 'CodeIgniter\Validation\Views\list',
|
||||
'single' => 'CodeIgniter\Validation\Views\single',
|
||||
];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Rules
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,36 +7,29 @@ use CodeIgniter\Config\View as BaseView;
|
|||
class View extends BaseView
|
||||
{
|
||||
/**
|
||||
* When false, the view method will clear the data between each
|
||||
* call. This keeps your data safe and ensures there is no accidental
|
||||
* leaking between calls, so you would need to explicitly pass the data
|
||||
* to each view. You might prefer to have the data stick around between
|
||||
* calls so that it is available to all views. If that is the case,
|
||||
* set $saveData to true.
|
||||
* When false, the view method will clear the data between each call. This keeps your data safe and ensures there is
|
||||
* no accidental leaking between calls, so you would need to explicitly pass the data to each view. You might prefer
|
||||
* to have the data stick around between calls so that it is available to all views. If that is the case, set
|
||||
* $saveData to true.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $saveData = true;
|
||||
|
||||
/**
|
||||
* Parser Filters map a filter name with any PHP callable. When the
|
||||
* Parser prepares a variable for display, it will chain it
|
||||
* through the filters in the order defined, inserting any parameters.
|
||||
* To prevent potential abuse, all filters MUST be defined here
|
||||
* in order for them to be available for use within the Parser.
|
||||
* Parser Filters map a filter name with any PHP callable. When the Parser prepares a variable for display, it will
|
||||
* chain it through the filters in the order defined, inserting any parameters. To prevent potential abuse, all
|
||||
* filters MUST be defined here in order for them to be available for use within the Parser.
|
||||
*
|
||||
* Examples:
|
||||
* { title|esc(js) }
|
||||
* { created_on|date(Y-m-d)|esc(attr) }
|
||||
* Examples: { title|esc(js) } { created_on|date(Y-m-d)|esc(attr) }
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $filters = [];
|
||||
|
||||
/**
|
||||
* Parser Plugins provide a way to extend the functionality provided
|
||||
* by the core Parser by creating aliases that will be replaced with
|
||||
* any callable. Can be single or tag pair.
|
||||
* Parser Plugins provide a way to extend the functionality provided by the core Parser by creating aliases that
|
||||
* will be replaced with any callable. Can be single or tag pair.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ class ActorController extends ActivityPubActorController
|
|||
public function follow(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->actor->podcast->id);
|
||||
}
|
||||
|
||||
$cacheName = "page_podcast-{$this->actor->username}_follow";
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
helper(['form', 'components', 'svg']);
|
||||
$data = [
|
||||
'actor' => $this->actor,
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ use Psr\Log\LoggerInterface;
|
|||
/**
|
||||
* Class BaseController
|
||||
*
|
||||
* BaseController provides a convenient place for loading components
|
||||
* and performing functions that are needed by all your controllers.
|
||||
* Extend this class in any new controllers:
|
||||
* class Home extends BaseController
|
||||
* BaseController provides a convenient place for loading components and performing functions that are needed by all
|
||||
* your controllers. Extend this class in any new controllers: class Home extends BaseController
|
||||
*
|
||||
* For security be sure to declare any new methods as protected or private.
|
||||
*/
|
||||
|
|
@ -21,9 +19,8 @@ use Psr\Log\LoggerInterface;
|
|||
class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* An array of helpers to be loaded automatically upon
|
||||
* class instantiation. These helpers will be available
|
||||
* to all other controllers that extend BaseController.
|
||||
* An array of helpers to be loaded automatically upon class instantiation. These helpers will be available to all
|
||||
* other controllers that extend BaseController.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
@ -39,10 +36,5 @@ class BaseController extends Controller
|
|||
): void {
|
||||
// Do Not Edit This Line
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Preload any models, libraries, etc, here.
|
||||
//--------------------------------------------------------------------
|
||||
// E.g.: $this->session = \Config\Services::session();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,19 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Authorization\GroupModel;
|
||||
use App\Entities\Podcast;
|
||||
use App\Entities\User;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Exception;
|
||||
use App\Authorization\GroupModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Exception;
|
||||
|
||||
class ContributorController extends BaseController
|
||||
{
|
||||
protected Podcast $podcast;
|
||||
|
||||
protected ?User $user;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
|
|
@ -27,16 +28,13 @@ class ContributorController extends BaseController
|
|||
$this->podcast = (new PodcastModel())->getPodcastById((int) $params[0]);
|
||||
|
||||
if (count($params) <= 1) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if (
|
||||
$this->user = (new UserModel())->getPodcastContributor(
|
||||
(int) $params[1],
|
||||
(int) $params[0],
|
||||
)
|
||||
$this->user = (new UserModel())->getPodcastContributor((int) $params[1], (int) $params[0],)
|
||||
) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -48,17 +46,16 @@ class ContributorController extends BaseController
|
|||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/contributor/list', $data);
|
||||
}
|
||||
|
||||
public function view(): string
|
||||
{
|
||||
$data = [
|
||||
'contributor' => (new UserModel())->getPodcastContributor(
|
||||
$this->user->id,
|
||||
$this->podcast->id,
|
||||
),
|
||||
'contributor' => (new UserModel())->getPodcastContributor($this->user->id, $this->podcast->id,),
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([
|
||||
|
|
@ -98,7 +95,9 @@ class ContributorController extends BaseController
|
|||
'roleOptions' => $roleOptions,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/contributor/add', $data);
|
||||
}
|
||||
|
||||
|
|
@ -114,9 +113,7 @@ class ContributorController extends BaseController
|
|||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', [
|
||||
lang('Contributor.messages.alreadyAddedError'),
|
||||
]);
|
||||
->with('errors', [lang('Contributor.messages.alreadyAddedError')]);
|
||||
}
|
||||
|
||||
return redirect()->route('contributor-list', [$this->podcast->id]);
|
||||
|
|
@ -169,17 +166,12 @@ class ContributorController extends BaseController
|
|||
if ($this->podcast->created_by === $this->user->id) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('errors', [
|
||||
lang('Contributor.messages.removeOwnerContributorError'),
|
||||
]);
|
||||
->with('errors', [lang('Contributor.messages.removeOwnerContributorError')]);
|
||||
}
|
||||
|
||||
$podcastModel = new PodcastModel();
|
||||
if (
|
||||
!$podcastModel->removePodcastContributor(
|
||||
$this->user->id,
|
||||
$this->podcast->id,
|
||||
)
|
||||
! $podcastModel->removePodcastContributor($this->user->id, $this->podcast->id,)
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Database;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Note;
|
||||
|
|
@ -19,26 +16,28 @@ use App\Models\EpisodeModel;
|
|||
use App\Models\NoteModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\SoundbiteModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use Config\Database;
|
||||
|
||||
class EpisodeController extends BaseController
|
||||
{
|
||||
protected Podcast $podcast;
|
||||
|
||||
protected ?Episode $episode;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
(int) $params[0],
|
||||
)) === null
|
||||
($this->podcast = (new PodcastModel())->getPodcastById((int) $params[0],)) === null
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
if (count($params) > 1) {
|
||||
if (
|
||||
!($this->episode = (new EpisodeModel())
|
||||
! ($this->episode = (new EpisodeModel())
|
||||
->where([
|
||||
'id' => $params[1],
|
||||
'podcast_id' => $params[0],
|
||||
|
|
@ -52,7 +51,7 @@ class EpisodeController extends BaseController
|
|||
unset($params[0]);
|
||||
}
|
||||
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
|
|
@ -112,7 +111,7 @@ class EpisodeController extends BaseController
|
|||
'chapters_file' => 'ext_in[chapters,json]|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -127,9 +126,7 @@ class EpisodeController extends BaseController
|
|||
'audio_file' => $this->request->getFile('audio_file'),
|
||||
'description_markdown' => $this->request->getPost('description'),
|
||||
'image' => $this->request->getFile('image'),
|
||||
'location' => new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
),
|
||||
'location' => new Location($this->request->getPost('location_name'),),
|
||||
'transcript' => $this->request->getFile('transcript'),
|
||||
'chapters' => $this->request->getFile('chapters'),
|
||||
'parental_advisory' =>
|
||||
|
|
@ -143,7 +140,7 @@ class EpisodeController extends BaseController
|
|||
? $this->request->getPost('season_number')
|
||||
: null,
|
||||
'type' => $this->request->getPost('type'),
|
||||
'is_blocked' => $this->request->getPost('block') == 'yes',
|
||||
'is_blocked' => $this->request->getPost('block') === 'yes',
|
||||
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
|
|
@ -157,9 +154,7 @@ class EpisodeController extends BaseController
|
|||
) {
|
||||
$newEpisode->transcript_file = $transcriptFile;
|
||||
} elseif ($transcriptChoice === 'remote-url') {
|
||||
$newEpisode->transcript_file_remote_url = $this->request->getPost(
|
||||
'transcript_file_remote_url',
|
||||
);
|
||||
$newEpisode->transcript_file_remote_url = $this->request->getPost('transcript_file_remote_url',);
|
||||
}
|
||||
|
||||
$chaptersChoice = $this->request->getPost('chapters-choice');
|
||||
|
|
@ -169,14 +164,12 @@ class EpisodeController extends BaseController
|
|||
) {
|
||||
$newEpisode->chapters_file = $chaptersFile;
|
||||
} elseif ($chaptersChoice === 'remote-url') {
|
||||
$newEpisode->chapters_file_remote_url = $this->request->getPost(
|
||||
'chapters_file_remote_url',
|
||||
);
|
||||
$newEpisode->chapters_file_remote_url = $this->request->getPost('chapters_file_remote_url',);
|
||||
}
|
||||
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
||||
if (!($newEpisodeId = $episodeModel->insert($newEpisode, true))) {
|
||||
if (! ($newEpisodeId = $episodeModel->insert($newEpisode, true))) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -187,11 +180,9 @@ class EpisodeController extends BaseController
|
|||
$podcastModel = new PodcastModel();
|
||||
|
||||
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
||||
'description_footer',
|
||||
);
|
||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost('description_footer',);
|
||||
|
||||
if (!$podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||
if (! $podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -199,10 +190,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
return redirect()->route('episode-view', [
|
||||
$this->podcast->id,
|
||||
$newEpisodeId,
|
||||
]);
|
||||
return redirect()->route('episode-view', [$this->podcast->id, $newEpisodeId]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
|
|
@ -233,7 +221,7 @@ class EpisodeController extends BaseController
|
|||
'chapters_file' => 'ext_in[chapters_file,json]|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -242,12 +230,8 @@ class EpisodeController extends BaseController
|
|||
|
||||
$this->episode->title = $this->request->getPost('title');
|
||||
$this->episode->slug = $this->request->getPost('slug');
|
||||
$this->episode->description_markdown = $this->request->getPost(
|
||||
'description',
|
||||
);
|
||||
$this->episode->location = new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
);
|
||||
$this->episode->description_markdown = $this->request->getPost('description',);
|
||||
$this->episode->location = new Location($this->request->getPost('location_name'),);
|
||||
$this->episode->parental_advisory =
|
||||
$this->request->getPost('parental_advisory') !== 'undefined'
|
||||
? $this->request->getPost('parental_advisory')
|
||||
|
|
@ -259,10 +243,8 @@ class EpisodeController extends BaseController
|
|||
? $this->request->getPost('season_number')
|
||||
: null;
|
||||
$this->episode->type = $this->request->getPost('type');
|
||||
$this->episode->is_blocked = $this->request->getPost('block') == 'yes';
|
||||
$this->episode->custom_rss_string = $this->request->getPost(
|
||||
'custom_rss',
|
||||
);
|
||||
$this->episode->is_blocked = $this->request->getPost('block') === 'yes';
|
||||
$this->episode->custom_rss_string = $this->request->getPost('custom_rss',);
|
||||
|
||||
$this->episode->updated_by = user_id();
|
||||
|
||||
|
|
@ -285,9 +267,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
} elseif ($transcriptChoice === 'remote-url') {
|
||||
if (
|
||||
($transcriptFileRemoteUrl = $this->request->getPost(
|
||||
'transcript_file_remote_url',
|
||||
)) &&
|
||||
($transcriptFileRemoteUrl = $this->request->getPost('transcript_file_remote_url',)) &&
|
||||
(($transcriptFile = $this->episode->transcript_file) &&
|
||||
$transcriptFile !== null)
|
||||
) {
|
||||
|
|
@ -306,9 +286,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
} elseif ($chaptersChoice === 'remote-url') {
|
||||
if (
|
||||
($chaptersFileRemoteUrl = $this->request->getPost(
|
||||
'chapters_file_remote_url',
|
||||
)) &&
|
||||
($chaptersFileRemoteUrl = $this->request->getPost('chapters_file_remote_url',)) &&
|
||||
(($chaptersFile = $this->episode->chapters_file) &&
|
||||
$chaptersFile !== null)
|
||||
) {
|
||||
|
|
@ -320,7 +298,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
||||
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||
if (! $episodeModel->update($this->episode->id, $this->episode)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -328,13 +306,11 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
// update podcast's episode_description_footer_markdown if changed
|
||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
||||
'description_footer',
|
||||
);
|
||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost('description_footer',);
|
||||
|
||||
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
||||
$podcastModel = new PodcastModel();
|
||||
if (!$podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||
if (! $podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -342,10 +318,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
return redirect()->route('episode-view', [
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
]);
|
||||
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id]);
|
||||
}
|
||||
|
||||
public function transcriptDelete(): RedirectResponse
|
||||
|
|
@ -355,7 +328,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
||||
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||
if (! $episodeModel->update($this->episode->id, $this->episode)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -372,7 +345,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
||||
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||
if (! $episodeModel->update($this->episode->id, $this->episode)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -410,7 +383,7 @@ class EpisodeController extends BaseController
|
|||
'valid_date[Y-m-d H:i]|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -429,9 +402,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$publishMethod = $this->request->getPost('publication_method');
|
||||
if ($publishMethod === 'schedule') {
|
||||
$scheduledPublicationDate = $this->request->getPost(
|
||||
'scheduled_publication_date',
|
||||
);
|
||||
$scheduledPublicationDate = $this->request->getPost('scheduled_publication_date',);
|
||||
if ($scheduledPublicationDate) {
|
||||
$scheduledDateUTC = Time::createFromFormat(
|
||||
'Y-m-d H:i',
|
||||
|
|
@ -454,7 +425,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
$noteModel = new NoteModel();
|
||||
if (!$noteModel->addNote($newNote)) {
|
||||
if (! $noteModel->addNote($newNote)) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -463,7 +434,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
$episodeModel = new EpisodeModel();
|
||||
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||
if (! $episodeModel->update($this->episode->id, $this->episode)) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -473,10 +444,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$db->transComplete();
|
||||
|
||||
return redirect()->route('episode-view', [
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
]);
|
||||
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id]);
|
||||
}
|
||||
|
||||
public function publishEdit(): string
|
||||
|
|
@ -513,7 +481,7 @@ class EpisodeController extends BaseController
|
|||
'valid_date[Y-m-d H:i]|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -523,16 +491,12 @@ class EpisodeController extends BaseController
|
|||
$db = Database::connect();
|
||||
$db->transStart();
|
||||
|
||||
$note = (new NoteModel())->getNoteById(
|
||||
$this->request->getPost('note_id'),
|
||||
);
|
||||
$note = (new NoteModel())->getNoteById($this->request->getPost('note_id'),);
|
||||
$note->message = $this->request->getPost('message');
|
||||
|
||||
$publishMethod = $this->request->getPost('publication_method');
|
||||
if ($publishMethod === 'schedule') {
|
||||
$scheduledPublicationDate = $this->request->getPost(
|
||||
'scheduled_publication_date',
|
||||
);
|
||||
$scheduledPublicationDate = $this->request->getPost('scheduled_publication_date',);
|
||||
if ($scheduledPublicationDate) {
|
||||
$scheduledDateUTC = Time::createFromFormat(
|
||||
'Y-m-d H:i',
|
||||
|
|
@ -555,7 +519,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
$noteModel = new NoteModel();
|
||||
if (!$noteModel->editNote($note)) {
|
||||
if (! $noteModel->editNote($note)) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -564,7 +528,7 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
$episodeModel = new EpisodeModel();
|
||||
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||
if (! $episodeModel->update($this->episode->id, $this->episode)) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -574,10 +538,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$db->transComplete();
|
||||
|
||||
return redirect()->route('episode-view', [
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
]);
|
||||
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id]);
|
||||
}
|
||||
|
||||
public function unpublish(): string
|
||||
|
|
@ -606,7 +567,7 @@ class EpisodeController extends BaseController
|
|||
'understand' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -630,7 +591,7 @@ class EpisodeController extends BaseController
|
|||
$this->episode->published_at = null;
|
||||
|
||||
$episodeModel = new EpisodeModel();
|
||||
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||
if (! $episodeModel->update($this->episode->id, $this->episode)) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -640,10 +601,7 @@ class EpisodeController extends BaseController
|
|||
|
||||
$db->transComplete();
|
||||
|
||||
return redirect()->route('episode-view', [
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
]);
|
||||
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id]);
|
||||
}
|
||||
|
||||
public function delete(): RedirectResponse
|
||||
|
|
@ -684,7 +642,7 @@ class EpisodeController extends BaseController
|
|||
"soundbites.{$soundbite_id}.duration" => 'required|decimal|greater_than_equal_to[0]',
|
||||
];
|
||||
}
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -701,14 +659,18 @@ class EpisodeController extends BaseController
|
|||
'label' => $soundbite['label'],
|
||||
'updated_by' => user_id(),
|
||||
];
|
||||
if ($soundbite_id == 0) {
|
||||
$data += ['created_by' => user_id()];
|
||||
if ($soundbite_id === 0) {
|
||||
$data += [
|
||||
'created_by' => user_id(),
|
||||
];
|
||||
} else {
|
||||
$data += ['id' => $soundbite_id];
|
||||
$data += [
|
||||
'id' => $soundbite_id,
|
||||
];
|
||||
}
|
||||
|
||||
$soundbiteModel = new SoundbiteModel();
|
||||
if (!$soundbiteModel->save($data)) {
|
||||
if (! $soundbiteModel->save($data)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -716,24 +678,14 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
}
|
||||
}
|
||||
return redirect()->route('soundbites-edit', [
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
]);
|
||||
return redirect()->route('soundbites-edit', [$this->podcast->id, $this->episode->id]);
|
||||
}
|
||||
|
||||
public function soundbiteDelete(int $soundbiteId): RedirectResponse
|
||||
{
|
||||
(new SoundbiteModel())->deleteSoundbite(
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
$soundbiteId,
|
||||
);
|
||||
(new SoundbiteModel())->deleteSoundbite($this->podcast->id, $this->episode->id, $soundbiteId,);
|
||||
|
||||
return redirect()->route('soundbites-edit', [
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
]);
|
||||
return redirect()->route('soundbites-edit', [$this->podcast->id, $this->episode->id]);
|
||||
}
|
||||
|
||||
public function embeddablePlayer(): string
|
||||
|
|
|
|||
|
|
@ -8,17 +8,18 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Podcast;
|
||||
use App\Entities\Episode;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PersonModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class EpisodePersonController extends BaseController
|
||||
{
|
||||
protected Podcast $podcast;
|
||||
|
||||
protected Episode $episode;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
|
|
@ -28,9 +29,7 @@ class EpisodePersonController extends BaseController
|
|||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
(int) $params[0],
|
||||
)) &&
|
||||
($this->podcast = (new PodcastModel())->getPodcastById((int) $params[0],)) &&
|
||||
($this->episode = (new EpisodeModel())
|
||||
->where([
|
||||
'id' => $params[1],
|
||||
|
|
@ -41,7 +40,7 @@ class EpisodePersonController extends BaseController
|
|||
unset($params[1]);
|
||||
unset($params[0]);
|
||||
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -70,7 +69,7 @@ class EpisodePersonController extends BaseController
|
|||
'person' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -89,11 +88,7 @@ class EpisodePersonController extends BaseController
|
|||
|
||||
public function remove(int $personId): RedirectResponse
|
||||
{
|
||||
(new PersonModel())->removePersonFromEpisode(
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
$personId,
|
||||
);
|
||||
(new PersonModel())->removePersonFromEpisode($this->podcast->id, $this->episode->id, $personId,);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ class FediverseController extends BaseController
|
|||
{
|
||||
helper(['form']);
|
||||
|
||||
$blockedActors = model('ActorModel')->getBlockedActors();
|
||||
$blockedActors = model('ActorModel')
|
||||
->getBlockedActors();
|
||||
|
||||
return view('admin/fediverse/blocked_actors', [
|
||||
'blockedActors' => $blockedActors,
|
||||
|
|
@ -30,7 +31,8 @@ class FediverseController extends BaseController
|
|||
{
|
||||
helper(['form']);
|
||||
|
||||
$blockedDomains = model('BlockedDomainModel')->getBlockedDomains();
|
||||
$blockedDomains = model('BlockedDomainModel')
|
||||
->getBlockedDomains();
|
||||
|
||||
return view('admin/fediverse/blocked_domains', [
|
||||
'blockedDomains' => $blockedDomains,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
public function index(): RedirectResponse
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Services;
|
||||
use App\Models\UserModel;
|
||||
|
||||
class MyAccountController extends BaseController
|
||||
{
|
||||
|
|
@ -38,7 +38,7 @@ class MyAccountController extends BaseController
|
|||
'new_password' => 'required|strong_password|differs[password]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -46,20 +46,22 @@ class MyAccountController extends BaseController
|
|||
}
|
||||
|
||||
$credentials = [
|
||||
'email' => user()->email,
|
||||
'email' => user()
|
||||
->email,
|
||||
'password' => $this->request->getPost('password'),
|
||||
];
|
||||
|
||||
if (!$auth->validate($credentials)) {
|
||||
if (! $auth->validate($credentials)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('error', lang('MyAccount.messages.wrongPasswordError'));
|
||||
}
|
||||
|
||||
user()->password = $this->request->getPost('new_password');
|
||||
user()
|
||||
->password = $this->request->getPost('new_password');
|
||||
|
||||
if (!$userModel->update(user_id(), user())) {
|
||||
if (! $userModel->update(user_id(), user())) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Page;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PageModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class PageController extends BaseController
|
||||
{
|
||||
|
|
@ -20,17 +20,17 @@ class PageController extends BaseController
|
|||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if ($this->page = (new PageModel())->find($params[0])) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
function list(): string
|
||||
public function list(): string
|
||||
{
|
||||
$data = [
|
||||
'pages' => (new PageModel())->findAll(),
|
||||
|
|
@ -39,19 +39,21 @@ class PageController extends BaseController
|
|||
return view('admin/page/list', $data);
|
||||
}
|
||||
|
||||
function view(): string
|
||||
public function view(): string
|
||||
{
|
||||
return view('admin/page/view', ['page' => $this->page]);
|
||||
return view('admin/page/view', [
|
||||
'page' => $this->page,
|
||||
]);
|
||||
}
|
||||
|
||||
function create(): string
|
||||
public function create(): string
|
||||
{
|
||||
helper('form');
|
||||
|
||||
return view('admin/page/create');
|
||||
}
|
||||
|
||||
function attemptCreate(): RedirectResponse
|
||||
public function attemptCreate(): RedirectResponse
|
||||
{
|
||||
$page = new Page([
|
||||
'title' => $this->request->getPost('title'),
|
||||
|
|
@ -61,7 +63,7 @@ class PageController extends BaseController
|
|||
|
||||
$pageModel = new PageModel();
|
||||
|
||||
if (!$pageModel->insert($page)) {
|
||||
if (! $pageModel->insert($page)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -70,23 +72,24 @@ class PageController extends BaseController
|
|||
|
||||
return redirect()
|
||||
->route('page-list')
|
||||
->with(
|
||||
'message',
|
||||
lang('Page.messages.createSuccess', [
|
||||
'pageTitle' => $page->title,
|
||||
]),
|
||||
);
|
||||
->with('message', lang('Page.messages.createSuccess', [
|
||||
'pageTitle' => $page->title,
|
||||
]),);
|
||||
}
|
||||
|
||||
function edit(): string
|
||||
public function edit(): string
|
||||
{
|
||||
helper('form');
|
||||
|
||||
replace_breadcrumb_params([0 => $this->page->title]);
|
||||
return view('admin/page/edit', ['page' => $this->page]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->page->title,
|
||||
]);
|
||||
return view('admin/page/edit', [
|
||||
'page' => $this->page,
|
||||
]);
|
||||
}
|
||||
|
||||
function attemptEdit(): RedirectResponse
|
||||
public function attemptEdit(): RedirectResponse
|
||||
{
|
||||
$this->page->title = $this->request->getPost('title');
|
||||
$this->page->slug = $this->request->getPost('slug');
|
||||
|
|
@ -94,7 +97,7 @@ class PageController extends BaseController
|
|||
|
||||
$pageModel = new PageModel();
|
||||
|
||||
if (!$pageModel->update($this->page->id, $this->page)) {
|
||||
if (! $pageModel->update($this->page->id, $this->page)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Image;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Person;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PersonModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class PersonController extends BaseController
|
||||
{
|
||||
|
|
@ -21,15 +21,13 @@ class PersonController extends BaseController
|
|||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if (
|
||||
($this->person = (new PersonModel())->getPersonById(
|
||||
(int) $params[0],
|
||||
)) !== null
|
||||
($this->person = (new PersonModel())->getPersonById((int) $params[0],)) !== null
|
||||
) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -37,16 +35,22 @@ class PersonController extends BaseController
|
|||
|
||||
public function index(): string
|
||||
{
|
||||
$data = ['persons' => (new PersonModel())->findAll()];
|
||||
$data = [
|
||||
'persons' => (new PersonModel())->findAll(),
|
||||
];
|
||||
|
||||
return view('admin/person/list', $data);
|
||||
}
|
||||
|
||||
public function view(): string
|
||||
{
|
||||
$data = ['person' => $this->person];
|
||||
$data = [
|
||||
'person' => $this->person,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->person->full_name]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->person->full_name,
|
||||
]);
|
||||
return view('admin/person/view', $data);
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +68,7 @@ class PersonController extends BaseController
|
|||
'is_image[image]|ext_in[image,jpg,jpeg,png]|min_dims[image,400,400]|is_image_squared[image]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -82,7 +86,7 @@ class PersonController extends BaseController
|
|||
|
||||
$personModel = new PersonModel();
|
||||
|
||||
if (!$personModel->insert($person)) {
|
||||
if (! $personModel->insert($person)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -100,7 +104,9 @@ class PersonController extends BaseController
|
|||
'person' => $this->person,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->person->full_name]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->person->full_name,
|
||||
]);
|
||||
return view('admin/person/edit', $data);
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +117,7 @@ class PersonController extends BaseController
|
|||
'is_image[image]|ext_in[image,jpg,jpeg,png]|min_dims[image,400,400]|is_image_squared[image]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -120,9 +126,7 @@ class PersonController extends BaseController
|
|||
|
||||
$this->person->full_name = $this->request->getPost('full_name');
|
||||
$this->person->unique_name = $this->request->getPost('unique_name');
|
||||
$this->person->information_url = $this->request->getPost(
|
||||
'information_url',
|
||||
);
|
||||
$this->person->information_url = $this->request->getPost('information_url',);
|
||||
$imageFile = $this->request->getFile('image');
|
||||
if ($imageFile !== null && $imageFile->isValid()) {
|
||||
$this->person->image = new Image($imageFile);
|
||||
|
|
@ -131,7 +135,7 @@ class PersonController extends BaseController
|
|||
$this->person->updated_by = user_id();
|
||||
|
||||
$personModel = new PersonModel();
|
||||
if (!$personModel->update($this->person->id, $this->person)) {
|
||||
if (! $personModel->update($this->person->id, $this->person)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
|||
|
|
@ -11,34 +11,29 @@ namespace App\Controllers\Admin;
|
|||
use App\Entities\Image;
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Podcast;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Config\Database;
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\LanguageModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Database;
|
||||
use Config\Services;
|
||||
|
||||
class PodcastController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast
|
||||
*/
|
||||
protected Podcast $podcast;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
(int) $params[0],
|
||||
)) !== null
|
||||
($this->podcast = (new PodcastModel())->getPodcastById((int) $params[0],)) !== null
|
||||
) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -46,14 +41,14 @@ class PodcastController extends BaseController
|
|||
|
||||
public function list(): string
|
||||
{
|
||||
if (!has_permission('podcasts-list')) {
|
||||
if (! has_permission('podcasts-list')) {
|
||||
$data = [
|
||||
'podcasts' => (new PodcastModel())->getUserPodcasts(
|
||||
(int) user_id(),
|
||||
),
|
||||
'podcasts' => (new PodcastModel())->getUserPodcasts((int) user_id(),),
|
||||
];
|
||||
} else {
|
||||
$data = ['podcasts' => (new PodcastModel())->findAll()];
|
||||
$data = [
|
||||
'podcasts' => (new PodcastModel())->findAll(),
|
||||
];
|
||||
}
|
||||
|
||||
return view('admin/podcast/list', $data);
|
||||
|
|
@ -61,65 +56,97 @@ class PodcastController extends BaseController
|
|||
|
||||
public function view(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/view', $data);
|
||||
}
|
||||
|
||||
public function viewAnalytics(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/index', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsWebpages(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/webpages', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsLocations(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/locations', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsUniqueListeners(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/unique_listeners', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsListeningTime(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/listening_time', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsTimePeriods(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/time_periods', $data);
|
||||
}
|
||||
|
||||
public function viewAnalyticsPlayers(): string
|
||||
{
|
||||
$data = ['podcast' => $this->podcast];
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/analytics/players', $data);
|
||||
}
|
||||
|
||||
|
|
@ -133,9 +160,7 @@ class PodcastController extends BaseController
|
|||
$data = [
|
||||
'languageOptions' => $languageOptions,
|
||||
'categoryOptions' => $categoryOptions,
|
||||
'browserLang' => get_browser_language(
|
||||
$this->request->getServer('HTTP_ACCEPT_LANGUAGE'),
|
||||
),
|
||||
'browserLang' => get_browser_language($this->request->getServer('HTTP_ACCEPT_LANGUAGE'),),
|
||||
];
|
||||
|
||||
return view('admin/podcast/create', $data);
|
||||
|
|
@ -148,7 +173,7 @@ class PodcastController extends BaseController
|
|||
'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -171,9 +196,7 @@ class PodcastController extends BaseController
|
|||
'publisher' => $this->request->getPost('publisher'),
|
||||
'type' => $this->request->getPost('type'),
|
||||
'copyright' => $this->request->getPost('copyright'),
|
||||
'location' => new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
),
|
||||
'location' => new Location($this->request->getPost('location_name'),),
|
||||
'payment_pointer' => $this->request->getPost('payment_pointer'),
|
||||
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
||||
'partner_id' => $this->request->getPost('partner_id'),
|
||||
|
|
@ -191,7 +214,7 @@ class PodcastController extends BaseController
|
|||
|
||||
$db->transStart();
|
||||
|
||||
if (!($newPodcastId = $podcastModel->insert($podcast, true))) {
|
||||
if (! ($newPodcastId = $podcastModel->insert($podcast, true))) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -202,11 +225,7 @@ class PodcastController extends BaseController
|
|||
$authorize = Services::authorization();
|
||||
$podcastAdminGroup = $authorize->group('podcast_admin');
|
||||
|
||||
$podcastModel->addPodcastContributor(
|
||||
user_id(),
|
||||
$newPodcastId,
|
||||
$podcastAdminGroup->id,
|
||||
);
|
||||
$podcastModel->addPodcastContributor(user_id(), $newPodcastId, $podcastAdminGroup->id,);
|
||||
|
||||
// set Podcast categories
|
||||
(new CategoryModel())->setPodcastCategories(
|
||||
|
|
@ -236,7 +255,9 @@ class PodcastController extends BaseController
|
|||
'categoryOptions' => $categoryOptions,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/edit', $data);
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +268,7 @@ class PodcastController extends BaseController
|
|||
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -255,9 +276,7 @@ class PodcastController extends BaseController
|
|||
}
|
||||
|
||||
$this->podcast->title = $this->request->getPost('title');
|
||||
$this->podcast->description_markdown = $this->request->getPost(
|
||||
'description',
|
||||
);
|
||||
$this->podcast->description_markdown = $this->request->getPost('description',);
|
||||
|
||||
$image = $this->request->getFile('image');
|
||||
if ($image !== null && $image->isValid()) {
|
||||
|
|
@ -274,22 +293,12 @@ class PodcastController extends BaseController
|
|||
$this->podcast->owner_email = $this->request->getPost('owner_email');
|
||||
$this->podcast->type = $this->request->getPost('type');
|
||||
$this->podcast->copyright = $this->request->getPost('copyright');
|
||||
$this->podcast->location = new Location(
|
||||
$this->request->getPost('location_name'),
|
||||
);
|
||||
$this->podcast->payment_pointer = $this->request->getPost(
|
||||
'payment_pointer',
|
||||
);
|
||||
$this->podcast->custom_rss_string = $this->request->getPost(
|
||||
'custom_rss',
|
||||
);
|
||||
$this->podcast->location = new Location($this->request->getPost('location_name'),);
|
||||
$this->podcast->payment_pointer = $this->request->getPost('payment_pointer',);
|
||||
$this->podcast->custom_rss_string = $this->request->getPost('custom_rss',);
|
||||
$this->podcast->partner_id = $this->request->getPost('partner_id');
|
||||
$this->podcast->partner_link_url = $this->request->getPost(
|
||||
'partner_link_url',
|
||||
);
|
||||
$this->podcast->partner_image_url = $this->request->getPost(
|
||||
'partner_image_url',
|
||||
);
|
||||
$this->podcast->partner_link_url = $this->request->getPost('partner_link_url',);
|
||||
$this->podcast->partner_image_url = $this->request->getPost('partner_image_url',);
|
||||
$this->podcast->is_blocked = $this->request->getPost('block') === 'yes';
|
||||
$this->podcast->is_completed =
|
||||
$this->request->getPost('complete') === 'yes';
|
||||
|
|
@ -300,7 +309,7 @@ class PodcastController extends BaseController
|
|||
$db->transStart();
|
||||
|
||||
$podcastModel = new PodcastModel();
|
||||
if (!$podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||
if (! $podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -326,7 +335,9 @@ class PodcastController extends BaseController
|
|||
->orderBy('created_at', 'desc')
|
||||
->findAll($limit);
|
||||
|
||||
return view('admin/podcast/latest_episodes', ['episodes' => $episodes]);
|
||||
return view('admin/podcast/latest_episodes', [
|
||||
'episodes' => $episodes,
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete(): RedirectResponse
|
||||
|
|
|
|||
|
|
@ -8,40 +8,37 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Podcast;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ErrorException;
|
||||
use Config\Database;
|
||||
use Podlibre\PodcastNamespace\ReversedTaxonomy;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Image;
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Person;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\LanguageModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PlatformModel;
|
||||
use App\Models\LanguageModel;
|
||||
use App\Models\PersonModel;
|
||||
use App\Models\PlatformModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Database;
|
||||
use Config\Services;
|
||||
use ErrorException;
|
||||
use League\HTMLToMarkdown\HtmlConverter;
|
||||
use Podlibre\PodcastNamespace\ReversedTaxonomy;
|
||||
|
||||
class PodcastImportController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast|null
|
||||
*/
|
||||
protected ?Podcast $podcast;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if (($this->podcast = (new PodcastModel())->getPodcastById((int) $params[0])) !== null) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -57,9 +54,7 @@ class PodcastImportController extends BaseController
|
|||
$data = [
|
||||
'languageOptions' => $languageOptions,
|
||||
'categoryOptions' => $categoryOptions,
|
||||
'browserLang' => get_browser_language(
|
||||
$this->request->getServer('HTTP_ACCEPT_LANGUAGE'),
|
||||
),
|
||||
'browserLang' => get_browser_language($this->request->getServer('HTTP_ACCEPT_LANGUAGE'),),
|
||||
];
|
||||
|
||||
return view('admin/podcast/import', $data);
|
||||
|
|
@ -75,7 +70,7 @@ class PodcastImportController extends BaseController
|
|||
'max_episodes' => 'is_natural_no_zero|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -83,9 +78,7 @@ class PodcastImportController extends BaseController
|
|||
}
|
||||
try {
|
||||
ini_set('user_agent', 'Castopod/' . CP_VERSION);
|
||||
$feed = simplexml_load_file(
|
||||
$this->request->getPost('imported_feed_url'),
|
||||
);
|
||||
$feed = simplexml_load_file($this->request->getPost('imported_feed_url'),);
|
||||
} catch (ErrorException $errorException) {
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -99,15 +92,11 @@ class PodcastImportController extends BaseController
|
|||
' ⎋</a>',
|
||||
]);
|
||||
}
|
||||
$nsItunes = $feed->channel[0]->children(
|
||||
'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||
);
|
||||
$nsItunes = $feed->channel[0]->children('http://www.itunes.com/dtds/podcast-1.0.dtd',);
|
||||
$nsPodcast = $feed->channel[0]->children(
|
||||
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md',
|
||||
);
|
||||
$nsContent = $feed->channel[0]->children(
|
||||
'http://purl.org/rss/1.0/modules/content/',
|
||||
);
|
||||
$nsContent = $feed->channel[0]->children('http://purl.org/rss/1.0/modules/content/',);
|
||||
|
||||
if ((string) $nsPodcast->locked === 'yes') {
|
||||
return redirect()
|
||||
|
|
@ -125,13 +114,9 @@ class PodcastImportController extends BaseController
|
|||
property_exists($nsItunes, 'image') && $nsItunes->image !== null &&
|
||||
$nsItunes->image->attributes()['href'] !== null
|
||||
) {
|
||||
$imageFile = download_file(
|
||||
(string) $nsItunes->image->attributes()['href'],
|
||||
);
|
||||
$imageFile = download_file((string) $nsItunes->image->attributes()['href'],);
|
||||
} else {
|
||||
$imageFile = download_file(
|
||||
(string) $feed->channel[0]->image->url,
|
||||
);
|
||||
$imageFile = download_file((string) $feed->channel[0]->image->url,);
|
||||
}
|
||||
|
||||
$location = null;
|
||||
|
|
@ -145,37 +130,37 @@ class PodcastImportController extends BaseController
|
|||
|
||||
$podcast = new Podcast([
|
||||
'name' => $this->request->getPost('name'),
|
||||
'imported_feed_url' => $this->request->getPost(
|
||||
'imported_feed_url',
|
||||
),
|
||||
'new_feed_url' => base_url(
|
||||
route_to('podcast_feed', $this->request->getPost('name')),
|
||||
),
|
||||
'imported_feed_url' => $this->request->getPost('imported_feed_url',),
|
||||
'new_feed_url' => base_url(route_to('podcast_feed', $this->request->getPost('name')),),
|
||||
'title' => (string) $feed->channel[0]->title,
|
||||
'description_markdown' => $converter->convert(
|
||||
$channelDescriptionHtml,
|
||||
),
|
||||
'description_markdown' => $converter->convert($channelDescriptionHtml,),
|
||||
'description_html' => $channelDescriptionHtml,
|
||||
'image' => new Image($imageFile),
|
||||
'language_code' => $this->request->getPost('language'),
|
||||
'category_id' => $this->request->getPost('category'),
|
||||
'parental_advisory' =>
|
||||
property_exists($nsItunes, 'explicit') && $nsItunes->explicit !== null
|
||||
? (in_array((string) $nsItunes->explicit, ['yes', 'true'])
|
||||
? (in_array((string) $nsItunes->explicit, ['yes', 'true'], true)
|
||||
? 'explicit'
|
||||
: (in_array((string) $nsItunes->explicit, ['no', 'false'])
|
||||
: (in_array((string) $nsItunes->explicit, ['no', 'false'], true)
|
||||
? 'clean'
|
||||
: null))
|
||||
: null,
|
||||
'owner_name' => (string) $nsItunes->owner->name,
|
||||
'owner_email' => (string) $nsItunes->owner->email,
|
||||
'publisher' => (string) $nsItunes->author,
|
||||
'type' => property_exists($nsItunes, 'type') && $nsItunes->type !== null ? (string) $nsItunes->type : 'episodic',
|
||||
'type' => property_exists(
|
||||
$nsItunes,
|
||||
'type'
|
||||
) && $nsItunes->type !== null ? (string) $nsItunes->type : 'episodic',
|
||||
'copyright' => (string) $feed->channel[0]->copyright,
|
||||
'is_blocked' =>
|
||||
property_exists($nsItunes, 'block') && $nsItunes->block !== null && (string) $nsItunes->block === 'yes',
|
||||
'is_completed' =>
|
||||
property_exists($nsItunes, 'complete') && $nsItunes->complete !== null && (string) $nsItunes->complete === 'yes',
|
||||
property_exists(
|
||||
$nsItunes,
|
||||
'complete'
|
||||
) && $nsItunes->complete !== null && (string) $nsItunes->complete === 'yes',
|
||||
'location' => $location,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
|
|
@ -199,7 +184,7 @@ class PodcastImportController extends BaseController
|
|||
|
||||
$db->transStart();
|
||||
|
||||
if (!($newPodcastId = $podcastModel->insert($podcast, true))) {
|
||||
if (! ($newPodcastId = $podcastModel->insert($podcast, true))) {
|
||||
$db->transRollback();
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -210,17 +195,22 @@ class PodcastImportController extends BaseController
|
|||
$authorize = Services::authorization();
|
||||
$podcastAdminGroup = $authorize->group('podcast_admin');
|
||||
|
||||
$podcastModel->addPodcastContributor(
|
||||
user_id(),
|
||||
$newPodcastId,
|
||||
$podcastAdminGroup->id,
|
||||
);
|
||||
$podcastModel->addPodcastContributor(user_id(), $newPodcastId, $podcastAdminGroup->id,);
|
||||
|
||||
$podcastsPlatformsData = [];
|
||||
$platformTypes = [
|
||||
['name' => 'podcasting', 'elements' => $nsPodcast->id],
|
||||
['name' => 'social', 'elements' => $nsPodcast->social],
|
||||
['name' => 'funding', 'elements' => $nsPodcast->funding],
|
||||
[
|
||||
'name' => 'podcasting',
|
||||
'elements' => $nsPodcast->id,
|
||||
],
|
||||
[
|
||||
'name' => 'social',
|
||||
'elements' => $nsPodcast->social,
|
||||
],
|
||||
[
|
||||
'name' => 'funding',
|
||||
'elements' => $nsPodcast->funding,
|
||||
],
|
||||
];
|
||||
$platformModel = new PlatformModel();
|
||||
foreach ($platformTypes as $platformType) {
|
||||
|
|
@ -240,10 +230,7 @@ class PodcastImportController extends BaseController
|
|||
}
|
||||
|
||||
if (count($podcastsPlatformsData) > 1) {
|
||||
$platformModel->createPodcastPlatforms(
|
||||
$newPodcastId,
|
||||
$podcastsPlatformsData,
|
||||
);
|
||||
$platformModel->createPodcastPlatforms($newPodcastId, $podcastsPlatformsData,);
|
||||
}
|
||||
|
||||
foreach ($nsPodcast->person as $podcastPerson) {
|
||||
|
|
@ -262,7 +249,7 @@ class PodcastImportController extends BaseController
|
|||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
if (!$newPersonId = $personModel->insert($newPodcastPerson)) {
|
||||
if (! $newPersonId = $personModel->insert($newPodcastPerson)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -271,8 +258,8 @@ class PodcastImportController extends BaseController
|
|||
}
|
||||
|
||||
// TODO: these checks should be in the taxonomy as default values
|
||||
$podcastPersonGroup = $podcastPerson->attributes()['group'] ?? "Cast";
|
||||
$podcastPersonRole = $podcastPerson->attributes()['role'] ?? "Host";
|
||||
$podcastPersonGroup = $podcastPerson->attributes()['group'] ?? 'Cast';
|
||||
$podcastPersonRole = $podcastPerson->attributes()['role'] ?? 'Host';
|
||||
|
||||
$personGroup = ReversedTaxonomy::$taxonomy[(string) $podcastPersonGroup];
|
||||
|
||||
|
|
@ -280,7 +267,12 @@ class PodcastImportController extends BaseController
|
|||
$personRoleSlug = $personGroup['roles'][(string) $podcastPersonRole]['slug'];
|
||||
|
||||
$podcastPersonModel = new PersonModel();
|
||||
if (!$podcastPersonModel->addPodcastPerson($newPodcastId, $newPersonId, $personGroupSlug, $personRoleSlug)) {
|
||||
if (! $podcastPersonModel->addPodcastPerson(
|
||||
$newPodcastId,
|
||||
$newPersonId,
|
||||
$personGroupSlug,
|
||||
$personRoleSlug
|
||||
)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -296,30 +288,23 @@ class PodcastImportController extends BaseController
|
|||
: $numberItems;
|
||||
|
||||
$slugs = [];
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// For each Episode:
|
||||
for ($itemNumber = 1; $itemNumber <= $lastItem; ++$itemNumber) {
|
||||
$item = $feed->channel[0]->item[$numberItems - $itemNumber];
|
||||
|
||||
$nsItunes = $item->children(
|
||||
'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||
);
|
||||
$nsItunes = $item->children('http://www.itunes.com/dtds/podcast-1.0.dtd',);
|
||||
$nsPodcast = $item->children(
|
||||
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md',
|
||||
);
|
||||
$nsContent = $item->children(
|
||||
'http://purl.org/rss/1.0/modules/content/',
|
||||
);
|
||||
$nsContent = $item->children('http://purl.org/rss/1.0/modules/content/',);
|
||||
|
||||
$slug = slugify(
|
||||
$this->request->getPost('slug_field') === 'title'
|
||||
? $item->title
|
||||
: basename($item->link),
|
||||
);
|
||||
if (in_array($slug, $slugs)) {
|
||||
if (in_array($slug, $slugs, true)) {
|
||||
$slugNumber = 2;
|
||||
while (in_array($slug . '-' . $slugNumber, $slugs)) {
|
||||
while (in_array($slug . '-' . $slugNumber, $slugs, true)) {
|
||||
++$slugNumber;
|
||||
}
|
||||
$slug = $slug . '-' . $slugNumber;
|
||||
|
|
@ -336,11 +321,7 @@ class PodcastImportController extends BaseController
|
|||
property_exists($nsItunes, 'image') && $nsItunes->image !== null &&
|
||||
$nsItunes->image->attributes()['href'] !== null
|
||||
) {
|
||||
$episodeImage = new Image(
|
||||
download_file(
|
||||
(string) $nsItunes->image->attributes()['href'],
|
||||
),
|
||||
);
|
||||
$episodeImage = new Image(download_file((string) $nsItunes->image->attributes()['href'],),);
|
||||
} else {
|
||||
$episodeImage = null;
|
||||
}
|
||||
|
|
@ -359,19 +340,15 @@ class PodcastImportController extends BaseController
|
|||
'guid' => $item->guid ?? null,
|
||||
'title' => $item->title,
|
||||
'slug' => $slug,
|
||||
'audio_file' => download_file(
|
||||
$item->enclosure->attributes()['url'],
|
||||
),
|
||||
'description_markdown' => $converter->convert(
|
||||
$itemDescriptionHtml,
|
||||
),
|
||||
'audio_file' => download_file($item->enclosure->attributes()['url'],),
|
||||
'description_markdown' => $converter->convert($itemDescriptionHtml,),
|
||||
'description_html' => $itemDescriptionHtml,
|
||||
'image' => $episodeImage,
|
||||
'parental_advisory' =>
|
||||
property_exists($nsItunes, 'explicit') && $nsItunes->explicit !== null
|
||||
? (in_array((string) $nsItunes->explicit, ['yes', 'true'])
|
||||
? (in_array((string) $nsItunes->explicit, ['yes', 'true'], true)
|
||||
? 'explicit'
|
||||
: (in_array((string) $nsItunes->explicit, ['no', 'false'])
|
||||
: (in_array((string) $nsItunes->explicit, ['no', 'false'], true)
|
||||
? 'clean'
|
||||
: null))
|
||||
: null,
|
||||
|
|
@ -386,7 +363,10 @@ class PodcastImportController extends BaseController
|
|||
'type' => property_exists($nsItunes, 'episodeType') && $nsItunes->episodeType !== null
|
||||
? (string) $nsItunes->episodeType
|
||||
: 'full',
|
||||
'is_blocked' => property_exists($nsItunes, 'block') && $nsItunes->block !== null && (string) $nsItunes->block === 'yes',
|
||||
'is_blocked' => property_exists(
|
||||
$nsItunes,
|
||||
'block'
|
||||
) && $nsItunes->block !== null && (string) $nsItunes->block === 'yes',
|
||||
'location' => $location,
|
||||
'created_by' => user_id(),
|
||||
'updated_by' => user_id(),
|
||||
|
|
@ -395,7 +375,7 @@ class PodcastImportController extends BaseController
|
|||
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
||||
if (!($newEpisodeId = $episodeModel->insert($newEpisode, true))) {
|
||||
if (! ($newEpisodeId = $episodeModel->insert($newEpisode, true))) {
|
||||
// FIXME: What shall we do?
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -419,7 +399,7 @@ class PodcastImportController extends BaseController
|
|||
'updated_by' => user_id(),
|
||||
]);
|
||||
|
||||
if (!($newPersonId = $personModel->insert($newPerson))) {
|
||||
if (! ($newPersonId = $personModel->insert($newPerson))) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -428,8 +408,8 @@ class PodcastImportController extends BaseController
|
|||
}
|
||||
|
||||
// TODO: these checks should be in the taxonomy as default values
|
||||
$episodePersonGroup = $episodePerson->attributes()['group'] ?? "Cast";
|
||||
$episodePersonRole = $episodePerson->attributes()['role'] ?? "Host";
|
||||
$episodePersonGroup = $episodePerson->attributes()['group'] ?? 'Cast';
|
||||
$episodePersonRole = $episodePerson->attributes()['role'] ?? 'Host';
|
||||
|
||||
$personGroup = ReversedTaxonomy::$taxonomy[(string) $episodePersonGroup];
|
||||
|
||||
|
|
@ -437,7 +417,13 @@ class PodcastImportController extends BaseController
|
|||
$personRoleSlug = $personGroup['roles'][(string) $episodePersonRole]['slug'];
|
||||
|
||||
$episodePersonModel = new PersonModel();
|
||||
if (!$episodePersonModel->addEpisodePerson($newPodcastId, $newEpisodeId, $newPersonId, $personGroupSlug, $personRoleSlug)) {
|
||||
if (! $episodePersonModel->addEpisodePerson(
|
||||
$newPodcastId,
|
||||
$newEpisodeId,
|
||||
$newPersonId,
|
||||
$personGroupSlug,
|
||||
$personRoleSlug
|
||||
)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
|||
|
|
@ -8,17 +8,14 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Podcast;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\PersonModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class PodcastPersonController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast
|
||||
*/
|
||||
protected Podcast $podcast;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
|
|
@ -28,12 +25,10 @@ class PodcastPersonController extends BaseController
|
|||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
(int) $params[0],
|
||||
)) !== null
|
||||
($this->podcast = (new PodcastModel())->getPodcastById((int) $params[0],)) !== null
|
||||
) {
|
||||
unset($params[0]);
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -45,9 +40,7 @@ class PodcastPersonController extends BaseController
|
|||
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'podcastPersons' => (new PersonModel())->getPodcastPersons(
|
||||
$this->podcast->id,
|
||||
),
|
||||
'podcastPersons' => (new PersonModel())->getPodcastPersons($this->podcast->id,),
|
||||
'personOptions' => (new PersonModel())->getPersonOptions(),
|
||||
'taxonomyOptions' => (new PersonModel())->getTaxonomyOptions(),
|
||||
];
|
||||
|
|
@ -63,7 +56,7 @@ class PodcastPersonController extends BaseController
|
|||
'persons' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -81,10 +74,7 @@ class PodcastPersonController extends BaseController
|
|||
|
||||
public function remove(int $personId): RedirectResponse
|
||||
{
|
||||
(new PersonModel())->removePersonFromPodcast(
|
||||
$this->podcast->id,
|
||||
$personId,
|
||||
);
|
||||
(new PersonModel())->removePersonFromPodcast($this->podcast->id, $personId,);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,33 +8,28 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use App\Entities\Podcast;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PlatformModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Services;
|
||||
|
||||
class PodcastPlatformController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var Podcast|null
|
||||
*/
|
||||
protected ?Podcast $podcast;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
(int) $params[0],
|
||||
)) !== null
|
||||
($this->podcast = (new PodcastModel())->getPodcastById((int) $params[0],)) !== null
|
||||
) {
|
||||
unset($params[0]);
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -52,19 +47,17 @@ class PodcastPlatformController extends BaseController
|
|||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'platformType' => $platformType,
|
||||
'platforms' => (new PlatformModel())->getPlatformsWithLinks(
|
||||
$this->podcast->id,
|
||||
$platformType,
|
||||
),
|
||||
'platforms' => (new PlatformModel())->getPlatformsWithLinks($this->podcast->id, $platformType,),
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->podcast->title]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->podcast->title,
|
||||
]);
|
||||
return view('admin/podcast/platforms', $data);
|
||||
}
|
||||
|
||||
public function attemptPlatformsUpdate(
|
||||
string $platformType
|
||||
): RedirectResponse {
|
||||
public function attemptPlatformsUpdate(string $platformType): RedirectResponse
|
||||
{
|
||||
$platformModel = new PlatformModel();
|
||||
$validation = Services::validation();
|
||||
|
||||
|
|
@ -78,7 +71,7 @@ class PodcastPlatformController extends BaseController
|
|||
if ($podcastPlatformUrl === null) {
|
||||
continue;
|
||||
}
|
||||
if (!$validation->check($podcastPlatformUrl, 'validate_url')) {
|
||||
if (! $validation->check($podcastPlatformUrl, 'validate_url')) {
|
||||
continue;
|
||||
}
|
||||
$podcastsPlatformsData[] = [
|
||||
|
|
@ -88,36 +81,28 @@ class PodcastPlatformController extends BaseController
|
|||
'link_content' => $podcastPlatform['content'],
|
||||
'is_visible' =>
|
||||
array_key_exists('visible', $podcastPlatform) &&
|
||||
$podcastPlatform['visible'] == 'yes',
|
||||
$podcastPlatform['visible'] === 'yes',
|
||||
'is_on_embeddable_player' =>
|
||||
array_key_exists(
|
||||
'on_embeddable_player',
|
||||
$podcastPlatform,
|
||||
) && $podcastPlatform['on_embeddable_player'] == 'yes',
|
||||
) && $podcastPlatform['on_embeddable_player'] === 'yes',
|
||||
];
|
||||
return redirect()
|
||||
->back()
|
||||
->with('message', lang('Platforms.messages.updateSuccess'));
|
||||
}
|
||||
|
||||
$platformModel->savePodcastPlatforms(
|
||||
$this->podcast->id,
|
||||
$platformType,
|
||||
$podcastsPlatformsData,
|
||||
);
|
||||
$platformModel->savePodcastPlatforms($this->podcast->id, $platformType, $podcastsPlatformsData,);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('message', lang('Platforms.messages.updateSuccess'));
|
||||
}
|
||||
|
||||
public function removePodcastPlatform(
|
||||
string $platformSlug
|
||||
): RedirectResponse {
|
||||
(new PlatformModel())->removePodcastPlatform(
|
||||
$this->podcast->id,
|
||||
$platformSlug,
|
||||
);
|
||||
public function removePodcastPlatform(string $platformSlug): RedirectResponse
|
||||
{
|
||||
(new PlatformModel())->removePodcastPlatform($this->podcast->id, $platformSlug,);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Authorization\GroupModel;
|
||||
use App\Entities\User;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Config\Services;
|
||||
|
||||
|
|
@ -22,11 +22,11 @@ class UserController extends BaseController
|
|||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
if ($this->user = (new UserModel())->find($params[0])) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -34,16 +34,22 @@ class UserController extends BaseController
|
|||
|
||||
public function list(): string
|
||||
{
|
||||
$data = ['users' => (new UserModel())->findAll()];
|
||||
$data = [
|
||||
'users' => (new UserModel())->findAll(),
|
||||
];
|
||||
|
||||
return view('admin/user/list', $data);
|
||||
}
|
||||
|
||||
public function view(): string
|
||||
{
|
||||
$data = ['user' => $this->user];
|
||||
$data = [
|
||||
'user' => $this->user,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->user->username]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->user->username,
|
||||
]);
|
||||
return view('admin/user/view', $data);
|
||||
}
|
||||
|
||||
|
|
@ -65,14 +71,16 @@ class UserController extends BaseController
|
|||
// Validate here first, since some things,
|
||||
// like the password, can only be validated properly here.
|
||||
$rules = array_merge(
|
||||
$userModel->getValidationRules(['only' => ['username']]),
|
||||
$userModel->getValidationRules([
|
||||
'only' => ['username'],
|
||||
]),
|
||||
[
|
||||
'email' => 'required|valid_email|is_unique[users.email]',
|
||||
'password' => 'required|strong_password',
|
||||
],
|
||||
);
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -88,7 +96,7 @@ class UserController extends BaseController
|
|||
// Force user to reset his password on first connection
|
||||
$user->forcePasswordReset();
|
||||
|
||||
if (!$userModel->insert($user)) {
|
||||
if (! $userModel->insert($user)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -98,12 +106,9 @@ class UserController extends BaseController
|
|||
// Success!
|
||||
return redirect()
|
||||
->route('user-list')
|
||||
->with(
|
||||
'message',
|
||||
lang('User.messages.createSuccess', [
|
||||
'username' => $user->username,
|
||||
]),
|
||||
);
|
||||
->with('message', lang('User.messages.createSuccess', [
|
||||
'username' => $user->username,
|
||||
]),);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
|
|
@ -125,7 +130,9 @@ class UserController extends BaseController
|
|||
'roleOptions' => $roleOptions,
|
||||
];
|
||||
|
||||
replace_breadcrumb_params([0 => $this->user->username]);
|
||||
replace_breadcrumb_params([
|
||||
0 => $this->user->username,
|
||||
]);
|
||||
return view('admin/user/edit', $data);
|
||||
}
|
||||
|
||||
|
|
@ -139,12 +146,9 @@ class UserController extends BaseController
|
|||
// Success!
|
||||
return redirect()
|
||||
->route('user-list')
|
||||
->with(
|
||||
'message',
|
||||
lang('User.messages.rolesEditSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),
|
||||
);
|
||||
->with('message', lang('User.messages.rolesEditSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),);
|
||||
}
|
||||
|
||||
public function forcePassReset(): RedirectResponse
|
||||
|
|
@ -152,7 +156,7 @@ class UserController extends BaseController
|
|||
$userModel = new UserModel();
|
||||
$this->user->forcePasswordReset();
|
||||
|
||||
if (!$userModel->update($this->user->id, $this->user)) {
|
||||
if (! $userModel->update($this->user->id, $this->user)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('errors', $userModel->errors());
|
||||
|
|
@ -186,7 +190,7 @@ class UserController extends BaseController
|
|||
// TODO: add ban reason?
|
||||
$this->user->ban('');
|
||||
|
||||
if (!$userModel->update($this->user->id, $this->user)) {
|
||||
if (! $userModel->update($this->user->id, $this->user)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('errors', $userModel->errors());
|
||||
|
|
@ -194,12 +198,9 @@ class UserController extends BaseController
|
|||
|
||||
return redirect()
|
||||
->route('user-list')
|
||||
->with(
|
||||
'message',
|
||||
lang('User.messages.banSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),
|
||||
);
|
||||
->with('message', lang('User.messages.banSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),);
|
||||
}
|
||||
|
||||
public function unBan(): RedirectResponse
|
||||
|
|
@ -207,7 +208,7 @@ class UserController extends BaseController
|
|||
$userModel = new UserModel();
|
||||
$this->user->unBan();
|
||||
|
||||
if (!$userModel->update($this->user->id, $this->user)) {
|
||||
if (! $userModel->update($this->user->id, $this->user)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('errors', $userModel->errors());
|
||||
|
|
@ -215,12 +216,9 @@ class UserController extends BaseController
|
|||
|
||||
return redirect()
|
||||
->route('user-list')
|
||||
->with(
|
||||
'message',
|
||||
lang('User.messages.unbanSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),
|
||||
);
|
||||
->with('message', lang('User.messages.unbanSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),);
|
||||
}
|
||||
|
||||
public function delete(): RedirectResponse
|
||||
|
|
@ -240,11 +238,8 @@ class UserController extends BaseController
|
|||
|
||||
return redirect()
|
||||
->back()
|
||||
->with(
|
||||
'message',
|
||||
lang('User.messages.deleteSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),
|
||||
);
|
||||
->with('message', lang('User.messages.deleteSuccess', [
|
||||
'username' => $this->user->username,
|
||||
]),);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,14 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Myth\Auth\Controllers\AuthController as MythAuthController;
|
||||
use App\Entities\User;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use Myth\Auth\Controllers\AuthController as MythAuthController;
|
||||
|
||||
class AuthController extends MythAuthController
|
||||
{
|
||||
/**
|
||||
* An array of helpers to be automatically loaded
|
||||
* upon class instantiation.
|
||||
* An array of helpers to be automatically loaded upon class instantiation.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
@ -28,7 +27,7 @@ class AuthController extends MythAuthController
|
|||
public function attemptRegister(): RedirectResponse
|
||||
{
|
||||
// Check if registration is allowed
|
||||
if (!$this->config->allowRegistration) {
|
||||
if (! $this->config->allowRegistration) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -46,7 +45,7 @@ class AuthController extends MythAuthController
|
|||
'password' => 'required|strong_password',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -54,11 +53,7 @@ class AuthController extends MythAuthController
|
|||
}
|
||||
|
||||
// Save the user
|
||||
$allowedPostFields = array_merge(
|
||||
['password'],
|
||||
$this->config->validFields,
|
||||
$this->config->personalFields,
|
||||
);
|
||||
$allowedPostFields = array_merge(['password'], $this->config->validFields, $this->config->personalFields,);
|
||||
$user = new User($this->request->getPost($allowedPostFields));
|
||||
|
||||
$this->config->requireActivation === null
|
||||
|
|
@ -70,7 +65,7 @@ class AuthController extends MythAuthController
|
|||
$users = $users->withGroup($this->config->defaultUserGroup);
|
||||
}
|
||||
|
||||
if (!$users->save($user)) {
|
||||
if (! $users->save($user)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -81,14 +76,11 @@ class AuthController extends MythAuthController
|
|||
$activator = service('activator');
|
||||
$sent = $activator->send($user);
|
||||
|
||||
if (!$sent) {
|
||||
if (! $sent) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with(
|
||||
'error',
|
||||
$activator->error() ?? lang('Auth.unknownError'),
|
||||
);
|
||||
->with('error', $activator->error() ?? lang('Auth.unknownError'),);
|
||||
}
|
||||
|
||||
// Success!
|
||||
|
|
@ -104,8 +96,7 @@ class AuthController extends MythAuthController
|
|||
}
|
||||
|
||||
/**
|
||||
* Verifies the code with the email and saves the new password,
|
||||
* if they all pass validation.
|
||||
* Verifies the code with the email and saves the new password, if they all pass validation.
|
||||
*/
|
||||
public function attemptReset(): RedirectResponse
|
||||
{
|
||||
|
|
@ -131,7 +122,7 @@ class AuthController extends MythAuthController
|
|||
'password' => 'required|strong_password',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -143,7 +134,7 @@ class AuthController extends MythAuthController
|
|||
->where('reset_hash', $this->request->getPost('token'))
|
||||
->first();
|
||||
|
||||
if (is_null($user)) {
|
||||
if ($user === null) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', lang('Auth.forgotNoUser'));
|
||||
|
|
@ -179,7 +170,7 @@ class AuthController extends MythAuthController
|
|||
'actor_id' => 'required|numeric',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
|
|||
|
|
@ -10,19 +10,16 @@ use Psr\Log\LoggerInterface;
|
|||
/**
|
||||
* Class BaseController
|
||||
*
|
||||
* BaseController provides a convenient place for loading components
|
||||
* and performing functions that are needed by all your controllers.
|
||||
* Extend this class in any new controllers:
|
||||
* class Home extends BaseController
|
||||
* BaseController provides a convenient place for loading components and performing functions that are needed by all
|
||||
* your controllers. Extend this class in any new controllers: class Home extends BaseController
|
||||
*
|
||||
* For security be sure to declare any new methods as protected or private.
|
||||
*/
|
||||
class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* An array of helpers to be loaded automatically upon
|
||||
* class instantiation. These helpers will be available
|
||||
* to all other controllers that extend BaseController.
|
||||
* An array of helpers to be loaded automatically upon class instantiation. These helpers will be available to all
|
||||
* other controllers that extend BaseController.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
@ -38,10 +35,5 @@ class BaseController extends Controller
|
|||
): void {
|
||||
// Do Not Edit This Line
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Preload any models, libraries, etc, here.
|
||||
//--------------------------------------------------------------------
|
||||
// E.g.: $this->session = \Config\Services::session();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
178
app/Controllers/CreditsController.php
Normal file
178
app/Controllers/CreditsController.php
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Entities\Page;
|
||||
use App\Models\CreditModel;
|
||||
use App\Models\PodcastModel;
|
||||
|
||||
class CreditsController extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$locale = service('request')
|
||||
->getLocale();
|
||||
$allPodcasts = (new PodcastModel())->findAll();
|
||||
|
||||
$cacheName = "page_credits_{$locale}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$page = new Page([
|
||||
'title' => lang('Person.credits', [], $locale),
|
||||
'slug' => 'credits',
|
||||
'content_markdown' => '',
|
||||
]);
|
||||
|
||||
$allCredits = (new CreditModel())->findAll();
|
||||
|
||||
// Unlike the carpenter, we make a tree from a table:
|
||||
$personGroup = null;
|
||||
$personId = null;
|
||||
$personRole = null;
|
||||
$credits = [];
|
||||
foreach ($allCredits as $credit) {
|
||||
if ($personGroup !== $credit->person_group) {
|
||||
$personGroup = $credit->person_group;
|
||||
$personId = $credit->person_id;
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup] = [
|
||||
'group_label' => $credit->group_label,
|
||||
'persons' => [
|
||||
$personId => [
|
||||
'full_name' => $credit->person->full_name,
|
||||
'thumbnail_url' =>
|
||||
$credit->person->image->thumbnail_url,
|
||||
'information_url' =>
|
||||
$credit->person->information_url,
|
||||
'roles' => [
|
||||
$personRole => [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode
|
||||
->title .
|
||||
episode_numbering(
|
||||
$credit->episode
|
||||
->number,
|
||||
$credit->episode
|
||||
->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
} elseif ($personId !== $credit->person_id) {
|
||||
$personId = $credit->person_id;
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup]['persons'][$personId] = [
|
||||
'full_name' => $credit->person->full_name,
|
||||
'thumbnail_url' =>
|
||||
$credit->person->image->thumbnail_url,
|
||||
'information_url' => $credit->person->information_url,
|
||||
'roles' => [
|
||||
$personRole => [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
$credit->episode->number,
|
||||
$credit->episode
|
||||
->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
} elseif ($personRole !== $credit->person_role) {
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup]['persons'][$personId]['roles'][
|
||||
$personRole
|
||||
] = [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
$credit->episode->number,
|
||||
$credit->episode->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
],
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$credits[$personGroup]['persons'][$personId]['roles'][
|
||||
$personRole
|
||||
]['is_in'][] = [
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
$credit->episode->number,
|
||||
$credit->episode->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'page' => $page,
|
||||
'credits' => $credits,
|
||||
];
|
||||
|
||||
$found = view('credits', $data);
|
||||
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use Analytics\AnalyticsTrait;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class EpisodeController extends BaseController
|
||||
|
|
@ -33,22 +33,17 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||
$params[0],
|
||||
)) === null
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName($params[0],)) === null
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
if (
|
||||
($this->episode = (new EpisodeModel())->getEpisodeBySlug(
|
||||
$this->podcast->id,
|
||||
$params[1],
|
||||
)) !== null
|
||||
($this->episode = (new EpisodeModel())->getEpisodeBySlug($this->podcast->id, $params[1],)) !== null
|
||||
) {
|
||||
unset($params[1]);
|
||||
unset($params[0]);
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -57,16 +52,17 @@ class EpisodeController extends BaseController
|
|||
public function index(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->episode->podcast_id);
|
||||
}
|
||||
|
||||
$locale = service('request')->getLocale();
|
||||
$locale = service('request')
|
||||
->getLocale();
|
||||
$cacheName =
|
||||
"page_podcast#{$this->podcast->id}_episode#{$this->episode->id}_{$locale}" .
|
||||
(can_user_interact() ? '_authenticated' : '');
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'episode' => $this->episode,
|
||||
|
|
@ -92,30 +88,27 @@ class EpisodeController extends BaseController
|
|||
return $cachedView;
|
||||
}
|
||||
|
||||
public function embeddablePlayer(
|
||||
string $theme = 'light-transparent'
|
||||
): string {
|
||||
public function embeddablePlayer(string $theme = 'light-transparent'): string
|
||||
{
|
||||
header('Content-Security-Policy: frame-ancestors https://* http://*');
|
||||
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->episode->podcast_id);
|
||||
}
|
||||
|
||||
$session = Services::session();
|
||||
$session->start();
|
||||
if (isset($_SERVER['HTTP_REFERER'])) {
|
||||
$session->set(
|
||||
'embeddable_player_domain',
|
||||
parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST),
|
||||
);
|
||||
$session->set('embeddable_player_domain', parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST),);
|
||||
}
|
||||
|
||||
$locale = service('request')->getLocale();
|
||||
$locale = service('request')
|
||||
->getLocale();
|
||||
|
||||
$cacheName = "page_podcast#{$this->podcast->id}_episode#{$this->episode->id}_embeddable_player_{$theme}_{$locale}";
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$theme = EpisodeModel::$themes[$theme];
|
||||
|
||||
$data = [
|
||||
|
|
@ -157,16 +150,16 @@ class EpisodeController extends BaseController
|
|||
'width' => 600,
|
||||
'height' => 200,
|
||||
'thumbnail_url' => $this->episode->image->large_url,
|
||||
'thumbnail_width' => config('Images')->largeSize,
|
||||
'thumbnail_height' => config('Images')->largeSize,
|
||||
'thumbnail_width' => config('Images')
|
||||
->largeSize,
|
||||
'thumbnail_height' => config('Images')
|
||||
->largeSize,
|
||||
]);
|
||||
}
|
||||
|
||||
public function oembedXML(): ResponseInterface
|
||||
{
|
||||
$oembed = new SimpleXMLElement(
|
||||
"<?xml version='1.0' encoding='utf-8' standalone='yes'?><oembed></oembed>",
|
||||
);
|
||||
$oembed = new SimpleXMLElement("<?xml version='1.0' encoding='utf-8' standalone='yes'?><oembed></oembed>",);
|
||||
|
||||
$oembed->addChild('type', 'rich');
|
||||
$oembed->addChild('version', '1.0');
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Opawg\UserAgentsPhp\UserAgentsRSS;
|
||||
use Exception;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Exception;
|
||||
use Opawg\UserAgentsPhp\UserAgentsRSS;
|
||||
|
||||
class FeedController extends Controller
|
||||
{
|
||||
|
|
@ -22,8 +22,9 @@ class FeedController extends Controller
|
|||
{
|
||||
helper('rss');
|
||||
|
||||
$podcast = (new PodcastModel())->where('name', $podcastName)->first();
|
||||
if (!$podcast) {
|
||||
$podcast = (new PodcastModel())->where('name', $podcastName)
|
||||
->first();
|
||||
if (! $podcast) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ class FeedController extends Controller
|
|||
$cacheName =
|
||||
"podcast#{$podcast->id}_feed" . ($service ? "_{$serviceSlug}" : '');
|
||||
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = get_rss_feed($podcast, $serviceSlug);
|
||||
|
||||
// The page cache is set to expire after next episode publication or a decade by default so it is deleted manually upon podcast update
|
||||
|
|
@ -51,13 +52,14 @@ class FeedController extends Controller
|
|||
$podcast->id,
|
||||
);
|
||||
|
||||
cache()->save(
|
||||
$cacheName,
|
||||
$found,
|
||||
$secondsToNextUnpublishedEpisode
|
||||
cache()
|
||||
->save(
|
||||
$cacheName,
|
||||
$found,
|
||||
$secondsToNextUnpublishedEpisode
|
||||
? $secondsToNextUnpublishedEpisode
|
||||
: DECADE,
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
return $this->response->setXML($found);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use CodeIgniter\HTTP\RedirectResponse;
|
|||
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
public function index(): RedirectResponse|string
|
||||
public function index(): RedirectResponse | string
|
||||
{
|
||||
$model = new PodcastModel();
|
||||
|
||||
|
|
@ -21,13 +21,13 @@ class HomeController extends BaseController
|
|||
|
||||
// check if there's only one podcast to redirect user to it
|
||||
if (count($allPodcasts) === 1) {
|
||||
return redirect()->route('podcast-activity', [
|
||||
$allPodcasts[0]->name,
|
||||
]);
|
||||
return redirect()->route('podcast-activity', [$allPodcasts[0]->name]);
|
||||
}
|
||||
|
||||
// default behavior: list all podcasts on home page
|
||||
$data = ['podcasts' => $allPodcasts];
|
||||
$data = [
|
||||
'podcasts' => $allPodcasts,
|
||||
];
|
||||
return view('home', $data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use Dotenv\Exception\ValidationException;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
use Config\Database;
|
||||
use App\Entities\User;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Database;
|
||||
use Config\Services;
|
||||
use Dotenv\Dotenv;
|
||||
use Dotenv\Exception\ValidationException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
class InstallController extends Controller
|
||||
{
|
||||
|
|
@ -43,15 +43,13 @@ class InstallController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* Every operation goes through this method to handle
|
||||
* the install logic.
|
||||
* Every operation goes through this method to handle the install logic.
|
||||
*
|
||||
* If all required actions have already been performed,
|
||||
* the install route will show a 404 page.
|
||||
* If all required actions have already been performed, the install route will show a 404 page.
|
||||
*/
|
||||
public function index(): string
|
||||
{
|
||||
if (!file_exists(ROOTPATH . '.env')) {
|
||||
if (! file_exists(ROOTPATH . '.env')) {
|
||||
// create empty .env file
|
||||
try {
|
||||
$envFile = fopen(ROOTPATH . '.env', 'w');
|
||||
|
|
@ -69,11 +67,7 @@ class InstallController extends Controller
|
|||
// Check if the created .env file is writable to continue install process
|
||||
if (is_really_writable(ROOTPATH . '.env')) {
|
||||
try {
|
||||
$dotenv->required([
|
||||
'app.baseURL',
|
||||
'app.adminGateway',
|
||||
'app.authGateway',
|
||||
]);
|
||||
$dotenv->required(['app.baseURL', 'app.adminGateway', 'app.authGateway']);
|
||||
} catch (ValidationException $e) {
|
||||
// form to input instance configuration
|
||||
return $this->instanceConfig();
|
||||
|
|
@ -128,10 +122,8 @@ class InstallController extends Controller
|
|||
} catch (DatabaseException) {
|
||||
// Could not connect to the database
|
||||
// show database config view to fix value
|
||||
session()->setFlashdata(
|
||||
'error',
|
||||
lang('Install.messages.databaseConnectError'),
|
||||
);
|
||||
session()
|
||||
->setFlashdata('error', lang('Install.messages.databaseConnectError'),);
|
||||
|
||||
return view('install/database_config');
|
||||
}
|
||||
|
|
@ -159,13 +151,9 @@ class InstallController extends Controller
|
|||
'auth_gateway' => 'required|differs[admin_gateway]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->to(
|
||||
(host_url() === null
|
||||
? config('App')->baseURL
|
||||
: host_url()) . config('App')->installGateway,
|
||||
)
|
||||
->to((host_url() === null ? config('App') ->baseURL : host_url()) . config('App')->installGateway,)
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
|
@ -183,11 +171,7 @@ class InstallController extends Controller
|
|||
helper('text');
|
||||
|
||||
// redirect to full install url with new baseUrl input
|
||||
return redirect()->to(
|
||||
reduce_double_slashes(
|
||||
$baseUrl . '/' . config('App')->installGateway,
|
||||
),
|
||||
);
|
||||
return redirect()->to(reduce_double_slashes($baseUrl . '/' . config('App')->installGateway,),);
|
||||
}
|
||||
|
||||
public function databaseConfig(): string
|
||||
|
|
@ -204,7 +188,7 @@ class InstallController extends Controller
|
|||
'db_password' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -212,16 +196,10 @@ class InstallController extends Controller
|
|||
}
|
||||
|
||||
self::writeEnv([
|
||||
'database.default.hostname' => $this->request->getPost(
|
||||
'db_hostname',
|
||||
),
|
||||
'database.default.hostname' => $this->request->getPost('db_hostname',),
|
||||
'database.default.database' => $this->request->getPost('db_name'),
|
||||
'database.default.username' => $this->request->getPost(
|
||||
'db_username',
|
||||
),
|
||||
'database.default.password' => $this->request->getPost(
|
||||
'db_password',
|
||||
),
|
||||
'database.default.username' => $this->request->getPost('db_username',),
|
||||
'database.default.password' => $this->request->getPost('db_password',),
|
||||
'database.default.DBPrefix' => $this->request->getPost('db_prefix'),
|
||||
]);
|
||||
|
||||
|
|
@ -239,7 +217,7 @@ class InstallController extends Controller
|
|||
'cache_handler' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -260,10 +238,14 @@ class InstallController extends Controller
|
|||
{
|
||||
$migrations = Services::migrations();
|
||||
|
||||
$migrations->setNamespace('Myth\Auth')->latest();
|
||||
$migrations->setNamespace('ActivityPub')->latest();
|
||||
$migrations->setNamespace('Analytics')->latest();
|
||||
$migrations->setNamespace(APP_NAMESPACE)->latest();
|
||||
$migrations->setNamespace('Myth\Auth')
|
||||
->latest();
|
||||
$migrations->setNamespace('ActivityPub')
|
||||
->latest();
|
||||
$migrations->setNamespace('Analytics')
|
||||
->latest();
|
||||
$migrations->setNamespace(APP_NAMESPACE)
|
||||
->latest();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -297,14 +279,16 @@ class InstallController extends Controller
|
|||
// Validate here first, since some things,
|
||||
// like the password, can only be validated properly here.
|
||||
$rules = array_merge(
|
||||
$userModel->getValidationRules(['only' => ['username']]),
|
||||
$userModel->getValidationRules([
|
||||
'only' => ['username'],
|
||||
]),
|
||||
[
|
||||
'email' => 'required|valid_email|is_unique[users.email]',
|
||||
'password' => 'required|strong_password',
|
||||
],
|
||||
);
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -320,7 +304,7 @@ class InstallController extends Controller
|
|||
$db = Database::connect();
|
||||
|
||||
$db->transStart();
|
||||
if (!($userId = $userModel->insert($user, true))) {
|
||||
if (! ($userId = $userModel->insert($user, true))) {
|
||||
$db->transRollback();
|
||||
|
||||
return redirect()
|
||||
|
|
@ -337,7 +321,8 @@ class InstallController extends Controller
|
|||
|
||||
// Success!
|
||||
// set redirect_url session as admin area to go to after login
|
||||
session()->set('redirect_url', route_to('admin'));
|
||||
session()
|
||||
->set('redirect_url', route_to('admin'));
|
||||
|
||||
return redirect()
|
||||
->route('login')
|
||||
|
|
@ -345,8 +330,7 @@ class InstallController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* writes config values in .env file
|
||||
* overwrites any existing key and appends new ones
|
||||
* writes config values in .env file overwrites any existing key and appends new ones
|
||||
*
|
||||
* @param array<string, string> $configData key/value config pairs
|
||||
*/
|
||||
|
|
@ -357,20 +341,18 @@ class InstallController extends Controller
|
|||
foreach ($configData as $key => $value) {
|
||||
$replaced = false;
|
||||
$keyVal = $key . '="' . $value . '"' . PHP_EOL;
|
||||
$envData = array_map(function ($line) use (
|
||||
$key,
|
||||
$keyVal,
|
||||
&$replaced
|
||||
) {
|
||||
if (str_starts_with($line, (string) $key)) {
|
||||
$replaced = true;
|
||||
return $keyVal;
|
||||
}
|
||||
return $line;
|
||||
},
|
||||
$envData);
|
||||
$envData = array_map(
|
||||
function ($line) use ($key, $keyVal, &$replaced) {
|
||||
if (str_starts_with($line, (string) $key)) {
|
||||
$replaced = true;
|
||||
return $keyVal;
|
||||
}
|
||||
return $line;
|
||||
},
|
||||
$envData
|
||||
);
|
||||
|
||||
if (!$replaced) {
|
||||
if (! $replaced) {
|
||||
$envData[] = $keyVal;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ActivityPub\Controllers\NoteController as ActivityPubNoteController;
|
||||
use ActivityPub\Entities\Note as ActivityPubNote;
|
||||
use Analytics\AnalyticsTrait;
|
||||
|
|
@ -17,6 +16,7 @@ use App\Entities\Note as CastopodNote;
|
|||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
|
@ -26,6 +26,7 @@ class NoteController extends ActivityPubNoteController
|
|||
use AnalyticsTrait;
|
||||
|
||||
protected Podcast $podcast;
|
||||
|
||||
protected Actor $actor;
|
||||
|
||||
/**
|
||||
|
|
@ -36,9 +37,7 @@ class NoteController extends ActivityPubNoteController
|
|||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||
$params[0],
|
||||
)) === null
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName($params[0],)) === null
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
|
@ -47,20 +46,20 @@ class NoteController extends ActivityPubNoteController
|
|||
|
||||
if (
|
||||
count($params) > 1 &&
|
||||
!($this->note = model('NoteModel')->getNoteById($params[1]))
|
||||
! ($this->note = model('NoteModel')->getNoteById($params[1]))
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
unset($params[0]);
|
||||
unset($params[1]);
|
||||
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
public function view(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->podcast->id);
|
||||
}
|
||||
|
||||
|
|
@ -69,12 +68,13 @@ class NoteController extends ActivityPubNoteController
|
|||
array_filter([
|
||||
'page',
|
||||
"note#{$this->note->id}",
|
||||
service('request')->getLocale(),
|
||||
service('request')
|
||||
->getLocale(),
|
||||
can_user_interact() ? '_authenticated' : null,
|
||||
]),
|
||||
);
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'actor' => $this->actor,
|
||||
|
|
@ -102,7 +102,7 @@ class NoteController extends ActivityPubNoteController
|
|||
'episode_url' => 'valid_url|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -122,10 +122,7 @@ class NoteController extends ActivityPubNoteController
|
|||
if (
|
||||
$episodeUri &&
|
||||
($params = extract_params_from_episode_uri(new URI($episodeUri))) &&
|
||||
($episode = (new EpisodeModel())->getEpisodeBySlug(
|
||||
$params['podcastName'],
|
||||
$params['episodeSlug'],
|
||||
))
|
||||
($episode = (new EpisodeModel())->getEpisodeBySlug($params['podcastName'], $params['episodeSlug'],))
|
||||
) {
|
||||
$newNote->episode_id = $episode->id;
|
||||
}
|
||||
|
|
@ -133,11 +130,8 @@ class NoteController extends ActivityPubNoteController
|
|||
$newNote->message = $message;
|
||||
|
||||
if (
|
||||
!model('NoteModel')->addNote(
|
||||
$newNote,
|
||||
!(bool) $newNote->episode_id,
|
||||
true,
|
||||
)
|
||||
! model('NoteModel')
|
||||
->addNote($newNote, ! (bool) $newNote->episode_id, true,)
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -155,7 +149,7 @@ class NoteController extends ActivityPubNoteController
|
|||
'message' => 'required|max_length[500]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -170,7 +164,7 @@ class NoteController extends ActivityPubNoteController
|
|||
'created_by' => user_id(),
|
||||
]);
|
||||
|
||||
if (!model('NoteModel')->addReply($newNote)) {
|
||||
if (! model('NoteModel')->addReply($newNote)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -183,10 +177,7 @@ class NoteController extends ActivityPubNoteController
|
|||
|
||||
public function attemptFavourite(): RedirectResponse
|
||||
{
|
||||
model('FavouriteModel')->toggleFavourite(
|
||||
interact_as_actor(),
|
||||
$this->note,
|
||||
);
|
||||
model('FavouriteModel')->toggleFavourite(interact_as_actor(), $this->note,);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
@ -204,7 +195,7 @@ class NoteController extends ActivityPubNoteController
|
|||
'action' => 'required|in_list[favourite,reblog,reply]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -231,21 +222,16 @@ class NoteController extends ActivityPubNoteController
|
|||
public function remoteAction(string $action): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->podcast->id);
|
||||
}
|
||||
|
||||
$cacheName = implode(
|
||||
'_',
|
||||
array_filter([
|
||||
'page',
|
||||
"note#{$this->note->id}",
|
||||
"remote_{$action}",
|
||||
service('request')->getLocale(),
|
||||
]),
|
||||
array_filter(['page', "note#{$this->note->id}", "remote_{$action}", service('request') ->getLocale()]),
|
||||
);
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'actor' => $this->actor,
|
||||
|
|
|
|||
|
|
@ -9,25 +9,23 @@
|
|||
namespace App\Controllers;
|
||||
|
||||
use App\Entities\Page;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use App\Models\PageModel;
|
||||
use App\Models\CreditModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
|
||||
class PageController extends BaseController
|
||||
{
|
||||
protected ?Page $page;
|
||||
protected Page $page;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (count($params) === 0) {
|
||||
return $this->$method();
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
if (
|
||||
$this->page = (new PageModel())->where('slug', $params[0])->first()
|
||||
) {
|
||||
return $this->$method();
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -36,7 +34,7 @@ class PageController extends BaseController
|
|||
public function index(): string
|
||||
{
|
||||
$cacheName = "page-{$this->page->slug}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$data = [
|
||||
'page' => $this->page,
|
||||
];
|
||||
|
|
@ -44,167 +42,8 @@ class PageController extends BaseController
|
|||
$found = view('page', $data);
|
||||
|
||||
// The page cache is set to a decade so it is deleted manually upon page update
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function credits(): string
|
||||
{
|
||||
$locale = service('request')->getLocale();
|
||||
$allPodcasts = (new PodcastModel())->findAll();
|
||||
|
||||
$cacheName = "page_credits_{$locale}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$page = new Page([
|
||||
'title' => lang('Person.credits', [], $locale),
|
||||
'slug' => 'credits',
|
||||
'content_markdown' => '',
|
||||
]);
|
||||
|
||||
$allCredits = (new CreditModel())->findAll();
|
||||
|
||||
// Unlike the carpenter, we make a tree from a table:
|
||||
$personGroup = null;
|
||||
$personId = null;
|
||||
$personRole = null;
|
||||
$credits = [];
|
||||
foreach ($allCredits as $credit) {
|
||||
if ($personGroup !== $credit->person_group) {
|
||||
$personGroup = $credit->person_group;
|
||||
$personId = $credit->person_id;
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup] = [
|
||||
'group_label' => $credit->group_label,
|
||||
'persons' => [
|
||||
$personId => [
|
||||
'full_name' => $credit->person->full_name,
|
||||
'thumbnail_url' =>
|
||||
$credit->person->image->thumbnail_url,
|
||||
'information_url' =>
|
||||
$credit->person->information_url,
|
||||
'roles' => [
|
||||
$personRole => [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode
|
||||
->title .
|
||||
episode_numbering(
|
||||
$credit->episode
|
||||
->number,
|
||||
$credit->episode
|
||||
->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
} elseif ($personId !== $credit->person_id) {
|
||||
$personId = $credit->person_id;
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup]['persons'][$personId] = [
|
||||
'full_name' => $credit->person->full_name,
|
||||
'thumbnail_url' =>
|
||||
$credit->person->image->thumbnail_url,
|
||||
'information_url' => $credit->person->information_url,
|
||||
'roles' => [
|
||||
$personRole => [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
$credit->episode->number,
|
||||
$credit->episode
|
||||
->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
} elseif ($personRole !== $credit->person_role) {
|
||||
$personRole = $credit->person_role;
|
||||
$credits[$personGroup]['persons'][$personId]['roles'][
|
||||
$personRole
|
||||
] = [
|
||||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
$credit->episode->number,
|
||||
$credit->episode->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
],
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$credits[$personGroup]['persons'][$personId]['roles'][
|
||||
$personRole
|
||||
]['is_in'][] = [
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$credit->podcast->title} › "
|
||||
: '') .
|
||||
$credit->episode->title .
|
||||
episode_numbering(
|
||||
$credit->episode->number,
|
||||
$credit->episode->season_number,
|
||||
'text-xs ml-2',
|
||||
true,
|
||||
)
|
||||
: $credit->podcast->title,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'page' => $page,
|
||||
'credits' => $credits,
|
||||
];
|
||||
|
||||
$found = view('credits', $data);
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use App\Models\PlatformModel;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
|
||||
/*
|
||||
* Provide public access to all platforms so that they can be exported
|
||||
|
|
|
|||
|
|
@ -8,20 +8,17 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Analytics\AnalyticsTrait;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\NoteModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
|
||||
class PodcastController extends BaseController
|
||||
{
|
||||
use AnalyticsTrait;
|
||||
|
||||
/**
|
||||
* @var Podcast
|
||||
*/
|
||||
protected Podcast $podcast;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
|
|
@ -31,12 +28,10 @@ class PodcastController extends BaseController
|
|||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||
$params[0],
|
||||
)) !== null
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName($params[0],)) !== null
|
||||
) {
|
||||
unset($params[0]);
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -45,7 +40,7 @@ class PodcastController extends BaseController
|
|||
public function activity(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->podcast->id);
|
||||
}
|
||||
|
||||
|
|
@ -55,17 +50,16 @@ class PodcastController extends BaseController
|
|||
'page',
|
||||
"podcast#{$this->podcast->id}",
|
||||
'activity',
|
||||
service('request')->getLocale(),
|
||||
service('request')
|
||||
->getLocale(),
|
||||
can_user_interact() ? '_authenticated' : null,
|
||||
]),
|
||||
);
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'notes' => (new NoteModel())->getActorPublishedNotes(
|
||||
$this->podcast->actor_id,
|
||||
),
|
||||
'notes' => (new NoteModel())->getActorPublishedNotes($this->podcast->actor_id,),
|
||||
];
|
||||
|
||||
// if user is logged in then send to the authenticated activity view
|
||||
|
|
@ -85,21 +79,19 @@ class PodcastController extends BaseController
|
|||
public function episodes(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->podcast->id);
|
||||
}
|
||||
|
||||
$yearQuery = $this->request->getGet('year');
|
||||
$seasonQuery = $this->request->getGet('season');
|
||||
|
||||
if (!$yearQuery && !$seasonQuery) {
|
||||
$defaultQuery = (new PodcastModel())->getDefaultQuery(
|
||||
$this->podcast->id,
|
||||
);
|
||||
if (! $yearQuery && ! $seasonQuery) {
|
||||
$defaultQuery = (new PodcastModel())->getDefaultQuery($this->podcast->id,);
|
||||
if ($defaultQuery) {
|
||||
if ($defaultQuery['type'] == 'season') {
|
||||
if ($defaultQuery['type'] === 'season') {
|
||||
$seasonQuery = $defaultQuery['data']['season_number'];
|
||||
} elseif ($defaultQuery['type'] == 'year') {
|
||||
} elseif ($defaultQuery['type'] === 'year') {
|
||||
$yearQuery = $defaultQuery['data']['year'];
|
||||
}
|
||||
}
|
||||
|
|
@ -113,12 +105,13 @@ class PodcastController extends BaseController
|
|||
'episodes',
|
||||
$yearQuery ? 'year' . $yearQuery : null,
|
||||
$seasonQuery ? 'season' . $seasonQuery : null,
|
||||
service('request')->getLocale(),
|
||||
service('request')
|
||||
->getLocale(),
|
||||
can_user_interact() ? '_authenticated' : null,
|
||||
]),
|
||||
);
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
// Build navigation array
|
||||
$podcastModel = new PodcastModel();
|
||||
$years = $podcastModel->getYears($this->podcast->id);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAddPodcastsPlatforms
|
||||
* Creates podcasts_platforms table in database
|
||||
* Class AddAddPodcastsPlatforms Creates podcasts_platforms table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddCategories
|
||||
* Creates categories table in database
|
||||
* Class AddCategories Creates categories table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddLanguages
|
||||
* Creates languages table in database
|
||||
* Class AddLanguages Creates languages table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPodcasts
|
||||
* Creates podcasts table in database
|
||||
* Class AddPodcasts Creates podcasts table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -190,13 +189,7 @@ class AddPodcasts extends Migration
|
|||
// TODO: remove name in favor of username from actor
|
||||
$this->forge->addUniqueKey('name');
|
||||
$this->forge->addUniqueKey('actor_id');
|
||||
$this->forge->addForeignKey(
|
||||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('category_id', 'categories', 'id');
|
||||
$this->forge->addForeignKey('language_code', 'languages', 'code');
|
||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddEpisodes
|
||||
* Creates episodes table in database
|
||||
* Class AddEpisodes Creates episodes table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -186,13 +185,7 @@ class AddEpisodes extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addUniqueKey(['podcast_id', 'slug']);
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||
$this->forge->addForeignKey('updated_by', 'users', 'id');
|
||||
$this->forge->createTable('episodes');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddSoundbites
|
||||
* Creates soundbites table in database
|
||||
* Class AddSoundbites Creates soundbites table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -64,20 +63,8 @@ class AddSoundbites extends Migration
|
|||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['episode_id', 'start_time', 'duration']);
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'episode_id',
|
||||
'episodes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||
$this->forge->addForeignKey('updated_by', 'users', 'id');
|
||||
$this->forge->createTable('soundbites');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPlatforms
|
||||
* Creates platforms table in database
|
||||
* Class AddPlatforms Creates platforms table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -42,9 +41,7 @@ class AddPlatforms extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT NOW()');
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT NOW() ON UPDATE NOW()',
|
||||
);
|
||||
$this->forge->addField('`updated_at` timestamp NOT NULL DEFAULT NOW() ON UPDATE NOW()',);
|
||||
$this->forge->addPrimaryKey('slug');
|
||||
$this->forge->createTable('platforms');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPodcastUsers
|
||||
* Creates podcast_users table in database
|
||||
* Class AddPodcastUsers Creates podcast_users table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -33,20 +32,8 @@ class AddPodcastsUsers extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['user_id', 'podcast_id']);
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', '', 'CASCADE');
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'group_id',
|
||||
'auth_groups',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('group_id', 'auth_groups', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('podcasts_users');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPages
|
||||
* Creates pages table in database
|
||||
* Class AddPages Creates pages table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPodcastsCategories
|
||||
* Creates podcasts_categories table in database
|
||||
* Class AddPodcastsCategories Creates podcasts_categories table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -28,20 +27,8 @@ class AddPodcastsCategories extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'category_id']);
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'category_id',
|
||||
'categories',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('category_id', 'categories', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('podcasts_categories');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class Persons
|
||||
* Creates persons table in database
|
||||
* Class Persons Creates persons table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPodcastsPersons
|
||||
* Creates podcasts_persons table in database
|
||||
* Class AddPodcastsPersons Creates podcasts_persons table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -41,26 +40,9 @@ class AddPodcastsPersons extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey([
|
||||
'podcast_id',
|
||||
'person_id',
|
||||
'person_group',
|
||||
'person_role',
|
||||
]);
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'person_id',
|
||||
'persons',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addUniqueKey(['podcast_id', 'person_id', 'person_group', 'person_role']);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('person_id', 'persons', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('podcasts_persons');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddEpisodesPersons
|
||||
* Creates episodes_persons table in database
|
||||
* Class AddEpisodesPersons Creates episodes_persons table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -45,34 +44,10 @@ class AddEpisodesPersons extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addUniqueKey([
|
||||
'podcast_id',
|
||||
'episode_id',
|
||||
'person_id',
|
||||
'person_group',
|
||||
'person_role',
|
||||
]);
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'episode_id',
|
||||
'episodes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'person_id',
|
||||
'persons',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addUniqueKey(['podcast_id', 'episode_id', 'person_id', 'person_group', 'person_role']);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('person_id', 'persons', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('episodes_persons');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddCreditView
|
||||
* Creates Credit View in database
|
||||
* Class AddCreditView Creates Credit View in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -22,7 +22,7 @@ class AddCreditView extends Migration
|
|||
$podcastPersonsTable = $this->db->prefixTable('podcasts_persons');
|
||||
$episodePersonsTable = $this->db->prefixTable('episodes_persons');
|
||||
$episodesTable = $this->db->prefixTable('episodes');
|
||||
$createQuery = <<<EOD
|
||||
$createQuery = <<<CODE_SAMPLE
|
||||
CREATE VIEW `{$viewName}` AS
|
||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, NULL AS `episode_id` FROM `{$podcastPersonsTable}`
|
||||
INNER JOIN `{$personsTable}`
|
||||
|
|
@ -35,7 +35,7 @@ class AddCreditView extends Migration
|
|||
ON (`episode_id`=`{$episodesTable}`.`id`)
|
||||
WHERE `{$episodesTable}`.published_at <= NOW()
|
||||
ORDER BY `person_group`, `full_name`, `person_role`, `podcast_id`, `episode_id`;
|
||||
EOD;
|
||||
CODE_SAMPLE;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddEpisodeIdToNotes
|
||||
* Adds episode_id field to activitypub_notes table in database
|
||||
* Class AddEpisodeIdToNotes Adds episode_id field to activitypub_notes table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -19,20 +18,17 @@ class AddEpisodeIdToNotes extends Migration
|
|||
{
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
$createQuery = <<<SQL
|
||||
$createQuery = <<<CODE_SAMPLE
|
||||
ALTER TABLE {$prefix}activitypub_notes
|
||||
ADD COLUMN `episode_id` INT UNSIGNED NULL AFTER `replies_count`,
|
||||
ADD FOREIGN KEY {$prefix}activitypub_notes_episode_id_foreign(episode_id) REFERENCES {$prefix}episodes(id) ON DELETE CASCADE;
|
||||
SQL;
|
||||
CODE_SAMPLE;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropForeignKey(
|
||||
'activitypub_notes',
|
||||
'activitypub_notes_episode_id_foreign',
|
||||
);
|
||||
$this->forge->dropForeignKey('activitypub_notes', 'activitypub_notes_episode_id_foreign',);
|
||||
$this->forge->dropColumn('activitypub_notes', 'episode_id');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddCreatedByToNotes
|
||||
* Adds created_by field to activitypub_notes table in database
|
||||
* Class AddCreatedByToNotes Adds created_by field to activitypub_notes table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -19,20 +18,17 @@ class AddCreatedByToNotes extends Migration
|
|||
{
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
$createQuery = <<<SQL
|
||||
$createQuery = <<<CODE_SAMPLE
|
||||
ALTER TABLE {$prefix}activitypub_notes
|
||||
ADD COLUMN `created_by` INT UNSIGNED AFTER `episode_id`,
|
||||
ADD FOREIGN KEY {$prefix}activitypub_notes_created_by_foreign(created_by) REFERENCES {$prefix}users(id) ON DELETE CASCADE;
|
||||
SQL;
|
||||
CODE_SAMPLE;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropForeignKey(
|
||||
'activitypub_notes',
|
||||
'activitypub_notes_created_by_foreign',
|
||||
);
|
||||
$this->forge->dropForeignKey('activitypub_notes', 'activitypub_notes_created_by_foreign',);
|
||||
$this->forge->dropColumn('activitypub_notes', 'created_by');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AppSeeder
|
||||
* Calls all required seeders for castopod to work properly
|
||||
* Class AppSeeder Calls all required seeders for castopod to work properly
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class PermissionSeeder
|
||||
* Inserts permissions
|
||||
* Class PermissionSeeder Inserts permissions
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -31,15 +30,10 @@ class AuthSeeder extends Seeder
|
|||
],
|
||||
];
|
||||
|
||||
/** Build permissions array as a list of:
|
||||
/**
|
||||
* Build permissions array as a list of:
|
||||
*
|
||||
* ```
|
||||
* context => [
|
||||
* [action, description],
|
||||
* [action, description],
|
||||
* ...
|
||||
* ]
|
||||
* ```
|
||||
* ``` context => [ [action, description], [action, description], ... ] ```
|
||||
*
|
||||
* @var array<string, array<string, string|array>[]>
|
||||
*/
|
||||
|
|
@ -281,10 +275,7 @@ class AuthSeeder extends Seeder
|
|||
foreach ($action['has_permission'] as $role) {
|
||||
// link permission to specified groups
|
||||
$dataGroupsPermissions[] = [
|
||||
'group_id' => $this->getGroupIdByName(
|
||||
$role,
|
||||
$dataGroups,
|
||||
),
|
||||
'group_id' => $this->getGroupIdByName($role, $dataGroups,),
|
||||
'permission_id' => $permissionId,
|
||||
];
|
||||
}
|
||||
|
|
@ -304,10 +295,11 @@ class AuthSeeder extends Seeder
|
|||
->ignore(true)
|
||||
->insertBatch($dataGroupsPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|int>[] $dataGroups
|
||||
*/
|
||||
static function getGroupIdByName(string $name, array $dataGroups): ?int
|
||||
public static function getGroupIdByName(string $name, array $dataGroups): ?int
|
||||
{
|
||||
foreach ($dataGroups as $group) {
|
||||
if ($group['name'] === $name) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class CategorySeeder
|
||||
* Inserts values in categories table in database
|
||||
* Class CategorySeeder Inserts values in categories table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class FakePodcastsAnalyticsSeeder
|
||||
* Inserts Fake Analytics in the database
|
||||
* Class FakePodcastsAnalyticsSeeder Inserts Fake Analytics in the database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -11,12 +10,12 @@
|
|||
|
||||
namespace App\Database\Seeds;
|
||||
|
||||
use GeoIp2\Database\Reader;
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\EpisodeModel;
|
||||
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Database\Seeder;
|
||||
use GeoIp2\Database\Reader;
|
||||
|
||||
use GeoIp2\Exception\AddressNotFoundException;
|
||||
|
||||
class FakePodcastsAnalyticsSeeder extends Seeder
|
||||
{
|
||||
|
|
@ -25,9 +24,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
|||
$podcast = (new PodcastModel())->first();
|
||||
|
||||
$jsonUserAgents = json_decode(
|
||||
file_get_contents(
|
||||
'https://raw.githubusercontent.com/opawg/user-agents/master/src/user-agents.json',
|
||||
),
|
||||
file_get_contents('https://raw.githubusercontent.com/opawg/user-agents/master/src/user-agents.json',),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
|
|
@ -66,9 +63,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
|||
])
|
||||
->findAll();
|
||||
foreach ($episodes as $episode) {
|
||||
$age = floor(
|
||||
($date - strtotime($episode->published_at)) / 86400,
|
||||
);
|
||||
$age = floor(($date - strtotime($episode->published_at)) / 86400,);
|
||||
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
|
||||
|
||||
for (
|
||||
|
|
@ -102,10 +97,7 @@ class FakePodcastsAnalyticsSeeder extends Seeder
|
|||
'.' .
|
||||
rand(0, 255);
|
||||
|
||||
$cityReader = new Reader(
|
||||
WRITEPATH .
|
||||
'uploads/GeoLite2-City/GeoLite2-City.mmdb',
|
||||
);
|
||||
$cityReader = new Reader(WRITEPATH . 'uploads/GeoLite2-City/GeoLite2-City.mmdb',);
|
||||
|
||||
$countryCode = 'N/A';
|
||||
$regionCode = 'N/A';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class FakeWebsiteAnalyticsSeeder
|
||||
* Inserts Fake Analytics in the database
|
||||
* Class FakeWebsiteAnalyticsSeeder Inserts Fake Analytics in the database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -11,8 +10,8 @@
|
|||
|
||||
namespace App\Database\Seeds;
|
||||
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
|
||||
use CodeIgniter\Database\Seeder;
|
||||
|
||||
|
|
@ -203,9 +202,7 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
|
|||
])
|
||||
->findAll();
|
||||
foreach ($episodes as $episode) {
|
||||
$age = floor(
|
||||
($date - strtotime($episode->published_at)) / 86400,
|
||||
);
|
||||
$age = floor(($date - strtotime($episode->published_at)) / 86400,);
|
||||
$probability1 = (int) floor(exp(3 - $age / 40)) + 1;
|
||||
|
||||
for (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class LanguageSeeder
|
||||
* Inserts values in languages table in database
|
||||
* Class LanguageSeeder Inserts values in languages table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -10,8 +9,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* From https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
* (cc) Creative Commons Attribution-ShareAlike 3.0
|
||||
* From https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes (cc) Creative Commons Attribution-ShareAlike 3.0
|
||||
* 2020-06-07
|
||||
*/
|
||||
|
||||
|
|
@ -24,29 +22,50 @@ class LanguageSeeder extends Seeder
|
|||
public function run(): void
|
||||
{
|
||||
$data = [
|
||||
['code' => 'aa', 'native_name' => 'Afaraf'],
|
||||
[
|
||||
'code' => 'aa',
|
||||
'native_name' => 'Afaraf',
|
||||
],
|
||||
[
|
||||
'code' => 'ab',
|
||||
'native_name' => 'аҧсуа бызшәа, аҧсшәа',
|
||||
],
|
||||
['code' => 'ae', 'native_name' => 'avesta'],
|
||||
[
|
||||
'code' => 'ae',
|
||||
'native_name' => 'avesta',
|
||||
],
|
||||
[
|
||||
'code' => 'af',
|
||||
'native_name' => 'Afrikaans',
|
||||
],
|
||||
['code' => 'ak', 'native_name' => 'Akan'],
|
||||
['code' => 'am', 'native_name' => 'አማርኛ'],
|
||||
[
|
||||
'code' => 'ak',
|
||||
'native_name' => 'Akan',
|
||||
],
|
||||
[
|
||||
'code' => 'am',
|
||||
'native_name' => 'አማርኛ',
|
||||
],
|
||||
[
|
||||
'code' => 'an',
|
||||
'native_name' => 'aragonés',
|
||||
],
|
||||
['code' => 'ar', 'native_name' => 'العربية'],
|
||||
['code' => 'as', 'native_name' => 'অসমীয়া'],
|
||||
[
|
||||
'code' => 'ar',
|
||||
'native_name' => 'العربية',
|
||||
],
|
||||
[
|
||||
'code' => 'as',
|
||||
'native_name' => 'অসমীয়া',
|
||||
],
|
||||
[
|
||||
'code' => 'av',
|
||||
'native_name' => 'авар мацӀ, магӀарул мацӀ',
|
||||
],
|
||||
['code' => 'ay', 'native_name' => 'aymar aru'],
|
||||
[
|
||||
'code' => 'ay',
|
||||
'native_name' => 'aymar aru',
|
||||
],
|
||||
[
|
||||
'code' => 'az',
|
||||
'native_name' => 'azərbaycan dili',
|
||||
|
|
@ -67,14 +86,26 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'bh',
|
||||
'native_name' => 'भोजपुरी',
|
||||
],
|
||||
['code' => 'bi', 'native_name' => 'Bislama'],
|
||||
[
|
||||
'code' => 'bi',
|
||||
'native_name' => 'Bislama',
|
||||
],
|
||||
[
|
||||
'code' => 'bm',
|
||||
'native_name' => 'bamanankan',
|
||||
],
|
||||
['code' => 'bn', 'native_name' => 'বাংলা'],
|
||||
['code' => 'bo', 'native_name' => 'བོད་ཡིག'],
|
||||
['code' => 'br', 'native_name' => 'brezhoneg'],
|
||||
[
|
||||
'code' => 'bn',
|
||||
'native_name' => 'বাংলা',
|
||||
],
|
||||
[
|
||||
'code' => 'bo',
|
||||
'native_name' => 'བོད་ཡིག',
|
||||
],
|
||||
[
|
||||
'code' => 'br',
|
||||
'native_name' => 'brezhoneg',
|
||||
],
|
||||
[
|
||||
'code' => 'bs',
|
||||
'native_name' => 'bosanski jezik',
|
||||
|
|
@ -87,12 +118,18 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'ce',
|
||||
'native_name' => 'нохчийн мотт',
|
||||
],
|
||||
['code' => 'ch', 'native_name' => 'Chamoru'],
|
||||
[
|
||||
'code' => 'ch',
|
||||
'native_name' => 'Chamoru',
|
||||
],
|
||||
[
|
||||
'code' => 'co',
|
||||
'native_name' => 'corsu, lingua corsa',
|
||||
],
|
||||
['code' => 'cr', 'native_name' => 'ᓀᐦᐃᔭᐍᐏᐣ'],
|
||||
[
|
||||
'code' => 'cr',
|
||||
'native_name' => 'ᓀᐦᐃᔭᐍᐏᐣ',
|
||||
],
|
||||
[
|
||||
'code' => 'cs',
|
||||
'native_name' => 'čeština, český jazyk',
|
||||
|
|
@ -105,20 +142,38 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'cv',
|
||||
'native_name' => 'чӑваш чӗлхи',
|
||||
],
|
||||
['code' => 'cy', 'native_name' => 'Cymraeg'],
|
||||
['code' => 'da', 'native_name' => 'dansk'],
|
||||
['code' => 'de', 'native_name' => 'Deutsch'],
|
||||
[
|
||||
'code' => 'cy',
|
||||
'native_name' => 'Cymraeg',
|
||||
],
|
||||
[
|
||||
'code' => 'da',
|
||||
'native_name' => 'dansk',
|
||||
],
|
||||
[
|
||||
'code' => 'de',
|
||||
'native_name' => 'Deutsch',
|
||||
],
|
||||
[
|
||||
'code' => 'dv',
|
||||
'native_name' => 'ދިވެހި',
|
||||
],
|
||||
['code' => 'dz', 'native_name' => 'རྫོང་ཁ'],
|
||||
['code' => 'ee', 'native_name' => 'Eʋegbe'],
|
||||
[
|
||||
'code' => 'dz',
|
||||
'native_name' => 'རྫོང་ཁ',
|
||||
],
|
||||
[
|
||||
'code' => 'ee',
|
||||
'native_name' => 'Eʋegbe',
|
||||
],
|
||||
[
|
||||
'code' => 'el',
|
||||
'native_name' => 'ελληνικά',
|
||||
],
|
||||
['code' => 'en', 'native_name' => 'English'],
|
||||
[
|
||||
'code' => 'en',
|
||||
'native_name' => 'English',
|
||||
],
|
||||
[
|
||||
'code' => 'eo',
|
||||
'native_name' => 'Esperanto',
|
||||
|
|
@ -135,7 +190,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'eu',
|
||||
'native_name' => 'euskara, euskera',
|
||||
],
|
||||
['code' => 'fa', 'native_name' => 'فارسی'],
|
||||
[
|
||||
'code' => 'fa',
|
||||
'native_name' => 'فارسی',
|
||||
],
|
||||
[
|
||||
'code' => 'ff',
|
||||
'native_name' => 'Fulfulde, Pulaar, Pular',
|
||||
|
|
@ -148,7 +206,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'fj',
|
||||
'native_name' => 'vosa Vakaviti',
|
||||
],
|
||||
['code' => 'fo', 'native_name' => 'føroyskt'],
|
||||
[
|
||||
'code' => 'fo',
|
||||
'native_name' => 'føroyskt',
|
||||
],
|
||||
[
|
||||
'code' => 'fr',
|
||||
'native_name' => 'français, langue française',
|
||||
|
|
@ -157,14 +218,26 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'fy',
|
||||
'native_name' => 'Frysk',
|
||||
],
|
||||
['code' => 'ga', 'native_name' => 'Gaeilge'],
|
||||
[
|
||||
'code' => 'ga',
|
||||
'native_name' => 'Gaeilge',
|
||||
],
|
||||
[
|
||||
'code' => 'gd',
|
||||
'native_name' => 'Gàidhlig',
|
||||
],
|
||||
['code' => 'gl', 'native_name' => 'Galego'],
|
||||
['code' => 'gn', 'native_name' => "Avañe'ẽ"],
|
||||
['code' => 'gu', 'native_name' => 'ગુજરાતી'],
|
||||
[
|
||||
'code' => 'gl',
|
||||
'native_name' => 'Galego',
|
||||
],
|
||||
[
|
||||
'code' => 'gn',
|
||||
'native_name' => "Avañe'ẽ",
|
||||
],
|
||||
[
|
||||
'code' => 'gu',
|
||||
'native_name' => 'ગુજરાતી',
|
||||
],
|
||||
[
|
||||
'code' => 'gv',
|
||||
'native_name' => 'Gaelg, Gailck',
|
||||
|
|
@ -173,7 +246,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'ha',
|
||||
'native_name' => '(Hausa) هَوُسَ',
|
||||
],
|
||||
['code' => 'he', 'native_name' => 'עברית'],
|
||||
[
|
||||
'code' => 'he',
|
||||
'native_name' => 'עברית',
|
||||
],
|
||||
[
|
||||
'code' => 'hi',
|
||||
'native_name' => 'हिन्दी, हिंदी',
|
||||
|
|
@ -190,9 +266,18 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'ht',
|
||||
'native_name' => 'Kreyòl ayisyen',
|
||||
],
|
||||
['code' => 'hu', 'native_name' => 'magyar'],
|
||||
['code' => 'hy', 'native_name' => 'Հայերեն'],
|
||||
['code' => 'hz', 'native_name' => 'Otjiherero'],
|
||||
[
|
||||
'code' => 'hu',
|
||||
'native_name' => 'magyar',
|
||||
],
|
||||
[
|
||||
'code' => 'hy',
|
||||
'native_name' => 'Հայերեն',
|
||||
],
|
||||
[
|
||||
'code' => 'hz',
|
||||
'native_name' => 'Otjiherero',
|
||||
],
|
||||
[
|
||||
'code' => 'ia',
|
||||
'native_name' => 'Interlingua',
|
||||
|
|
@ -206,7 +291,10 @@ class LanguageSeeder extends Seeder
|
|||
'native_name' =>
|
||||
'(originally:) Occidental, (after WWII:) Interlingue',
|
||||
],
|
||||
['code' => 'ig', 'native_name' => 'Asụsụ Igbo'],
|
||||
[
|
||||
'code' => 'ig',
|
||||
'native_name' => 'Asụsụ Igbo',
|
||||
],
|
||||
[
|
||||
'code' => 'ii',
|
||||
'native_name' => 'ꆈꌠ꒿ Nuosuhxop',
|
||||
|
|
@ -215,13 +303,22 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'ik',
|
||||
'native_name' => 'Iñupiaq, Iñupiatun',
|
||||
],
|
||||
['code' => 'io', 'native_name' => 'Ido'],
|
||||
[
|
||||
'code' => 'io',
|
||||
'native_name' => 'Ido',
|
||||
],
|
||||
[
|
||||
'code' => 'is',
|
||||
'native_name' => 'Íslenska',
|
||||
],
|
||||
['code' => 'it', 'native_name' => 'Italiano'],
|
||||
['code' => 'iu', 'native_name' => 'ᐃᓄᒃᑎᑐᑦ'],
|
||||
[
|
||||
'code' => 'it',
|
||||
'native_name' => 'Italiano',
|
||||
],
|
||||
[
|
||||
'code' => 'iu',
|
||||
'native_name' => 'ᐃᓄᒃᑎᑐᑦ',
|
||||
],
|
||||
[
|
||||
'code' => 'ja',
|
||||
'native_name' => '日本語 (にほんご)',
|
||||
|
|
@ -230,8 +327,14 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'jv',
|
||||
'native_name' => 'ꦧꦱꦗꦮ, Basa Jawa',
|
||||
],
|
||||
['code' => 'ka', 'native_name' => 'ქართული'],
|
||||
['code' => 'kg', 'native_name' => 'Kikongo'],
|
||||
[
|
||||
'code' => 'ka',
|
||||
'native_name' => 'ქართული',
|
||||
],
|
||||
[
|
||||
'code' => 'kg',
|
||||
'native_name' => 'Kikongo',
|
||||
],
|
||||
[
|
||||
'code' => 'ki',
|
||||
'native_name' => 'Gĩkũyũ',
|
||||
|
|
@ -240,7 +343,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'kj',
|
||||
'native_name' => 'Kuanyama',
|
||||
],
|
||||
['code' => 'kk', 'native_name' => 'қазақ тілі'],
|
||||
[
|
||||
'code' => 'kk',
|
||||
'native_name' => 'қазақ тілі',
|
||||
],
|
||||
[
|
||||
'code' => 'kl',
|
||||
'native_name' => 'kalaallisut, kalaallit oqaasii',
|
||||
|
|
@ -249,9 +355,18 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'km',
|
||||
'native_name' => 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ',
|
||||
],
|
||||
['code' => 'kn', 'native_name' => 'ಕನ್ನಡ'],
|
||||
['code' => 'ko', 'native_name' => '한국어'],
|
||||
['code' => 'kr', 'native_name' => 'Kanuri'],
|
||||
[
|
||||
'code' => 'kn',
|
||||
'native_name' => 'ಕನ್ನಡ',
|
||||
],
|
||||
[
|
||||
'code' => 'ko',
|
||||
'native_name' => '한국어',
|
||||
],
|
||||
[
|
||||
'code' => 'kr',
|
||||
'native_name' => 'Kanuri',
|
||||
],
|
||||
[
|
||||
'code' => 'ks',
|
||||
'native_name' => 'कश्मीरी, كشميري',
|
||||
|
|
@ -260,8 +375,14 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'ku',
|
||||
'native_name' => 'Kurdî, کوردی',
|
||||
],
|
||||
['code' => 'kv', 'native_name' => 'коми кыв'],
|
||||
['code' => 'kw', 'native_name' => 'Kernewek'],
|
||||
[
|
||||
'code' => 'kv',
|
||||
'native_name' => 'коми кыв',
|
||||
],
|
||||
[
|
||||
'code' => 'kw',
|
||||
'native_name' => 'Kernewek',
|
||||
],
|
||||
[
|
||||
'code' => 'ky',
|
||||
'native_name' => 'Кыргызча, Кыргыз тили',
|
||||
|
|
@ -274,13 +395,22 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'lb',
|
||||
'native_name' => 'Lëtzebuergesch',
|
||||
],
|
||||
['code' => 'lg', 'native_name' => 'Luganda'],
|
||||
[
|
||||
'code' => 'lg',
|
||||
'native_name' => 'Luganda',
|
||||
],
|
||||
[
|
||||
'code' => 'li',
|
||||
'native_name' => 'Limburgs',
|
||||
],
|
||||
['code' => 'ln', 'native_name' => 'Lingála'],
|
||||
['code' => 'lo', 'native_name' => 'ພາສາລາວ'],
|
||||
[
|
||||
'code' => 'ln',
|
||||
'native_name' => 'Lingála',
|
||||
],
|
||||
[
|
||||
'code' => 'lo',
|
||||
'native_name' => 'ພາສາລາວ',
|
||||
],
|
||||
[
|
||||
'code' => 'lt',
|
||||
'native_name' => 'lietuvių kalba',
|
||||
|
|
@ -309,18 +439,30 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'mk',
|
||||
'native_name' => 'македонски јазик',
|
||||
],
|
||||
['code' => 'ml', 'native_name' => 'മലയാളം'],
|
||||
[
|
||||
'code' => 'ml',
|
||||
'native_name' => 'മലയാളം',
|
||||
],
|
||||
[
|
||||
'code' => 'mn',
|
||||
'native_name' => 'Монгол хэл',
|
||||
],
|
||||
['code' => 'mr', 'native_name' => 'मराठी'],
|
||||
[
|
||||
'code' => 'mr',
|
||||
'native_name' => 'मराठी',
|
||||
],
|
||||
[
|
||||
'code' => 'ms',
|
||||
'native_name' => 'Bahasa Melayu, بهاس ملايو',
|
||||
],
|
||||
['code' => 'mt', 'native_name' => 'Malti'],
|
||||
['code' => 'my', 'native_name' => 'ဗမာစာ'],
|
||||
[
|
||||
'code' => 'mt',
|
||||
'native_name' => 'Malti',
|
||||
],
|
||||
[
|
||||
'code' => 'my',
|
||||
'native_name' => 'ဗမာစာ',
|
||||
],
|
||||
[
|
||||
'code' => 'na',
|
||||
'native_name' => 'Dorerin Naoero',
|
||||
|
|
@ -333,8 +475,14 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'nd',
|
||||
'native_name' => 'isiNdebele',
|
||||
],
|
||||
['code' => 'ne', 'native_name' => 'नेपाली'],
|
||||
['code' => 'ng', 'native_name' => 'Owambo'],
|
||||
[
|
||||
'code' => 'ne',
|
||||
'native_name' => 'नेपाली',
|
||||
],
|
||||
[
|
||||
'code' => 'ng',
|
||||
'native_name' => 'Owambo',
|
||||
],
|
||||
[
|
||||
'code' => 'nl',
|
||||
'native_name' => 'Nederlands, Vlaams',
|
||||
|
|
@ -343,7 +491,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'nn',
|
||||
'native_name' => 'Norsk Nynorsk',
|
||||
],
|
||||
['code' => 'no', 'native_name' => 'Norsk'],
|
||||
[
|
||||
'code' => 'no',
|
||||
'native_name' => 'Norsk',
|
||||
],
|
||||
[
|
||||
'code' => 'nr',
|
||||
'native_name' => 'isiNdebele',
|
||||
|
|
@ -360,12 +511,18 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'oc',
|
||||
'native_name' => 'occitan, lenga d’òc',
|
||||
],
|
||||
['code' => 'oj', 'native_name' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ'],
|
||||
[
|
||||
'code' => 'oj',
|
||||
'native_name' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ',
|
||||
],
|
||||
[
|
||||
'code' => 'om',
|
||||
'native_name' => 'Afaan Oromoo',
|
||||
],
|
||||
['code' => 'or', 'native_name' => 'ଓଡ଼ିଆ'],
|
||||
[
|
||||
'code' => 'or',
|
||||
'native_name' => 'ଓଡ଼ିଆ',
|
||||
],
|
||||
[
|
||||
'code' => 'os',
|
||||
'native_name' => 'ирон æвзаг',
|
||||
|
|
@ -374,7 +531,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'pa',
|
||||
'native_name' => 'ਪੰਜਾਬੀ, پنجابی',
|
||||
],
|
||||
['code' => 'pi', 'native_name' => 'पालि, पाळि'],
|
||||
[
|
||||
'code' => 'pi',
|
||||
'native_name' => 'पालि, पाळि',
|
||||
],
|
||||
[
|
||||
'code' => 'pl',
|
||||
'native_name' => 'język polski, polszczyzna',
|
||||
|
|
@ -395,12 +555,18 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'rm',
|
||||
'native_name' => 'Rumantsch Grischun',
|
||||
],
|
||||
['code' => 'rn', 'native_name' => 'Ikirundi'],
|
||||
[
|
||||
'code' => 'rn',
|
||||
'native_name' => 'Ikirundi',
|
||||
],
|
||||
[
|
||||
'code' => 'ro',
|
||||
'native_name' => 'Română',
|
||||
],
|
||||
['code' => 'ru', 'native_name' => 'русский'],
|
||||
[
|
||||
'code' => 'ru',
|
||||
'native_name' => 'русский',
|
||||
],
|
||||
[
|
||||
'code' => 'rw',
|
||||
'native_name' => 'Ikinyarwanda',
|
||||
|
|
@ -409,7 +575,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'sa',
|
||||
'native_name' => 'संस्कृतम्',
|
||||
],
|
||||
['code' => 'sc', 'native_name' => 'sardu'],
|
||||
[
|
||||
'code' => 'sc',
|
||||
'native_name' => 'sardu',
|
||||
],
|
||||
[
|
||||
'code' => 'sd',
|
||||
'native_name' => 'सिन्धी, سنڌي، سندھی',
|
||||
|
|
@ -438,17 +607,26 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'sm',
|
||||
'native_name' => "gagana fa'a Samoa",
|
||||
],
|
||||
['code' => 'sn', 'native_name' => 'chiShona'],
|
||||
[
|
||||
'code' => 'sn',
|
||||
'native_name' => 'chiShona',
|
||||
],
|
||||
[
|
||||
'code' => 'so',
|
||||
'native_name' => 'Soomaaliga, af Soomaali',
|
||||
],
|
||||
['code' => 'sq', 'native_name' => 'Shqip'],
|
||||
[
|
||||
'code' => 'sq',
|
||||
'native_name' => 'Shqip',
|
||||
],
|
||||
[
|
||||
'code' => 'sr',
|
||||
'native_name' => 'српски језик',
|
||||
],
|
||||
['code' => 'ss', 'native_name' => 'SiSwati'],
|
||||
[
|
||||
'code' => 'ss',
|
||||
'native_name' => 'SiSwati',
|
||||
],
|
||||
[
|
||||
'code' => 'st',
|
||||
'native_name' => 'Sesotho',
|
||||
|
|
@ -457,16 +635,34 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'su',
|
||||
'native_name' => 'Basa Sunda',
|
||||
],
|
||||
['code' => 'sv', 'native_name' => 'Svenska'],
|
||||
['code' => 'sw', 'native_name' => 'Kiswahili'],
|
||||
['code' => 'ta', 'native_name' => 'தமிழ்'],
|
||||
['code' => 'te', 'native_name' => 'తెలుగు'],
|
||||
[
|
||||
'code' => 'sv',
|
||||
'native_name' => 'Svenska',
|
||||
],
|
||||
[
|
||||
'code' => 'sw',
|
||||
'native_name' => 'Kiswahili',
|
||||
],
|
||||
[
|
||||
'code' => 'ta',
|
||||
'native_name' => 'தமிழ்',
|
||||
],
|
||||
[
|
||||
'code' => 'te',
|
||||
'native_name' => 'తెలుగు',
|
||||
],
|
||||
[
|
||||
'code' => 'tg',
|
||||
'native_name' => 'тоҷикӣ, toçikī, تاجیکی',
|
||||
],
|
||||
['code' => 'th', 'native_name' => 'ไทย'],
|
||||
['code' => 'ti', 'native_name' => 'ትግርኛ'],
|
||||
[
|
||||
'code' => 'th',
|
||||
'native_name' => 'ไทย',
|
||||
],
|
||||
[
|
||||
'code' => 'ti',
|
||||
'native_name' => 'ትግርኛ',
|
||||
],
|
||||
[
|
||||
'code' => 'tk',
|
||||
'native_name' => 'Türkmen, Түркмен',
|
||||
|
|
@ -475,18 +671,30 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'tl',
|
||||
'native_name' => 'Wikang Tagalog',
|
||||
],
|
||||
['code' => 'tn', 'native_name' => 'Setswana'],
|
||||
[
|
||||
'code' => 'tn',
|
||||
'native_name' => 'Setswana',
|
||||
],
|
||||
[
|
||||
'code' => 'to',
|
||||
'native_name' => 'Faka Tonga',
|
||||
],
|
||||
['code' => 'tr', 'native_name' => 'Türkçe'],
|
||||
['code' => 'ts', 'native_name' => 'Xitsonga'],
|
||||
[
|
||||
'code' => 'tr',
|
||||
'native_name' => 'Türkçe',
|
||||
],
|
||||
[
|
||||
'code' => 'ts',
|
||||
'native_name' => 'Xitsonga',
|
||||
],
|
||||
[
|
||||
'code' => 'tt',
|
||||
'native_name' => 'татар теле, tatar tele',
|
||||
],
|
||||
['code' => 'tw', 'native_name' => 'Twi'],
|
||||
[
|
||||
'code' => 'tw',
|
||||
'native_name' => 'Twi',
|
||||
],
|
||||
[
|
||||
'code' => 'ty',
|
||||
'native_name' => 'Reo Tahiti',
|
||||
|
|
@ -499,22 +707,46 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'uk',
|
||||
'native_name' => 'Українська',
|
||||
],
|
||||
['code' => 'ur', 'native_name' => 'اردو'],
|
||||
[
|
||||
'code' => 'ur',
|
||||
'native_name' => 'اردو',
|
||||
],
|
||||
[
|
||||
'code' => 'uz',
|
||||
'native_name' => 'Oʻzbek, Ўзбек, أۇزبېك',
|
||||
],
|
||||
['code' => 've', 'native_name' => 'Tshivenḓa'],
|
||||
[
|
||||
'code' => 've',
|
||||
'native_name' => 'Tshivenḓa',
|
||||
],
|
||||
[
|
||||
'code' => 'vi',
|
||||
'native_name' => 'Tiếng Việt',
|
||||
],
|
||||
['code' => 'vo', 'native_name' => 'Volapük'],
|
||||
['code' => 'wa', 'native_name' => 'Walon'],
|
||||
['code' => 'wo', 'native_name' => 'Wollof'],
|
||||
['code' => 'xh', 'native_name' => 'isiXhosa'],
|
||||
['code' => 'yi', 'native_name' => 'ייִדיש'],
|
||||
['code' => 'yo', 'native_name' => 'Yorùbá'],
|
||||
[
|
||||
'code' => 'vo',
|
||||
'native_name' => 'Volapük',
|
||||
],
|
||||
[
|
||||
'code' => 'wa',
|
||||
'native_name' => 'Walon',
|
||||
],
|
||||
[
|
||||
'code' => 'wo',
|
||||
'native_name' => 'Wollof',
|
||||
],
|
||||
[
|
||||
'code' => 'xh',
|
||||
'native_name' => 'isiXhosa',
|
||||
],
|
||||
[
|
||||
'code' => 'yi',
|
||||
'native_name' => 'ייִדיש',
|
||||
],
|
||||
[
|
||||
'code' => 'yo',
|
||||
'native_name' => 'Yorùbá',
|
||||
],
|
||||
[
|
||||
'code' => 'za',
|
||||
'native_name' => 'Saɯ cueŋƅ, Saw cuengh',
|
||||
|
|
@ -523,7 +755,10 @@ class LanguageSeeder extends Seeder
|
|||
'code' => 'zh',
|
||||
'native_name' => '中文 (Zhōngwén), 汉语, 漢語',
|
||||
],
|
||||
['code' => 'zu', 'native_name' => 'isiZulu'],
|
||||
[
|
||||
'code' => 'zu',
|
||||
'native_name' => 'isiZulu',
|
||||
],
|
||||
];
|
||||
|
||||
$this->db
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class PlatformsSeeder
|
||||
* Inserts values in platforms table in database
|
||||
* Class PlatformsSeeder Inserts values in platforms table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class TestSeeder
|
||||
* Inserts a superadmin user in the database
|
||||
* Class TestSeeder Inserts a superadmin user in the database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -17,21 +16,24 @@ class TestSeeder extends Seeder
|
|||
{
|
||||
public function run(): void
|
||||
{
|
||||
/** Inserts an active user with the following credentials:
|
||||
* username: admin
|
||||
* password: AGUehL3P
|
||||
/**
|
||||
* Inserts an active user with the following credentials: username: admin password: AGUehL3P
|
||||
*/
|
||||
$this->db->table('users')->insert([
|
||||
'id' => 1,
|
||||
'username' => 'admin',
|
||||
'email' => 'admin@example.com',
|
||||
'password_hash' =>
|
||||
'$2y$10$TXJEHX/djW8jtzgpDVf7dOOCGo5rv1uqtAYWdwwwkttQcDkAeB2.6',
|
||||
'active' => 1,
|
||||
]);
|
||||
$this->db->table('users')
|
||||
->insert([
|
||||
'id' => 1,
|
||||
'username' => 'admin',
|
||||
'email' => 'admin@example.com',
|
||||
'password_hash' =>
|
||||
'$2y$10$TXJEHX/djW8jtzgpDVf7dOOCGo5rv1uqtAYWdwwwkttQcDkAeB2.6',
|
||||
'active' => 1,
|
||||
]);
|
||||
|
||||
$this->db
|
||||
->table('auth_groups_users')
|
||||
->insert(['group_id' => 1, 'user_id' => 1]);
|
||||
->insert([
|
||||
'group_id' => 1,
|
||||
'user_id' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use RuntimeException;
|
|||
class Actor extends ActivityPubActor
|
||||
{
|
||||
protected ?Podcast $podcast = null;
|
||||
|
||||
protected bool $is_podcast;
|
||||
|
||||
public function getIsPodcast(): bool
|
||||
|
|
@ -29,15 +30,11 @@ class Actor extends ActivityPubActor
|
|||
public function getPodcast(): ?Podcast
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast id must be set before getting associated podcast.',
|
||||
);
|
||||
throw new RuntimeException('Podcast id must be set before getting associated podcast.',);
|
||||
}
|
||||
|
||||
if ($this->podcast === null) {
|
||||
$this->podcast = (new PodcastModel())->getPodcastByActorId(
|
||||
$this->id,
|
||||
);
|
||||
$this->podcast = (new PodcastModel())->getPodcastByActorId($this->id,);
|
||||
}
|
||||
|
||||
return $this->podcast;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class Category extends Entity
|
|||
'google_category' => 'string',
|
||||
];
|
||||
|
||||
public function getParent(): ?Category
|
||||
public function getParent(): ?self
|
||||
{
|
||||
if ($this->parent_id === null) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use RuntimeException;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PersonModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\EpisodeModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property int $podcast_id
|
||||
|
|
@ -30,9 +30,13 @@ use CodeIgniter\Entity\Entity;
|
|||
class Credit extends Entity
|
||||
{
|
||||
protected ?Person $person = null;
|
||||
|
||||
protected ?Podcast $podcast = null;
|
||||
|
||||
protected ?Episode $episode = null;
|
||||
|
||||
protected string $group_label;
|
||||
|
||||
protected string $role_label;
|
||||
|
||||
/**
|
||||
|
|
@ -50,15 +54,11 @@ class Credit extends Entity
|
|||
public function getPerson(): ?Person
|
||||
{
|
||||
if ($this->person_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have person_id before getting person.',
|
||||
);
|
||||
throw new RuntimeException('Credit must have person_id before getting person.',);
|
||||
}
|
||||
|
||||
if ($this->person === null) {
|
||||
$this->person = (new PersonModel())->getPersonById(
|
||||
$this->person_id,
|
||||
);
|
||||
$this->person = (new PersonModel())->getPersonById($this->person_id,);
|
||||
}
|
||||
|
||||
return $this->person;
|
||||
|
|
@ -67,15 +67,11 @@ class Credit extends Entity
|
|||
public function getPodcast(): ?Podcast
|
||||
{
|
||||
if ($this->podcast_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have podcast_id before getting podcast.',
|
||||
);
|
||||
throw new RuntimeException('Credit must have podcast_id before getting podcast.',);
|
||||
}
|
||||
|
||||
if ($this->podcast === null) {
|
||||
$this->podcast = (new PodcastModel())->getPodcastById(
|
||||
$this->podcast_id,
|
||||
);
|
||||
$this->podcast = (new PodcastModel())->getPodcastById($this->podcast_id,);
|
||||
}
|
||||
|
||||
return $this->podcast;
|
||||
|
|
@ -84,16 +80,11 @@ class Credit extends Entity
|
|||
public function getEpisode(): ?Episode
|
||||
{
|
||||
if ($this->episode_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Credit must have episode_id before getting episode.',
|
||||
);
|
||||
throw new RuntimeException('Credit must have episode_id before getting episode.',);
|
||||
}
|
||||
|
||||
if ($this->episode === null) {
|
||||
$this->episode = (new EpisodeModel())->getPublishedEpisodeById(
|
||||
$this->podcast_id,
|
||||
$this->episode_id,
|
||||
);
|
||||
$this->episode = (new EpisodeModel())->getPublishedEpisodeById($this->podcast_id, $this->episode_id,);
|
||||
}
|
||||
|
||||
return $this->episode;
|
||||
|
|
@ -118,8 +109,6 @@ class Credit extends Entity
|
|||
return '';
|
||||
}
|
||||
|
||||
return lang(
|
||||
"PersonsTaxonomy.persons.{$this->person_group}.roles.{$this->person_role}.label",
|
||||
);
|
||||
return lang("PersonsTaxonomy.persons.{$this->person_group}.roles.{$this->person_role}.label",);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use App\Entities\Location;
|
||||
use App\Libraries\SimpleRSSElement;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\SoundbiteModel;
|
||||
use App\Models\NoteModel;
|
||||
use App\Models\PersonModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\SoundbiteModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use CodeIgniter\Files\File;
|
||||
use CodeIgniter\HTTP\Files\UploadedFile;
|
||||
|
|
@ -82,16 +81,27 @@ use RuntimeException;
|
|||
class Episode extends Entity
|
||||
{
|
||||
protected Podcast $podcast;
|
||||
|
||||
protected string $link;
|
||||
|
||||
protected File $audio_file;
|
||||
|
||||
protected string $audio_file_url;
|
||||
|
||||
protected string $audio_file_analytics_url;
|
||||
|
||||
protected string $audio_file_web_url;
|
||||
|
||||
protected string $audio_file_opengraph_url;
|
||||
|
||||
protected string $embeddable_player_url;
|
||||
|
||||
protected Image $image;
|
||||
|
||||
protected ?string $description = null;
|
||||
|
||||
protected File $transcript_file;
|
||||
|
||||
protected File $chapters_file;
|
||||
|
||||
/**
|
||||
|
|
@ -110,18 +120,15 @@ class Episode extends Entity
|
|||
protected ?array $notes = null;
|
||||
|
||||
protected ?Location $location = null;
|
||||
|
||||
protected string $custom_rss_string;
|
||||
|
||||
protected ?string $publication_status = null;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $dates = [
|
||||
'published_at',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at',
|
||||
];
|
||||
protected $dates = ['published_at', 'created_at', 'updated_at', 'deleted_at'];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
|
|
@ -171,10 +178,7 @@ class Episode extends Entity
|
|||
}
|
||||
|
||||
// Save image
|
||||
$image->saveImage(
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
$image->saveImage('podcasts/' . $this->getPodcast()->name, $this->attributes['slug'],);
|
||||
|
||||
$this->attributes['image_mimetype'] = $image->mimetype;
|
||||
$this->attributes['image_path'] = $image->path;
|
||||
|
|
@ -185,11 +189,7 @@ class Episode extends Entity
|
|||
public function getImage(): Image
|
||||
{
|
||||
if ($imagePath = $this->attributes['image_path']) {
|
||||
return new Image(
|
||||
null,
|
||||
$imagePath,
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
return new Image(null, $imagePath, $this->attributes['image_mimetype'],);
|
||||
}
|
||||
|
||||
return $this->podcast->image;
|
||||
|
|
@ -198,7 +198,7 @@ class Episode extends Entity
|
|||
/**
|
||||
* Saves an audio file
|
||||
*/
|
||||
public function setAudioFile(UploadedFile|File $audioFile): static
|
||||
public function setAudioFile(UploadedFile | File $audioFile): static
|
||||
{
|
||||
helper(['media', 'id3']);
|
||||
|
||||
|
|
@ -222,13 +222,14 @@ class Episode extends Entity
|
|||
/**
|
||||
* Saves an episode transcript file
|
||||
*/
|
||||
public function setTranscriptFile(UploadedFile|File $transcriptFile): static
|
||||
public function setTranscriptFile(UploadedFile | File $transcriptFile): static
|
||||
{
|
||||
helper('media');
|
||||
|
||||
$this->attributes['transcript_file_path'] = save_media(
|
||||
$transcriptFile,
|
||||
$this->getPodcast()->name,
|
||||
$this->getPodcast()
|
||||
->name,
|
||||
$this->attributes['slug'] . '-transcript',
|
||||
);
|
||||
|
||||
|
|
@ -238,13 +239,14 @@ class Episode extends Entity
|
|||
/**
|
||||
* Saves an episode chapters file
|
||||
*/
|
||||
public function setChaptersFile(UploadedFile|File $chaptersFile): static
|
||||
public function setChaptersFile(UploadedFile | File $chaptersFile): static
|
||||
{
|
||||
helper('media');
|
||||
|
||||
$this->attributes['chapters_file_path'] = save_media(
|
||||
$chaptersFile,
|
||||
$this->getPodcast()->name,
|
||||
$this->getPodcast()
|
||||
->name,
|
||||
$this->attributes['slug'] . '-chapters',
|
||||
);
|
||||
|
||||
|
|
@ -263,9 +265,7 @@ class Episode extends Entity
|
|||
if ($this->attributes['transcript_file_path']) {
|
||||
helper('media');
|
||||
|
||||
return new File(
|
||||
media_path($this->attributes['transcript_file_path']),
|
||||
);
|
||||
return new File(media_path($this->attributes['transcript_file_path']),);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -276,9 +276,7 @@ class Episode extends Entity
|
|||
if ($this->attributes['chapters_file_path']) {
|
||||
helper('media');
|
||||
|
||||
return new File(
|
||||
media_path($this->attributes['chapters_file_path']),
|
||||
);
|
||||
return new File(media_path($this->attributes['chapters_file_path']),);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -317,8 +315,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.
|
||||
* Gets transcript url from transcript file uri if it exists or returns the transcript_file_remote_url which can be
|
||||
* null.
|
||||
*/
|
||||
public function getTranscriptFileUrl(): ?string
|
||||
{
|
||||
|
|
@ -329,8 +327,8 @@ class Episode extends Entity
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets chapters file url from chapters file uri if it exists
|
||||
* or returns the chapters_file_remote_url which can be null.
|
||||
* Gets chapters file url from chapters file uri if it exists or returns the chapters_file_remote_url which can be
|
||||
* null.
|
||||
*/
|
||||
public function getChaptersFileUrl(): ?string
|
||||
{
|
||||
|
|
@ -349,16 +347,11 @@ class Episode extends Entity
|
|||
public function getPersons(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Episode must be created before getting persons.',
|
||||
);
|
||||
throw new RuntimeException('Episode must be created before getting persons.',);
|
||||
}
|
||||
|
||||
if ($this->persons === null) {
|
||||
$this->persons = (new PersonModel())->getEpisodePersons(
|
||||
$this->podcast_id,
|
||||
$this->id,
|
||||
);
|
||||
$this->persons = (new PersonModel())->getEpisodePersons($this->podcast_id, $this->id,);
|
||||
}
|
||||
|
||||
return $this->persons;
|
||||
|
|
@ -372,16 +365,11 @@ class Episode extends Entity
|
|||
public function getSoundbites(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Episode must be created before getting soundbites.',
|
||||
);
|
||||
throw new RuntimeException('Episode must be created before getting soundbites.',);
|
||||
}
|
||||
|
||||
if ($this->soundbites === null) {
|
||||
$this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites(
|
||||
$this->getPodcast()->id,
|
||||
$this->id,
|
||||
);
|
||||
$this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites($this->getPodcast() ->id, $this->id,);
|
||||
}
|
||||
|
||||
return $this->soundbites;
|
||||
|
|
@ -393,9 +381,7 @@ class Episode extends Entity
|
|||
public function getNotes(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Episode must be created before getting soundbites.',
|
||||
);
|
||||
throw new RuntimeException('Episode must be created before getting soundbites.',);
|
||||
}
|
||||
|
||||
if ($this->notes === null) {
|
||||
|
|
@ -407,13 +393,7 @@ class Episode extends Entity
|
|||
|
||||
public function getLink(): string
|
||||
{
|
||||
return base_url(
|
||||
route_to(
|
||||
'episode',
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
),
|
||||
);
|
||||
return base_url(route_to('episode', $this->getPodcast() ->name, $this->attributes['slug'],),);
|
||||
}
|
||||
|
||||
public function getEmbeddablePlayerUrl(string $theme = null): string
|
||||
|
|
@ -422,15 +402,12 @@ class Episode extends Entity
|
|||
$theme
|
||||
? route_to(
|
||||
'embeddable-player-theme',
|
||||
$this->getPodcast()->name,
|
||||
$this->getPodcast()
|
||||
->name,
|
||||
$this->attributes['slug'],
|
||||
$theme,
|
||||
)
|
||||
: route_to(
|
||||
'embeddable-player',
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
),
|
||||
: route_to('embeddable-player', $this->getPodcast() ->name, $this->attributes['slug'],),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -443,9 +420,7 @@ class Episode extends Entity
|
|||
|
||||
public function getPodcast(): ?Podcast
|
||||
{
|
||||
return (new PodcastModel())->getPodcastById(
|
||||
$this->attributes['podcast_id'],
|
||||
);
|
||||
return (new PodcastModel())->getPodcastById($this->attributes['podcast_id'],);
|
||||
}
|
||||
|
||||
public function setDescriptionMarkdown(string $descriptionMarkdown): static
|
||||
|
|
@ -456,9 +431,7 @@ class Episode extends Entity
|
|||
]);
|
||||
|
||||
$this->attributes['description_markdown'] = $descriptionMarkdown;
|
||||
$this->attributes['description_html'] = $converter->convertToHtml(
|
||||
$descriptionMarkdown,
|
||||
);
|
||||
$this->attributes['description_html'] = $converter->convertToHtml($descriptionMarkdown,);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -467,19 +440,25 @@ class Episode extends Entity
|
|||
{
|
||||
$descriptionHtml = '';
|
||||
if (
|
||||
$this->getPodcast()->partner_id !== null &&
|
||||
$this->getPodcast()->partner_link_url !== null &&
|
||||
$this->getPodcast()->partner_image_url !== null
|
||||
$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->getPartnerImageUrl($serviceSlug,
|
||||
$descriptionHtml .= "<div><a href=\"{$this->getPartnerLink(
|
||||
$serviceSlug,
|
||||
)}\" rel=\"sponsored noopener noreferrer\" target=\"_blank\"><img src=\"{$this->getPartnerImageUrl(
|
||||
$serviceSlug,
|
||||
)}\" alt=\"Partner image\" /></a></div>";
|
||||
}
|
||||
|
||||
$descriptionHtml .= $this->attributes['description_html'];
|
||||
|
||||
if ($this->getPodcast()->episode_description_footer_html) {
|
||||
$descriptionHtml .= "<footer>{$this->getPodcast()->episode_description_footer_html}</footer>";
|
||||
$descriptionHtml .= "<footer>{$this->getPodcast()
|
||||
->episode_description_footer_html}</footer>";
|
||||
}
|
||||
|
||||
return $descriptionHtml;
|
||||
|
|
@ -489,11 +468,7 @@ class Episode extends Entity
|
|||
{
|
||||
if ($this->description === null) {
|
||||
$this->description = trim(
|
||||
preg_replace(
|
||||
'~\s+~',
|
||||
' ',
|
||||
strip_tags($this->attributes['description_html']),
|
||||
),
|
||||
preg_replace('~\s+~', ' ', strip_tags($this->attributes['description_html']),),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -529,7 +504,7 @@ class Episode extends Entity
|
|||
}
|
||||
|
||||
if (
|
||||
!isset($this->attributes['location_name']) ||
|
||||
! isset($this->attributes['location_name']) ||
|
||||
$this->attributes['location_name'] !== $location->name
|
||||
) {
|
||||
$location->fetchOsmLocation();
|
||||
|
|
@ -549,11 +524,7 @@ class Episode extends Entity
|
|||
}
|
||||
|
||||
if ($this->location === null) {
|
||||
$this->location = new Location(
|
||||
$this->location_name,
|
||||
$this->location_geo,
|
||||
$this->location_osm,
|
||||
);
|
||||
$this->location = new Location($this->location_name, $this->location_geo, $this->location_osm,);
|
||||
}
|
||||
|
||||
return $this->location;
|
||||
|
|
@ -562,7 +533,7 @@ class Episode extends Entity
|
|||
/**
|
||||
* Get custom rss tag as XML String
|
||||
*/
|
||||
function getCustomRssString(): string
|
||||
public function getCustomRssString(): string
|
||||
{
|
||||
if ($this->custom_rss === null) {
|
||||
return '';
|
||||
|
|
@ -575,12 +546,9 @@ class Episode extends Entity
|
|||
))
|
||||
->addChild('channel')
|
||||
->addChild('item');
|
||||
array_to_rss(
|
||||
[
|
||||
'elements' => $this->custom_rss,
|
||||
],
|
||||
$xmlNode,
|
||||
);
|
||||
array_to_rss([
|
||||
'elements' => $this->custom_rss,
|
||||
], $xmlNode,);
|
||||
|
||||
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
||||
}
|
||||
|
|
@ -588,7 +556,7 @@ class Episode extends Entity
|
|||
/**
|
||||
* Saves custom rss tag into json
|
||||
*/
|
||||
function setCustomRssString(?string $customRssString = null): static
|
||||
public function setCustomRssString(?string $customRssString = null): static
|
||||
{
|
||||
if ($customRssString === null) {
|
||||
return $this;
|
||||
|
|
@ -604,9 +572,7 @@ class Episode extends Entity
|
|||
)['elements'][0]['elements'][0];
|
||||
|
||||
if (array_key_exists('elements', $customRssArray)) {
|
||||
$this->attributes['custom_rss'] = json_encode(
|
||||
$customRssArray['elements'],
|
||||
);
|
||||
$this->attributes['custom_rss'] = json_encode($customRssArray['elements'],);
|
||||
} else {
|
||||
$this->attributes['custom_rss'] = null;
|
||||
}
|
||||
|
|
@ -614,12 +580,13 @@ class Episode extends Entity
|
|||
return $this;
|
||||
}
|
||||
|
||||
function getPartnerLink(?string $serviceSlug = null): string
|
||||
public function getPartnerLink(?string $serviceSlug = null): string
|
||||
{
|
||||
$partnerLink =
|
||||
rtrim($this->getPodcast()->partner_link_url, '/') .
|
||||
'?pid=' .
|
||||
$this->getPodcast()->partner_id .
|
||||
$this->getPodcast()
|
||||
->partner_id .
|
||||
'&guid=' .
|
||||
urlencode($this->attributes['guid']);
|
||||
|
||||
|
|
@ -630,7 +597,7 @@ class Episode extends Entity
|
|||
return $partnerLink;
|
||||
}
|
||||
|
||||
function getPartnerImageUrl(string $serviceSlug = null): string
|
||||
public function getPartnerImageUrl(string $serviceSlug = null): string
|
||||
{
|
||||
if ($serviceSlug !== null) {
|
||||
return '&_from=' . $serviceSlug;
|
||||
|
|
@ -638,7 +605,8 @@ class Episode extends Entity
|
|||
|
||||
return rtrim($this->getPodcast()->partner_image_url, '/') .
|
||||
'?pid=' .
|
||||
$this->getPodcast()->partner_id .
|
||||
$this->getPodcast()
|
||||
->partner_id .
|
||||
'&guid=' .
|
||||
urlencode($this->attributes['guid']);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,20 +36,19 @@ use RuntimeException;
|
|||
class Image extends Entity
|
||||
{
|
||||
protected Images $config;
|
||||
|
||||
protected ?File $file = null;
|
||||
|
||||
protected string $dirname;
|
||||
|
||||
protected string $filename;
|
||||
|
||||
protected string $extension;
|
||||
|
||||
public function __construct(
|
||||
?File $file,
|
||||
string $path = '',
|
||||
string $mimetype = ''
|
||||
) {
|
||||
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.',
|
||||
);
|
||||
throw new RuntimeException('File or path must be set to create an Image.',);
|
||||
}
|
||||
|
||||
$this->config = config('Images');
|
||||
|
|
@ -80,7 +79,7 @@ class Image extends Entity
|
|||
$this->mimetype = $mimetype;
|
||||
}
|
||||
|
||||
function getFile(): File
|
||||
public function getFile(): File
|
||||
{
|
||||
if ($this->file === null) {
|
||||
$this->file = new File($this->path);
|
||||
|
|
@ -89,19 +88,19 @@ class Image extends Entity
|
|||
return $this->file;
|
||||
}
|
||||
|
||||
function getPath(): string
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->dirname . '/' . $this->filename . '.' . $this->extension;
|
||||
}
|
||||
|
||||
function getUrl(): string
|
||||
public function getUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->path);
|
||||
}
|
||||
|
||||
function getThumbnailPath(): string
|
||||
public function getThumbnailPath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
|
|
@ -111,14 +110,14 @@ class Image extends Entity
|
|||
$this->extension;
|
||||
}
|
||||
|
||||
function getThumbnailUrl(): string
|
||||
public function getThumbnailUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->thumbnail_path);
|
||||
}
|
||||
|
||||
function getMediumPath(): string
|
||||
public function getMediumPath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
|
|
@ -128,14 +127,14 @@ class Image extends Entity
|
|||
$this->extension;
|
||||
}
|
||||
|
||||
function getMediumUrl(): string
|
||||
public function getMediumUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->medium_path);
|
||||
}
|
||||
|
||||
function getLargePath(): string
|
||||
public function getLargePath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
|
|
@ -145,14 +144,14 @@ class Image extends Entity
|
|||
$this->extension;
|
||||
}
|
||||
|
||||
function getLargeUrl(): string
|
||||
public function getLargeUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->large_path);
|
||||
}
|
||||
|
||||
function getFeedPath(): string
|
||||
public function getFeedPath(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
|
|
@ -162,14 +161,14 @@ class Image extends Entity
|
|||
$this->extension;
|
||||
}
|
||||
|
||||
function getFeedUrl(): string
|
||||
public function getFeedUrl(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
return media_base_url($this->feed_path);
|
||||
}
|
||||
|
||||
function getId3Path(): string
|
||||
public function getId3Path(): string
|
||||
{
|
||||
return $this->dirname .
|
||||
'/' .
|
||||
|
|
@ -179,7 +178,7 @@ class Image extends Entity
|
|||
$this->extension;
|
||||
}
|
||||
|
||||
function getId3Url(): string
|
||||
public function getId3Url(): string
|
||||
{
|
||||
helper('media');
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@ class Location extends Entity
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
const OSM_URL = 'https://www.openstreetmap.org/';
|
||||
private const OSM_URL = 'https://www.openstreetmap.org/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const NOMINATIM_URL = 'https://nominatim.openstreetmap.org/';
|
||||
private const NOMINATIM_URL = 'https://nominatim.openstreetmap.org/';
|
||||
|
||||
public function __construct(
|
||||
protected string $name,
|
||||
|
|
@ -37,7 +37,7 @@ class Location extends Entity
|
|||
parent::__construct([
|
||||
'name' => $name,
|
||||
'geo' => $geo,
|
||||
'osm' => $osm
|
||||
'osm' => $osm,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,11 @@ class Location extends Entity
|
|||
{
|
||||
if ($this->osm !== null) {
|
||||
return self::OSM_URL .
|
||||
['N' => 'node', 'W' => 'way', 'R' => 'relation'][substr($this->osm, 0, 1)] .
|
||||
[
|
||||
'N' => 'node',
|
||||
'W' => 'way',
|
||||
'R' => 'relation',
|
||||
][substr($this->osm, 0, 1)] .
|
||||
'/' .
|
||||
substr($this->osm, 1);
|
||||
}
|
||||
|
|
@ -80,22 +84,23 @@ class Location extends Entity
|
|||
],
|
||||
);
|
||||
|
||||
$places = json_decode(
|
||||
$response->getBody(),
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
$places = json_decode($response->getBody(), false, 512, JSON_THROW_ON_ERROR,);
|
||||
|
||||
if ($places === []) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (property_exists($places[0], 'lat') && $places[0]->lat !== null && (property_exists($places[0], 'lon') && $places[0]->lon !== null)) {
|
||||
if (property_exists($places[0], 'lat') && $places[0]->lat !== null && (property_exists(
|
||||
$places[0],
|
||||
'lon'
|
||||
) && $places[0]->lon !== null)) {
|
||||
$this->attributes['geo'] = "geo:{$places[0]->lat},{$places[0]->lon}";
|
||||
}
|
||||
|
||||
if (property_exists($places[0], 'osm_type') && $places[0]->osm_type !== null && (property_exists($places[0], 'osm_id') && $places[0]->osm_id !== null)) {
|
||||
if (property_exists($places[0], 'osm_type') && $places[0]->osm_type !== null && (property_exists(
|
||||
$places[0],
|
||||
'osm_id'
|
||||
) && $places[0]->osm_id !== null)) {
|
||||
$this->attributes['osm'] = strtoupper(substr($places[0]->osm_type, 0, 1)) . $places[0]->osm_id;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,15 +47,11 @@ class Note extends ActivityPubNote
|
|||
public function getEpisode(): ?Episode
|
||||
{
|
||||
if ($this->episode_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Note must have an episode_id before getting episode.',
|
||||
);
|
||||
throw new RuntimeException('Note must have an episode_id before getting episode.',);
|
||||
}
|
||||
|
||||
if ($this->episode === null) {
|
||||
$this->episode = (new EpisodeModel())->getEpisodeById(
|
||||
$this->episode_id,
|
||||
);
|
||||
$this->episode = (new EpisodeModel())->getEpisodeById($this->episode_id,);
|
||||
}
|
||||
|
||||
return $this->episode;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use League\CommonMark\CommonMarkConverter;
|
|||
class Page extends Entity
|
||||
{
|
||||
protected string $link;
|
||||
|
||||
protected string $content_html;
|
||||
|
||||
/**
|
||||
|
|
@ -52,9 +53,7 @@ class Page extends Entity
|
|||
]);
|
||||
|
||||
$this->attributes['content_markdown'] = $contentMarkdown;
|
||||
$this->attributes['content_html'] = $converter->convertToHtml(
|
||||
$contentMarkdown,
|
||||
);
|
||||
$this->attributes['content_html'] = $converter->convertToHtml($contentMarkdown,);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ use RuntimeException;
|
|||
class Person extends Entity
|
||||
{
|
||||
protected Image $image;
|
||||
|
||||
protected ?int $podcast_id = null;
|
||||
|
||||
protected ?int $episode_id = null;
|
||||
|
||||
/**
|
||||
|
|
@ -69,25 +71,24 @@ class Person extends Entity
|
|||
|
||||
public function getImage(): Image
|
||||
{
|
||||
return new Image(
|
||||
null,
|
||||
$this->attributes['image_path'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
return new Image(null, $this->attributes['image_path'], $this->attributes['image_mimetype'],);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object[]
|
||||
*/
|
||||
public function getRoles(): array {
|
||||
public function getRoles(): array
|
||||
{
|
||||
if ($this->attributes['podcast_id'] === null) {
|
||||
throw new RuntimeException(
|
||||
'Person must have a podcast_id before getting roles.',
|
||||
);
|
||||
throw new RuntimeException('Person must have a podcast_id before getting roles.',);
|
||||
}
|
||||
|
||||
if ($this->roles === null) {
|
||||
$this->roles = (new PersonModel())->getPersonRoles($this->id, $this->attributes['podcast_id'], $this->episode_id);
|
||||
$this->roles = (new PersonModel())->getPersonRoles(
|
||||
$this->id,
|
||||
$this->attributes['podcast_id'],
|
||||
$this->episode_id
|
||||
);
|
||||
}
|
||||
|
||||
return $this->roles;
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ use App\Models\CategoryModel;
|
|||
use App\Models\EpisodeModel;
|
||||
use App\Models\PersonModel;
|
||||
use App\Models\PlatformModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use RuntimeException;
|
||||
|
|
@ -73,14 +73,17 @@ use RuntimeException;
|
|||
* @property Platform[] $podcasting_platforms
|
||||
* @property Platform[] $social_platforms
|
||||
* @property Platform[] $funding_platforms
|
||||
*
|
||||
*/
|
||||
class Podcast extends Entity
|
||||
{
|
||||
protected string $link;
|
||||
|
||||
protected ?Actor $actor = null;
|
||||
|
||||
protected Image $image;
|
||||
|
||||
protected ?string $description = null;
|
||||
|
||||
protected ?Category $category = null;
|
||||
|
||||
/**
|
||||
|
|
@ -124,6 +127,7 @@ class Podcast extends Entity
|
|||
protected ?array $funding_platforms = null;
|
||||
|
||||
protected ?Location $location = null;
|
||||
|
||||
protected string $custom_rss_string;
|
||||
|
||||
/**
|
||||
|
|
@ -168,13 +172,12 @@ class Podcast extends Entity
|
|||
public function getActor(): Actor
|
||||
{
|
||||
if ($this->actor_id === 0) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must have an actor_id before getting actor.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must have an actor_id before getting actor.',);
|
||||
}
|
||||
|
||||
if ($this->actor === null) {
|
||||
$this->actor = model('ActorModel')->getActorById($this->actor_id);
|
||||
$this->actor = model('ActorModel')
|
||||
->getActorById($this->actor_id);
|
||||
}
|
||||
|
||||
return $this->actor;
|
||||
|
|
@ -217,16 +220,11 @@ class Podcast extends Entity
|
|||
public function getEpisodes(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting episodes.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting episodes.',);
|
||||
}
|
||||
|
||||
if ($this->episodes === null) {
|
||||
$this->episodes = (new EpisodeModel())->getPodcastEpisodes(
|
||||
$this->id,
|
||||
$this->type,
|
||||
);
|
||||
$this->episodes = (new EpisodeModel())->getPodcastEpisodes($this->id, $this->type,);
|
||||
}
|
||||
|
||||
return $this->episodes;
|
||||
|
|
@ -240,9 +238,7 @@ class Podcast extends Entity
|
|||
public function getPersons(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting persons.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting persons.',);
|
||||
}
|
||||
|
||||
if ($this->persons === null) {
|
||||
|
|
@ -258,15 +254,11 @@ class Podcast extends Entity
|
|||
public function getCategory(): ?Category
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting category.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting category.',);
|
||||
}
|
||||
|
||||
if ($this->category === null) {
|
||||
$this->category = (new CategoryModel())->getCategoryById(
|
||||
$this->category_id,
|
||||
);
|
||||
$this->category = (new CategoryModel())->getCategoryById($this->category_id,);
|
||||
}
|
||||
|
||||
return $this->category;
|
||||
|
|
@ -280,15 +272,11 @@ class Podcast extends Entity
|
|||
public function getContributors(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcasts must be created before getting contributors.',
|
||||
);
|
||||
throw new RuntimeException('Podcasts must be created before getting contributors.',);
|
||||
}
|
||||
|
||||
if ($this->contributors === null) {
|
||||
$this->contributors = (new UserModel())->getPodcastContributors(
|
||||
$this->id,
|
||||
);
|
||||
$this->contributors = (new UserModel())->getPodcastContributors($this->id,);
|
||||
}
|
||||
|
||||
return $this->contributors;
|
||||
|
|
@ -302,16 +290,13 @@ class Podcast extends Entity
|
|||
]);
|
||||
|
||||
$this->attributes['description_markdown'] = $descriptionMarkdown;
|
||||
$this->attributes['description_html'] = $converter->convertToHtml(
|
||||
$descriptionMarkdown,
|
||||
);
|
||||
$this->attributes['description_html'] = $converter->convertToHtml($descriptionMarkdown,);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEpisodeDescriptionFooterMarkdown(
|
||||
?string $episodeDescriptionFooterMarkdown = null
|
||||
): static {
|
||||
public function setEpisodeDescriptionFooterMarkdown(?string $episodeDescriptionFooterMarkdown = null): static
|
||||
{
|
||||
if ($episodeDescriptionFooterMarkdown) {
|
||||
$converter = new CommonMarkConverter([
|
||||
'html_input' => 'strip',
|
||||
|
|
@ -333,11 +318,7 @@ class Podcast extends Entity
|
|||
{
|
||||
if ($this->description === null) {
|
||||
$this->description = trim(
|
||||
(string) preg_replace(
|
||||
'~\s+~',
|
||||
' ',
|
||||
strip_tags($this->attributes['description_html']),
|
||||
),
|
||||
(string) preg_replace('~\s+~', ' ', strip_tags($this->attributes['description_html']),),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -352,16 +333,11 @@ class Podcast extends Entity
|
|||
public function getPodcastingPlatforms(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting podcasting platform links.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting podcasting platform links.',);
|
||||
}
|
||||
|
||||
if ($this->podcasting_platforms === null) {
|
||||
$this->podcasting_platforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
$this->id,
|
||||
'podcasting',
|
||||
);
|
||||
$this->podcasting_platforms = (new PlatformModel())->getPodcastPlatforms($this->id, 'podcasting',);
|
||||
}
|
||||
|
||||
return $this->podcasting_platforms;
|
||||
|
|
@ -375,16 +351,11 @@ class Podcast extends Entity
|
|||
public function getSocialPlatforms(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting social platform links.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting social platform links.',);
|
||||
}
|
||||
|
||||
if ($this->social_platforms === null) {
|
||||
$this->social_platforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
$this->id,
|
||||
'social',
|
||||
);
|
||||
$this->social_platforms = (new PlatformModel())->getPodcastPlatforms($this->id, 'social',);
|
||||
}
|
||||
|
||||
return $this->social_platforms;
|
||||
|
|
@ -398,16 +369,11 @@ class Podcast extends Entity
|
|||
public function getFundingPlatforms(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting funding platform links.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting funding platform links.',);
|
||||
}
|
||||
|
||||
if ($this->funding_platforms === null) {
|
||||
$this->funding_platforms = (new PlatformModel())->getPodcastPlatforms(
|
||||
$this->id,
|
||||
'funding',
|
||||
);
|
||||
$this->funding_platforms = (new PlatformModel())->getPodcastPlatforms($this->id, 'funding',);
|
||||
}
|
||||
|
||||
return $this->funding_platforms;
|
||||
|
|
@ -419,15 +385,11 @@ class Podcast extends Entity
|
|||
public function getOtherCategories(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Podcast must be created before getting other categories.',
|
||||
);
|
||||
throw new RuntimeException('Podcast must be created before getting other categories.',);
|
||||
}
|
||||
|
||||
if ($this->other_categories === null) {
|
||||
$this->other_categories = (new CategoryModel())->getPodcastCategories(
|
||||
$this->id,
|
||||
);
|
||||
$this->other_categories = (new CategoryModel())->getPodcastCategories($this->id,);
|
||||
}
|
||||
|
||||
return $this->other_categories;
|
||||
|
|
@ -439,10 +401,7 @@ class Podcast extends Entity
|
|||
public function getOtherCategoriesIds(): array
|
||||
{
|
||||
if ($this->other_categories_ids === null) {
|
||||
$this->other_categories_ids = array_column(
|
||||
$this->getOtherCategories(),
|
||||
'id',
|
||||
);
|
||||
$this->other_categories_ids = array_column($this->getOtherCategories(), 'id',);
|
||||
}
|
||||
|
||||
return $this->other_categories_ids;
|
||||
|
|
@ -462,7 +421,7 @@ class Podcast extends Entity
|
|||
}
|
||||
|
||||
if (
|
||||
!isset($this->attributes['location_name']) ||
|
||||
! isset($this->attributes['location_name']) ||
|
||||
$this->attributes['location_name'] !== $location->name
|
||||
) {
|
||||
$location->fetchOsmLocation();
|
||||
|
|
@ -482,11 +441,7 @@ class Podcast extends Entity
|
|||
}
|
||||
|
||||
if ($this->location === null) {
|
||||
$this->location = new Location(
|
||||
$this->location_name,
|
||||
$this->location_geo,
|
||||
$this->location_osm,
|
||||
);
|
||||
$this->location = new Location($this->location_name, $this->location_geo, $this->location_osm,);
|
||||
}
|
||||
|
||||
return $this->location;
|
||||
|
|
@ -495,7 +450,7 @@ class Podcast extends Entity
|
|||
/**
|
||||
* Get custom rss tag as XML String
|
||||
*/
|
||||
function getCustomRssString(): string
|
||||
public function getCustomRssString(): string
|
||||
{
|
||||
if ($this->attributes['custom_rss'] === null) {
|
||||
return '';
|
||||
|
|
@ -506,12 +461,9 @@ class Podcast extends Entity
|
|||
$xmlNode = (new SimpleRSSElement(
|
||||
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"/>',
|
||||
))->addChild('channel');
|
||||
array_to_rss(
|
||||
[
|
||||
'elements' => $this->custom_rss,
|
||||
],
|
||||
$xmlNode,
|
||||
);
|
||||
array_to_rss([
|
||||
'elements' => $this->custom_rss,
|
||||
], $xmlNode,);
|
||||
|
||||
return str_replace(['<channel>', '</channel>'], '', $xmlNode->asXML());
|
||||
}
|
||||
|
|
@ -519,7 +471,7 @@ class Podcast extends Entity
|
|||
/**
|
||||
* Saves custom rss tag into json
|
||||
*/
|
||||
function setCustomRssString(string $customRssString): static
|
||||
public function setCustomRssString(string $customRssString): static
|
||||
{
|
||||
if ($customRssString === '') {
|
||||
return $this;
|
||||
|
|
@ -535,9 +487,7 @@ class Podcast extends Entity
|
|||
)['elements'][0];
|
||||
|
||||
if (array_key_exists('elements', $customRssArray)) {
|
||||
$this->attributes['custom_rss'] = json_encode(
|
||||
$customRssArray['elements'],
|
||||
);
|
||||
$this->attributes['custom_rss'] = json_encode($customRssArray['elements'],);
|
||||
} else {
|
||||
$this->attributes['custom_rss'] = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
namespace App\Entities;
|
||||
|
||||
use RuntimeException;
|
||||
use App\Models\PodcastModel;
|
||||
use Myth\Auth\Entities\User as MythAuthUser;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
|
|
@ -32,8 +32,7 @@ class User extends MythAuthUser
|
|||
protected ?array $podcasts = null;
|
||||
|
||||
/**
|
||||
* Array of field names and the type of value to cast them as
|
||||
* when they are accessed.
|
||||
* Array of field names and the type of value to cast them as when they are accessed.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
|
|
@ -53,9 +52,7 @@ class User extends MythAuthUser
|
|||
public function getPodcasts(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Users must be created before getting podcasts.',
|
||||
);
|
||||
throw new RuntimeException('Users must be created before getting podcasts.',);
|
||||
}
|
||||
|
||||
if ($this->podcasts === null) {
|
||||
|
|
|
|||
|
|
@ -3,23 +3,19 @@
|
|||
namespace App\Filters;
|
||||
|
||||
use App\Models\PodcastModel;
|
||||
use Config\Services;
|
||||
use CodeIgniter\Filters\FilterInterface;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Filters\FilterInterface;
|
||||
use Config\Services;
|
||||
use Myth\Auth\Exceptions\PermissionException;
|
||||
|
||||
class PermissionFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Do whatever processing this filter needs to do.
|
||||
* By default it should not return anything during
|
||||
* normal execution. However, when an abnormal state
|
||||
* is found, it should return an instance of
|
||||
* CodeIgniter\HTTP\Response. If it does, script
|
||||
* execution will end and that Response will be
|
||||
* sent back to the client, allowing for error pages,
|
||||
* redirects, etc.
|
||||
* Do whatever processing this filter needs to do. By default it should not return anything during normal execution.
|
||||
* However, when an abnormal state is found, it should return an instance of CodeIgniter\HTTP\Response. If it does,
|
||||
* script execution will end and that Response will be sent back to the client, allowing for error pages, redirects,
|
||||
* etc.
|
||||
*
|
||||
* @param string[]|null $params
|
||||
* @return void|mixed
|
||||
|
|
@ -35,7 +31,7 @@ class PermissionFilter implements FilterInterface
|
|||
$authenticate = Services::authentication();
|
||||
|
||||
// if no user is logged in then send to the login form
|
||||
if (!$authenticate->check()) {
|
||||
if (! $authenticate->check()) {
|
||||
session()->set('redirect_url', current_url());
|
||||
return redirect('login');
|
||||
}
|
||||
|
|
@ -72,7 +68,7 @@ class PermissionFilter implements FilterInterface
|
|||
}
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
if (! $result) {
|
||||
if ($authenticate->silent()) {
|
||||
$redirectURL = session('redirect_url') ?? '/';
|
||||
unset($_SESSION['redirect_url']);
|
||||
|
|
@ -85,19 +81,15 @@ class PermissionFilter implements FilterInterface
|
|||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Allows After filters to inspect and modify the response
|
||||
* object as needed. This method does not allow any way
|
||||
* to stop execution of other after filters, short of
|
||||
* throwing an Exception or Error.
|
||||
* Allows After filters to inspect and modify the response object as needed. This method does not allow any way to
|
||||
* stop execution of other after filters, short of throwing an Exception or Error.
|
||||
*
|
||||
* @param string[]|null $arguments
|
||||
*/
|
||||
public function after(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
$arguments = null
|
||||
): void {
|
||||
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null): void
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use App\Entities\User;
|
|||
use CodeIgniter\Database\Exceptions\DataException;
|
||||
use Config\Services;
|
||||
|
||||
if (!function_exists('user')) {
|
||||
if (! function_exists('user')) {
|
||||
/**
|
||||
* Returns the User instance for the current logged in user.
|
||||
*/
|
||||
|
|
@ -23,7 +23,7 @@ if (!function_exists('user')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_interact_as_actor')) {
|
||||
if (! function_exists('set_interact_as_actor')) {
|
||||
/**
|
||||
* Sets the actor id of which the user is acting as
|
||||
*/
|
||||
|
|
@ -37,7 +37,7 @@ if (!function_exists('set_interact_as_actor')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('remove_interact_as_actor')) {
|
||||
if (! function_exists('remove_interact_as_actor')) {
|
||||
/**
|
||||
* Removes the actor id of which the user is acting as
|
||||
*/
|
||||
|
|
@ -48,7 +48,7 @@ if (!function_exists('remove_interact_as_actor')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('interact_as_actor_id')) {
|
||||
if (! function_exists('interact_as_actor_id')) {
|
||||
/**
|
||||
* Sets the podcast id of which the user is acting as
|
||||
*/
|
||||
|
|
@ -62,27 +62,25 @@ if (!function_exists('interact_as_actor_id')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('interact_as_actor')) {
|
||||
if (! function_exists('interact_as_actor')) {
|
||||
/**
|
||||
* Get the actor the user is currently interacting as
|
||||
*/
|
||||
function interact_as_actor(): Actor|false
|
||||
function interact_as_actor(): Actor | false
|
||||
{
|
||||
$authenticate = Services::authentication();
|
||||
$authenticate->check();
|
||||
|
||||
$session = session();
|
||||
if ($session->has('interact_as_actor_id')) {
|
||||
return model('ActorModel')->getActorById(
|
||||
$session->get('interact_as_actor_id'),
|
||||
);
|
||||
return model('ActorModel')->getActorById($session->get('interact_as_actor_id'),);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('can_user_interact')) {
|
||||
if (! function_exists('can_user_interact')) {
|
||||
/**
|
||||
* @throws DataException
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use Config\Services;
|
||||
|
||||
if (!function_exists('render_breadcrumb')) {
|
||||
if (! function_exists('render_breadcrumb')) {
|
||||
/**
|
||||
* Renders the breadcrumb navigation through the Breadcrumb service
|
||||
*
|
||||
|
|
@ -22,7 +22,7 @@ if (!function_exists('render_breadcrumb')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('replace_breadcrumb_params')) {
|
||||
if (! function_exists('replace_breadcrumb_params')) {
|
||||
/**
|
||||
* @param string[] $newParams
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
use App\Entities\Location;
|
||||
use App\Entities\Person;
|
||||
use CodeIgniter\View\Table;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use CodeIgniter\View\Table;
|
||||
|
||||
if (!function_exists('button')) {
|
||||
if (! function_exists('button')) {
|
||||
/**
|
||||
* Button component
|
||||
*
|
||||
|
|
@ -92,36 +92,27 @@ if (!function_exists('button')) {
|
|||
}
|
||||
|
||||
if ($uri !== '') {
|
||||
return anchor(
|
||||
$uri,
|
||||
$label,
|
||||
array_merge(
|
||||
[
|
||||
'class' => $buttonClass,
|
||||
],
|
||||
$customAttributes,
|
||||
),
|
||||
);
|
||||
return anchor($uri, $label, array_merge([
|
||||
'class' => $buttonClass,
|
||||
], $customAttributes,),);
|
||||
}
|
||||
|
||||
$defaultButtonAttributes = [
|
||||
'type' => 'button',
|
||||
];
|
||||
$attributes = stringify_attributes(
|
||||
array_merge($defaultButtonAttributes, $customAttributes),
|
||||
);
|
||||
$attributes = stringify_attributes(array_merge($defaultButtonAttributes, $customAttributes),);
|
||||
|
||||
return <<<HTML
|
||||
return <<<CODE_SAMPLE
|
||||
<button class="{$buttonClass}" {$attributes}>
|
||||
{$label}
|
||||
</button>
|
||||
HTML;
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('icon_button')) {
|
||||
if (! function_exists('icon_button')) {
|
||||
/**
|
||||
* Icon Button component
|
||||
*
|
||||
|
|
@ -157,7 +148,7 @@ if (!function_exists('icon_button')) {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('hint_tooltip')) {
|
||||
if (! function_exists('hint_tooltip')) {
|
||||
/**
|
||||
* Hint component
|
||||
*
|
||||
|
|
@ -182,7 +173,7 @@ if (!function_exists('hint_tooltip')) {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('data_table')) {
|
||||
if (! function_exists('data_table')) {
|
||||
/**
|
||||
* Data table component
|
||||
*
|
||||
|
|
@ -240,17 +231,14 @@ if (!function_exists('data_table')) {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('publication_pill')) {
|
||||
if (! function_exists('publication_pill')) {
|
||||
/**
|
||||
* Publication pill component
|
||||
*
|
||||
* Shows the stylized publication datetime in regards to current datetime.
|
||||
*/
|
||||
function publication_pill(
|
||||
?Time $publicationDate,
|
||||
string $publicationStatus,
|
||||
string $customClass = ''
|
||||
): string {
|
||||
function publication_pill(?Time $publicationDate, string $publicationStatus, string $customClass = ''): string
|
||||
{
|
||||
if ($publicationDate === null) {
|
||||
return '';
|
||||
}
|
||||
|
|
@ -270,10 +258,7 @@ if (!function_exists('publication_pill')) {
|
|||
'</time>',
|
||||
];
|
||||
|
||||
$label = lang(
|
||||
'Episode.publication_status.' . $publicationStatus,
|
||||
$langOptions,
|
||||
);
|
||||
$label = lang('Episode.publication_status.' . $publicationStatus, $langOptions,);
|
||||
|
||||
return '<span class="px-1 font-semibold border ' .
|
||||
$class .
|
||||
|
|
@ -287,17 +272,14 @@ if (!function_exists('publication_pill')) {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('publication_button')) {
|
||||
if (! function_exists('publication_button')) {
|
||||
/**
|
||||
* Publication button component
|
||||
*
|
||||
* Displays the appropriate publication button depending on the publication status.
|
||||
*/
|
||||
function publication_button(
|
||||
int $podcastId,
|
||||
int $episodeId,
|
||||
string $publicationStatus
|
||||
): string {
|
||||
function publication_button(int $podcastId, int $episodeId, string $publicationStatus): string
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
switch ($publicationStatus) {
|
||||
case 'not_published':
|
||||
|
|
@ -308,11 +290,7 @@ if (!function_exists('publication_button')) {
|
|||
break;
|
||||
case 'scheduled':
|
||||
$label = lang('Episode.publish_edit');
|
||||
$route = route_to(
|
||||
'episode-publish_edit',
|
||||
$podcastId,
|
||||
$episodeId,
|
||||
);
|
||||
$route = route_to('episode-publish_edit', $podcastId, $episodeId,);
|
||||
$variant = 'accent';
|
||||
$iconLeft = 'upload-cloud';
|
||||
break;
|
||||
|
|
@ -339,7 +317,7 @@ if (!function_exists('publication_button')) {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('episode_numbering')) {
|
||||
if (! function_exists('episode_numbering')) {
|
||||
/**
|
||||
* Returns relevant translated episode numbering.
|
||||
*
|
||||
|
|
@ -351,7 +329,7 @@ if (!function_exists('episode_numbering')) {
|
|||
string $class = '',
|
||||
bool $isAbbr = false
|
||||
): string {
|
||||
if (!$episodeNumber && !$seasonNumber) {
|
||||
if (! $episodeNumber && ! $seasonNumber) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
@ -391,7 +369,7 @@ if (!function_exists('episode_numbering')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('location_link')) {
|
||||
if (! function_exists('location_link')) {
|
||||
/**
|
||||
* Returns link to display from location info
|
||||
*/
|
||||
|
|
@ -417,7 +395,7 @@ if (!function_exists('location_link')) {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('person_list')) {
|
||||
if (! function_exists('person_list')) {
|
||||
/**
|
||||
* Returns list of persons images
|
||||
*
|
||||
|
|
@ -436,7 +414,7 @@ if (!function_exists('person_list')) {
|
|||
$person->information_url ?? '#',
|
||||
"<img
|
||||
src='{$person->image->thumbnail_url}'
|
||||
alt='$person->full_name'
|
||||
alt='{$person->full_name}'
|
||||
class='object-cover w-12 h-12 rounded-full' />",
|
||||
[
|
||||
'class' =>
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
if (!function_exists('form_section')) {
|
||||
if (! function_exists('form_section')) {
|
||||
/**
|
||||
* Form section
|
||||
*
|
||||
* Used to produce a responsive form section with a title and subtitle. To close section,
|
||||
* use form_section_close()
|
||||
* Used to produce a responsive form section with a title and subtitle. To close section, use form_section_close()
|
||||
*
|
||||
* @param string $title The section title
|
||||
* @param string $subtitle The section subtitle
|
||||
|
|
@ -48,11 +47,9 @@ if (!function_exists('form_section')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('form_section_close')) {
|
||||
if (! function_exists('form_section_close')) {
|
||||
/**
|
||||
* Form Section close Tag
|
||||
*
|
||||
*
|
||||
*/
|
||||
function form_section_close(string $extra = ''): string
|
||||
{
|
||||
|
|
@ -62,7 +59,7 @@ if (!function_exists('form_section_close')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('form_switch')) {
|
||||
if (! function_exists('form_switch')) {
|
||||
/**
|
||||
* Form Checkbox Switch
|
||||
*
|
||||
|
|
@ -95,7 +92,7 @@ if (!function_exists('form_switch')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('form_label')) {
|
||||
if (! function_exists('form_label')) {
|
||||
/**
|
||||
* Form Label Tag
|
||||
*
|
||||
|
|
@ -142,7 +139,7 @@ if (!function_exists('form_label')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('form_multiselect')) {
|
||||
if (! function_exists('form_multiselect')) {
|
||||
/**
|
||||
* Multi-select menu
|
||||
*
|
||||
|
|
@ -160,15 +157,9 @@ if (!function_exists('form_multiselect')) {
|
|||
'data-class' => $customExtra['class'],
|
||||
'data-select-text' => lang('Common.forms.multiSelect.selectText'),
|
||||
'data-loading-text' => lang('Common.forms.multiSelect.loadingText'),
|
||||
'data-no-results-text' => lang(
|
||||
'Common.forms.multiSelect.noResultsText',
|
||||
),
|
||||
'data-no-choices-text' => lang(
|
||||
'Common.forms.multiSelect.noChoicesText',
|
||||
),
|
||||
'data-max-item-text' => lang(
|
||||
'Common.forms.multiSelect.maxItemText',
|
||||
),
|
||||
'data-no-results-text' => lang('Common.forms.multiSelect.noResultsText',),
|
||||
'data-no-choices-text' => lang('Common.forms.multiSelect.noChoicesText',),
|
||||
'data-max-item-text' => lang('Common.forms.multiSelect.maxItemText',),
|
||||
];
|
||||
$extra = stringify_attributes(array_merge($defaultExtra, $customExtra));
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use CodeIgniter\Files\File;
|
|||
use JamesHeinrich\GetID3\GetID3;
|
||||
use JamesHeinrich\GetID3\WriteTags;
|
||||
|
||||
if (!function_exists('get_file_tags')) {
|
||||
if (! function_exists('get_file_tags')) {
|
||||
/**
|
||||
* Gets audio file metadata and ID3 info
|
||||
*
|
||||
|
|
@ -31,7 +31,7 @@ if (!function_exists('get_file_tags')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('write_audio_file_tags')) {
|
||||
if (! function_exists('write_audio_file_tags')) {
|
||||
/**
|
||||
* Write audio file metadata / ID3 tags
|
||||
*/
|
||||
|
|
@ -67,11 +67,7 @@ if (!function_exists('write_audio_file_tags')) {
|
|||
: $episode->podcast->publisher,
|
||||
],
|
||||
'album' => [$episode->podcast->title],
|
||||
'year' => [
|
||||
$episode->published_at !== null
|
||||
? $episode->published_at->format('Y')
|
||||
: '',
|
||||
],
|
||||
'year' => [$episode->published_at !== null ? $episode->published_at->format('Y') : ''],
|
||||
'genre' => ['Podcast'],
|
||||
'comment' => [$episode->description],
|
||||
'track_number' => [(string) $episode->number],
|
||||
|
|
@ -92,7 +88,8 @@ if (!function_exists('write_audio_file_tags')) {
|
|||
];
|
||||
|
||||
$TagData['attached_picture'][] = [
|
||||
'picturetypeid' => 2, // Cover. More: module.tag.id3v2.php
|
||||
// picturetypeid == Cover. More: module.tag.id3v2.php
|
||||
'picturetypeid' => 2,
|
||||
'data' => $APICdata,
|
||||
'description' => 'cover',
|
||||
'mime' => $cover->getMimeType(),
|
||||
|
|
|
|||
|
|
@ -7,28 +7,26 @@
|
|||
*/
|
||||
|
||||
use CodeIgniter\Files\File;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\HTTP\Files\UploadedFile;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
|
||||
if (!function_exists('save_media')) {
|
||||
if (! function_exists('save_media')) {
|
||||
/**
|
||||
* Saves a file to the corresponding podcast folder in `public/media`
|
||||
*
|
||||
* @param File|UploadedFile $file
|
||||
*/
|
||||
function save_media(
|
||||
File $file,
|
||||
string $folder = '',
|
||||
string $filename = ''
|
||||
): string {
|
||||
function save_media(File $file, string $folder = '', string $filename = ''): string
|
||||
{
|
||||
if (($extension = $file->getExtension()) !== '') {
|
||||
$filename = $filename . '.' . $extension;
|
||||
}
|
||||
|
||||
$mediaRoot = config('App')->mediaRoot . '/' . $folder;
|
||||
$mediaRoot = config('App')
|
||||
->mediaRoot . '/' . $folder;
|
||||
|
||||
if (!file_exists($mediaRoot)) {
|
||||
if (! file_exists($mediaRoot)) {
|
||||
mkdir($mediaRoot, 0777, true);
|
||||
touch($mediaRoot . '/index.html');
|
||||
}
|
||||
|
|
@ -40,7 +38,7 @@ if (!function_exists('save_media')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('download_file')) {
|
||||
if (! function_exists('download_file')) {
|
||||
function download_file(string $fileUrl): File
|
||||
{
|
||||
$client = Services::curlrequest();
|
||||
|
|
@ -87,13 +85,13 @@ if (!function_exists('download_file')) {
|
|||
return new File($tmpFilePath);
|
||||
}
|
||||
}
|
||||
if (!function_exists('media_path')) {
|
||||
if (! function_exists('media_path')) {
|
||||
/**
|
||||
* Prefixes the root media path to a given uri
|
||||
*
|
||||
* @param string|string[] $uri URI string or array of URI segments
|
||||
*/
|
||||
function media_path(string|array $uri = ''): string
|
||||
function media_path(string | array $uri = ''): string
|
||||
{
|
||||
// convert segment array to string
|
||||
if (is_array($uri)) {
|
||||
|
|
@ -105,13 +103,13 @@ if (!function_exists('media_path')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('media_base_url')) {
|
||||
if (! function_exists('media_base_url')) {
|
||||
/**
|
||||
* Return the media base URL to use in views
|
||||
*
|
||||
* @param string|string[] $uri URI string or array of URI segments
|
||||
*/
|
||||
function media_base_url(string|array $uri = ''): string
|
||||
function media_base_url(string | array $uri = ''): string
|
||||
{
|
||||
// convert segment array to string
|
||||
if (is_array($uri)) {
|
||||
|
|
@ -121,7 +119,8 @@ if (!function_exists('media_base_url')) {
|
|||
|
||||
return rtrim(config('App')->mediaBaseURL, '/') .
|
||||
'/' .
|
||||
config('App')->mediaRoot .
|
||||
config('App')
|
||||
->mediaRoot .
|
||||
'/' .
|
||||
$uri;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
if (!function_exists('get_browser_language')) {
|
||||
if (! function_exists('get_browser_language')) {
|
||||
/**
|
||||
* Gets the browser default language using the request header key `HTTP_ACCEPT_LANGUAGE`
|
||||
*
|
||||
|
|
@ -20,7 +20,7 @@ if (!function_exists('get_browser_language')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('slugify')) {
|
||||
if (! function_exists('slugify')) {
|
||||
function slugify(string $text): string
|
||||
{
|
||||
// replace non letter or digits by -
|
||||
|
|
@ -127,7 +127,7 @@ if (!function_exists('slugify')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('format_duration')) {
|
||||
if (! function_exists('format_duration')) {
|
||||
/**
|
||||
* Formats duration in seconds to an hh:mm:ss string
|
||||
*
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use App\Models\PageModel;
|
||||
|
||||
if (!function_exists('render_page_links')) {
|
||||
if (! function_exists('render_page_links')) {
|
||||
/**
|
||||
* Returns instance pages as links inside nav tag
|
||||
*
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use App\Entities\Category;
|
||||
use App\Entities\Podcast;
|
||||
use App\Libraries\SimpleRSSElement;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use Config\Mimes;
|
||||
use App\Entities\Podcast;
|
||||
use App\Entities\Category;
|
||||
|
||||
if (!function_exists('get_rss_feed')) {
|
||||
if (! function_exists('get_rss_feed')) {
|
||||
/**
|
||||
* Generates the rss feed for a given podcast entity
|
||||
*
|
||||
|
|
@ -34,32 +34,18 @@ if (!function_exists('get_rss_feed')) {
|
|||
|
||||
$channel = $rss->addChild('channel');
|
||||
|
||||
$atomLink = $channel->addChild(
|
||||
'atom:link',
|
||||
null,
|
||||
'http://www.w3.org/2005/Atom',
|
||||
);
|
||||
$atomLink = $channel->addChild('atom:link', null, 'http://www.w3.org/2005/Atom',);
|
||||
$atomLink->addAttribute('href', $podcast->feed_url);
|
||||
$atomLink->addAttribute('rel', 'self');
|
||||
$atomLink->addAttribute('type', 'application/rss+xml');
|
||||
|
||||
if ($podcast->new_feed_url !== null) {
|
||||
$channel->addChild(
|
||||
'new-feed-url',
|
||||
$podcast->new_feed_url,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$channel->addChild('new-feed-url', $podcast->new_feed_url, $itunesNamespace,);
|
||||
}
|
||||
|
||||
// the last build date corresponds to the creation of the feed.xml cache
|
||||
$channel->addChild(
|
||||
'lastBuildDate',
|
||||
(new Time('now'))->format(DATE_RFC1123),
|
||||
);
|
||||
$channel->addChild(
|
||||
'generator',
|
||||
'Castopod Host - https://castopod.org/',
|
||||
);
|
||||
$channel->addChild('lastBuildDate', (new Time('now'))->format(DATE_RFC1123),);
|
||||
$channel->addChild('generator', 'Castopod Host - https://castopod.org/',);
|
||||
$channel->addChild('docs', 'https://cyber.harvard.edu/rss/rss.html');
|
||||
|
||||
$channel->addChild('title', $podcast->title);
|
||||
|
|
@ -85,63 +71,31 @@ if (!function_exists('get_rss_feed')) {
|
|||
}
|
||||
}
|
||||
if ($podcast->payment_pointer !== null) {
|
||||
$valueElement = $channel->addChild(
|
||||
'value',
|
||||
null,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$valueElement = $channel->addChild('value', null, $podcastNamespace,);
|
||||
$valueElement->addAttribute('type', 'webmonetization');
|
||||
$valueElement->addAttribute('method', '');
|
||||
$valueElement->addAttribute('suggested', '');
|
||||
$recipientElement = $valueElement->addChild(
|
||||
'valueRecipient',
|
||||
null,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$recipientElement = $valueElement->addChild('valueRecipient', null, $podcastNamespace,);
|
||||
$recipientElement->addAttribute('name', $podcast->owner_name);
|
||||
$recipientElement->addAttribute('type', 'ILP');
|
||||
$recipientElement->addAttribute(
|
||||
'address',
|
||||
$podcast->payment_pointer,
|
||||
);
|
||||
$recipientElement->addAttribute('address', $podcast->payment_pointer,);
|
||||
$recipientElement->addAttribute('split', '100');
|
||||
}
|
||||
$channel
|
||||
->addChild(
|
||||
'locked',
|
||||
$podcast->is_locked ? 'yes' : 'no',
|
||||
$podcastNamespace,
|
||||
)
|
||||
->addChild('locked', $podcast->is_locked ? 'yes' : 'no', $podcastNamespace,)
|
||||
->addAttribute('owner', $podcast->owner_email);
|
||||
if ($podcast->imported_feed_url !== null) {
|
||||
$channel->addChild(
|
||||
'previousUrl',
|
||||
$podcast->imported_feed_url,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$channel->addChild('previousUrl', $podcast->imported_feed_url, $podcastNamespace,);
|
||||
}
|
||||
|
||||
foreach ($podcast->podcasting_platforms as $podcastingPlatform) {
|
||||
$podcastingPlatformElement = $channel->addChild(
|
||||
'id',
|
||||
null,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$podcastingPlatformElement->addAttribute(
|
||||
'platform',
|
||||
$podcastingPlatform->slug,
|
||||
);
|
||||
$podcastingPlatformElement = $channel->addChild('id', null, $podcastNamespace,);
|
||||
$podcastingPlatformElement->addAttribute('platform', $podcastingPlatform->slug,);
|
||||
if ($podcastingPlatform->link_content !== null) {
|
||||
$podcastingPlatformElement->addAttribute(
|
||||
'id',
|
||||
$podcastingPlatform->link_content,
|
||||
);
|
||||
$podcastingPlatformElement->addAttribute('id', $podcastingPlatform->link_content,);
|
||||
}
|
||||
if ($podcastingPlatform->link_url !== null) {
|
||||
$podcastingPlatformElement->addAttribute(
|
||||
'url',
|
||||
htmlspecialchars($podcastingPlatform->link_url),
|
||||
);
|
||||
$podcastingPlatformElement->addAttribute('url', htmlspecialchars($podcastingPlatform->link_url),);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,15 +105,9 @@ if (!function_exists('get_rss_feed')) {
|
|||
$socialPlatform->link_content,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$socialPlatformElement->addAttribute(
|
||||
'platform',
|
||||
$socialPlatform->slug,
|
||||
);
|
||||
$socialPlatformElement->addAttribute('platform', $socialPlatform->slug,);
|
||||
if ($socialPlatform->link_url !== null) {
|
||||
$socialPlatformElement->addAttribute(
|
||||
'url',
|
||||
htmlspecialchars($socialPlatform->link_url),
|
||||
);
|
||||
$socialPlatformElement->addAttribute('url', htmlspecialchars($socialPlatform->link_url),);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,15 +117,9 @@ if (!function_exists('get_rss_feed')) {
|
|||
$fundingPlatform->link_content,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$fundingPlatformElement->addAttribute(
|
||||
'platform',
|
||||
$fundingPlatform->slug,
|
||||
);
|
||||
$fundingPlatformElement->addAttribute('platform', $fundingPlatform->slug,);
|
||||
if ($fundingPlatform->link_url !== null) {
|
||||
$fundingPlatformElement->addAttribute(
|
||||
'url',
|
||||
htmlspecialchars($fundingPlatform->link_url),
|
||||
);
|
||||
$fundingPlatformElement->addAttribute('url', htmlspecialchars($fundingPlatform->link_url),);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,32 +134,19 @@ if (!function_exists('get_rss_feed')) {
|
|||
$personElement->addAttribute('img', $person->image->large_url);
|
||||
|
||||
if ($person->information_url !== null) {
|
||||
$personElement->addAttribute(
|
||||
'href',
|
||||
$person->information_url,
|
||||
);
|
||||
$personElement->addAttribute('href', $person->information_url,);
|
||||
}
|
||||
|
||||
$personElement->addAttribute(
|
||||
'role',
|
||||
htmlspecialchars(
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label",
|
||||
[],
|
||||
'en',
|
||||
),
|
||||
lang("PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", [], 'en',),
|
||||
),
|
||||
);
|
||||
|
||||
$personElement->addAttribute(
|
||||
'group',
|
||||
htmlspecialchars(
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.label",
|
||||
[],
|
||||
'en',
|
||||
),
|
||||
),
|
||||
htmlspecialchars(lang("PersonsTaxonomy.persons.{$role->group}.label", [], 'en',),),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -261,12 +190,9 @@ if (!function_exists('get_rss_feed')) {
|
|||
$image->addChild('link', $podcast->link);
|
||||
|
||||
if ($podcast->custom_rss !== null) {
|
||||
array_to_rss(
|
||||
[
|
||||
'elements' => $podcast->custom_rss,
|
||||
],
|
||||
$channel,
|
||||
);
|
||||
array_to_rss([
|
||||
'elements' => $podcast->custom_rss,
|
||||
], $channel,);
|
||||
}
|
||||
|
||||
foreach ($episodes as $episode) {
|
||||
|
|
@ -285,10 +211,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
$enclosure->addAttribute('type', $episode->audio_file_mimetype);
|
||||
|
||||
$item->addChild('guid', $episode->guid);
|
||||
$item->addChild(
|
||||
'pubDate',
|
||||
$episode->published_at->format(DATE_RFC1123),
|
||||
);
|
||||
$item->addChild('pubDate', $episode->published_at->format(DATE_RFC1123),);
|
||||
if ($episode->location !== null) {
|
||||
$locationElement = $item->addChild(
|
||||
'location',
|
||||
|
|
@ -296,37 +219,17 @@ if (!function_exists('get_rss_feed')) {
|
|||
$podcastNamespace,
|
||||
);
|
||||
if ($episode->location->geo !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'geo',
|
||||
$episode->location->geo,
|
||||
);
|
||||
$locationElement->addAttribute('geo', $episode->location->geo,);
|
||||
}
|
||||
if ($episode->location->osm !== null) {
|
||||
$locationElement->addAttribute(
|
||||
'osm',
|
||||
$episode->location->osm,
|
||||
);
|
||||
$locationElement->addAttribute('osm', $episode->location->osm,);
|
||||
}
|
||||
}
|
||||
$item->addChildWithCDATA(
|
||||
'description',
|
||||
$episode->getDescriptionHtml($serviceSlug),
|
||||
);
|
||||
$item->addChild(
|
||||
'duration',
|
||||
$episode->audio_file_duration,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$item->addChildWithCDATA('description', $episode->getDescriptionHtml($serviceSlug),);
|
||||
$item->addChild('duration', $episode->audio_file_duration, $itunesNamespace,);
|
||||
$item->addChild('link', $episode->link);
|
||||
$episodeItunesImage = $item->addChild(
|
||||
'image',
|
||||
null,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$episodeItunesImage->addAttribute(
|
||||
'href',
|
||||
$episode->image->feed_url,
|
||||
);
|
||||
$episodeItunesImage = $item->addChild('image', null, $itunesNamespace,);
|
||||
$episodeItunesImage->addAttribute('href', $episode->image->feed_url,);
|
||||
|
||||
$episode->parental_advisory &&
|
||||
$item->addChild(
|
||||
|
|
@ -340,68 +243,29 @@ if (!function_exists('get_rss_feed')) {
|
|||
$episode->number &&
|
||||
$item->addChild('episode', $episode->number, $itunesNamespace);
|
||||
$episode->season_number &&
|
||||
$item->addChild(
|
||||
'season',
|
||||
$episode->season_number,
|
||||
$itunesNamespace,
|
||||
);
|
||||
$item->addChild('season', $episode->season_number, $itunesNamespace,);
|
||||
$item->addChild('episodeType', $episode->type, $itunesNamespace);
|
||||
|
||||
if ($episode->transcript_file_url) {
|
||||
$transcriptElement = $item->addChild(
|
||||
'transcript',
|
||||
null,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$transcriptElement->addAttribute(
|
||||
'url',
|
||||
$episode->transcript_file_url,
|
||||
);
|
||||
$transcriptElement = $item->addChild('transcript', null, $podcastNamespace,);
|
||||
$transcriptElement->addAttribute('url', $episode->transcript_file_url,);
|
||||
$transcriptElement->addAttribute(
|
||||
'type',
|
||||
Mimes::guessTypeFromExtension(
|
||||
pathinfo(
|
||||
$episode->transcript_file_url,
|
||||
PATHINFO_EXTENSION,
|
||||
),
|
||||
),
|
||||
);
|
||||
$transcriptElement->addAttribute(
|
||||
'language',
|
||||
$podcast->language_code,
|
||||
Mimes::guessTypeFromExtension(pathinfo($episode->transcript_file_url, PATHINFO_EXTENSION,),),
|
||||
);
|
||||
$transcriptElement->addAttribute('language', $podcast->language_code,);
|
||||
}
|
||||
|
||||
if ($episode->chapters_file_url) {
|
||||
$chaptersElement = $item->addChild(
|
||||
'chapters',
|
||||
null,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$chaptersElement->addAttribute(
|
||||
'url',
|
||||
$episode->chapters_file_url,
|
||||
);
|
||||
$chaptersElement->addAttribute(
|
||||
'type',
|
||||
'application/json+chapters',
|
||||
);
|
||||
$chaptersElement = $item->addChild('chapters', null, $podcastNamespace,);
|
||||
$chaptersElement->addAttribute('url', $episode->chapters_file_url,);
|
||||
$chaptersElement->addAttribute('type', 'application/json+chapters',);
|
||||
}
|
||||
|
||||
foreach ($episode->soundbites as $soundbite) {
|
||||
$soundbiteElement = $item->addChild(
|
||||
'soundbite',
|
||||
$soundbite->label,
|
||||
$podcastNamespace,
|
||||
);
|
||||
$soundbiteElement->addAttribute(
|
||||
'start_time',
|
||||
$soundbite->start_time,
|
||||
);
|
||||
$soundbiteElement->addAttribute(
|
||||
'duration',
|
||||
$soundbite->duration,
|
||||
);
|
||||
$soundbiteElement = $item->addChild('soundbite', $soundbite->label, $podcastNamespace,);
|
||||
$soundbiteElement->addAttribute('start_time', $soundbite->start_time,);
|
||||
$soundbiteElement->addAttribute('duration', $soundbite->duration,);
|
||||
}
|
||||
|
||||
foreach ($episode->persons as $person) {
|
||||
|
|
@ -415,35 +279,19 @@ if (!function_exists('get_rss_feed')) {
|
|||
$personElement->addAttribute(
|
||||
'role',
|
||||
htmlspecialchars(
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label",
|
||||
[],
|
||||
'en',
|
||||
),
|
||||
lang("PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", [], 'en',),
|
||||
),
|
||||
);
|
||||
|
||||
$personElement->addAttribute(
|
||||
'group',
|
||||
htmlspecialchars(
|
||||
lang(
|
||||
"PersonsTaxonomy.persons.{$role->group}.label",
|
||||
[],
|
||||
'en',
|
||||
),
|
||||
),
|
||||
htmlspecialchars(lang("PersonsTaxonomy.persons.{$role->group}.label", [], 'en',),),
|
||||
);
|
||||
|
||||
$personElement->addAttribute(
|
||||
'img',
|
||||
$person->image->large_url,
|
||||
);
|
||||
$personElement->addAttribute('img', $person->image->large_url,);
|
||||
|
||||
if ($person->information_url !== null) {
|
||||
$personElement->addAttribute(
|
||||
'href',
|
||||
$person->information_url,
|
||||
);
|
||||
$personElement->addAttribute('href', $person->information_url,);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -452,12 +300,9 @@ if (!function_exists('get_rss_feed')) {
|
|||
$item->addChild('block', 'Yes', $itunesNamespace);
|
||||
|
||||
if ($episode->custom_rss !== null) {
|
||||
array_to_rss(
|
||||
[
|
||||
'elements' => $episode->custom_rss,
|
||||
],
|
||||
$item,
|
||||
);
|
||||
array_to_rss([
|
||||
'elements' => $episode->custom_rss,
|
||||
], $item,);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -465,7 +310,7 @@ if (!function_exists('get_rss_feed')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('add_category_tag')) {
|
||||
if (! function_exists('add_category_tag')) {
|
||||
/**
|
||||
* Adds <itunes:category> and <category> tags to node for a given category
|
||||
*/
|
||||
|
|
@ -482,22 +327,15 @@ if (!function_exists('add_category_tag')) {
|
|||
);
|
||||
|
||||
if ($category->parent !== null) {
|
||||
$itunesCategoryChild = $itunesCategory->addChild(
|
||||
'category',
|
||||
'',
|
||||
$itunesNamespace,
|
||||
);
|
||||
$itunesCategoryChild->addAttribute(
|
||||
'text',
|
||||
$category->apple_category,
|
||||
);
|
||||
$itunesCategoryChild = $itunesCategory->addChild('category', '', $itunesNamespace,);
|
||||
$itunesCategoryChild->addAttribute('text', $category->apple_category,);
|
||||
$node->addChild('category', $category->parent->apple_category);
|
||||
}
|
||||
$node->addChild('category', $category->apple_category);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('rss_to_array')) {
|
||||
if (! function_exists('rss_to_array')) {
|
||||
/**
|
||||
* Converts XML to array
|
||||
*
|
||||
|
|
@ -532,17 +370,15 @@ if (!function_exists('rss_to_array')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('array_to_rss')) {
|
||||
if (! function_exists('array_to_rss')) {
|
||||
/**
|
||||
* Inserts array (converted to XML node) in XML node
|
||||
*
|
||||
* @param array<string, mixed> $arrayNode
|
||||
* @param SimpleRSSElement $xmlNode The XML parent node where this arrayNode should be attached
|
||||
*/
|
||||
function array_to_rss(
|
||||
array $arrayNode,
|
||||
SimpleRSSElement &$xmlNode
|
||||
): SimpleRSSElement {
|
||||
function array_to_rss(array $arrayNode, SimpleRSSElement &$xmlNode): SimpleRSSElement
|
||||
{
|
||||
if (array_key_exists('elements', $arrayNode)) {
|
||||
foreach ($arrayNode['elements'] as $childArrayNode) {
|
||||
$childXmlNode = $xmlNode->addChild(
|
||||
|
|
@ -557,10 +393,7 @@ if (!function_exists('array_to_rss')) {
|
|||
$childArrayNode['attributes']
|
||||
as $attributeKey => $attributeValue
|
||||
) {
|
||||
$childXmlNode->addAttribute(
|
||||
$attributeKey,
|
||||
$attributeValue,
|
||||
);
|
||||
$childXmlNode->addAttribute($attributeKey, $attributeValue,);
|
||||
}
|
||||
}
|
||||
array_to_rss($childArrayNode, $childXmlNode);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
if (!function_exists('icon')) {
|
||||
if (! function_exists('icon')) {
|
||||
/**
|
||||
* Returns the inline svg icon
|
||||
*
|
||||
|
|
@ -18,18 +18,14 @@ if (!function_exists('icon')) {
|
|||
{
|
||||
$svgContents = file_get_contents('assets/icons/' . $name . '.svg');
|
||||
if ($class !== '') {
|
||||
$svgContents = str_replace(
|
||||
'<svg',
|
||||
'<svg class="' . $class . '"',
|
||||
$svgContents,
|
||||
);
|
||||
$svgContents = str_replace('<svg', '<svg class="' . $class . '"', $svgContents,);
|
||||
}
|
||||
|
||||
return $svgContents;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('svg')) {
|
||||
if (! function_exists('svg')) {
|
||||
/**
|
||||
* Returns the inline svg image
|
||||
*
|
||||
|
|
@ -41,11 +37,7 @@ if (!function_exists('svg')) {
|
|||
{
|
||||
$svgContents = file_get_contents('assets/images/' . $name . '.svg');
|
||||
if ($class) {
|
||||
$svgContents = str_replace(
|
||||
'<svg',
|
||||
'<svg class="' . $class . '"',
|
||||
$svgContents,
|
||||
);
|
||||
$svgContents = str_replace('<svg', '<svg class="' . $class . '"', $svgContents,);
|
||||
}
|
||||
return $svgContents;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use CodeIgniter\HTTP\URI;
|
||||
|
||||
if (!function_exists('host_url')) {
|
||||
if (! function_exists('host_url')) {
|
||||
/**
|
||||
* Return the host URL to use in views
|
||||
*/
|
||||
|
|
@ -17,7 +17,7 @@ if (!function_exists('host_url')) {
|
|||
if (isset($_SERVER['HTTP_HOST'])) {
|
||||
$protocol =
|
||||
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
|
||||
$_SERVER['SERVER_PORT'] == 443
|
||||
$_SERVER['SERVER_PORT'] === 443
|
||||
? 'https://'
|
||||
: 'http://';
|
||||
return $protocol . $_SERVER['HTTP_HOST'] . '/';
|
||||
|
|
@ -29,7 +29,7 @@ if (!function_exists('host_url')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (!function_exists('extract_params_from_episode_uri')) {
|
||||
if (! function_exists('extract_params_from_episode_uri')) {
|
||||
/**
|
||||
* Returns podcast name and episode slug from episode string
|
||||
*
|
||||
|
|
@ -48,8 +48,8 @@ if (!function_exists('extract_params_from_episode_uri')) {
|
|||
}
|
||||
|
||||
if (
|
||||
!array_key_exists('podcastName', $matches) ||
|
||||
!array_key_exists('episodeSlug', $matches)
|
||||
! array_key_exists('podcastName', $matches) ||
|
||||
! array_key_exists('episodeSlug', $matches)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
return [
|
||||
'label' => 'breadcrumb',
|
||||
config('App')->adminGateway => 'Home',
|
||||
config('App')
|
||||
->adminGateway => 'Home',
|
||||
'podcasts' => 'podcasts',
|
||||
'episodes' => 'episodes',
|
||||
'contributors' => 'contributors',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/**
|
||||
* ISO 3166 country codes
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
return [
|
||||
'label' => 'Fil d’Ariane',
|
||||
config('App')->adminGateway => 'Accueil',
|
||||
config('App')
|
||||
->adminGateway => 'Accueil',
|
||||
'podcasts' => 'podcasts',
|
||||
'episodes' => 'épisodes',
|
||||
'contributors' => 'contributeurs',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/**
|
||||
* ISO 3166 country codes
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -27,9 +25,6 @@ class AnnounceActivity extends Activity
|
|||
|
||||
$this->published = $reblogNote->published_at->format(DATE_W3C);
|
||||
|
||||
$this->cc = [
|
||||
$reblogNote->actor->uri,
|
||||
$reblogNote->actor->followers_url,
|
||||
];
|
||||
$this->cc = [$reblogNote->actor->uri, $reblogNote->actor->followers_url];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -8,18 +8,20 @@
|
|||
|
||||
namespace ActivityPub;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\HTTP\CURLRequest;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use ActivityPub\Core\Activity;
|
||||
use Config\Services;
|
||||
use CodeIgniter\HTTP\CURLRequest;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use Config\Services;
|
||||
use phpseclib\Crypt\RSA;
|
||||
|
||||
class ActivityRequest
|
||||
{
|
||||
protected CURLRequest $request;
|
||||
|
||||
protected URI $uri;
|
||||
|
||||
protected ?Activity $activity;
|
||||
|
||||
/**
|
||||
|
|
@ -28,7 +30,8 @@ class ActivityRequest
|
|||
protected array $options = [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/activity+json',
|
||||
'Accept' => 'application/activity+json', // TODO: outgoing and incoming requests
|
||||
'Accept' => 'application/activity+json',
|
||||
// TODO: outgoing and incoming requests
|
||||
],
|
||||
];
|
||||
|
||||
|
|
@ -63,7 +66,7 @@ class ActivityRequest
|
|||
public function sign(string $keyId, string $privateKey): void
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey($privateKey); // private key
|
||||
$rsa->loadKey($privateKey);
|
||||
$rsa->setHash('sha256');
|
||||
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ $routes->addPlaceholder('noteAction', '\bfavourite|\breblog|\breply');
|
|||
* ActivityPub routes file
|
||||
*/
|
||||
|
||||
$routes->group('', ['namespace' => 'ActivityPub\Controllers'], function (
|
||||
$routes
|
||||
): void {
|
||||
$routes->group('', [
|
||||
'namespace' => 'ActivityPub\Controllers',
|
||||
], function ($routes): void {
|
||||
// webfinger
|
||||
$routes->get('.well-known/webfinger', 'WebFingerController', [
|
||||
'as' => 'webfinger',
|
||||
|
|
@ -77,13 +77,17 @@ $routes->group('', ['namespace' => 'ActivityPub\Controllers'], function (
|
|||
$routes->post(
|
||||
'fediverse-block-actor',
|
||||
'BlockController::attemptBlockActor',
|
||||
['as' => 'fediverse-attempt-block-actor'],
|
||||
[
|
||||
'as' => 'fediverse-attempt-block-actor',
|
||||
],
|
||||
);
|
||||
|
||||
$routes->post(
|
||||
'fediverse-block-domain',
|
||||
'BlockController::attemptBlockDomain',
|
||||
['as' => 'fediverse-attempt-block-domain'],
|
||||
[
|
||||
'as' => 'fediverse-attempt-block-domain',
|
||||
],
|
||||
);
|
||||
|
||||
$routes->post(
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@
|
|||
namespace ActivityPub\Controllers;
|
||||
|
||||
use ActivityPub\Config\ActivityPub;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Objects\OrderedCollectionObject;
|
||||
use ActivityPub\Objects\OrderedCollectionPage;
|
||||
use App\Entities\Actor;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
class ActorController extends Controller
|
||||
|
|
@ -27,6 +27,7 @@ class ActorController extends Controller
|
|||
protected $helpers = ['activitypub'];
|
||||
|
||||
protected Actor $actor;
|
||||
|
||||
protected ActivityPub $config;
|
||||
|
||||
public function __construct()
|
||||
|
|
@ -38,15 +39,13 @@ class ActorController extends Controller
|
|||
{
|
||||
if (
|
||||
count($params) > 0 &&
|
||||
!($this->actor = model('ActorModel')->getActorByUsername(
|
||||
$params[0],
|
||||
))
|
||||
! ($this->actor = model('ActorModel')->getActorByUsername($params[0],))
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
unset($params[0]);
|
||||
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
public function index(): RedirectResponse
|
||||
|
|
@ -71,25 +70,26 @@ class ActorController extends Controller
|
|||
$payloadActor = get_or_create_actor_from_uri($payload->actor);
|
||||
|
||||
// store activity to database
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
$payload->type,
|
||||
$payloadActor->id,
|
||||
$this->actor->id,
|
||||
null,
|
||||
json_encode($payload, JSON_THROW_ON_ERROR),
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
$payload->type,
|
||||
$payloadActor->id,
|
||||
$this->actor->id,
|
||||
null,
|
||||
json_encode($payload, JSON_THROW_ON_ERROR),
|
||||
);
|
||||
|
||||
// switch/case on activity type
|
||||
/** @phpstan-ignore-next-line */
|
||||
switch ($payload->type) {
|
||||
case 'Create':
|
||||
if ($payload->object->type == 'Note') {
|
||||
if (!$payload->object->inReplyTo) {
|
||||
return $this->response->setStatusCode(501)->setJSON([]);
|
||||
if ($payload->object->type === 'Note') {
|
||||
if (! $payload->object->inReplyTo) {
|
||||
return $this->response->setStatusCode(501)
|
||||
->setJSON([]);
|
||||
}
|
||||
$replyToNote = model('NoteModel')->getNoteByUri(
|
||||
$payload->object->inReplyTo,
|
||||
);
|
||||
$replyToNote = model('NoteModel')
|
||||
->getNoteByUri($payload->object->inReplyTo,);
|
||||
// TODO: strip content from html to retrieve message
|
||||
// remove all html tags and reconstruct message with mentions?
|
||||
extract_text_from_html($payload->object->content);
|
||||
|
|
@ -98,103 +98,103 @@ class ActorController extends Controller
|
|||
'actor_id' => $payloadActor->id,
|
||||
'in_reply_to_id' => $replyToNote->id,
|
||||
'message' => $payload->object->content,
|
||||
'published_at' => Time::parse(
|
||||
$payload->object->published,
|
||||
),
|
||||
'published_at' => Time::parse($payload->object->published,),
|
||||
]);
|
||||
$noteId = model('NoteModel')->addReply($reply, true, false);
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'note_id' => service('uuid')
|
||||
->fromBytes($noteId)
|
||||
->getString(),
|
||||
]);
|
||||
return $this->response->setStatusCode(200)->setJSON([]);
|
||||
$noteId = model('NoteModel')
|
||||
->addReply($reply, true, false);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'note_id' => service('uuid')
|
||||
->fromBytes($noteId)
|
||||
->getString(),
|
||||
]);
|
||||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
}
|
||||
// return not handled undo error (501 = not implemented)
|
||||
return $this->response->setStatusCode(501)->setJSON([]);
|
||||
return $this->response->setStatusCode(501)
|
||||
->setJSON([]);
|
||||
case 'Delete':
|
||||
$noteToDelete = model('NoteModel')->getNoteByUri(
|
||||
$payload->object->id,
|
||||
);
|
||||
$noteToDelete = model('NoteModel')
|
||||
->getNoteByUri($payload->object->id,);
|
||||
|
||||
model('NoteModel')->removeNote($noteToDelete, false);
|
||||
model('NoteModel')
|
||||
->removeNote($noteToDelete, false);
|
||||
|
||||
return $this->response->setStatusCode(200)->setJSON([]);
|
||||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
case 'Follow':
|
||||
// add to followers table
|
||||
model('FollowModel')->addFollower(
|
||||
$payloadActor,
|
||||
$this->actor,
|
||||
false,
|
||||
);
|
||||
model('FollowModel')
|
||||
->addFollower($payloadActor, $this->actor, false,);
|
||||
|
||||
// Automatically accept follow by returning accept activity
|
||||
accept_follow($this->actor, $payloadActor, $payload->id);
|
||||
|
||||
// TODO: return 202 (Accepted) followed!
|
||||
return $this->response->setStatusCode(202)->setJSON([]);
|
||||
return $this->response->setStatusCode(202)
|
||||
->setJSON([]);
|
||||
|
||||
case 'Like':
|
||||
// get favourited note
|
||||
$note = model('NoteModel')->getNoteByUri($payload->object);
|
||||
$note = model('NoteModel')
|
||||
->getNoteByUri($payload->object);
|
||||
|
||||
// Like side-effect
|
||||
model('FavouriteModel')->addFavourite(
|
||||
$payloadActor,
|
||||
$note,
|
||||
false,
|
||||
);
|
||||
model('FavouriteModel')
|
||||
->addFavourite($payloadActor, $note, false,);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
|
||||
return $this->response->setStatusCode(200)->setJSON([]);
|
||||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
case 'Announce':
|
||||
$note = model('NoteModel')->getNoteByUri($payload->object);
|
||||
$note = model('NoteModel')
|
||||
->getNoteByUri($payload->object);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
|
||||
model('NoteModel')->reblog($payloadActor, $note, false);
|
||||
model('NoteModel')
|
||||
->reblog($payloadActor, $note, false);
|
||||
|
||||
return $this->response->setStatusCode(200)->setJSON([]);
|
||||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
case 'Undo':
|
||||
// switch/case on the type of activity to undo
|
||||
/** @phpstan-ignore-next-line */
|
||||
switch ($payload->object->type) {
|
||||
case 'Follow':
|
||||
// revert side-effect by removing follow from database
|
||||
model('FollowModel')->removeFollower(
|
||||
$payloadActor,
|
||||
$this->actor,
|
||||
false,
|
||||
);
|
||||
model('FollowModel')
|
||||
->removeFollower($payloadActor, $this->actor, false,);
|
||||
|
||||
// TODO: undo has been accepted! (202 - Accepted)
|
||||
return $this->response->setStatusCode(202)->setJSON([]);
|
||||
return $this->response->setStatusCode(202)
|
||||
->setJSON([]);
|
||||
case 'Like':
|
||||
$note = model('NoteModel')->getNoteByUri(
|
||||
$payload->object->object,
|
||||
);
|
||||
$note = model('NoteModel')
|
||||
->getNoteByUri($payload->object->object,);
|
||||
|
||||
// revert side-effect by removing favourite from database
|
||||
model('FavouriteModel')->removeFavourite(
|
||||
$payloadActor,
|
||||
$note,
|
||||
false,
|
||||
);
|
||||
model('FavouriteModel')
|
||||
->removeFavourite($payloadActor, $note, false,);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
|
||||
return $this->response->setStatusCode(200)->setJSON([]);
|
||||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
case 'Announce':
|
||||
$note = model('NoteModel')->getNoteByUri(
|
||||
$payload->object->object,
|
||||
);
|
||||
$note = model('NoteModel')
|
||||
->getNoteByUri($payload->object->object,);
|
||||
|
||||
$reblogNote = model('NoteModel')
|
||||
->where([
|
||||
|
|
@ -205,20 +205,26 @@ class ActorController extends Controller
|
|||
])
|
||||
->first();
|
||||
|
||||
model('NoteModel')->undoReblog($reblogNote, false);
|
||||
model('NoteModel')
|
||||
->undoReblog($reblogNote, false);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'note_id' => $note->id,
|
||||
]);
|
||||
|
||||
return $this->response->setStatusCode(200)->setJSON([]);
|
||||
return $this->response->setStatusCode(200)
|
||||
->setJSON([]);
|
||||
default:
|
||||
// return not handled undo error (501 = not implemented)
|
||||
return $this->response->setStatusCode(501)->setJSON([]);
|
||||
return $this->response->setStatusCode(501)
|
||||
->setJSON([]);
|
||||
}
|
||||
// no break
|
||||
default:
|
||||
// return not handled activity error (501 = not implemented)
|
||||
return $this->response->setStatusCode(501)->setJSON([]);
|
||||
return $this->response->setStatusCode(501)
|
||||
->setJSON([]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,16 +238,12 @@ class ActorController extends Controller
|
|||
|
||||
$pageNumber = $this->request->getGet('page');
|
||||
|
||||
if (!isset($pageNumber)) {
|
||||
if (! isset($pageNumber)) {
|
||||
$actorActivity->paginate(12);
|
||||
$pager = $actorActivity->pager;
|
||||
$collection = new OrderedCollectionObject(null, $pager);
|
||||
} else {
|
||||
$paginatedActivity = $actorActivity->paginate(
|
||||
12,
|
||||
'default',
|
||||
$pageNumber,
|
||||
);
|
||||
$paginatedActivity = $actorActivity->paginate(12, 'default', $pageNumber,);
|
||||
$pager = $actorActivity->pager;
|
||||
$orderedItems = [];
|
||||
foreach ($paginatedActivity as $activity) {
|
||||
|
|
@ -259,36 +261,25 @@ class ActorController extends Controller
|
|||
{
|
||||
// get followers for a specific actor
|
||||
$followers = model('ActorModel')
|
||||
->join(
|
||||
'activitypub_follows',
|
||||
'activitypub_follows.actor_id = id',
|
||||
'inner',
|
||||
)
|
||||
->join('activitypub_follows', 'activitypub_follows.actor_id = id', 'inner',)
|
||||
->where('activitypub_follows.target_actor_id', $this->actor->id)
|
||||
->orderBy('activitypub_follows.created_at', 'DESC');
|
||||
|
||||
$pageNumber = $this->request->getGet('page');
|
||||
|
||||
if (!isset($pageNumber)) {
|
||||
if (! isset($pageNumber)) {
|
||||
$followers->paginate(12);
|
||||
$pager = $followers->pager;
|
||||
$followersCollection = new OrderedCollectionObject(null, $pager);
|
||||
} else {
|
||||
$paginatedFollowers = $followers->paginate(
|
||||
12,
|
||||
'default',
|
||||
$pageNumber,
|
||||
);
|
||||
$paginatedFollowers = $followers->paginate(12, 'default', $pageNumber,);
|
||||
$pager = $followers->pager;
|
||||
|
||||
$orderedItems = [];
|
||||
foreach ($paginatedFollowers as $follower) {
|
||||
$orderedItems[] = $follower->uri;
|
||||
}
|
||||
$followersCollection = new OrderedCollectionPage(
|
||||
$pager,
|
||||
$orderedItems,
|
||||
);
|
||||
$followersCollection = new OrderedCollectionPage($pager, $orderedItems,);
|
||||
}
|
||||
|
||||
return $this->response
|
||||
|
|
@ -296,14 +287,14 @@ class ActorController extends Controller
|
|||
->setBody($followersCollection->toJSON());
|
||||
}
|
||||
|
||||
public function attemptFollow(): RedirectResponse|ResponseInterface
|
||||
public function attemptFollow(): RedirectResponse | ResponseInterface
|
||||
{
|
||||
$rules = [
|
||||
'handle' =>
|
||||
'regex_match[/^@?(?P<username>[\w\.\-]+)@(?P<host>[\w\.\-]+)(?P<port>:[\d]+)?$/]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -317,8 +308,8 @@ class ActorController extends Controller
|
|||
// check if actor and domain exist
|
||||
|
||||
if (
|
||||
!($parts = split_handle($this->request->getPost('handle'))) ||
|
||||
!($data = get_webfinger_data($parts['username'], $parts['domain']))
|
||||
! ($parts = split_handle($this->request->getPost('handle'))) ||
|
||||
! ($data = get_webfinger_data($parts['username'], $parts['domain']))
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -329,27 +320,24 @@ class ActorController extends Controller
|
|||
$ostatusKey = array_search(
|
||||
'http://ostatus.org/schema/1.0/subscribe',
|
||||
array_column($data->links, 'rel'),
|
||||
true,
|
||||
);
|
||||
|
||||
if (!$ostatusKey) {
|
||||
if (! $ostatusKey) {
|
||||
// TODO: error, couldn't subscribe to activitypub account
|
||||
// The instance doesn't allow its users to follow others
|
||||
return $this->response->setJSON([]);
|
||||
}
|
||||
|
||||
return redirect()->to(
|
||||
str_replace(
|
||||
'{uri}',
|
||||
urlencode($this->actor->uri),
|
||||
$data->links[$ostatusKey]->template,
|
||||
),
|
||||
str_replace('{uri}', urlencode($this->actor->uri), $data->links[$ostatusKey]->template,),
|
||||
);
|
||||
}
|
||||
|
||||
public function activity(string $activityId): RedirectResponse
|
||||
{
|
||||
if (
|
||||
!($activity = model('ActivityModel')->getActivityById($activityId))
|
||||
! ($activity = model('ActivityModel')->getActivityById($activityId))
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace ActivityPub\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
|
||||
class BlockController extends Controller
|
||||
{
|
||||
|
|
@ -24,7 +24,7 @@ class BlockController extends Controller
|
|||
'handle' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -35,10 +35,7 @@ class BlockController extends Controller
|
|||
|
||||
if ($parts = split_handle($handle)) {
|
||||
if (
|
||||
($actor = get_or_create_actor(
|
||||
$parts['username'],
|
||||
$parts['domain'],
|
||||
)) === null
|
||||
($actor = get_or_create_actor($parts['username'], $parts['domain'],)) === null
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -46,66 +43,66 @@ class BlockController extends Controller
|
|||
->with('error', 'Actor not found.');
|
||||
}
|
||||
|
||||
model('ActorModel')->blockActor($actor->id);
|
||||
model('ActorModel')
|
||||
->blockActor($actor->id);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
function attemptBlockDomain(): RedirectResponse
|
||||
public function attemptBlockDomain(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'domain' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
model('BlockedDomainModel')->blockDomain(
|
||||
$this->request->getPost('domain'),
|
||||
);
|
||||
model('BlockedDomainModel')
|
||||
->blockDomain($this->request->getPost('domain'),);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
function attemptUnblockActor(): RedirectResponse
|
||||
public function attemptUnblockActor(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'actor_id' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
model('ActorModel')->unblockActor($this->request->getPost('actor_id'));
|
||||
model('ActorModel')
|
||||
->unblockActor($this->request->getPost('actor_id'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
function attemptUnblockDomain(): RedirectResponse
|
||||
public function attemptUnblockDomain(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'domain' => 'required',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
model('BlockedDomainModel')->unblockDomain(
|
||||
$this->request->getPost('domain'),
|
||||
);
|
||||
model('BlockedDomainModel')
|
||||
->unblockDomain($this->request->getPost('domain'),);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,14 @@
|
|||
|
||||
namespace ActivityPub\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Config\ActivityPub;
|
||||
use ActivityPub\Models\NoteModel;
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Objects\OrderedCollectionObject;
|
||||
use ActivityPub\Objects\OrderedCollectionPage;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
||||
class NoteController extends Controller
|
||||
|
|
@ -27,6 +26,7 @@ class NoteController extends Controller
|
|||
protected $helpers = ['activitypub'];
|
||||
|
||||
protected Note $note;
|
||||
|
||||
protected ActivityPub $config;
|
||||
|
||||
public function __construct()
|
||||
|
|
@ -36,12 +36,12 @@ class NoteController extends Controller
|
|||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
{
|
||||
if (!($this->note = model('NoteModel')->getNoteById($params[0]))) {
|
||||
if (! ($this->note = model('NoteModel')->getNoteById($params[0]))) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
unset($params[0]);
|
||||
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
public function index(): RedirectResponse
|
||||
|
|
@ -56,29 +56,22 @@ class NoteController extends Controller
|
|||
|
||||
public function replies(): RedirectResponse
|
||||
{
|
||||
/** get note replies */
|
||||
/**
|
||||
* get note replies
|
||||
*/
|
||||
$noteReplies = model('NoteModel')
|
||||
->where(
|
||||
'in_reply_to_id',
|
||||
service('uuid')
|
||||
->fromString($this->note->id)
|
||||
->getBytes(),
|
||||
)
|
||||
->where('in_reply_to_id', service('uuid') ->fromString($this->note->id) ->getBytes(),)
|
||||
->where('`published_at` <= NOW()', null, false)
|
||||
->orderBy('published_at', 'ASC');
|
||||
|
||||
$pageNumber = $this->request->getGet('page');
|
||||
|
||||
if (!isset($pageNumber)) {
|
||||
if (! isset($pageNumber)) {
|
||||
$noteReplies->paginate(12);
|
||||
$pager = $noteReplies->pager;
|
||||
$collection = new OrderedCollectionObject(null, $pager);
|
||||
} else {
|
||||
$paginatedReplies = $noteReplies->paginate(
|
||||
12,
|
||||
'default',
|
||||
$pageNumber,
|
||||
);
|
||||
$paginatedReplies = $noteReplies->paginate(12, 'default', $pageNumber,);
|
||||
$pager = $noteReplies->pager;
|
||||
|
||||
$orderedItems = [];
|
||||
|
|
@ -106,7 +99,7 @@ class NoteController extends Controller
|
|||
'message' => 'required|max_length[500]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -119,7 +112,7 @@ class NoteController extends Controller
|
|||
'published_at' => Time::now(),
|
||||
]);
|
||||
|
||||
if (!model('NoteModel')->addNote($newNote)) {
|
||||
if (! model('NoteModel')->addNote($newNote)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -137,18 +130,18 @@ class NoteController extends Controller
|
|||
'actor_id' => 'required|is_natural_no_zero',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$actor = model('ActorModel')->getActorById(
|
||||
$this->request->getPost('actor_id'),
|
||||
);
|
||||
$actor = model('ActorModel')
|
||||
->getActorById($this->request->getPost('actor_id'),);
|
||||
|
||||
model('FavouriteModel')->toggleFavourite($actor, $this->note->id);
|
||||
model('FavouriteModel')
|
||||
->toggleFavourite($actor, $this->note->id);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
@ -159,18 +152,18 @@ class NoteController extends Controller
|
|||
'actor_id' => 'required|is_natural_no_zero',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$actor = model('ActorModel')->getActorById(
|
||||
$this->request->getPost('actor_id'),
|
||||
);
|
||||
$actor = model('ActorModel')
|
||||
->getActorById($this->request->getPost('actor_id'),);
|
||||
|
||||
model('NoteModel')->toggleReblog($actor, $this->note);
|
||||
model('NoteModel')
|
||||
->toggleReblog($actor, $this->note);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
@ -182,7 +175,7 @@ class NoteController extends Controller
|
|||
'message' => 'required|max_length[500]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -196,7 +189,7 @@ class NoteController extends Controller
|
|||
'published_at' => Time::now(),
|
||||
]);
|
||||
|
||||
if (!model('NoteModel')->addReply($newReplyNote)) {
|
||||
if (! model('NoteModel')->addReply($newReplyNote)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -208,14 +201,14 @@ class NoteController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function attemptRemoteAction(string $action): RedirectResponse|ResponseInterface
|
||||
public function attemptRemoteAction(string $action): RedirectResponse | ResponseInterface
|
||||
{
|
||||
$rules = [
|
||||
'handle' =>
|
||||
'regex_match[/^@?(?P<username>[\w\.\-]+)@(?P<host>[\w\.\-]+)(?P<port>:[\d]+)?$/]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
|
|
@ -228,8 +221,8 @@ class NoteController extends Controller
|
|||
// parse activityPub id to get actor and domain
|
||||
// check if actor and domain exist
|
||||
if (
|
||||
!($parts = split_handle($this->request->getPost('handle'))) ||
|
||||
!($data = get_webfinger_data($parts['username'], $parts['domain']))
|
||||
! ($parts = split_handle($this->request->getPost('handle'))) ||
|
||||
! ($data = get_webfinger_data($parts['username'], $parts['domain']))
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
|
|
@ -240,20 +233,17 @@ class NoteController extends Controller
|
|||
$ostatusKey = array_search(
|
||||
'http://ostatus.org/schema/1.0/subscribe',
|
||||
array_column($data->links, 'rel'),
|
||||
true,
|
||||
);
|
||||
|
||||
if (!$ostatusKey) {
|
||||
if (! $ostatusKey) {
|
||||
// TODO: error, couldn't remote favourite/share/reply to note
|
||||
// The instance doesn't allow its users remote actions on notes
|
||||
return $this->response->setJSON([]);
|
||||
}
|
||||
|
||||
return redirect()->to(
|
||||
str_replace(
|
||||
'{uri}',
|
||||
urlencode($this->note->uri),
|
||||
$data->links[$ostatusKey]->template,
|
||||
),
|
||||
str_replace('{uri}', urlencode($this->note->uri), $data->links[$ostatusKey]->template,),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ class SchedulerController extends Controller
|
|||
public function activity(): void
|
||||
{
|
||||
// retrieve scheduled activities from database
|
||||
$scheduledActivities = model('ActivityModel')->getScheduledActivities();
|
||||
$scheduledActivities = model('ActivityModel')
|
||||
->getScheduledActivities();
|
||||
|
||||
// Send activity to all followers
|
||||
foreach ($scheduledActivities as $scheduledActivity) {
|
||||
|
|
@ -31,9 +32,10 @@ class SchedulerController extends Controller
|
|||
);
|
||||
|
||||
// set activity status to delivered
|
||||
model('ActivityModel')->update($scheduledActivity->id, [
|
||||
'status' => 'delivered',
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($scheduledActivity->id, [
|
||||
'status' => 'delivered',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
namespace ActivityPub\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use ActivityPub\WebFinger;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Exception;
|
||||
|
||||
class WebFingerController extends Controller
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class defines the Object which is the
|
||||
* primary base type for the Activity Streams vocabulary.
|
||||
* This class defines the Object which is the primary base type for the Activity Streams vocabulary.
|
||||
*
|
||||
* Object is a reserved word in php, so the class is named ObjectType.
|
||||
*
|
||||
|
|
@ -20,7 +19,7 @@ abstract class AbstractObject
|
|||
*/
|
||||
public function set(string $property, $value): static
|
||||
{
|
||||
$this->$property = $value;
|
||||
$this->{$property} = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -49,7 +48,7 @@ abstract class AbstractObject
|
|||
});
|
||||
}
|
||||
|
||||
public function toJSON(): string|bool
|
||||
public function toJSON(): string | bool
|
||||
{
|
||||
return json_encode($this->toArray(), JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Activity objects are specializations of the base Object type
|
||||
* that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring,
|
||||
* or may occur in the future.
|
||||
* Activity objects are specializations of the base Object type that provide information about actions that have either
|
||||
* already occurred, are in the process of occurring, or may occur in the future.
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -16,6 +14,8 @@ namespace ActivityPub\Core;
|
|||
class Activity extends ObjectType
|
||||
{
|
||||
protected string $type = 'Activity';
|
||||
|
||||
protected string $actor;
|
||||
protected string|ObjectType $object;
|
||||
|
||||
protected string | ObjectType $object;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class defines the Object which is the
|
||||
* primary base type for the Activity Streams vocabulary.
|
||||
* This class defines the Object which is the primary base type for the Activity Streams vocabulary.
|
||||
*
|
||||
* Object is a reserved word in php, so the class is named ObjectType.
|
||||
*
|
||||
|
|
@ -18,10 +17,14 @@ class ObjectType extends AbstractObject
|
|||
/**
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected string|array $context = 'https://www.w3.org/ns/activitystreams';
|
||||
protected string | array $context = 'https://www.w3.org/ns/activitystreams';
|
||||
|
||||
protected string $id;
|
||||
|
||||
protected string $type = 'Object';
|
||||
|
||||
protected string $content;
|
||||
|
||||
protected string $published;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddActors
|
||||
* Creates activitypub_actors table in database
|
||||
* Class AddActors Creates activitypub_actors table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddNotes
|
||||
* Creates activitypub_notes table in database
|
||||
* Class AddNotes Creates activitypub_notes table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -77,27 +76,9 @@ class AddNotes extends Migration
|
|||
$this->forge->addUniqueKey('uri');
|
||||
// FIXME: an actor must reblog a note only once
|
||||
// $this->forge->addUniqueKey(['actor_id', 'reblog_of_id']);
|
||||
$this->forge->addForeignKey(
|
||||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'in_reply_to_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'reblog_of_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('in_reply_to_id', 'activitypub_notes', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('reblog_of_id', 'activitypub_notes', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('activitypub_notes');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddActivities
|
||||
* Creates activitypub_activities table in database
|
||||
* Class AddActivities Creates activitypub_activities table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -59,27 +58,9 @@ class AddActivities extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addForeignKey(
|
||||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'target_actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'note_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('target_actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('note_id', 'activitypub_notes', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('activitypub_activities');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddFavourites
|
||||
* Creates activitypub_favourites table in database
|
||||
* Class AddFavourites Creates activitypub_favourites table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -27,24 +26,10 @@ class AddFavourites extends Migration
|
|||
'constraint' => 16,
|
||||
],
|
||||
]);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addPrimaryKey(['actor_id', 'note_id']);
|
||||
$this->forge->addForeignKey(
|
||||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'note_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('note_id', 'activitypub_notes', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('activitypub_favourites');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddFollowers
|
||||
* Creates activitypub_followers table in database
|
||||
* Class AddFollowers Creates activitypub_followers table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -29,24 +28,10 @@ class AddFollowers extends Migration
|
|||
'comment' => 'Actor that is followed',
|
||||
],
|
||||
]);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addPrimaryKey(['actor_id', 'target_actor_id']);
|
||||
$this->forge->addForeignKey(
|
||||
'actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'target_actor_id',
|
||||
'activitypub_actors',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('target_actor_id', 'activitypub_actors', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('activitypub_follows');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddPreviewCards
|
||||
* Creates activitypub_preview_cards table in database
|
||||
* Class AddPreviewCards Creates activitypub_preview_cards table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -31,7 +30,9 @@ class AddPreviewCards extends Migration
|
|||
'type' => 'VARCHAR',
|
||||
'constraint' => 128,
|
||||
],
|
||||
'description' => ['type' => 'TEXT'],
|
||||
'description' => [
|
||||
'type' => 'TEXT',
|
||||
],
|
||||
'type' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['link', 'video', 'image', 'rich'],
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddNotePreviewCards
|
||||
* Creates activitypub_notes_preview_cards table in database
|
||||
* Class AddNotePreviewCards Creates activitypub_notes_preview_cards table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -29,20 +28,8 @@ class AddNotesPreviewCards extends Migration
|
|||
]);
|
||||
|
||||
$this->forge->addPrimaryKey(['note_id', 'preview_card_id']);
|
||||
$this->forge->addForeignKey(
|
||||
'note_id',
|
||||
'activitypub_notes',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'preview_card_id',
|
||||
'activitypub_preview_cards',
|
||||
'id',
|
||||
'',
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey('note_id', 'activitypub_notes', 'id', '', 'CASCADE',);
|
||||
$this->forge->addForeignKey('preview_card_id', 'activitypub_preview_cards', 'id', '', 'CASCADE',);
|
||||
$this->forge->createTable('activitypub_notes_preview_cards');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddBlockedDomains
|
||||
* Creates activitypub_blocked_domains table in database
|
||||
* Class AddBlockedDomains Creates activitypub_blocked_domains table in database
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace ActivityPub\Entities;
|
||||
|
||||
use RuntimeException;
|
||||
use Michalsn\Uuid\UuidEntity;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
|
|
@ -28,7 +28,9 @@ use Michalsn\Uuid\UuidEntity;
|
|||
class Activity extends UuidEntity
|
||||
{
|
||||
protected ?Actor $actor;
|
||||
|
||||
protected ?Actor $target_actor;
|
||||
|
||||
protected ?Note $note;
|
||||
|
||||
/**
|
||||
|
|
@ -57,13 +59,12 @@ class Activity extends UuidEntity
|
|||
public function getActor(): Actor
|
||||
{
|
||||
if ($this->actor_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Activity must have an actor_id before getting the actor.',
|
||||
);
|
||||
throw new RuntimeException('Activity must have an actor_id before getting the actor.',);
|
||||
}
|
||||
|
||||
if ($this->actor === null) {
|
||||
$this->actor = model('ActorModel')->getActorById($this->actor_id);
|
||||
$this->actor = model('ActorModel')
|
||||
->getActorById($this->actor_id);
|
||||
}
|
||||
|
||||
return $this->actor;
|
||||
|
|
@ -72,15 +73,12 @@ class Activity extends UuidEntity
|
|||
public function getTargetActor(): Actor
|
||||
{
|
||||
if ($this->target_actor_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Activity must have a target_actor_id before getting the target actor.',
|
||||
);
|
||||
throw new RuntimeException('Activity must have a target_actor_id before getting the target actor.',);
|
||||
}
|
||||
|
||||
if ($this->target_actor === null) {
|
||||
$this->target_actor = model('ActorModel')->getActorById(
|
||||
$this->target_actor_id,
|
||||
);
|
||||
$this->target_actor = model('ActorModel')
|
||||
->getActorById($this->target_actor_id,);
|
||||
}
|
||||
|
||||
return $this->target_actor;
|
||||
|
|
@ -89,13 +87,12 @@ class Activity extends UuidEntity
|
|||
public function getNote(): Note
|
||||
{
|
||||
if ($this->note_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Activity must have a note_id before getting note.',
|
||||
);
|
||||
throw new RuntimeException('Activity must have a note_id before getting note.',);
|
||||
}
|
||||
|
||||
if ($this->note === null) {
|
||||
$this->note = model('NoteModel')->getNoteById($this->note_id);
|
||||
$this->note = model('NoteModel')
|
||||
->getNoteById($this->note_id);
|
||||
}
|
||||
|
||||
return $this->note;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace ActivityPub\Entities;
|
||||
|
||||
use RuntimeException;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
|
|
@ -43,6 +43,7 @@ class Actor extends Entity
|
|||
* @var Actor[]
|
||||
*/
|
||||
protected ?array $followers = null;
|
||||
|
||||
protected bool $is_local = false;
|
||||
|
||||
/**
|
||||
|
|
@ -76,7 +77,7 @@ class Actor extends Entity
|
|||
|
||||
public function getIsLocal(): bool
|
||||
{
|
||||
if (!$this->is_local) {
|
||||
if (! $this->is_local) {
|
||||
$uri = current_url(true);
|
||||
|
||||
$this->is_local =
|
||||
|
|
@ -94,15 +95,12 @@ class Actor extends Entity
|
|||
public function getFollowers(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Actor must be created before getting followers.',
|
||||
);
|
||||
throw new RuntimeException('Actor must be created before getting followers.',);
|
||||
}
|
||||
|
||||
if ($this->followers === null) {
|
||||
$this->followers = (array) model('ActorModel')->getFollowers(
|
||||
$this->id,
|
||||
);
|
||||
$this->followers = (array) model('ActorModel')
|
||||
->getFollowers($this->id,);
|
||||
}
|
||||
|
||||
return $this->followers;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
namespace ActivityPub\Entities;
|
||||
|
||||
use CodeIgniter\I18n\Time;
|
||||
use RuntimeException;
|
||||
use Michalsn\Uuid\UuidEntity;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
|
|
@ -41,11 +41,17 @@ use Michalsn\Uuid\UuidEntity;
|
|||
class Note extends UuidEntity
|
||||
{
|
||||
protected ?Actor $actor = null;
|
||||
|
||||
protected bool $is_reply = false;
|
||||
|
||||
protected ?Note $reply_to_note = null;
|
||||
|
||||
protected bool $is_reblog = false;
|
||||
|
||||
protected ?Note $reblog_of_note = null;
|
||||
|
||||
protected ?PreviewCard $preview_card = null;
|
||||
|
||||
protected bool $has_preview_card = false;
|
||||
|
||||
/**
|
||||
|
|
@ -92,13 +98,12 @@ class Note extends UuidEntity
|
|||
public function getActor(): Actor
|
||||
{
|
||||
if ($this->actor_id === null) {
|
||||
throw new RuntimeException(
|
||||
'Note must have an actor_id before getting actor.',
|
||||
);
|
||||
throw new RuntimeException('Note must have an actor_id before getting actor.',);
|
||||
}
|
||||
|
||||
if ($this->actor === null) {
|
||||
$this->actor = model('ActorModel')->getActorById($this->actor_id);
|
||||
$this->actor = model('ActorModel')
|
||||
->getActorById($this->actor_id);
|
||||
}
|
||||
|
||||
return $this->actor;
|
||||
|
|
@ -107,15 +112,12 @@ class Note extends UuidEntity
|
|||
public function getPreviewCard(): ?PreviewCard
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Note must be created before getting preview_card.',
|
||||
);
|
||||
throw new RuntimeException('Note must be created before getting preview_card.',);
|
||||
}
|
||||
|
||||
if ($this->preview_card === null) {
|
||||
$this->preview_card = model('PreviewCardModel')->getNotePreviewCard(
|
||||
$this->id,
|
||||
);
|
||||
$this->preview_card = model('PreviewCardModel')
|
||||
->getNotePreviewCard($this->id,);
|
||||
}
|
||||
|
||||
return $this->preview_card;
|
||||
|
|
@ -139,15 +141,12 @@ class Note extends UuidEntity
|
|||
public function getReplies(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Note must be created before getting replies.',
|
||||
);
|
||||
throw new RuntimeException('Note must be created before getting replies.',);
|
||||
}
|
||||
|
||||
if ($this->replies === null) {
|
||||
$this->replies = (array) model('NoteModel')->getNoteReplies(
|
||||
$this->id,
|
||||
);
|
||||
$this->replies = (array) model('NoteModel')
|
||||
->getNoteReplies($this->id,);
|
||||
}
|
||||
|
||||
return $this->replies;
|
||||
|
|
@ -158,16 +157,15 @@ class Note extends UuidEntity
|
|||
return $this->getReplies() !== null;
|
||||
}
|
||||
|
||||
public function getReplyToNote(): Note
|
||||
public function getReplyToNote(): self
|
||||
{
|
||||
if ($this->in_reply_to_id === null) {
|
||||
throw new RuntimeException('Note is not a reply.');
|
||||
}
|
||||
|
||||
if ($this->reply_to_note === null) {
|
||||
$this->reply_to_note = model('NoteModel')->getNoteById(
|
||||
$this->in_reply_to_id,
|
||||
);
|
||||
$this->reply_to_note = model('NoteModel')
|
||||
->getNoteById($this->in_reply_to_id,);
|
||||
}
|
||||
|
||||
return $this->reply_to_note;
|
||||
|
|
@ -179,15 +177,12 @@ class Note extends UuidEntity
|
|||
public function getReblogs(): array
|
||||
{
|
||||
if ($this->id === null) {
|
||||
throw new RuntimeException(
|
||||
'Note must be created before getting reblogs.',
|
||||
);
|
||||
throw new RuntimeException('Note must be created before getting reblogs.',);
|
||||
}
|
||||
|
||||
if ($this->reblogs === null) {
|
||||
$this->reblogs = (array) model('NoteModel')->getNoteReblogs(
|
||||
$this->id,
|
||||
);
|
||||
$this->reblogs = (array) model('NoteModel')
|
||||
->getNoteReblogs($this->id,);
|
||||
}
|
||||
|
||||
return $this->reblogs;
|
||||
|
|
@ -195,19 +190,18 @@ class Note extends UuidEntity
|
|||
|
||||
public function getIsReblog(): bool
|
||||
{
|
||||
return $this->reblog_of_id != null;
|
||||
return $this->reblog_of_id !== null;
|
||||
}
|
||||
|
||||
public function getReblogOfNote(): Note
|
||||
public function getReblogOfNote(): self
|
||||
{
|
||||
if ($this->reblog_of_id === null) {
|
||||
throw new RuntimeException('Note is not a reblog.');
|
||||
}
|
||||
|
||||
if ($this->reblog_of_note === null) {
|
||||
$this->reblog_of_note = model('NoteModel')->getNoteById(
|
||||
$this->reblog_of_id,
|
||||
);
|
||||
$this->reblog_of_note = model('NoteModel')
|
||||
->getNoteById($this->reblog_of_id,);
|
||||
}
|
||||
|
||||
return $this->reblog_of_note;
|
||||
|
|
@ -220,11 +214,7 @@ class Note extends UuidEntity
|
|||
$messageWithoutTags = strip_tags($message);
|
||||
|
||||
$this->attributes['message'] = $messageWithoutTags;
|
||||
$this->attributes['message_html'] = str_replace(
|
||||
"\n",
|
||||
'<br />',
|
||||
linkify($messageWithoutTags),
|
||||
);
|
||||
$this->attributes['message_html'] = str_replace("\n", '<br />', linkify($messageWithoutTags),);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,26 +2,22 @@
|
|||
|
||||
namespace ActivityPub\Filters;
|
||||
|
||||
use Config\Services;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use Exception;
|
||||
use ActivityPub\HttpSignature;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\Filters\FilterInterface;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Filters\FilterInterface;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use Config\Services;
|
||||
use Exception;
|
||||
|
||||
class ActivityPubFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Do whatever processing this filter needs to do.
|
||||
* By default it should not return anything during
|
||||
* normal execution. However, when an abnormal state
|
||||
* is found, it should return an instance of
|
||||
* CodeIgniter\HTTP\Response. If it does, script
|
||||
* execution will end and that Response will be
|
||||
* sent back to the client, allowing for error pages,
|
||||
* redirects, etc.
|
||||
* Do whatever processing this filter needs to do. By default it should not return anything during normal execution.
|
||||
* However, when an abnormal state is found, it should return an instance of CodeIgniter\HTTP\Response. If it does,
|
||||
* script execution will end and that Response will be sent back to the client, allowing for error pages, redirects,
|
||||
* etc.
|
||||
*
|
||||
* @param string[]|null $params
|
||||
* @return void|mixed
|
||||
|
|
@ -32,7 +28,7 @@ class ActivityPubFilter implements FilterInterface
|
|||
return;
|
||||
}
|
||||
|
||||
if (in_array('verify-activitystream', $params)) {
|
||||
if (in_array('verify-activitystream', $params, true)) {
|
||||
$negotiate = Services::negotiator();
|
||||
|
||||
$allowedContentTypes = [
|
||||
|
|
@ -45,7 +41,7 @@ class ActivityPubFilter implements FilterInterface
|
|||
}
|
||||
}
|
||||
|
||||
if (in_array('verify-blocks', $params)) {
|
||||
if (in_array('verify-blocks', $params, true)) {
|
||||
$payload = $request->getJSON();
|
||||
|
||||
$actorUri = $payload->actor;
|
||||
|
|
@ -62,7 +58,7 @@ class ActivityPubFilter implements FilterInterface
|
|||
}
|
||||
}
|
||||
|
||||
if (in_array('verify-signature', $params)) {
|
||||
if (in_array('verify-signature', $params, true)) {
|
||||
try {
|
||||
// securityCheck: check activity signature before handling it
|
||||
(new HttpSignature())->verify();
|
||||
|
|
@ -75,19 +71,15 @@ class ActivityPubFilter implements FilterInterface
|
|||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Allows After filters to inspect and modify the response
|
||||
* object as needed. This method does not allow any way
|
||||
* to stop execution of other after filters, short of
|
||||
* throwing an Exception or Error.
|
||||
* Allows After filters to inspect and modify the response object as needed. This method does not allow any way to
|
||||
* stop execution of other after filters, short of throwing an Exception or Error.
|
||||
*
|
||||
* @param string[]|null $arguments
|
||||
*/
|
||||
public function after(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
$arguments = null
|
||||
): void {
|
||||
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null): void
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@
|
|||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use ActivityPub\Activities\AcceptActivity;
|
||||
use ActivityPub\ActivityRequest;
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Entities\PreviewCard;
|
||||
use CodeIgniter\HTTP\Exceptions\HTTPException;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use Config\Database;
|
||||
use Essence\Essence;
|
||||
use ActivityPub\Entities\PreviewCard;
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Activities\AcceptActivity;
|
||||
use ActivityPub\ActivityRequest;
|
||||
use CodeIgniter\HTTP\Exceptions\HTTPException;
|
||||
|
||||
if (!function_exists('get_webfinger_data')) {
|
||||
if (! function_exists('get_webfinger_data')) {
|
||||
/**
|
||||
* Retrieve actor webfinger data from username and domain
|
||||
*/
|
||||
|
|
@ -30,16 +30,11 @@ if (!function_exists('get_webfinger_data')) {
|
|||
$webfingerRequest = new ActivityRequest($webfingerUri);
|
||||
$webfingerResponse = $webfingerRequest->get();
|
||||
|
||||
return json_decode(
|
||||
$webfingerResponse->getBody(),
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
return json_decode($webfingerResponse->getBody(), false, 512, JSON_THROW_ON_ERROR,);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('split_handle')) {
|
||||
if (! function_exists('split_handle')) {
|
||||
/**
|
||||
* Splits handle into its parts (username, host and port)
|
||||
*
|
||||
|
|
@ -48,11 +43,7 @@ if (!function_exists('split_handle')) {
|
|||
function split_handle(string $handle)
|
||||
{
|
||||
if (
|
||||
!preg_match(
|
||||
'~^@?(?P<username>[\w\.\-]+)@(?P<domain>[\w\.\-]+)(?P<port>:[\d]+)?$~',
|
||||
$handle,
|
||||
$matches,
|
||||
)
|
||||
! preg_match('~^@?(?P<username>[\w\.\-]+)@(?P<domain>[\w\.\-]+)(?P<port>:[\d]+)?$~', $handle, $matches,)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -61,20 +52,18 @@ if (!function_exists('split_handle')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('accept_follow')) {
|
||||
if (! function_exists('accept_follow')) {
|
||||
/**
|
||||
* Sends an accept activity to the targetActor's inbox
|
||||
*
|
||||
* @param Actor $actor Actor which accepts the follow
|
||||
* @param Actor $targetActor Actor which receives the accept follow
|
||||
*/
|
||||
function accept_follow(
|
||||
Actor $actor,
|
||||
Actor $targetActor,
|
||||
string $objectId
|
||||
): void {
|
||||
function accept_follow(Actor $actor, Actor $targetActor, string $objectId): void
|
||||
{
|
||||
$acceptActivity = new AcceptActivity();
|
||||
$acceptActivity->set('actor', $actor->uri)->set('object', $objectId);
|
||||
$acceptActivity->set('actor', $actor->uri)
|
||||
->set('object', $objectId);
|
||||
|
||||
$db = Database::connect();
|
||||
$db->transStart();
|
||||
|
|
@ -88,20 +77,14 @@ if (!function_exists('accept_follow')) {
|
|||
$acceptActivity->toJSON(),
|
||||
);
|
||||
|
||||
$acceptActivity->set(
|
||||
'id',
|
||||
url_to('activity', $actor->username, $activityId),
|
||||
);
|
||||
$acceptActivity->set('id', url_to('activity', $actor->username, $activityId),);
|
||||
|
||||
$activityModel->update($activityId, [
|
||||
'payload' => $acceptActivity->toJSON(),
|
||||
]);
|
||||
|
||||
try {
|
||||
$acceptRequest = new ActivityRequest(
|
||||
$targetActor->inbox_url,
|
||||
$acceptActivity->toJSON(),
|
||||
);
|
||||
$acceptRequest = new ActivityRequest($targetActor->inbox_url, $acceptActivity->toJSON(),);
|
||||
$acceptRequest->sign($actor->public_key_id, $actor->private_key);
|
||||
$acceptRequest->post();
|
||||
} catch (Exception) {
|
||||
|
|
@ -112,24 +95,16 @@ if (!function_exists('accept_follow')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('send_activity_to_followers')) {
|
||||
if (! function_exists('send_activity_to_followers')) {
|
||||
/**
|
||||
* Sends an activity to all actor followers
|
||||
*/
|
||||
function send_activity_to_followers(
|
||||
Actor $actor,
|
||||
string $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->public_key_id,
|
||||
$actor->private_key,
|
||||
);
|
||||
$acceptRequest = new ActivityRequest($follower->inbox_url, $activityPayload,);
|
||||
$acceptRequest->sign($actor->public_key_id, $actor->private_key,);
|
||||
$acceptRequest->post();
|
||||
} catch (Exception $e) {
|
||||
// log error
|
||||
|
|
@ -139,7 +114,7 @@ if (!function_exists('send_activity_to_followers')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('extract_urls_from_message')) {
|
||||
if (! function_exists('extract_urls_from_message')) {
|
||||
/**
|
||||
* Returns an array of all urls from a string
|
||||
*
|
||||
|
|
@ -147,17 +122,13 @@ if (!function_exists('extract_urls_from_message')) {
|
|||
*/
|
||||
function extract_urls_from_message(string $message): array
|
||||
{
|
||||
preg_match_all(
|
||||
'~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i',
|
||||
$message,
|
||||
$match,
|
||||
);
|
||||
preg_match_all('~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i', $message, $match,);
|
||||
|
||||
return $match[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('create_preview_card_from_url')) {
|
||||
if (! function_exists('create_preview_card_from_url')) {
|
||||
/**
|
||||
* Extract open graph metadata from given url and create preview card
|
||||
*/
|
||||
|
|
@ -198,10 +169,7 @@ if (!function_exists('create_preview_card_from_url')) {
|
|||
]);
|
||||
|
||||
if (
|
||||
!($newPreviewCardId = model('PreviewCardModel')->insert(
|
||||
$newPreviewCard,
|
||||
true,
|
||||
))
|
||||
! ($newPreviewCardId = model('PreviewCardModel')->insert($newPreviewCard, true,))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -215,7 +183,7 @@ if (!function_exists('create_preview_card_from_url')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_or_create_preview_card_from_url')) {
|
||||
if (! function_exists('get_or_create_preview_card_from_url')) {
|
||||
/**
|
||||
* Extract open graph metadata from given url and create preview card
|
||||
*/
|
||||
|
|
@ -223,9 +191,8 @@ if (!function_exists('get_or_create_preview_card_from_url')) {
|
|||
{
|
||||
// check if preview card has already been generated
|
||||
if (
|
||||
$previewCard = model('PreviewCardModel')->getPreviewCardFromUrl(
|
||||
(string) $url,
|
||||
)
|
||||
$previewCard = model('PreviewCardModel')
|
||||
->getPreviewCardFromUrl((string) $url,)
|
||||
) {
|
||||
return $previewCard;
|
||||
}
|
||||
|
|
@ -235,10 +202,10 @@ if (!function_exists('get_or_create_preview_card_from_url')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_or_create_actor_from_uri')) {
|
||||
if (! function_exists('get_or_create_actor_from_uri')) {
|
||||
/**
|
||||
* Retrieves actor from database using the actor uri
|
||||
* If Actor is not present, it creates the record in the database and returns it.
|
||||
* Retrieves actor from database using the actor uri If Actor is not present, it creates the record in the database
|
||||
* and returns it.
|
||||
*/
|
||||
function get_or_create_actor_from_uri(string $actorUri): ?Actor
|
||||
{
|
||||
|
|
@ -252,46 +219,38 @@ if (!function_exists('get_or_create_actor_from_uri')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_or_create_actor')) {
|
||||
if (! function_exists('get_or_create_actor')) {
|
||||
/**
|
||||
* Retrieves actor from database using the actor username and domain
|
||||
* If actor is not present, it creates the record in the database and returns it.
|
||||
* Retrieves actor from database using the actor username and domain If actor is not present, it creates the record
|
||||
* in the database and returns it.
|
||||
*/
|
||||
function get_or_create_actor(string $username, string $domain): ?Actor
|
||||
{
|
||||
// check if actor exists in database already and return it
|
||||
if (
|
||||
$actor = model('ActorModel')->getActorByUsername($username, $domain)
|
||||
$actor = model('ActorModel')
|
||||
->getActorByUsername($username, $domain)
|
||||
) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
// get actorUri with webfinger request
|
||||
$webfingerData = get_webfinger_data($username, $domain);
|
||||
$actorUriKey = array_search(
|
||||
'self',
|
||||
array_column($webfingerData->links, 'rel'),
|
||||
);
|
||||
$actorUriKey = array_search('self', array_column($webfingerData->links, 'rel'), true,);
|
||||
|
||||
return create_actor_from_uri($webfingerData->links[$actorUriKey]->href);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('create_actor_from_uri')) {
|
||||
if (! function_exists('create_actor_from_uri')) {
|
||||
/**
|
||||
* Creates actor record in database using
|
||||
* the info gathered from the actorUri parameter
|
||||
* Creates actor record in database using the info gathered from the actorUri parameter
|
||||
*/
|
||||
function create_actor_from_uri(string $actorUri): ?Actor
|
||||
{
|
||||
$activityRequest = new ActivityRequest($actorUri);
|
||||
$actorResponse = $activityRequest->get();
|
||||
$actorPayload = json_decode(
|
||||
$actorResponse->getBody(),
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
$actorPayload = json_decode($actorResponse->getBody(), false, 512, JSON_THROW_ON_ERROR,);
|
||||
|
||||
$newActor = new Actor();
|
||||
$newActor->uri = $actorUri;
|
||||
|
|
@ -314,7 +273,7 @@ if (!function_exists('create_actor_from_uri')) {
|
|||
$newActor->outbox_url = $actorPayload->outbox;
|
||||
$newActor->followers_url = $actorPayload->followers;
|
||||
|
||||
if (!($newActorId = model('ActorModel')->insert($newActor, true))) {
|
||||
if (! ($newActorId = model('ActorModel')->insert($newActor, true))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +282,7 @@ if (!function_exists('create_actor_from_uri')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_current_domain')) {
|
||||
if (! function_exists('get_current_domain')) {
|
||||
/**
|
||||
* Returns instance's domain name
|
||||
*
|
||||
|
|
@ -336,7 +295,7 @@ if (!function_exists('get_current_domain')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('extract_text_from_html')) {
|
||||
if (! function_exists('extract_text_from_html')) {
|
||||
/**
|
||||
* Extracts the text from html content
|
||||
*/
|
||||
|
|
@ -346,17 +305,14 @@ if (!function_exists('extract_text_from_html')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('linkify')) {
|
||||
if (! function_exists('linkify')) {
|
||||
/**
|
||||
* Turn all link elements in clickable links.
|
||||
* Transforms urls and handles
|
||||
* Turn all link elements in clickable links. Transforms urls and handles
|
||||
*
|
||||
* @param string[] $protocols http/https, twitter
|
||||
*/
|
||||
function linkify(
|
||||
string $text,
|
||||
array $protocols = ['http', 'handle']
|
||||
): string {
|
||||
function linkify(string $text, array $protocols = ['http', 'handle']): string
|
||||
{
|
||||
$links = [];
|
||||
|
||||
// Extract text links for each protocol
|
||||
|
|
@ -375,11 +331,7 @@ if (!function_exists('linkify')) {
|
|||
|
||||
helper('text');
|
||||
|
||||
$link = preg_replace(
|
||||
'~^www\.(.+\.)~i',
|
||||
'$1',
|
||||
$link,
|
||||
);
|
||||
$link = preg_replace('~^www\.(.+\.)~i', '$1', $link,);
|
||||
|
||||
return '<' .
|
||||
array_push(
|
||||
|
|
@ -407,10 +359,7 @@ if (!function_exists('linkify')) {
|
|||
if (
|
||||
$actor = model(
|
||||
'ActorModel',
|
||||
)->getActorByUsername(
|
||||
$match['username'],
|
||||
$match['domain'],
|
||||
)
|
||||
)->getActorByUsername($match['username'], $match['domain'],)
|
||||
) {
|
||||
// TODO: check that host is local to remove target blank?
|
||||
return '<' .
|
||||
|
|
@ -425,10 +374,7 @@ if (!function_exists('linkify')) {
|
|||
}
|
||||
|
||||
try {
|
||||
$actor = get_or_create_actor(
|
||||
$match['username'],
|
||||
$match['domain'],
|
||||
);
|
||||
$actor = get_or_create_actor($match['username'], $match['domain'],);
|
||||
return '<' .
|
||||
array_push(
|
||||
$links,
|
||||
|
|
@ -446,15 +392,11 @@ if (!function_exists('linkify')) {
|
|||
}
|
||||
} else {
|
||||
if (
|
||||
$actor = model(
|
||||
'ActorModel',
|
||||
)->getActorByUsername($match['username'])
|
||||
$actor = model('ActorModel',)
|
||||
->getActorByUsername($match['username'])
|
||||
) {
|
||||
return '<' .
|
||||
array_push(
|
||||
$links,
|
||||
anchor($actor->uri, $match[0]),
|
||||
) .
|
||||
array_push($links, anchor($actor->uri, $match[0]),) .
|
||||
'>';
|
||||
}
|
||||
|
||||
|
|
@ -476,7 +418,7 @@ if (!function_exists('linkify')) {
|
|||
array_push(
|
||||
$links,
|
||||
anchor(
|
||||
"{$protocol}://$match[1]",
|
||||
"{$protocol}://{$match[1]}",
|
||||
$match[1],
|
||||
[
|
||||
'target' => '_blank',
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is based on the HttpSignature file from the ActivityPhp package.
|
||||
* It is adapted to work with CodeIgniter4
|
||||
* This file is based on the HttpSignature file from the ActivityPhp package. It is adapted to work with CodeIgniter4
|
||||
*
|
||||
* More info: https://github.com/landrok/activitypub
|
||||
*
|
||||
|
|
@ -27,7 +26,7 @@ class HttpSignature
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
const SIGNATURE_PATTERN = '/^
|
||||
private const SIGNATURE_PATTERN = '/^
|
||||
keyId="(?P<keyId>
|
||||
(https?:\/\/[\w\-\.]+[\w]+)
|
||||
(:[\d]+)?
|
||||
|
|
@ -59,16 +58,13 @@ class HttpSignature
|
|||
*/
|
||||
public function verify(): bool
|
||||
{
|
||||
if (!($dateHeader = $this->request->header('date'))) {
|
||||
if (! ($dateHeader = $this->request->header('date'))) {
|
||||
throw new Exception('Request must include a date header.');
|
||||
}
|
||||
|
||||
// verify that request has been made within the last hour
|
||||
$currentTime = Time::now();
|
||||
$requestTime = Time::createFromFormat(
|
||||
'D, d M Y H:i:s T',
|
||||
$dateHeader->getValue(),
|
||||
);
|
||||
$requestTime = Time::createFromFormat('D, d M Y H:i:s T', $dateHeader->getValue(),);
|
||||
|
||||
$diff = $requestTime->difference($currentTime);
|
||||
if ($diff->getSeconds() > 3600) {
|
||||
|
|
@ -76,7 +72,7 @@ class HttpSignature
|
|||
}
|
||||
|
||||
// check that digest header is set
|
||||
if (!($digestHeader = $this->request->header('digest'))) {
|
||||
if (! ($digestHeader = $this->request->header('digest'))) {
|
||||
throw new Exception('Request must include a digest header');
|
||||
}
|
||||
// compute body digest and compare with header digest
|
||||
|
|
@ -93,7 +89,7 @@ class HttpSignature
|
|||
}
|
||||
|
||||
// Split it into its parts (keyId, headers and signature)
|
||||
if (!($parts = $this->splitSignature($signature))) {
|
||||
if (! ($parts = $this->splitSignature($signature))) {
|
||||
throw new Exception('Malformed signature string.');
|
||||
}
|
||||
|
||||
|
|
@ -105,12 +101,7 @@ class HttpSignature
|
|||
// Fetch the public key linked from keyId
|
||||
$actorRequest = new ActivityRequest($keyId);
|
||||
$actorResponse = $actorRequest->get();
|
||||
$actor = json_decode(
|
||||
$actorResponse->getBody(),
|
||||
false,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
$actor = json_decode($actorResponse->getBody(), false, 512, JSON_THROW_ON_ERROR,);
|
||||
|
||||
$publicKeyPem = $actor->publicKey->publicKeyPem;
|
||||
|
||||
|
|
@ -132,15 +123,15 @@ class HttpSignature
|
|||
*
|
||||
* @return array<string, string>|false
|
||||
*/
|
||||
private function splitSignature(string $signature): array|false
|
||||
private function splitSignature(string $signature): array | false
|
||||
{
|
||||
if (!preg_match(self::SIGNATURE_PATTERN, $signature, $matches)) {
|
||||
if (! preg_match(self::SIGNATURE_PATTERN, $signature, $matches)) {
|
||||
// Signature pattern failed
|
||||
return false;
|
||||
}
|
||||
|
||||
// Headers are optional
|
||||
if (!isset($matches['headers']) || $matches['headers'] == '') {
|
||||
if (! isset($matches['headers']) || $matches['headers'] === '') {
|
||||
$matches['headers'] = 'date';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ namespace ActivityPub\Models;
|
|||
|
||||
use ActivityPub\Entities\Activity;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Database\Exceptions\DataException;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use DateTimeInterface;
|
||||
use Michalsn\Uuid\UuidModel;
|
||||
|
|
@ -21,6 +20,7 @@ class ActivityModel extends UuidModel
|
|||
* @var string
|
||||
*/
|
||||
protected $table = 'activitypub_activities';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
|
@ -49,6 +49,7 @@ class ActivityModel extends UuidModel
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = Activity::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -58,16 +59,19 @@ class ActivityModel extends UuidModel
|
|||
* @var bool
|
||||
*/
|
||||
protected $useTimestamps = true;
|
||||
|
||||
protected $updatedField;
|
||||
|
||||
public function getActivityById(string $activityId): ?Activity
|
||||
{
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix . "activity#{$activityId}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
config('ActivityPub')
|
||||
->cachePrefix . "activity#{$activityId}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->find($activityId);
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -86,7 +90,7 @@ class ActivityModel extends UuidModel
|
|||
string $payload,
|
||||
DateTimeInterface $scheduledAt = null,
|
||||
?string $status = null
|
||||
): BaseResult|int|string|false {
|
||||
): BaseResult | int | string | false {
|
||||
return $this->insert(
|
||||
[
|
||||
'actor_id' => $actorId,
|
||||
|
|
@ -102,7 +106,7 @@ class ActivityModel extends UuidModel
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Activity[]
|
||||
* @return Activity[]
|
||||
*/
|
||||
public function getScheduledActivities(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
namespace ActivityPub\Models;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use CodeIgniter\Database\Exceptions\DataException;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
|
|
@ -48,6 +47,7 @@ class ActorModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = Actor::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -60,39 +60,39 @@ class ActorModel extends Model
|
|||
|
||||
public function getActorById(int $id): Actor
|
||||
{
|
||||
$cacheName = config('ActivityPub')->cachePrefix . "actor#{$id}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$cacheName = config('ActivityPub')
|
||||
->cachePrefix . "actor#{$id}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->find($id);
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for actor with username and domain,
|
||||
* if no domain has been specified, the current host will be used
|
||||
* Looks for actor with username and domain, if no domain has been specified, the current host will be used
|
||||
*/
|
||||
public function getActorByUsername(
|
||||
string $username,
|
||||
?string $domain = null
|
||||
): ?Actor {
|
||||
public function getActorByUsername(string $username, ?string $domain = null): ?Actor
|
||||
{
|
||||
// TODO: is there a better way?
|
||||
helper('activitypub');
|
||||
|
||||
if (!$domain) {
|
||||
if (! $domain) {
|
||||
$domain = get_current_domain();
|
||||
}
|
||||
|
||||
$cacheName = "actor-{$username}-{$domain}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where([
|
||||
'username' => $username,
|
||||
'domain' => $domain,
|
||||
])->first();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -102,11 +102,14 @@ class ActorModel extends Model
|
|||
{
|
||||
$hashedActorUri = md5($actorUri);
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix . "actor-{$hashedActorUri}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->where('uri', $actorUri)->first();
|
||||
config('ActivityPub')
|
||||
->cachePrefix . "actor-{$hashedActorUri}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where('uri', $actorUri)
|
||||
->first();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -118,25 +121,22 @@ class ActorModel extends Model
|
|||
public function getFollowers(int $actorId): array
|
||||
{
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix . "actor#{$actorId}_followers";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->join(
|
||||
'activitypub_follows',
|
||||
'activitypub_follows.actor_id = id',
|
||||
'inner',
|
||||
)
|
||||
config('ActivityPub')
|
||||
->cachePrefix . "actor#{$actorId}_followers";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->join('activitypub_follows', 'activitypub_follows.actor_id = id', 'inner',)
|
||||
->where('activitypub_follows.target_actor_id', $actorId)
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an existing actor is blocked using its uri.
|
||||
* Returns FALSE if the actor doesn't exist
|
||||
* Check if an existing actor is blocked using its uri. Returns FALSE if the actor doesn't exist
|
||||
*/
|
||||
public function isActorBlocked(string $actorUri): bool
|
||||
{
|
||||
|
|
@ -154,11 +154,14 @@ class ActorModel extends Model
|
|||
*/
|
||||
public function getBlockedActors(): array
|
||||
{
|
||||
$cacheName = config('ActivityPub')->cachePrefix . 'blocked_actors';
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->where('is_blocked', 1)->findAll();
|
||||
$cacheName = config('ActivityPub')
|
||||
->cachePrefix . 'blocked_actors';
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where('is_blocked', 1)
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -166,23 +169,33 @@ class ActorModel extends Model
|
|||
|
||||
public function blockActor(int $actorId): void
|
||||
{
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($prefix . 'blocked_actors');
|
||||
cache()->deleteMatching($prefix . '*replies');
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($prefix . 'blocked_actors');
|
||||
cache()
|
||||
->deleteMatching($prefix . '*replies');
|
||||
|
||||
Events::trigger('on_block_actor', $actorId);
|
||||
|
||||
$this->update($actorId, ['is_blocked' => 1]);
|
||||
$this->update($actorId, [
|
||||
'is_blocked' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function unblockActor(int $actorId): void
|
||||
{
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($prefix . 'blocked_actors');
|
||||
cache()->deleteMatching($prefix . '*replies');
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($prefix . 'blocked_actors');
|
||||
cache()
|
||||
->deleteMatching($prefix . '*replies');
|
||||
|
||||
Events::trigger('on_unblock_actor', $actorId);
|
||||
|
||||
$this->update($actorId, ['is_blocked' => 0]);
|
||||
$this->update($actorId, [
|
||||
'is_blocked' => 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace ActivityPub\Models;
|
||||
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use ActivityPub\Entities\BlockedDomain;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
|
|
@ -49,16 +49,18 @@ class BlockedDomainModel extends Model
|
|||
|
||||
/**
|
||||
* Retrieves instance or podcast domain blocks depending on whether or not $podcastId param is set.
|
||||
*
|
||||
*
|
||||
* @return BlockedDomain[]
|
||||
*/
|
||||
public function getBlockedDomains(): array
|
||||
{
|
||||
$cacheName = config('ActivityPub')->cachePrefix . 'blocked_domains';
|
||||
if (!($found = cache($cacheName))) {
|
||||
$cacheName = config('ActivityPub')
|
||||
->cachePrefix . 'blocked_domains';
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -67,25 +69,31 @@ class BlockedDomainModel extends Model
|
|||
{
|
||||
$hashedDomainName = md5($name);
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix .
|
||||
config('ActivityPub')
|
||||
->cachePrefix .
|
||||
"domain#{$hashedDomainName}_isBlocked";
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = (bool) $this->find($name);
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function blockDomain(string $name): int|bool
|
||||
public function blockDomain(string $name): int | bool
|
||||
{
|
||||
$hashedDomain = md5($name);
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($prefix . "domain#{$hashedDomain}_isBlocked");
|
||||
cache()->delete($prefix . 'blocked_domains');
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($prefix . "domain#{$hashedDomain}_isBlocked");
|
||||
cache()
|
||||
->delete($prefix . 'blocked_domains');
|
||||
|
||||
cache()->deleteMatching($prefix . '*replies');
|
||||
cache()
|
||||
->deleteMatching($prefix . '*replies');
|
||||
|
||||
Events::trigger('on_block_domain', $name);
|
||||
|
||||
|
|
@ -106,14 +114,18 @@ class BlockedDomainModel extends Model
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function unblockDomain(string $name): BaseResult|bool
|
||||
public function unblockDomain(string $name): BaseResult | bool
|
||||
{
|
||||
$hashedDomain = md5($name);
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($prefix . "domain#{$hashedDomain}_isBlocked");
|
||||
cache()->delete($prefix . 'blocked_domains');
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($prefix . "domain#{$hashedDomain}_isBlocked");
|
||||
cache()
|
||||
->delete($prefix . 'blocked_domains');
|
||||
|
||||
cache()->deleteMatching($prefix . '*replies');
|
||||
cache()
|
||||
->deleteMatching($prefix . '*replies');
|
||||
|
||||
Events::trigger('on_unblock_domain', $name);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
namespace ActivityPub\Models;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Entities\Favourite;
|
||||
use ActivityPub\Activities\LikeActivity;
|
||||
use ActivityPub\Activities\UndoActivity;
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Entities\Favourite;
|
||||
use ActivityPub\Entities\Note;
|
||||
use CodeIgniter\Events\Events;
|
||||
use Michalsn\Uuid\UuidModel;
|
||||
|
||||
|
|
@ -45,11 +45,8 @@ class FavouriteModel extends UuidModel
|
|||
|
||||
protected $updatedField;
|
||||
|
||||
public function addFavourite(
|
||||
Actor $actor,
|
||||
Note $note,
|
||||
bool $registerActivity = true
|
||||
): void {
|
||||
public function addFavourite(Actor $actor, Note $note, bool $registerActivity = true): void
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
$this->insert([
|
||||
|
|
@ -58,83 +55,76 @@ class FavouriteModel extends UuidModel
|
|||
]);
|
||||
|
||||
model('NoteModel')
|
||||
->where(
|
||||
'id',
|
||||
service('uuid')
|
||||
->fromString($note->id)
|
||||
->getBytes(),
|
||||
)
|
||||
->where('id', service('uuid') ->fromString($note->id) ->getBytes(),)
|
||||
->increment('favourites_count');
|
||||
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
$hashedNoteUri = md5($note->uri);
|
||||
cache()->delete($prefix . "note#{$note->id}");
|
||||
cache()->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()->delete($prefix . "actor#{$actor->id}_published_notes");
|
||||
cache()
|
||||
->delete($prefix . "note#{$note->id}");
|
||||
cache()
|
||||
->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($prefix . "actor#{$actor->id}_published_notes");
|
||||
|
||||
if ($note->in_reply_to_id) {
|
||||
cache()->delete($prefix . "note#{$note->in_reply_to_id}_replies");
|
||||
cache()->delete(
|
||||
$prefix . "note#{$note->in_reply_to_id}_replies_withBlocked",
|
||||
);
|
||||
cache()
|
||||
->delete($prefix . "note#{$note->in_reply_to_id}_replies_withBlocked",);
|
||||
}
|
||||
|
||||
Events::trigger('on_note_favourite', $actor, $note);
|
||||
|
||||
if ($registerActivity) {
|
||||
$likeActivity = new LikeActivity();
|
||||
$likeActivity->set('actor', $actor->uri)->set('object', $note->uri);
|
||||
$likeActivity->set('actor', $actor->uri)
|
||||
->set('object', $note->uri);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Like',
|
||||
$actor->id,
|
||||
null,
|
||||
$note->id,
|
||||
$likeActivity->toJSON(),
|
||||
$note->published_at,
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Like',
|
||||
$actor->id,
|
||||
null,
|
||||
$note->id,
|
||||
$likeActivity->toJSON(),
|
||||
$note->published_at,
|
||||
'queued',
|
||||
);
|
||||
|
||||
$likeActivity->set(
|
||||
'id',
|
||||
url_to('activity', $actor->username, $activityId),
|
||||
);
|
||||
$likeActivity->set('id', url_to('activity', $actor->username, $activityId),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $likeActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $likeActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
}
|
||||
|
||||
public function removeFavourite(
|
||||
Actor $actor,
|
||||
Note $note,
|
||||
bool $registerActivity = true
|
||||
): void {
|
||||
public function removeFavourite(Actor $actor, Note $note, bool $registerActivity = true): void
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
model('NoteModel')
|
||||
->where(
|
||||
'id',
|
||||
service('uuid')
|
||||
->fromString($note->id)
|
||||
->getBytes(),
|
||||
)
|
||||
->where('id', service('uuid') ->fromString($note->id) ->getBytes(),)
|
||||
->decrement('favourites_count');
|
||||
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
$hashedNoteUri = md5($note->uri);
|
||||
cache()->delete($prefix . "note#{$note->id}");
|
||||
cache()->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()->delete($prefix . "actor#{$actor->id}_published_notes");
|
||||
cache()
|
||||
->delete($prefix . "note#{$note->id}");
|
||||
cache()
|
||||
->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($prefix . "actor#{$actor->id}_published_notes");
|
||||
|
||||
if ($note->in_reply_to_id) {
|
||||
cache()->delete($prefix . "note#{$note->in_reply_to_id}_replies");
|
||||
cache()->delete(
|
||||
$prefix . "note#{$note->in_reply_to_id}_replies_withBlocked",
|
||||
);
|
||||
cache()
|
||||
->delete($prefix . "note#{$note->in_reply_to_id}_replies_withBlocked",);
|
||||
}
|
||||
|
||||
$this->db
|
||||
|
|
@ -164,12 +154,7 @@ class FavouriteModel extends UuidModel
|
|||
|
||||
$likeActivity = new LikeActivity();
|
||||
$likeActivity
|
||||
->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to('activity', $actor->username, $activity->id),
|
||||
),
|
||||
)
|
||||
->set('id', base_url(route_to('activity', $actor->username, $activity->id),),)
|
||||
->set('actor', $actor->uri)
|
||||
->set('object', $note->uri);
|
||||
|
||||
|
|
@ -177,24 +162,23 @@ class FavouriteModel extends UuidModel
|
|||
->set('actor', $actor->uri)
|
||||
->set('object', $likeActivity);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Undo',
|
||||
$actor->id,
|
||||
null,
|
||||
$note->id,
|
||||
$undoActivity->toJSON(),
|
||||
$note->published_at,
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Undo',
|
||||
$actor->id,
|
||||
null,
|
||||
$note->id,
|
||||
$undoActivity->toJSON(),
|
||||
$note->published_at,
|
||||
'queued',
|
||||
);
|
||||
|
||||
$undoActivity->set(
|
||||
'id',
|
||||
url_to('activity', $actor->username, $activityId),
|
||||
);
|
||||
$undoActivity->set('id', url_to('activity', $actor->username, $activityId),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $undoActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $undoActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
namespace ActivityPub\Models;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Entities\Follow;
|
||||
use Exception;
|
||||
use ActivityPub\Activities\FollowActivity;
|
||||
use ActivityPub\Activities\UndoActivity;
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Entities\Follow;
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use CodeIgniter\Model;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class FollowModel extends Model
|
||||
|
|
@ -47,11 +47,8 @@ class FollowModel extends Model
|
|||
* @param Actor $targetActor Actor that is being followed
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function addFollower(
|
||||
Actor $actor,
|
||||
Actor $targetActor,
|
||||
bool $registerActivity = true
|
||||
): void {
|
||||
public function addFollower(Actor $actor, Actor $targetActor, bool $registerActivity = true): void
|
||||
{
|
||||
try {
|
||||
$this->db->transStart();
|
||||
|
||||
|
|
@ -65,13 +62,10 @@ class FollowModel extends Model
|
|||
->where('id', $targetActor->id)
|
||||
->increment('followers_count');
|
||||
|
||||
cache()->delete(
|
||||
config('ActivityPub')->cachePrefix . "actor#{$targetActor->id}",
|
||||
);
|
||||
cache()->delete(
|
||||
config('ActivityPub')->cachePrefix .
|
||||
"actor#{$targetActor->id}_followers",
|
||||
);
|
||||
cache()
|
||||
->delete(config('ActivityPub') ->cachePrefix . "actor#{$targetActor->id}",);
|
||||
cache()
|
||||
->delete(config('ActivityPub') ->cachePrefix . "actor#{$targetActor->id}_followers",);
|
||||
|
||||
if ($registerActivity) {
|
||||
$followActivity = new FollowActivity();
|
||||
|
|
@ -80,26 +74,23 @@ class FollowModel extends Model
|
|||
->set('actor', $actor->uri)
|
||||
->set('object', $targetActor->uri);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Follow',
|
||||
$actor->id,
|
||||
$targetActor->id,
|
||||
null,
|
||||
$followActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Follow',
|
||||
$actor->id,
|
||||
$targetActor->id,
|
||||
null,
|
||||
$followActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
|
||||
$followActivity->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to('activity', $actor->username, $activityId),
|
||||
),
|
||||
);
|
||||
$followActivity->set('id', base_url(route_to('activity', $actor->username, $activityId),),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $followActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $followActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
|
@ -114,11 +105,8 @@ class FollowModel extends Model
|
|||
* @throws InvalidArgumentException
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function removeFollower(
|
||||
Actor $actor,
|
||||
Actor $targetActor,
|
||||
bool $registerActivity = true
|
||||
): void {
|
||||
public function removeFollower(Actor $actor, Actor $targetActor, bool $registerActivity = true): void
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
$this->where([
|
||||
|
|
@ -131,13 +119,10 @@ class FollowModel extends Model
|
|||
->where('id', $targetActor->id)
|
||||
->decrement('followers_count');
|
||||
|
||||
cache()->delete(
|
||||
config('ActivityPub')->cachePrefix . "actor#{$targetActor->id}",
|
||||
);
|
||||
cache()->delete(
|
||||
config('ActivityPub')->cachePrefix .
|
||||
"actor#{$targetActor->id}_followers",
|
||||
);
|
||||
cache()
|
||||
->delete(config('ActivityPub') ->cachePrefix . "actor#{$targetActor->id}",);
|
||||
cache()
|
||||
->delete(config('ActivityPub') ->cachePrefix . "actor#{$targetActor->id}_followers",);
|
||||
|
||||
if ($registerActivity) {
|
||||
$undoActivity = new UndoActivity();
|
||||
|
|
@ -154,24 +139,23 @@ class FollowModel extends Model
|
|||
->set('actor', $actor->uri)
|
||||
->set('object', $followActivity->payload);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Undo',
|
||||
$actor->id,
|
||||
$targetActor->id,
|
||||
null,
|
||||
$undoActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Undo',
|
||||
$actor->id,
|
||||
$targetActor->id,
|
||||
null,
|
||||
$undoActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
|
||||
$undoActivity->set(
|
||||
'id',
|
||||
url_to('activity', $actor->username, $activityId),
|
||||
);
|
||||
$undoActivity->set('id', url_to('activity', $actor->username, $activityId),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $undoActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $undoActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
|
|
|||
|
|
@ -8,21 +8,19 @@
|
|||
|
||||
namespace ActivityPub\Models;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use CodeIgniter\Database\Query;
|
||||
use Exception;
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Activities\AnnounceActivity;
|
||||
use ActivityPub\Activities\CreateActivity;
|
||||
use ActivityPub\Activities\DeleteActivity;
|
||||
use ActivityPub\Activities\UndoActivity;
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Objects\TombstoneObject;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Database\Query;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use CodeIgniter\Router\Exceptions\RouterException;
|
||||
use InvalidArgumentException;
|
||||
use Exception;
|
||||
use Michalsn\Uuid\UuidModel;
|
||||
|
||||
class NoteModel extends UuidModel
|
||||
|
|
@ -31,6 +29,7 @@ class NoteModel extends UuidModel
|
|||
* @var string
|
||||
*/
|
||||
protected $table = 'activitypub_notes';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
|
@ -90,11 +89,13 @@ class NoteModel extends UuidModel
|
|||
|
||||
public function getNoteById(string $noteId): ?Note
|
||||
{
|
||||
$cacheName = config('ActivityPub')->cachePrefix . "note#{$noteId}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$cacheName = config('ActivityPub')
|
||||
->cachePrefix . "note#{$noteId}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->find($noteId);
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -104,11 +105,14 @@ class NoteModel extends UuidModel
|
|||
{
|
||||
$hashedNoteUri = md5($noteUri);
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix . "note-{$hashedNoteUri}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->where('uri', $noteUri)->first();
|
||||
config('ActivityPub')
|
||||
->cachePrefix . "note-{$hashedNoteUri}";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where('uri', $noteUri)
|
||||
->first();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -122,9 +126,10 @@ class NoteModel extends UuidModel
|
|||
public function getActorPublishedNotes(int $actorId): array
|
||||
{
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix .
|
||||
config('ActivityPub')
|
||||
->cachePrefix .
|
||||
"actor#{$actorId}_published_notes";
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where([
|
||||
'actor_id' => $actorId,
|
||||
'in_reply_to_id' => null,
|
||||
|
|
@ -133,47 +138,40 @@ class NoteModel extends UuidModel
|
|||
->orderBy('published_at', 'DESC')
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all published replies for a given note.
|
||||
* By default, it does not get replies from blocked actors.
|
||||
* Retrieves all published replies for a given note. By default, it does not get replies from blocked actors.
|
||||
*
|
||||
* @return Note[]
|
||||
*/
|
||||
public function getNoteReplies(
|
||||
string $noteId,
|
||||
bool $withBlocked = false
|
||||
): array {
|
||||
public function getNoteReplies(string $noteId, bool $withBlocked = false): array
|
||||
{
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix .
|
||||
config('ActivityPub')
|
||||
->cachePrefix .
|
||||
"note#{$noteId}_replies" .
|
||||
($withBlocked ? '_withBlocked' : '');
|
||||
|
||||
if (!($found = cache($cacheName))) {
|
||||
if (!$withBlocked) {
|
||||
if (! ($found = cache($cacheName))) {
|
||||
if (! $withBlocked) {
|
||||
$this->select('activitypub_notes.*')
|
||||
->join(
|
||||
'activitypub_actors',
|
||||
'activitypub_actors.id = activitypub_notes.actor_id',
|
||||
'inner',
|
||||
)
|
||||
->join('activitypub_actors', 'activitypub_actors.id = activitypub_notes.actor_id', 'inner',)
|
||||
->where('activitypub_actors.is_blocked', 0);
|
||||
}
|
||||
|
||||
$this->where(
|
||||
'in_reply_to_id',
|
||||
$this->uuid->fromString($noteId)->getBytes(),
|
||||
)
|
||||
$this->where('in_reply_to_id', $this->uuid->fromString($noteId) ->getBytes(),)
|
||||
->where('`published_at` <= NOW()', null, false)
|
||||
->orderBy('published_at', 'ASC');
|
||||
$found = $this->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -181,35 +179,36 @@ class NoteModel extends UuidModel
|
|||
|
||||
/**
|
||||
* Retrieves all published reblogs for a given note
|
||||
*
|
||||
*
|
||||
* @return Note[]
|
||||
*/
|
||||
public function getNoteReblogs(string $noteId): array
|
||||
{
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix . "note#{$noteId}_reblogs";
|
||||
config('ActivityPub')
|
||||
->cachePrefix . "note#{$noteId}_reblogs";
|
||||
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->where(
|
||||
'reblog_of_id',
|
||||
$this->uuid->fromString($noteId)->getBytes(),
|
||||
)
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where('reblog_of_id', $this->uuid->fromString($noteId) ->getBytes(),)
|
||||
->where('`published_at` <= NOW()', null, false)
|
||||
->orderBy('published_at', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function addPreviewCard(string $noteId, int $previewCardId): Query|bool
|
||||
public function addPreviewCard(string $noteId, int $previewCardId): Query | bool
|
||||
{
|
||||
return $this->db->table('activitypub_notes_preview_cards')->insert([
|
||||
'note_id' => $this->uuid->fromString($noteId)->getBytes(),
|
||||
'preview_card_id' => $previewCardId,
|
||||
]);
|
||||
return $this->db->table('activitypub_notes_preview_cards')
|
||||
->insert([
|
||||
'note_id' => $this->uuid->fromString($noteId)
|
||||
->getBytes(),
|
||||
'preview_card_id' => $previewCardId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -221,12 +220,12 @@ class NoteModel extends UuidModel
|
|||
Note $note,
|
||||
bool $createPreviewCard = true,
|
||||
bool $registerActivity = true
|
||||
): string|false {
|
||||
): string | false {
|
||||
helper('activitypub');
|
||||
|
||||
$this->db->transStart();
|
||||
|
||||
if (!($newNoteId = $this->insert($note, true))) {
|
||||
if (! ($newNoteId = $this->insert($note, true))) {
|
||||
$this->db->transRollback();
|
||||
|
||||
// Couldn't insert note
|
||||
|
|
@ -239,10 +238,8 @@ class NoteModel extends UuidModel
|
|||
|
||||
if (
|
||||
$messageUrls !== [] &&
|
||||
($previewCard = get_or_create_preview_card_from_url(
|
||||
new URI($messageUrls[0]),
|
||||
)) &&
|
||||
!$this->addPreviewCard($newNoteId, $previewCard->id)
|
||||
($previewCard = get_or_create_preview_card_from_url(new URI($messageUrls[0]),)) &&
|
||||
! $this->addPreviewCard($newNoteId, $previewCard->id)
|
||||
) {
|
||||
$this->db->transRollback();
|
||||
// problem when linking note to preview card
|
||||
|
|
@ -254,47 +251,44 @@ class NoteModel extends UuidModel
|
|||
->where('id', $note->actor_id)
|
||||
->increment('notes_count');
|
||||
|
||||
$cachePrefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($cachePrefix . "actor#{$note->actor_id}");
|
||||
cache()->delete(
|
||||
$cachePrefix . "actor#{$note->actor_id}_published_notes",
|
||||
);
|
||||
$cachePrefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($cachePrefix . "actor#{$note->actor_id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "actor#{$note->actor_id}_published_notes",);
|
||||
|
||||
Events::trigger('on_note_add', $note);
|
||||
|
||||
if ($registerActivity) {
|
||||
// set note id and uri to construct NoteObject
|
||||
$note->id = $newNoteId;
|
||||
$note->uri = base_url(
|
||||
route_to('note', $note->actor->username, $newNoteId),
|
||||
);
|
||||
$note->uri = base_url(route_to('note', $note->actor->username, $newNoteId),);
|
||||
|
||||
$createActivity = new CreateActivity();
|
||||
$noteObjectClass = config('ActivityPub')->noteObject;
|
||||
$noteObjectClass = config('ActivityPub')
|
||||
->noteObject;
|
||||
$createActivity
|
||||
->set('actor', $note->actor->uri)
|
||||
->set('object', new $noteObjectClass($note));
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Create',
|
||||
$note->actor_id,
|
||||
null,
|
||||
$newNoteId,
|
||||
$createActivity->toJSON(),
|
||||
$note->published_at,
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Create',
|
||||
$note->actor_id,
|
||||
null,
|
||||
$newNoteId,
|
||||
$createActivity->toJSON(),
|
||||
$note->published_at,
|
||||
'queued',
|
||||
);
|
||||
|
||||
$createActivity->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to('activity', $note->actor->username, $activityId),
|
||||
),
|
||||
);
|
||||
$createActivity->set('id', base_url(route_to('activity', $note->actor->username, $activityId),),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $createActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $createActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
|
@ -318,22 +312,24 @@ class NoteModel extends UuidModel
|
|||
|
||||
// update published date in payload
|
||||
$newPayload = $scheduledActivity->payload;
|
||||
$newPayload->object->published = $updatedNote->published_at->format(
|
||||
DATE_W3C,
|
||||
);
|
||||
model('ActivityModel')->update($scheduledActivity->id, [
|
||||
'payload' => json_encode($newPayload, JSON_THROW_ON_ERROR),
|
||||
'scheduled_at' => $updatedNote->published_at,
|
||||
]);
|
||||
$newPayload->object->published = $updatedNote->published_at->format(DATE_W3C,);
|
||||
model('ActivityModel')
|
||||
->update($scheduledActivity->id, [
|
||||
'payload' => json_encode($newPayload, JSON_THROW_ON_ERROR),
|
||||
'scheduled_at' => $updatedNote->published_at,
|
||||
]);
|
||||
|
||||
// update note
|
||||
$updateResult = $this->update($updatedNote->id, $updatedNote);
|
||||
|
||||
// Clear note cache
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
$hashedNoteUri = md5($updatedNote->uri);
|
||||
cache()->delete($prefix . "note#{$updatedNote->id}");
|
||||
cache()->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($prefix . "note#{$updatedNote->id}");
|
||||
cache()
|
||||
->delete($prefix . "note-{$hashedNoteUri}");
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
|
|
@ -343,36 +339,36 @@ class NoteModel extends UuidModel
|
|||
/**
|
||||
* Removes a note from the database and decrements meta data
|
||||
*/
|
||||
public function removeNote(Note $note, bool $registerActivity = true): BaseResult|bool
|
||||
public function removeNote(Note $note, bool $registerActivity = true): BaseResult | bool
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
$cachePrefix = config('ActivityPub')->cachePrefix;
|
||||
$cachePrefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
|
||||
model('ActorModel')
|
||||
->where('id', $note->actor_id)
|
||||
->decrement('notes_count');
|
||||
cache()->delete($cachePrefix . "actor#{$note->actor_id}");
|
||||
cache()->delete(
|
||||
$cachePrefix . "actor#{$note->actor_id}_published_notes",
|
||||
);
|
||||
cache()
|
||||
->delete($cachePrefix . "actor#{$note->actor_id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "actor#{$note->actor_id}_published_notes",);
|
||||
|
||||
if ($note->in_reply_to_id) {
|
||||
// Note to remove is a reply
|
||||
model('NoteModel')
|
||||
->where(
|
||||
'id',
|
||||
$this->uuid->fromString($note->in_reply_to_id)->getBytes(),
|
||||
)
|
||||
->where('id', $this->uuid->fromString($note->in_reply_to_id) ->getBytes(),)
|
||||
->decrement('replies_count');
|
||||
|
||||
$replyToNote = $note->reply_to_note;
|
||||
cache()->delete($cachePrefix . "note#{$replyToNote->id}");
|
||||
cache()->delete($cachePrefix . "note-{$replyToNote->uri}");
|
||||
cache()->delete($cachePrefix . "note#{$replyToNote->id}_replies");
|
||||
cache()->delete(
|
||||
$cachePrefix . "note#{$replyToNote->id}_replies_withBlocked",
|
||||
);
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$replyToNote->id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note-{$replyToNote->uri}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$replyToNote->id}_replies");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$replyToNote->id}_replies_withBlocked",);
|
||||
|
||||
Events::trigger('on_reply_remove', $note);
|
||||
}
|
||||
|
|
@ -395,10 +391,7 @@ class NoteModel extends UuidModel
|
|||
->where('preview_card_id', $note->preview_card->id)
|
||||
->countAll() <= 1
|
||||
) {
|
||||
model('PreviewCardModel')->deletePreviewCard(
|
||||
$note->preview_card->id,
|
||||
$note->preview_card->url,
|
||||
);
|
||||
model('PreviewCardModel')->deletePreviewCard($note->preview_card->id, $note->preview_card->url,);
|
||||
}
|
||||
|
||||
Events::trigger('on_note_remove', $note);
|
||||
|
|
@ -411,38 +404,42 @@ class NoteModel extends UuidModel
|
|||
->set('actor', $note->actor->uri)
|
||||
->set('object', $tombstoneObject);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Delete',
|
||||
$note->actor_id,
|
||||
null,
|
||||
null,
|
||||
$deleteActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Delete',
|
||||
$note->actor_id,
|
||||
null,
|
||||
null,
|
||||
$deleteActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
|
||||
$deleteActivity->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to('activity', $note->actor->username, $activityId),
|
||||
),
|
||||
);
|
||||
$deleteActivity->set('id', base_url(route_to('activity', $note->actor->username, $activityId),),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $deleteActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $deleteActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
// clear note + replies / reblogs + actor and its published notes
|
||||
$hashedNoteUri = md5($note->uri);
|
||||
cache()->delete($cachePrefix . "note#{$note->id}");
|
||||
cache()->delete($cachePrefix . "note-{$hashedNoteUri}");
|
||||
cache()->delete($cachePrefix . "note#{$note->id}_replies");
|
||||
cache()->delete($cachePrefix . "note#{$note->id}_replies_withBlocked");
|
||||
cache()->delete($cachePrefix . "note#{$note->id}_reblogs");
|
||||
cache()->delete($cachePrefix . "note#{$note->id}_preview_card");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$note->id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$note->id}_replies");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$note->id}_replies_withBlocked");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$note->id}_reblogs");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$note->id}_preview_card");
|
||||
|
||||
$result = model('NoteModel', false)->delete($note->id);
|
||||
$result = model('NoteModel', false)
|
||||
->delete($note->id);
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
|
|
@ -453,8 +450,8 @@ class NoteModel extends UuidModel
|
|||
Note $reply,
|
||||
bool $createPreviewCard = true,
|
||||
bool $registerActivity = true
|
||||
): string|false {
|
||||
if (!$reply->in_reply_to_id) {
|
||||
): string | false {
|
||||
if (! $reply->in_reply_to_id) {
|
||||
throw new Exception('Passed note is not a reply!');
|
||||
}
|
||||
|
||||
|
|
@ -463,20 +460,20 @@ class NoteModel extends UuidModel
|
|||
$noteId = $this->addNote($reply, $createPreviewCard, $registerActivity);
|
||||
|
||||
model('NoteModel')
|
||||
->where(
|
||||
'id',
|
||||
$this->uuid->fromString($reply->in_reply_to_id)->getBytes(),
|
||||
)
|
||||
->where('id', $this->uuid->fromString($reply->in_reply_to_id) ->getBytes(),)
|
||||
->increment('replies_count');
|
||||
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
$hashedNoteUri = md5($reply->reply_to_note->uri);
|
||||
cache()->delete($prefix . "note#{$reply->in_reply_to_id}");
|
||||
cache()->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()->delete($prefix . "note#{$reply->in_reply_to_id}_replies");
|
||||
cache()->delete(
|
||||
$prefix . "note#{$reply->in_reply_to_id}_replies_withBlocked",
|
||||
);
|
||||
cache()
|
||||
->delete($prefix . "note#{$reply->in_reply_to_id}");
|
||||
cache()
|
||||
->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($prefix . "note#{$reply->in_reply_to_id}_replies");
|
||||
cache()
|
||||
->delete($prefix . "note#{$reply->in_reply_to_id}_replies_withBlocked",);
|
||||
|
||||
Events::trigger('on_note_reply', $reply);
|
||||
|
||||
|
|
@ -485,7 +482,7 @@ class NoteModel extends UuidModel
|
|||
return $noteId;
|
||||
}
|
||||
|
||||
public function reblog(Actor $actor, Note $note, bool $registerActivity = true): string|false
|
||||
public function reblog(Actor $actor, Note $note, bool $registerActivity = true): string | false
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
|
|
@ -502,44 +499,47 @@ class NoteModel extends UuidModel
|
|||
->where('id', $actor->id)
|
||||
->increment('notes_count');
|
||||
|
||||
$prefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($prefix . "actor#{$note->actor_id}");
|
||||
cache()->delete($prefix . "actor#{$note->actor_id}_published_notes");
|
||||
$prefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($prefix . "actor#{$note->actor_id}");
|
||||
cache()
|
||||
->delete($prefix . "actor#{$note->actor_id}_published_notes");
|
||||
|
||||
model('NoteModel')
|
||||
->where('id', $this->uuid->fromString($note->id)->getBytes())
|
||||
->increment('reblogs_count');
|
||||
|
||||
$hashedNoteUri = md5($note->uri);
|
||||
cache()->delete($prefix . "note#{$note->id}");
|
||||
cache()->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()->delete($prefix . "note#{$note->id}_reblogs");
|
||||
cache()
|
||||
->delete($prefix . "note#{$note->id}");
|
||||
cache()
|
||||
->delete($prefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($prefix . "note#{$note->id}_reblogs");
|
||||
|
||||
Events::trigger('on_note_reblog', $actor, $note);
|
||||
|
||||
if ($registerActivity) {
|
||||
$announceActivity = new AnnounceActivity($reblog);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Announce',
|
||||
$actor->id,
|
||||
null,
|
||||
$note->id,
|
||||
$announceActivity->toJSON(),
|
||||
$reblog->published_at,
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Announce',
|
||||
$actor->id,
|
||||
null,
|
||||
$note->id,
|
||||
$announceActivity->toJSON(),
|
||||
$reblog->published_at,
|
||||
'queued',
|
||||
);
|
||||
|
||||
$announceActivity->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to('activity', $note->actor->username, $activityId),
|
||||
),
|
||||
);
|
||||
$announceActivity->set('id', base_url(route_to('activity', $note->actor->username, $activityId),),);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $announceActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $announceActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
|
@ -547,7 +547,7 @@ class NoteModel extends UuidModel
|
|||
return $reblogId;
|
||||
}
|
||||
|
||||
public function undoReblog(Note $reblogNote, bool $registerActivity = true): BaseResult|bool
|
||||
public function undoReblog(Note $reblogNote, bool $registerActivity = true): BaseResult | bool
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
|
|
@ -555,25 +555,27 @@ class NoteModel extends UuidModel
|
|||
->where('id', $reblogNote->actor_id)
|
||||
->decrement('notes_count');
|
||||
|
||||
$cachePrefix = config('ActivityPub')->cachePrefix;
|
||||
cache()->delete($cachePrefix . "actor#{$reblogNote->actor_id}");
|
||||
cache()->delete(
|
||||
$cachePrefix . "actor#{$reblogNote->actor_id}_published_notes",
|
||||
);
|
||||
$cachePrefix = config('ActivityPub')
|
||||
->cachePrefix;
|
||||
cache()
|
||||
->delete($cachePrefix . "actor#{$reblogNote->actor_id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "actor#{$reblogNote->actor_id}_published_notes",);
|
||||
|
||||
model('NoteModel')
|
||||
->where(
|
||||
'id',
|
||||
$this->uuid->fromString($reblogNote->reblog_of_id)->getBytes(),
|
||||
)
|
||||
->where('id', $this->uuid->fromString($reblogNote->reblog_of_id) ->getBytes(),)
|
||||
->decrement('reblogs_count');
|
||||
|
||||
$hashedReblogNoteUri = md5($reblogNote->uri);
|
||||
$hashedNoteUri = md5($reblogNote->reblog_of_note->uri);
|
||||
cache()->delete($cachePrefix . "note#{$reblogNote->id}");
|
||||
cache()->delete($cachePrefix . "note-{$hashedReblogNoteUri}");
|
||||
cache()->delete($cachePrefix . "note#{$reblogNote->reblog_of_id}");
|
||||
cache()->delete($cachePrefix . "note-{$hashedNoteUri}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$reblogNote->id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note-{$hashedReblogNoteUri}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note#{$reblogNote->reblog_of_id}");
|
||||
cache()
|
||||
->delete($cachePrefix . "note-{$hashedNoteUri}");
|
||||
|
||||
Events::trigger('on_note_undo_reblog', $reblogNote);
|
||||
|
||||
|
|
@ -593,46 +595,37 @@ class NoteModel extends UuidModel
|
|||
$announceActivity = new AnnounceActivity($reblogNote);
|
||||
$announceActivity->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to(
|
||||
'activity',
|
||||
$reblogNote->actor->username,
|
||||
$activity->id,
|
||||
),
|
||||
),
|
||||
base_url(route_to('activity', $reblogNote->actor->username, $activity->id,),),
|
||||
);
|
||||
|
||||
$undoActivity
|
||||
->set('actor', $reblogNote->actor->uri)
|
||||
->set('object', $announceActivity);
|
||||
|
||||
$activityId = model('ActivityModel')->newActivity(
|
||||
'Undo',
|
||||
$reblogNote->actor_id,
|
||||
null,
|
||||
$reblogNote->reblog_of_id,
|
||||
$undoActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
$activityId = model('ActivityModel')
|
||||
->newActivity(
|
||||
'Undo',
|
||||
$reblogNote->actor_id,
|
||||
null,
|
||||
$reblogNote->reblog_of_id,
|
||||
$undoActivity->toJSON(),
|
||||
Time::now(),
|
||||
'queued',
|
||||
);
|
||||
|
||||
$undoActivity->set(
|
||||
'id',
|
||||
base_url(
|
||||
route_to(
|
||||
'activity',
|
||||
$reblogNote->actor->username,
|
||||
$activityId,
|
||||
),
|
||||
),
|
||||
base_url(route_to('activity', $reblogNote->actor->username, $activityId,),),
|
||||
);
|
||||
|
||||
model('ActivityModel')->update($activityId, [
|
||||
'payload' => $undoActivity->toJSON(),
|
||||
]);
|
||||
model('ActivityModel')
|
||||
->update($activityId, [
|
||||
'payload' => $undoActivity->toJSON(),
|
||||
]);
|
||||
}
|
||||
|
||||
$result = model('NoteModel', false)->delete($reblogNote->id);
|
||||
$result = model('NoteModel', false)
|
||||
->delete($reblogNote->id);
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
|
|
@ -642,7 +635,7 @@ class NoteModel extends UuidModel
|
|||
public function toggleReblog(Actor $actor, Note $note): void
|
||||
{
|
||||
if (
|
||||
!($reblogNote = $this->where([
|
||||
! ($reblogNote = $this->where([
|
||||
'actor_id' => $actor->id,
|
||||
'reblog_of_id' => $this->uuid
|
||||
->fromString($note->id)
|
||||
|
|
@ -655,7 +648,7 @@ class NoteModel extends UuidModel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @param array<string, array<string|int, mixed>> $data
|
||||
* @return array<string, array<string|int, mixed>>
|
||||
*/
|
||||
|
|
@ -664,14 +657,11 @@ class NoteModel extends UuidModel
|
|||
$uuid4 = $this->uuid->{$this->uuidVersion}();
|
||||
$data['data']['id'] = $uuid4->toString();
|
||||
|
||||
if (!isset($data['data']['uri'])) {
|
||||
$actor = model('ActorModel')->getActorById(
|
||||
$data['data']['actor_id'],
|
||||
);
|
||||
if (! isset($data['data']['uri'])) {
|
||||
$actor = model('ActorModel')
|
||||
->getActorById($data['data']['actor_id'],);
|
||||
|
||||
$data['data']['uri'] = base_url(
|
||||
route_to('note', $actor->username, $uuid4->toString()),
|
||||
);
|
||||
$data['data']['uri'] = base_url(route_to('note', $actor->username, $uuid4->toString()),);
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace ActivityPub\Models;
|
||||
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use ActivityPub\Entities\PreviewCard;
|
||||
use CodeIgniter\Database\BaseResult;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class PreviewCardModel extends Model
|
||||
|
|
@ -55,11 +55,14 @@ class PreviewCardModel extends Model
|
|||
{
|
||||
$hashedPreviewCardUrl = md5($url);
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix .
|
||||
config('ActivityPub')
|
||||
->cachePrefix .
|
||||
"preview_card-{$hashedPreviewCardUrl}";
|
||||
if (!($found = cache($cacheName))) {
|
||||
$found = $this->where('url', $url)->first();
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->where('url', $url)
|
||||
->first();
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -68,34 +71,29 @@ class PreviewCardModel extends Model
|
|||
public function getNotePreviewCard(string $noteId): ?PreviewCard
|
||||
{
|
||||
$cacheName =
|
||||
config('ActivityPub')->cachePrefix . "note#{$noteId}_preview_card";
|
||||
if (!($found = cache($cacheName))) {
|
||||
config('ActivityPub')
|
||||
->cachePrefix . "note#{$noteId}_preview_card";
|
||||
if (! ($found = cache($cacheName))) {
|
||||
$found = $this->join(
|
||||
'activitypub_notes_preview_cards',
|
||||
'activitypub_notes_preview_cards.preview_card_id = id',
|
||||
'inner',
|
||||
)
|
||||
->where(
|
||||
'note_id',
|
||||
service('uuid')
|
||||
->fromString($noteId)
|
||||
->getBytes(),
|
||||
)
|
||||
->where('note_id', service('uuid') ->fromString($noteId) ->getBytes(),)
|
||||
->first();
|
||||
|
||||
cache()->save($cacheName, $found, DECADE);
|
||||
cache()
|
||||
->save($cacheName, $found, DECADE);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function deletePreviewCard(int $id, string $url): BaseResult|bool
|
||||
public function deletePreviewCard(int $id, string $url): BaseResult | bool
|
||||
{
|
||||
$hashedPreviewCardUrl = md5($url);
|
||||
cache()->delete(
|
||||
config('ActivityPub')->cachePrefix .
|
||||
"preview_card-{$hashedPreviewCardUrl}",
|
||||
);
|
||||
cache()
|
||||
->delete(config('ActivityPub') ->cachePrefix . "preview_card-{$hashedPreviewCardUrl}",);
|
||||
|
||||
return $this->delete($id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,26 +8,30 @@
|
|||
|
||||
namespace ActivityPub\Objects;
|
||||
|
||||
use ActivityPub\Entities\Actor;
|
||||
use ActivityPub\Core\ObjectType;
|
||||
use ActivityPub\Entities\Actor;
|
||||
|
||||
class ActorObject extends ObjectType
|
||||
{
|
||||
/**
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected string|array $context = [
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
'https://w3id.org/security/v1',
|
||||
];
|
||||
protected string | array $context = ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'];
|
||||
|
||||
protected string $type = 'Person';
|
||||
|
||||
protected string $name;
|
||||
|
||||
protected string $preferredUsername;
|
||||
|
||||
protected string $summary;
|
||||
|
||||
protected string $inbox;
|
||||
|
||||
protected string $outbox;
|
||||
|
||||
protected string $followers;
|
||||
|
||||
protected string $url;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class defines the Object which is the
|
||||
* primary base type for the Activity Streams vocabulary.
|
||||
* This class defines the Object which is the primary base type for the Activity Streams vocabulary.
|
||||
*
|
||||
* Object is a reserved word in php, so the class is named ObjectType.
|
||||
*
|
||||
|
|
@ -13,14 +12,17 @@
|
|||
|
||||
namespace ActivityPub\Objects;
|
||||
|
||||
use ActivityPub\Entities\Note;
|
||||
use ActivityPub\Core\ObjectType;
|
||||
use ActivityPub\Entities\Note;
|
||||
|
||||
class NoteObject extends ObjectType
|
||||
{
|
||||
protected string $type = 'Note';
|
||||
|
||||
protected string $attributedTo;
|
||||
|
||||
protected string $inReplyTo;
|
||||
|
||||
protected string $replies;
|
||||
|
||||
public function __construct(Note $note)
|
||||
|
|
@ -35,9 +37,7 @@ class NoteObject extends ObjectType
|
|||
$this->inReplyTo = $note->reply_to_note->uri;
|
||||
}
|
||||
|
||||
$this->replies = base_url(
|
||||
route_to('note-replies', $note->actor->username, $note->id),
|
||||
);
|
||||
$this->replies = base_url(route_to('note-replies', $note->actor->username, $note->id),);
|
||||
|
||||
$this->cc = [$note->actor->followers_url];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class defines a Paginated OrderedCollection
|
||||
* based on CodeIgniter4 Pager to get the pagination metadata
|
||||
* This class defines a Paginated OrderedCollection based on CodeIgniter4 Pager to get the pagination metadata
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -11,15 +10,19 @@
|
|||
|
||||
namespace ActivityPub\Objects;
|
||||
|
||||
use CodeIgniter\Pager\Pager;
|
||||
use ActivityPub\Core\ObjectType;
|
||||
use CodeIgniter\Pager\Pager;
|
||||
|
||||
class OrderedCollectionObject extends ObjectType
|
||||
{
|
||||
protected string $type = 'OrderedCollection';
|
||||
|
||||
protected int $totalItems;
|
||||
|
||||
protected ?string $first;
|
||||
|
||||
protected ?string $current;
|
||||
|
||||
protected ?string $last;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class defines a Paginated OrderedCollection
|
||||
* based on CodeIgniter4 Pager to get the pagination metadata
|
||||
* This class defines a Paginated OrderedCollection based on CodeIgniter4 Pager to get the pagination metadata
|
||||
*
|
||||
* @copyright 2021 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -12,11 +11,15 @@
|
|||
namespace ActivityPub\Objects;
|
||||
|
||||
use CodeIgniter\Pager\Pager;
|
||||
|
||||
class OrderedCollectionPage extends OrderedCollectionObject
|
||||
{
|
||||
protected string $type = 'OrderedCollectionPage';
|
||||
|
||||
protected string $partOf;
|
||||
|
||||
protected ?string $prev;
|
||||
|
||||
protected ?string $next;
|
||||
|
||||
public function __construct(Pager $pager, ?array $orderedItems = null)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@ class WebFinger
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
const RESOURCE_PATTERN = '/^acct:(?P<username>([\w_]+))@(?P<domain>([\w\-\.]+[\w]+)(:[\d]+)?)$/x';
|
||||
private const RESOURCE_PATTERN = '/^acct:(?P<username>([\w_]+))@(?P<domain>([\w\-\.]+[\w]+)(:[\d]+)?)$/x';
|
||||
|
||||
protected string $username;
|
||||
|
||||
protected string $domain;
|
||||
|
||||
protected string $host;
|
||||
|
||||
protected string $port;
|
||||
|
||||
/**
|
||||
|
|
@ -32,11 +35,12 @@ class WebFinger
|
|||
*/
|
||||
protected array $links = [];
|
||||
|
||||
public function __construct(protected string $subject)
|
||||
{
|
||||
public function __construct(
|
||||
protected string $subject
|
||||
) {
|
||||
// Split resource into its parts (username, domain)
|
||||
$parts = $this->splitResource($subject);
|
||||
if (!$parts) {
|
||||
if (! $parts) {
|
||||
throw new Exception('Wrong WebFinger resource pattern.');
|
||||
}
|
||||
|
||||
|
|
@ -56,10 +60,7 @@ class WebFinger
|
|||
}
|
||||
|
||||
if (
|
||||
!($actor = model('ActorModel')->getActorByUsername(
|
||||
$username,
|
||||
$domain,
|
||||
))
|
||||
! ($actor = model('ActorModel')->getActorByUsername($username, $domain,))
|
||||
) {
|
||||
throw new Exception('Could not find actor');
|
||||
}
|
||||
|
|
@ -74,7 +75,8 @@ class WebFinger
|
|||
[
|
||||
'rel' => 'http://webfinger.net/rel/profile-page',
|
||||
'type' => 'text/html',
|
||||
'href' => $actor->uri, # TODO: should there be 2 values? @actorUsername
|
||||
'href' => $actor->uri,
|
||||
# TODO: should there be 2 values? @actorUsername
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
@ -92,14 +94,15 @@ class WebFinger
|
|||
'links' => $this->links,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Split resource into its parts (username, domain)
|
||||
*
|
||||
* @return array<string, string>|false
|
||||
*/
|
||||
private function splitResource(string $resource): array|false
|
||||
private function splitResource(string $resource): array | false
|
||||
{
|
||||
if (!preg_match(self::RESOURCE_PATTERN, $resource, $matches)) {
|
||||
if (! preg_match(self::RESOURCE_PATTERN, $resource, $matches)) {
|
||||
// Resource pattern failed
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace Analytics;
|
||||
|
||||
use Config\Services;
|
||||
use Config\Database;
|
||||
use Config\Services;
|
||||
|
||||
trait AnalyticsTrait
|
||||
{
|
||||
|
|
@ -25,7 +25,7 @@ trait AnalyticsTrait
|
|||
$session = Services::session();
|
||||
$session->start();
|
||||
|
||||
if (!$session->get('denyListIp')) {
|
||||
if (! $session->get('denyListIp')) {
|
||||
$db = Database::connect();
|
||||
|
||||
$referer = $session->get('referer');
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ use CodeIgniter\Config\BaseConfig;
|
|||
class Analytics extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Gateway to analytic routes.
|
||||
* By default, all analytics routes will be under `/analytics` path
|
||||
* Gateway to analytic routes. By default, all analytics routes will be under `/analytics` path
|
||||
*/
|
||||
public string $gateway = 'analytics';
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ class Analytics extends BaseConfig
|
|||
*
|
||||
* @param string|string[] $audioFilePath
|
||||
*/
|
||||
public function getAudioFileUrl(string|array $audioFilePath): string
|
||||
public function getAudioFileUrl(string | array $audioFilePath): string
|
||||
{
|
||||
return base_url($audioFilePath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,22 +19,22 @@ $routes->addPlaceholder(
|
|||
'\bWeekly|\bYearly|\bByDay|\bByWeekday|\bByMonth|\bByAppWeekly|\bByAppYearly|\bByOsWeekly|\bByDeviceWeekly|\bBots|\bByServiceWeekly|\bBandwidthByDay|\bUniqueListenersByDay|\bUniqueListenersByMonth|\bTotalListeningTimeByDay|\bTotalListeningTimeByMonth|\bByDomainWeekly|\bByDomainYearly',
|
||||
);
|
||||
|
||||
$routes->group('', ['namespace' => 'Analytics\Controllers'], function (
|
||||
$routes
|
||||
): void {
|
||||
$routes->group(config('Analytics')->gateway . '/(:num)/(:class)', function (
|
||||
$routes
|
||||
): void {
|
||||
$routes->group('', [
|
||||
'namespace' => 'Analytics\Controllers',
|
||||
], function ($routes): void {
|
||||
$routes->group(config('Analytics')->gateway . '/(:num)/(:class)', function ($routes): void {
|
||||
$routes->get('/', 'AnalyticsController::getData/$1/$2', [
|
||||
'as' => 'analytics-full-data',
|
||||
'filter' => config('Analytics')->routeFilters[
|
||||
'filter' => config('Analytics')
|
||||
->routeFilters[
|
||||
'analytics-full-data'
|
||||
],
|
||||
]);
|
||||
|
||||
$routes->get('(:filter)', 'AnalyticsController::getData/$1/$2/$3', [
|
||||
'as' => 'analytics-data',
|
||||
'filter' => config('Analytics')->routeFilters['analytics-data'],
|
||||
'filter' => config('Analytics')
|
||||
->routeFilters['analytics-data'],
|
||||
]);
|
||||
|
||||
$routes->get(
|
||||
|
|
@ -42,7 +42,8 @@ $routes->group('', ['namespace' => 'Analytics\Controllers'], function (
|
|||
'AnalyticsController::getData/$1/$2/$3/$4',
|
||||
[
|
||||
'as' => 'analytics-filtered-data',
|
||||
'filter' => config('Analytics')->routeFilters[
|
||||
'filter' => config('Analytics')
|
||||
->routeFilters[
|
||||
'analytics-filtered-data'
|
||||
],
|
||||
],
|
||||
|
|
@ -68,7 +69,4 @@ $routes->group('', ['namespace' => 'Analytics\Controllers'], function (
|
|||
|
||||
// Show the Unknown UserAgents
|
||||
$routes->get('.well-known/unknown-useragents', 'UnknownUserAgentsController');
|
||||
$routes->get(
|
||||
'.well-known/unknown-useragents/(:num)',
|
||||
'UnknownUserAgentsController/$1',
|
||||
);
|
||||
$routes->get('.well-known/unknown-useragents/(:num)', 'UnknownUserAgentsController/$1',);
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@
|
|||
|
||||
namespace Analytics\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class AnalyticsController extends Controller
|
||||
{
|
||||
protected Model $analyticsModel;
|
||||
|
||||
protected string $methodName = '';
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
|
|
@ -27,26 +28,20 @@ class AnalyticsController extends Controller
|
|||
$this->analyticsModel = model('Analytics' . $params[1] . 'Model');
|
||||
$this->methodName = 'getData' . (count($params) >= 3 ? $params[2] : '');
|
||||
|
||||
return $this->$method(
|
||||
return $this->{$method}(
|
||||
$params[0],
|
||||
count($params) >= 4 ? $params[3] : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getData(
|
||||
int $podcastId,
|
||||
?int $episodeId = null
|
||||
): ResponseInterface {
|
||||
public function getData(int $podcastId, ?int $episodeId = null): ResponseInterface
|
||||
{
|
||||
$methodName = $this->methodName;
|
||||
|
||||
if ($episodeId === null) {
|
||||
return $this->response->setJSON(
|
||||
$this->analyticsModel->$methodName($podcastId),
|
||||
);
|
||||
return $this->response->setJSON($this->analyticsModel->{$methodName}($podcastId),);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(
|
||||
$this->analyticsModel->$methodName($podcastId, $episodeId),
|
||||
);
|
||||
return $this->response->setJSON($this->analyticsModel->{$methodName}($podcastId, $episodeId),);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,19 +9,18 @@
|
|||
namespace Analytics\Controllers;
|
||||
|
||||
use Analytics\Config\Analytics;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Config\Services;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class EpisodeAnalyticsController extends Controller
|
||||
{
|
||||
/**
|
||||
* An array of helpers to be loaded automatically upon
|
||||
* class instantiation. These helpers will be available
|
||||
* to all other controllers that extend Analytics.
|
||||
* An array of helpers to be loaded automatically upon class instantiation. These helpers will be available to all
|
||||
* other controllers that extend Analytics.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
|
|
@ -40,12 +39,6 @@ class EpisodeAnalyticsController extends Controller
|
|||
// Do Not Edit This Line
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Preload any models, libraries, etc, here.
|
||||
//--------------------------------------------------------------------
|
||||
// E.g.:
|
||||
// $this->session = \Config\Services::session();
|
||||
|
||||
set_user_session_deny_list_ip();
|
||||
set_user_session_location();
|
||||
set_user_session_player();
|
||||
|
|
@ -53,10 +46,8 @@ class EpisodeAnalyticsController extends Controller
|
|||
$this->config = config('Analytics');
|
||||
}
|
||||
|
||||
public function hit(
|
||||
string $base64EpisodeData,
|
||||
string ...$audioFilePath
|
||||
): RedirectResponse {
|
||||
public function hit(string $base64EpisodeData, string ...$audioFilePath): RedirectResponse
|
||||
{
|
||||
$session = Services::session();
|
||||
$session->start();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use Analytics\AnalyticsTrait;
|
||||
use App\Entities\Episode;
|
||||
use App\Entities\Podcast;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class EpisodeController extends BaseController
|
||||
|
|
@ -23,6 +23,7 @@ class EpisodeController extends BaseController
|
|||
use AnalyticsTrait;
|
||||
|
||||
protected Podcast $podcast;
|
||||
|
||||
protected Episode $episode;
|
||||
|
||||
public function _remap(string $method, string ...$params): mixed
|
||||
|
|
@ -32,22 +33,17 @@ class EpisodeController extends BaseController
|
|||
}
|
||||
|
||||
if (
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||
$params[0],
|
||||
)) === null
|
||||
($this->podcast = (new PodcastModel())->getPodcastByName($params[0],)) === null
|
||||
) {
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
if (
|
||||
($this->episode = (new EpisodeModel())->getEpisodeBySlug(
|
||||
$this->podcast->id,
|
||||
$params[1],
|
||||
)) !== null
|
||||
($this->episode = (new EpisodeModel())->getEpisodeBySlug($this->podcast->id, $params[1],)) !== null
|
||||
) {
|
||||
unset($params[1]);
|
||||
unset($params[0]);
|
||||
return $this->$method(...$params);
|
||||
return $this->{$method}(...$params);
|
||||
}
|
||||
|
||||
throw PageNotFoundException::forPageNotFound();
|
||||
|
|
@ -56,16 +52,17 @@ class EpisodeController extends BaseController
|
|||
public function index(): string
|
||||
{
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->episode->podcast_id);
|
||||
}
|
||||
|
||||
$locale = service('request')->getLocale();
|
||||
$locale = service('request')
|
||||
->getLocale();
|
||||
$cacheName =
|
||||
"page_podcast#{$this->podcast->id}_episode#{$this->episode->id}_{$locale}" .
|
||||
(can_user_interact() ? '_authenticated' : '');
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
'episode' => $this->episode,
|
||||
|
|
@ -91,30 +88,27 @@ class EpisodeController extends BaseController
|
|||
return $cachedView;
|
||||
}
|
||||
|
||||
public function embeddablePlayer(
|
||||
string $theme = 'light-transparent'
|
||||
): string {
|
||||
public function embeddablePlayer(string $theme = 'light-transparent'): string
|
||||
{
|
||||
header('Content-Security-Policy: frame-ancestors https://* http://*');
|
||||
|
||||
// Prevent analytics hit when authenticated
|
||||
if (!can_user_interact()) {
|
||||
if (! can_user_interact()) {
|
||||
$this->registerPodcastWebpageHit($this->episode->podcast_id);
|
||||
}
|
||||
|
||||
$session = Services::session();
|
||||
$session->start();
|
||||
if (isset($_SERVER['HTTP_REFERER'])) {
|
||||
$session->set(
|
||||
'embeddable_player_domain',
|
||||
parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST),
|
||||
);
|
||||
$session->set('embeddable_player_domain', parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST),);
|
||||
}
|
||||
|
||||
$locale = service('request')->getLocale();
|
||||
$locale = service('request')
|
||||
->getLocale();
|
||||
|
||||
$cacheName = "page_podcast#{$this->podcast->id}_episode#{$this->episode->id}_embeddable_player_{$theme}_{$locale}";
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
if (! ($cachedView = cache($cacheName))) {
|
||||
$theme = EpisodeModel::$themes[$theme];
|
||||
|
||||
$data = [
|
||||
|
|
@ -156,16 +150,16 @@ class EpisodeController extends BaseController
|
|||
'width' => 600,
|
||||
'height' => 200,
|
||||
'thumbnail_url' => $this->episode->image->large_url,
|
||||
'thumbnail_width' => config('Images')->largeSize,
|
||||
'thumbnail_height' => config('Images')->largeSize,
|
||||
'thumbnail_width' => config('Images')
|
||||
->largeSize,
|
||||
'thumbnail_height' => config('Images')
|
||||
->largeSize,
|
||||
]);
|
||||
}
|
||||
|
||||
public function oembedXML(): ResponseInterface
|
||||
{
|
||||
$oembed = new SimpleXMLElement(
|
||||
"<?xml version='1.0' encoding='utf-8' standalone='yes'?><oembed></oembed>",
|
||||
);
|
||||
$oembed = new SimpleXMLElement("<?xml version='1.0' encoding='utf-8' standalone='yes'?><oembed></oembed>",);
|
||||
|
||||
$oembed->addChild('type', 'rich');
|
||||
$oembed->addChild('version', '1.0');
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace Analytics\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
|
||||
class UnknownUserAgentsController extends Controller
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcasts
|
||||
* Creates analytics_podcasts table in database
|
||||
* Class AddAnalyticsPodcasts Creates analytics_podcasts table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -45,9 +44,7 @@ class AddAnalyticsPodcasts extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcastsByEpisode
|
||||
* Creates analytics_episodes_by_episode table in database
|
||||
* Class AddAnalyticsPodcastsByEpisode Creates analytics_episodes_by_episode table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -41,9 +40,7 @@ class AddAnalyticsPodcastsByEpisode extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'episode_id']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcastsByHour
|
||||
* Creates analytics_podcasts_by_hour table in database
|
||||
* Class AddAnalyticsPodcastsByHour Creates analytics_podcasts_by_hour table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -36,9 +35,7 @@ class AddAnalyticsPodcastsByHour extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'hour']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcastsByPlayer
|
||||
* Creates analytics_podcasts_by_player table in database
|
||||
* Class AddAnalyticsPodcastsByPlayer Creates analytics_podcasts_by_player table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -52,18 +51,8 @@ class AddAnalyticsPodcastsByPlayer extends Migration
|
|||
'default' => 1,
|
||||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey([
|
||||
'podcast_id',
|
||||
'date',
|
||||
'service',
|
||||
'app',
|
||||
'device',
|
||||
'os',
|
||||
'is_bot',
|
||||
]);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'service', 'app', 'device', 'os', 'is_bot']);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcastsByCountry
|
||||
* Creates analytics_podcasts_by_country table in database
|
||||
* Class AddAnalyticsPodcastsByCountry Creates analytics_podcasts_by_country table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -37,9 +36,7 @@ class AddAnalyticsPodcastsByCountry extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcastsByRegion
|
||||
* Creates analytics_podcasts_by_region table in database
|
||||
* Class AddAnalyticsPodcastsByRegion Creates analytics_podcasts_by_region table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -49,15 +48,8 @@ class AddAnalyticsPodcastsByRegion extends Migration
|
|||
'default' => 1,
|
||||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey([
|
||||
'podcast_id',
|
||||
'date',
|
||||
'country_code',
|
||||
'region_code',
|
||||
]);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code', 'region_code']);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsWebsiteByBrowser
|
||||
* Creates analytics_website_by_browser table in database
|
||||
* Class AddAnalyticsWebsiteByBrowser Creates analytics_website_by_browser table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -37,9 +36,7 @@ class AddAnalyticsWebsiteByBrowser extends Migration
|
|||
]);
|
||||
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'browser']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsWebsiteByReferer
|
||||
* Creates analytics_website_by_referer table in database
|
||||
* Class AddAnalyticsWebsiteByReferer Creates analytics_website_by_referer table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -36,7 +35,8 @@ class AddAnalyticsWebsiteByReferer extends Migration
|
|||
],
|
||||
'keywords' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 384, // length of referer_url (512) - domain (128)
|
||||
// length of referer_url (512) - domain (128) = 384
|
||||
'constraint' => 384,
|
||||
'null' => true,
|
||||
],
|
||||
'hits' => [
|
||||
|
|
@ -46,9 +46,7 @@ class AddAnalyticsWebsiteByReferer extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'referer_url']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsWebsiteByEntryPage
|
||||
* Creates analytics_website_by_entry_page table in database
|
||||
* Class AddAnalyticsWebsiteByEntryPage Creates analytics_website_by_entry_page table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -36,9 +35,7 @@ class AddAnalyticsWebsiteByEntryPage extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'entry_page_url']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsUnknownUseragents
|
||||
* Creates analytics_unknown_useragents table in database
|
||||
* Class AddAnalyticsUnknownUseragents Creates analytics_unknown_useragents table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -37,9 +36,7 @@ class AddAnalyticsUnknownUseragents extends Migration
|
|||
|
||||
$this->forge->addPrimaryKey('id');
|
||||
// `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Procedure will be used instead)
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()',);
|
||||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsPodcastsProcedure
|
||||
* Creates analytics_podcasts procedure in database
|
||||
* Class AddAnalyticsPodcastsProcedure Creates analytics_podcasts procedure in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -21,7 +20,7 @@ class AddAnalyticsPodcastsProcedure extends Migration
|
|||
// Example: CALL analytics_podcasts(1, 2, 'FR', 'IDF', 48.853, 2.349, PodcastAddict, 'phone', 'android', 0, 1);
|
||||
$prefix = $this->db->getPrefix();
|
||||
|
||||
$createQuery = <<<EOD
|
||||
$createQuery = <<<CODE_SAMPLE
|
||||
CREATE PROCEDURE `{$prefix}analytics_podcasts` (
|
||||
IN `p_podcast_id` INT UNSIGNED,
|
||||
IN `p_episode_id` INT UNSIGNED,
|
||||
|
|
@ -73,15 +72,13 @@ class AddAnalyticsPodcastsProcedure extends Migration
|
|||
VALUES (p_podcast_id, p_service, p_app, p_device, p_os, p_bot, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END
|
||||
EOD;
|
||||
CODE_SAMPLE;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$prefix = $this->db->getPrefix();
|
||||
$this->db->query(
|
||||
"DROP PROCEDURE IF EXISTS `{$prefix}analytics_podcasts`",
|
||||
);
|
||||
$this->db->query("DROP PROCEDURE IF EXISTS `{$prefix}analytics_podcasts`",);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsUnknownUseragentsProcedure
|
||||
* Creates analytics_unknown_useragents procedure in database
|
||||
* Class AddAnalyticsUnknownUseragentsProcedure Creates analytics_unknown_useragents procedure in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -20,7 +19,7 @@ class AddAnalyticsUnknownUseragentsProcedure extends Migration
|
|||
// Creates Procedure for data insertion
|
||||
// Example: CALL analytics_unknown_useragents('Podcasts/1430.46 CFNetwork/1125.2 Darwin/19.4.0');
|
||||
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
|
||||
$createQuery = <<<EOD
|
||||
$createQuery = <<<CODE_SAMPLE
|
||||
CREATE PROCEDURE `{$procedureName}` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
|
|
@ -28,7 +27,7 @@ class AddAnalyticsUnknownUseragentsProcedure extends Migration
|
|||
INSERT INTO `{$procedureName}`(`useragent`)
|
||||
VALUES (p_useragent)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
|
||||
EOD;
|
||||
CODE_SAMPLE;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddAnalyticsWebsiteProcedure
|
||||
* Creates analytics_website stored procedure in database
|
||||
* Class AddAnalyticsWebsiteProcedure Creates analytics_website stored procedure in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
|
@ -20,7 +19,7 @@ class AddAnalyticsWebsiteProcedure extends Migration
|
|||
// Creates Procedure for data insertion
|
||||
// Example: CALL analytics_website(1,'FR','Firefox');
|
||||
$procedureName = $this->db->prefixTable('analytics_website');
|
||||
$createQuery = <<<EOD
|
||||
$createQuery = <<<CODE_SAMPLE
|
||||
CREATE PROCEDURE `{$procedureName}` (IN `p_podcast_id` INT UNSIGNED, IN `p_browser` VARCHAR(191) CHARSET utf8mb4, IN `p_entry_page` VARCHAR(512) CHARSET utf8mb4, IN `p_referer_url` VARCHAR(512) CHARSET utf8mb4, IN `p_domain` VARCHAR(128) CHARSET utf8mb4, IN `p_keywords` VARCHAR(384) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
|
|
@ -39,7 +38,7 @@ class AddAnalyticsWebsiteProcedure extends Migration
|
|||
VALUES (p_podcast_id, p_entry_page, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END
|
||||
EOD;
|
||||
CODE_SAMPLE;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcasts
|
||||
* Entity for AnalyticsPodcasts
|
||||
* Class AnalyticsPodcasts Entity for AnalyticsPodcasts
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastsByCountry
|
||||
* Entity for AnalyticsPodcastsByCountry
|
||||
* Class AnalyticsPodcastsByCountry Entity for AnalyticsPodcastsByCountry
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastsByEpisode
|
||||
* Entity for AnalyticsPodcastsByEpisode
|
||||
* Class AnalyticsPodcastsByEpisode Entity for AnalyticsPodcastsByEpisode
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastsByHour
|
||||
* Entity for AnalyticsPodcastsByHour
|
||||
* Class AnalyticsPodcastsByHour Entity for AnalyticsPodcastsByHour
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastsByPlayer
|
||||
* Entity for AnalyticsPodcastsByPlayer
|
||||
* Class AnalyticsPodcastsByPlayer Entity for AnalyticsPodcastsByPlayer
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastsByRegion
|
||||
* Entity for AnalyticsPodcastsByRegion
|
||||
* Class AnalyticsPodcastsByRegion Entity for AnalyticsPodcastsByRegion
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastsByService
|
||||
* Entity for AnalyticsPodcastsByService
|
||||
* Class AnalyticsPodcastsByService Entity for AnalyticsPodcastsByService
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
namespace Analytics\Entities;
|
||||
|
||||
use Opawg\UserAgentsPhp\UserAgentsRSS;
|
||||
use CodeIgniter\Entity\Entity;
|
||||
use Opawg\UserAgentsPhp\UserAgentsRSS;
|
||||
|
||||
/**
|
||||
* @property int $podcast_id
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsUnknownUseragents
|
||||
* Entity for AnalyticsUnknownUseragents
|
||||
* Class AnalyticsUnknownUseragents Entity for AnalyticsUnknownUseragents
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsWebsiteByBrowser
|
||||
* Entity for AnalyticsWebsiteByBrowser
|
||||
* Class AnalyticsWebsiteByBrowser Entity for AnalyticsWebsiteByBrowser
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsWebsiteByEntryPage
|
||||
* Entity for AnalyticsWebsiteByEntryPage
|
||||
* Class AnalyticsWebsiteByEntryPage Entity for AnalyticsWebsiteByEntryPage
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class class AnalyticsWebsiteByReferer
|
||||
* Entity for AnalyticsWebsiteByReferer
|
||||
* Class class AnalyticsWebsiteByReferer Entity for AnalyticsWebsiteByReferer
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
<?php
|
||||
|
||||
use CodeIgniter\Router\Exceptions\RouterException;
|
||||
use Config\Database;
|
||||
use Config\Services;
|
||||
use Podlibre\Ipcat\IpDb;
|
||||
use GeoIp2\Database\Reader;
|
||||
use Opawg\UserAgentsPhp\UserAgents;
|
||||
use Config\Database;
|
||||
use WhichBrowser\Parser;
|
||||
use Podlibre\Ipcat\IpDb;
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
use CodeIgniter\Router\Exceptions\RouterException;
|
||||
use WhichBrowser\Parser;
|
||||
|
||||
if (!function_exists('base64_url_encode')) {
|
||||
if (! function_exists('base64_url_encode')) {
|
||||
/**
|
||||
* Encode Base64 for URLs
|
||||
*/
|
||||
|
|
@ -24,20 +24,19 @@ if (!function_exists('base64_url_encode')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('base64_url_decode')) {
|
||||
if (! function_exists('base64_url_decode')) {
|
||||
/**
|
||||
* Decode Base64 from URL
|
||||
*/
|
||||
function base64_url_decode(string $input): string
|
||||
{
|
||||
return base64_decode(strtr($input, '._-', '+/='));
|
||||
return base64_decode(strtr($input, '._-', '+/='), true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('generate_episode_analytics_url')) {
|
||||
if (! function_exists('generate_episode_analytics_url')) {
|
||||
/**
|
||||
* Builds the episode analytics url that redirects to the audio file url
|
||||
* after analytics hit.
|
||||
* Builds the episode analytics url that redirects to the audio file url after analytics hit.
|
||||
*
|
||||
* @throws RouterException
|
||||
*/
|
||||
|
|
@ -63,11 +62,7 @@ if (!function_exists('generate_episode_analytics_url')) {
|
|||
$audioFileDuration <= 60
|
||||
? $audioFileSize
|
||||
: $audioFileHeaderSize +
|
||||
floor(
|
||||
(($audioFileSize - $audioFileHeaderSize) /
|
||||
$audioFileDuration) *
|
||||
60,
|
||||
),
|
||||
floor((($audioFileSize - $audioFileHeaderSize) / $audioFileDuration) * 60,),
|
||||
$audioFileSize,
|
||||
$audioFileDuration,
|
||||
strtotime($publicationDate),
|
||||
|
|
@ -78,7 +73,7 @@ if (!function_exists('generate_episode_analytics_url')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_user_session_deny_list_ip')) {
|
||||
if (! function_exists('set_user_session_deny_list_ip')) {
|
||||
/**
|
||||
* Set user country in session variable, for analytic purposes
|
||||
*/
|
||||
|
|
@ -87,16 +82,13 @@ if (!function_exists('set_user_session_deny_list_ip')) {
|
|||
$session = Services::session();
|
||||
$session->start();
|
||||
|
||||
if (!$session->has('denyListIp')) {
|
||||
$session->set(
|
||||
'denyListIp',
|
||||
IpDb::find($_SERVER['REMOTE_ADDR']) != null,
|
||||
);
|
||||
if (! $session->has('denyListIp')) {
|
||||
$session->set('denyListIp', IpDb::find($_SERVER['REMOTE_ADDR']) !== null,);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_user_session_location')) {
|
||||
if (! function_exists('set_user_session_location')) {
|
||||
/**
|
||||
* Set user country in session variable, for analytic purposes
|
||||
*/
|
||||
|
|
@ -113,11 +105,9 @@ if (!function_exists('set_user_session_location')) {
|
|||
];
|
||||
|
||||
// Finds location:
|
||||
if (!$session->has('location')) {
|
||||
if (! $session->has('location')) {
|
||||
try {
|
||||
$cityReader = new Reader(
|
||||
WRITEPATH . 'uploads/GeoLite2-City/GeoLite2-City.mmdb',
|
||||
);
|
||||
$cityReader = new Reader(WRITEPATH . 'uploads/GeoLite2-City/GeoLite2-City.mmdb',);
|
||||
$city = $cityReader->city($_SERVER['REMOTE_ADDR']);
|
||||
|
||||
$location = [
|
||||
|
|
@ -138,7 +128,7 @@ if (!function_exists('set_user_session_location')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_user_session_player')) {
|
||||
if (! function_exists('set_user_session_player')) {
|
||||
/**
|
||||
* Set user player in session variable, for analytic purposes
|
||||
*/
|
||||
|
|
@ -147,7 +137,7 @@ if (!function_exists('set_user_session_player')) {
|
|||
$session = Services::session();
|
||||
$session->start();
|
||||
|
||||
if (!$session->has('player')) {
|
||||
if (! $session->has('player')) {
|
||||
$playerFound = null;
|
||||
$userAgent = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
|
|
@ -168,13 +158,8 @@ if (!function_exists('set_user_session_player')) {
|
|||
// Add to unknown list
|
||||
try {
|
||||
$db = Database::connect();
|
||||
$procedureNameAnalyticsUnknownUseragents = $db->prefixTable(
|
||||
'analytics_unknown_useragents',
|
||||
);
|
||||
$db->query(
|
||||
"CALL {$procedureNameAnalyticsUnknownUseragents}(?)",
|
||||
[$userAgent],
|
||||
);
|
||||
$procedureNameAnalyticsUnknownUseragents = $db->prefixTable('analytics_unknown_useragents',);
|
||||
$db->query("CALL {$procedureNameAnalyticsUnknownUseragents}(?)", [$userAgent],);
|
||||
// If things go wrong the show must go on and the user must be able to download the file
|
||||
} catch (Exception) {
|
||||
}
|
||||
|
|
@ -183,16 +168,18 @@ if (!function_exists('set_user_session_player')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_user_session_browser')) {
|
||||
if (! function_exists('set_user_session_browser')) {
|
||||
/**
|
||||
* Set user browser in session variable, for analytic purposes
|
||||
*
|
||||
* FIXME: session key should be null instead of "Could not get browser name"
|
||||
*/
|
||||
function set_user_session_browser(): void
|
||||
{
|
||||
$session = Services::session();
|
||||
$session->start();
|
||||
|
||||
if (!$session->has('browser')) {
|
||||
if (! $session->has('browser')) {
|
||||
$browserName = '- Other -';
|
||||
try {
|
||||
$whichbrowser = new Parser(getallheaders());
|
||||
|
|
@ -200,7 +187,7 @@ if (!function_exists('set_user_session_browser')) {
|
|||
} catch (Exception) {
|
||||
$browserName = '- Could not get browser name -';
|
||||
}
|
||||
if ($browserName == null) {
|
||||
if ($browserName === '') {
|
||||
$browserName = '- Could not get browser name -';
|
||||
}
|
||||
$session->set('browser', $browserName);
|
||||
|
|
@ -208,7 +195,7 @@ if (!function_exists('set_user_session_browser')) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_user_session_referer')) {
|
||||
if (! function_exists('set_user_session_referer')) {
|
||||
/**
|
||||
* Set user referer in session variable, for analytic purposes
|
||||
*/
|
||||
|
|
@ -225,13 +212,13 @@ if (!function_exists('set_user_session_referer')) {
|
|||
parse_url(current_url(false), PHP_URL_HOST)
|
||||
? '- Direct -'
|
||||
: $newreferer;
|
||||
if (!$session->has('referer') || $newreferer != '- Direct -') {
|
||||
if (! $session->has('referer') || $newreferer !== '- Direct -') {
|
||||
$session->set('referer', $newreferer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('set_user_session_entry_page')) {
|
||||
if (! function_exists('set_user_session_entry_page')) {
|
||||
/**
|
||||
* Set user entry page in session variable, for analytic purposes
|
||||
*/
|
||||
|
|
@ -241,28 +228,24 @@ if (!function_exists('set_user_session_entry_page')) {
|
|||
$session->start();
|
||||
|
||||
$entryPage = $_SERVER['REQUEST_URI'];
|
||||
if (!$session->has('entryPage')) {
|
||||
if (! $session->has('entryPage')) {
|
||||
$session->set('entryPage', $entryPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('podcast_hit')) {
|
||||
if (! function_exists('podcast_hit')) {
|
||||
/**
|
||||
* Counting podcast episode downloads for analytic purposes
|
||||
* ✅ No IP address is ever stored on the server.
|
||||
* ✅ Only aggregate data is stored in the database.
|
||||
* We follow IAB Podcast Measurement Technical Guidelines Version 2.0:
|
||||
* https://iabtechlab.com/standards/podcast-measurement-guidelines/
|
||||
* https://iabtechlab.com/wp-content/uploads/2017/12/Podcast_Measurement_v2-Dec-20-2017.pdf
|
||||
* ✅ Rolling 24-hour window
|
||||
* ✅ Castopod does not do pre-load
|
||||
* ✅ IP deny list https://github.com/client9/ipcat
|
||||
* ✅ User-agent Filtering https://github.com/opawg/user-agents
|
||||
* ✅ RSS User-agent https://github.com/opawg/podcast-rss-useragents
|
||||
* ✅ Ignores 2 bytes range "Range: 0-1" (performed by official Apple iOS Podcast app)
|
||||
* ✅ In case of partial content, adds up all requests to check >1mn was downloaded
|
||||
* ✅ Identifying Uniques is done with a combination of IP Address and User Agent
|
||||
* Counting podcast episode downloads for analytic purposes ✅ No IP address is ever stored on the server. ✅ Only
|
||||
* aggregate data is stored in the database. We follow IAB Podcast Measurement Technical Guidelines Version 2.0:
|
||||
* https://iabtechlab.com/standards/podcast-measurement-guidelines/
|
||||
* https://iabtechlab.com/wp-content/uploads/2017/12/Podcast_Measurement_v2-Dec-20-2017.pdf ✅ Rolling 24-hour
|
||||
* window ✅ Castopod does not do pre-load ✅ IP deny list https://github.com/client9/ipcat ✅ User-agent
|
||||
* Filtering https://github.com/opawg/user-agents ✅ RSS User-agent https://github.com/opawg/podcast-rss-useragents
|
||||
* ✅ Ignores 2 bytes range "Range: 0-1" (performed by official Apple iOS Podcast app) ✅ In case of partial
|
||||
* content, adds up all requests to check >1mn was downloaded ✅ Identifying Uniques is done with a combination of
|
||||
* IP Address and User Agent
|
||||
*
|
||||
* @param integer $podcastId The podcast ID
|
||||
* @param integer $episodeId The Episode ID
|
||||
* @param integer $bytesThreshold The minimum total number of bytes that must be downloaded so that an episode is counted (>1mn)
|
||||
|
|
@ -297,13 +280,7 @@ if (!function_exists('podcast_hit')) {
|
|||
// We create a sha1 hash for this IP_Address+User_Agent+Episode_ID (used to count only once multiple episode downloads):
|
||||
$episodeHashId =
|
||||
'_IpUaEp_' .
|
||||
sha1(
|
||||
$_SERVER['REMOTE_ADDR'] .
|
||||
'_' .
|
||||
$_SERVER['HTTP_USER_AGENT'] .
|
||||
'_' .
|
||||
$episodeId,
|
||||
);
|
||||
sha1($_SERVER['REMOTE_ADDR'] . '_' . $_SERVER['HTTP_USER_AGENT'] . '_' . $episodeId,);
|
||||
// Was this episode downloaded in the past 24h:
|
||||
$downloadedBytes = cache($episodeHashId);
|
||||
// Rolling window is 24 hours (86400 seconds):
|
||||
|
|
@ -311,7 +288,8 @@ if (!function_exists('podcast_hit')) {
|
|||
if ($downloadedBytes) {
|
||||
// In case it was already downloaded, TTL should be adjusted (rolling window is 24h since 1st download):
|
||||
$rollingTTL =
|
||||
cache()->getMetadata($episodeHashId)['expire'] - time();
|
||||
cache()
|
||||
->getMetadata($episodeHashId)['expire'] - time();
|
||||
} else {
|
||||
// If it was never downloaded that means that zero byte were downloaded:
|
||||
$downloadedBytes = 0;
|
||||
|
|
@ -320,9 +298,9 @@ if (!function_exists('podcast_hit')) {
|
|||
// (Otherwise it means that this was already counted, therefore we don't do anything)
|
||||
if ($downloadedBytes < $bytesThreshold) {
|
||||
// If HTTP_RANGE is null we are downloading the complete file:
|
||||
if (!$httpRange) {
|
||||
if (! $httpRange) {
|
||||
$downloadedBytes = $fileSize;
|
||||
} elseif ($httpRange != 'bytes=0-1') {
|
||||
} elseif ($httpRange !== 'bytes=0-1') {
|
||||
// [0-1] bytes range requests are used (by Apple) to check that file exists and that 206 partial content is working.
|
||||
// We don't count these requests.
|
||||
// We calculate how many bytes are being downloaded based on HTTP_RANGE values:
|
||||
|
|
@ -336,7 +314,8 @@ if (!function_exists('podcast_hit')) {
|
|||
}
|
||||
}
|
||||
// We save the number of downloaded bytes for this user and this episode:
|
||||
cache()->save($episodeHashId, $downloadedBytes, $rollingTTL);
|
||||
cache()
|
||||
->save($episodeHashId, $downloadedBytes, $rollingTTL);
|
||||
|
||||
// If more that 1mn was downloaded, that's a hit, we send that to the database:
|
||||
if ($downloadedBytes >= $bytesThreshold) {
|
||||
|
|
@ -348,13 +327,7 @@ if (!function_exists('podcast_hit')) {
|
|||
// We create a sha1 hash for this IP_Address+User_Agent+Podcast_ID (used to count unique listeners):
|
||||
$listenerHashId =
|
||||
'_IpUaPo_' .
|
||||
sha1(
|
||||
$_SERVER['REMOTE_ADDR'] .
|
||||
'_' .
|
||||
$_SERVER['HTTP_USER_AGENT'] .
|
||||
'_' .
|
||||
$podcastId,
|
||||
);
|
||||
sha1($_SERVER['REMOTE_ADDR'] . '_' . $_SERVER['HTTP_USER_AGENT'] . '_' . $podcastId,);
|
||||
$newListener = 1;
|
||||
// Has this listener already downloaded an episode today:
|
||||
$downloadsByUser = cache($listenerHashId);
|
||||
|
|
@ -368,11 +341,8 @@ if (!function_exists('podcast_hit')) {
|
|||
// Listener count is calculated from 00h00 to 23h59:
|
||||
$midnightTTL = strtotime('tomorrow') - time();
|
||||
// We save the download count for this user until midnight:
|
||||
cache()->save(
|
||||
$listenerHashId,
|
||||
$downloadsByUser,
|
||||
$midnightTTL,
|
||||
);
|
||||
cache()
|
||||
->save($listenerHashId, $downloadsByUser, $midnightTTL,);
|
||||
|
||||
$db->query(
|
||||
"CALL {$procedureName}(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastByCountryModel
|
||||
* Model for analytics_podcasts_by_country table in database
|
||||
* Class AnalyticsPodcastByCountryModel Model for analytics_podcasts_by_country table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastByCountryModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcastsByCountry::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -42,9 +43,7 @@ class AnalyticsPodcastByCountryModel extends Model
|
|||
public function getDataWeekly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_by_country_weekly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_by_country_weekly",))
|
||||
) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('country_code as labels')
|
||||
|
|
@ -57,11 +56,8 @@ class AnalyticsPodcastByCountryModel extends Model
|
|||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_by_country_weekly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_country_weekly", $found, 600,);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -75,9 +71,7 @@ class AnalyticsPodcastByCountryModel extends Model
|
|||
public function getDataYearly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_by_country_yearly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_by_country_yearly",))
|
||||
) {
|
||||
$oneYearAgo = date('Y-m-d', strtotime('-1 year'));
|
||||
$found = $this->select('country_code as labels')
|
||||
|
|
@ -90,11 +84,8 @@ class AnalyticsPodcastByCountryModel extends Model
|
|||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_by_country_yearly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_country_yearly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastByEpisodeModel
|
||||
* Model for analytics_podcasts_by_episodes table in database
|
||||
* Class AnalyticsPodcastByEpisodeModel Model for analytics_podcasts_by_episodes table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastByEpisodeModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcastsByEpisode::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -40,9 +41,7 @@ class AnalyticsPodcastByEpisodeModel extends Model
|
|||
public function getDataByDay(int $podcastId, int $episodeId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_day",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_day",))
|
||||
) {
|
||||
$found = $this->select('date as labels')
|
||||
->selectSum('hits', 'values')
|
||||
|
|
@ -55,11 +54,8 @@ class AnalyticsPodcastByEpisodeModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_day",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_day", $found, 600,);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
@ -71,9 +67,7 @@ class AnalyticsPodcastByEpisodeModel extends Model
|
|||
public function getDataByMonth(int $podcastId, int $episodeId = null): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_month",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_month",))
|
||||
) {
|
||||
$found = $this->select('DATE_FORMAT(date,"%Y-%m-01") as labels')
|
||||
->selectSum('hits', 'values')
|
||||
|
|
@ -85,11 +79,8 @@ class AnalyticsPodcastByEpisodeModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_month",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_month", $found, 600,);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastByHour
|
||||
* Model for analytics_podcasts_by_hour table in database
|
||||
* Class AnalyticsPodcastByHour Model for analytics_podcasts_by_hour table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastByHourModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcastsByHour::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -41,7 +42,7 @@ class AnalyticsPodcastByHourModel extends Model
|
|||
*/
|
||||
public function getData(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_podcasts_by_hour"))) {
|
||||
if (! ($found = cache("{$podcastId}_analytics_podcasts_by_hour"))) {
|
||||
$found = $this->select("right(concat('0',hour,'h'),3) as labels")
|
||||
->selectSum('hits', 'values')
|
||||
->where([
|
||||
|
|
@ -52,11 +53,8 @@ class AnalyticsPodcastByHourModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_hour",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_hour", $found, 600,);
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastByPlayerModel
|
||||
* Model for analytics_podcasts_by_player table in database
|
||||
* Class AnalyticsPodcastByPlayerModel Model for analytics_podcasts_by_player table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcastsByPlayer::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -42,9 +43,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
public function getDataByAppWeekly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_app_weekly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcasts_by_player_by_app_weekly",))
|
||||
) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('app as labels')
|
||||
|
|
@ -58,11 +57,8 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_app_weekly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_app_weekly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -75,9 +71,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
public function getDataByAppYearly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_app_yearly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcasts_by_player_by_app_yearly",))
|
||||
) {
|
||||
$oneYearAgo = date('Y-m-d', strtotime('-1 year'));
|
||||
$found = $this->select('app as labels')
|
||||
|
|
@ -91,11 +85,8 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_app_yearly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_app_yearly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -108,9 +99,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
public function getDataByOsWeekly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_os_weekly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcasts_by_player_by_os_weekly",))
|
||||
) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('os as labels')
|
||||
|
|
@ -125,11 +114,8 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_os_weekly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_os_weekly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -142,9 +128,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
public function getDataByDeviceWeekly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_device_weekly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcasts_by_player_by_device_weekly",))
|
||||
) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('device as labels')
|
||||
|
|
@ -158,11 +142,8 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_player_by_device_weekly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_by_device_weekly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -175,7 +156,7 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
public function getDataBots(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache("{$podcastId}_analytics_podcasts_by_player_bots"))
|
||||
! ($found = cache("{$podcastId}_analytics_podcasts_by_player_bots"))
|
||||
) {
|
||||
$oneYearAgo = date('Y-m-d', strtotime('-1 year'));
|
||||
$found = $this->select('DATE_FORMAT(date,"%Y-%m-01") as labels')
|
||||
|
|
@ -189,11 +170,8 @@ class AnalyticsPodcastByPlayerModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_player_bots",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_player_bots", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastByRegionModel
|
||||
* Model for analytics_podcasts_by_region table in database
|
||||
* Class AnalyticsPodcastByRegionModel Model for analytics_podcasts_by_region table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastByRegionModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcastsByRegion::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -41,11 +42,10 @@ class AnalyticsPodcastByRegionModel extends Model
|
|||
*/
|
||||
public function getData(int $podcastId): array
|
||||
{
|
||||
$locale = service('request')->getLocale();
|
||||
$locale = service('request')
|
||||
->getLocale();
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_by_region_{$locale}",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_by_region_{$locale}",))
|
||||
) {
|
||||
$found = $this->select('country_code, region_code')
|
||||
->selectSum('hits', 'value')
|
||||
|
|
@ -59,11 +59,8 @@ class AnalyticsPodcastByRegionModel extends Model
|
|||
->orderBy('value', 'DESC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_by_region_{$locale}",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_region_{$locale}", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastByServiceModel
|
||||
* Model for analytics_podcasts_by_player table in database
|
||||
* Class AnalyticsPodcastByServiceModel Model for analytics_podcasts_by_player table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastByServiceModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcastsByService::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -42,9 +43,7 @@ class AnalyticsPodcastByServiceModel extends Model
|
|||
public function getDataByServiceWeekly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcasts_by_service_weekly",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcasts_by_service_weekly",))
|
||||
) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('service as labels')
|
||||
|
|
@ -58,11 +57,8 @@ class AnalyticsPodcastByServiceModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_service_weekly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_service_weekly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsPodcastModel
|
||||
* Model for analytics_podcasts table in database
|
||||
* Class AnalyticsPodcastModel Model for analytics_podcasts table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsPodcastModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsPodcasts::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -41,7 +42,7 @@ class AnalyticsPodcastModel extends Model
|
|||
*/
|
||||
public function getDataByDay(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_podcast_by_day"))) {
|
||||
if (! ($found = cache("{$podcastId}_analytics_podcast_by_day"))) {
|
||||
$found = $this->select('date as labels, hits as values')
|
||||
->where([
|
||||
'podcast_id' => $podcastId,
|
||||
|
|
@ -50,7 +51,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save("{$podcastId}_analytics_podcast_by_day", $found, 600);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_day", $found, 600);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -62,10 +64,8 @@ class AnalyticsPodcastModel extends Model
|
|||
*/
|
||||
public function getDataByWeekday(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_podcasts_by_weekday"))) {
|
||||
$found = $this->select(
|
||||
'LEFT(DAYNAME(date),3) as labels, WEEKDAY(date) as sort_labels',
|
||||
)
|
||||
if (! ($found = cache("{$podcastId}_analytics_podcasts_by_weekday"))) {
|
||||
$found = $this->select('LEFT(DAYNAME(date),3) as labels, WEEKDAY(date) as sort_labels',)
|
||||
->selectSum('hits', 'values')
|
||||
->where([
|
||||
'podcast_id' => $podcastId,
|
||||
|
|
@ -75,11 +75,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('sort_labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcasts_by_weekday",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcasts_by_weekday", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -91,10 +88,8 @@ class AnalyticsPodcastModel extends Model
|
|||
*/
|
||||
public function getDataBandwidthByDay(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_podcast_by_bandwidth"))) {
|
||||
$found = $this->select(
|
||||
'date as labels, round(bandwidth / 1048576, 1) as `values`',
|
||||
)
|
||||
if (! ($found = cache("{$podcastId}_analytics_podcast_by_bandwidth"))) {
|
||||
$found = $this->select('date as labels, round(bandwidth / 1048576, 1) as `values`',)
|
||||
->where([
|
||||
'podcast_id' => $podcastId,
|
||||
'date >' => date('Y-m-d', strtotime('-60 days')),
|
||||
|
|
@ -102,11 +97,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_by_bandwidth",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_bandwidth", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -118,7 +110,7 @@ class AnalyticsPodcastModel extends Model
|
|||
*/
|
||||
public function getDataByMonth(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_podcast_by_month"))) {
|
||||
if (! ($found = cache("{$podcastId}_analytics_podcast_by_month"))) {
|
||||
$found = $this->select('DATE_FORMAT(date,"%Y-%m-01") as labels')
|
||||
->selectSum('hits', 'values')
|
||||
->where([
|
||||
|
|
@ -128,11 +120,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_by_month",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_by_month", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -145,9 +134,7 @@ class AnalyticsPodcastModel extends Model
|
|||
public function getDataUniqueListenersByDay(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_unique_listeners_by_day",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_unique_listeners_by_day",))
|
||||
) {
|
||||
$found = $this->select('date as labels, unique_listeners as values')
|
||||
->where([
|
||||
|
|
@ -157,11 +144,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_unique_listeners_by_day",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_unique_listeners_by_day", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -174,9 +158,7 @@ class AnalyticsPodcastModel extends Model
|
|||
public function getDataUniqueListenersByMonth(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_unique_listeners_by_month",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_unique_listeners_by_month",))
|
||||
) {
|
||||
$found = $this->select('DATE_FORMAT(date,"%Y-%m-01") as labels')
|
||||
->selectSum('unique_listeners', 'values')
|
||||
|
|
@ -187,11 +169,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_unique_listeners_by_month",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_unique_listeners_by_month", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -204,9 +183,7 @@ class AnalyticsPodcastModel extends Model
|
|||
public function getDataTotalListeningTimeByDay(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_listening_time_by_day",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_listening_time_by_day",))
|
||||
) {
|
||||
$found = $this->select('date as labels')
|
||||
->selectSum('duration', 'values')
|
||||
|
|
@ -218,11 +195,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_listening_time_by_day",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_listening_time_by_day", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -235,9 +209,7 @@ class AnalyticsPodcastModel extends Model
|
|||
public function getDataTotalListeningTimeByMonth(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache(
|
||||
"{$podcastId}_analytics_podcast_listening_time_by_month",
|
||||
))
|
||||
! ($found = cache("{$podcastId}_analytics_podcast_listening_time_by_month",))
|
||||
) {
|
||||
$found = $this->select('DATE_FORMAT(date,"%Y-%m-01") as labels')
|
||||
->selectSum('duration', 'values')
|
||||
|
|
@ -248,11 +220,8 @@ class AnalyticsPodcastModel extends Model
|
|||
->orderBy('labels', 'ASC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_podcast_listening_time_by_month",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_podcast_listening_time_by_month", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsUnknownUseragentsModel
|
||||
* Model for analytics_unknown_useragents table in database
|
||||
* Class AnalyticsUnknownUseragentsModel Model for analytics_unknown_useragents table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsUnknownUserAgentModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsUnknownUserAgent::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -39,6 +40,7 @@ class AnalyticsUnknownUserAgentModel extends Model
|
|||
*/
|
||||
public function getUserAgents(int $lastKnownId = 0): array
|
||||
{
|
||||
return $this->where('id >', $lastKnownId)->findAll();
|
||||
return $this->where('id >', $lastKnownId)
|
||||
->findAll();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsWebsiteByBrowserModel
|
||||
* Model for analytics_website_by_browser table in database
|
||||
* Class AnalyticsWebsiteByBrowserModel Model for analytics_website_by_browser table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsWebsiteByBrowserModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsWebsiteByBrowser::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -41,7 +42,7 @@ class AnalyticsWebsiteByBrowserModel extends Model
|
|||
*/
|
||||
public function getData(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_website_by_browser"))) {
|
||||
if (! ($found = cache("{$podcastId}_analytics_website_by_browser"))) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('browser as labels')
|
||||
->selectSum('hits', 'values')
|
||||
|
|
@ -53,11 +54,8 @@ class AnalyticsWebsiteByBrowserModel extends Model
|
|||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_website_by_browser",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_browser", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsWebsiteByEntryPageModel
|
||||
* Model for analytics_website_by_entry_page table in database
|
||||
* Class AnalyticsWebsiteByEntryPageModel Model for analytics_website_by_entry_page table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsWebsiteByEntryPageModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsWebsiteByEntryPage::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -41,11 +42,9 @@ class AnalyticsWebsiteByEntryPageModel extends Model
|
|||
*/
|
||||
public function getData(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_website_by_entry_page"))) {
|
||||
if (! ($found = cache("{$podcastId}_analytics_website_by_entry_page"))) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select(
|
||||
"IF(entry_page_url='/','/',SUBSTRING_INDEX(entry_page_url,'/',-1)) as labels",
|
||||
)
|
||||
$found = $this->select("IF(entry_page_url='/','/',SUBSTRING_INDEX(entry_page_url,'/',-1)) as labels",)
|
||||
->selectSum('hits', 'values')
|
||||
->where([
|
||||
'podcast_id' => $podcastId,
|
||||
|
|
@ -54,11 +53,8 @@ class AnalyticsWebsiteByEntryPageModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_website_by_entry_page",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_entry_page", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AnalyticsWebsiteByRefererModel
|
||||
* Model for analytics_website_by_referer table in database
|
||||
* Class AnalyticsWebsiteByRefererModel Model for analytics_website_by_referer table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
|
@ -24,6 +24,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
* @var string
|
||||
*/
|
||||
protected $returnType = AnalyticsWebsiteByReferer::class;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
|
@ -41,7 +42,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
*/
|
||||
public function getData(int $podcastId): array
|
||||
{
|
||||
if (!($found = cache("{$podcastId}_analytics_website_by_referer"))) {
|
||||
if (! ($found = cache("{$podcastId}_analytics_website_by_referer"))) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select('referer_url as labels')
|
||||
->selectSum('hits', 'values')
|
||||
|
|
@ -52,11 +53,8 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_website_by_referer",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_referer", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -69,7 +67,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
public function getDataByDomainWeekly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache("{$podcastId}_analytics_website_by_domain_weekly"))
|
||||
! ($found = cache("{$podcastId}_analytics_website_by_domain_weekly"))
|
||||
) {
|
||||
$oneWeekAgo = date('Y-m-d', strtotime('-1 week'));
|
||||
$found = $this->select("SUBSTRING_INDEX(domain, '.', -2) as labels")
|
||||
|
|
@ -81,11 +79,8 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_website_by_domain_weekly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_domain_weekly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
@ -98,7 +93,7 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
public function getDataByDomainYearly(int $podcastId): array
|
||||
{
|
||||
if (
|
||||
!($found = cache("{$podcastId}_analytics_website_by_domain_yearly"))
|
||||
! ($found = cache("{$podcastId}_analytics_website_by_domain_yearly"))
|
||||
) {
|
||||
$oneYearAgo = date('Y-m-d', strtotime('-1 year'));
|
||||
$found = $this->select("SUBSTRING_INDEX(domain, '.', -2) as labels")
|
||||
|
|
@ -110,11 +105,8 @@ class AnalyticsWebsiteByRefererModel extends Model
|
|||
->groupBy('labels')
|
||||
->orderBy('values', 'DESC')
|
||||
->findAll();
|
||||
cache()->save(
|
||||
"{$podcastId}_analytics_website_by_domain_yearly",
|
||||
$found,
|
||||
600,
|
||||
);
|
||||
cache()
|
||||
->save("{$podcastId}_analytics_website_by_domain_yearly", $found, 600,);
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,18 +15,15 @@ class Breadcrumb
|
|||
/**
|
||||
* List of breadcrumb links.
|
||||
*
|
||||
* $links = [
|
||||
* 'text' => 'Example Link',
|
||||
* 'href' => 'https://example.com/',
|
||||
* ]
|
||||
* $links = [ 'text' => 'Example Link', 'href' => 'https://example.com/', ]
|
||||
*
|
||||
* @var array<array<string, string>>
|
||||
*/
|
||||
protected array $links = [];
|
||||
|
||||
/**
|
||||
* Initializes the Breadcrumb object using the segments from
|
||||
* current_url by populating the $links property with text and href data
|
||||
* Initializes the Breadcrumb object using the segments from current_url by populating the $links property with text
|
||||
* and href data
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
|
@ -43,19 +40,13 @@ class Breadcrumb
|
|||
}
|
||||
|
||||
/**
|
||||
* Replaces all numeric text in breadcrumb's $link property
|
||||
* with new params at same position
|
||||
* Replaces all numeric text in breadcrumb's $link property with new params at same position
|
||||
*
|
||||
* Given a breadcrumb with numeric params, this function
|
||||
* replaces them with the values provided in $newParams
|
||||
* Given a breadcrumb with numeric params, this function replaces them with the values provided in $newParams
|
||||
*
|
||||
* Example with `Home / podcasts / 1 / episodes / 1`
|
||||
*
|
||||
* $newParams = [
|
||||
* 0 => 'foo',
|
||||
* 1 => 'bar'
|
||||
* ]
|
||||
* replaceParams($newParams);
|
||||
* $newParams = [ 0 => 'foo', 1 => 'bar' ] replaceParams($newParams);
|
||||
*
|
||||
* The breadcrumb is now `Home / podcasts / foo / episodes / bar`
|
||||
*
|
||||
|
|
@ -79,7 +70,7 @@ class Breadcrumb
|
|||
$listItems = '';
|
||||
$keys = array_keys($this->links);
|
||||
foreach ($this->links as $key => $link) {
|
||||
if (end($keys) == $key) {
|
||||
if (end($keys) === $key) {
|
||||
$listItem =
|
||||
'<li class="breadcrumb-item active" aria-current="page">' .
|
||||
$link['text'] .
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue