Commit 8acd011f authored by Benjamin Bellamy's avatar Benjamin Bellamy 💬
Browse files

feat(person): add podcastindex.org namespace person tag

parent 17e1e94a
Pipeline #624 passed with stage
in 5 minutes and 14 seconds
......@@ -30,6 +30,9 @@ $RECYCLE.BIN/
# Linux
*~
# vim
*.swp
# KDE directory preferences
.directory
......@@ -135,6 +138,7 @@ node_modules
# public folder
public/*
!public/media
!public/media/~person
!public/.htaccess
!public/favicon.ico
!public/index.php
......@@ -144,6 +148,14 @@ public/*
public/media/*
!public/media/index.html
# public person folder
public/media/~person/*
!public/media/~person/index.html
# Generated files
app/Language/en/PersonsTaxonomy.php
app/Language/fr/PersonsTaxonomy.php
#-------------------------
# Docker volumes
#-------------------------
......
......@@ -85,6 +85,37 @@ $routes->group(
'as' => 'my-podcasts',
]);
$routes->group('persons', function ($routes) {
$routes->get('/', 'Person', [
'as' => 'person-list',
'filter' => 'permission:person-list',
]);
$routes->get('new', 'Person::create', [
'as' => 'person-create',
'filter' => 'permission:person-create',
]);
$routes->post('new', 'Person::attemptCreate', [
'filter' => 'permission:person-create',
]);
$routes->group('(:num)', function ($routes) {
$routes->get('/', 'Person::view/$1', [
'as' => 'person-view',
'filter' => 'permission:person-view',
]);
$routes->get('edit', 'Person::edit/$1', [
'as' => 'person-edit',
'filter' => 'permission:person-edit',
]);
$routes->post('edit', 'Person::attemptEdit/$1', [
'filter' => 'permission:person-edit',
]);
$routes->add('delete', 'Person::delete/$1', [
'as' => 'person-delete',
'filter' => 'permission:person-delete',
]);
});
});
// Podcasts
$routes->group('podcasts', function ($routes) {
$routes->get('/', 'Podcast::list', [
......@@ -124,6 +155,25 @@ $routes->group(
'filter' => 'permission:podcasts-delete',
]);
$routes->group('persons', function ($routes) {
$routes->get('/', 'PodcastPerson/$1', [
'as' => 'podcast-person-manage',
'filter' => 'permission:podcast-edit',
]);
$routes->post('/', 'PodcastPerson::attemptAdd/$1', [
'filter' => 'permission:podcast-edit',
]);
$routes->get(
'(:num)/remove',
'PodcastPerson::remove/$1/$2',
[
'as' => 'podcast-person-remove',
'filter' => 'permission:podcast-edit',
]
);
});
$routes->group('analytics', function ($routes) {
$routes->get('/', 'Podcast::viewAnalytics/$1', [
'as' => 'podcast-analytics',
......@@ -276,6 +326,30 @@ $routes->group(
'filter' => 'permission:podcast_episodes-edit',
]
);
$routes->group('persons', function ($routes) {
$routes->get('/', 'EpisodePerson/$1/$2', [
'as' => 'episode-person-manage',
'filter' => 'permission:podcast_episodes-edit',
]);
$routes->post(
'/',
'EpisodePerson::attemptAdd/$1/$2',
[
'filter' =>
'permission:podcast_episodes-edit',
]
);
$routes->get(
'(:num)/remove',
'EpisodePerson::remove/$1/$2/$3',
[
'as' => 'episode-person-remove',
'filter' =>
'permission:podcast_episodes-edit',
]
);
});
});
});
......@@ -497,6 +571,7 @@ $routes->group('@(:podcastName)', function ($routes) {
$routes->head('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
$routes->get('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
});
$routes->get('/credits', 'Page::credits', ['as' => 'credits']);
$routes->get('/(:slug)', 'Page/$1', ['as' => 'page']);
/**
......
<?php
/**
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Controllers\Admin;
use App\Models\EpisodePersonModel;
use App\Models\PodcastModel;
use App\Models\EpisodeModel;
use App\Models\PersonModel;
class EpisodePerson extends BaseController
{
/**
* @var \App\Entities\Podcast
*/
protected $podcast;
/**
* @var \App\Entities\Episode
*/
protected $episode;
public function _remap($method, ...$params)
{
if (count($params) > 1) {
if (
!($this->podcast = (new PodcastModel())->getPodcastById(
$params[0]
))
) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
if (
!($this->episode = (new EpisodeModel())
->where([
'id' => $params[1],
'podcast_id' => $params[0],
])
->first())
) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
} else {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
unset($params[1]);
unset($params[0]);
return $this->$method(...$params);
}
public function index()
{
helper('form');
$data = [
'episode' => $this->episode,
'podcast' => $this->podcast,
'episodePersons' => (new EpisodePersonModel())->getPersonsByEpisodeId(
$this->podcast->id,
$this->episode->id
),
'personOptions' => (new PersonModel())->getPersonOptions(),
'taxonomyOptions' => (new PersonModel())->getTaxonomyOptions(),
];
replace_breadcrumb_params([
0 => $this->podcast->title,
1 => $this->episode->title,
]);
return view('admin/episode/person', $data);
}
public function attemptAdd()
{
$rules = [
'person' => 'required',
];
if (!$this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
(new EpisodePersonModel())->addEpisodePersons(
$this->podcast->id,
$this->episode->id,
$this->request->getPost('person'),
$this->request->getPost('person_group_role')
);
return redirect()->back();
}
public function remove($episodePersonId)
{
(new EpisodePersonModel())->removeEpisodePersons(
$this->podcast->id,
$this->episode->id,
$episodePersonId
);
return redirect()->back();
}
}
<?php
/**
* @copyright 2021 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Controllers\Admin;
use App\Models\PersonModel;
class Person extends BaseController
{
/**
* @var \App\Entities\Person|null
*/
protected $person;
public function _remap($method, ...$params)
{
if (count($params) > 0) {
if (
!($this->person = (new PersonModel())->getPersonById(
$params[0]
))
) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
}
return $this->$method();
}
public function index()
{
$data = ['persons' => (new PersonModel())->findAll()];
return view('admin/person/list', $data);
}
public function view()
{
$data = ['person' => $this->person];
replace_breadcrumb_params([0 => $this->person->full_name]);
return view('admin/person/view', $data);
}
public function create()
{
helper(['form']);
return view('admin/person/create');
}
public function attemptCreate()
{
$rules = [
'image' =>
'is_image[image]|ext_in[image,jpg,jpeg,png]|min_dims[image,400,400]|is_image_squared[image]',
];
if (!$this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$person = new \App\Entities\Person([
'full_name' => $this->request->getPost('full_name'),
'unique_name' => $this->request->getPost('unique_name'),
'information_url' => $this->request->getPost('information_url'),
'image' => $this->request->getFile('image'),
'created_by' => user()->id,
'updated_by' => user()->id,
]);
$personModel = new PersonModel();
if (!$personModel->insert($person)) {
return redirect()
->back()
->withInput()
->with('errors', $personModel->errors());
}
return redirect()->route('person-list');
}
public function edit()
{
helper('form');
$data = [
'person' => $this->person,
];
replace_breadcrumb_params([0 => $this->person->full_name]);
return view('admin/person/edit', $data);
}
public function attemptEdit()
{
$rules = [
'image' =>
'is_image[image]|ext_in[image,jpg,jpeg,png]|min_dims[image,400,400]|is_image_squared[image]',
];
if (!$this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$this->person->full_name = $this->request->getPost('full_name');
$this->person->unique_name = $this->request->getPost('unique_name');
$this->person->information_url = $this->request->getPost(
'information_url'
);
$image = $this->request->getFile('image');
if ($image->isValid()) {
$this->person->image = $image;
}
$this->updated_by = user();
$personModel = new PersonModel();
if (!$personModel->update($this->person->id, $this->person)) {
return redirect()
->back()
->withInput()
->with('errors', $personModel->errors());
}
return redirect()->route('person-view', [$this->person->id]);
}
public function delete()
{
(new PersonModel())->delete($this->person->id);
return redirect()->route('person-list');
}
}
......@@ -13,6 +13,9 @@ use App\Models\LanguageModel;
use App\Models\PodcastModel;
use App\Models\EpisodeModel;
use App\Models\PlatformModel;
use App\Models\PersonModel;
use App\Models\PodcastPersonModel;
use App\Models\EpisodePersonModel;
use Config\Services;
use League\HTMLToMarkdown\HtmlConverter;
......@@ -150,7 +153,7 @@ class PodcastImport extends BaseController
: $nsItunes->complete === 'yes',
'location_name' => !$nsPodcast->location
? null
: $nsPodcast->location->attributes()['name'],
: $nsPodcast->location,
'location_geo' =>
!$nsPodcast->location ||
empty($nsPodcast->location->attributes()['geo'])
......@@ -158,9 +161,9 @@ class PodcastImport extends BaseController
: $nsPodcast->location->attributes()['geo'],
'location_osmid' =>
!$nsPodcast->location ||
empty($nsPodcast->location->attributes()['osmid'])
empty($nsPodcast->location->attributes()['osm'])
? null
: $nsPodcast->location->attributes()['osmid'],
: $nsPodcast->location->attributes()['osm'],
'created_by' => user(),
'updated_by' => user(),
]);
......@@ -200,40 +203,40 @@ class PodcastImport extends BaseController
$podcastAdminGroup->id
);
$platformModel = new PlatformModel();
$podcastsPlatformsData = [];
foreach ($nsPodcast->id as $podcastingPlatform) {
$slug = $podcastingPlatform->attributes()['platform'];
$platformModel->getOrCreatePlatform($slug, 'podcasting');
array_push($podcastsPlatformsData, [
'platform_slug' => $slug,
'podcast_id' => $newPodcastId,
'link_url' => $podcastingPlatform->attributes()['url'],
'link_content' => $podcastingPlatform->attributes()['id'],
'is_visible' => false,
]);
}
foreach ($nsPodcast->social as $socialPlatform) {
$slug = $socialPlatform->attributes()['platform'];
$platformModel->getOrCreatePlatform($slug, 'social');
array_push($podcastsPlatformsData, [
'platform_slug' => $socialPlatform->attributes()['platform'],
'podcast_id' => $newPodcastId,
'link_url' => $socialPlatform->attributes()['url'],
'link_content' => $socialPlatform,
'is_visible' => false,
]);
}
foreach ($nsPodcast->funding as $fundingPlatform) {
$slug = $fundingPlatform->attributes()['platform'];
$platformModel->getOrCreatePlatform($slug, 'funding');
array_push($podcastsPlatformsData, [
'platform_slug' => $fundingPlatform->attributes()['platform'],
'podcast_id' => $newPodcastId,
'link_url' => $fundingPlatform->attributes()['url'],
'link_content' => $fundingPlatform->attributes()['id'],
'is_visible' => false,
]);
$platformTypes = [
['name' => 'podcasting', 'elements' => $nsPodcast->id],
['name' => 'social', 'elements' => $nsPodcast->social],
['name' => 'funding', 'elements' => $nsPodcast->funding],
];
$platformModel = new PlatformModel();
foreach ($platformTypes as $platformType) {
foreach ($platformType['elements'] as $platform) {
$platformLabel = $platform->attributes()['platform'];
$platformSlug = slugify($platformLabel);
if (!$platformModel->getPlatform($platformSlug)) {
if (
!$platformModel->createPlatform(
$platformSlug,
$platformType['name'],
$platformLabel,
''
)
) {
return redirect()
->back()
->withInput()
->with('errors', $platformModel->errors());
}
}
array_push($podcastsPlatformsData, [
'platform_slug' => $platformSlug,
'podcast_id' => $newPodcastId,
'link_url' => $platform->attributes()['url'],
'link_content' => $platform->attributes()['id'],
'is_visible' => false,
]);
}
}
if (count($podcastsPlatformsData) > 1) {
$platformModel->createPodcastPlatforms(
......@@ -242,6 +245,54 @@ class PodcastImport extends BaseController
);
}
foreach ($nsPodcast->person as $podcastPerson) {
$personModel = new PersonModel();
$newPersonId = null;
if ($newPerson = $personModel->getPerson($podcastPerson)) {
$newPersonId = $newPerson->id;
} else {
if (
!($newPersonId = $personModel->createPerson(
$podcastPerson,
$podcastPerson->attributes()['href'],
$podcastPerson->attributes()['img']
))
) {
return redirect()
->back()
->withInput()
->with('errors', $personModel->errors());
}
}
$personGroup = empty($podcastPerson->attributes()['group'])
? ['slug' => '']
: \Podlibre\PodcastNamespace\ReversedTaxonomy::$taxonomy[
(string) $podcastPerson->attributes()['group']
];
$personRole =
empty($podcastPerson->attributes()['role']) ||
empty($personGroup)
? ['slug' => '']
: $personGroup['roles'][
strval($podcastPerson->attributes()['role'])
];
$newPodcastPerson = new \App\Entities\PodcastPerson([
'podcast_id' => $newPodcastId,
'person_id' => $newPersonId,
'person_group' => $personGroup['slug'],
'person_role' => $personRole['slug'],
]);
$podcastPersonModel = new PodcastPersonModel();
if (!$podcastPersonModel->insert($newPodcastPerson)) {
return redirect()
->back()
->withInput()
->with('errors', $podcastPersonModel->errors());
}
}
$numberItems = $feed->channel[0]->item->count();
$lastItem =
!empty($this->request->getPost('max_episodes')) &&
......@@ -251,6 +302,7 @@ class PodcastImport extends BaseController
$slugs = [];
//////////////////////////////////////////////////////////////////
// For each Episode:
for ($itemNumber = 1; $itemNumber <= $lastItem; $itemNumber++) {
$item = $feed->channel[0]->item[$numberItems - $itemNumber];
......@@ -326,7 +378,7 @@ class PodcastImport extends BaseController
: $nsItunes->block === 'yes',
'location_name' => !$nsPodcast->location
? null
: $nsPodcast->location->attributes()['name'],
: $nsPodcast->location,
'location_geo' =>
!$nsPodcast->location ||
empty($nsPodcast->location->attributes()['geo'])
......@@ -334,9 +386,9 @@ class PodcastImport extends BaseController
: $nsPodcast->location->attributes()['geo'],
'location_osmid' =>
!$nsPodcast->location ||
empty($nsPodcast->location->attributes()['osmid'])
empty($nsPodcast->location->attributes()['osm'])
? null
: $nsPodcast->location->attributes()['osmid'],
: $nsPodcast->location->attributes()['osm'],
'created_by' => user(),
'updated_by' => user(),
'published_at' => strtotime($item->pubDate),
......@@ -344,13 +396,62 @@ class PodcastImport extends BaseController
$episodeModel = new EpisodeModel();
if (!$episodeModel->insert($newEpisode)) {
if (!($newEpisodeId = $episodeModel->insert($newEpisode, true))) {
// FIXME: What shall we do?
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());
}
foreach ($nsPodcast->person as $episodePerson) {
$personModel = new PersonModel();
$newPersonId = null;
if ($newPerson = $personModel->getPerson($episodePerson)) {
$newPersonId = $newPerson->id;
} else {
if (
!($newPersonId = $personModel->createPerson(
$episodePerson,
$episodePerson->attributes()['href'],
$episodePerson->attributes()['img']
))
) {
return redirect()
->back()
->withInput()
<