diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 878b6c6..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,25 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file, in reverse chronological order by release. - -## 1.0.0 - TBD - -### Added - -- Its a composer package now - -### Changed - -- 100% of 0.9.x Codebase - -### Deprecated - -- 100% of 0.9.x Codebase - -### Removed - -- 100% of 0.9.x Codebase - -### Fixed - -- Removed dependencies diff --git a/composer.json b/composer.json index 595b1ab..7b01da7 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "mvc", "task", "oneplace", + "oneplace-module", "framework" ], "require-dev": { diff --git a/config/module.config.php b/config/module.config.php index 4be144a..93e9a4e 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -61,4 +61,16 @@ 'task' => __DIR__ . '/../view', ], ], + + # Translator + 'translator' => [ + 'locale' => 'de_DE', + 'translation_file_patterns' => [ + [ + 'type' => 'gettext', + 'base_dir' => __DIR__ . '/../language', + 'pattern' => '%s.mo', + ], + ], + ], ]; diff --git a/data/createmodulefromskeleton.ps1 b/data/createmodulefromskeleton.ps1 deleted file mode 100644 index 30b4edd..0000000 --- a/data/createmodulefromskeleton.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -$sModuleName = "Article" -$sModuleKey = "article" -$sTargetDir = "C:\Users\Praesidiarius\PhpstormProjects\OS\PLC_X_Article_NoGIT" - -# Copy Task -Copy-Item -Path "..\*" -Destination "$sTargetDir" -recurse -Force \ No newline at end of file diff --git a/data/install.sql b/data/install.sql index 158fa1e..3793cf5 100644 --- a/data/install.sql +++ b/data/install.sql @@ -29,7 +29,8 @@ INSERT INTO `permission` (`permission_key`, `module`, `label`, `nav_label`, `nav -- -- Form -- -INSERT INTO `core_form` (`form_key`, `label`) VALUES ('task-single', 'Task'); +INSERT INTO `core_form` (`form_key`, `label`, `entity_class`, `entity_tbl_class`) VALUES +('task-single', 'Task', 'OnePlace\\Task\\Model\\Task', 'OnePlace\\Task\\Model\\TaskTable'); -- -- Index List @@ -56,4 +57,11 @@ INSERT INTO `core_form_button` (`Button_ID`, `label`, `icon`, `title`, `href`, ` INSERT INTO `core_form_field` (`Field_ID`, `type`, `label`, `fieldkey`, `tab`, `form`, `class`, `url_view`, `url_ist`, `show_widget_left`, `allow_clear`, `readonly`, `tbl_cached_name`, `tbl_class`, `tbl_permission`) VALUES (NULL, 'text', 'Name', 'label', 'task-base', 'task-single', 'col-md-3', '/task/view/##ID##', '', 0, 1, 0, '', '', ''); +-- +-- Default Widgets +-- +INSERT INTO `core_widget` (`Widget_ID`, `widget_name`, `label`, `permission`) VALUES +(NULL, 'task_dailystats', 'Task - Daily Stats', 'index-Task\\Controller\\TaskController'), +(NULL, 'task_taginfo', 'Task - Tag Info', 'index-Task\\Controller\\TaskController'); + COMMIT; \ No newline at end of file diff --git a/docs/book/index.md b/docs/book/index.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/book/quick-start.md b/docs/book/quick-start.md deleted file mode 100644 index f118638..0000000 --- a/docs/book/quick-start.md +++ /dev/null @@ -1,28 +0,0 @@ -# Quick Start - -Now that you have basic knowledge of oneplace, we'll show you the easy way to get started. - -## Install onePlace Task - -The easiest way to get started is to install the task module via -Composer. - -If you have not yet done so, [install Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx). - -Go to the directory, where you installed oneplace core and run: - -```bash -$ composer require oneplace/oneplace-task -``` - -## Setup -Open the browser and login to your oneplace app. - -Go to /update - -You will see that a new module is detected and it needs db install. - -click "Update" - -now you have the module enabled and active. you can now add new fields / tabs -and manage permissions with the user module \ No newline at end of file diff --git a/language/de_DE.mo b/language/de_DE.mo new file mode 100644 index 0000000..0018dfd Binary files /dev/null and b/language/de_DE.mo differ diff --git a/language/de_DE.po b/language/de_DE.po new file mode 100644 index 0000000..7475098 --- /dev/null +++ b/language/de_DE.po @@ -0,0 +1,68 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2019-02-13 18:38+0100\n" +"PO-Revision-Date: 2020-01-30 18:54+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.4\n" +"X-Poedit-Basepath: .\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: de_DE\n" + +msgid "Model" +msgstr "Modell" + +msgid "Coolant" +msgstr "Kühlmittel" + +msgid "Internal" +msgstr "Intern" + +msgid "State" +msgstr "Status" + +msgid "Year of Construction" +msgstr "Baujahr" + +msgid "Origin" +msgstr "Ursprungsland" + +msgid "Categories" +msgstr "Kategorien" + +msgid "Condition" +msgstr "Zustand" + +msgid "Owner" +msgstr "Eigentümer" + +msgid "Loadbase" +msgstr "Frachtbasis" + +msgid "Specialaddons" +msgstr "Spezialzubehör" + +msgid "Description" +msgstr "Beschreibung" + +msgid "Created" +msgstr "Erstellt" + +msgid "Last Edited" +msgstr "Zuletzt bearbeitet" + +msgid "Edit Task" +msgstr "Task bearbeiten" + +msgid "Add Task" +msgstr "Task erfassen" + +msgid "Dates" +msgstr "Daten" + +msgid "Images" +msgstr "Bilder" diff --git a/language/en_US.mo b/language/en_US.mo new file mode 100644 index 0000000..b3f03cd Binary files /dev/null and b/language/en_US.mo differ diff --git a/language/en_US.po b/language/en_US.po new file mode 100644 index 0000000..e22de4b --- /dev/null +++ b/language/en_US.po @@ -0,0 +1,20 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2019-02-13 18:38+0100\n" +"PO-Revision-Date: 2020-01-30 18:55+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.4\n" +"X-Poedit-Basepath: .\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: en_US\n" + +msgid "Testmodell" +msgstr "Testmodel" + +msgid "Neue Location" +msgstr "New Location" diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index f590dff..0000000 --- a/mkdocs.yml +++ /dev/null @@ -1,15 +0,0 @@ -docs_dir: docs/book -site_dir: docs/html -nav: - - Home: index.md - - Introduction: intro.md - - 'Quick Start': quick-start.md - - Reference: - - 'Dynamic Fields': dynamic-fields.md - - Examples: examples.md -site_name: oneplace-task -site_description: "onePlace Application Task Module" -repo_url: 'https://github.com/OnePlc/PLC_X_Task' -theme: readthedocs -extra: - project: onePlc \ No newline at end of file diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php index edd14aa..2fa4656 100644 --- a/src/Controller/ApiController.php +++ b/src/Controller/ApiController.php @@ -21,6 +21,7 @@ use OnePlace\Task\Model\TaskTable; use Laminas\View\Model\ViewModel; use Laminas\Db\Adapter\AdapterInterface; +use Zend\I18n\Translator\Translator; class ApiController extends CoreController { /** @@ -67,7 +68,46 @@ public function indexAction() { public function listAction() { $this->layout('layout/json'); + # Check license + if(!$this->checkLicense('task')) { + $aReturn = ['state'=>'error','message'=>'no valid license for task found']; + echo json_encode($aReturn); + return false; + } + + # Set default values $bSelect2 = true; + $sListLabel = 'label'; + + # Get list mode from query + if(isset($_REQUEST['listmode'])) { + if($_REQUEST['listmode'] == 'entity') { + $bSelect2 = false; + } + } + + # get list label from query + if(isset($_REQUEST['listlabel'])) { + $sListLabel = $_REQUEST['listlabel']; + } + + # get list label from query + $sLang = 'en_US'; + if(isset($_REQUEST['lang'])) { + $sLang = $_REQUEST['lang']; + } + + // translating system + $translator = new Translator(); + $aLangs = ['en_US','de_DE']; + foreach($aLangs as $sLoadLang) { + if(file_exists(__DIR__.'/../../../oneplace-translation/language/'.$sLoadLang.'.mo')) { + $translator->addTranslationFile('gettext', __DIR__.'/../../../oneplace-translation/language/'.$sLang.'.mo', 'task', $sLoadLang); + } + } + + $translator->setLocale($sLang); + /** * todo: enforce to use /api/contact instead of /contact/api so we can do security checks in main api controller @@ -79,16 +119,94 @@ public function listAction() { } **/ + # Init Item List for Response $aItems = []; + $aFields = $this->getFormFields('task-single'); + $aFieldsByKey = []; + # fields are sorted by tab , we need an index with all fields + foreach($aFields as $oField) { + $aFieldsByKey[$oField->fieldkey] = $oField; + } + + # only allow form fields as list labels + if(!array_key_exists($sListLabel,$aFieldsByKey)) { + $aReturn = [ + 'state'=>'error', + 'results' => [], + 'message' => 'invalid list label', + ]; + + # Print List with all Entities + echo json_encode($aReturn); + return false; + } + # Get All Task Entities from Database $oItemsDB = $this->oTableGateway->fetchAll(false); if(count($oItemsDB) > 0) { + # Loop all items foreach($oItemsDB as $oItem) { + + # Output depending on list mode if($bSelect2) { - $aItems[] = ['id'=>$oItem->getID(),'text'=>$oItem->getLabel()]; + $sVal = null; + # get value for list label field + switch($aFieldsByKey[$sListLabel]->type) { + case 'select': + $oTag = $oItem->getSelectField($aFieldsByKey[$sListLabel]->fieldkey); + if($oTag) { + $sVal = $oTag->getLabel(); + } + break; + case 'text': + case 'date': + case 'textarea': + $sVal = $oItem->getTextField($aFieldsByKey[$sListLabel]->fieldkey); + break; + default: + break; + } + $aItems[] = ['id'=>$oItem->getID(),'text'=>$sVal]; } else { - $aItems[] = $oItem; + # Init public item + $aPublicItem = []; + + # add all fields to item + foreach($aFields as $oField) { + switch($oField->type) { + case 'multiselect': + # get selected + $oTags = $oItem->getMultiSelectField($oField->fieldkey); + $aTags = []; + foreach($oTags as $oTag) { + $aTags[] = ['id'=>$oTag->id,'label'=>$translator->translate($oTag->text,'task',$sLang)]; + } + $aPublicItem[$oField->fieldkey] = $aTags; + break; + case 'select': + # get selected + $oTag = $oItem->getSelectField($oField->fieldkey); + if($oTag) { + if (property_exists($oTag, 'tag_value')) { + $aPublicItem[$oField->fieldkey] = ['id' => $oTag->id, 'label' => $translator->translate($oTag->tag_value,'task',$sLang)]; + } else { + $aPublicItem[$oField->fieldkey] = ['id' => $oTag->getID(), 'label' => $translator->translate($oTag->getLabel(),'task',$sLang)]; + } + } + break; + case 'text': + case 'date': + case 'textarea': + $aPublicItem[$oField->fieldkey] = $translator->translate($oItem->getTextField($oField->fieldkey),'task',$sLang); + break; + default: + break; + } + } + + # add item to list + $aItems[] = $aPublicItem; } } @@ -118,6 +236,13 @@ public function listAction() { public function getAction() { $this->layout('layout/json'); + # Check license + if(!$this->checkLicense('task')) { + $aReturn = ['state'=>'error','message'=>'no valid license for task found']; + echo json_encode($aReturn); + return false; + } + # Get Task ID from route $iItemID = $this->params()->fromRoute('id', 0); diff --git a/src/Controller/SkeletonController.php b/src/Controller/TaskController.php similarity index 88% rename from src/Controller/SkeletonController.php rename to src/Controller/TaskController.php index 47a1962..8aea5d9 100644 --- a/src/Controller/SkeletonController.php +++ b/src/Controller/TaskController.php @@ -62,6 +62,12 @@ public function indexAction() { # Set Layout based on users theme $this->setThemeBasedLayout('task'); + # Check license + if(!$this->checkLicense('task')) { + $this->flashMessenger()->addErrorMessage('You have no active license for task'); + $this->redirect()->toRoute('home'); + } + # Add Buttons for breadcrumb $this->setViewButtons('task-index'); @@ -95,6 +101,12 @@ public function addAction() { # Set Layout based on users theme $this->setThemeBasedLayout('task'); + # Check license + if(!$this->checkLicense('task')) { + $this->flashMessenger()->addErrorMessage('You have no active license for task'); + $this->redirect()->toRoute('home'); + } + # Get Request to decide wether to save or display form $oRequest = $this->getRequest(); @@ -149,6 +161,12 @@ public function editAction() { # Set Layout based on users theme $this->setThemeBasedLayout('task'); + # Check license + if(!$this->checkLicense('task')) { + $this->flashMessenger()->addErrorMessage('You have no active license for task'); + $this->redirect()->toRoute('home'); + } + # Get Request to decide wether to save or display form $oRequest = $this->getRequest(); @@ -199,8 +217,11 @@ public function editAction() { $this->layout('layout/json'); + # Parse Form Data + $aFormData = $this->parseFormData($_REQUEST); + # Save Multiselect - $this->updateMultiSelectFields($_REQUEST,$oTask,'task-single'); + $this->updateMultiSelectFields($aFormData,$oTask,'task-single'); # Log Performance in DB $aMeasureEnd = getrusage(); @@ -221,6 +242,12 @@ public function viewAction() { # Set Layout based on users theme $this->setThemeBasedLayout('task'); + # Check license + if(!$this->checkLicense('task')) { + $this->flashMessenger()->addErrorMessage('You have no active license for task'); + $this->redirect()->toRoute('home'); + } + # Get Task ID from URL $iTaskID = $this->params()->fromRoute('id', 0); diff --git a/src/Model/Skeleton.php b/src/Model/Task.php similarity index 100% rename from src/Model/Skeleton.php rename to src/Model/Task.php diff --git a/src/Model/SkeletonTable.php b/src/Model/TaskTable.php similarity index 76% rename from src/Model/SkeletonTable.php rename to src/Model/TaskTable.php index b0b65a3..173d69e 100644 --- a/src/Model/SkeletonTable.php +++ b/src/Model/TaskTable.php @@ -43,12 +43,26 @@ public function __construct(TableGateway $tableGateway) { * Fetch All Task Entities based on Filters * * @param bool $bPaginated + * @param array $aWhere * @return Paginator Paginated Table Connection * @since 1.0.0 */ - public function fetchAll($bPaginated = false) { + public function fetchAll($bPaginated = false,$aWhere = []) { $oSel = new Select($this->oTableGateway->getTable()); + # Build where + $oWh = new Where(); + foreach(array_keys($aWhere) as $sWh) { + $bIsLike = stripos($sWh,'-like'); + if($bIsLike === false) { + + } else { + # its a like + $oWh->like(substr($sWh,0,strlen($sWh)-strlen('-like')),$aWhere[$sWh].'%'); + } + } + $oSel->where($oWh); + # Return Paginator or Raw ResultSet based on selection if ($bPaginated) { # Create result set for user entity @@ -77,12 +91,13 @@ public function fetchAll($bPaginated = false) { * Get Task Entity * * @param int $id + * @param string $sKey custom key * @return mixed * @since 1.0.0 */ - public function getSingle($id) { + public function getSingle($id,$sKey = 'Task_ID') { $id = (int) $id; - $rowset = $this->oTableGateway->select(['Task_ID' => $id]); + $rowset = $this->oTableGateway->select([$sKey => $id]); $row = $rowset->current(); if (! $row) { throw new \RuntimeException(sprintf( @@ -143,4 +158,23 @@ public function saveSingle(Task $oTask) { return $id; } + + /** + * Generate daily stats for task + * + * @since 1.0.5 + */ + public function generateDailyStats() { + # get all tasks + $iTotal = count($this->fetchAll(false)); + # get newly created tasks + $iNew = count($this->fetchAll(false,['created_date-like'=>date('Y-m-d',time())])); + + # add statistics + CoreController::$aCoreTables['core-statistic']->insert([ + 'stats_key'=>'task-daily', + 'data'=>json_encode(['new'=>$iNew,'total'=>$iTotal]), + 'date'=>date('Y-m-d H:i:s',time()), + ]); + } } \ No newline at end of file diff --git a/src/Module.php b/src/Module.php index bc3c42b..68ca45f 100644 --- a/src/Module.php +++ b/src/Module.php @@ -23,15 +23,15 @@ use Laminas\Session\Config\StandardConfig; use Laminas\Session\SessionManager; use Laminas\Session\Container; +use Application\Controller\CoreController; class Module { /** * Module Version * - * @since 1.0.5 + * @since 1.0.6 */ - const VERSION = '1.0.5'; - + const VERSION = '1.0.0'; /** * Load module config file * diff --git a/test/Controller/SkeletonControllerTest.php b/test/Controller/TaskControllerTest.php similarity index 100% rename from test/Controller/SkeletonControllerTest.php rename to test/Controller/TaskControllerTest.php diff --git a/view/layout/skeleton-default.phtml b/view/layout/skeleton-default.phtml deleted file mode 100644 index c62fc23..0000000 --- a/view/layout/skeleton-default.phtml +++ /dev/null @@ -1,67 +0,0 @@ -doctype() ?> - - - - headTitle('Task - onePlace X - RC 1')->setSeparator(' - ')->setAutoEscape(false) ?> - - headMeta() - ->appendName('viewport', 'width=device-width, initial-scale=1.0') - ->appendHttpEquiv('X-UA-Compatible', 'IE=edge') - ?> - - - headLink(['rel' => 'shortcut icon', 'type' => 'image/vnd.microsoft.icon', 'href' => $this->basePath() . '/img/favicon.ico']) - ->prependStylesheet($this->basePath('css/style.css')) - ->prependStylesheet($this->basePath('vendor/jquery-ui/jquery-uia.min.css')) - ->prependStylesheet($this->basePath('vendor/fontawesome/css/all.min.css')) - ->prependStylesheet($this->basePath('css/bootstrap.min.css')) - ?> - - - inlineScript() - ->prependFile($this->basePath('js/listener.js')) - ->prependFile($this->basePath('vendor/jquery-ui/jquery-ui.min.js')) - ->prependFile($this->basePath('js/bootstrap.min.js')) - ->prependFile($this->basePath('js/jquery-3.4.1.min.js')) - ?> - - - -
- partial('partial/breadcrumb', ['aButtons'=>isset($this->aButtons) ? $this->aButtons : [], 'pages'=>[]]); ?> - content ?> -
- -
-inlineScript() ?> - - diff --git a/view/one-place/skeleton/skeleton/add.phtml b/view/one-place/task/task/add.phtml similarity index 100% rename from view/one-place/skeleton/skeleton/add.phtml rename to view/one-place/task/task/add.phtml diff --git a/view/one-place/skeleton/skeleton/edit.phtml b/view/one-place/task/task/edit.phtml similarity index 100% rename from view/one-place/skeleton/skeleton/edit.phtml rename to view/one-place/task/task/edit.phtml diff --git a/view/one-place/skeleton/skeleton/index.phtml b/view/one-place/task/task/index.phtml similarity index 100% rename from view/one-place/skeleton/skeleton/index.phtml rename to view/one-place/task/task/index.phtml diff --git a/view/one-place/skeleton/skeleton/view.phtml b/view/one-place/task/task/view.phtml similarity index 100% rename from view/one-place/skeleton/skeleton/view.phtml rename to view/one-place/task/task/view.phtml diff --git a/view/widget/task_dailystats.phtml b/view/widget/task_dailystats.phtml new file mode 100644 index 0000000..ebfab69 --- /dev/null +++ b/view/widget/task_dailystats.phtml @@ -0,0 +1,93 @@ +get(TaskTable::class); + $iCountLive = count($oTaskTbl->fetchAll(false)); + + # Get Stats + $oStatSel = new Select(CoreController::$aCoreTables['core-statistic']->getTable()); + $oStatSel->order('date ASC'); + $oStatSel->where(['stats_key'=>'task-daily']); + $oStatSel->limit(30); + $oRecentStats = CoreController::$aCoreTables['core-statistic']->selectWith($oStatSel); +} catch(ServiceNotFoundException $e) { + +} + ?> + +
+
+
+
+ +
+
translate('Task')?> - translate('Info')?>
+
+
+

