make id public, organigram impl. media password/encryption, settings bug fix, Money->FloatInt change, ...

This commit is contained in:
Dennis Eichhorn 2023-05-06 11:42:06 +00:00
parent 83757a469d
commit c9b3946e76
21 changed files with 910 additions and 30 deletions

View File

@ -0,0 +1,23 @@
[
{
"type": "email_template",
"from": "",
"to": "",
"cc": "",
"bcc": "",
"ishtml": true,
"l11n": {
"en": {
"subject": "ORW Resource Change",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Resource Change</title></head><body style=\"font-family: Arial, sans-serif; font-size: 16px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0; text-align: center;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px;\">Resource Change</h1><p style=\"margin-bottom: 20px;\">The resource {resource.url} changed.</p><p style=\"margin-top: 40px;\">This email is sent to you from {owner_email}, if you don't wan't to receive these emails click <a href=\"https://orw.jingga.app/unsubscribe?email={email}&resource={resource.id}\">here</a></p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Resource Change\n\nThe resource {resource.url} changed.\n\n\nThis email is sent to you from {owner_email}, if you don't wan't to receive these emails visit https://orw.jingga.app/unsubscribe?email={email}&resource={resource.id}\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn"
},
"de": {
"subject": "Ressourcenänderung",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Ressourcenänderung</title></head><body style=\"font-family: Arial, sans-serif; font-size: 16px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0; text-align: center;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px;\">Ressourcenänderung</h1><p style=\"margin-bottom: 20px;\">Die Ressource {resource.url} hat sich geändert.</p><p style=\"margin-top: 40px;\">Diese E-Mail wird Ihnen von {owner_email} gesendet. Wenn Sie diese E-Mails nicht mehr erhalten möchten, klicken Sie <a href=\"https://orw.jingga.app/unsubscribe?email={email}&resource={resource.id}\">hier</a>.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Ressourcenänderung\n\nDie Ressource {resource.url} hat sich geändert.\n\nDiese E-Mail wird Ihnen von {owner_email} gesendet. Wenn Sie diese E-Mails nicht mehr erhalten möchten, besuchen Sie https://orw.jingga.app/unsubscribe?email={email}&resource={resource.id}\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn"
}
},
"send": false
}
]

67
Admin/Install/Messages.php Executable file
View File

@ -0,0 +1,67 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Admin\Install
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Admin\Install;
use Modules\Admin\Models\SettingsEnum;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Uri\HttpUri;
/**
* Media class.
*
* @package Modules\OnlineResourceWatcher\Admin\Install
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Messages
{
/**
* Install media providing
*
* @param ApplicationAbstract $app Application
* @param string $path Module path
*
* @return void
*
* @since 1.0.0
*/
public static function install(ApplicationAbstract $app, string $path) : void
{
$messages = \Modules\Messages\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Messages.install.json']);
/** @var \Modules\Admin\Controller\ApiController $module */
$module = $app->moduleManager->get('Admin');
$settings = [
[
'id' => null,
'name' => SettingsEnum::LOGIN_MAIL_REGISTRATION_TEMPLATE,
'content' => (string) $messages['email_template'][0]['id'],
'module' => 'OnlineResourceWatcher',
],
];
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request->header->account = 1;
$request->setData('settings', \json_encode($settings));
$module->apiSettingsSet($request, $response);
}
}

View File

@ -158,11 +158,6 @@
"default": null,
"foreignTable": "orw_resource",
"foreignKey": "orw_resource_id"
},
"orw_resource_info_created_at": {
"name": "orw_resource_info_created_at",
"type": "DATETIME",
"null": false
}
}
},
@ -184,11 +179,6 @@
"annotations": {
"gdpr": true
}
},
"orw_resource_blacklist_created_at": {
"name": "orw_resource_blacklist_created_at",
"type": "DATETIME",
"null": false
}
}
}

View File

