Loading app/Config/Routes.php +23 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,29 @@ $routes->group( 'filter' => 'permission:podcast_episodes-edit', ] ); $routes->get( 'soundbites', 'Episode::soundbitesEdit/$1/$2', [ 'as' => 'soundbites-edit', 'filter' => 'permission:podcast_episodes-edit', ] ); $routes->post( 'soundbites', 'Episode::soundbitesAttemptEdit/$1/$2', [ 'filter' => 'permission:podcast_episodes-edit', ] ); $routes->add( 'soundbites/(:num)/delete', 'Episode::soundbiteDelete/$1/$2/$3', [ 'as' => 'soundbite-delete', 'filter' => 'permission:podcast_episodes-edit', ] ); }); }); Loading app/Controllers/Admin/Episode.php +95 −1 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ namespace App\Controllers\Admin; use App\Models\EpisodeModel; use App\Models\PodcastModel; use App\Models\SoundbiteModel; use CodeIgniter\I18n\Time; class Episode extends BaseController Loading @@ -24,6 +25,11 @@ class Episode extends BaseController */ protected $episode; /** * @var \App\Entities\Soundbite|null */ protected $soundbites; public function _remap($method, ...$params) { $this->podcast = (new PodcastModel())->getPodcastById($params[0]); Loading @@ -39,9 +45,12 @@ class Episode extends BaseController ) { throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); } unset($params[1]); unset($params[0]); } return $this->$method(); return $this->$method(...$params); } public function list() Loading Loading @@ -316,4 +325,89 @@ class Episode extends BaseController return redirect()->route('episode-list', [$this->podcast->id]); } public function soundbitesEdit() { helper(['form']); $data = [ 'podcast' => $this->podcast, 'episode' => $this->episode, ]; replace_breadcrumb_params([ 0 => $this->podcast->title, 1 => $this->episode->title, ]); return view('admin/episode/soundbites', $data); } public function soundbitesAttemptEdit() { $soundbites_array = $this->request->getPost('soundbites_array'); $rules = [ 'soundbites_array.0.start_time' => 'permit_empty|required_with[soundbites_array.0.duration]|decimal|greater_than_equal_to[0]', 'soundbites_array.0.duration' => 'permit_empty|required_with[soundbites_array.0.start_time]|decimal|greater_than_equal_to[0]', ]; foreach ($soundbites_array as $soundbite_id => $soundbite) { $rules += [ "soundbites_array.{$soundbite_id}.start_time" => 'required|decimal|greater_than_equal_to[0]', "soundbites_array.{$soundbite_id}.duration" => 'required|decimal|greater_than_equal_to[0]', ]; } if (!$this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } foreach ($soundbites_array as $soundbite_id => $soundbite) { if ( !empty($soundbite['start_time']) && !empty($soundbite['duration']) ) { $data = [ 'podcast_id' => $this->podcast->id, 'episode_id' => $this->episode->id, 'start_time' => $soundbite['start_time'], 'duration' => $soundbite['duration'], 'label' => $soundbite['label'], 'updated_by' => user()->id, ]; if ($soundbite_id == 0) { $data += ['created_by' => user()->id]; } else { $data += ['id' => $soundbite_id]; } $soundbiteModel = new SoundbiteModel(); if (!$soundbiteModel->save($data)) { return redirect() ->back() ->withInput() ->with('errors', $soundbiteModel->errors()); } } } return redirect()->route('soundbites-edit', [ $this->podcast->id, $this->episode->id, ]); } public function soundbiteDelete($soundbiteId) { (new SoundbiteModel())->deleteSoundbite( $this->podcast->id, $this->episode->id, $soundbiteId ); return redirect()->route('soundbites-edit', [ $this->podcast->id, $this->episode->id, ]); } } app/Database/Migrations/2020-06-05-180000_add_soundbites.php 0 → 100644 +77 −0 Original line number Diff line number Diff line <?php /** * Class AddSoundbites * Creates soundbites 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 AddSoundbites extends Migration { public function up() { $this->forge->addField([ 'id' => [ 'type' => 'INT', 'unsigned' => true, 'auto_increment' => true, ], 'podcast_id' => [ 'type' => 'INT', 'unsigned' => true, ], 'episode_id' => [ 'type' => 'INT', 'unsigned' => true, ], 'start_time' => [ 'type' => 'FLOAT', ], 'duration' => [ 'type' => 'FLOAT', ], 'label' => [ 'type' => 'VARCHAR', 'constraint' => 128, 'null' => true, ], 'created_by' => [ 'type' => 'INT', 'unsigned' => true, ], 'updated_by' => [ 'type' => 'INT', 'unsigned' => true, ], 'created_at' => [ 'type' => 'DATETIME', ], 'updated_at' => [ 'type' => 'DATETIME', ], 'deleted_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'); $this->forge->addForeignKey('episode_id', 'episodes', 'id'); $this->forge->addForeignKey('created_by', 'users', 'id'); $this->forge->addForeignKey('updated_by', 'users', 'id'); $this->forge->createTable('soundbites'); } public function down() { $this->forge->dropTable('soundbites'); } } app/Entities/Category.php +1 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ class Category extends Entity protected $parent; protected $casts = [ 'id' => 'integer', 'parent_id' => 'integer', 'code' => 'string', 'apple_category' => 'string', Loading app/Entities/Episode.php +30 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ namespace App\Entities; use App\Models\PodcastModel; use App\Models\SoundbiteModel; use CodeIgniter\Entity; use CodeIgniter\I18n\Time; use League\CommonMark\CommonMarkConverter; Loading Loading @@ -75,6 +76,11 @@ class Episode extends Entity */ protected $chapters_url; /** * @var \App\Entities\Soundbite[] */ protected $soundbites; /** * Holds text only description, striped of any markdown or html special characters * Loading @@ -95,6 +101,7 @@ class Episode extends Entity ]; protected $casts = [ 'id' => 'integer', 'guid' => 'string', 'slug' => 'string', 'title' => 'string', Loading Loading @@ -348,6 +355,29 @@ class Episode extends Entity : null; } /** * Returns the episode’s soundbites * * @return \App\Entities\Episode[] */ public function getSoundbites() { if (empty($this->id)) { throw new \RuntimeException( 'Episode must be created before getting soundbites.' ); } if (empty($this->soundbites)) { $this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites( $this->getPodcast()->id, $this->id ); } return $this->soundbites; } public function getLink() { return base_url( Loading Loading
app/Config/Routes.php +23 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,29 @@ $routes->group( 'filter' => 'permission:podcast_episodes-edit', ] ); $routes->get( 'soundbites', 'Episode::soundbitesEdit/$1/$2', [ 'as' => 'soundbites-edit', 'filter' => 'permission:podcast_episodes-edit', ] ); $routes->post( 'soundbites', 'Episode::soundbitesAttemptEdit/$1/$2', [ 'filter' => 'permission:podcast_episodes-edit', ] ); $routes->add( 'soundbites/(:num)/delete', 'Episode::soundbiteDelete/$1/$2/$3', [ 'as' => 'soundbite-delete', 'filter' => 'permission:podcast_episodes-edit', ] ); }); }); Loading
app/Controllers/Admin/Episode.php +95 −1 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ namespace App\Controllers\Admin; use App\Models\EpisodeModel; use App\Models\PodcastModel; use App\Models\SoundbiteModel; use CodeIgniter\I18n\Time; class Episode extends BaseController Loading @@ -24,6 +25,11 @@ class Episode extends BaseController */ protected $episode; /** * @var \App\Entities\Soundbite|null */ protected $soundbites; public function _remap($method, ...$params) { $this->podcast = (new PodcastModel())->getPodcastById($params[0]); Loading @@ -39,9 +45,12 @@ class Episode extends BaseController ) { throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); } unset($params[1]); unset($params[0]); } return $this->$method(); return $this->$method(...$params); } public function list() Loading Loading @@ -316,4 +325,89 @@ class Episode extends BaseController return redirect()->route('episode-list', [$this->podcast->id]); } public function soundbitesEdit() { helper(['form']); $data = [ 'podcast' => $this->podcast, 'episode' => $this->episode, ]; replace_breadcrumb_params([ 0 => $this->podcast->title, 1 => $this->episode->title, ]); return view('admin/episode/soundbites', $data); } public function soundbitesAttemptEdit() { $soundbites_array = $this->request->getPost('soundbites_array'); $rules = [ 'soundbites_array.0.start_time' => 'permit_empty|required_with[soundbites_array.0.duration]|decimal|greater_than_equal_to[0]', 'soundbites_array.0.duration' => 'permit_empty|required_with[soundbites_array.0.start_time]|decimal|greater_than_equal_to[0]', ]; foreach ($soundbites_array as $soundbite_id => $soundbite) { $rules += [ "soundbites_array.{$soundbite_id}.start_time" => 'required|decimal|greater_than_equal_to[0]', "soundbites_array.{$soundbite_id}.duration" => 'required|decimal|greater_than_equal_to[0]', ]; } if (!$this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } foreach ($soundbites_array as $soundbite_id => $soundbite) { if ( !empty($soundbite['start_time']) && !empty($soundbite['duration']) ) { $data = [ 'podcast_id' => $this->podcast->id, 'episode_id' => $this->episode->id, 'start_time' => $soundbite['start_time'], 'duration' => $soundbite['duration'], 'label' => $soundbite['label'], 'updated_by' => user()->id, ]; if ($soundbite_id == 0) { $data += ['created_by' => user()->id]; } else { $data += ['id' => $soundbite_id]; } $soundbiteModel = new SoundbiteModel(); if (!$soundbiteModel->save($data)) { return redirect() ->back() ->withInput() ->with('errors', $soundbiteModel->errors()); } } } return redirect()->route('soundbites-edit', [ $this->podcast->id, $this->episode->id, ]); } public function soundbiteDelete($soundbiteId) { (new SoundbiteModel())->deleteSoundbite( $this->podcast->id, $this->episode->id, $soundbiteId ); return redirect()->route('soundbites-edit', [ $this->podcast->id, $this->episode->id, ]); } }
app/Database/Migrations/2020-06-05-180000_add_soundbites.php 0 → 100644 +77 −0 Original line number Diff line number Diff line <?php /** * Class AddSoundbites * Creates soundbites 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 AddSoundbites extends Migration { public function up() { $this->forge->addField([ 'id' => [ 'type' => 'INT', 'unsigned' => true, 'auto_increment' => true, ], 'podcast_id' => [ 'type' => 'INT', 'unsigned' => true, ], 'episode_id' => [ 'type' => 'INT', 'unsigned' => true, ], 'start_time' => [ 'type' => 'FLOAT', ], 'duration' => [ 'type' => 'FLOAT', ], 'label' => [ 'type' => 'VARCHAR', 'constraint' => 128, 'null' => true, ], 'created_by' => [ 'type' => 'INT', 'unsigned' => true, ], 'updated_by' => [ 'type' => 'INT', 'unsigned' => true, ], 'created_at' => [ 'type' => 'DATETIME', ], 'updated_at' => [ 'type' => 'DATETIME', ], 'deleted_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'); $this->forge->addForeignKey('episode_id', 'episodes', 'id'); $this->forge->addForeignKey('created_by', 'users', 'id'); $this->forge->addForeignKey('updated_by', 'users', 'id'); $this->forge->createTable('soundbites'); } public function down() { $this->forge->dropTable('soundbites'); } }
app/Entities/Category.php +1 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ class Category extends Entity protected $parent; protected $casts = [ 'id' => 'integer', 'parent_id' => 'integer', 'code' => 'string', 'apple_category' => 'string', Loading
app/Entities/Episode.php +30 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ namespace App\Entities; use App\Models\PodcastModel; use App\Models\SoundbiteModel; use CodeIgniter\Entity; use CodeIgniter\I18n\Time; use League\CommonMark\CommonMarkConverter; Loading Loading @@ -75,6 +76,11 @@ class Episode extends Entity */ protected $chapters_url; /** * @var \App\Entities\Soundbite[] */ protected $soundbites; /** * Holds text only description, striped of any markdown or html special characters * Loading @@ -95,6 +101,7 @@ class Episode extends Entity ]; protected $casts = [ 'id' => 'integer', 'guid' => 'string', 'slug' => 'string', 'title' => 'string', Loading Loading @@ -348,6 +355,29 @@ class Episode extends Entity : null; } /** * Returns the episode’s soundbites * * @return \App\Entities\Episode[] */ public function getSoundbites() { if (empty($this->id)) { throw new \RuntimeException( 'Episode must be created before getting soundbites.' ); } if (empty($this->soundbites)) { $this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites( $this->getPodcast()->id, $this->id ); } return $this->soundbites; } public function getLink() { return base_url( Loading