Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions lib/Caching/VideosCaching.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file needs to be deleted


namespace Opencast\Caching;

use Opencast\Models\Videos;

class VideosCaching
{
private $cache_factory;
private $cache_name;
const OC_CACHE_KEY_DOMAIN_USERS = 'OpencastV3/videos/users/';
const OC_CACHE_KEY_DOMAIN_COURSES = 'OpencastV3/videos/courses/';
const OC_CACHE_KEY_DOMAIN_PLAYLIST = 'OpencastV3/videos/playlist/';

public function __construct() {
$this->cache_factory = \StudipCacheFactory::getCache();
}

public function userVideos(string $user_id)
{
$this->cache_name = self::OC_CACHE_KEY_DOMAIN_USERS . $user_id;
return $this;
}

public function courseVideos(string $course_id)
{
$this->cache_name = self::OC_CACHE_KEY_DOMAIN_COURSES . $course_id;
return $this;
}

public function playlistVideos(int $playlist_id)
{
$this->cache_name = self::OC_CACHE_KEY_DOMAIN_PLAYLIST . $playlist_id;
return $this;
}

public function readAll()
{
if (empty($this->cache_name)) {
throw new \Error('Unable to read the cache due to missing cache name!');
}

$content = $this->cache_factory->read($this->cache_name);
return $content ? unserialize($content) : [];
}

public function read(string $unique_query_id)
{
if (empty($unique_query_id)) {
throw new \Error('Unable to read the cache due to missing cache name!');
}

$all = $this->readAll();

if (!isset($all[$unique_query_id])) {
return false;
}

return $all[$unique_query_id];
}

public function write($unique_query_id, $content)
{
if (empty($unique_query_id)) {
throw new \Error('Unable to write the cache data due to missing cache name!');
}

$all = $this->readAll();

$all[$unique_query_id] = $content;

$serialized_records = serialize($all);

return $this->cache_factory->write($this->cache_name, $serialized_records);
}

public function delete($unique_query_id)
{
if (empty($unique_query_id)) {
throw new \Error('Unable to expire the cache data due to missing cache name!');
}

$all = $this->readAll();

if (empty($all)) {
return true;
}

if (isset($all[$unique_query_id])) {
unset($all[$unique_query_id]);
}

if (empty($all)) {
$this->expire();
return true;
}

return $this->cache_factory->write($this->cache_name, serialize($all));
}

public function expire()
{
$this->cache_factory->expire($this->cache_name);
}

public static function expireAllVideoCaches(Videos $video)
{
$cache = \StudipCacheFactory::getCache();
if (!empty($video->perms)) {
foreach ($video->perms->pluck('user_id') as $user_id) {
$cache->expire(self::OC_CACHE_KEY_DOMAIN_USERS . $user_id);
}
}

if (!empty($video->playlists)) {
foreach ($video->playlists as $playlist) {
$cache->expire(self::OC_CACHE_KEY_DOMAIN_PLAYLIST . $playlist->id);

if (!empty($playlist->courses)) {
foreach ($playlist->courses as $course) {
$cache->expire(self::OC_CACHE_KEY_DOMAIN_COURSES . $course->id);
}
}
}
}

// We need to also look for root accounts!
$stmt = \DBManager::get()->prepare($q = "SELECT `user_id` FROM `auth_user_md5` WHERE `perms` = :perm");
$stmt->execute([
':perm' => 'root',
]);
$root_user_ids = $stmt->fetchAll(\PDO::FETCH_COLUMN);
foreach ($root_user_ids as $root_user_id) {
$cache->expire(self::OC_CACHE_KEY_DOMAIN_USERS . $root_user_id);
}
}
}
5 changes: 5 additions & 0 deletions lib/Models/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,9 @@ public function getTrashed()
{
return $this->trashed;
}

public function decodeVars()
{
return base64_encode(json_encode(get_object_vars($this)));
}
Comment on lines +109 to +113
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function decodeVars()
{
return base64_encode(json_encode(get_object_vars($this)));
}

}
3 changes: 3 additions & 0 deletions lib/Models/Playlists.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Opencast\Models\REST\ApiPlaylistsClient;
use Opencast\Helpers\PlaylistMigration;
use Opencast\Errors\Error;
use Opencast\Caching\VideosCaching;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use Opencast\Caching\VideosCaching;


class Playlists extends UPMap
{
Expand Down Expand Up @@ -575,6 +576,8 @@ public function delete()
$playlist_client->deletePlaylist($this->service_playlist_id);
}

(new VideosCaching())->playlistVideos($this->id)->expire();

Comment on lines +579 to +580
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(new VideosCaching())->playlistVideos($this->id)->expire();

return parent::delete();
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Models/ScheduledRecordings.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Opencast\Models;

use Opencast\Models\PlaylistSeminars;
use Opencast\Models\Video;
use Opencast\Models\Videos;

