bug fixes from the day before

This commit is contained in:
Dennis Eichhorn 2022-03-19 00:02:44 +01:00
parent 09e3dc0336
commit 9f08680c77
19 changed files with 414 additions and 334 deletions

View File

@ -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"
}
}
}

View File

@ -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<string, \Modules\Media\Models\Media|\Modules\Media\Models\Media[]> $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;

View File

@ -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
{

View File

@ -1,15 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Models\Components
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
// Create email on workflow change

View File

@ -1,15 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Models\Components
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
// Trigger event on workflow change

View File

@ -1,15 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Models\Components
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
// Create/update task/task element on workflow change

View File

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

View File

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

View File

@ -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;

View File

@ -0,0 +1,85 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Workflow\Models;
use Modules\Admin\Models\Account;
use Modules\Admin\Models\NullAccount;
/**
* Workflow instance class.
*
* @package Modules\Workflow\Models
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
class WorkflowInstance
{
/**
* ID.
*
* @var int
* @since 1.0.0
*/
protected int $id = 0;
/**
* Template.
*
* @var WorkflowTemplate
* @since 1.0.0
*/
public WorkflowTemplate $template;
/**
* Creator.
*
* @var Account
* @since 1.0.0
*/
public Account $createdBy;
/**
* Created.
*
* @var \DateTimeImmutable
* @since 1.0.0
*/
public \DateTimeImmutable $createdAt;
/**
* Constructor.
*
* @since 1.0.0
*/
public function __construct()
{
$this->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;
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
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 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.
*
* @package Modules\Workflow\Models
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
final class WorkflowInstanceMapper 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 = [
'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<string, array{mapper:string, external:string}>
* @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';
}

View File

@ -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();
}
/**

View File

@ -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<string, array{mapper:string, external:string, by?:string, column?:string, conditional?:bool}>
* @since 1.0.0
*/
public const OWNS_ONE = [
'source' => [
'mapper' => CollectionMapper::class,
'external' => 'workflow_template_media',
],
];
/**
* Belongs to.
*
* @var array<string, array{mapper:string, external:string}>
* @since 1.0.0
*/
public const BELONGS_TO = [
'createdBy' => [
'mapper' => AccountMapper::class,
'external' => 'workflow_template_created_by',
],
];
/**

View File

@ -0,0 +1,32 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Workflow\Models;
use phpOMS\Stdlib\Base\Enum;
/**
* Bill status enum.
*
* @package Modules\Workflow\Models
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
abstract class WorkflowTemplateStatus extends Enum
{
public const ACTIVE = 1;
public const INACTIVE = 2;
}

View File

@ -1,34 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Templates\Permission
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Workflow\Templates\Permission;
use phpOMS\Stdlib\Base\Enum;
/**
* Permission status enum.
*
* @package Modules\Workflow\Templates\Permission
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
abstract class PermissionStatus extends Enum
{
public const PENDING = 1;
public const APPROVED = 2;
public const DISMISSED = 3;
}

View File

@ -1,36 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow\Templates\Permission
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Workflow\Templates\Permission;
use phpOMS\Stdlib\Base\Enum;
/**
* Permission status enum.
*
* @package Modules\Workflow\Templates\Permission
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
abstract class States extends Enum
{
public const DEFAULT = 0;
public const PENDING = 1;
public const APPROVED = 2;
public const DISMISSED = 3;
}

View File

@ -1,113 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.0
*
* @package Modules\Workflow
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://karaka.app
*/
declare(strict_types=1);
namespace Modules\Workflow\Templates\Permission;
use Modules\Workflow\Models\WorkflowInterface;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
/**
* Workflow class.
*
* @package Modules\Workflow
* @license OMS License 1.0
* @link https://karaka.app
* @since 1.0.0
*/
class Workflow implements WorkflowInterface
{
private $id = 0;
private $state = 0;
private $con = null;
/**
* Constructor.
*
* @param ConnectionAbstract $con Database connection
*
* @since 1.0.0
*/
public function __construct(ConnectionAbstract $con)
{
$this->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;
}
}