diff --git a/.gitignore b/.gitignore index cd61f5a..722bfae 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .vs obj/ +/Files/ app/server/build/*.txt app/server/build/*.cmake CMakeFiles diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index 6faecbf..61f8dd3 100755 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -5,21 +5,21 @@ "type": 2, "subtype": 1, "name": "OnlineResourceWatcher", - "uri": "{/lang}/{/app}/orw/dashboard?u={?u}", + "uri": "{/lang}/{/app}/orw/resource/list?u={?u}", "target": "self", "icon": null, "order": 40, "from": "OnlineResourceWatcher", "permission": { "permission": 2, "category": null, "element": null }, - "parent": 1006901001, + "parent": 1003301001, "children": [ { "id": 1008002001, "pid": "/orw", "type": 3, "subtype": 1, - "name": "OnlineResourceWatcher", - "uri": "{/lang}/{/app}/orw/dashboard?u={?u}", + "name": "Resources", + "uri": "{/lang}/{/app}/orw/resource/list?u={?u}", "target": "self", "icon": null, "order": 1, @@ -27,66 +27,6 @@ "permission": { "permission": 2, "category": null, "element": null }, "parent": 1008001001, "children": [] - }, - { - "id": 1008003001, - "pid": "/orw", - "type": 3, - "subtype": 1, - "name": "Archive", - "uri": "{/lang}/{/app}/orw/archive?u={?u}", - "target": "self", - "icon": null, - "order": 5, - "from": "OnlineResourceWatcher", - "permission": { "permission": 2, "category": null, "element": null }, - "parent": 1008001001, - "children": [] - }, - { - "id": 1008004001, - "pid": "/orw", - "type": 3, - "subtype": 1, - "name": "Create", - "uri": "{/lang}/{/app}/orw/create?{?}", - "target": "self", - "icon": null, - "order": 10, - "from": "OnlineResourceWatcher", - "permission": { "permission": 4, "category": null, "element": null }, - "parent": 1008001001, - "children": [] - }, - { - "id": 1008005001, - "pid": "/orw", - "type": 3, - "subtype": 1, - "name": "Draft", - "uri": "{/lang}/{/app}/orw/draft/list?u={?u}", - "target": "self", - "icon": null, - "order": 15, - "from": "OnlineResourceWatcher", - "permission": { "permission": 4, "category": null, "element": null }, - "parent": 1008001001, - "children": [] - }, - { - "id": 1008006001, - "pid": "/orw", - "type": 3, - "subtype": 1, - "name": "Analysis", - "uri": "{/lang}/{/app}/orw/analysis", - "target": "self", - "icon": null, - "order": 15, - "from": "OnlineResourceWatcher", - "permission": { "permission": 4, "category": null, "element": null }, - "parent": 1008001001, - "children": [] } ] } diff --git a/Admin/Install/db.json b/Admin/Install/db.json index da6fc2b..c138696 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -79,33 +79,43 @@ } } }, - "orw_resource_check": { - "name": "orw_resource_check", + "orw_resource_report": { + "name": "orw_resource_report", "fields": { - "orw_resource_check_id": { - "name": "orw_resource_check_id", + "orw_resource_report_id": { + "name": "orw_resource_report_id", "type": "INT", "null": false, "primary": true, "autoincrement": true }, - "orw_resource_check_status": { - "name": "orw_resource_check_status", + "orw_resource_report_status": { + "name": "orw_resource_report_status", "type": "TINYINT", "null": false }, - "orw_resource_check_change": { - "name": "orw_resource_check_change", + "orw_resource_report_metric": { + "name": "orw_resource_report_metric", + "type": "INT", + "null": false + }, + "orw_resource_report_path": { + "name": "orw_resource_report_path", + "type": "VARCHAR(255)", + "null": false + }, + "orw_resource_report_change": { + "name": "orw_resource_report_change", "type": "TEXT", "null": false }, - "orw_resource_check_created_at": { - "name": "orw_resource_check_created_at", + "orw_resource_report_created_at": { + "name": "orw_resource_report_created_at", "type": "DATETIME", "null": false }, - "orw_resource_check_resource": { - "name": "orw_resource_check_resource", + "orw_resource_report_resource": { + "name": "orw_resource_report_resource", "type": "INT", "null": true, "default": null, diff --git a/Admin/Installer.php b/Admin/Installer.php index af2dfcc..6e2a786 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -14,7 +14,10 @@ declare(strict_types=1); namespace Modules\OnlineResourceWatcher\Admin; +use phpOMS\Application\ApplicationAbstract; +use phpOMS\Config\SettingsInterface; use phpOMS\Module\InstallerAbstract; +use phpOMS\Module\ModuleInfo; /** * Installer class. @@ -33,4 +36,16 @@ final class Installer extends InstallerAbstract * @since 1.0.0 */ public const PATH = __DIR__; + + /** + * {@inheritdoc} + */ + public static function install(ApplicationAbstract $app, ModuleInfo $info, SettingsInterface $cfgHandler) : void + { + parent::install($app, $info, $cfgHandler); + + if (!\is_dir(__DIR__ . '/../Files')) { + mkdir(__DIR__ . '/../Files'); + } + } } diff --git a/Admin/Routes/Console.php b/Admin/Routes/Console.php new file mode 100644 index 0000000..599bccf --- /dev/null +++ b/Admin/Routes/Console.php @@ -0,0 +1,31 @@ + [ + [ + 'dest' => '\Modules\OnlineResourceWatcher\Controller\ApiController:apiCheckResources', + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::CREATE, + 'state' => PermissionCategory::RESOURCE, + ], + ], + ] +]; \ No newline at end of file diff --git a/Admin/Routes/Web/Backend.php b/Admin/Routes/Web/Backend.php index 913e10b..709e173 100755 --- a/Admin/Routes/Web/Backend.php +++ b/Admin/Routes/Web/Backend.php @@ -18,9 +18,9 @@ use phpOMS\Account\PermissionType; use phpOMS\Router\RouteVerb; return [ - '^.*/news/dashboard.*$' => [ + '^.*/orw/resource/list.*$' => [ [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherDashboard', + 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewResourceList', 'verb' => RouteVerb::GET, 'permission' => [ 'module' => BackendController::NAME, @@ -29,9 +29,9 @@ return [ ], ], ], - '^.*/news/article.*$' => [ + '^.*/orw/resource\?.*$' => [ [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherArticle', + 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewResource', 'verb' => RouteVerb::GET, 'permission' => [ 'module' => BackendController::NAME, @@ -40,31 +40,9 @@ return [ ], ], ], - '^.*/news/archive.*$' => [ + '^.*/orw/resource/create.*$' => [ [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherArchive', - 'verb' => RouteVerb::GET, - 'permission' => [ - 'module' => BackendController::NAME, - 'type' => PermissionType::READ, - 'state' => PermissionCategory::RESOURCE, - ], - ], - ], - '^.*/news/draft/list.*$' => [ - [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherDraftList', - 'verb' => RouteVerb::GET, - 'permission' => [ - 'module' => BackendController::NAME, - 'type' => PermissionType::MODIFY, - 'state' => PermissionCategory::RESOURCE, - ], - ], - ], - '^.*/news/create.*$' => [ - [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherCreate', + 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewResourceCreate', 'verb' => RouteVerb::GET, 'permission' => [ 'module' => BackendController::NAME, @@ -73,9 +51,9 @@ return [ ], ], ], - '^.*/news/edit.*$' => [ + '^.*/orw/resource/report/list.*$' => [ [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherEdit', + 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewReportList', 'verb' => RouteVerb::GET, 'permission' => [ 'module' => BackendController::NAME, @@ -84,9 +62,9 @@ return [ ], ], ], - '^.*/news/analysis.*$' => [ + '^.*/orw/resource/report\?.*$' => [ [ - 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewOnlineResourceWatcherAnalysis', + 'dest' => '\Modules\OnlineResourceWatcher\Controller\BackendController:viewReport', 'verb' => RouteVerb::GET, 'permission' => [ 'module' => BackendController::NAME, diff --git a/Controller/ApiController.php b/Controller/ApiController.php index b741988..4665c93 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -17,12 +17,19 @@ namespace Modules\OnlineResourceWatcher\Controller; use Modules\Admin\Models\NullAccount; use Modules\OnlineResourceWatcher\Models\Resource; use Modules\OnlineResourceWatcher\Models\ResourceMapper; +use Modules\OnlineResourceWatcher\Models\Report; +use Modules\OnlineResourceWatcher\Models\ReportStatus; +use Modules\OnlineResourceWatcher\Models\ReportMapper; +use Modules\OnlineResourceWatcher\Models\ResourceStatus; use phpOMS\Message\Http\RequestStatusCode; use phpOMS\Message\NotificationLevel; use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; use phpOMS\Model\Message\FormValidation; use phpOMS\System\SystemUtils; +use phpOMS\System\File\Local\Directory; +use phpOMS\Utils\StringUtils; +use phpOMS\Utils\ImageUtils; /** * OnlineResourceWatcher controller class. @@ -103,7 +110,7 @@ final class ApiController extends Controller // @todo: check if user is part of organization below AND has free resources to add!!! $resource->organization = new NullAccount( empty($request->getData('organization')) - ? $request->header->account + ? 1 : (int) ($request->getData('organization')) ); @@ -125,11 +132,249 @@ final class ApiController extends Controller */ public function apiCheckResources(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void { - SystemUtils::runProc( - __DIR__ . '/server/bin/OnlineResourceWatcherServerApp', '' - ); + $resources = ResourceMapper::getAll() + ->where('status', ResourceStatus::ACTIVE) + ->execute(); - $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Resources', 'Resources are getting checked.', null); + $toCheck = []; + + $basePath = __DIR__ . '/../Files'; + Directory::delete($basePath . '/temp'); + + if (!\is_dir($basePath . '/temp')) { + \mkdir($basePath . '/temp'); + } + + // Load resources + foreach ($resources as $resource) { + $path = $basePath . '/'; + $timestamp = \time(); + + $path .= 'temp/' . $resource->getId() . '/' . $timestamp; + $toCheck[] = [ + 'resource' => $resource, + 'timestamp' => $timestamp, + 'path' => $path, + 'handled' => false, + 'loop' => 0, + ]; + + SystemUtils::runProc( + 'wget', + '--retry-connrefused --waitretry=1 --read-timeout=10 --timeout=10 --dns-timeout=10 -t 2 --quota=25m --adjust-extension --span-hosts --convert-links --page-requisites --no-directories --restrict-file-names=windows --no-parent ‐‐execute robots=off --limit-rate=5m --accept css,png,jpg,jpeg,gif,htm,html,txt,md,pdf,xls,xlsx,doc,docx --directory-prefix=' . $path . ' ‐‐output-document=index.html ' . $resource->uri, + true + ); + } + + // Check downloaded resources + // @todo: this may not work correctly because the download runs async. + $totalCount = \count($toCheck); + + // @todo: the following code is INSANE, simplify!!! + $baseLen = \strlen($basePath . '/temp'); + while (!empty($toCheck)) { + foreach ($toCheck as $index => $check) { + ++$toCheck[$index]['loop']; + $resource = $check['resource']; + + // too many tries + if ($check['loop'] > 60 * 10) { + $report = new Report(); + $report->resource = $resource->getId(); + $report->versionPath = (string) $check['timestamp']; + $report->status = ReportStatus::DOWNLOAD_ERROR; + + ReportMapper::create()->execute($report); + + $resource->checkedAt = $report->createdAt; + ResourceMapper::update()->execute($resource); + + unset($toCheck[$index]); + + continue; + } + + $path = $check['path']; + if (!\is_dir($path)) { + // Either the download takes too long or the download failed! + continue; + } + + $end = \stripos($path, '/', $baseLen + 1); + $id = (int) \substr($path, $baseLen + 1, $end - $baseLen - 1); + + // new resource + if ($check['loop'] === 60 * 10 && !\is_dir($basePath . '/' . $id)) { + $filesNew = \scandir($path); + + $fileName = ''; + if (in_array('index.htm', $filesNew) || \in_array('index.html', $filesNew)) { + $fileName = \in_array('index.htm', $filesNew) ? 'index.htm' : 'index.html'; + } else { + foreach ($filesNew as $file) { + if (StringUtils::endsWith($file, '.png') + || StringUtils::endsWith($file, '.jpg') + || StringUtils::endsWith($file, '.jpeg') + || StringUtils::endsWith($file, '.gif') + || StringUtils::endsWith($file, '.pdf') + || StringUtils::endsWith($file, '.doc') + || StringUtils::endsWith($file, '.docx') + || StringUtils::endsWith($file, '.xls') + || StringUtils::endsWith($file, '.xlsx') + || StringUtils::endsWith($file, '.md') + || StringUtils::endsWith($file, '.txt') + ) { + $fileName = $file; + break; + } + } + } + + $report = new Report(); + $report->resource = $resource->getId(); + $report->versionPath = (string) $check['timestamp']; + + $hash = ''; + if (!empty($fileName)) { + $report->status = ReportStatus::ADDED; + $hash = \md5_file($path . '/' . $fileName); + } else { + $report->status = ReportStatus::DOWNLOAD_ERROR; + } + + ReportMapper::create()->execute($report); + + $resource->path = (string) $resource->getId(); + $resource->lastVersionPath = (string) $check['timestamp']; + $resource->lastVersionDate = $report->createdAt; + $resource->hash = $hash; + $resource->checkedAt = $report->createdAt; + ResourceMapper::update()->execute($resource); + + Directory::copy($path, $basePath . '/' . $id . '/' . $check['timestamp']); + unset($toCheck[$index]); + + continue; + } + + if (!\is_dir($basePath . '/' . $id)) { + continue; + } + + // existing resource + $resourcePaths = \scandir($basePath . '/' . $id); + \natsort($resourcePaths); + + $lastVersionTimestamp = \end($resourcePaths); + if ($lastVersionTimestamp === '.' && $lastVersionTimestamp === '..') { + $lastVersionTimestamp = \reset($resourcePaths); + + if ($lastVersionTimestamp === '.' && $lastVersionTimestamp === '..') { + Directory::delete($basePath . '/' . $id); + } + } + + $lastVersionPath = $basePath . '/' . $id . '/' . $lastVersionTimestamp; + + $filesNew = \scandir($path); + + // Using this because the index.htm gets created last and at the time of the check below it may not yet exist. + $filesOld = \scandir($lastVersionPath); + + $oldPath = ''; + $newPath = ''; + $extension = ''; + + if (\in_array('index.htm', $filesOld) || \in_array('index.html', $filesOld) + || \in_array('index.htm', $filesNew) || \in_array('index.html', $filesNew) + ) { + $extension = \in_array('index.htm', $filesOld) ? 'htm' : 'html'; + $oldPath = $lastVersionPath . '/index.' . $extension; + $newPath = $path . '/index.' . $extension; + + $toCheck[$index]['handled'] = true; + } else { + foreach ($filesNew as $file) { + if (StringUtils::endsWith($file, '.png') + || StringUtils::endsWith($file, '.jpg') + || StringUtils::endsWith($file, '.jpeg') + || StringUtils::endsWith($file, '.gif') + || StringUtils::endsWith($file, '.pdf') + || StringUtils::endsWith($file, '.doc') + || StringUtils::endsWith($file, '.docx') + || StringUtils::endsWith($file, '.xls') + || StringUtils::endsWith($file, '.xlsx') + || StringUtils::endsWith($file, '.md') + || StringUtils::endsWith($file, '.txt') + ) { + $oldPath = $lastVersionPath . '/' . $file; + $newPath = $path . '/' . $file; + $extension = \substr($file, \strripos($file, '.') + 1); + + $toCheck[$index]['handled'] = true; + + break; + } + } + } + + if (!\is_file($newPath) || !$toCheck[$index]['handled']) { + continue; + } + + $md5Old = $resource->hash; + $md5New = \md5_file($newPath); + $hasDifferentHash = $md5Old !== $md5New; + + // @todo: check if old path exists and if not, don't calculate a diff + + $difference = 0; + if ($hasDifferentHash) { + if (\in_array($extension, ['md', 'txt', 'doc', 'docx', 'pdf', 'xls', 'xlsx'])) { + $contentOld = \Modules\Media\Controller\ApiController::loadFileContent($oldPath); + $contentNew = \Modules\Media\Controller\ApiController::loadFileContent($newPath); + + $difference = \levenshtein($contentOld, $contentNew); + } elseif (\in_array($extension, ['png', 'jpg', 'jpeg', 'gif'])) { + $difference = ImageUtils::difference($oldPath, $newPath, $path . '/_' . $file, 0); + } + } + + $report = new Report(); + $report->resource = $resource->getId(); + $report->versionPath = (string) $check['timestamp']; + $report->changeMetric = $difference; + + if ($difference !== 0) { + $report->status = ReportStatus::CHANGE; + + $resource->path = (string) $resource->getId(); + $resource->lastVersionPath = (string) $check['timestamp']; + $resource->lastVersionDate = $report->createdAt; + $resource->hash = $md5New; + + Directory::copy($path, $basePath . '/' . $id . '/' . $check['timestamp']); + } + + ReportMapper::create()->execute($report); + + $resource->checkedAt = $report->createdAt; + ResourceMapper::update()->execute($resource); + + Directory::delete($basePath . '/temp/' . $id); + + // @todo: delete older history depending on plan + // @todo: inform users + + unset($toCheck[$index]); + } + + \sleep(1); + } + + Directory::delete($basePath . '/temp'); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Resources', 'Resources were checked.', null); } /** diff --git a/Controller/BackendController.php b/Controller/BackendController.php index b35d947..5d00cf1 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -14,7 +14,7 @@ declare(strict_types=1); namespace Modules\OnlineResourceWatcher\Controller; -use Modules\Auditor\Models\AuditMapper; +use Modules\OnlineResourceWatcher\Models\ResourceMapper; use phpOMS\Contract\RenderableInterface; use phpOMS\DataStorage\Database\Query\OrderType; use phpOMS\Message\RequestAbstract; @@ -44,7 +44,116 @@ final class BackendController extends Controller * @since 1.0.0 * @codeCoverageIgnore */ - public function viewOnlineResourceWatcherDashboard(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + public function viewResourceList(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/OnlineResourceWatcher/Theme/Backend/resource-list'); + + /* Table functionality */ + + $searchFieldData = $request->getLike('.*\-p\-.*'); + $searchField = []; + foreach ($searchFieldData as $key => $data) { + if ($data === '1') { + $split = \explode('-', $key); + $member = \end($split); + + $searchField[] = $member; + } + } + + $filterFieldData = $request->getLike('.*\-f\-.*?\-t'); + $filterField = []; + foreach ($filterFieldData as $key => $type) { + $split = \explode('-', $key); + \end($split); + + $member = \prev($split); + + if (!empty($request->getData('organizationUserList-f-' . $member . '-f1'))) { + $filterField[$member] = [ + 'type' => $type, + 'value1' => $request->getData('organizationUserList-f-' . $member . '-f1'), + 'logic1' => $request->getData('organizationUserList-f-' . $member . '-o1'), + 'value2' => $request->getData('organizationUserList-f-' . $member . '-f2'), + 'logic2' => $request->getData('organizationUserList-f-' . $member . '-o2'), + ]; + } + } + + $pageLimit = 25; + $view->addData('pageLimit', $pageLimit); + + $mapper = ResourceMapper::getAll()->with('createdBy'); + $list = ResourceMapper::find( + search: $request->getData('search'), + mapper: $mapper, + id: (int) ($request->getData('id') ?? 0), + secondaryId: (string) ($request->getData('subid') ?? ''), + type: $request->getData('pType'), + pageLimit: empty((int) ($request->getData('limit') ?? 0)) ? 100 : ((int) $request->getData('limit')), + sortBy: $request->getData('sort_by') ?? '', + sortOrder: $request->getData('sort_order') ?? OrderType::DESC, + searchFields: $searchField, + filters: $filterField + ); + + $view->setData('resources', $list['data']); + + $tableView = new TableView($this->app->l11nManager, $request, $response); + $tableView->module = 'OnlineResourceWatcher'; + $tableView->theme = 'Backend'; + $tableView->setTitleTemplate('/Web/Backend/Themes/table-title'); + $tableView->setColumnHeaderElementTemplate('/Web/Backend/Themes/header-element-table'); + $tableView->setFilterTemplate('/Web/Backend/Themes/popup-filter-table'); + $tableView->setSortTemplate('/Web/Backend/Themes/sort-table'); + $tableView->setData('hasPrevious', $list['hasPrevious']); + $tableView->setData('hasNext', $list['hasNext']); + + $view->addData('tableView', $tableView); + + return $view; + } + + /** + * Routing end-point for application behaviour. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return RenderableInterface Returns a renderable object + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewResource(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/OnlineResourceWatcher/Theme/Backend/resource-single'); + + $resource = ResourceMapper::get() + ->where('id', (int) $request->getData('id')) + ->execute(); + + $view->setData('resource', $resource); + + return $view; + } + + /** + * Routing end-point for application behaviour. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return RenderableInterface Returns a renderable object + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewResourceCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface { $view = new View($this->app->l11nManager, $request, $response); @@ -63,7 +172,7 @@ final class BackendController extends Controller * @since 1.0.0 * @codeCoverageIgnore */ - public function viewOnlineResourceWatcherArticle(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + public function viewReportList(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface { $view = new View($this->app->l11nManager, $request, $response); @@ -82,83 +191,7 @@ final class BackendController extends Controller * @since 1.0.0 * @codeCoverageIgnore */ - public function viewOnlineResourceWatcherArchive(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface - { - $view = new View($this->app->l11nManager, $request, $response); - - return $view; - } - - /** - * Routing end-point for application behaviour. - * - * @param RequestAbstract $request Request - * @param ResponseAbstract $response Response - * @param mixed $data Generic data - * - * @return RenderableInterface Returns a renderable object - * - * @since 1.0.0 - * @codeCoverageIgnore - */ - public function viewOnlineResourceWatcherDraftList(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface - { - $view = new View($this->app->l11nManager, $request, $response); - - return $view; - } - - /** - * Routing end-point for application behaviour. - * - * @param RequestAbstract $request Request - * @param ResponseAbstract $response Response - * @param mixed $data Generic data - * - * @return RenderableInterface Returns a renderable object - * - * @since 1.0.0 - * @codeCoverageIgnore - */ - public function viewOnlineResourceWatcherCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface - { - $view = new View($this->app->l11nManager, $request, $response); - - return $view; - } - - /** - * Routing end-point for application behaviour. - * - * @param RequestAbstract $request Request - * @param ResponseAbstract $response Response - * @param mixed $data Generic data - * - * @return RenderableInterface Returns a renderable object - * - * @since 1.0.0 - * @codeCoverageIgnore - */ - public function viewOnlineResourceWatcherEdit(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface - { - $view = new View($this->app->l11nManager, $request, $response); - - return $view; - } - - /** - * Routing end-point for application behaviour. - * - * @param RequestAbstract $request Request - * @param ResponseAbstract $response Response - * @param mixed $data Generic data - * - * @return RenderableInterface Returns a renderable object - * - * @since 1.0.0 - * @codeCoverageIgnore - */ - public function viewOnlineResourceWatcherAnalysis(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + public function viewReport(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface { $view = new View($this->app->l11nManager, $request, $response); diff --git a/Models/NullReport.ph b/Models/NullReport.ph new file mode 100644 index 0000000..df6bfc2 --- /dev/null +++ b/Models/NullReport.ph @@ -0,0 +1,47 @@ +id = $id; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return ['id' => $this->id]; + } +} diff --git a/Models/NullResource.php b/Models/NullResource.php new file mode 100644 index 0000000..24ec638 --- /dev/null +++ b/Models/NullResource.php @@ -0,0 +1,47 @@ +id = $id; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return ['id' => $this->id]; + } +} diff --git a/Models/Report.php b/Models/Report.php new file mode 100644 index 0000000..2023f8b --- /dev/null +++ b/Models/Report.php @@ -0,0 +1,87 @@ +createdAt = new \DateTimeImmutable('now'); + } + + /** + * {@inheritdoc} + */ + public function toArray() : array + { + return [ + 'id' => $this->id, + 'createdAt' => $this->createdAt, + 'resource' => $this->resource, + 'status' => $this->status, + 'changemetric' => $this->changeMetric, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return $this->toArray(); + } +} diff --git a/Models/ReportMapper.php b/Models/ReportMapper.php new file mode 100644 index 0000000..4734a69 --- /dev/null +++ b/Models/ReportMapper.php @@ -0,0 +1,61 @@ + + * @since 1.0.0 + */ + public const COLUMNS = [ + 'orw_resource_report_id' => ['name' => 'orw_resource_report_id', 'type' => 'int', 'internal' => 'id'], + 'orw_resource_report_status' => ['name' => 'orw_resource_report_status', 'type' => 'int', 'internal' => 'status',], + 'orw_resource_report_metric' => ['name' => 'orw_resource_report_metric', 'type' => 'int', 'internal' => 'changeMetric',], + 'orw_resource_report_path' => ['name' => 'orw_resource_report_path', 'type' => 'string', 'internal' => 'versionPath',], + 'orw_resource_report_change' => ['name' => 'orw_resource_report_change', 'type' => 'string', 'internal' => 'change',], + 'orw_resource_report_resource' => ['name' => 'orw_resource_report_resource', 'type' => 'int', 'internal' => 'resource',], + 'orw_resource_report_created_at' => ['name' => 'orw_resource_report_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt',], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'orw_resource_report'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD ='orw_resource_report_id'; +} diff --git a/Models/ReportStatus.php b/Models/ReportStatus.php new file mode 100644 index 0000000..86f2391 --- /dev/null +++ b/Models/ReportStatus.php @@ -0,0 +1,36 @@ +status; + } + /** * {@inheritdoc} */ diff --git a/Theme/Backend/Lang/Navigation.en.lang.php b/Theme/Backend/Lang/Navigation.en.lang.php new file mode 100644 index 0000000..a1eca9f --- /dev/null +++ b/Theme/Backend/Lang/Navigation.en.lang.php @@ -0,0 +1,17 @@ + [ + 'OnlineResourceWatcher' => 'Online Resource Watcher', +]]; diff --git a/Theme/Backend/admin-bills.tpl.php b/Theme/Backend/admin-bills.tpl.php deleted file mode 100755 index ccb5f54..0000000 --- a/Theme/Backend/admin-bills.tpl.php +++ /dev/null @@ -1,111 +0,0 @@ -getData('audits') ?? []; - -$tableView = $this->getData('tableView'); -$tableView->id = 'auditList'; -$tableView->baseUri = '{/prefix}admin/audit/list'; -$tableView->setObjects($audits); - -$previous = $tableView->getPreviousLink( - $this->request, - empty($this->objects) || !$this->getData('hasPrevious') ? null : \reset($this->objects) -); - -$next = $tableView->getNextLink( - $this->request, - empty($this->objects) ? null : \end($this->objects), - $this->getData('hasNext') ?? false -); - -?> -
- Jingga
-
-
-