diff --git a/Admin/Install/Messages.install.json b/Admin/Install/Messages.install.json new file mode 100755 index 0000000..674b454 --- /dev/null +++ b/Admin/Install/Messages.install.json @@ -0,0 +1,23 @@ +[ + { + "type": "email_template", + "from": "", + "to": "", + "cc": "", + "bcc": "", + "ishtml": true, + "l11n": { + "en": { + "subject": "ORW Resource Change", + "body": "Resource Change

Resource Change

The resource {resource.url} changed.

This email is sent to you from {owner_email}, if you don't wan't to receive these emails click here

Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn

", + "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": "Ressourcenänderung

Ressourcenänderung

Die Ressource {resource.url} hat sich geändert.

Diese E-Mail wird Ihnen von {owner_email} gesendet. Wenn Sie diese E-Mails nicht mehr erhalten möchten, klicken Sie hier.

Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn

", + "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 + } +] \ No newline at end of file diff --git a/Admin/Install/Messages.php b/Admin/Install/Messages.php new file mode 100755 index 0000000..a994310 --- /dev/null +++ b/Admin/Install/Messages.php @@ -0,0 +1,67 @@ + __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); + } +} diff --git a/Admin/Install/db.json b/Admin/Install/db.json index c138696..b70ea8c 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -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 } } } diff --git a/Controller/ApiController.php b/Controller/ApiController.php index 8c33292..54c8989 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -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 + * + * @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 + * + * @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 + * + * @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 + * + * @since 1.0.0 + */ + private function validateInformDelete(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = !$request->hasData('id')) + ) { + return $val; + } + + return []; } } diff --git a/Models/Inform.php b/Models/Inform.php new file mode 100644 index 0000000..2d11fd7 --- /dev/null +++ b/Models/Inform.php @@ -0,0 +1,60 @@ + $this->id, + 'email' => $this->email, + 'account' => $this->account, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return $this->toArray(); + } +} diff --git a/Models/InformBlacklist.php b/Models/InformBlacklist.php new file mode 100644 index 0000000..4a7380b --- /dev/null +++ b/Models/InformBlacklist.php @@ -0,0 +1,55 @@ + $this->id, + 'email' => $this->email, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return $this->toArray(); + } +} diff --git a/Models/InformBlacklistMapper.php b/Models/InformBlacklistMapper.php new file mode 100644 index 0000000..17ec56a --- /dev/null +++ b/Models/InformBlacklistMapper.php @@ -0,0 +1,59 @@ + + */ +final class InformBlacklistMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var 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'; +} diff --git a/Models/InformMapper.php b/Models/InformMapper.php new file mode 100644 index 0000000..46ce530 --- /dev/null +++ b/Models/InformMapper.php @@ -0,0 +1,61 @@ + + */ +final class InformMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var 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'; +} diff --git a/Models/NullInform.php b/Models/NullInform.php new file mode 100644 index 0000000..343afa7 --- /dev/null +++ b/Models/NullInform.php @@ -0,0 +1,46 @@ +id = $id; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return ['id' => $this->id]; + } +} diff --git a/Models/NullInformBlacklist.php b/Models/NullInformBlacklist.php new file mode 100644 index 0000000..6dbc684 --- /dev/null +++ b/Models/NullInformBlacklist.php @@ -0,0 +1,46 @@ +id = $id; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return ['id' => $this->id]; + } +} diff --git a/Models/NullReport.ph b/Models/NullReport.php similarity index 100% rename from Models/NullReport.ph rename to Models/NullReport.php diff --git a/Models/Report.php b/Models/Report.php index f0a347a..0781027 100755 --- a/Models/Report.php +++ b/Models/Report.php @@ -33,7 +33,7 @@ class Report implements \JsonSerializable * @var int * @since 1.0.0 */ - protected int $id = 0; + public int $id = 0; /** * Created. diff --git a/Models/ReportMapper.php b/Models/ReportMapper.php index 92a51a5..2e016ff 100755 --- a/Models/ReportMapper.php +++ b/Models/ReportMapper.php @@ -14,7 +14,6 @@ declare(strict_types=1); namespace Modules\OnlineResourceWatcher\Models; -use Modules\Admin\Models\AccountMapper; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; /** diff --git a/Models/Resource.php b/Models/Resource.php index 87f51b4..3c316a6 100755 --- a/Models/Resource.php +++ b/Models/Resource.php @@ -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. * diff --git a/Models/ResourceMapper.php b/Models/ResourceMapper.php index 6cbc109..c951d90 100755 --- a/Models/ResourceMapper.php +++ b/Models/ResourceMapper.php @@ -69,6 +69,21 @@ final class ResourceMapper extends DataMapperFactory ], ]; + /** + * Has many relation. + * + * @var array + * @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. * diff --git a/Models/SettingsEnum.php b/Models/SettingsEnum.php new file mode 100755 index 0000000..e5af795 --- /dev/null +++ b/Models/SettingsEnum.php @@ -0,0 +1,30 @@ +getHtml('User', '0', '0'); ?> getHtml('Email', '0', '0'); ?> - $value) : ++$c; $url = UriFactory::build('{/base}/admin/account/settings?{?}&id=' . $value->getId()); ?> + $value) : ++$c; $url = UriFactory::build('{/base}/admin/account/settings?{?}&id=' . $value->id); ?> diff --git a/Theme/Backend/resource-list.tpl.php b/Theme/Backend/resource-list.tpl.php index 5c7c2aa..1b4afd2 100755 --- a/Theme/Backend/resource-list.tpl.php +++ b/Theme/Backend/resource-list.tpl.php @@ -78,9 +78,9 @@ $next = $tableView->getNextLink( $resource) : ++$count; - $url = UriFactory::build('{/base}/orw/resource?id=' . $resource->getId()); ?> + $url = UriFactory::build('{/base}/orw/resource?id=' . $resource->id); ?> - getId(); ?> + id; ?> printHtml($resource->title); ?> printHtml((string) $resource->getStatus()); ?> printHtml($resource->checkedAt->format('Y-m-d H:i')); ?> diff --git a/Theme/Backend/resource-single.tpl.php b/Theme/Backend/resource-single.tpl.php index 36a5cd8..3853d59 100755 --- a/Theme/Backend/resource-single.tpl.php +++ b/Theme/Backend/resource-single.tpl.php @@ -78,7 +78,7 @@ $resource = $this->getData('resource') ?? new \Modules\OnlineResourceWatcher\Mod
- +
diff --git a/info.json b/info.json index ac1b646..d2d839a 100755 --- a/info.json +++ b/info.json @@ -18,10 +18,13 @@ "directory": "OnlineResourceWatcher", "dependencies": { "Admin": "1.0.0", - "Media": "*" + "Media": "*", + "Messages": "*" }, "providing": { - "Navigation": "*" + "Navigation": "*", + "Messages": "*", + "Workflow": "*" }, "load": [ { diff --git a/tests/Controller/ApiControllerTest.php b/tests/Controller/ApiControllerTest.php index 05eecb8..1e4b97b 100755 --- a/tests/Controller/ApiControllerTest.php +++ b/tests/Controller/ApiControllerTest.php @@ -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); } }