@ -15,6 +15,8 @@ declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Controller;
use Modules\Admin\Models\NullAccount;
use Modules\OnlineResourceWatcher\Models\Inform;
use Modules\OnlineResourceWatcher\Models\InformMapper;
use Modules\OnlineResourceWatcher\Models\Report;
use Modules\OnlineResourceWatcher\Models\ReportMapper;
use Modules\OnlineResourceWatcher\Models\ReportStatus;
@ -31,6 +33,11 @@ use phpOMS\System\File\Local\Directory;
use phpOMS\System\SystemUtils;
use phpOMS\Utils\ImageUtils;
use phpOMS\Utils\StringUtils;
use Modules\Admin\Models\SettingsEnum;
use Modules\OnlineResourceWatcher\Models\SettingsEnum as OrwSettingsEnum;
use Modules\Messages\Models\EmailMapper;
use Modules\OnlineResourceWatcher\Models\InformBlacklistMapper;
use phpOMS\Uri\UriFactory;
/**
* OnlineResourceWatcher controller class.
@ -155,6 +162,7 @@ final class ApiController extends Controller
$resource->title = $request->getDataString('title') ?? '';
$resource->uri = $request->getDataString('uri') ?? '';
$resource->owner = new NullAccount($request->header->account);
$resource->path = $request->getDataString('path') ?? '';
// @todo: check if user is part of organization below AND has free resources to add!!!
$resource->organization = new NullAccount(
@ -181,7 +189,7 @@ final class ApiController extends Controller
*/
public function apiCheckResources(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
$this->checkResources();
$this->checkResources($request, $response);
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Resources', 'Resources were checked.', null);
}
@ -195,7 +203,7 @@ final class ApiController extends Controller
*
* @since 1.0.0
*/
public function informUsers(mixed $var = null) : void
public function informUsers(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
$dateTime = new \DateTime('now');
$dateTime = $dateTime->modify('-1 hour');
@ -220,13 +228,17 @@ final class ApiController extends Controller
* @return array
*
* @since 1.0.0
* @todo: implement iterative approach where you can define a "offset" and "limit" to check only a few resources at a time
*/
public function checkResources(mixed $var = null) : array
public function checkResources(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : array
{
$changed = [];
/** @var Resource[] $resources */
$resources = ResourceMapper::getAll()
->with('owner')
->with('owner/l11n')
->with('inform')
->where('status', ResourceStatus::ACTIVE)
->execute();
@ -244,7 +256,7 @@ final class ApiController extends Controller
$path = $basePath . '/';
$timestamp = \time();
$path .= 'temp/' . $resource->getId() . '/' . $timestamp;
$path .= 'temp/' . $resource->id . '/' . $timestamp;
$toCheck[] = [
'resource' => $resource,
'timestamp' => $timestamp,
@ -260,6 +272,28 @@ final class ApiController extends Controller
);
}
$handler = $this->app->moduleManager->get('Admin', 'Api')->setUpServerMailHandler();
$emailSettings = $this->app->appSettings->get(
names: SettingsEnum::MAIL_SERVER_ADDR,
module: 'OnlineResourceWatcher'
);
$templateSettings = $this->app->appSettings->get(
names: OrwSettingsEnum::ORW_CHANGE_MAIL_TEMPLATE,
module: 'OnlineResourceWatcher'
);
/** @var \Modules\Messages\Models\Email $baseEmail */
$baseEmail = EmailMapper::get()
->with('l11n')
->where('id', (int) $templateSettings->content)
->execute();
/** @var \Modules\OnlineResourceWatcher\Models\InformBlacklist[] */
$blacklist = InformBlacklistMapper::getAll()
->execute();
// Check downloaded resources
// @todo: this may not work correctly because the download runs async.
$totalCount = \count($toCheck);
@ -270,12 +304,14 @@ final class ApiController extends Controller
while (!empty($toCheck)) {
foreach ($toCheck as $index => $check) {
++$toCheck[$index]['loop'];
/** @var Resource $resource */
$resource = $check['resource'];
// too many tries
if ($check['loop'] > $maxLoops) {
$report = new Report();
$report->resource = $resource->getId();
$report->resource = $resource->id;
$report->versionPath = (string) $check['timestamp'];
$report->status = ReportStatus::DOWNLOAD_ERROR;
@ -329,7 +365,7 @@ final class ApiController extends Controller
}
$report = new Report();
$report->resource = $resource->getId();
$report->resource = $resource->id;
$report->versionPath = (string) $check['timestamp'];
$hash = '';
@ -342,7 +378,7 @@ final class ApiController extends Controller
ReportMapper::create()->execute($report);
$resource->path = (string) $resource->getId();
$resource->path = (string) $resource->id;
$resource->lastVersionPath = (string) $check['timestamp'];
$resource->lastVersionDate = $report->createdAt;
$resource->hash = $hash == false ? '' : $hash;
@ -448,20 +484,54 @@ final class ApiController extends Controller
$contentNew = \Modules\Media\Controller\ApiController::loadFileContent($newPath, $extension);
$difference = \levenshtein($contentOld, $contentNew);
// Handle xpath
if ($difference > 0
&& ($extension === 'htm' || $extension === 'html')
&& $resource->path !== ''
) {
$xmlOld = new \DOMDocument();
$xmlNew = new \DOMDocument();
$xmlOld->loadHtml($contentOld);
$xmlNew->loadHtml($contentNew);
$xpathOld = new \DOMXpath($xmlOld);
$xpathNew = new \DOMXpath($xmlNew);
$elementsOld = $xpathOld->query($resource->path);
$elementsNew = $xpathNew->query($resource->path);
$subcontentOld = '';
foreach ($elementsOld as $node) {
foreach ($node->childNodes as $child) {
$subcontentOld .= $xmlOld->saveXML($child);
}
}
$subcontentNew = '';
foreach ($elementsNew as $node) {
foreach ($node->childNodes as $child) {
$subcontentNew .= $xmlNew->saveXML($child);
}
}
$difference = \levenshtein($subcontentOld, $subcontentNew);
}
} elseif (\in_array($extension, ['png', 'jpg', 'jpeg', 'gif'])) {
$difference = ImageUtils::difference($oldPath, $newPath, $path . '/_' . \basename($newPath), 0);
}
}
$report = new Report();
$report->resource = $resource->getId();
$report->resource = $resource->id;
$report->versionPath = (string) $check['timestamp'];
$report->changeMetric = $difference;
if ($difference !== 0) {
$report->status = ReportStatus::CHANGE;
$resource->path = (string) $resource->getId();
$resource->path = (string) $resource->id;
$resource->lastVersionPath = (string) $check['timestamp'];
$resource->lastVersionDate = $report->createdAt;
$resource->hash = $md5New;
@ -469,6 +539,69 @@ final class ApiController extends Controller
$changed[] = $report;
Directory::copy($path, $basePath . '/' . $id . '/' . $check['timestamp']);
// @todo: move to informUsers function
$owner = new Inform();
$owner->email = $resource->owner->getEmail();
$resource->inform[] = $owner;
foreach ($resource->inform as $inform) {
foreach ($blacklist as $block) {
if (\stripos($inform->email, $block->email) !== false) {
continue 2;
}
}
$mail = clone $baseEmail;
$mail->setFrom($emailSettings->content);
$mailL11n = $baseEmail->getL11nByLanguage($resource->owner->l11n->getLanguage());
if ($mailL11n->id === 0) {
$mailL11n = $baseEmail->getL11nByLanguage($this->app->l11nServer->getLanguage());
}
if ($mailL11n->id === 0) {
$mailL11n = $baseEmail->getL11nByLanguage('en');
}
$mail->subject = $mailL11n->subject;
$mail->body = \str_replace(
[
'{resource.id}',
'{email}',
'{resource.url}',
'{owner_email}',
],
[
$resource->id,
$inform->email,
$resource->uri,
$resource->owner->getEmail()
],
$mailL11n->body
);
$mail->msgHTML($mail->body);
$mail->bodyAlt = \str_replace(
[
'{resource.id}',
'{email}',
'{resource.url}',
'{owner_email}',
],
[
$resource->id,
$inform->email,
$resource->uri,
$resource->owner->getEmail()
],
$mailL11n->bodyAlt
);
$mail->addTo($inform->email);
$handler->send($mail);
}
}
ReportMapper::create()->execute($report);
@ -479,7 +612,6 @@ final class ApiController extends Controller
Directory::delete($basePath . '/temp/' . $id);
// @todo: delete older history depending on plan
// @todo: inform users
unset($toCheck[$index]);
}
@ -507,6 +639,78 @@ final class ApiController extends Controller
*/
public function apiResourceUpdate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateResourceUpdate($request))) {
$response->set('resource_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
/** @var \Modules\OnlineResourceWatcher\Models\Resource $old */
$old = ResourceMapper::get()
->where('id', (int) $request->getData('id'))
->execute();
if ($old->owner->id !== $request->header->account) {
$response->header->status = RequestStatusCode::R_403;
$response->set($request->uri->__toString(), [
'status' => NotificationLevel::WARNING,
'title' => 'Update',
'message' => 'Insufficient permissions to update resource.',
'response' => null,
]);
return;
}
$new = $this->updateResourceFromRequest($request, clone $old);
$this->updateModel($request->header->account, $old, $new, ResourceMapper::class, 'resource', $request->getOrigin());
$this->fillJsonResponse(
$request,
$response,
NotificationLevel::OK,
'',
$this->app->l11nManager->getText($response->getLanguage(), '0', '0', 'SuccessfulUpdate'),
$new
);
}
/**
* Validate resource create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateResourceUpdate(RequestAbstract $request) : array
{
$val = [];
if (($val['id'] = !$request->hasData('id'))
) {
return $val;
}
return [];
}
/**
* Method to create news article from request.
*
* @param RequestAbstract $request Request
*
* @return Resource
*
* @since 1.0.0
*/
private function updateResourceFromRequest(RequestAbstract $request, Resource $resource) : Resource
{
$resource->title = $request->getDataString('title') ?? '';
$resource->uri = $request->getDataString('uri') ?? '';
return $resource;
}
/**
@ -541,5 +745,219 @@ final class ApiController extends Controller
*/
public function apiResourceDelete(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateResourceDelete($request))) {
$response->set('resource_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
/** @var \Modules\OnlineResourceWatcher\Models\Resource $resource */
$resource = ResourceMapper::get()
->where('id', (int) $request->getData('id'))
->execute();
if ($resource->owner->id !== $request->header->account) {
$response->header->status = RequestStatusCode::R_403;
$response->set($request->uri->__toString(), [
'status' => NotificationLevel::WARNING,
'title' => 'Delete',
'message' => 'Insufficient permissions to delete resource.',
'response' => null,
]);
return;
}
$this->deleteModel($request->header->account, $resource, ResourceMapper::class, 'resource', $request->getOrigin());
$this->fillJsonResponse(
$request,
$response,
NotificationLevel::OK,
'',
$this->app->l11nManager->getText($response->getLanguage(), '0', '0', 'SuccessfulDelete'),
$resource
);
}
/**
* Validate resource create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateResourceDelete(RequestAbstract $request) : array
{
$val = [];
if (($val['id'] = !$request->hasData('id'))
) {
return $val;
}
return [];
}
/**
* Api method to create resource
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiInformCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateInformCreate($request))) {
$response->set('resource_inform_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
$resource = ResourceMapper::get()
->where('id', $request->getDataInt('resource'))
->execute();
if ($resource->owner->id !== $request->header->account) {
$response->header->status = RequestStatusCode::R_403;
$response->set($request->uri->__toString(), [
'status' => NotificationLevel::WARNING,
'title' => 'Create',
'message' => 'Insufficient permissions',
'response' => null,
]);
return;
}
$resource = $this->createInformFromRequest($request);
$this->createModel($request->header->account, $resource, InformMapper::class, 'resource', $request->getOrigin());
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Inform', 'Successfully created', $resource);
}
/**
* Validate inform create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateInformCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['email'] = (!$request->hasData('email') && !$request->hasData('account')))
&& ($val['resource'] = ($request->getDataInt('resource') === null))
) {
return $val;
}
return [];
}
/**
* Method to create news article from request.
*
* @param RequestAbstract $request Request
*
* @return Inform
*
* @since 1.0.0
*/
private function createInformFromRequest(RequestAbstract $request) : Inform
{
$inform = new Inform();
$inform->account = $request->getDataInt('account');
$inform->email = $request->getDataString('email');
$inform->resource = $request->getDataInt('resource');
return $inform;
}
/**
* Api method to create resource
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiInformDelete(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateInformDelete($request))) {
$response->set('resource_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
/** @var \Modules\OnlineResourceWatcher\Models\Inform $inform */
$inform = InformMapper::get()
->where('id', (int) $request->getData('id'))
->execute();
/** @var \Modules\OnlineResourceWatcher\Models\Resource $resource */
$resource = ResourceMapper::get()
->where('id', $inform->resource)
->execute();
if ($resource->owner->id !== $request->header->account) {
$response->header->status = RequestStatusCode::R_403;
$response->set($request->uri->__toString(), [
'status' => NotificationLevel::WARNING,
'title' => 'Delete',
'message' => 'Insufficient permissions.',
'response' => null,
]);
return;
}
$this->deleteModel($request->header->account, $inform, InformMapper::class, 'inform', $request->getOrigin());
$this->fillJsonResponse(
$request,
$response,
NotificationLevel::OK,
'',
$this->app->l11nManager->getText($response->getLanguage(), '0', '0', 'SuccessfulDelete'),
$inform
);
}
/**
* Validate inform delete request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateInformDelete(RequestAbstract $request) : array
{
$val = [];
if (($val['id'] = !$request->hasData('id'))
) {
return $val;
}
return [];
}
}

60
Models/Inform.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
/**
* Inform class.
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Inform implements \JsonSerializable
{
/**
* ID.
*
* @var int
* @since 1.0.0
*/
public int $id = 0;
public string $email = '';
public ?int $account = null;
public int $resource = 0;
/**
* {@inheritdoc}
*/
public function toArray() : array
{
return [
'id' => $this->id,
'email' => $this->email,
'account' => $this->account,
];
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return $this->toArray();
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
/**
* Inform class.
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class InformBlacklist implements \JsonSerializable
{
/**
* ID.
*
* @var int
* @since 1.0.0
*/
public int $id = 0;
public string $email = '';
/**
* {@inheritdoc}
*/
public function toArray() : array
{
return [
'id' => $this->id,
'email' => $this->email,
];
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return $this->toArray();
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
use Modules\Admin\Models\AccountMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Inform mapper class.
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of Inform
* @extends DataMapperFactory<T>
*/
final class InformBlacklistMapper 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 = [
'orw_resource_blacklist_id' => ['name' => 'orw_resource_blacklist_id', 'type' => 'int', 'internal' => 'id'],
'orw_resource_blacklist_mail' => ['name' => 'orw_resource_blacklist_mail', 'type' => 'string', 'internal' => 'email',],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'orw_resource_blacklist';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'orw_resource_blacklist_id';
}

61
Models/InformMapper.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
use Modules\Admin\Models\AccountMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Inform mapper class.
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of Inform
* @extends DataMapperFactory<T>
*/
final class InformMapper 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 = [
'orw_resource_info_id' => ['name' => 'orw_resource_info_id', 'type' => 'int', 'internal' => 'id'],
'orw_resource_info_mail' => ['name' => 'orw_resource_info_mail', 'type' => 'string', 'internal' => 'email',],
'orw_resource_info_account' => ['name' => 'orw_resource_info_account', 'type' => 'int', 'internal' => 'account',],
'orw_resource_info_resource' => ['name' => 'orw_resource_info_resource', 'type' => 'int', 'internal' => 'resource',],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'orw_resource_info';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'orw_resource_info_id';
}

46
Models/NullInform.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
/**
* Null model
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 1.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullInform extends Inform
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
/**
* Null model
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 1.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullInformBlacklist extends InformBlacklist
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -33,7 +33,7 @@ class Report implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Created.

View File

@ -14,7 +14,6 @@ declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
use Modules\Admin\Models\AccountMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**

View File

@ -33,7 +33,7 @@ class Resource implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Status.
@ -99,6 +99,14 @@ class Resource implements \JsonSerializable
*/
public Account $owner;
/**
* Inform.
*
* @var Inform[]
* @since 1.0.0
*/
public array $inform = [];
/**
* Organization.
*

View File

@ -69,6 +69,21 @@ final class ResourceMapper extends DataMapperFactory
],
];
/**
* Has many relation.
*
* @var array<string, array{mapper:class-string, table:string, self?:?string, external?:?string, column?:string}>
* @since 1.0.0
*/
public const HAS_MANY = [
'inform' => [
'mapper' => InformMapper::class,
'table' => 'orw_resource_info',
'self' => 'orw_resource_info_resource',
'external' => null,
],
];
/**
* Primary table.
*

30
Models/SettingsEnum.php Executable file
View File

@ -0,0 +1,30 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\OnlineResourceWatcher\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\OnlineResourceWatcher\Models;
use phpOMS\Stdlib\Base\Enum;
/**
* Default settings enum.
*
* @package Modules\OnlineResourceWatcher\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
abstract class SettingsEnum extends Enum
{
public const ORW_CHANGE_MAIL_TEMPLATE = '1008000001';
}

View File

@ -76,7 +76,7 @@ use phpOMS\Uri\UriFactory;
<td><?= $this->getHtml('User', '0', '0'); ?><i class="sort-asc fa fa-chevron-up"></i><i class="sort-desc fa fa-chevron-down"></i>
<td><?= $this->getHtml('Email', '0', '0'); ?><i class="sort-asc fa fa-chevron-up"></i><i class="sort-desc fa fa-chevron-down"></i>
<tbody>
<?php $c = 0; foreach ([] as $key => $value) : ++$c; $url = UriFactory::build('{/base}/admin/account/settings?{?}&id=' . $value->getId()); ?>
<?php $c = 0; foreach ([] as $key => $value) : ++$c; $url = UriFactory::build('{/base}/admin/account/settings?{?}&id=' . $value->id); ?>
<tr data-href="<?= $url; ?>">
<td>
<td>

View File

@ -78,9 +78,9 @@ $next = $tableView->getNextLink(
<tbody>
<?php $count = 0;
foreach ($resources as $key => $resource) : ++$count;
$url = UriFactory::build('{/base}/orw/resource?id=' . $resource->getId()); ?>
$url = UriFactory::build('{/base}/orw/resource?id=' . $resource->id); ?>
<tr tabindex="0" data-href="<?= $url; ?>">
<td><?= $resource->getId(); ?>
<td><?= $resource->id; ?>
<td><?= $this->printHtml($resource->title); ?>
<td><?= $this->printHtml((string) $resource->getStatus()); ?>
<td><?= $this->printHtml($resource->checkedAt->format('Y-m-d H:i')); ?>

View File

@ -78,7 +78,7 @@ $resource = $this->getData('resource') ?? new \Modules\OnlineResourceWatcher\Mod
<div class="col-xs-12 col-simple">
<section id="mediaFile" class="portlet col-simple">
<div class="portlet-body col-simple">
<iframe class="col-simple" id="iRenderFrame" src="<?= UriFactory::build('{/api}/orw/resource/render?id=' . $resource->getId()); ?>" loading="lazy" allowfullscreen></iframe>
<iframe class="col-simple" id="iRenderFrame" src="<?= UriFactory::build('{/api}orw/resource/render?id=' . $resource->id); ?>" loading="lazy" allowfullscreen></iframe>
</div>
</section>
</div>

View File

@ -18,10 +18,13 @@
"directory": "OnlineResourceWatcher",
"dependencies": {
"Admin": "1.0.0",
"Media": "*"
"Media": "*",
"Messages": "*"
},
"providing": {
"Navigation": "*"
"Navigation": "*",
"Messages": "*",
"Workflow": "*"
},
"load": [
{

View File

@ -105,6 +105,6 @@ final class ApiControllerTest extends \PHPUnit\Framework\TestCase
$this->module->apiResourceCreate($request, $response);
self::assertGreaterThan(0, $response->get('')['response']->getId());
self::assertGreaterThan(0, $response->get('')['response']->id);
}
}