mirror of
https://code.castopod.org/adaures/castopod
synced 2025-04-19 13:01:19 +00:00
feat: create optimized & resized images upon upload
- resize uploaded image to thumbnail, medium, large, feed, and id3 formats - set image url formats where adapted in views - set format sizes and extensions in Images config file for customization - add validation for image uploads: `min_dims` and `is_image_squared` - update codeigniter4 and myth-auth php packages to latest develop versions - update npm packages to latest versions - update public/.htaccess closes #6
This commit is contained in:
parent
40a0535fc1
commit
02e4441f98
@ -10,8 +10,12 @@ WORKDIR /castopod
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libicu-dev \
|
||||
libpng-dev \
|
||||
libjpeg-dev \
|
||||
zlib1g-dev \
|
||||
&& docker-php-ext-install intl gd
|
||||
&& docker-php-ext-install intl
|
||||
|
||||
RUN docker-php-ext-configure gd --with-jpeg-dir=/usr/include/ \
|
||||
&& docker-php-ext-install gd
|
||||
|
||||
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
|
||||
|
||||
@ -19,4 +23,5 @@ RUN echo "file_uploads = On\n" \
|
||||
"memory_limit = 100M\n" \
|
||||
"upload_max_filesize = 100M\n" \
|
||||
"post_max_size = 120M\n" \
|
||||
"max_execution_time = 300\n" \
|
||||
> /usr/local/etc/php/conf.d/uploads.ini
|
||||
|
@ -30,4 +30,73 @@ class Images extends BaseConfig
|
||||
'gd' => \CodeIgniter\Images\Handlers\GDHandler::class,
|
||||
'imagick' => \CodeIgniter\Images\Handlers\ImageMagickHandler::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* 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).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $thumbnailSize = 150;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $mediumSize = 320;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $largeSize = 1024;
|
||||
|
||||
/**
|
||||
* Size of images linked in the rss feed (should be between 1400 and 3000)
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $feedSize = 1400;
|
||||
|
||||
/**
|
||||
* Size for ID3 tag cover art (should be between 300 and 800)
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $id3Size = 500;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Uploaded images naming extensions
|
||||
* --------------------------------------------------------------------------
|
||||
* The properties listed below set the name extensions for the resized images
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $thumbnailExtension = '_thumbnail';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $mediumExtension = '_medium';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $largeExtension = '_large';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $feedExtension = '_feed';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $id3Extension = '_id3';
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ class Validation
|
||||
public $ruleSets = [
|
||||
\CodeIgniter\Validation\Rules::class,
|
||||
\CodeIgniter\Validation\FormatRules::class,
|
||||
\CodeIgniter\Validation\FileRules::class,
|
||||
\CodeIgniter\Validation\CreditCardRules::class,
|
||||
\App\Validation\Rules::class,
|
||||
\App\Validation\FileRules::class,
|
||||
\Myth\Auth\Authentication\Passwords\ValidationRules::class,
|
||||
];
|
||||
|
||||
|
@ -85,7 +85,7 @@ class Episode extends BaseController
|
||||
$rules = [
|
||||
'enclosure' => 'uploaded[enclosure]|ext_in[enclosure,mp3,m4a]',
|
||||
'image' =>
|
||||
'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|permit_empty',
|
||||
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||
'publication_date' => 'valid_date[Y-m-d]|permit_empty',
|
||||
'publication_time' =>
|
||||
'regex_match[/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/]|permit_empty',
|
||||
@ -151,7 +151,7 @@ class Episode extends BaseController
|
||||
'enclosure' =>
|
||||
'uploaded[enclosure]|ext_in[enclosure,mp3,m4a]|permit_empty',
|
||||
'image' =>
|
||||
'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|permit_empty',
|
||||
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||
'publication_date' => 'valid_date[Y-m-d]|permit_empty',
|
||||
'publication_time' =>
|
||||
'regex_match[/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/]|permit_empty',
|
||||
|
@ -79,7 +79,8 @@ class Podcast extends BaseController
|
||||
public function attemptCreate()
|
||||
{
|
||||
$rules = [
|
||||
'image' => 'uploaded[image]|is_image[image]|ext_in[image,jpg,png]',
|
||||
'image' =>
|
||||
'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
@ -162,8 +163,9 @@ class Podcast extends BaseController
|
||||
helper(['media', 'misc']);
|
||||
|
||||
$rules = [
|
||||
'name' => 'required',
|
||||
'imported_feed_url' => 'required',
|
||||
'imported_feed_url' => 'required|valid_url',
|
||||
'season_number' => 'is_natural_no_zero|permit_empty',
|
||||
'max_episodes' => 'is_natural_no_zero|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
@ -217,8 +219,6 @@ class Podcast extends BaseController
|
||||
'complete' => empty($nsItunes->complete)
|
||||
? false
|
||||
: $nsItunes->complete == 'yes',
|
||||
'episode_description_footer' => '',
|
||||
'custom_html_head' => '',
|
||||
'created_by' => user(),
|
||||
'updated_by' => user(),
|
||||
]);
|
||||
@ -299,9 +299,10 @@ class Podcast extends BaseController
|
||||
? null
|
||||
: download_file($nsItunes->image->attributes()),
|
||||
'explicit' => $nsItunes->explicit == 'yes',
|
||||
'number' => $this->request->getPost('force_renumber')
|
||||
? $itemNumber
|
||||
: $nsItunes->episode,
|
||||
'number' =>
|
||||
$this->request->getPost('force_renumber') == 'yes'
|
||||
? $itemNumber
|
||||
: $nsItunes->episode,
|
||||
'season_number' => empty(
|
||||
$this->request->getPost('season_number')
|
||||
)
|
||||
@ -358,7 +359,7 @@ class Podcast extends BaseController
|
||||
{
|
||||
$rules = [
|
||||
'image' =>
|
||||
'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|permit_empty',
|
||||
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
|
@ -47,6 +47,8 @@ class Analytics extends Controller
|
||||
// Add one hit to this episode:
|
||||
public function hit($p_podcastId, $p_episodeId, ...$filename)
|
||||
{
|
||||
helper('media');
|
||||
|
||||
podcast_hit($p_podcastId, $p_episodeId);
|
||||
return redirect()->to(media_url(implode('/', $filename)));
|
||||
}
|
||||
|
@ -25,20 +25,10 @@ class Episode extends Entity
|
||||
protected $link;
|
||||
|
||||
/**
|
||||
* @var \CodeIgniter\Files\File
|
||||
* @var \App\Entities\Image
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $image_media_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $image_url;
|
||||
|
||||
/**
|
||||
* @var \CodeIgniter\Files\File
|
||||
*/
|
||||
@ -98,33 +88,30 @@ class Episode extends Entity
|
||||
(!($image instanceof \CodeIgniter\HTTP\Files\UploadedFile) ||
|
||||
$image->isValid())
|
||||
) {
|
||||
helper('media');
|
||||
|
||||
// check whether the user has inputted an image and store it
|
||||
$this->attributes['image_uri'] = save_podcast_media(
|
||||
$image,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug']
|
||||
);
|
||||
|
||||
$this->image = new \App\Entities\Image(
|
||||
$this->attributes['image_uri']
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImage(): \CodeIgniter\Files\File
|
||||
{
|
||||
return new \CodeIgniter\Files\File($this->getImageMediaPath());
|
||||
}
|
||||
|
||||
public function getImageMediaPath(): string
|
||||
{
|
||||
return media_path($this->attributes['image_uri']);
|
||||
}
|
||||
|
||||
public function getImageUrl(): string
|
||||
public function getImage(): \App\Entities\Image
|
||||
{
|
||||
if ($image_uri = $this->attributes['image_uri']) {
|
||||
return media_url($image_uri);
|
||||
return new \App\Entities\Image($image_uri);
|
||||
}
|
||||
return $this->getPodcast()->image_url;
|
||||
return $this->getPodcast()->image;
|
||||
}
|
||||
|
||||
/**
|
||||
|
151
app/Entities/Image.php
Normal file
151
app/Entities/Image.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace App\Entities;
|
||||
|
||||
use CodeIgniter\Entity;
|
||||
|
||||
class Image extends Entity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $original_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $original_url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $thumbnail_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $thumbnail_url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $medium_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $medium_url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $large_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $large_url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $feed_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $feed_url;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $id3_path;
|
||||
|
||||
public function __construct($originalUri)
|
||||
{
|
||||
helper('media');
|
||||
|
||||
$originalPath = media_path($originalUri);
|
||||
|
||||
[
|
||||
'filename' => $filename,
|
||||
'dirname' => $dirname,
|
||||
'extension' => $extension,
|
||||
] = pathinfo($originalPath);
|
||||
|
||||
// load images extensions from config
|
||||
$imageConfig = config('Images');
|
||||
$thumbnailExtension = $imageConfig->thumbnailExtension;
|
||||
$mediumExtension = $imageConfig->mediumExtension;
|
||||
$largeExtension = $imageConfig->largeExtension;
|
||||
$feedExtension = $imageConfig->feedExtension;
|
||||
$id3Extension = $imageConfig->id3Extension;
|
||||
|
||||
$thumbnail =
|
||||
$dirname . '/' . $filename . $thumbnailExtension . '.' . $extension;
|
||||
$medium =
|
||||
$dirname . '/' . $filename . $mediumExtension . '.' . $extension;
|
||||
$large =
|
||||
$dirname . '/' . $filename . $largeExtension . '.' . $extension;
|
||||
$feed = $dirname . '/' . $filename . $feedExtension . '.' . $extension;
|
||||
$id3 = $dirname . '/' . $filename . $id3Extension . '.' . $extension;
|
||||
|
||||
parent::__construct([
|
||||
'original_path' => $originalPath,
|
||||
'original_url' => media_url($originalUri),
|
||||
'thumbnail_path' => $thumbnail,
|
||||
'thumbnail_url' => base_url($thumbnail),
|
||||
'medium_path' => $medium,
|
||||
'medium_url' => base_url($medium),
|
||||
'large_path' => $large,
|
||||
'large_url' => base_url($large),
|
||||
'feed_path' => $feed,
|
||||
'feed_url' => base_url($feed),
|
||||
'id3_path' => $id3,
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveSizes()
|
||||
{
|
||||
// load images sizes from config
|
||||
$imageConfig = config('Images');
|
||||
$thumbnailSize = $imageConfig->thumbnailSize;
|
||||
$mediumSize = $imageConfig->mediumSize;
|
||||
$largeSize = $imageConfig->largeSize;
|
||||
$feedSize = $imageConfig->feedSize;
|
||||
$id3Size = $imageConfig->id3Size;
|
||||
|
||||
$imageService = \Config\Services::image();
|
||||
|
||||
$imageService
|
||||
->withFile($this->attributes['original_path'])
|
||||
->resize($thumbnailSize, $thumbnailSize)
|
||||
->save($this->attributes['thumbnail_path']);
|
||||
|
||||
$imageService
|
||||
->withFile($this->attributes['original_path'])
|
||||
->resize($mediumSize, $mediumSize)
|
||||
->save($this->attributes['medium_path']);
|
||||
|
||||
$imageService
|
||||
->withFile($this->attributes['original_path'])
|
||||
->resize($largeSize, $largeSize)
|
||||
->save($this->attributes['large_path']);
|
||||
|
||||
$imageService
|
||||
->withFile($this->attributes['original_path'])
|
||||
->resize($feedSize, $feedSize)
|
||||
->save($this->attributes['feed_path']);
|
||||
|
||||
$imageService
|
||||
->withFile($this->attributes['original_path'])
|
||||
->resize($id3Size, $id3Size)
|
||||
->save($this->attributes['id3_path']);
|
||||
}
|
||||
}
|
@ -23,20 +23,10 @@ class Podcast extends Entity
|
||||
protected $link;
|
||||
|
||||
/**
|
||||
* @var \CodeIgniter\Files\File
|
||||
* @var \App\Entities\Image
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $image_media_path;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $image_url;
|
||||
|
||||
/**
|
||||
* @var \App\Entities\Episode[]
|
||||
*/
|
||||
@ -101,24 +91,18 @@ class Podcast extends Entity
|
||||
$this->attributes['name'],
|
||||
'cover'
|
||||
);
|
||||
|
||||
return $this;
|
||||
$this->image = new \App\Entities\Image(
|
||||
$this->attributes['image_uri']
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImage()
|
||||
{
|
||||
return new \CodeIgniter\Files\File($this->getImageMediaPath());
|
||||
}
|
||||
|
||||
public function getImageMediaPath()
|
||||
{
|
||||
return media_path($this->attributes['image_uri']);
|
||||
}
|
||||
|
||||
public function getImageUrl()
|
||||
{
|
||||
return media_url($this->attributes['image_uri']);
|
||||
return new \App\Entities\Image($this->attributes['image_uri']);
|
||||
}
|
||||
|
||||
public function getLink()
|
||||
|
@ -47,7 +47,7 @@ function write_enclosure_tags($episode)
|
||||
$tagwriter->tagformats = ['id3v2.4'];
|
||||
$tagwriter->tag_encoding = $TextEncoding;
|
||||
|
||||
$cover = new \CodeIgniter\Files\File($episode->image_media_path);
|
||||
$cover = new \CodeIgniter\Files\File($episode->image->id3_path);
|
||||
|
||||
$APICdata = file_get_contents($cover->getRealPath());
|
||||
|
||||
|
@ -19,17 +19,15 @@ function save_podcast_media($file, $podcast_name, $media_name)
|
||||
{
|
||||
$file_name = $media_name . '.' . $file->getExtension();
|
||||
|
||||
if (!file_exists(config('App')->mediaRoot . '/' . $podcast_name)) {
|
||||
mkdir(config('App')->mediaRoot . '/' . $podcast_name, 0777, true);
|
||||
touch(config('App')->mediaRoot . '/' . $podcast_name . '/index.html');
|
||||
$mediaRoot = config('App')->mediaRoot;
|
||||
|
||||
if (!file_exists($mediaRoot . '/' . $podcast_name)) {
|
||||
mkdir($mediaRoot . '/' . $podcast_name, 0777, true);
|
||||
touch($mediaRoot . '/' . $podcast_name . '/index.html');
|
||||
}
|
||||
|
||||
// move to media folder and overwrite file if already existing
|
||||
$file->move(
|
||||
config('App')->mediaRoot . '/' . $podcast_name . '/',
|
||||
$file_name,
|
||||
true
|
||||
);
|
||||
$file->move($mediaRoot . '/' . $podcast_name . '/', $file_name, true);
|
||||
|
||||
return $podcast_name . '/' . $file_name;
|
||||
}
|
||||
@ -64,3 +62,15 @@ function media_path($uri = ''): string
|
||||
|
||||
return config('App')->mediaRoot . '/' . $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the media base URL to use in views
|
||||
*
|
||||
* @param mixed $uri URI string or array of URI segments
|
||||
* @param string $protocol
|
||||
* @return string
|
||||
*/
|
||||
function media_url($uri = '', string $protocol = null): string
|
||||
{
|
||||
return base_url(config('App')->mediaRoot . '/' . $uri, $protocol);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ function get_rss_feed($podcast)
|
||||
$channel->addChild('title', $podcast->title);
|
||||
$channel->addChildWithCDATA('description', $podcast->description_html);
|
||||
$itunes_image = $channel->addChild('image', null, $itunes_namespace);
|
||||
$itunes_image->addAttribute('href', $podcast->image_url);
|
||||
$itunes_image->addAttribute('href', $podcast->image->url);
|
||||
$channel->addChild('language', $podcast->language);
|
||||
|
||||
$itunes_category = $channel->addChild('category', null, $itunes_namespace);
|
||||
@ -106,7 +106,7 @@ function get_rss_feed($podcast)
|
||||
$channel->addChild('complete', 'Yes', $itunes_namespace);
|
||||
|
||||
$image = $channel->addChild('image');
|
||||
$image->addChild('url', $podcast->image_url);
|
||||
$image->addChild('url', $podcast->image->feed_url);
|
||||
$image->addChild('title', $podcast->title);
|
||||
$image->addChild('link', $podcast->link);
|
||||
|
||||
@ -136,7 +136,7 @@ function get_rss_feed($podcast)
|
||||
null,
|
||||
$itunes_namespace
|
||||
);
|
||||
$episode_itunes_image->addAttribute('href', $episode->image_url);
|
||||
$episode_itunes_image->addAttribute('href', $episode->image->feed_url);
|
||||
$item->addChild(
|
||||
'explicit',
|
||||
$episode->explicit ? 'true' : 'false',
|
||||
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return the media base URL to use in views
|
||||
*
|
||||
* @param mixed $uri URI string or array of URI segments
|
||||
* @param string $protocol
|
||||
* @return string
|
||||
*/
|
||||
function media_url($uri = '', string $protocol = null): string
|
||||
{
|
||||
return base_url(config('App')->mediaRoot . '/' . $uri, $protocol);
|
||||
}
|
@ -12,4 +12,8 @@ return [
|
||||
'mediumDate' => '{0,date,medium}',
|
||||
'duration' => '{0,duration}',
|
||||
'powered_by' => 'Powered by {castopod}.',
|
||||
'forms' => [
|
||||
'image_size_hint' =>
|
||||
'Image must be squared with at least 1400px wide and tall.',
|
||||
],
|
||||
];
|
||||
|
@ -9,4 +9,8 @@
|
||||
return [
|
||||
'not_in_protected_slugs' =>
|
||||
'The {field} field conflicts with one of the gateway routes (admin, auth or install).',
|
||||
'min_dims' =>
|
||||
'{field} is either not an image, or it is not wide or tall enough.',
|
||||
'is_image_squared' =>
|
||||
'{field} is either not an image, or it is not squared (width and height differ).',
|
||||
];
|
||||
|
105
app/Validation/FileRules.php
Normal file
105
app/Validation/FileRules.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
namespace App\Validation;
|
||||
|
||||
use CodeIgniter\Validation\FileRules as ValidationFileRules;
|
||||
|
||||
class FileRules extends ValidationFileRules
|
||||
{
|
||||
/**
|
||||
* Checks an uploaded file to verify that the dimensions are within
|
||||
* a specified allowable dimension.
|
||||
*
|
||||
* @param string|null $blank
|
||||
* @param string $params
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function min_dims(string $blank = null, string $params): bool
|
||||
{
|
||||
// Grab the file name off the top of the $params
|
||||
// after we split it.
|
||||
$params = explode(',', $params);
|
||||
$name = array_shift($params);
|
||||
|
||||
if (!($files = $this->request->getFileMultiple($name))) {
|
||||
$files = [$this->request->getFile($name)];
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (is_null($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get Parameter sizes
|
||||
$minWidth = $params[0] ?? 0;
|
||||
$minHeight = $params[1] ?? 0;
|
||||
|
||||
// Get uploaded image size
|
||||
$info = getimagesize($file->getTempName());
|
||||
$fileWidth = $info[0];
|
||||
$fileHeight = $info[1];
|
||||
|
||||
if ($fileWidth < $minWidth || $fileHeight < $minHeight) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks an uploaded file to verify that the image ratio is of 1:1
|
||||
*
|
||||
* @param string|null $blank
|
||||
* @param string $params
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_image_squared(string $blank = null, string $params): bool
|
||||
{
|
||||
// Grab the file name off the top of the $params
|
||||
// after we split it.
|
||||
$params = explode(',', $params);
|
||||
$name = array_shift($params);
|
||||
|
||||
if (!($files = $this->request->getFileMultiple($name))) {
|
||||
$files = [$this->request->getFile($name)];
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (is_null($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($file->getError() === UPLOAD_ERR_NO_FILE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get uploaded image size
|
||||
$info = getimagesize($file->getTempName());
|
||||
$fileWidth = $info[0];
|
||||
$fileHeight = $info[1];
|
||||
|
||||
if ($fileWidth != $fileHeight) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
@ -27,4 +27,6 @@ class Rules
|
||||
];
|
||||
return !in_array($value, $protectedSlugs, true);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
<article class="flex w-full max-w-lg mb-4 bg-white border rounded shadow">
|
||||
<img src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-32 h-32 rounded-l" />
|
||||
<img
|
||||
loading="lazy"
|
||||
src="<?= $episode->image->thumbnail_url ?>"
|
||||
alt="<?= $episode->title ?>" class="object-cover w-32 h-32 rounded-l" />
|
||||
<div class="flex flex-col flex-1 px-4 py-2">
|
||||
<a href="<?= route_to(
|
||||
'episode-view',
|
||||
|
@ -1,5 +1,8 @@
|
||||
<article class="w-48 h-full mb-4 mr-4 overflow-hidden bg-white border rounded shadow">
|
||||
<img alt="<?= $podcast->title ?>" src="<?= $podcast->image_url ?>" class="object-cover w-full h-40" />
|
||||
<img
|
||||
alt="<?= $podcast->title ?>"
|
||||
src="<?= $podcast->image
|
||||
->thumbnail_url ?>" class="object-cover w-full h-40" />
|
||||
<div class="p-2">
|
||||
<a href="<?= route_to(
|
||||
'podcast-view',
|
||||
|
@ -23,6 +23,18 @@
|
||||
'accept' => '.mp3,.m4a',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Episode.form.image'), 'image') ?>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
<small class="mb-4 text-gray-600"><?= lang(
|
||||
'Common.forms.image_size_hint'
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(lang('Episode.form.title'), 'title') ?>
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
@ -87,16 +99,6 @@
|
||||
</div>
|
||||
<?= form_fieldset_close() ?>
|
||||
|
||||
|
||||
<?= form_label(lang('Episode.form.image'), 'image') ?>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input mb-4',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Episode.form.season_number'), 'season_number') ?>
|
||||
<?= form_input([
|
||||
'id' => 'season_number',
|
||||
|
@ -22,6 +22,23 @@
|
||||
'accept' => '.mp3,.m4a',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Episode.form.image'), 'image') ?>
|
||||
<img
|
||||
src="<?= $episode->image->thumbnail_url ?>"
|
||||
alt="<?= $episode->title ?>"
|
||||
class="object-cover w-32 h-32"
|
||||
/>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
<small class="mb-4 text-gray-600"><?= lang(
|
||||
'Common.forms.image_size_hint'
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(lang('Episode.form.title'), 'title') ?>
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
@ -94,16 +111,6 @@
|
||||
</div>
|
||||
<?= form_fieldset_close() ?>
|
||||
|
||||
<?= form_label(lang('Episode.form.image'), 'image') ?>
|
||||
<img src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-32 h-32" />
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input mb-4',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Episode.form.season_number'), 'season_number') ?>
|
||||
<?= form_input([
|
||||
'id' => 'season_number',
|
||||
|
@ -6,7 +6,11 @@
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<img src="<?= $episode->image_url ?>" alt="Episode cover" class="object-cover w-40 h-40 mb-6" />
|
||||
<img
|
||||
src="<?= $episode->image->medium_url ?>"
|
||||
alt="Episode cover"
|
||||
class="object-cover w-40 h-40 mb-6"
|
||||
/>
|
||||
<audio controls preload="none" class="mb-12">
|
||||
<source src="<?= $episode->enclosure_url ?>" type="<?= $episode->enclosure_type ?>">
|
||||
Your browser does not support the audio tag.
|
||||
|
@ -13,6 +13,19 @@
|
||||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.image'), 'image') ?>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input',
|
||||
'required' => 'required',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
<small class="mb-4 text-gray-600"><?= lang(
|
||||
'Common.forms.image_size_hint'
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(lang('Podcast.form.title'), 'title') ?>
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
@ -54,7 +67,6 @@
|
||||
[
|
||||
'id' => 'episode_description_footer',
|
||||
'name' => 'episode_description_footer',
|
||||
|
||||
'class' => 'form-textarea',
|
||||
],
|
||||
old('episode_description_footer', '', false),
|
||||
@ -62,16 +74,6 @@
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<?= form_label(lang('Podcast.form.image'), 'image') ?>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input mb-4',
|
||||
'required' => 'required',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.language'), 'language') ?>
|
||||
<?= form_dropdown('language', $languageOptions, old('language', $browserLang), [
|
||||
'id' => 'language',
|
||||
@ -122,7 +124,9 @@
|
||||
'value' => old('author'),
|
||||
]) ?>
|
||||
|
||||
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
|
||||
<?= form_fieldset('', [
|
||||
'class' => 'flex flex-col mb-4',
|
||||
]) ?>
|
||||
<legend><?= lang('Podcast.form.type.label') ?></legend>
|
||||
<label for="episodic" class="inline-flex items-center">
|
||||
<?= form_radio(
|
||||
|
@ -13,6 +13,22 @@
|
||||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.image'), 'image') ?>
|
||||
<img
|
||||
src="<?= $podcast->image->thumbnail_url ?>"
|
||||
alt="<?= $podcast->title ?>"
|
||||
class="object-cover w-32 h-32"
|
||||
/>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
<small class="mb-4 text-gray-600"><?= lang(
|
||||
'Common.forms.image_size_hint'
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(lang('Podcast.form.title'), 'title') ?>
|
||||
<?= form_input([
|
||||
@ -66,16 +82,6 @@
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<?= form_label(lang('Podcast.form.image'), 'image') ?>
|
||||
<img src="<?= $podcast->image_url ?>" alt="<?= $podcast->title ?>" class="object-cover w-32 h-32" />
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input mb-4',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.language'), 'language') ?>
|
||||
<?= form_dropdown(
|
||||
'language',
|
||||
|
@ -7,28 +7,33 @@
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= form_open_multipart(route_to('podcast_import'), [
|
||||
<?= form_open_multipart(route_to('rzqr'), [
|
||||
'method' => 'post',
|
||||
'class' => 'flex flex-col max-w-md',
|
||||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form_import.name'), 'name') ?>
|
||||
<?= form_input([
|
||||
'id' => 'name',
|
||||
'name' => 'name',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('name'),
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<div class="flex flex-col mb-4">
|
||||
<label for="name"><?= lang('Podcast.form_import.name') ?></label>
|
||||
<input type="text" class="form-input" id="name" name="name" value="<?= old(
|
||||
'name'
|
||||
) ?>" required />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col mb-4">
|
||||
<label for="name"><?= lang(
|
||||
'Podcast.form_import.imported_feed_url'
|
||||
) ?></label>
|
||||
<input type="text" class="form-input" id="imported_feed_url" name="imported_feed_url" value="<?= old(
|
||||
'imported_feed_url'
|
||||
) ?>" required />
|
||||
</div>
|
||||
<?= form_label(
|
||||
lang('Podcast.form_import.imported_feed_url'),
|
||||
'imported_feed_url'
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'imported_feed_url',
|
||||
'name' => 'imported_feed_url',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('imported_feed_url'),
|
||||
'type' => 'url',
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.language'), 'language') ?>
|
||||
<?= form_dropdown('language', $languageOptions, old('language', $browserLang), [
|
||||
@ -44,9 +49,8 @@
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_fieldset(lang('Podcast.form_import.slug_field.label'), [
|
||||
'class' => 'flex flex-col mb-4',
|
||||
]) ?>
|
||||
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
|
||||
<legend><?= lang('Podcast.form_import.slug_field.label') ?></legend>
|
||||
<label for="link" class="inline-flex items-center">
|
||||
<?= form_radio(
|
||||
['id' => 'link', 'name' => 'slug_field', 'class' => 'form-radio'],
|
||||
@ -69,9 +73,8 @@
|
||||
</label>
|
||||
<?= form_fieldset_close() ?>
|
||||
|
||||
<?= form_fieldset(lang('Podcast.form_import.description_field.label'), [
|
||||
'class' => 'flex flex-col mb-4',
|
||||
]) ?>
|
||||
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
|
||||
<legend><?= lang('Podcast.form_import.description_field.label') ?></legend>
|
||||
<label for="description" class="inline-flex items-center">
|
||||
<?= form_radio(
|
||||
[
|
||||
@ -88,7 +91,7 @@
|
||||
'Podcast.form_import.description_field.description'
|
||||
) ?></span>
|
||||
</label>
|
||||
<label for="subtitle_summary" class="inline-flex items-center">
|
||||
<label for="summary" class="inline-flex items-center">
|
||||
<?= form_radio(
|
||||
[
|
||||
'id' => 'summary',
|
||||
@ -136,27 +139,30 @@
|
||||
<span class="ml-2"><?= lang('Podcast.form_import.force_renumber') ?></span>
|
||||
</label>
|
||||
|
||||
<div class="flex flex-col mb-4">
|
||||
<label for="name"><?= lang('Podcast.form_import.season_number') ?></label>
|
||||
<input type="text" class="form-input" id="season_number" name="season_number" value="<?= old(
|
||||
'season_number'
|
||||
) ?>" />
|
||||
</div>
|
||||
<?= form_label(lang('Podcast.form_import.season_number'), 'season_number') ?>
|
||||
<?= form_input([
|
||||
'id' => 'season_number',
|
||||
'name' => 'season_number',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('season_number'),
|
||||
'type' => 'number',
|
||||
]) ?>
|
||||
|
||||
<div class="flex flex-col mb-4">
|
||||
<label for="max_episodes"><?= lang(
|
||||
'Podcast.form_import.max_episodes'
|
||||
) ?></label>
|
||||
<input type="text" class="form-input" id="max_episodes" name="max_episodes" value="<?= old(
|
||||
'max_episodes'
|
||||
) ?>" />
|
||||
</div>
|
||||
<?= form_label(lang('Podcast.form_import.max_episodes'), 'max_episodes') ?>
|
||||
<?= form_input([
|
||||
'id' => 'max_episodes',
|
||||
'name' => 'max_episodes',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('max_episodes'),
|
||||
'type' => 'number',
|
||||
]) ?>
|
||||
|
||||
<?= form_button([
|
||||
'content' => lang('Podcast.form_import.submit_import'),
|
||||
'type' => 'submit',
|
||||
'class' => 'self-end px-4 py-2 bg-gray-200',
|
||||
]) ?>
|
||||
|
||||
<button type="submit" name="submit" onsubmit="this.disabled=true; this.value='<?= lang(
|
||||
'Podcast.form_import.submit_importing'
|
||||
) ?>';" class="self-end px-4 py-2 bg-gray-200"><?= lang(
|
||||
'Podcast.form_import.submit_import'
|
||||
) ?></button>
|
||||
<?= form_close() ?>
|
||||
|
||||
|
||||
|
@ -18,7 +18,11 @@
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<img class="w-64 mb-4" src="<?= $podcast->image_url ?>" alt="<?= $podcast->title ?>" />
|
||||
<img
|
||||
class="w-64 mb-4"
|
||||
src="<?= $podcast->image->medium_url ?>"
|
||||
alt="<?= $podcast->title ?>"
|
||||
/>
|
||||
<a class="inline-flex px-2 py-1 mb-2 text-white bg-yellow-700 hover:bg-yellow-800" href="<?= route_to(
|
||||
'contributor-list',
|
||||
$podcast->id
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?= helper('page') ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="<?= $episode->podcast->language ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
@ -14,14 +14,15 @@
|
||||
<body class="flex flex-col min-h-screen mx-auto">
|
||||
<header class="border-b bg-gradient-to-tr from-gray-900 to-gray-800">
|
||||
<div class="container flex items-start px-2 py-2 mx-auto">
|
||||
<img class="w-12 h-12 mr-2 rounded cover" src="<?= $episode->podcast
|
||||
->image_url ?>" alt="<?= $episode->podcast->title ?>" />
|
||||
<a href="<?= route_to(
|
||||
'podcast',
|
||||
$episode->podcast->name
|
||||
) ?>" class="flex flex-col text-lg leading-tight text-white" title="<?= lang(
|
||||
'Episode.back_to_podcast'
|
||||
) ?>">
|
||||
<img
|
||||
class="w-12 h-12 mr-2 rounded cover"
|
||||
src="<?= $episode->podcast->image->thumbnail_url ?>"
|
||||
alt="<?= $episode->podcast->title ?>"
|
||||
/>
|
||||
<a
|
||||
href="<?= route_to('podcast', $episode->podcast->name) ?>"
|
||||
class="flex flex-col text-lg leading-tight text-white"
|
||||
title="<?= lang('Episode.back_to_podcast') ?>">
|
||||
<?= $episode->podcast->title ?>
|
||||
<span class="text-sm text-gray-300">
|
||||
@<?= $episode->podcast->name ?>
|
||||
@ -57,7 +58,8 @@
|
||||
<?php endif; ?>
|
||||
</nav>
|
||||
<header class="flex flex-col items-center px-4 md:items-stretch md:justify-center md:flex-row">
|
||||
<img src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-full max-w-xs mb-2 rounded-lg md:mb-0 md:mr-4" />
|
||||
<img src="<?= $episode->image->medium_url ?>"
|
||||
alt="<?= $episode->title ?>" class="object-cover w-full max-w-xs mb-2 rounded-lg md:mb-0 md:mr-4" />
|
||||
<div class="flex flex-col w-full max-w-sm">
|
||||
<h1 class="text-lg font-semibold md:text-2xl"><?= $episode->title ?></h1>
|
||||
<?php if ($episode->number): ?>
|
||||
|
@ -12,7 +12,9 @@
|
||||
<?php foreach ($podcasts as $podcast): ?>
|
||||
<a href="<?= route_to('podcast', $podcast->name) ?>">
|
||||
<article class="w-48 h-full p-2 mb-4 mr-4 border shadow-sm hover:bg-gray-100 hover:shadow">
|
||||
<img alt="<?= $podcast->title ?>" src="<?= $podcast->image_url ?>" class="object-cover w-full h-40 mb-2" />
|
||||
<img alt="<?= $podcast->title ?>"
|
||||
src="<?= $podcast->image->thumbnail_url ?>"
|
||||
class="object-cover w-full h-40 mb-2" />
|
||||
<h2 class="font-semibold leading-tight"><?= $podcast->title ?></h2>
|
||||
<p class="text-gray-600">@<?= $podcast->name ?></p>
|
||||
</article>
|
||||
|
@ -17,7 +17,8 @@
|
||||
<main class="flex-1 bg-gray-200">
|
||||
<header class="border-b bg-gradient-to-tr from-gray-900 to-gray-800">
|
||||
<div class="flex flex-col items-center justify-center md:items-stretch md:mx-auto md:container md:py-12 md:flex-row ">
|
||||
<img src="<?= $podcast->image_url ?>" alt="Podcast cover" class="object-cover w-full max-w-xs m-4 rounded-lg shadow-xl" />
|
||||
<img src="<?= $podcast->image->medium_url ?>"
|
||||
alt="<?= $podcast->title ?>" class="object-cover w-full max-w-xs m-4 rounded-lg shadow-xl" />
|
||||
<div class="w-full p-4 bg-white md:w-auto md:text-white md:bg-transparent">
|
||||
<h1 class="text-2xl font-semibold leading-tight"><?= $podcast->title ?> <span class="text-lg font-normal opacity-75">@<?= $podcast->name ?></span></h1>
|
||||
<div class="flex items-center mb-4">
|
||||
@ -99,7 +100,10 @@
|
||||
</h1>
|
||||
<?php foreach ($episodes as $episode): ?>
|
||||
<article class="flex w-full max-w-lg p-4 mx-auto">
|
||||
<img loading="lazy" src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-20 h-20 mr-2 rounded-lg" />
|
||||
<img
|
||||
loading="lazy"
|
||||
src="<?= $episode->image->thumbnail_url ?>"
|
||||
alt="<?= $episode->title ?>" class="object-cover w-20 h-20 mr-2 rounded-lg" />
|
||||
<div class="flex flex-col flex-1">
|
||||
<a class="text-sm hover:underline" href="<?= $episode->link ?>">
|
||||
<h2 class="inline-flex justify-between w-full font-bold leading-none group">
|
||||
|
56
composer.lock
generated
56
composer.lock
generated
@ -12,12 +12,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeigniter4/CodeIgniter4.git",
|
||||
"reference": "9a7e826138bf8940ef8c7a25d59d67b1aebfe0ee"
|
||||
"reference": "9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/9a7e826138bf8940ef8c7a25d59d67b1aebfe0ee",
|
||||
"reference": "9a7e826138bf8940ef8c7a25d59d67b1aebfe0ee",
|
||||
"url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4",
|
||||
"reference": "9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -34,7 +34,7 @@
|
||||
"codeigniter4/codeigniter4-standard": "^1.0",
|
||||
"fzaninotto/faker": "^1.9@dev",
|
||||
"mikey179/vfsstream": "1.6.*",
|
||||
"phpstan/phpstan": "^0.12.37",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/phpunit": "^8.5",
|
||||
"predis/predis": "^1.1",
|
||||
"squizlabs/php_codesniffer": "^3.3"
|
||||
@ -66,20 +66,20 @@
|
||||
"slack": "https://codeigniterchat.slack.com",
|
||||
"issues": "https://github.com/codeigniter4/CodeIgniter4/issues"
|
||||
},
|
||||
"time": "2020-08-17T14:11:23+00:00"
|
||||
"time": "2020-09-07T16:29:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/ca-bundle.git",
|
||||
"reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd"
|
||||
"reference": "8a7ecad675253e4654ea05505233285377405215"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd",
|
||||
"reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215",
|
||||
"reference": "8a7ecad675253e4654ea05505233285377405215",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -127,12 +127,16 @@
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/composer",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-08T08:27:21+00:00"
|
||||
"time": "2020-08-23T12:54:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "geoip2/geoip2",
|
||||
@ -451,23 +455,23 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-zendframework-bridge",
|
||||
"version": "1.0.4",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
|
||||
"reference": "fcd87520e4943d968557803919523772475e8ea3"
|
||||
"reference": "4939c81f63a8a4968c108c440275c94955753b19"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/fcd87520e4943d968557803919523772475e8ea3",
|
||||
"reference": "fcd87520e4943d968557803919523772475e8ea3",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/4939c81f63a8a4968c108c440275c94955753b19",
|
||||
"reference": "4939c81f63a8a4968c108c440275c94955753b19",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0"
|
||||
"php": "^5.6 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1",
|
||||
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
@ -505,20 +509,20 @@
|
||||
"type": "community_bridge"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-20T16:45:56+00:00"
|
||||
"time": "2020-08-18T16:34:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "1.5.3",
|
||||
"version": "1.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/commonmark.git",
|
||||
"reference": "2574454b97e4103dc4e36917bd783b25624aefcd"
|
||||
"reference": "21819c989e69bab07e933866ad30c7e3f32984ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2574454b97e4103dc4e36917bd783b25624aefcd",
|
||||
"reference": "2574454b97e4103dc4e36917bd783b25624aefcd",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/21819c989e69bab07e933866ad30c7e3f32984ba",
|
||||
"reference": "21819c989e69bab07e933866ad30c7e3f32984ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -600,7 +604,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-19T22:47:30+00:00"
|
||||
"time": "2020-08-18T01:19:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/html-to-markdown",
|
||||
@ -796,12 +800,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lonnieezell/myth-auth.git",
|
||||
"reference": "d9c9b0e4a8bea9ba6c847dcfefc6645bf1e1d694"
|
||||
"reference": "e838cb8de6ffa118caf2b9909e71776a866c8973"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/d9c9b0e4a8bea9ba6c847dcfefc6645bf1e1d694",
|
||||
"reference": "d9c9b0e4a8bea9ba6c847dcfefc6645bf1e1d694",
|
||||
"url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/e838cb8de6ffa118caf2b9909e71776a866c8973",
|
||||
"reference": "e838cb8de6ffa118caf2b9909e71776a866c8973",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -848,7 +852,7 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-16T14:00:14+00:00"
|
||||
"time": "2020-09-07T03:37:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
|
745
package-lock.json
generated
745
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@ -29,12 +29,12 @@
|
||||
"prosemirror-example-setup": "^1.1.2",
|
||||
"prosemirror-markdown": "^1.5.0",
|
||||
"prosemirror-state": "^1.3.3",
|
||||
"prosemirror-view": "^1.15.5"
|
||||
"prosemirror-view": "^1.15.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.4",
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@babel/preset-typescript": "^7.10.4",
|
||||
"@commitlint/cli": "^9.1.2",
|
||||
"@commitlint/config-conventional": "^9.1.2",
|
||||
@ -49,30 +49,30 @@
|
||||
"@types/codemirror": "0.0.97",
|
||||
"@types/prosemirror-markdown": "^1.0.3",
|
||||
"@types/prosemirror-view": "^1.15.1",
|
||||
"@typescript-eslint/eslint-plugin": "^3.10.1",
|
||||
"@typescript-eslint/parser": "^3.10.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
||||
"@typescript-eslint/parser": "^4.0.1",
|
||||
"cross-env": "^7.0.2",
|
||||
"cssnano": "^4.1.10",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^7.7.0",
|
||||
"eslint": "^7.8.1",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.13",
|
||||
"postcss-cli": "^7.1.1",
|
||||
"lint-staged": "^10.3.0",
|
||||
"postcss-cli": "^7.1.2",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"prettier": "2.1.1",
|
||||
"prettier-plugin-organize-imports": "^1.1.1",
|
||||
"rollup": "^2.26.6",
|
||||
"rollup": "^2.26.10",
|
||||
"rollup-plugin-multi-input": "^1.1.1",
|
||||
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||
"rollup-plugin-postcss": "^3.1.6",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"stylelint": "^13.6.1",
|
||||
"rollup-plugin-postcss": "^3.1.8",
|
||||
"rollup-plugin-terser": "^7.0.1",
|
||||
"stylelint": "^13.7.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"svgo": "^1.3.2",
|
||||
"tailwindcss": "^1.7.5",
|
||||
"tailwindcss": "^1.7.6",
|
||||
"typescript": "^4.0.2"
|
||||
},
|
||||
"husky": {
|
||||
|
@ -18,7 +18,8 @@ Options All -Indexes
|
||||
|
||||
# Redirect Trailing Slashes...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)/$ /$1 [L,R=301]
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Rewrite "www.example.com -> example.com"
|
||||
RewriteCond %{HTTPS} !=on
|
||||
@ -30,7 +31,7 @@ Options All -Indexes
|
||||
# request to the front controller, index.php
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php/$1 [L]
|
||||
RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
|
||||
|
||||
# Ensure Authorization header is passed along
|
||||
RewriteCond %{HTTP:Authorization} .
|
||||
@ -45,4 +46,4 @@ Options All -Indexes
|
||||
|
||||
# Disable server signature start
|
||||
ServerSignature Off
|
||||
# Disable server signature end
|
||||
# Disable server signature end
|
Loading…
x
Reference in New Issue
Block a user