feat(settings): add general config for instance (site name, description and icon)
2
.gitignore
vendored
@ -137,9 +137,11 @@ node_modules
|
||||
|
||||
# public folder
|
||||
public/*
|
||||
public/media/site
|
||||
!public/media
|
||||
!public/.htaccess
|
||||
!public/favicon.ico
|
||||
!public/icon*
|
||||
!public/index.php
|
||||
!public/robots.txt
|
||||
|
||||
|
@ -427,4 +427,24 @@ class App extends BaseConfig
|
||||
* Defines the root folder for media files storage
|
||||
*/
|
||||
public string $mediaRoot = 'media';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Instance / Site Config
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
public string $siteName = 'Castopod';
|
||||
|
||||
public string $siteDescription = 'Castopod Host is an open-source hosting platform made for podcasters who want engage and interact with their audience.';
|
||||
|
||||
/**
|
||||
* @var array<int|string, string>
|
||||
*/
|
||||
public array $siteIcon = [
|
||||
'ico' => '/favicon.ico',
|
||||
'64' => '/icon-64.png',
|
||||
'180' => '/icon-180.png',
|
||||
'192' => '/icon-192.png',
|
||||
'512' => '/icon-512.png',
|
||||
];
|
||||
}
|
||||
|
@ -48,9 +48,13 @@ $routes->addPlaceholder(
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
$routes->get('manifest.webmanifest', 'WebmanifestController', [
|
||||
'as' => 'webmanifest',
|
||||
]);
|
||||
|
||||
// We get a performance increase by specifying the default
|
||||
// route since we don't have to scan directories.
|
||||
$routes->get('/', 'HomeController::index', [
|
||||
$routes->get('/', 'HomeController', [
|
||||
'as' => 'home',
|
||||
]);
|
||||
|
||||
|
45
app/Controllers/WebmanifestController.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
|
||||
class WebmanifestController extends Controller
|
||||
{
|
||||
public function index(): ResponseInterface
|
||||
{
|
||||
$webmanifest = [
|
||||
'name' => service('settings')
|
||||
->get('App.siteName'),
|
||||
'description' => service('settings')
|
||||
->get('App.siteDescription'),
|
||||
'display' => 'minimal-ui',
|
||||
'theme_color' => '#009486',
|
||||
'icons' => [
|
||||
[
|
||||
'src' => service('settings')
|
||||
->get('App.siteIcon')['192'],
|
||||
'type' => 'image/png',
|
||||
'sizes' => '192x192',
|
||||
],
|
||||
[
|
||||
'src' => service('settings')
|
||||
->get('App.siteIcon')['512'],
|
||||
'type' => 'image/png',
|
||||
'sizes' => '512x512',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $this->response->setJSON($webmanifest);
|
||||
}
|
||||
}
|
@ -40,6 +40,18 @@ class AuthSeeder extends Seeder
|
||||
* @var array<string, array<string, string|array>[]>
|
||||
*/
|
||||
protected array $permissions = [
|
||||
'settings' => [
|
||||
[
|
||||
'name' => 'view',
|
||||
'description' => 'View settings options',
|
||||
'has_permission' => ['superadmin'],
|
||||
],
|
||||
[
|
||||
'name' => 'manage',
|
||||
'description' => 'Update general settings',
|
||||
'has_permission' => ['superadmin'],
|
||||
],
|
||||
],
|
||||
'users' => [
|
||||
[
|
||||
'name' => 'create',
|
||||
|
@ -29,6 +29,9 @@ if (! function_exists('save_media')) {
|
||||
|
||||
if (! file_exists($mediaRoot)) {
|
||||
mkdir($mediaRoot, 0777, true);
|
||||
}
|
||||
|
||||
if (! file_exists($mediaRoot . '/index.html')) {
|
||||
touch($mediaRoot . '/index.html');
|
||||
}
|
||||
|
||||
|
@ -12,15 +12,17 @@
|
||||
"geoip2/geoip2": "^v2.11.0",
|
||||
"myth/auth": "dev-develop",
|
||||
"codeigniter4/codeigniter4": "dev-develop",
|
||||
"league/commonmark": "^1.6.6",
|
||||
"league/commonmark": "^v1.6.6",
|
||||
"vlucas/phpdotenv": "^v5.3.0",
|
||||
"league/html-to-markdown": "^5.0.0",
|
||||
"league/html-to-markdown": "^v5.0.1",
|
||||
"opawg/user-agents-php": "^v1.0",
|
||||
"podlibre/ipcat": "^v1.0",
|
||||
"podlibre/podcast-namespace": "^v1.0.6",
|
||||
"phpseclib/phpseclib": "~2.0.30",
|
||||
"michalsn/codeigniter4-uuid": "dev-develop",
|
||||
"essence/essence": "^3.5.4"
|
||||
"essence/essence": "^3.5.4",
|
||||
"codeigniter4/settings": "dev-develop",
|
||||
"chrisjean/php-ico": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "^v1.6.8",
|
||||
|
153
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "af4a438816f7adbbd6950d93ed333e9f",
|
||||
"content-hash": "f35a050323bdc632cd550f9d13f0679c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@ -60,6 +60,46 @@
|
||||
],
|
||||
"time": "2021-01-20T22:51:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "chrisjean/php-ico",
|
||||
"version": "1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chrisbliss18/php-ico.git",
|
||||
"reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/chrisbliss18/php-ico/zipball/ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6",
|
||||
"reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": ["class-php-ico.php"]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": ["GPL-2.0+"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Chris Jean",
|
||||
"homepage": "https://chrisjean.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "An easy-to-use library to generate valid ICO files.",
|
||||
"homepage": "https://github.com/chrisbliss18/php-ico",
|
||||
"keywords": ["favicon", "ico"],
|
||||
"support": {
|
||||
"issues": "https://github.com/chrisbliss18/php-ico/issues",
|
||||
"source": "https://github.com/chrisbliss18/php-ico"
|
||||
},
|
||||
"time": "2016-09-27T22:00:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "codeigniter4/codeigniter4",
|
||||
"version": "dev-develop",
|
||||
@ -137,6 +177,59 @@
|
||||
},
|
||||
"time": "2021-06-10T06:40:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "codeigniter4/settings",
|
||||
"version": "dev-develop",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeigniter4/settings.git",
|
||||
"reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeigniter4/settings/zipball/5d758e5e0a3f9dda9f66303d82ccfbb82e979577",
|
||||
"reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeigniter4/codeigniter4": "dev-develop",
|
||||
"fakerphp/faker": "^1.9",
|
||||
"mockery/mockery": "^1.0",
|
||||
"nexusphp/tachycardia": "^1.0",
|
||||
"php-coveralls/php-coveralls": "^2.4",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"squizlabs/php_codesniffer": "^3.3"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sparks\\Settings\\": "src"
|
||||
},
|
||||
"exclude-from-classmap": ["**/Database/Migrations/**"]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": ["MIT"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Lonnie Ezell",
|
||||
"email": "lonnieje@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Settings library for CodeIgniter 4",
|
||||
"homepage": "https://github.com/codeigniter4/settings",
|
||||
"keywords": ["Settings", "codeigniter", "codeigniter4"],
|
||||
"support": {
|
||||
"issues": "https://github.com/codeigniter4/settings/issues",
|
||||
"source": "https://github.com/codeigniter4/settings/tree/develop"
|
||||
},
|
||||
"time": "2021-08-16T05:07:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.2.10",
|
||||
@ -494,16 +587,16 @@
|
||||
},
|
||||
{
|
||||
"name": "james-heinrich/getid3",
|
||||
"version": "2.0.x-dev",
|
||||
"version": "v2.0.0-beta4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JamesHeinrich/getID3.git",
|
||||
"reference": "ee238d552571c6029898b087d5fc95df826418d6"
|
||||
"reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/ee238d552571c6029898b087d5fc95df826418d6",
|
||||
"reference": "ee238d552571c6029898b087d5fc95df826418d6",
|
||||
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/5ad79104e937e7d9c8a9141a97e1f063dd1123f8",
|
||||
"reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -562,9 +655,9 @@
|
||||
"keywords": ["audio", "codecs", "id3", "metadata", "tags", "video"],
|
||||
"support": {
|
||||
"issues": "https://github.com/JamesHeinrich/getID3/issues",
|
||||
"source": "https://github.com/JamesHeinrich/getID3/tree/2.0"
|
||||
"source": "https://github.com/JamesHeinrich/getID3/tree/v2.0.0-beta4"
|
||||
},
|
||||
"time": "2021-12-15T17:29:14+00:00"
|
||||
"time": "2021-10-06T16:23:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "kint-php/kint",
|
||||
@ -745,16 +838,16 @@
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/commonmark.git",
|
||||
"reference": "7d70d2f19c84bcc16275ea47edabee24747352eb"
|
||||
"reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/7d70d2f19c84bcc16275ea47edabee24747352eb",
|
||||
"reference": "7d70d2f19c84bcc16275ea47edabee24747352eb",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c4228d11e30d7493c6836d20872f9582d8ba6dcf",
|
||||
"reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -772,7 +865,7 @@
|
||||
"github/gfm": "0.29.0",
|
||||
"michelf/php-markdown": "~1.4",
|
||||
"mikehaertl/php-shellcommand": "^1.4",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpstan/phpstan": "^0.12.90",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.2",
|
||||
"scrutinizer/ocular": "^1.5",
|
||||
"symfony/finder": "^4.2"
|
||||
@ -838,37 +931,40 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-05-12T11:39:41+00:00"
|
||||
"time": "2021-07-17T17:13:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/html-to-markdown",
|
||||
"version": "4.10.0",
|
||||
"version": "5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||
"reference": "0868ae7a552e809e5cd8f93ba022071640408e88"
|
||||
"reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0868ae7a552e809e5cd8f93ba022071640408e88",
|
||||
"reference": "0868ae7a552e809e5cd8f93ba022071640408e88",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/e5600a2c5ce7b7571b16732c7086940f56f7abec",
|
||||
"reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-xml": "*",
|
||||
"php": ">=5.3.3"
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||
"phpunit/phpunit": "^4.8|^5.7",
|
||||
"scrutinizer/ocular": "~1.1"
|
||||
"mikehaertl/php-shellcommand": "^1.1.0",
|
||||
"phpstan/phpstan": "^0.12.82",
|
||||
"phpunit/phpunit": "^8.5 || ^9.2",
|
||||
"scrutinizer/ocular": "^1.6",
|
||||
"unleashedtech/php-coding-standard": "^2.7",
|
||||
"vimeo/psalm": "^4.6"
|
||||
},
|
||||
"bin": ["bin/html-to-markdown"],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.10-dev"
|
||||
"dev-master": "5.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -897,7 +993,7 @@
|
||||
"keywords": ["html", "markdown"],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/html-to-markdown/issues",
|
||||
"source": "https://github.com/thephpleague/html-to-markdown/tree/4.10.0"
|
||||
"source": "https://github.com/thephpleague/html-to-markdown/tree/5.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -913,11 +1009,11 @@
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/colinodell",
|
||||
"type": "patreon"
|
||||
"url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-01T00:34:03+00:00"
|
||||
"time": "2021-09-17T20:00:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maxmind-db/reader",
|
||||
@ -7457,7 +7553,8 @@
|
||||
"james-heinrich/getid3": 20,
|
||||
"myth/auth": 20,
|
||||
"codeigniter4/codeigniter4": 20,
|
||||
"michalsn/codeigniter4-uuid": 20
|
||||
"michalsn/codeigniter4-uuid": 20,
|
||||
"codeigniter4/settings": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
@ -7465,5 +7562,5 @@
|
||||
"php": "^8.0"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.1.0"
|
||||
}
|
||||
|
1
ecs.php
@ -17,7 +17,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
__DIR__ . '/themes',
|
||||
__DIR__ . '/tests',
|
||||
__DIR__ . '/public',
|
||||
__DIR__ . '/public',
|
||||
]);
|
||||
|
||||
$parameters->set(Option::SKIP, [
|
||||
|
@ -18,6 +18,21 @@ $routes->group(
|
||||
'as' => 'admin',
|
||||
]);
|
||||
|
||||
$routes->group('settings', function ($routes): void {
|
||||
$routes->get('/', 'SettingsController', [
|
||||
'as' => 'settings-general',
|
||||
'filter' => 'permission:settings-manage',
|
||||
]);
|
||||
$routes->post('instance', 'SettingsController::attemptInstanceEdit', [
|
||||
'as' => 'settings-instance',
|
||||
'filter' => 'permission:settings-manage',
|
||||
]);
|
||||
$routes->get('instance-delete-icon', 'SettingsController::deleteIcon', [
|
||||
'as' => 'settings-instance-delete-icon',
|
||||
'filter' => 'permission:settings-manage',
|
||||
]);
|
||||
});
|
||||
|
||||
$routes->group('persons', function ($routes): void {
|
||||
$routes->get('/', 'PersonController', [
|
||||
'as' => 'person-list',
|
||||
|
105
modules/Admin/Controllers/SettingsController.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace Modules\Admin\Controllers;
|
||||
|
||||
use CodeIgniter\HTTP\RedirectResponse;
|
||||
use PHP_ICO;
|
||||
|
||||
class SettingsController extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
helper('form');
|
||||
return view('settings/general');
|
||||
}
|
||||
|
||||
public function attemptInstanceEdit(): RedirectResponse
|
||||
{
|
||||
$rules = [
|
||||
'site_icon' =>
|
||||
'is_image[site_icon]|ext_in[site_icon,png,jpeg]|is_image_squared[site_icon]|min_dims[image,512,512]|permit_empty',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$siteName = $this->request->getPost('site_name');
|
||||
if ($siteName !== service('settings')->get('App.siteName')) {
|
||||
service('settings')->set('App.siteName', $siteName);
|
||||
}
|
||||
|
||||
$siteDescription = $this->request->getPost('site_description');
|
||||
if ($siteDescription !== service('settings')->get('App.siteDescription')) {
|
||||
service('settings')->set('App.siteDescription', $siteDescription);
|
||||
}
|
||||
|
||||
$siteIconFile = $this->request->getFile('site_icon');
|
||||
if ($siteIconFile !== null && $siteIconFile->isValid()) {
|
||||
helper(['filesystem', 'media']);
|
||||
|
||||
// delete site folder in media before repopulating it
|
||||
delete_files(ROOTPATH . 'public/media/site/');
|
||||
|
||||
// save original in disk
|
||||
$originalFilename = save_media($siteIconFile, 'site', 'icon');
|
||||
|
||||
// convert jpeg image to png if not
|
||||
if ($siteIconFile->getClientMimeType() !== 'image/png') {
|
||||
service('image')->withFile(ROOTPATH . 'public/media/' . $originalFilename)
|
||||
->convert(IMAGETYPE_JPEG)
|
||||
->save(ROOTPATH . 'public/media/site/icon.png');
|
||||
}
|
||||
|
||||
// generate random hash to use as a suffix to renew browser cache
|
||||
$randomHash = substr(bin2hex(random_bytes(18)), 0, 8);
|
||||
|
||||
// generate ico
|
||||
$ico_lib = new PHP_ICO();
|
||||
$ico_lib->add_image(ROOTPATH . 'public/media/site/icon.png', [[32, 32], [64, 64]]);
|
||||
$ico_lib->save_ico(ROOTPATH . "public/media/site/favicon.{$randomHash}.ico");
|
||||
|
||||
// resize original to needed sizes
|
||||
foreach ([64, 180, 192, 512] as $size) {
|
||||
service('image')
|
||||
->withFile(ROOTPATH . 'public/media/site/icon.png')
|
||||
->resize($size, $size)
|
||||
->save(ROOTPATH . "public/media/site/icon-{$size}.{$randomHash}.png");
|
||||
}
|
||||
|
||||
service('settings')
|
||||
->set('App.siteIcon', [
|
||||
'ico' => "/media/site/favicon.{$randomHash}.ico",
|
||||
'64' => "/media/site/icon-64.{$randomHash}.png",
|
||||
'180' => "/media/site/icon-180.{$randomHash}.png",
|
||||
'192' => "/media/site/icon-192.{$randomHash}.png",
|
||||
'512' => "/media/site/icon-512.{$randomHash}.png",
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function deleteIcon(): RedirectResponse
|
||||
{
|
||||
helper('filesystem');
|
||||
// delete site folder in media
|
||||
delete_files(ROOTPATH . 'public/media/site/');
|
||||
|
||||
service('settings')
|
||||
->forget('App.siteIcon');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
@ -29,6 +29,8 @@ return [
|
||||
'pages' => 'Pages',
|
||||
'page-list' => 'All pages',
|
||||
'page-create' => 'New Page',
|
||||
'settings' => 'Settings',
|
||||
'settings-general' => 'General',
|
||||
'account' => [
|
||||
'my-account' => 'My account',
|
||||
'change-password' => 'Change password',
|
||||
|
@ -16,6 +16,7 @@ return [
|
||||
'episodes' => 'episodes',
|
||||
'contributors' => 'contributors',
|
||||
'pages' => 'pages',
|
||||
'settings' => 'settings',
|
||||
'add' => 'add',
|
||||
'new' => 'new',
|
||||
'edit' => 'edit',
|
||||
|
23
modules/Admin/Language/en/Settings.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
return [
|
||||
'title' => 'General settings',
|
||||
'form' => [
|
||||
'site_section_title' => 'Instance',
|
||||
'site_icon' => 'Site icon',
|
||||
'site_icon_delete' => 'Delete site icon',
|
||||
'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.',
|
||||
'site_icon_helper' => 'Icon must be squared with at least 512px wide and tall.',
|
||||
'site_name' => 'Site name',
|
||||
'site_description' => 'Site description',
|
||||
'submit' => 'Save',
|
||||
],
|
||||
];
|
@ -28,6 +28,8 @@ return [
|
||||
'pages' => 'Pages',
|
||||
'page-list' => 'Toutes les pages',
|
||||
'page-create' => 'Créer une page',
|
||||
'settings' => 'Paramètres',
|
||||
'settings-general' => 'Général',
|
||||
'account' => [
|
||||
'my-account' => 'Mon compte',
|
||||
'change-password' => 'Modifier le mot de passe',
|
||||
|
24
modules/Admin/Language/fr/Settings.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
return [
|
||||
'title' => 'Paramètres généraux',
|
||||
'form' => [
|
||||
'site_section_title' => 'Instance',
|
||||
'site_section_subtitle' => 'configuration de l’instance',
|
||||
'site_icon' => 'Favicon du site',
|
||||
'site_icon_delete' => 'Supprimer la favicon du site',
|
||||
'site_icon_hint' => 'Les favicons sont ce que vous voyez sur les onglets de votre navigateur, dans votre barre de favoris, et lorsque vous ajoutez un site web en raccourci sur des appareils mobiles.',
|
||||
'site_icon_helper' => 'La favicon doit être carrée et avoir au moins 512px de largeur et de hauteur.',
|
||||
'site_name' => 'Titre du site',
|
||||
'site_description' => 'Description du site',
|
||||
'submit' => 'Save',
|
||||
],
|
||||
];
|
@ -243,6 +243,8 @@ class InstallController extends Controller
|
||||
{
|
||||
$migrations = Services::migrations();
|
||||
|
||||
$migrations->setNamespace('Sparks\Settings')
|
||||
->latest();
|
||||
$migrations->setNamespace('Myth\Auth')
|
||||
->latest();
|
||||
$migrations->setNamespace('Modules\Fediverse')
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 21 KiB |
BIN
public/icon-180.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
public/icon-192.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
public/icon-512.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
public/icon-64.png
Normal file
After Width: | Height: | Size: 738 B |
BIN
public/icon.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
@ -7,7 +7,10 @@
|
||||
<title><?= $this->renderSection('title') ?> | Castopod Admin</title>
|
||||
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
|
@ -22,6 +22,10 @@ $navigation = [
|
||||
'items' => ['page-list', 'page-create'],
|
||||
|
||||
],
|
||||
'settings' => [
|
||||
'icon' => 'settings',
|
||||
'items' => ['settings-general'],
|
||||
],
|
||||
]; ?>
|
||||
|
||||
<nav class="flex flex-col flex-1 py-4 overflow-y-auto gap-y-4">
|
||||
|
@ -35,6 +35,7 @@
|
||||
label="<?= lang('Person.form.unique_name') ?>"
|
||||
hint="<?= lang('Person.form.unique_name_hint') ?>"
|
||||
required="true" />
|
||||
|
||||
<Forms.Field
|
||||
name="information_url"
|
||||
label="<?= lang('Person.form.information_url') ?>"
|
||||
|
59
themes/cp_admin/settings/general.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?= $this->extend('_layout') ?>
|
||||
|
||||
<?= $this->section('title') ?>
|
||||
<?= lang('Settings.title') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('pageTitle') ?>
|
||||
<?= lang('Settings.title') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<form action="<?= route_to('settings-instance') ?>" method="POST" class="flex flex-col max-w-sm gap-y-4" enctype="multipart/form-data">
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<Forms.Section
|
||||
title="<?= lang('Settings.form.site_section_title') ?>">
|
||||
|
||||
<Forms.Field
|
||||
name="site_name"
|
||||
label="<?= lang('Settings.form.site_name') ?>"
|
||||
value="<?= service('settings')
|
||||
->get('App.siteName') ?>"
|
||||
required="true" />
|
||||
|
||||
<Forms.Field
|
||||
as="Textarea"
|
||||
name="site_description"
|
||||
label="<?= lang('Settings.form.site_description') ?>"
|
||||
value="<?= service('settings')
|
||||
->get('App.siteDescription') ?>"
|
||||
required="true"
|
||||
rows="4" />
|
||||
|
||||
<div class="flex items-center">
|
||||
<Forms.Field
|
||||
name="site_icon"
|
||||
type="file"
|
||||
label="<?= lang('Settings.form.site_icon') ?>"
|
||||
hint="<?= lang('Settings.form.site_icon_hint') ?>"
|
||||
helper="<?= lang('Settings.form.site_icon_helper') ?>"
|
||||
accept=".png,.jpeg"
|
||||
class="flex-1"
|
||||
/>
|
||||
<?php if (config('App')->siteIcon['ico'] !== service('settings')->get('App.siteIcon')['ico']): ?>
|
||||
<div class="relative ml-2">
|
||||
<a href="<?= route_to('settings-instance-delete-icon') ?>" class="absolute p-1 text-white bg-red-600 border-2 border-black rounded-full hover:bg-red-800 -top-3 -right-3 focus:ring-castopod" title="<?= lang('Settings.form.site_icon_delete') ?>"><?= icon('delete-bin') ?></a>
|
||||
<img src="<?= service('settings')->get('App.siteIcon')['64'] ?>" alt="<?= service('settings')->get('App.siteName') ?> Favicon" class="w-10 h-10" />
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<Button variant="primary" type="submit" class="self-end"><?= lang('Settings.form.submit') ?></Button>
|
||||
|
||||
</Forms.Section>
|
||||
|
||||
</form>
|
||||
|
||||
<?= $this->endSection() ?>
|
@ -6,9 +6,20 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title><?= $this->renderSection('title') ?></title>
|
||||
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
|
||||
<meta name="description" content="<?= service('settings')
|
||||
->get('App.siteDescription') ?>"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<meta property="og:title" content="<?= service('settings')
|
||||
->get('App.siteName') ?>" />
|
||||
<meta property="og:description" content="<?= service('settings')
|
||||
->get('App.siteDescription') ?>" />
|
||||
<meta property="og:site_name" content="<?= service('settings')
|
||||
->get('App.siteName') ?>" />
|
||||
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
|
@ -8,7 +8,10 @@
|
||||
<meta name="description" content="<?= htmlspecialchars(
|
||||
$episode->description,
|
||||
) ?>" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<link rel="canonical" href="<?= $episode->link ?>" />
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
|
@ -7,7 +7,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<?= $this->renderSection('meta-tags') ?>
|
||||
<?php if ($podcast->payment_pointer): ?>
|
||||
|
@ -5,10 +5,23 @@
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Castopod</title>
|
||||
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
|
||||
<title><?= service('settings')
|
||||
->get('App.siteName') ?></title>
|
||||
<meta name="description" content="<?= service('settings')
|
||||
->get('App.siteDescription') ?>"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<meta property="og:title" content="<?= service('settings')
|
||||
->get('App.siteName') ?>" />
|
||||
<meta property="og:description" content="<?= service('settings')
|
||||
->get('App.siteDescription') ?>" />
|
||||
<meta property="og:site_name" content="<?= service('settings')
|
||||
->get('App.siteName') ?>" />
|
||||
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
<?= service('vite')
|
||||
|
@ -8,7 +8,10 @@
|
||||
<title><?= lang('Page.map') ?></title>
|
||||
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
<?= service('vite')
|
||||
|
@ -7,7 +7,10 @@
|
||||
<meta charset="UTF-8"/>
|
||||
<title><?= $page->title ?></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
<?= service('vite')
|
||||
|
@ -7,7 +7,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<?= $this->renderSection('meta-tags') ?>
|
||||
<?php if ($podcast->payment_pointer): ?>
|
||||
|
@ -9,7 +9,10 @@
|
||||
<meta name="description" content="<?= htmlspecialchars(
|
||||
$podcast->description,
|
||||
) ?>" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<link rel="canonical" href="<?= current_url() ?>" />
|
||||
<meta property="og:title" content="<?= $podcast->title ?>" />
|
||||
<meta property="og:description" content="<?= $podcast->description ?>" />
|
||||
|
@ -7,7 +7,10 @@
|
||||
<meta name="description" content="<?= htmlspecialchars(
|
||||
$podcast->description,
|
||||
) ?>" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<link rel="canonical" href="<?= current_url() ?>" />
|
||||
<meta property="og:title" content="<?= $podcast->title ?>" />
|
||||
<meta property="og:description" content="<?= $podcast->description ?>" />
|
||||
|
@ -7,7 +7,10 @@
|
||||
<meta name="description" content="<?= htmlspecialchars(
|
||||
$podcast->description,
|
||||
) ?>" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<link rel="canonical" href="<?= current_url() ?>" />
|
||||
<meta property="og:title" content="<?= $podcast->title ?>" />
|
||||
<meta property="og:description" content="<?= $podcast->description ?>" />
|
||||
|
@ -7,8 +7,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<?= service('vite')->asset('styles/index.css', 'css') ?>
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<title><?= lang('Podcast.followTitle', [
|
||||
'actorDisplayName' => $actor->display_name,
|
||||
|
@ -5,7 +5,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
|
||||
<title><?= lang('Fediverse.' . $action . '.title', [
|
||||
'actorDisplayName' => $post->actor->display_name,
|
||||
|
@ -7,7 +7,7 @@
|
||||
<title>Castopod Auth</title>
|
||||
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
</head>
|
||||
|
@ -6,7 +6,10 @@
|
||||
<title>Castopod</title>
|
||||
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/x-icon" href="<?= service('settings')
|
||||
->get('App.siteIcon')['ico'] ?>" />
|
||||
<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
|
||||
<link rel="manifest" href="<?= route_to('webmanifest') ?>">
|
||||
<?= service('vite')
|
||||
->asset('styles/index.css', 'css') ?>
|
||||
<?= service('vite')
|
||||
|