class ScheduledRecordings extends \SimpleORMap
{
Expand Down
34 changes: 33 additions & 1 deletion lib/Models/Videos.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Opencast\Models\REST\ApiWorkflowsClient;
use Opencast\Models\Helpers;
use Opencast\Models\ScheduledRecordings;
use Opencast\Caching\VideosCaching;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
use Opencast\Caching\VideosCaching;


class Videos extends UPMap
{
Expand Down Expand Up @@ -297,9 +298,14 @@ protected static function getFilteredVideos($query, $filters)
$course_ids = [];
$lecturer_ids = [];

$count_selected_columns = [
'id', 'token', 'config_id', 'created'
];

foreach ($filters->getFilters() as $filter) {
switch ($filter['type']) {
case 'text':
$count_selected_columns[] = 'title';
$pname = ':text' . sizeof($params);
$where .= " AND (title LIKE $pname OR description LIKE $pname)";
$params[$pname] = '%' . $filter['value'] .'%';
Expand Down Expand Up @@ -450,7 +456,11 @@ protected static function getFilteredVideos($query, $filters)

$sql .= ' GROUP BY oc_video.id';

$stmt = \DBManager::get()->prepare($s = "SELECT COUNT(*) FROM (SELECT oc_video.* FROM oc_video $sql) t");
// Preparing count sql, specifically define columns to select in order to increase performance.
$count_selected_columns = array_map(function($clmn) { return 'oc_video.' . $clmn; }, array_unique($count_selected_columns));
$count_select_columns_sql = implode(', ', $count_selected_columns);
$s = "SELECT COUNT(*) FROM (SELECT $count_select_columns_sql FROM oc_video $sql) t";
$stmt = \DBManager::get()->prepare($s);
$stmt->execute($params);
$count = $stmt->fetchColumn();

Expand Down Expand Up @@ -1273,4 +1283,26 @@ public static function addToCoursePlaylist($episode, $video)
}
}
}

/**
* @inheritDoc
*
* Overriding store method, in order to expire caches.
*/
public function store()
{
VideosCaching::expireAllVideoCaches($this);
return parent::store();
}

/**
* @inheritDoc
*
* Overriding delete method, in order to expire caches.
*/
public function delete()
{
VideosCaching::expireAllVideoCaches($this);
return parent::delete();
}
Comment on lines +1286 to +1307
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* @inheritDoc
*
* Overriding store method, in order to expire caches.
*/
public function store()
{
VideosCaching::expireAllVideoCaches($this);
return parent::store();
}
/**
* @inheritDoc
*
* Overriding delete method, in order to expire caches.
*/
public function delete()
{
VideosCaching::expireAllVideoCaches($this);
return parent::delete();
}

}
43 changes: 30 additions & 13 deletions lib/Routes/Course/CourseVideoList.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Opencast\OpencastController;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file need to be reverted

use Opencast\Models\Filter;
use Opencast\Models\Videos;
use Opencast\Caching\VideosCaching;

class CourseVideoList extends OpencastController
{
Expand All @@ -29,22 +30,38 @@ public function __invoke(Request $request, Response $response, $args)
throw new \AccessDeniedException();
}

// show videos for this course and filter them with optional additional filters
$videos = Videos::getCourseVideos($course_id, new Filter($params));
$response_result = [
'videos' => [],
'count' => 0,
];

$ret = [];
foreach ($videos['videos'] as $video) {
$video_array = $video->toSanitizedArray($params['cid']);
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write'))
{
$video_array['perms'] = $video->perms->toSanitizedArray();
$filter = new Filter($params);
$video_caching = new VideosCaching();
$course_videos_cache = $video_caching->courseVideos($course_id);
$unique_query_id = $filter->decodeVars();
$response_result = $course_videos_cache->read($unique_query_id);
if (empty($response_result)) {
// show videos for this course and filter them with optional additional filters
$videos = Videos::getCourseVideos($course_id, $filter);

$ret = [];
foreach ($videos['videos'] as $video) {
$video_array = $video->toSanitizedArray($params['cid']);
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write'))
{
$video_array['perms'] = $video->perms->toSanitizedArray();
}
$ret[] = $video_array;
}
$ret[] = $video_array;

$response_result = [
'videos' => $ret,
'count' => $videos['count'],
];

$course_videos_cache->write($unique_query_id, $response_result);
}

return $this->createResponse([
'videos' => $ret,
'count' => $videos['count'],
], $response);
return $this->createResponse($response_result, $response);
}
}
43 changes: 30 additions & 13 deletions lib/Routes/Playlist/PlaylistVideoList.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Opencast\Models\Playlists;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file need to be reverted

use Opencast\Models\Videos;
use Opencast\Models\PlaylistSeminarVideos;
use Opencast\Caching\VideosCaching;

class PlaylistVideoList extends OpencastController
{
Expand Down Expand Up @@ -49,22 +50,38 @@ public function __invoke(Request $request, Response $response, $args)
}
}

// show videos for this playlist and filter them with optional additional filters
$videos = Videos::getPlaylistVideos($playlist->id, new Filter($params));
$response_result = [
'videos' => [],
'count' => 0,
];

$ret = [];
foreach ($videos['videos'] as $video) {
$video_array = $video->toSanitizedArray($course_id, $playlist->id);
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write'))
{
$video_array['perms'] = $video->perms->toSanitizedArray();
$filter = new Filter($params);
$video_caching = new VideosCaching();
$playlist_videos_cache = $video_caching->playlistVideos($playlist->id);
$unique_query_id = $filter->decodeVars();
$response_result = $playlist_videos_cache->read($unique_query_id);
if (empty($response_result)) {
// show videos for this playlist and filter them with optional additional filters
$videos = Videos::getPlaylistVideos($playlist->id, $filter);

$ret = [];
foreach ($videos['videos'] as $video) {
$video_array = $video->toSanitizedArray($course_id, $playlist->id);
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write'))
{
$video_array['perms'] = $video->perms->toSanitizedArray();
}
$ret[] = $video_array;
}
$ret[] = $video_array;

$response_result = [
'videos' => $ret,
'count' => $videos['count'],
];

$playlist_videos_cache->write($unique_query_id, $response_result);
}

return $this->createResponse([
'videos' => $ret,
'count' => $videos['count']
], $response);
return $this->createResponse($response_result, $response);
}
}
Loading