diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 39a9954..66ea7a4 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -1,5 +1,5 @@ { - "workflow": { + "workflow_template": { "name": "workflow_template", "fields": { "workflow_template_id": { @@ -26,8 +26,21 @@ "default": null, "null": true }, - "workflow_template_created": { - "name": "workflow_template_created", + "workflow_template_descRaw": { + "name": "workflow_template_descRaw", + "type": "TEXT", + "default": null, + "null": true + }, + "workflow_template_media": { + "name": "workflow_template_media", + "type": "INT", + "null": false, + "foreignTable": "media", + "foreignKey": "media_id" + }, + "workflow_template_created_at": { + "name": "workflow_template_created_at", "type": "DATETIME", "null": false }, @@ -40,34 +53,34 @@ } } }, - "workflow_template_media": { - "name": "workflow_template_media", + "workflow_instance": { + "name": "workflow_instance", "fields": { - "workflow_template_media_id": { - "name": "workflow_template_media_id", + "workflow_instance_id": { + "name": "workflow_instance_id", "type": "INT", "null": false, "primary": true, "autoincrement": true }, - "workflow_template_media_media": { - "name": "workflow_template_media_media", - "type": "INT", - "null": false, - "foreignTable": "media", - "foreignKey": "media_id" - }, - "workflow_template_media_workflow": { - "name": "workflow_template_media_workflow", + "workflow_instance_template": { + "name": "workflow_instance_template", "type": "INT", "null": false, "foreignTable": "workflow_template", "foreignKey": "workflow_template_id" }, - "workflow_template_media_type": { - "name": "workflow_template_media_type", - "type": "TINYINT", + "workflow_instance_created_at": { + "name": "workflow_instance_created_at", + "type": "DATETIME", "null": false + }, + "workflow_instance_created_by": { + "name": "workflow_instance_created_by", + "type": "INT", + "null": false, + "foreignTable": "account", + "foreignKey": "account_id" } } } diff --git a/Controller/ApiController.php b/Controller/ApiController.php index 069f085..0b75fb2 100644 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -20,6 +20,8 @@ use Modules\Media\Models\CollectionMapper; use Modules\Media\Models\NullCollection; use Modules\Media\Models\NullMedia; use Modules\Workflow\Models\PermissionCategory; +use Modules\Workflow\Models\WorkflowInstance; +use Modules\Workflow\Models\WorkflowInstanceMapper; use Modules\Workflow\Models\WorkflowTemplate; use Modules\Workflow\Models\WorkflowTemplateMapper; use phpOMS\Account\PermissionType; @@ -33,6 +35,9 @@ use phpOMS\Message\ResponseAbstract; use phpOMS\Model\Message\FormValidation; use phpOMS\System\MimeType; use phpOMS\System\SystemUtils; +use phpOMS\Utils\Parser\Markdown\Markdown; +use phpOMS\Utils\StringUtils; +use phpOMS\Views\View; /** * Workflow controller class. @@ -66,13 +71,11 @@ final class ApiController extends Controller return; } - /** @var Template $template */ - $template = WorkflowTemplateMapper::get() - ->with('source') - ->with('source/sources') - ->with('reports') - ->with('reports/source') - ->with('reports/source/sources') + /** @var WorkflowInstance $instance */ + $instance = WorkflowInstanceMapper::get() + ->with('template') + ->with('template/source') + ->with('template/source/sources') ->with('createdBy') ->where('id', (int) $request->getData('id')) ->execute(); @@ -81,7 +84,7 @@ final class ApiController extends Controller $isExport = \in_array($request->getData('type'), ['xlsx', 'pdf', 'docx', 'pptx', 'csv', 'json']); // is allowed to read - if (!$this->app->accountManager->get($accountId)->hasPermission(PermissionType::READ, $this->app->orgId, null, self::NAME, PermissionCategory::REPORT, $template->getId()) + if (!$this->app->accountManager->get($accountId)->hasPermission(PermissionType::READ, $this->app->orgId, null, self::NAME, PermissionCategory::INSTANCE, $instance->getId()) || ($isExport && !$this->app->accountManager->get($accountId)->hasPermission(PermissionType::READ, $this->app->orgId, $this->app->appName, self::NAME, PermissionCategory::EXPORT)) ) { $response->header->status = RequestStatusCode::R_403; @@ -91,11 +94,11 @@ final class ApiController extends Controller if ($isExport) { Autoloader::addPath(__DIR__ . '/../../../Resources/'); - $response->header->setDownloadable($template->name, (string) $request->getData('type')); + $response->header->setDownloadable($instance->template->name, (string) $request->getData('type')); } - $view = $this->createView($template, $request, $response); - $this->setHelperResponseHeader($view, $template->name, $request, $response); + $view = $this->createView($instance, $request, $response); + $this->setHelperResponseHeader($view, $instance->template->name, $request, $response); $view->setData('path', __DIR__ . '/../../../'); $response->set('export', $view); @@ -203,7 +206,7 @@ final class ApiController extends Controller /** * Create view from template * - * @param Template $template Template to create view from + * @param WorkflowInstance $instance Instance to create view from * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @@ -213,11 +216,11 @@ final class ApiController extends Controller * * @since 1.0.0 */ - private function createView(Template $template, RequestAbstract $request, ResponseAbstract $response) : View + private function createView(WorkflowInstance $instance, RequestAbstract $request, ResponseAbstract $response) : View { /** @var array $tcoll */ $tcoll = []; - $files = $template->source->getSources(); + $files = $instance->source->getSources(); /** @var \Modules\Media\Models\Media $tMedia */ foreach ($files as $tMedia) { @@ -282,35 +285,11 @@ final class ApiController extends Controller } $view = new View($this->app->l11nManager, $request, $response); - if (!$template->isStandalone) { - /** @var Report $report */ - $report = ReportMapper::get() - ->with('template') - ->with('source') - ->with('source/sources') - ->where('template', $template->getId()) - ->sort('id', OrderType::DESC) - ->limit(1) - ->execute(); - - $rcoll = []; - $report = $report === false ? new NullReport() : $report; - - if (!($report instanceof NullReport)) { - $files = $report->source->getSources(); - - foreach ($files as $media) { - $rcoll[$media->name . '.' . $media->extension] = $media; - } - } - - $view->addData('report', $report); - $view->addData('rcoll', $rcoll); - } $view->addData('tcoll', $tcoll); $view->addData('lang', $request->getData('lang') ?? $request->getLanguage()); - $view->addData('template', $template); + $view->addData('instance', $instance); + $view->addData('template', $instance->template); $view->addData('basepath', __DIR__ . '/../../../'); return $view; @@ -387,23 +366,7 @@ final class ApiController extends Controller $template = $this->createTemplateFromRequest($request, $collection->getId()); - $this->app->moduleManager->get('Admin')->createAccountModelPermission( - new AccountPermission( - $request->header->account, - $this->app->orgId, - $this->app->appName, - self::NAME, - self::NAME, - PermissionCategory::TEMPLATE, - $template->getId(), - null, - PermissionType::READ | PermissionType::MODIFY | PermissionType::DELETE | PermissionType::PERMISSION, - ), - $request->header->account, - $request->getOrigin() - ); - - $this->createModel($request->header->account, $template, TemplateMapper::class, 'template', $request->getOrigin()); + $this->createModel($request->header->account, $template, WorkflowTemplateMapper::class, 'template', $request->getOrigin()); $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Template', 'Template successfully created', $template); } @@ -439,10 +402,8 @@ final class ApiController extends Controller */ private function createTemplateFromRequest(RequestAbstract $request, int $collectionId) : WorkflowTemplate { - $expected = $request->getData('expected'); - $workflowTemplate = new WorkflowTemplate(); - $workflowTemplate->name = $request->getData('name') ?? 'Empty'; + $workflowTemplate->name = $request->getData('name') ?? ''; $workflowTemplate->description = Markdown::parse((string) ($request->getData('description') ?? '')); $workflowTemplate->descriptionRaw = (string) ($request->getData('description') ?? ''); @@ -450,10 +411,7 @@ final class ApiController extends Controller $workflowTemplate->source = new NullCollection($collectionId); } - $workflowTemplate->isStandalone = (bool) ($request->getData('standalone') ?? false); - $workflowTemplate->setExpected(!empty($expected) ? \json_decode($expected, true) : []); $workflowTemplate->createdBy = new NullAccount($request->header->account); - $workflowTemplate->setDatatype((int) ($request->getData('datatype') ?? TemplateDataType::OTHER)); $workflowTemplate->virtualPath = (string) ($request->getData('virtualpath') ?? '/'); return $workflowTemplate; diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 8286308..79971b6 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -26,23 +26,6 @@ use phpOMS\Views\View; * @license OMS License 1.0 * @link https://karaka.app * @since 1.0.0 - * - * @todo Karaka/Modules#20 - * The workflow module can be used by other modules to register a workflow. - * The article management module for example could register a workflow for generating articles. - * This way multiple employees have to insert data and only after everything is done the article will be generated by the system itself. - * User permissions for creating an article would now get disabled and only allowed through this module. - * Other things that could be changing prices, customers etc. (essential tool for SOX and ISO and maybe even IFRS) - * This module would also make use of the task module to notify users that they have a task. - * At the same time actions such as changing a price could also create a workflow. - * If a user changes a price a workflow element for price changes gets triggered which now needs to be approved by authorized employees. - * Such modules now should add an additional tab for workflow steps. - * In this list a log of all workflows is displayed (pending, done, canceled). - * This way changes/events get forwarded to the workflow module and later the workflow decides what to do with these information - * (e.g. inserting these information into other modules etc). - * Instead of actually doing changes this can be extended further to only request something. - * E.g. a user could request a unlocking of a customer for invoicing by a simple button click and a credit manager only has to approve it. - * The workflow module now knows that the approval means to unlock the customer (maybe for only one invoice, limited time, value etc). */ final class BackendController extends Controller { diff --git a/Models/Components/Email.php b/Models/Components/Email.php deleted file mode 100755 index bfa4829..0000000 --- a/Models/Components/Email.php +++ /dev/null @@ -1,15 +0,0 @@ -id = $id; + parent::__construct(); + } +} diff --git a/Models/NullWorkflowTemplate.php b/Models/NullWorkflowTemplate.php new file mode 100644 index 0000000..3b39feb --- /dev/null +++ b/Models/NullWorkflowTemplate.php @@ -0,0 +1,39 @@ +id = $id; + parent::__construct(); + } +} diff --git a/Models/PermissionCategory.php b/Models/PermissionCategory.php index 95a963f..8cb3bd5 100755 --- a/Models/PermissionCategory.php +++ b/Models/PermissionCategory.php @@ -26,7 +26,7 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class PermissionCategory extends Enum { - public const WORKFLOW = 1; + public const INSTANCE = 1; public const TEMPLATE = 2; diff --git a/Models/WorkflowInstance.php b/Models/WorkflowInstance.php new file mode 100644 index 0000000..f6f635c --- /dev/null +++ b/Models/WorkflowInstance.php @@ -0,0 +1,85 @@ +template = new NullWorkflowTemplate(); + $this->createdBy = new NullAccount(); + $this->createdAt = new \DateTimeImmutable('now'); + } + + /** + * Get id + * + * @return int + * + * @since 1.0.0 + */ + public function getId() : int + { + return $this->id; + } +} diff --git a/Models/WorkflowInstanceMapper.php b/Models/WorkflowInstanceMapper.php new file mode 100644 index 0000000..5250ad6 --- /dev/null +++ b/Models/WorkflowInstanceMapper.php @@ -0,0 +1,89 @@ + + * @since 1.0.0 + */ + public const COLUMNS = [ + 'workflow_instance_id' => ['name' => 'workflow_instance_id', 'type' => 'int', 'internal' => 'id'], + 'workflow_instance_template' => ['name' => 'workflow_instance_template', 'type' => 'int', 'internal' => 'template'], + 'workflow_instance_created_at' => ['name' => 'workflow_instance_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true], + 'workflow_instance_created_by' => ['name' => 'workflow_instance_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true], + ]; + + /** + * Belongs to. + * + * @var array + * @since 1.0.0 + */ + public const BELONGS_TO = [ + 'createdBy' => [ + 'mapper' => AccountMapper::class, + 'external' => 'workflow_instance_created_by', + ], + 'template' => [ + 'mapper' => WorkflowTemplateMapper::class, + 'external' => 'workflow_instance_template', + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'workflow_instance'; + + /** + * Created at. + * + * @var string + * @since 1.0.0 + */ + public const CREATED_AT = 'workflow_instance_created_at'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD ='workflow_instance_id'; +} diff --git a/Models/WorkflowTemplate.php b/Models/WorkflowTemplate.php index ab540c2..f5cd7df 100644 --- a/Models/WorkflowTemplate.php +++ b/Models/WorkflowTemplate.php @@ -16,6 +16,8 @@ namespace Modules\Workflow\Models; use Modules\Admin\Models\Account; use Modules\Admin\Models\NullAccount; +use Modules\Media\Models\Collection; +use Modules\Media\Models\NullCollection; /** * Workflow template class. @@ -35,6 +37,38 @@ class WorkflowTemplate */ protected int $id = 0; + /** + * Name. + * + * @var string + * @since 1.0.0 + */ + public string $name = ''; + + /** + * Description. + * + * @var string + * @since 1.0.0 + */ + public string $description = ''; + + /** + * Description. + * + * @var string + * @since 1.0.0 + */ + public string $descriptionRaw = ''; + + /** + * Status. + * + * @var string + * @since 1.0.0 + */ + public int $status = WorkflowTemplateStatus::ACTIVE; + /** * Creator. * @@ -51,6 +85,14 @@ class WorkflowTemplate */ public \DateTimeImmutable $createdAt; + /** + * Template source. + * + * @var Collection + * @since 1.0.0 + */ + public Collection $source; + /** * Constructor. * @@ -60,6 +102,7 @@ class WorkflowTemplate { $this->createdBy = new NullAccount(); $this->createdAt = new \DateTimeImmutable('now'); + $this->source = new NullCollection(); } /** diff --git a/Models/WorkflowTemplateMapper.php b/Models/WorkflowTemplateMapper.php index f64e0a6..5c2e2c3 100644 --- a/Models/WorkflowTemplateMapper.php +++ b/Models/WorkflowTemplateMapper.php @@ -15,13 +15,8 @@ declare(strict_types=1); namespace Modules\Workflow\Models; use Modules\Admin\Models\AccountMapper; -use Modules\Calendar\Models\ScheduleMapper; -use Modules\Media\Models\MediaMapper; -use Modules\Tag\Models\TagMapper; +use Modules\Media\Models\CollectionMapper; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; -use phpOMS\DataStorage\Database\Mapper\ReadMapper; -use phpOMS\DataStorage\Database\Query\Builder; -use phpOMS\DataStorage\Database\Query\Where; /** * Mapper class. @@ -41,7 +36,39 @@ final class WorkflowTemplateMapper extends DataMapperFactory */ public const COLUMNS = [ 'workflow_template_id' => ['name' => 'workflow_template_id', 'type' => 'int', 'internal' => 'id'], + 'workflow_template_status' => ['name' => 'workflow_template_status', 'type' => 'int', 'internal' => 'status'], + 'workflow_template_name' => ['name' => 'workflow_template_name', 'type' => 'string', 'internal' => 'name'], + 'workflow_template_desc' => ['name' => 'workflow_template_desc', 'type' => 'string', 'internal' => 'description'], + 'workflow_template_descRaw' => ['name' => 'workflow_template_descRaw', 'type' => 'string', 'internal' => 'descriptionRaw'], + 'workflow_template_media' => ['name' => 'workflow_template_media', 'type' => 'string', 'internal' => 'source'], 'workflow_template_created_at' => ['name' => 'workflow_template_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true], + 'workflow_template_created_by' => ['name' => 'workflow_template_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + public const OWNS_ONE = [ + 'source' => [ + 'mapper' => CollectionMapper::class, + 'external' => 'workflow_template_media', + ], + ]; + + /** + * Belongs to. + * + * @var array + * @since 1.0.0 + */ + public const BELONGS_TO = [ + 'createdBy' => [ + 'mapper' => AccountMapper::class, + 'external' => 'workflow_template_created_by', + ], ]; /** diff --git a/Models/WorkflowTemplateStatus.php b/Models/WorkflowTemplateStatus.php new file mode 100644 index 0000000..56719a2 --- /dev/null +++ b/Models/WorkflowTemplateStatus.php @@ -0,0 +1,32 @@ +con = $con; - } - - /** - * Execute the workflow - * - * @return int - * - * @since 1.0.0 - */ - public function run($data) : int - { - switch ($this->state) { - case States::DEFAULT: - $this->state = $this->runRequest($data); - break; - case States::PENDING: - $this->state = $this->runPending($data); - break; - default: - } - - return $this->state; - } - - /** - * Run tasks during the request - * - * @return int - * - * @since 1.0.0 - */ - public function runRequest($data) : int - { - // create workflow - // create task - // set state - - return 0; - } - - /** - * Run tasks after the status change from pending - * - * The next status could be a new request, an approval or dismissal - * - * @return int - * - * @since 1.0.0 - */ - public function runPending($data) : int - { - // approve?! - - return 0; - } - - /** - * Get the state of the workflow - * - * @return int - * - * @since 1.0.0 - */ - public function getState() : int - { - return $this->state; - } -} diff --git a/Templates/Permission/permission-info.tpl.php b/Templates/Permission/permission-info.tpl.php deleted file mode 100755 index e69de29..0000000 diff --git a/Templates/Permission/template.tpl.php b/Templates/Permission/template.tpl.php deleted file mode 100755 index e69de29..0000000