Skip to content

Commit

Permalink
Allow downloading of media files (#1141)
Browse files Browse the repository at this point in the history
* allow removing of videos from playlist which are not present in opencast

* fixes #816

* fixes #816

* update package lock

* fixes #1083

* only log errors
  • Loading branch information
tgloeggl authored Jan 28, 2025
1 parent 0a69190 commit 074f5f6
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 22 deletions.
7 changes: 6 additions & 1 deletion OpencastV3.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,9 @@ public function perform($unconsumed_path)

if (substr($unconsumed_path, 0, 3) == 'api') {
// make sure, slim knows if we are running https, see https://github.com/elan-ev/studip-opencast-plugin/issues/816
if (strpos($GLOBALS['ABSOLUTE_URI_STUDIP'], 'https') === 0) {
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = 443;
}

$appFactory = new AppFactory();
Expand All @@ -315,6 +316,10 @@ public function perform($unconsumed_path)

$app->run();
} else {
if (!empty($GLOBALS['ABSOLUTE_URI_STUDIP'])) {
URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']);
}

$css = VersionHelper::get()->getVersionSpecificStylesheet();

if ($css) {
Expand Down
32 changes: 32 additions & 0 deletions app/controllers/redirect.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,38 @@ public function perform_action($action, $token)
$this->set_layout(null);
}

public function download_action($token, $type, $index)
{
$video = null;
$video = Videos::findByToken($token);

if (empty($video)) {
$this->error = _('Das Video wurde nicht gefunden, ist defekt oder momentan (noch) nicht verfügbar.');
} else if ($video->trashed) {
$this->error = _('Das Video wurde zur Löschung markiert und kann daher nicht abgerufen werden.');
}

$perm = $video->getUserPerm();

if ($perm) {

$publication = $video->publication? json_decode($video->publication, true) : null;
if (!empty($publication) && isset($publication['downloads'][$type][$index]['url'])) {
$url = $publication['downloads'][$type][$index]['url'];

$api_events = ApiEventsClient::getInstance($video->config_id);
$response = $api_events->fileRequest($url);

header('Content-Type: '. $response['mimetype']);

echo $response['body'];
die;
}
}

throw new \AccessDeniedException();
}

/**
* Directly redirect to passed LTI endpoint
*
Expand Down
14 changes: 10 additions & 4 deletions lib/Models/Videos.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ public function getUserPerm($user_id = null)
}

// check if user has permission on this video due to course ownership
if ($this->haveCoursePerm('dozent')) {
if ($this->haveCoursePerm('dozent', $user_id)) {
return 'owner';
}

Expand All @@ -574,7 +574,7 @@ public function getUserPerm($user_id = null)

if (!$ret_perm) {
// check if at least read perms are present due to course participation
if ($this->haveCoursePerm('user')) {
if ($this->haveCoursePerm('user', $user_id)) {
return 'read';
}
}
Expand All @@ -585,13 +585,19 @@ public function getUserPerm($user_id = null)
/**
* Check if current user has permission for a course of this video
*/
public function haveCoursePerm(string $perm)
public function haveCoursePerm(string $course_perm, string $user_id = null)
{
global $user, $perm;

if (!$user_id) {
$user_id = $user->id;
}

$video_courses = PlaylistSeminars::getCoursesOfVideo($this);

if (!empty($video_courses)) {
foreach ($video_courses as $video_course_id) {
if ($GLOBALS['perm']->have_studip_perm($perm, $video_course_id)) {
if ($perm->have_studip_perm($course_perm, $video_course_id, $user_id)) {
return true;
}
}
Expand Down
6 changes: 3 additions & 3 deletions lib/Routes/Playlist/PlaylistRemoveVideos.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ public function __invoke(Request $request, Response $response, $args)
$playlist_client = ApiPlaylistsClient::getInstance($playlist->config_id);
$oc_playlist = $playlist_client->getPlaylist($playlist->service_playlist_id);

$old_entries = $oc_playlist->entries;
$entries = $oc_playlist->entries;
$old_entries = (array)$oc_playlist->entries;
$entries = (array)$oc_playlist->entries;

foreach ($videos as $video) {
if (!Authority::canAddVideoToPlaylist($user, $playlist, $video, $course_id)) {
Expand Down Expand Up @@ -82,7 +82,7 @@ public function __invoke(Request $request, Response $response, $args)
}

// Update playlist videos in DB
$playlist->setEntries($oc_playlist->entries);
$playlist->setEntries((array)$oc_playlist->entries);

return $response->withStatus(204);
}
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vueapp/components/Videos/Actions/CaptionUpload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export default {
},
annotation_tool_link() {
let redirectUrl = window.OpencastPlugin.REDIRECT_URL;
let redirectUrl = window.OpencastPlugin.REDIRECT_URL + '/perform';
let action = '/annotation/' + this.event.token;
if (redirectUrl && this.event.publication.annotation_tool) {
Expand Down
1 change: 0 additions & 1 deletion vueapp/components/Videos/Actions/VideoAccess.vue
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,6 @@ export default {
if (data.message.type == 'success') {
event.visibility = vis;
}
console.log('visibility', event.visibility);
view.$store.dispatch('addMessage', data.message);
view.processing = false;
})
Expand Down
2 changes: 1 addition & 1 deletion vueapp/components/Videos/Actions/VideoCut.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default {
methods: {
openEditor() {
let redirectUrl = window.OpencastPlugin.REDIRECT_URL + '/editor/' + this.event.token;
let redirectUrl = window.OpencastPlugin.REDIRECT_URL + '/perform/editor/' + this.event.token;
window.open(redirectUrl, '_blank');
this.$emit('done');
},
Expand Down
12 changes: 6 additions & 6 deletions vueapp/components/Videos/Actions/VideoDownload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
ReferentIn
</h2>
<a v-for="(media, index) in presenters" :key="index">
<StudipButton @click.prevent="downloadFile(media)">
<StudipButton @click.prevent="downloadFile(media, 'presenter', media.size)">
{{ getMediaText(media) }}
</StudipButton>

Expand Down Expand Up @@ -42,7 +42,7 @@
Bildschirm
</h2>
<a v-for="(media, index) in presentations" :key="index">
<StudipButton @click.prevent="downloadFile(media)">
<StudipButton @click.prevent="downloadFile(media, 'presentation', media.size)">
{{ getMediaText(media) }}
</StudipButton>

Expand Down Expand Up @@ -97,10 +97,10 @@ export default {
},
methods: {
async downloadFile(media) {
axios.get(media.url, {
crossDomain: true,
withCredentials: true,
async downloadFile(media, type, index) {
let url = window.OpencastPlugin.REDIRECT_URL + '/download/' + this.event.token + '/' + type + '/' + index;
axios.get(url, {
responseType: 'blob'
}).then(response => {
const blob = new Blob([response.data]);
Expand Down
2 changes: 1 addition & 1 deletion vueapp/components/Videos/VideosTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ export default {
},
redirectAction(action) {
let redirectUrl = window.OpencastPlugin.REDIRECT_URL;
let redirectUrl = window.OpencastPlugin.REDIRECT_URL + '/perform';
if (redirectUrl) {
redirectUrl = redirectUrl + action;
Expand Down
1 change: 0 additions & 1 deletion vueapp/store/playlists.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ const actions = {
* @param data.videos list of video tokens to remove
*/
async removeVideosFromPlaylist(context, data) {
console.log('removeVideosFromPlaylist', data);
return ApiService.patch('/playlists/' + data.playlist + '/videos', data)
.then(() => {
context.commit('addToVideosCount', {'token': data.playlist, 'addToCount': -data.videos.removedCount});
Expand Down
2 changes: 1 addition & 1 deletion vueapp/templates/admin_index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
ICON_URL : '<?= Assets::url('images/icons/') ?>',
ASSETS_URL : '<?= Assets::url('') ?>',
ROUTE : 'admin',
REDIRECT_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect/perform', true) ?>',
REDIRECT_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect', true) ?>',
AUTH_URL : '<?= PluginEngine::getURL('opencastv3', [], 'redirect/authenticate', true) ?>'
};
<?= isset($languages) ? "window.OpencastPlugin.STUDIP_LANGUAGES = $languages;" : '' ?>;
Expand Down
2 changes: 1 addition & 1 deletion vueapp/templates/contents_index.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
ASSETS_URL : '<?= Assets::url('') ?>',
PLUGIN_ASSET_URL : '<?= $plugin->getAssetsUrl() ?>',
ROUTE : 'videos',
REDIRECT_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect/perform') ?>',
REDIRECT_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect') ?>',
AUTH_URL : '<?= PluginEngine::getURL('opencastv3', [], 'redirect/authenticate') ?>'
};
<?= isset($languages) ? "window.OpencastPlugin.STUDIP_LANGUAGES = $languages;" : '' ?>;
Expand Down
2 changes: 1 addition & 1 deletion vueapp/templates/course_index.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
ASSETS_URL : '<?= Assets::url('') ?>',
PLUGIN_ASSET_URL : '<?= $plugin->getAssetsUrl() ?>',
ROUTE : 'course',
REDIRECT_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect/perform', true) ?>',
REDIRECT_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect', true) ?>',
AUTH_URL: '<?= PluginEngine::getURL('opencastv3', [], 'redirect/authenticate', true) ?>'
};
<?= isset($languages) ? "window.OpencastPlugin.STUDIP_LANGUAGES = $languages;" : '' ?>;
Expand Down

0 comments on commit 074f5f6

Please sign in to comment.