translate('Tasks')?> translate('total')?> +
+
+
+
+
+
+ diff --git a/view/widget/task_taginfo.phtml b/view/widget/task_taginfo.phtml new file mode 100644 index 0000000..534fe0c --- /dev/null +++ b/view/widget/task_taginfo.phtml @@ -0,0 +1,86 @@ +select(['tag_key'=>'category']); +$aFinalTags = []; +if(count($oTag) > 0) { + $oTag = $oTag->current(); + $oEntityTags = CoreController::$aCoreTables['core-entity-tag']->select(['tag_idfs'=>$oTag->Tag_ID,'entity_form_idfs'=>'task-single']); + + try { + # Get Task Table + $oTaskTbl = CoreController::$oServiceManager->get(\OnePlace\Task\Model\TaskTable::class); + + # Sort Tags by Task Count per Tag + $aTopTagsByCount = []; + $aSortArray = []; + if(count($oEntityTags) > 0) { + foreach($oEntityTags as $oEntityTag) { + $iCount = count(CoreController::$aCoreTables['core-entity-tag-entity']->select(['entity_tag_idfs'=>$oEntityTag->Entitytag_ID,'entity_type'=>'task'])); + $aTopTagsByCount[$oEntityTag->Entitytag_ID] = ['iCount'=>$iCount,'oTag'=>$oEntityTag]; + $aSortArray['iCount'][] = $iCount; + } + } + array_multisort($aSortArray['iCount'],SORT_DESC,$aTopTagsByCount); + + # Only show top tags by count + $iMaxTags = 5; + $iCount = 0; + foreach($aTopTagsByCount as $oTmpTag) { + if($iCount == $iMaxTags) { + break; + } + $aFinalTags[] = $oTmpTag; + $iCount++; + } + } catch(\RuntimeException $e) { + + } +} + +# Only show widget if we have tags to show +if(count($aFinalTags) > 0) { +?> + +
+
+
+
+ +
+
+ translate('Task')?> - translate('Category Info')?> +
+
+
+
    + +
  • + tag_value?> +
  • + +
+
+
+
+ + \ No newline at end of file