This commit is contained in:
Dennis Eichhorn 2024-04-12 00:52:07 +00:00
parent a5ea656a26
commit 00b1c84163
19 changed files with 141 additions and 40 deletions

View File

@ -5,7 +5,7 @@
"type": 2,
"subtype": 1,
"name": "Media",
"uri": "{/base}/media/list?{?}",
"uri": "{/base}/media/list",
"target": "self",
"icon": null,
"order": 20,
@ -21,7 +21,7 @@
"type": 2,
"subtype": 2,
"name": "Media",
"uri": "{/base}/profile/view/media?{?}",
"uri": "{/base}/profile/view/media",
"target": "self",
"icon": null,
"order": 3,

View File

@ -22,6 +22,7 @@ return [
[
'dest' => '\Modules\Media\Controller\SearchController:searchGeneral',
'verb' => RouteVerb::ANY,
'active' => true,
'permission' => [
'module' => SearchController::NAME,
'type' => PermissionType::READ,
@ -33,6 +34,7 @@ return [
[
'dest' => '\Modules\Media\Controller\SearchController:searchTag',
'verb' => RouteVerb::ANY,
'active' => true,
'permission' => [
'module' => SearchController::NAME,
'type' => PermissionType::READ,

View File

@ -19,6 +19,7 @@ use Modules\Admin\Models\NullAccount;
use Modules\Media\Models\Collection;
use Modules\Media\Models\CollectionMapper;
use Modules\Media\Models\Media;
use Modules\Media\Models\MediaClass;
use Modules\Media\Models\MediaContent;
use Modules\Media\Models\MediaContentMapper;
use Modules\Media\Models\MediaMapper;
@ -154,7 +155,8 @@ final class ApiController extends Controller
pathSettings: $request->getDataInt('pathsettings') ?? PathSettings::RANDOM_PATH, // IMPORTANT!!!
hasAccountRelation: $request->getDataBool('link_account') ?? false,
readContent: $request->getDataBool('parse_content') ?? false,
unit: $request->getDataInt('unit')
unit: $request->getDataInt('unit'),
createCollection: $request->getDataBool('create_collection') ?? false,
);
$ids = [];
@ -317,11 +319,16 @@ final class ApiController extends Controller
int $pathSettings = PathSettings::RANDOM_PATH,
bool $hasAccountRelation = true,
bool $readContent = false,
?int $unit = null
) : array
?int $unit = null,
bool $createCollection = true,
?int $type = null,
?int $rel = null,
string $mapper = '',
string $field = ''
) : Collection
{
if (empty($files)) {
return [];
return new NullCollection();
}
$outputDir = '';
@ -333,11 +340,11 @@ final class ApiController extends Controller
$outputDir = \rtrim($basePath, '/\\');
$absolute = true;
} else {
return [];
return new NullCollection();
}
if (!Guard::isSafePath($outputDir, __DIR__ . '/../../../')) {
return [];
return new NullCollection();
}
$upload = new UploadFile();
@ -356,7 +363,7 @@ final class ApiController extends Controller
// Possible: name != filename (name = database media name, filename = name on the file system)
$stat['name'] = $sameLength ? $names[$nCounter] : $stat['filename'];
$created[] = self::createDbEntry(
$media = self::createDbEntry(
$stat,
$account,
$virtualPath,
@ -366,9 +373,34 @@ final class ApiController extends Controller
password: $password,
isEncrypted: !empty($encryptionKey)
);
// Create relation to type
if (!empty($type)) {
$this->createModelRelation($account, $media->id, $type, MediaMapper::class, 'types', '', '127.0.0.1');
}
// Create relation to model
if (!empty($rel)) {
$this->createModelRelation($account, $rel, $media->id, $mapper, $field, '', '127.0.0.1');
}
$created[] = $media;
}
return $created;
if (!$createCollection) {
$collection = new NullCollection();
$collection->sources = $created;
return $collection;
}
$collection = $this->createRecursiveMediaCollection($virtualPath, $account, $basePath);
foreach ($created as $media) {
$this->createModelRelation($account, $collection->id, $media->id, CollectionMapper::class, 'sources', '','127.0.0.1');
$collection->sources[] = $media;
}
return $collection;
}
/**
@ -975,11 +1007,19 @@ final class ApiController extends Controller
*/
public function createRecursiveMediaCollection(string $path, int $account, string $physicalPath = '') : Collection
{
$status = false;
$status = true;
if (!empty($physicalPath)) {
$status = \is_dir($physicalPath) ? true : \mkdir($physicalPath, 0755, true);
}
if (!$status) {
$this->app->logger?->error(\phpOMS\Log\FileLogger::MSG_FULL, [
'message' => 'Couldn\'t create directory "' . $physicalPath . '"',
'line' => __LINE__,
'file' => self::class,
]);
}
$virtualPath = \trim($path, '/');
$virtualPaths = \explode('/', $virtualPath);
$tempVirtualPaths = $virtualPaths;
@ -996,10 +1036,15 @@ final class ApiController extends Controller
$virtual = '/' . \implode('/', $tempVirtualPaths);
/** @var Collection $parentCollection */
$parentCollection = CollectionMapper::getParentCollection($virtual)->execute();
$parentCollection = CollectionMapper::get()
->where('virtualPath', \dirname($virtual))
->where('class', MediaClass::COLLECTION)
->where('name', \basename($virtual))
->limit(1)
->execute();
if ($parentCollection->id > 0) {
$real = $parentCollection->getPath();
$real = \rtrim($parentCollection->path, '/') . '/' . $parentCollection->name;
break;
}
@ -1012,10 +1057,10 @@ final class ApiController extends Controller
$childCollection = new Collection();
$childCollection->name = $virtualPaths[$i];
$childCollection->createdBy = new NullAccount($account);
$childCollection->setVirtualPath('/'. \ltrim($virtual, '/'));
$childCollection->setVirtualPath('/'. \trim($virtual, '/'));
// We assume that the new path is real path of the first found parent directory + the new virtual path
$childCollection->setPath(\rtrim($real, '/') . '/' . \ltrim($newVirtual, '/'));
$childCollection->setPath(\rtrim($real, '/') . '/' . \trim($newVirtual, '/'));
$this->createModel($account, $childCollection, CollectionMapper::class, 'collection', '127.0.0.1');
$this->createModelRelation(
@ -1035,6 +1080,53 @@ final class ApiController extends Controller
return $parentCollection;
}
public function addMediaToCollectionAndModel(
int $account,
array $files,
?int $rel = null, string $mapper = '', string $field = '',
string $collectionPath = ''
) : void
{
$mediaFiles = MediaMapper::getAll()->where('id', $files)->executeGetArray();
$collection = null;
foreach ($mediaFiles as $media) {
if ($rel !== null) {
$this->createModelRelation($account, $rel, $media->id, $mapper, $field, '', '127.0.0.1');
}
if (!empty($addToCollection)) {
$ref = new Reference();
$ref->name = $media->name;
$ref->source = new NullMedia($media->id);
$ref->createdBy = new NullAccount($account);
$ref->setVirtualPath($collectionPath);
$this->createModel($account, $ref, ReferenceMapper::class, 'media_reference', '127.0.0.1');
if ($collection === null) {
/** @var \Modules\Media\Models\Collection $collection */
$collection = CollectionMapper::get()
->where('virtualPath', \dirname($collectionPath))
->where('class', MediaClass::COLLECTION)
->where('name', \basename($collectionPath))
->limit(1)
->execute();
if ($collection->id === 0) {
$collection = $this->app->moduleManager->get('Media', 'Api')->createRecursiveMediaCollection(
$collectionPath,
$account,
__DIR__ . '/../../../Modules/Media/Files' . $collectionPath
);
}
}
$this->createModelRelation($account, $collection->id, $ref->id, CollectionMapper::class, 'sources', '', '127.0.0.1');
}
}
}
/**
* Api method to create media file.
*

View File

@ -94,10 +94,12 @@ final class BackendController extends Controller
}
/** @var Media[] $media */
$media = $mediaMapper->execute();
$media = $mediaMapper->executeGetArray();
$collectionMapper = CollectionMapper::getParentCollection($path)
->where('tags/title/language', $request->header->l11n->language);
$collectionMapper = CollectionMapper::getAll()
->where('virtualPath', \dirname($path))
->where('class', MediaClass::COLLECTION)
->where('name', \basename($path));
if (!$hasPermission) {
$permWhere = PermissionAbstractMapper::helper($this->app->dbPool->get('select'))

View File

@ -369,7 +369,7 @@ class Media implements \JsonSerializable
*/
public function setPath(string $path) : void
{
$this->path = \strtr($path, '\\', '/');
$this->path = \rtrim(\strtr($path, '\\', '/'), '/');
}
/**
@ -381,7 +381,10 @@ class Media implements \JsonSerializable
*/
public function setVirtualPath(string $path) : void
{
$this->virtualPath = \strtr($path, '\\', '/');
$this->virtualPath = \rtrim(\strtr($path, '\\', '/'), '/');
if ($this->virtualPath === '') {
$this->virtualPath = '/';
}
}
/**

View File

@ -155,11 +155,11 @@ class MediaMapper extends DataMapperFactory
* and in fact most of the time it is different. This is because the location on a hard drive or web
* drive should not have any impact on the media file/media structure in the application.
*
* As a result media files are structured by virutal path in the app, by file path on the file system
* As a result media files are structured by virtual path in the app, by file path on the file system
* and by Collections which can have sub-collections as well. Collections allow to reference files
* in a different virtual path and are therfore similar to "symlinks", except that they don't reference
* in a different virtual path and are therefore similar to "symlinks", except that they don't reference
* a file but create a new virtual media model which groups other media models together in a new virtual
* path if so desired without deleting or moving the orginal media files.
* path if so desired without deleting or moving the original media files.
*
* @param string $virtualPath Virtual path
* @param int $status Media status

View File

@ -18,7 +18,7 @@ use phpOMS\Uri\UriFactory;
<section id="mediaFile" class="portlet">
<div class="portlet-body">
<audio width="100%" controls>
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id); ?>" type="audio/<?= $this->media->extension; ?>">
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'); ?>" type="audio/<?= $this->media->extension; ?>">
Your browser does not support HTML audio.
</audio>
</div>

View File

@ -18,6 +18,6 @@ use phpOMS\Uri\UriFactory;
<!DOCTYPE html>
<style>html, body, iframe { margin: 0; padding: 0; border: 0; }</style>
<audio width="100%" controls>
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id); ?>" type="audio/<?= $this->media->extension; ?>">
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'); ?>" type="audio/<?= $this->media->extension; ?>">
Your browser does not support HTML audio.
</audio>

View File

@ -28,8 +28,8 @@ use phpOMS\Uri\UriFactory;
<input type="radio" id="media-c-tab-1" name="tabular-1" checked>
<div class="x-overflow cT">
<img alt="<?= $this->printHtml($this->media->name); ?>" style="max-width: 100%; max-height: 100%; align-self: center;" src="<?= $this->media->id !== 0
? UriFactory::build('{/api}media/export?id=' . $this->media->id)
: UriFactory::build('{/api}media/export?path=' . \urlencode($this->media->getPath()));
? UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}')
: UriFactory::build('{/api}media/export?path=' . \urlencode($this->media->getPath()) . '&csrf={$CSRF}');
?>">
</div>
<?php if (!empty($this->media->content->content)) : ?>

View File

@ -18,6 +18,6 @@ use phpOMS\Uri\UriFactory;
<!DOCTYPE html>
<style>html, body, iframe { margin: 0; padding: 0; border: 0; }</style>
<img alt="<?= $this->printHtml($this->media->name); ?>" style="max-width: 100%" src="<?= $this->media->id !== 0
? UriFactory::build('{/api}media/export?id=' . $this->media->id)
: UriFactory::build('{/api}media/export?path=' . \urlencode($this->media->getPath()));
? UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}')
: UriFactory::build('{/api}media/export?path=' . \urlencode($this->media->getPath()) . '&csrf={$CSRF}');
?>">

View File

@ -26,7 +26,7 @@ use \phpOMS\Uri\UriFactory;
<div class="tab-content col-simple">
<input type="radio" id="media-c-tab-1" name="tabular-1" checked>
<div class="tab col-simple">
<iframe class="col-simple" id="iHelperFrame" src="<?= UriFactory::build('Resources/mozilla/Pdf/web/viewer.html?file=' . \urlencode(UriFactory::build('{/api}media/export?id=' . $this->media->id))); ?>" allowfullscreen></iframe>
<iframe class="col-simple" id="iHelperFrame" src="<?= UriFactory::build('Resources/mozilla/Pdf/web/viewer.html?file=' . \urlencode(UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'))); ?>" allowfullscreen></iframe>
</div>
<input type="radio" id="media-c-tab-2" name="tabular-1">
<div class="tab">

View File

@ -25,7 +25,7 @@ use \phpOMS\Uri\UriFactory;
src="<?= UriFactory::build(
'/Resources/mozilla/Pdf/web/viewer.html?file='
. ($this->media->id === 0
? \urlencode(UriFactory::build('{/api}media/export?path=' . $this->media->getPath()))
: \urlencode(UriFactory::build('{/api}media/export?id=' . $this->media->id)
? \urlencode(UriFactory::build('{/api}media/export?path=' . $this->media->getPath()) . '&csrf={$CSRF}')
: \urlencode(UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}')
)));
?>" allowfullscreen></iframe>

View File

@ -29,7 +29,7 @@ Autoloader::addPath(__DIR__ . '/../../../../../../Resources/');
<div class="tab-content col-simple">
<input type="radio" id="media-c-tab-1" name="tabular-1" checked>
<div class="tab col-simple">
<iframe class="col-simple" src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id); ?>&type=html"></iframe>
<iframe class="col-simple" src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'); ?>&type=html"></iframe>
</div>
<input type="radio" id="media-c-tab-2" name="tabular-1" checked>
<div class="tab col-simple">

View File

@ -18,7 +18,7 @@ use phpOMS\Uri\UriFactory;
<section id="mediaFile" class="portlet">
<div class="portlet-body">
<video width="100%" controls>
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id); ?>" type="video/<?= $this->media->extension; ?>">
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'); ?>" type="video/<?= $this->media->extension; ?>">
Your browser does not support HTML video.
</video>
</div>

View File

@ -18,6 +18,6 @@ use phpOMS\Uri\UriFactory;
<!DOCTYPE html>
<style>html, body, iframe { margin: 0; padding: 0; border: 0; }</style>
<video width="100%" controls>
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id); ?>" type="video/<?= $this->media->extension; ?>">
<source src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'); ?>" type="video/<?= $this->media->extension; ?>">
Your browser does not support HTML video.
</video>

View File

@ -17,6 +17,6 @@ use phpOMS\Uri\UriFactory;
?>
<section id="mediaFile" class="portlet col-simple">
<div class="portlet-body col-simple">
<iframe class="col-simple" src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id); ?>&type=html"></iframe>
<iframe class="col-simple" src="<?= UriFactory::build('{/api}media/export?id=' . $this->media->id . '&csrf={$CSRF}'); ?>&type=html"></iframe>
</div>
</section>

View File

@ -76,7 +76,7 @@ use phpOMS\Uri\UriFactory;
<tbody
id="iMediaInput-tags"
class="tags"
data-action='[{"listener": "change", "action": [{"key": 1, "type": "dom.set", "selector": "#iMediaFile", "value": "<?= UriFactory::build('{/api}media/export') . '?id={!#iFiles [name=media_file]:checked}&type=html'; ?>"}]}]'
data-action='[{"listener": "change", "action": [{"key": 1, "type": "dom.set", "selector": "#iMediaFile", "value": "<?= UriFactory::build('{/api}media/export?csrf={$CSRF}') . '&id={!#iFiles [name=media_file]:checked}&type=html'; ?>"}]}]'
data-limit="0"
data-active="true"
data-form="<?= $this->form; ?>"
@ -116,7 +116,7 @@ use phpOMS\Uri\UriFactory;
<section id="mediaFile" class="portlet col-simple">
<div class="portlet-body col-simple">
<?php if (!empty($this->files)) : ?>
<iframe class="col-simple" id="iMediaFile" data-src="<?= UriFactory::build('{/api}media/export') . '?id={!#iFiles [name=media_file]:checked}&type=html'; ?>" allowfullscreen></iframe>
<iframe class="col-simple" id="iMediaFile" data-src="<?= UriFactory::build('{/api}media/export?csrf={$CSRF}') . '&id={!#iFiles [name=media_file]:checked}&type=html'; ?>" allowfullscreen></iframe>
<?php else : ?>
<img width="100%" src="Web/Backend/img/logo_grey.png">
<?php endif; ?>

View File

@ -209,6 +209,7 @@ $next = empty($media) ? '{/base}/media/list' : '{/base}/media/list?{?}&offse
<td data-label="<?= $this->getHtml('Name'); ?>">
<a href="<?= $url; ?>"><?= $this->printHtml($value->name); ?></a>
<td data-label="<?= $this->getHtml('Tag'); ?>">
<div class="tag-list">
<?php foreach ($value->tags as $tag) : ?>
<a href="<?= $url; ?>">
<span class="tag" style="background: <?= $this->printHtml($tag->color); ?>">
@ -217,6 +218,7 @@ $next = empty($media) ? '{/base}/media/list' : '{/base}/media/list?{?}&offse
</span>
</a>
<?php endforeach; ?>
</div>
<td data-label="<?= $this->getHtml('Extension'); ?>">
<a href="<?= $url; ?>"><?= $this->printHtml($value->extension); ?></a>
<td data-label="<?= $this->getHtml('Size'); ?>"><a href="<?= $url; ?>"><?php
@ -240,7 +242,7 @@ $next = empty($media) ? '{/base}/media/list' : '{/base}/media/list?{?}&offse
<div class="portlet-foot">
<a tabindex="0" class="button" href="<?= UriFactory::build($previous); ?>"><?= $this->getHtml('Previous', '0', '0'); ?></a>
<a tabindex="0" class="button" href="<?= UriFactory::build($next); ?>"><?= $this->getHtml('Next', '0', '0'); ?></a>
<a tabindex="0" class="button rf" href="<?= UriFactory::build('{/api}media/export?path={?path}&type=download'); ?>">
<a tabindex="0" class="button rf" href="<?= UriFactory::build('{/api}media/export?path={?path}&csrf={$CSRF}&type=download'); ?>">
<?= $this->getHtml('Download'); ?>
</a>
</div>

View File

@ -121,7 +121,7 @@ echo $this->data['nav']->render();
data-uri="<?= UriFactory::build('{/api}media?{?}&csrf={$CSRF}'); ?>">
<a tabindex="0"
class="button"
href="<?= UriFactory::build('{/api}media/export?id=' . $media->id . '&type=download'); ?>"
href="<?= UriFactory::build('{/api}media/export?id=' . $media->id . '&csrf={$CSRF}&type=download'); ?>"
><?= $this->getHtml('Download'); ?></a>
<?php
$path = $this->filePathFunction($media, $this->request->getData('sub') ?? '');