Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • adaures/castopod
  • mkljczk/castopod-host
  • spaetz/castopod-host
  • PatrykMis/castopod
  • jonas/castopod
  • ajeremias/castopod
  • misuzu/castopod
  • KrzysztofDomanczyk/castopod
  • Behel/castopod
  • nebulon/castopod
  • ewen/castopod
  • NeoluxConsulting/castopod
  • nateritter/castopod-og
  • prcutler/castopod
14 results
Show changes
Showing
with 1415 additions and 239 deletions
......@@ -3,7 +3,7 @@
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
......@@ -13,19 +13,29 @@ namespace App\Controllers;
use App\Models\EpisodeModel;
use CodeIgniter\HTTP\ResponseInterface;
class MapMarkerController extends BaseController
class MapController extends BaseController
{
public function index(): string
{
$locale = service('request')
->getLocale();
$cacheName = "page_map_{$locale}";
$cacheName = implode(
'_',
array_filter([
'page',
'map',
service('request')
->getLocale(),
auth()
->loggedIn() ? 'authenticated' : null,
]),
);
if (! ($found = cache($cacheName))) {
$found = view('map', [], [
'cache' => DECADE,
return view('pages/map', [], [
'cache' => DECADE,
'cache_name' => $cacheName,
]);
}
return $found;
}
......@@ -34,27 +44,29 @@ class MapMarkerController extends BaseController
$cacheName = 'episodes_markers';
if (! ($found = cache($cacheName))) {
$episodes = (new EpisodeModel())
->where('`published_at` <= NOW()', null, false)
->where('`published_at` <= UTC_TIMESTAMP()', null, false)
->where('location_geo is not', null)
->findAll();
$found = [];
foreach ($episodes as $episode) {
$found[] = [
'latitude' => $episode->location->latitude,
'longitude' => $episode->location->longitude,
'location_name' => $episode->location->name,
'location_url' => $episode->location->url,
'episode_link' => $episode->link,
'podcast_link' => $episode->podcast->link,
'image_path' => $episode->image->thumbnail_url,
'podcast_title' => $episode->podcast->title,
'episode_title' => $episode->title,
'latitude' => $episode->location->latitude,
'longitude' => $episode->location->longitude,
'location_name' => esc($episode->location->name),
'location_url' => $episode->location->url,
'episode_link' => $episode->link,
'podcast_link' => $episode->podcast->link,
'cover_url' => $episode->cover->thumbnail_url,
'podcast_title' => esc($episode->podcast->title),
'episode_title' => esc($episode->title),
];
}
// The page cache is set to a decade so it is deleted manually upon episode update
cache()
->save($cacheName, $found, DECADE);
}
return $this->response->setJSON($found);
}
}
......@@ -3,7 +3,7 @@
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
......@@ -24,9 +24,8 @@ class PageController extends BaseController
throw PageNotFoundException::forPageNotFound();
}
if (
($page = (new PageModel())->where('slug', $params[0])->first()) === null
) {
$page = (new PageModel())->where('slug', $params[0])->first();
if (! $page instanceof Page) {
throw PageNotFoundException::forPageNotFound();
}
......@@ -37,13 +36,25 @@ class PageController extends BaseController
public function index(): string
{
$cacheName = "page-{$this->page->slug}";
$cacheName = implode(
'_',
array_filter([
'page',
$this->page->slug,
service('request')
->getLocale(),
auth()
->loggedIn() ? 'authenticated' : null,
]),
);
if (! ($found = cache($cacheName))) {
set_page_metatags($this->page);
$data = [
'page' => $this->page,
];
$found = view('page', $data);
$found = view('pages/page', $data);
// The page cache is set to a decade so it is deleted manually upon page update
cache()
......
<?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 App\Models\PlatformModel;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\ResponseInterface;
/*
* Provide public access to all platforms so that they can be exported
*/
class PlatformController extends Controller
{
public function index(): ResponseInterface
{
$model = new PlatformModel();
return $this->response->setJSON($model->getPlatforms());
}
}
......@@ -3,16 +3,13 @@
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Controllers;
use ActivityPub\Objects\OrderedCollectionObject;
use ActivityPub\Objects\OrderedCollectionPage;
use Analytics\AnalyticsTrait;
use App\Entities\Podcast;
use App\Libraries\PodcastActor;
use App\Libraries\PodcastEpisode;
......@@ -20,7 +17,10 @@ use App\Models\EpisodeModel;
use App\Models\PodcastModel;
use App\Models\PostModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\Response;
use CodeIgniter\HTTP\ResponseInterface;
use Modules\Analytics\AnalyticsTrait;
use Modules\Fediverse\Objects\OrderedCollectionObject;
use Modules\Fediverse\Objects\OrderedCollectionPage;
class PodcastController extends BaseController
{
......@@ -35,7 +35,7 @@ class PodcastController extends BaseController
}
if (
($podcast = (new PodcastModel())->getPodcastByHandle($params[0])) === null
! ($podcast = (new PodcastModel())->getPodcastByHandle($params[0])) instanceof Podcast
) {
throw PageNotFoundException::forPageNotFound();
}
......@@ -47,10 +47,7 @@ class PodcastController extends BaseController
return $this->{$method}(...$params);
}
/**
* @noRector ReturnTypeDeclarationRector
*/
public function podcastActor(): Response
public function podcastActor(): ResponseInterface
{
$podcastActor = new PodcastActor($this->podcast);
......@@ -61,10 +58,7 @@ class PodcastController extends BaseController
public function activity(): string
{
// Prevent analytics hit when authenticated
if (! can_user_interact()) {
$this->registerPodcastWebpageHit($this->podcast->id);
}
$this->registerPodcastWebpageHit($this->podcast->id);
$cacheName = implode(
'_',
......@@ -74,20 +68,24 @@ class PodcastController extends BaseController
'activity',
service('request')
->getLocale(),
can_user_interact() ? '_authenticated' : null,
is_unlocked($this->podcast->handle) ? 'unlocked' : null,
auth()
->loggedIn() ? 'authenticated' : null,
]),
);
if (! ($cachedView = cache($cacheName))) {
set_podcast_metatags($this->podcast, 'activity');
$data = [
'podcast' => $this->podcast,
'posts' => (new PostModel())->getActorPublishedPosts($this->podcast->actor_id),
'posts' => (new PostModel())->getActorPublishedPosts($this->podcast->actor_id),
];
// if user is logged in then send to the authenticated activity view
if (can_user_interact()) {
if (auth()->loggedIn()) {
helper('form');
return view('podcast/activity_authenticated', $data);
return view('podcast/activity', $data);
}
$secondsToNextUnpublishedEpisode = (new EpisodeModel())->getSecondsToNextUnpublishedEpisode(
......@@ -95,9 +93,7 @@ class PodcastController extends BaseController
);
return view('podcast/activity', $data, [
'cache' => $secondsToNextUnpublishedEpisode
? $secondsToNextUnpublishedEpisode
: DECADE,
'cache' => $secondsToNextUnpublishedEpisode ?: DECADE,
'cache_name' => $cacheName,
]);
}
......@@ -105,13 +101,57 @@ class PodcastController extends BaseController
return $cachedView;
}
public function episodes(): string
public function about(): string
{
// Prevent analytics hit when authenticated
if (! can_user_interact()) {
$this->registerPodcastWebpageHit($this->podcast->id);
$this->registerPodcastWebpageHit($this->podcast->id);
$cacheName = implode(
'_',
array_filter([
'page',
"podcast#{$this->podcast->id}",
'about',
service('request')
->getLocale(),
is_unlocked($this->podcast->handle) ? 'unlocked' : null,
auth()
->loggedIn() ? 'authenticated' : null,
]),
);
if (! ($cachedView = cache($cacheName))) {
$stats = (new EpisodeModel())->getPodcastStats($this->podcast->id);
set_podcast_metatags($this->podcast, 'about');
$data = [
'podcast' => $this->podcast,
'stats' => $stats,
];
// // if user is logged in then send to the authenticated activity view
if (auth()->loggedIn()) {
helper('form');
return view('podcast/about', $data);
}
$secondsToNextUnpublishedEpisode = (new EpisodeModel())->getSecondsToNextUnpublishedEpisode(
$this->podcast->id,
);
return view('podcast/about', $data, [
'cache' => $secondsToNextUnpublishedEpisode ?: DECADE,
'cache_name' => $cacheName,
]);
}
return $cachedView;
}
public function episodes(): string
{
$this->registerPodcastWebpageHit($this->podcast->id);
$yearQuery = $this->request->getGet('year');
$seasonQuery = $this->request->getGet('season');
......@@ -136,7 +176,9 @@ class PodcastController extends BaseController
$seasonQuery ? 'season' . $seasonQuery : null,
service('request')
->getLocale(),
can_user_interact() ? '_authenticated' : null,
is_unlocked($this->podcast->handle) ? 'unlocked' : null,
auth()
->loggedIn() ? 'authenticated' : null,
]),
);
......@@ -152,18 +194,17 @@ class PodcastController extends BaseController
$isActive = $yearQuery === $year['year'];
if ($isActive) {
$activeQuery = [
'type' => 'year',
'value' => $year['year'],
'label' => $year['year'],
'type' => 'year',
'value' => $year['year'],
'label' => $year['year'],
'number_of_episodes' => $year['number_of_episodes'],
];
}
$episodesNavigation[] = [
'label' => $year['year'],
'label' => $year['year'],
'number_of_episodes' => $year['number_of_episodes'],
'route' =>
route_to('podcast-episodes', $this->podcast->handle) .
'route' => route_to('podcast-episodes', $this->podcast->handle) .
'?year=' .
$year['year'],
'is_active' => $isActive,
......@@ -174,7 +215,7 @@ class PodcastController extends BaseController
$isActive = $seasonQuery === $season['season_number'];
if ($isActive) {
$activeQuery = [
'type' => 'season',
'type' => 'season',
'value' => $season['season_number'],
'label' => lang('Podcast.season', [
'seasonNumber' => $season['season_number'],
......@@ -188,19 +229,19 @@ class PodcastController extends BaseController
'seasonNumber' => $season['season_number'],
]),
'number_of_episodes' => $season['number_of_episodes'],
'route' =>
route_to('podcast-episodes', $this->podcast->handle) .
'route' => route_to('podcast-episodes', $this->podcast->handle) .
'?season=' .
$season['season_number'],
'is_active' => $isActive,
];
}
set_podcast_metatags($this->podcast, 'episodes');
$data = [
'podcast' => $this->podcast,
'podcast' => $this->podcast,
'episodesNav' => $episodesNavigation,
'activeQuery' => $activeQuery,
'episodes' => (new EpisodeModel())->getPodcastEpisodes(
'episodes' => (new EpisodeModel())->getPodcastEpisodes(
$this->podcast->id,
$this->podcast->type,
$yearQuery,
......@@ -208,18 +249,15 @@ class PodcastController extends BaseController
),
];
if (auth()->loggedIn()) {
return view('podcast/episodes', $data);
}
$secondsToNextUnpublishedEpisode = (new EpisodeModel())->getSecondsToNextUnpublishedEpisode(
$this->podcast->id,
);
// if user is logged in then send to the authenticated episodes view
if (can_user_interact()) {
return view('podcast/episodes_authenticated', $data);
}
return view('podcast/episodes', $data, [
'cache' => $secondsToNextUnpublishedEpisode
? $secondsToNextUnpublishedEpisode
: DECADE,
'cache' => $secondsToNextUnpublishedEpisode ?: DECADE,
'cache_name' => $cacheName,
]);
}
......@@ -227,19 +265,16 @@ class PodcastController extends BaseController
return $cachedView;
}
/**
* @noRector ReturnTypeDeclarationRector
*/
public function episodeCollection(): Response
public function episodeCollection(): ResponseInterface
{
if ($this->podcast->type === 'serial') {
// podcast is serial
$episodes = model('EpisodeModel')
->where('`published_at` <= NOW()', null, false)
->where('`published_at` <= UTC_TIMESTAMP()', null, false)
->orderBy('season_number DESC, number ASC');
} else {
$episodes = model('EpisodeModel')
->where('`published_at` <= NOW()', null, false)
->where('`published_at` <= UTC_TIMESTAMP()', null, false)
->orderBy('published_at', 'DESC');
}
......@@ -268,4 +303,12 @@ class PodcastController extends BaseController
->setContentType('application/activity+json')
->setBody($collection->toJSON());
}
public function links(): string
{
set_podcast_metatags($this->podcast, 'links');
return view('podcast/links', [
'podcast' => $this->podcast,
]);
}
}
......@@ -3,16 +3,13 @@
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Controllers;
use ActivityPub\Controllers\PostController as ActivityPubPostController;
use ActivityPub\Entities\Post as ActivityPubPost;
use Analytics\AnalyticsTrait;
use App\Entities\Actor;
use App\Entities\Podcast;
use App\Entities\Post as CastopodPost;
......@@ -23,8 +20,11 @@ use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\URI;
use CodeIgniter\I18n\Time;
use Modules\Analytics\AnalyticsTrait;
use Modules\Fediverse\Controllers\PostController as FediversePostController;
use Override;
class PostController extends ActivityPubPostController
class PostController extends FediversePostController
{
use AnalyticsTrait;
......@@ -33,14 +33,21 @@ class PostController extends ActivityPubPostController
protected Actor $actor;
/**
* @var string[]
* @var CastopodPost
*/
protected $helpers = ['auth', 'activitypub', 'svg', 'components', 'misc'];
protected $post;
/**
* @var list<string>
*/
protected $helpers = ['auth', 'fediverse', 'svg', 'components', 'misc', 'seo', 'premium_podcasts'];
#[Override]
public function _remap(string $method, string ...$params): mixed
{
if (
($podcast = (new PodcastModel())->getPodcastByHandle($params[0],)) === null
! ($podcast = (new PodcastModel())->getPodcastByHandle($params[0])) instanceof Podcast
) {
throw PageNotFoundException::forPageNotFound();
}
......@@ -48,25 +55,29 @@ class PostController extends ActivityPubPostController
$this->podcast = $podcast;
$this->actor = $this->podcast->actor;
if (count($params) <= 1) {
unset($params[0]);
return $this->{$method}(...$params);
}
if (
count($params) > 1 &&
($post = (new PostModel())->getPostById($params[1])) !== null
! ($post = (new PostModel())->getPostById($params[1])) instanceof CastopodPost
) {
$this->post = $post;
unset($params[0]);
unset($params[1]);
throw PageNotFoundException::forPageNotFound();
}
$this->post = $post;
unset($params[0]);
unset($params[1]);
return $this->{$method}(...$params);
}
public function view(): string
{
// Prevent analytics hit when authenticated
if (! can_user_interact()) {
$this->registerPodcastWebpageHit($this->podcast->id);
}
$this->registerPodcastWebpageHit($this->podcast->id);
$cacheName = implode(
'_',
......@@ -75,24 +86,26 @@ class PostController extends ActivityPubPostController
"post#{$this->post->id}",
service('request')
->getLocale(),
can_user_interact() ? '_authenticated' : null,
auth()
->loggedIn() ? 'authenticated' : null,
]),
);
if (! ($cachedView = cache($cacheName))) {
set_post_metatags($this->post);
$data = [
'post' => $this->post,
'podcast' => $this->podcast,
'actor' => $this->actor,
'post' => $this->post,
];
// if user is logged in then send to the authenticated activity view
if (can_user_interact()) {
if (auth()->loggedIn()) {
helper('form');
return view('podcast/post_authenticated', $data);
return view('post/post', $data);
}
return view('podcast/post', $data, [
'cache' => DECADE,
return view('post/post', $data, [
'cache' => DECADE,
'cache_name' => $cacheName,
]);
}
......@@ -100,11 +113,12 @@ class PostController extends ActivityPubPostController
return $cachedView;
}
public function attemptCreate(): RedirectResponse
#[Override]
public function createAction(): RedirectResponse
{
$rules = [
'message' => 'required|max_length[500]',
'episode_url' => 'valid_url|permit_empty',
'message' => 'required|max_length[500]',
'episode_url' => 'valid_url_strict|permit_empty',
];
if (! $this->validate($rules)) {
......@@ -114,16 +128,18 @@ class PostController extends ActivityPubPostController
->with('errors', $this->validator->getErrors());
}
$message = $this->request->getPost('message');
$validData = $this->validator->getValidated();
$message = $validData['message'];
$newPost = new CastopodPost([
'actor_id' => interact_as_actor_id(),
'actor_id' => interact_as_actor_id(),
'published_at' => Time::now(),
'created_by' => user_id(),
'created_by' => user_id(),
]);
// get episode if episodeUrl has been set
$episodeUri = $this->request->getPost('episode_url');
$episodeUri = $validData['episode_url'];
if (
$episodeUri &&
($params = extract_params_from_episode_uri(new URI($episodeUri))) &&
......@@ -149,7 +165,8 @@ class PostController extends ActivityPubPostController
return redirect()->back();
}
public function attemptReply(): RedirectResponse
#[Override]
public function replyAction(): RedirectResponse
{
$rules = [
'message' => 'required|max_length[500]',
......@@ -162,14 +179,20 @@ class PostController extends ActivityPubPostController
->with('errors', $this->validator->getErrors());
}
$newPost = new ActivityPubPost([
'actor_id' => interact_as_actor_id(),
$validData = $this->validator->getValidated();
$newPost = new CastopodPost([
'actor_id' => interact_as_actor_id(),
'in_reply_to_id' => $this->post->id,
'message' => $this->request->getPost('message'),
'published_at' => Time::now(),
'created_by' => user_id(),
'message' => $validData['message'],
'published_at' => Time::now(),
'created_by' => user_id(),
]);
if ($this->post->episode_id !== null) {
$newPost->episode_id = $this->post->episode_id;
}
$postModel = new PostModel();
if (! $postModel->addReply($newPost)) {
return redirect()
......@@ -182,21 +205,23 @@ class PostController extends ActivityPubPostController
return redirect()->back();
}
public function attemptFavourite(): RedirectResponse
#[Override]
public function favouriteAction(): RedirectResponse
{
model('FavouriteModel')->toggleFavourite(interact_as_actor(), $this->post);
return redirect()->back();
}
public function attemptReblog(): RedirectResponse
#[Override]
public function reblogAction(): RedirectResponse
{
(new PostModel())->toggleReblog(interact_as_actor(), $this->post);
return redirect()->back();
}
public function attemptAction(): RedirectResponse
public function action(): RedirectResponse
{
$rules = [
'action' => 'required|in_list[favourite,reblog,reply]',
......@@ -209,46 +234,35 @@ class PostController extends ActivityPubPostController
->with('errors', $this->validator->getErrors());
}
$action = $this->request->getPost('action');
$validData = $this->validator->getValidated();
$action = $validData['action'];
return match ($action) {
'favourite' => $this->attemptFavourite(),
'reblog' => $this->attemptReblog(),
'reply' => $this->attemptReply(),
default => redirect()
'favourite' => $this->favouriteAction(),
'reblog' => $this->reblogAction(),
'reply' => $this->replyAction(),
default => redirect()
->back()
->withInput()
->with('errors', 'error'),
};
}
public function remoteAction(string $action): string
public function remoteActionView(string $action): string
{
// Prevent analytics hit when authenticated
if (! can_user_interact()) {
$this->registerPodcastWebpageHit($this->podcast->id);
}
$cacheName = implode(
'_',
array_filter(['page', "post#{$this->post->id}", "remote_{$action}", service('request') ->getLocale()]),
);
if (! ($cachedView = cache($cacheName))) {
$data = [
'podcast' => $this->podcast,
'actor' => $this->actor,
'post' => $this->post,
'action' => $action,
];
helper('form');
$this->registerPodcastWebpageHit($this->podcast->id);
set_remote_actions_metatags($this->post, $action);
$data = [
'podcast' => $this->podcast,
'actor' => $this->actor,
'post' => $this->post,
'action' => $action,
];
return view('podcast/post_remote_action', $data, [
'cache' => DECADE,
'cache_name' => $cacheName,
]);
}
helper('form');
return (string) $cachedView;
// NO VIEW CACHING: form has a CSRF token which should change on each request
return view('post/remote_action', $data);
}
}
<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Controllers;
use App\Entities\Podcast;
use App\Models\PodcastModel;
use CodeIgniter\Controller;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\ResponseInterface;
class WebmanifestController extends Controller
{
/**
* @var array<string, array<string, string>>
*/
final public const array THEME_COLORS = [
'pine' => [
'theme' => '#009486',
'background' => '#F0F9F8',
],
'lake' => [
'theme' => '#00ACE0',
'background' => '#F0F7F9',
],
'jacaranda' => [
'theme' => '#562CDD',
'background' => '#F2F0F9',
],
'crimson' => [
'theme' => '#F24562',
'background' => '#F9F0F2',
],
'amber' => [
'theme' => '#FF6224',
'background' => '#F9F3F0',
],
'onyx' => [
'theme' => '#040406',
'background' => '#F3F3F7',
],
];
public function index(): ResponseInterface
{
helper('misc');
$webmanifest = [
'name' => esc(service('settings') ->get('App.siteName')),
'description' => esc(service('settings') ->get('App.siteDescription')),
'lang' => service('request')
->getLocale(),
'start_url' => base_url(),
'display' => 'standalone',
'orientation' => 'portrait',
'theme_color' => self::THEME_COLORS[service('settings')->get('App.theme')]['theme'],
'background_color' => self::THEME_COLORS[service('settings')->get('App.theme')]['background'],
'icons' => [
[
'src' => get_site_icon_url('192'),
'type' => 'image/png',
'sizes' => '192x192',
],
[
'src' => get_site_icon_url('512'),
'type' => 'image/png',
'sizes' => '512x512',
],
],
];
return $this->response->setJSON($webmanifest);
}
public function podcastManifest(string $podcastHandle): ResponseInterface
{
if (
! ($podcast = (new PodcastModel())->getPodcastByHandle($podcastHandle)) instanceof Podcast
) {
throw PageNotFoundException::forPageNotFound();
}
$webmanifest = [
'name' => esc($podcast->title),
'short_name' => $podcast->at_handle,
'description' => $podcast->description,
'lang' => $podcast->language_code,
'start_url' => $podcast->link,
'scope' => '/' . $podcast->at_handle,
'display' => 'standalone',
'orientation' => 'portrait',
'theme_color' => self::THEME_COLORS[service('settings')->get('App.theme')]['theme'],
'background_color' => self::THEME_COLORS[service('settings')->get('App.theme')]['background'],
'icons' => [
[
'src' => $podcast->cover->webmanifest192_url,
'type' => $podcast->cover->webmanifest192_mimetype,
'sizes' => '192x192',
],
[
'src' => $podcast->cover->webmanifest512_url,
'type' => $podcast->cover->webmanifest512_mimetype,
'sizes' => '512x512',
],
],
];
return $this->response->setJSON($webmanifest);
}
}
<?php
declare(strict_types=1);
/**
* Class AddPodcastUsers Creates podcast_users table in database
*
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddPodcastsUsers extends Migration
{
public function up(): void
{
$this->forge->addField([
'podcast_id' => [
'type' => 'INT',
'unsigned' => true,
],
'user_id' => [
'type' => 'INT',
'unsigned' => true,
],
'group_id' => [
'type' => 'INT',
'unsigned' => true,
],
]);
$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->createTable('podcasts_users');
}
public function down(): void
{
$this->forge->dropTable('podcasts_users');
}
}
<?php
declare(strict_types=1);
/**
* Class AddEpisodeIdToPosts Adds episode_id field to activitypub_posts table in database
*
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddEpisodeIdToPosts extends Migration
{
public function up(): void
{
$prefix = $this->db->getPrefix();
$createQuery = <<<CODE_SAMPLE
ALTER TABLE {$prefix}activitypub_posts
ADD COLUMN `episode_id` INT UNSIGNED NULL AFTER `replies_count`,
ADD FOREIGN KEY {$prefix}activitypub_posts_episode_id_foreign(episode_id) REFERENCES {$prefix}episodes(id) ON DELETE CASCADE;
CODE_SAMPLE;
$this->db->query($createQuery);
}
public function down(): void
{
$this->forge->dropForeignKey('activitypub_posts', 'activitypub_posts_episode_id_foreign');
$this->forge->dropColumn('activitypub_posts', 'episode_id');
}
}
......@@ -5,39 +5,40 @@ declare(strict_types=1);
/**
* Class AddCategories Creates categories table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddCategories extends Migration
class AddCategories extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'parent_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'null' => true,
'null' => true,
],
'code' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
'apple_category' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
'google_category' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
]);
......@@ -47,6 +48,7 @@ class AddCategories extends Migration
$this->forge->createTable('categories');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('categories');
......
......@@ -5,27 +5,28 @@ declare(strict_types=1);
/**
* Class AddLanguages Creates languages table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddLanguages extends Migration
class AddLanguages extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'code' => [
'type' => 'VARCHAR',
'comment' => 'ISO 639-1 language code',
'type' => 'VARCHAR',
'comment' => 'ISO 639-1 language code',
'constraint' => 2,
],
'native_name' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
],
]);
......@@ -33,6 +34,7 @@ class AddLanguages extends Migration
$this->forge->createTable('languages');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('languages');
......
......@@ -5,39 +5,40 @@ declare(strict_types=1);
/**
* Class AddPodcasts Creates podcasts table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddPodcasts extends Migration
class AddPodcasts extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'unsigned' => true,
'type' => 'INT',
'unsigned' => true,
'auto_increment' => true,
],
'guid' => [
'type' => 'CHAR',
'type' => 'CHAR',
'constraint' => 36,
],
'actor_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'handle' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
'title' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
],
'description_markdown' => [
......@@ -46,53 +47,51 @@ class AddPodcasts extends Migration
'description_html' => [
'type' => 'TEXT',
],
'image_path' => [
'type' => 'VARCHAR',
'constraint' => 255,
'cover_id' => [
'type' => 'INT',
'unsigned' => true,
],
// constraint is 13 because the longest safe mimetype for images is image/svg+xml,
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
'image_mimetype' => [
'type' => 'VARCHAR',
'constraint' => 13,
'banner_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
],
'language_code' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 2,
],
'category_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'default' => 0,
'default' => 0,
],
'parental_advisory' => [
'type' => 'ENUM',
'type' => 'ENUM',
'constraint' => ['clean', 'explicit'],
'null' => true,
'default' => null,
'null' => true,
],
'owner_name' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
],
'owner_email' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 255,
],
'publisher' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
'null' => true,
'null' => true,
],
'type' => [
'type' => 'ENUM',
'type' => 'ENUM',
'constraint' => ['episodic', 'serial'],
'default' => 'episodic',
'default' => 'episodic',
],
'copyright' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
'null' => true,
'null' => true,
],
'episode_description_footer_markdown' => [
'type' => 'TEXT',
......@@ -103,91 +102,94 @@ class AddPodcasts extends Migration
'null' => true,
],
'is_blocked' => [
'type' => 'TINYINT',
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'default' => 0,
],
'is_completed' => [
'type' => 'TINYINT',
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'default' => 0,
],
'is_locked' => [
'type' => 'TINYINT',
'type' => 'TINYINT',
'constraint' => 1,
'default' => 1,
'default' => 1,
],
'imported_feed_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
'comment' =>
'The RSS feed URL if this podcast was imported, NULL otherwise.',
'null' => true,
'comment' => 'The RSS feed URL if this podcast was imported, NULL otherwise.',
'null' => true,
],
'new_feed_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
'comment' =>
'The RSS new feed URL if this podcast is moving out, NULL otherwise.',
'null' => true,
'comment' => 'The RSS new feed URL if this podcast is moving out, NULL otherwise.',
'null' => true,
],
'payment_pointer' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
'comment' => 'Wallet address for Web Monetization payments',
'null' => true,
'comment' => 'Wallet address for Web Monetization payments',
'null' => true,
],
'location_name' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
'null' => true,
'null' => true,
],
'location_geo' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
'null' => true,
'null' => true,
],
'location_osm' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 12,
'null' => true,
'null' => true,
],
'custom_rss' => [
'type' => 'JSON',
'null' => true,
],
'partner_id' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
'null' => true,
'null' => true,
],
'partner_link_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
'null' => true,
'null' => true,
],
'partner_image_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
'null' => true,
'null' => true,
],
'is_premium_by_default' => [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
],
'created_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'updated_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'created_at' => [
'published_at' => [
'type' => 'DATETIME',
'null' => true,
],
'updated_at' => [
'created_at' => [
'type' => 'DATETIME',
],
'deleted_at' => [
'updated_at' => [
'type' => 'DATETIME',
'null' => true,
],
]);
......@@ -196,7 +198,9 @@ class AddPodcasts extends Migration
$this->forge->addUniqueKey('handle');
$this->forge->addUniqueKey('guid');
$this->forge->addUniqueKey('actor_id');
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('cover_id', 'media', 'id');
$this->forge->addForeignKey('banner_id', 'media', 'id', '', 'SET NULL');
$this->forge->addForeignKey('category_id', 'categories', 'id');
$this->forge->addForeignKey('language_code', 'languages', 'code');
$this->forge->addForeignKey('created_by', 'users', 'id');
......@@ -204,6 +208,7 @@ class AddPodcasts extends Migration
$this->forge->createTable('podcasts');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('podcasts');
......
......@@ -5,64 +5,45 @@ declare(strict_types=1);
/**
* Class AddEpisodes Creates episodes table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddEpisodes extends Migration
class AddEpisodes extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'unsigned' => true,
'type' => 'INT',
'unsigned' => true,
'auto_increment' => true,
],
'podcast_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'guid' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 255,
],
'title' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
],
'slug' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
],
'audio_file_path' => [
'type' => 'VARCHAR',
'constraint' => 255,
],
'audio_file_duration' => [
// exact value for duration with max 99999,999 ~ 27.7 hours
'type' => 'DECIMAL(8,3)',
'unsigned' => true,
'comment' => 'Playtime in seconds',
],
'audio_file_mimetype' => [
'type' => 'VARCHAR',
'constraint' => 255,
],
'audio_file_size' => [
'type' => 'INT',
'unsigned' => true,
'comment' => 'File size in bytes',
],
'audio_file_header_size' => [
'type' => 'INT',
'audio_id' => [
'type' => 'INT',
'unsigned' => true,
'comment' => 'Header size in bytes',
],
'description_markdown' => [
'type' => 'TEXT',
......@@ -70,99 +51,96 @@ class AddEpisodes extends Migration
'description_html' => [
'type' => 'TEXT',
],
'image_path' => [
'type' => 'VARCHAR',
'constraint' => 255,
'null' => true,
],
// constraint is 13 because the longest safe mimetype for images is image/svg+xml,
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
'image_mimetype' => [
'type' => 'VARCHAR',
'constraint' => 13,
'null' => true,
'cover_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
],
'transcript_file_path' => [
'type' => 'VARCHAR',
'constraint' => 255,
'null' => true,
'transcript_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
],
'transcript_file_remote_url' => [
'type' => 'VARCHAR',
'transcript_remote_url' => [
'type' => 'VARCHAR',
'constraint' => 512,
'null' => true,
'null' => true,
],
'chapters_file_path' => [
'type' => 'VARCHAR',
'constraint' => 255,
'null' => true,
'chapters_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
],
'chapters_file_remote_url' => [
'type' => 'VARCHAR',
'chapters_remote_url' => [
'type' => 'VARCHAR',
'constraint' => 512,
'null' => true,
'null' => true,
],
'parental_advisory' => [
'type' => 'ENUM',
'type' => 'ENUM',
'constraint' => ['clean', 'explicit'],
'null' => true,
'default' => null,
'null' => true,
],
'number' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'null' => true,
'null' => true,
],
'season_number' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'null' => true,
'null' => true,
],
'type' => [
'type' => 'ENUM',
'type' => 'ENUM',
'constraint' => ['trailer', 'full', 'bonus'],
'default' => 'full',
'default' => 'full',
],
'is_blocked' => [
'type' => 'TINYINT',
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'default' => 0,
],
'location_name' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
'null' => true,
'null' => true,
],
'location_geo' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
'null' => true,
'null' => true,
],
'location_osm' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 12,
'null' => true,
'null' => true,
],
'custom_rss' => [
'type' => 'JSON',
'null' => true,
],
'posts_count' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'default' => 0,
'default' => 0,
],
'comments_count' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'default' => 0,
'default' => 0,
],
'is_premium' => [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
],
'created_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'updated_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'published_at' => [
......@@ -175,19 +153,28 @@ class AddEpisodes extends Migration
'updated_at' => [
'type' => 'DATETIME',
],
'deleted_at' => [
'type' => 'DATETIME',
'null' => true,
],
]);
$this->forge->addPrimaryKey('id');
$this->forge->addUniqueKey(['podcast_id', 'slug']);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE');
$this->forge->addForeignKey('audio_id', 'media', 'id');
$this->forge->addForeignKey('cover_id', 'media', 'id', '', 'SET NULL');
$this->forge->addForeignKey('transcript_id', 'media', 'id', '', 'SET NULL');
$this->forge->addForeignKey('chapters_id', 'media', 'id', '', 'SET NULL');
$this->forge->addForeignKey('created_by', 'users', 'id');
$this->forge->addForeignKey('updated_by', 'users', 'id');
$this->forge->createTable('episodes');
// Add Full-Text Search index on title and description_markdown
$prefix = $this->db->getPrefix();
$createQuery = <<<SQL
ALTER TABLE {$prefix}episodes
ADD FULLTEXT title (title, description_markdown);
SQL;
$this->db->query($createQuery);
}
#[Override]
public function down(): void
{
$this->forge->dropTable('episodes');
......
......@@ -5,49 +5,52 @@ declare(strict_types=1);
/**
* Class AddPlatforms Creates platforms table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddPlatforms extends Migration
class AddPlatforms extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'slug' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
'type' => [
'type' => 'ENUM',
'type' => 'ENUM',
'constraint' => ['podcasting', 'social', 'funding'],
],
'label' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
'home_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 255,
],
'submit_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
'null' => true,
'default' => null,
'null' => true,
],
]);
$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('`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP()');
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()',
);
$this->forge->addPrimaryKey('slug');
$this->forge->createTable('platforms');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('platforms');
......
......@@ -5,53 +5,57 @@ declare(strict_types=1);
/**
* Class AddAddPodcastsPlatforms Creates podcasts_platforms table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace Analytics\Database\Migrations;
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddPodcastsPlatforms extends Migration
class AddPodcastsPlatforms extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'podcast_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'platform_slug' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 32,
],
'link_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
],
'link_content' => [
'type' => 'VARCHAR',
'account_id' => [
'type' => 'VARCHAR',
'constraint' => 128,
'null' => true,
'null' => true,
],
'is_visible' => [
'type' => 'TINYINT',
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'default' => 0,
],
'is_on_embeddable_player' => [
'type' => 'TINYINT',
'is_on_embed' => [
'type' => 'TINYINT',
'constraint' => 1,
'default' => 0,
'default' => 0,
],
]);
$this->forge->addPrimaryKey(['podcast_id', 'platform_slug']);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE');
$this->forge->addForeignKey('platform_slug', 'platforms', 'slug', 'CASCADE');
$this->forge->createTable('podcasts_platforms');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('podcasts_platforms');
......
......@@ -3,83 +3,80 @@
declare(strict_types=1);
/**
* Class AddComments creates comments table in database
* Class AddEpisodeComments creates episode_comments table in database
*
* @copyright 2020 Podlibre
* @copyright 2021 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddComments extends Migration
class AddEpisodeComments extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'BINARY',
'type' => 'BINARY',
'constraint' => 16,
],
'uri' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 255,
],
'episode_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'actor_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'in_reply_to_id' => [
'type' => 'BINARY',
'type' => 'BINARY',
'constraint' => 16,
'null' => true,
'null' => true,
],
'message' => [
'type' => 'VARCHAR',
'constraint' => 500,
'null' => true,
'type' => 'VARCHAR',
'constraint' => 5000,
],
'message_html' => [
'type' => 'VARCHAR',
'constraint' => 600,
'null' => true,
'type' => 'VARCHAR',
'constraint' => 6000,
],
'likes_count' => [
'type' => 'INT',
'unsigned' => true,
],
'dislikes_count' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'replies_count' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'created_at' => [
'type' => 'DATETIME',
],
'created_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
'null' => true,
'null' => true,
],
]);
$this->forge->addPrimaryKey('id');
$this->forge->addForeignKey('episode_id', 'episodes', 'id', '', 'CASCADE');
$this->forge->addForeignKey('actor_id', 'activitypub_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('created_by', 'users', 'id');
$this->forge->createTable('comments');
$this->forge->createTable('episode_comments');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('comments');
$this->forge->dropTable('episode_comments');
}
}
<?php
declare(strict_types=1);
/**
* Class AddLikes Creates likes table in database
*
* @copyright 2021 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use Override;
class AddLikes extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'actor_id' => [
'type' => 'INT',
'unsigned' => true,
],
'comment_id' => [
'type' => 'BINARY',
'constraint' => 16,
],
]);
$this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()');
$this->forge->addPrimaryKey(['actor_id', 'comment_id']);
$this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE');
$this->forge->addForeignKey('comment_id', 'episode_comments', 'id', '', 'CASCADE');
$this->forge->createTable('likes');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('likes');
}
}
......@@ -5,33 +5,34 @@ declare(strict_types=1);
/**
* Class AddPages Creates pages table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddPages extends Migration
class AddPages extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'unsigned' => true,
'type' => 'INT',
'unsigned' => true,
'auto_increment' => true,
],
'title' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 255,
],
'slug' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 128,
'unique' => true,
'unique' => true,
],
'content_markdown' => [
'type' => 'TEXT',
......@@ -45,15 +46,12 @@ class AddPages extends Migration
'updated_at' => [
'type' => 'DATETIME',
],
'deleted_at' => [
'type' => 'DATETIME',
'null' => true,
],
]);
$this->forge->addPrimaryKey('id');
$this->forge->createTable('pages');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('pages');
......
......@@ -5,26 +5,27 @@ declare(strict_types=1);
/**
* Class AddPodcastsCategories Creates podcasts_categories table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddPodcastsCategories extends Migration
class AddPodcastsCategories extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'podcast_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'category_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
]);
......@@ -34,6 +35,7 @@ class AddPodcastsCategories extends Migration
$this->forge->createTable('podcasts_categories');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('podcasts_categories');
......
......@@ -3,79 +3,103 @@
declare(strict_types=1);
/**
* Class AddSoundbites Creates soundbites table in database
*
* @copyright 2020 Podlibre
* @copyright 2021 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddSoundbites extends Migration
class AddClips extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'unsigned' => true,
'type' => 'INT',
'unsigned' => true,
'auto_increment' => true,
],
'podcast_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'episode_id' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'start_time' => [
'type' => 'DECIMAL(8,3)',
'type' => 'DECIMAL(8,3)',
'unsigned' => true,
],
'duration' => [
// soundbite duration cannot be higher than 9999,999 seconds ~ 2.77 hours
'type' => 'DECIMAL(7,3)',
// clip duration cannot be higher than 9999,999 seconds ~ 2.77 hours
'type' => 'DECIMAL(7,3)',
'unsigned' => true,
],
'label' => [
'type' => 'VARCHAR',
'title' => [
'type' => 'VARCHAR',
'constraint' => 128,
],
'type' => [
'type' => 'ENUM',
'constraint' => ['audio', 'video'],
],
'media_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
],
'metadata' => [
'type' => 'JSON',
'null' => true,
],
'status' => [
'type' => 'ENUM',
'constraint' => ['queued', 'pending', 'running', 'passed', 'failed'],
],
'logs' => [
'type' => 'TEXT',
],
'created_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'updated_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'created_at' => [
'job_started_at' => [
'type' => 'DATETIME',
'null' => true,
],
'updated_at' => [
'job_ended_at' => [
'type' => 'DATETIME',
'null' => true,
],
'deleted_at' => [
'created_at' => [
'type' => 'DATETIME',
],
'updated_at' => [
'type' => 'DATETIME',
'null' => true,
],
]);
$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('media_id', 'media', 'id', '', 'CASCADE');
$this->forge->addForeignKey('created_by', 'users', 'id');
$this->forge->addForeignKey('updated_by', 'users', 'id');
$this->forge->createTable('soundbites');
$this->forge->createTable('clips');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('soundbites');
$this->forge->dropTable('clips');
}
}
......@@ -5,61 +5,54 @@ declare(strict_types=1);
/**
* Class Persons Creates persons table in database
*
* @copyright 2020 Podlibre
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use Override;
class AddPersons extends Migration
class AddPersons extends BaseMigration
{
#[Override]
public function up(): void
{
$this->forge->addField([
'id' => [
'type' => 'INT',
'unsigned' => true,
'type' => 'INT',
'unsigned' => true,
'auto_increment' => true,
],
'full_name' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 192,
'comment' => 'This is the full name or alias of the person.',
'comment' => 'This is the full name or alias of the person.',
],
'unique_name' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 192,
'comment' => 'This is the slug name or alias of the person.',
'unique' => true,
'comment' => 'This is the slug name or alias of the person.',
'unique' => true,
],
'information_url' => [
'type' => 'VARCHAR',
'type' => 'VARCHAR',
'constraint' => 512,
'comment' =>
'The url to a relevant resource of information about the person, such as a homepage or third-party profile platform.',
'null' => true,
],
'image_path' => [
'type' => 'VARCHAR',
'constraint' => 255,
'null' => true,
'comment' => 'The url to a relevant resource of information about the person, such as a homepage or third-party profile platform.',
'null' => true,
],
// constraint is 13 because the longest safe mimetype for images is image/svg+xml,
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
'image_mimetype' => [
'type' => 'VARCHAR',
'constraint' => 13,
'null' => true,
'avatar_id' => [
'type' => 'INT',
'unsigned' => true,
'null' => true,
],
'created_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'updated_by' => [
'type' => 'INT',
'type' => 'INT',
'unsigned' => true,
],
'created_at' => [
......@@ -71,11 +64,13 @@ class AddPersons extends Migration
]);
$this->forge->addKey('id', true);
$this->forge->addForeignKey('avatar_id', 'media', 'id', '', 'SET NULL');
$this->forge->addForeignKey('created_by', 'users', 'id');
$this->forge->addForeignKey('updated_by', 'users', 'id');
$this->forge->createTable('persons');
}
#[Override]
public function down(): void
{
$this->forge->dropTable('persons');
......