added parsed content field, fixed directory listing bug

This commit is contained in:
Dennis Eichhorn 2022-03-11 23:13:15 +01:00
parent 2e067f63f0
commit 7227aabc9b
10 changed files with 326 additions and 61 deletions

View File

@ -53,6 +53,23 @@
} }
} }
}, },
"media_parsed": {
"name": "media_parsed",
"fields": {
"media_parsed_id": {
"name": "media_parsed_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"media_parsed_content": {
"name": "media_parsed_content",
"type": "LONGTEXT",
"null": false
}
}
},
"media": { "media": {
"name": "media", "name": "media",
"fields": { "fields": {
@ -142,6 +159,14 @@
"default": null, "default": null,
"null": true "null": true
}, },
"media_content": {
"name": "media_content",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "media_parsed",
"foreignKey": "media_parsed_id"
},
"media_source": { "media_source": {
"name": "media_source", "name": "media_source",
"type": "INT", "type": "INT",

View File

@ -19,6 +19,7 @@ use Modules\Admin\Models\NullAccount;
use Modules\Media\Models\Collection; use Modules\Media\Models\Collection;
use Modules\Media\Models\CollectionMapper; use Modules\Media\Models\CollectionMapper;
use Modules\Media\Models\Media; use Modules\Media\Models\Media;
use Modules\Media\Models\MediaContent;
use Modules\Media\Models\MediaMapper; use Modules\Media\Models\MediaMapper;
use Modules\Media\Models\NullCollection; use Modules\Media\Models\NullCollection;
use Modules\Media\Models\NullMedia; use Modules\Media\Models\NullMedia;
@ -43,6 +44,11 @@ use phpOMS\System\File\Local\Directory;
use phpOMS\System\MimeType; use phpOMS\System\MimeType;
use phpOMS\Utils\Parser\Markdown\Markdown; use phpOMS\Utils\Parser\Markdown\Markdown;
use phpOMS\Views\View; use phpOMS\Views\View;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\Writer\HTML;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Autoloader;
use phpOMS\Utils\Parser\Pdf\PdfParser;
/** /**
* Media class. * Media class.
@ -133,6 +139,7 @@ final class ApiController extends Controller
* @param int $pathSettings Settings which describe where the file should be uploaded to (physically) * @param int $pathSettings Settings which describe where the file should be uploaded to (physically)
* RANDOM_PATH = random location in the base path * RANDOM_PATH = random location in the base path
* FILE_PATH = combination of base path and virtual path * FILE_PATH = combination of base path and virtual path
* @param bool $hasAccountRelation The uploaded files should be related to an account
* *
* @return array * @return array
* *
@ -148,7 +155,8 @@ final class ApiController extends Controller
int $type = null, int $type = null,
string $password = '', string $password = '',
string $encryptionKey = '', string $encryptionKey = '',
int $pathSettings = PathSettings::RANDOM_PATH int $pathSettings = PathSettings::RANDOM_PATH,
bool $hasAccountRelation = true
) : array ) : array
{ {
if (empty($files)) { if (empty($files)) {
@ -174,12 +182,22 @@ final class ApiController extends Controller
$sameLength = \count($names) === \count($status); $sameLength = \count($names) === \count($status);
$nCounter = -1; $nCounter = -1;
$created = [];
foreach ($status as &$stat) { foreach ($status as &$stat) {
++$nCounter; ++$nCounter;
$stat['name'] = $sameLength ? $names[$nCounter] : $stat['filename']; $stat['name'] = $sameLength ? $names[$nCounter] : $stat['filename'];
$created[] = self::createDbEntry(
$stat,
$account,
$virtualPath,
$type,
app: $hasAccountRelation ? $this->app : null
);
} }
return $this->createDbEntries($status, $account, $virtualPath, $type); return $created;
} }
/** /**
@ -220,54 +238,6 @@ final class ApiController extends Controller
return $basePath . '/_' . $rndPath[0] . $rndPath[1] . $rndPath[2] . $rndPath[3] . '/_' . $rndPath[4] . $rndPath[5] . $rndPath[6] . $rndPath[7]; return $basePath . '/_' . $rndPath[0] . $rndPath[1] . $rndPath[2] . $rndPath[3] . '/_' . $rndPath[4] . $rndPath[5] . $rndPath[6] . $rndPath[7];
} }
/**
* Create database entries for uploaded files
*
* @param array $status Files
* @param int $account Uploader
* @param string $virtualPath Virtual path
* @param null|int $type Media type (internal categorization = identifier for modules)
* @param string $ip Ip
*
* @return Media[]
*
* @since 1.0.0
*/
public function createDbEntries(
array $status,
int $account,
string $virtualPath = '',
int $type = null,
string $ip = '127.0.0.1'
) : array
{
$mediaCreated = [];
foreach ($status as $uFile) {
if (($created = self::createDbEntry($uFile, $account, $virtualPath, $type)) !== null) {
$mediaCreated[] = $created;
$this->app->moduleManager->get('Admin')->createAccountModelPermission(
new AccountPermission(
$account,
$this->app->orgId,
$this->app->appName,
self::NAME,
self::NAME,
PermissionState::MEDIA,
$created->getId(),
null,
PermissionType::READ | PermissionType::MODIFY | PermissionType::DELETE | PermissionType::PERMISSION
),
$account,
$ip
);
}
}
return $mediaCreated;
}
/** /**
* Create db entry for uploaded file * Create db entry for uploaded file
* *
@ -275,12 +245,20 @@ final class ApiController extends Controller
* @param int $account Uploader * @param int $account Uploader
* @param string $virtualPath Virtual path (not on the hard-drive) * @param string $virtualPath Virtual path (not on the hard-drive)
* @param null|int $type Media type (internal categorization) * @param null|int $type Media type (internal categorization)
* @param ApplicationAbstract $app Should create relation to uploader
* *
* @return null|Media * @return null|Media
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function createDbEntry(array $status, int $account, string $virtualPath = '', int $type = null) : ?Media public static function createDbEntry(
array $status,
int $account,
string $virtualPath = '',
int $type = null,
string $ip = '127.0.0.1',
ApplicationAbstract $app = null
) : ?Media
{ {
if ($status['status'] !== UploadStatus::OK) { if ($status['status'] !== UploadStatus::OK) {
return null; return null;
@ -296,11 +274,63 @@ final class ApiController extends Controller
$media->setVirtualPath($virtualPath); $media->setVirtualPath($virtualPath);
$media->type = $type === null ? null : new NullMediaType($type); $media->type = $type === null ? null : new NullMediaType($type);
if (\is_file($media->getAbsolutePath())) {
$content = self::loadFileContent($media->getAbsolutePath(), $media->extension);
if (!empty($content)) {
$media->content = new MediaContent();
$media->content->content = $content;
}
}
MediaMapper::create()->execute($media); MediaMapper::create()->execute($media);
if ($app !== null) {
$app->moduleManager->get('Admin')->createAccountModelPermission(
new AccountPermission(
$account,
$app->orgId,
$app->appName,
self::NAME,
self::NAME,
PermissionState::MEDIA,
$media->getId(),
null,
PermissionType::READ | PermissionType::MODIFY | PermissionType::DELETE | PermissionType::PERMISSION
),
$account,
$ip
);
}
return $media; return $media;
} }
private static function loadFileContent(string $path, string $extension) : string
{
switch ($extension) {
case 'pdf':
return PdfParser::pdf2text($path);
break;
case 'doc':
case 'docx':
Autoloader::addPath(__DIR__ . '/../../../Resources/');
$reader = IOFactory::createReader('Word2007');
$doc = $reader->load($path);
$writer = new HTML($doc);
return $writer->getContent();
break;
case 'txt':
case 'md':
return \file_get_contents($path);
break;
default:
return '';
};
}
/** /**
* Normalize the file path * Normalize the file path
* *
@ -624,11 +654,18 @@ final class ApiController extends Controller
], ],
]; ];
$created = $this->createDbEntries($status, $request->header->account, $virtualPath, $request->getData('type', 'int'));
$ids = []; $ids = [];
foreach ($created as $file) { foreach ($status as $stat) {
$ids[] = $file->getId(); $created = self::createDbEntry(
$status,
$request->header->account,
$virtualPath,
$request->getData('type', 'int'),
$request->getOrigin(),
$this->app
);
$ids[] = $created->getId();
} }
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media successfully created.', $ids); $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media successfully created.', $ids);

View File

@ -123,7 +123,7 @@ final class BackendController extends Controller
$collection = $collectionMapper->execute(); $collection = $collectionMapper->execute();
if (\is_array($collection) && \is_dir(__DIR__ . '/../Files' . $path)) { if ((\is_array($collection) || $collection instanceof NullCollection) && \is_dir(__DIR__ . '/../Files' . $path)) {
$collection = new Collection(); $collection = new Collection();
$collection->name = \basename($path); $collection->name = \basename($path);
$collection->setVirtualPath(\dirname($path)); $collection->setVirtualPath(\dirname($path));
@ -149,6 +149,8 @@ final class BackendController extends Controller
: \glob(__DIR__ . '/../Files/' . \trim($collection->getVirtualPath(), '/') . '/' . $collection->name . '/*'); : \glob(__DIR__ . '/../Files/' . \trim($collection->getVirtualPath(), '/') . '/' . $collection->name . '/*');
$glob = $glob === false ? [] : $glob; $glob = $glob === false ? [] : $glob;
$unIndexedFiles = [];
foreach ($glob as $file) { foreach ($glob as $file) {
$basename = \basename($file); $basename = \basename($file);
if ($basename[0] === '_' && \strlen($basename) === 5) { if ($basename[0] === '_' && \strlen($basename) === 5) {
@ -158,7 +160,7 @@ final class BackendController extends Controller
foreach ($media as $obj) { foreach ($media as $obj) {
if ($obj->name === $basename if ($obj->name === $basename
|| $obj->name . '.' . $obj->extension === $basename || $obj->name . '.' . $obj->extension === $basename
|| StringUtils::endsWith(\realpath($file), $obj->getPath()) || ($obj->getPath() !== '' && StringUtils::endsWith(\realpath($file), $obj->getPath()))
) { ) {
continue 2; continue 2;
} }
@ -172,8 +174,10 @@ final class BackendController extends Controller
$localMedia->setVirtualPath($path); $localMedia->setVirtualPath($path);
$localMedia->createdBy = new Account(); $localMedia->createdBy = new Account();
$media[] = $localMedia; $unIndexedFiles[] = $localMedia;
} }
$media = \array_merge($media, $unIndexedFiles);
} }
$view->addData('media', $media); $view->addData('media', $media);
@ -221,6 +225,7 @@ final class BackendController extends Controller
->with('createdBy') ->with('createdBy')
->with('tags') ->with('tags')
->with('tags/title') ->with('tags/title')
->with('content')
->where('id', $id) ->where('id', $id)
->where('tags/title/language', $request->getLanguage()) ->where('tags/title/language', $request->getLanguage())
->execute(); ->execute();

View File

@ -45,6 +45,14 @@ class Media implements \JsonSerializable
*/ */
public string $name = ''; public string $name = '';
/**
* Content.
*
* @var null|MediaContent
* @since 1.0.0
*/
public ?MediaContent $content = null;
/** /**
* Type. * Type.
* *

70
Models/MediaContent.php Normal file
View File

@ -0,0 +1,70 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Media\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Media\Models;
use Modules\Admin\Models\Account;
use Modules\Admin\Models\NullAccount;
use Modules\Tag\Models\NullTag;
use Modules\Tag\Models\Tag;
/**
* Media class.
*
* @package Modules\Media\Models
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
class MediaContent implements \JsonSerializable
{
/**
* ID.
*
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public string $content = '';
/**
* @return int
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function toArray() : array
{
return [
'id' => $this->id,
'content' => $this->content,
];
}
/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return $this->toArray();
}
}

View File

@ -0,0 +1,63 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Media\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Media\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Media mapper class.
*
* @package Modules\Media\Models
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
class MediaContentMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
* @since 1.0.0
*/
public const COLUMNS = [
'media_parsed_id' => ['name' => 'media_parsed_id', 'type' => 'int', 'internal' => 'id'],
'media_parsed_content' => ['name' => 'media_parsed_content', 'type' => 'string', 'internal' => 'content'],
];
/**
* Model to use by the mapper.
*
* @var string
* @since 1.0.0
*/
public const MODEL = MediaContent::class;
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'media_parsed';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD ='media_parsed_id';
}

View File

@ -41,6 +41,7 @@ class MediaMapper extends DataMapperFactory
'media_type' => ['name' => 'media_type', 'type' => 'int', 'internal' => 'type'], 'media_type' => ['name' => 'media_type', 'type' => 'int', 'internal' => 'type'],
'media_description' => ['name' => 'media_description', 'type' => 'string', 'internal' => 'description', 'autocomplete' => true], 'media_description' => ['name' => 'media_description', 'type' => 'string', 'internal' => 'description', 'autocomplete' => true],
'media_description_raw' => ['name' => 'media_description_raw', 'type' => 'string', 'internal' => 'descriptionRaw'], 'media_description_raw' => ['name' => 'media_description_raw', 'type' => 'string', 'internal' => 'descriptionRaw'],
'media_content' => ['name' => 'media_content', 'type' => 'int', 'internal' => 'content'],
'media_versioned' => ['name' => 'media_versioned', 'type' => 'bool', 'internal' => 'isVersioned'], 'media_versioned' => ['name' => 'media_versioned', 'type' => 'bool', 'internal' => 'isVersioned'],
'media_hidden' => ['name' => 'media_hidden', 'type' => 'bool', 'internal' => 'isHidden'], 'media_hidden' => ['name' => 'media_hidden', 'type' => 'bool', 'internal' => 'isHidden'],
'media_file' => ['name' => 'media_file', 'type' => 'string', 'internal' => 'path', 'autocomplete' => true], 'media_file' => ['name' => 'media_file', 'type' => 'string', 'internal' => 'path', 'autocomplete' => true],
@ -84,6 +85,10 @@ class MediaMapper extends DataMapperFactory
'mapper' => self::class, 'mapper' => self::class,
'external' => 'media_source', 'external' => 'media_source',
], ],
'content' => [
'mapper' => MediaContentMapper::class,
'external' => 'media_content',
],
]; ];
/** /**
@ -180,7 +185,7 @@ class MediaMapper extends DataMapperFactory
$virtualPath = '/' . \trim(\substr($path, 0, \strripos($path, '/') + 1), '/'); $virtualPath = '/' . \trim(\substr($path, 0, \strripos($path, '/') + 1), '/');
$name = \substr($path, \strripos($path, '/') + 1); $name = \substr($path, \strripos($path, '/') + 1);
return self::get() return CollectionMapper::get()
->with('sources') ->with('sources')
->with('source') ->with('source')
->where('virtualPath', $virtualPath) ->where('virtualPath', $virtualPath)

View File

@ -0,0 +1,38 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Media\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Media\Models;
/**
* Media class.
*
* @package Modules\Media\Models
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
final class NullMediaContent extends MediaContent
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
}

View File

@ -18,6 +18,20 @@ use \phpOMS\Uri\UriFactory;
<section id="mediaFile" class="portlet"> <section id="mediaFile" class="portlet">
<div class="portlet-body"> <div class="portlet-body">
<iframe style="min-height: 600px;" data-form="iUiSettings" data-name="iframeHelper" id="iHelperFrame" src="<?= UriFactory::build('{/backend}Resources/mozilla/Pdf/web/viewer.html?{?}&file=' . \urlencode(($this->media->isAbsolute ? '' : '/../../../../') . $this->media->getPath())); ?>" allowfullscreen></iframe> <div id="media" class="tabview tab-2 m-editor">
<ul class="tab-links">
<li><label tabindex="0" for="media-c-tab-1"><?= $this->getHtml('Preview', 'Media'); ?></label>
<li><label tabindex="0" for="media-c-tab-2"><?= $this->getHtml('Content', 'Media'); ?></label>
</ul>
<div class="tab-content">
<input type="radio" id="media-c-tab-1" name="tabular-1" checked>
<div class="tab">
<iframe style="min-height: 600px;" data-form="iUiSettings" data-name="iframeHelper" id="iHelperFrame" src="<?= UriFactory::build('{/backend}Resources/mozilla/Pdf/web/viewer.html?{?}&file=' . \urlencode(($this->media->isAbsolute ? '' : '/../../../../') . $this->media->getPath())); ?>" allowfullscreen></iframe>
</div>
<input type="radio" id="media-c-tab-2" name="tabular-1">
<div class="tab">
<pre class="textContent" data-tpl-text="/media/content" data-tpl-value="/media/content"><?= $this->printHtml($this->media->content->content); ?></pre>
</div>
</div>
</div> </div>
</section> </section>

View File

@ -207,7 +207,7 @@ $next = empty($media) ? '{/prefix}media/list' : '{/prefix}media/list?{?}&id=
<td data-label="<?= $this->getHtml('Size'); ?>"><a href="<?= $url; ?>"><?php <td data-label="<?= $this->getHtml('Size'); ?>"><a href="<?= $url; ?>"><?php
$size = FileSizeType::autoFormat($value->size); $size = FileSizeType::autoFormat($value->size);
echo $this->printHtml($value->extension !== 'collection' ? \number_format($size[0], 1, '.', ',') . $size[1] : ''); ?></a> echo $this->printHtml($value->extension !== 'collection' ? \number_format($size[0], 1, '.', ',') . $size[1] : ''); ?></a>
<td data-label="<?= $this->getHtml('Creator'); ?>"><a class="content" href="<?= UriFactory::build('{/prefix}profile/single?{?}&for=' . $value->createdBy->getId()); ?>"><?= $this->printHtml($value->createdBy->name1); ?></a> <td data-label="<?= $this->getHtml('Creator'); ?>"><a class="content" href="<?= UriFactory::build('{/prefix}profile/single?{?}&for=' . $value->createdBy->getId()); ?>"><?= $this->printHtml($this->renderUserName('%3$s %2$s %1$s', [$value->createdBy->name1, $value->createdBy->name2, $value->createdBy->name3, $value->createdBy->login ?? ''])); ?></a>
<td data-label="<?= $this->getHtml('Created'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->createdAt->format('Y-m-d')); ?></a> <td data-label="<?= $this->getHtml('Created'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->createdAt->format('Y-m-d')); ?></a>
<?php endforeach; ?> <?php endforeach; ?>
<?php if ($count === 0) : ?> <?php if ($count === 0) : ?>