diff --git a/Admin/Installer.php b/Admin/Installer.php index 787c545..94cba81 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -85,7 +85,7 @@ final class Installer extends InstallerAbstract $collection = new Collection(); $collection->setName((string) $data['name'] ?? ''); $collection->setVirtualPath((string) $data['virtualPath'] ?? '/'); - $collection->setPath((string) $data['virtualPath'] ?? '/'); + $collection->setPath((string) ($data['path'] ?? '/Modules/Media/Files/' . ((string) $data['name'] ?? ''))); $collection->setCreatedBy(new NullAccount((int) $data['user'] ?? 1)); CollectionMapper::create($collection); diff --git a/Admin/Routes/Web/Api.php b/Admin/Routes/Web/Api.php index e5e3344..74c60aa 100755 --- a/Admin/Routes/Web/Api.php +++ b/Admin/Routes/Web/Api.php @@ -37,6 +37,17 @@ return [ ], ], ], + '^.*/media/collection(\?+.*|$)' => [ + [ + 'dest' => '\Modules\Media\Controller\ApiController:apiCollectionCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::MODULE_NAME, + 'type' => PermissionType::CREATE, + 'state' => PermissionState::MEDIA, + ], + ], + ], '^.*/media/find.*$' => [ [ 'dest' => '\Modules\Media\Controller\ApiController:apiMediaFind', diff --git a/Controller/ApiController.php b/Controller/ApiController.php index 5faac8f..ece1222 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -114,7 +114,7 @@ final class ApiController extends Controller $request->getData('name') === null || $request->getFiles() !== null ? '' : $request->getData('name'), $request->getFiles(), $request->getHeader()->getAccount(), - (string) ($request->getData('path') ?? __DIR__ . '/../../../Modules/Media/Files'), + __DIR__ . '/../../../Modules/Media/Files' . ((string) ($request->getData('path') ?? '')), (string) ($request->getData('virtualPath') ?? ''), (string) ($request->getData('password') ?? ''), (string) ($request->getData('encrypt') ?? ''), @@ -152,7 +152,7 @@ final class ApiController extends Controller string $name, array $files, int $account, - string $basePath = 'Modules/Media/Files', + string $basePath = '/Modules/Media/Files', string $virtualPath = '', string $password = '', string $encryptionKey = '', @@ -286,7 +286,7 @@ final class ApiController extends Controller return \str_replace('\\', '/', \str_replace($realpath, '', - \rtrim($path, '/') + \rtrim($path, '\\/') ) ); } @@ -327,14 +327,32 @@ final class ApiController extends Controller */ private function updateMediaFromRequest(RequestAbstract $request) : Media { + $id = (int) $request->getData('id'); + /** @var Media $media */ - $media = MediaMapper::get((int) $request->getData('id')); + $media = MediaMapper::get($id); $media->setName((string) ($request->getData('name') ?? $media->getName())); $media->setVirtualPath(\urldecode((string) ($request->getData('virtualpath') ?? $media->getVirtualPath()))); + if ($id == 0) { + $path = \urldecode($request->getData('path')); + + if ($media instanceof NullMedia + && \is_file(__DIR__ . '/../Files' . $path) + ) { + $name = \explode('.', \basename($path)); + + $media->setName($name[0]); + $media->setExtension($name[1] ?? ''); + $media->setVirtualPath(\dirname($path)); + $media->setPath('/Modules/Media/Files/' . \ltrim($path, '\\/')); + $media->setAbsolute(false); + } + } + if ($request->getData('content') !== null) { \file_put_contents( - $media->isAbsolute() ? $media->getPath() : __DIR__ . '/../../../' . \ltrim($media->getPath(), '/'), + $media->isAbsolute() ? $media->getPath() : __DIR__ . '/../../../' . \ltrim($media->getPath(), '\\/'), $request->getData('content') ); @@ -382,9 +400,7 @@ final class ApiController extends Controller private function validateCollectionCreate(RequestAbstract $request) : array { $val = []; - if (($val['name'] = empty($request->getData('name'))) - || ($val['media'] = empty($request->getDataJson('media-list'))) - ) { + if (($val['name'] = empty($request->getData('name')))) { return $val; } @@ -413,8 +429,20 @@ final class ApiController extends Controller $mediaCollection->addSource(new NullMedia((int) $file)); } - $mediaCollection->setVirtualPath($request->getData('virtualpath') ?? '/'); - $mediaCollection->setPath($request->getData('virtualpath') ?? '/'); + $virtualPath = \urldecode((string) ($request->getData('virtualpath') ?? '/')); + + $outputDir = ''; + if (empty($request->getData('path'))) { + $outputDir = self::createMediaPath(__DIR__ . '/../../../Modules/Media/Files'); + } else { + $outputDir = __DIR__ . '/../../../Modules/Media/Files/' . \ltrim($request->getData('path'), '\\/'); + Directory::create($outputDir . '/' . $request->getData('name'), 0775, true); + } + + $outputDir = \substr($outputDir, \strlen(__DIR__ . '/../../..')); + + $mediaCollection->setVirtualPath($virtualPath); + $mediaCollection->setPath($outputDir); CollectionMapper::create($mediaCollection); @@ -453,10 +481,8 @@ final class ApiController extends Controller $mediaCollection->setDescriptionRaw($description); $mediaCollection->setCreatedBy(new NullAccount($account)); $mediaCollection->setSources($media); - $mediaCollection->setVirtualPath('/Modules/Helper'); - $mediaCollection->setPath('/Modules/Helper'); - - CollectionMapper::create($mediaCollection); + $mediaCollection->setVirtualPath('/'); + $mediaCollection->setPath('/Modules/Media/Files'); return $mediaCollection; } @@ -476,23 +502,28 @@ final class ApiController extends Controller */ public function apiMediaCreate(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { - $virtualPath = \urldecode((string) ($request->getData('path') ?? '')); + $path = \urldecode((string) ($request->getData('path') ?? '')); + $virtualPath = \urldecode((string) ($request->getData('virtualpath') ?? '')); $fileName = (string) ($request->getData('fileName') ?? ($request->getData('name') ?? '')); $fileName .= \strripos($fileName, '.') === false ? '.txt' : ''; - $pathSettings = (int) ($request->getData('pathsettings') ?? PathSettings::RANDOM_PATH); $outputDir = ''; - if ($pathSettings === PathSettings::RANDOM_PATH) { + if (empty($request->getData('path'))) { $outputDir = self::createMediaPath(__DIR__ . '/../../../Modules/Media/Files'); - } elseif ($pathSettings === PathSettings::FILE_PATH) { - $outputDir = __DIR__ . '/../../../Modules/Media/Files/' . \ltrim($virtualPath, '\\/'); + } else { + $outputDir = __DIR__ . '/../../../Modules/Media/Files/' . \ltrim($path, '\\/'); } if (!\is_dir($outputDir)) { - Directory::create($outputDir, 0755, true); + $created = Directory::create($outputDir, 0775, true); + + if (!$created) { + throw new \Exception('Couldn\'t create outputdir: "' . $outputDir . '"'); + } } \file_put_contents($outputDir . '/' . $fileName, (string) ($request->getData('content') ?? '')); + $outputDir = \substr($outputDir, \strlen(__DIR__ . '/../../..')); $status = [ [ diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 04d77bc..de85207 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -19,6 +19,7 @@ use Modules\Media\Models\Collection; use Modules\Media\Models\CollectionMapper; use Modules\Media\Models\Media; use Modules\Media\Models\MediaMapper; +use Modules\Media\Models\NullMedia; use Modules\Media\Views\MediaView; use phpOMS\Asset\AssetType; use phpOMS\Contract\RenderableInterface; @@ -130,16 +131,32 @@ final class BackendController extends Controller $media = MediaMapper::getByVirtualPath($path); $collection = CollectionMapper::getParentCollection(\str_replace('+', ' ', $path)); + + if (\is_array($collection) && \is_dir(__DIR__ . '/../Files' . $path)) { + $collection = new Collection(); + $collection->setName(\basename($path)); + $collection->setVirtualPath(\dirname($path)); + $collection->setPath(\dirname($path)); + $collection->setAbsolute(false); + } + if ($collection instanceof Collection) { $media += $collection->getSources(); /** @var string[] $glob */ - $glob = \glob(__DIR__ . '/../Files' . \trim($collection->getPath(), '/') . '/' . $collection->getName() . '/*'); + $glob = $collection->isAbsolute() + ? $collection->getPath() . '/' . $collection->getName() . '/*' + : \glob(__DIR__ . '/../Files' . '/' . \rtrim($collection->getPath(), '/') . '/' . $collection->getName() . '/*'); $glob = $glob === false ? [] : $glob; foreach ($glob as $file) { foreach ($media as $obj) { - if ($obj->getName() . '.' . $obj->getExtension() === \basename($file)) { + if (($obj->getExtension() !== 'collection' + && !empty($obj->getExtension()) + && $obj->getName() . '.' . $obj->getExtension() === \basename($file)) + || ($obj->getExtension() === 'collection' + && $obj->getName() === \basename($file)) + ) { continue 2; } } @@ -148,7 +165,8 @@ final class BackendController extends Controller $localMedia = new Media(); $localMedia->setName($pathinfo['filename']); - $localMedia->setExtension($pathinfo['extension'] ?? ''); + $localMedia->setExtension(\is_dir($file) ? 'collection' : $pathinfo['extension'] ?? ''); + $localMedia->setVirtualPath($path); $localMedia->setCreatedBy(new Account()); $media[] = $localMedia; @@ -179,10 +197,10 @@ final class BackendController extends Controller $view->setTemplate('/Modules/Media/Theme/Backend/media-single'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1000401001, $request, $response)); - $media = MediaMapper::get((int) $request->getData('id')); + $id = (int) $request->getData('id'); + $media = MediaMapper::get($id); if ($media->getExtension() === 'collection') { - //$media = CollectionMapper::get($media->getId()); $media = MediaMapper::getByVirtualPath( $media->getVirtualPath() . ($media->getVirtualPath() !== '/' ? '/' : '') . $media->getName() ); @@ -194,6 +212,22 @@ final class BackendController extends Controller $view->setTemplate('/Modules/Media/Theme/Backend/media-list'); } + if ($id == 0) { + $path = \urldecode($request->getData('path')); + + if ($media instanceof NullMedia + && \is_file(__DIR__ . '/../Files' . $path) + ) { + $name = \explode('.', \basename($path)); + + $media->setName($name[0]); + $media->setExtension($name[1] ?? ''); + $media->setVirtualPath(\dirname($path)); + $media->setPath('/Modules/Media/Files/' . \ltrim($path, '\\/')); + $media->setAbsolute(false); + } + } + $view->addData('media', $media); return $view; diff --git a/Docs/Dev/en/SUMMARY.md b/Docs/Dev/en/SUMMARY.md new file mode 100644 index 0000000..6329860 --- /dev/null +++ b/Docs/Dev/en/SUMMARY.md @@ -0,0 +1,4 @@ +# Developer Content + +* [Media]({%}&page=Dev/media) +* [Collection]({%}&page=Dev/collection) diff --git a/Docs/Dev/en/collection.md b/Docs/Dev/en/collection.md new file mode 100644 index 0000000..7fec1f9 --- /dev/null +++ b/Docs/Dev/en/collection.md @@ -0,0 +1,7 @@ +# Collection + +A collection is a special `Media` element similar to directories. A collection can contain other collections, media elements and hard drive files & directories. + +If a directory on the hard drive has the same path as the virtual path of the colllection, all files in that directory are also shown as part of that collection. If the content of the hard drive directory changes the colllection also shows the changed content. + +A collection doesn't need to have a hard drive directory, this is optional. diff --git a/Docs/Dev/en/media.md b/Docs/Dev/en/media.md new file mode 100644 index 0000000..5d09f8a --- /dev/null +++ b/Docs/Dev/en/media.md @@ -0,0 +1,24 @@ +# Media + +A media element is used in order to handle files, directories, virtual directories and other resources (e.g. links, external resource such as dropbox etc.). + +## Path + +### File system + +The path is either the absolute path on the file system or relative path in relation to applications path. If the path is an absolute path the media element also needs to be set to `isAbsolute() === true`. The path includes the file itself. + +## Virtual Path + +The virtual path is the virtual location where it should show up in the media module. This makes it possible to change the visual location without changing the physical storage location. Additionally, this makes it also possible to reference the same physical file from different locations. Think about it similar to `symlink` + +## Absolute + +Is the file path an absolute file path or a relative file path (relative to the application path). + +## Extensions + +The extension can be one of the following two: + +1. Extension of the file +2. `collection` if it is a virtual directory/collection \ No newline at end of file diff --git a/Docs/Help/en/SUMMARY.md b/Docs/Help/en/SUMMARY.md new file mode 100644 index 0000000..4b927b3 --- /dev/null +++ b/Docs/Help/en/SUMMARY.md @@ -0,0 +1,3 @@ +# Developer Content + +* [Templates]({%}&page=Dev/api_template) diff --git a/Docs/introduction.md b/Docs/Help/en/introduction.md similarity index 100% rename from Docs/introduction.md rename to Docs/Help/en/introduction.md diff --git a/Models/Media.php b/Models/Media.php index 9c1f90a..706027b 100755 --- a/Models/Media.php +++ b/Models/Media.php @@ -156,6 +156,8 @@ class Media implements \JsonSerializable { $this->createdBy = new NullAccount(); $this->createdAt = new \DateTime(); + + $this->setExtension('colection'); } /** @@ -337,7 +339,7 @@ class Media implements \JsonSerializable */ public function getPath() : string { - return $this->isAbsolute ? $this->path : \ltrim($this->path, '/'); + return $this->isAbsolute ? $this->path : \ltrim($this->path, '\\/'); } /** diff --git a/Theme/Backend/Lang/de.lang.php b/Theme/Backend/Lang/de.lang.php index 547f82e..db10801 100755 --- a/Theme/Backend/Lang/de.lang.php +++ b/Theme/Backend/Lang/de.lang.php @@ -42,5 +42,6 @@ return ['Media' => [ 'Size' => 'Größe', 'Type' => 'Typ', 'Upload' => 'Hochladen', + 'VirtualPath' => 'Virtueller Pfad', 'Visibility' => 'Sichtbarkeit', ]]; diff --git a/Theme/Backend/Lang/en.lang.php b/Theme/Backend/Lang/en.lang.php index 1783a97..ac14a23 100755 --- a/Theme/Backend/Lang/en.lang.php +++ b/Theme/Backend/Lang/en.lang.php @@ -42,5 +42,6 @@ return ['Media' => [ 'Size' => 'Size', 'Type' => 'Type', 'Upload' => 'Upload', + 'VirtualPath' => 'Virtual Path', 'Visibility' => 'Visibility', ]]; diff --git a/Theme/Backend/media-collection-create.tpl.php b/Theme/Backend/media-collection-create.tpl.php index e69de29..2482f4c 100755 --- a/Theme/Backend/media-collection-create.tpl.php +++ b/Theme/Backend/media-collection-create.tpl.php @@ -0,0 +1,63 @@ + + +
| + |
| - |
| + |
| - |
| - |
| - |