From be09b836051d61d3de9455019d7cb1bb989c420e Mon Sep 17 00:00:00 2001 From: Winfried Kappeler Date: Mon, 25 May 2020 00:34:36 +0200 Subject: [PATCH] WCL2020.05.24.00: Start MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * lauffähige Version --- .buildpath | 5 + .gitignore | 2 + .project | 28 + app/common | 1 + app/configurations | 1 + .../build/common/locals.common.config.php | 9 + .../build/common/locals.common.snippets.html | 15 + .../build/common/locals.frame.snippets.html | 259 ++++++++ app/locals/locals.controller.php | 82 +++ app/locals/locals.model.php | 79 +++ app/locals/locals.service.php | 168 +++++ app/locals/locals.view.php | 32 + app/locals/sql/locals.snippets.sql | 26 + app/login | 1 + app/logs | 1 + app/overview | 1 + app/roles | 1 + app/sessions | 1 + app/settings | 1 + app/starters | 1 + app/sysflags | 1 + app/terms/build/base/terms.base.config.php | 15 + app/terms/build/base/terms.base.snippets.html | 58 ++ .../build/common/terms.common.config.php | 13 + .../build/common/terms.common.snippets.html | 8 + .../build/delete/terms.delete.config.php | 14 + .../build/delete/terms.delete.snippets.html | 27 + app/terms/build/edit/terms.edit.config.php | 14 + app/terms/build/edit/terms.edit.snippets.html | 41 ++ app/terms/build/new/terms.new.config.php | 14 + app/terms/build/new/terms.new.snippets.html | 27 + app/terms/sql/terms.snippets.sql | 85 +++ app/terms/sql/terms.sql | 64 ++ app/terms/terms.controller.php | 23 + app/terms/terms.model.php | 205 ++++++ app/terms/terms.view.php | 622 ++++++++++++++++++ app/users | 1 + config/changes/skeletonversion.php | 1 + config/changes/version.php | 22 + config/sys/.gitignore | 1 + config/sys/error.php | 1 + config/sys/loader.php | 1 + db/.gitignore | 1 + lib | 1 + public/css/page/common/global.css | 1 + .../css/page/common/jquery.datetimepicker.css | 1 + public/css/page/common/local.css | 133 ++++ public/css/page/common/pdf.global.css | 1 + public/css/page/overview/overview.global.css | 1 + public/css/page/overview/overview.local.css | 13 + public/css/vendor | 1 + public/fonts | 1 + public/icon/famfamfam | 1 + public/icon/favicon.ico | 1 + public/icon/kirchturm.ico | Bin 0 -> 8830 bytes public/icon/msg | 1 + public/icon/start | 1 + public/img/vendor | 1 + public/index.php | 72 ++ public/js/common | 1 + public/js/vendor | 1 + tools/generator/.gitignore | 2 + tools/generator/templates | 1 + tools/generator/terms.module | 102 +++ tools/generator/terms.snippets.php | 39 ++ tpl/email/newPwd.html | 16 + tpl/email/newPwd.txt | 7 + tpl/email/newUser.html | 26 + tpl/email/newUser.txt | 10 + tpl/email/pwdForgotten.html | 17 + tpl/email/pwdForgotten.txt | 9 + 71 files changed, 2434 insertions(+) create mode 100644 .buildpath create mode 100644 .gitignore create mode 100644 .project create mode 120000 app/common create mode 120000 app/configurations create mode 100644 app/locals/build/common/locals.common.config.php create mode 100644 app/locals/build/common/locals.common.snippets.html create mode 100644 app/locals/build/common/locals.frame.snippets.html create mode 100644 app/locals/locals.controller.php create mode 100644 app/locals/locals.model.php create mode 100644 app/locals/locals.service.php create mode 100644 app/locals/locals.view.php create mode 100644 app/locals/sql/locals.snippets.sql create mode 120000 app/login create mode 120000 app/logs create mode 120000 app/overview create mode 120000 app/roles create mode 120000 app/sessions create mode 120000 app/settings create mode 120000 app/starters create mode 120000 app/sysflags create mode 100644 app/terms/build/base/terms.base.config.php create mode 100644 app/terms/build/base/terms.base.snippets.html create mode 100644 app/terms/build/common/terms.common.config.php create mode 100644 app/terms/build/common/terms.common.snippets.html create mode 100644 app/terms/build/delete/terms.delete.config.php create mode 100644 app/terms/build/delete/terms.delete.snippets.html create mode 100644 app/terms/build/edit/terms.edit.config.php create mode 100644 app/terms/build/edit/terms.edit.snippets.html create mode 100644 app/terms/build/new/terms.new.config.php create mode 100644 app/terms/build/new/terms.new.snippets.html create mode 100644 app/terms/sql/terms.snippets.sql create mode 100644 app/terms/sql/terms.sql create mode 100644 app/terms/terms.controller.php create mode 100644 app/terms/terms.model.php create mode 100644 app/terms/terms.view.php create mode 120000 app/users create mode 120000 config/changes/skeletonversion.php create mode 100644 config/changes/version.php create mode 100644 config/sys/.gitignore create mode 120000 config/sys/error.php create mode 120000 config/sys/loader.php create mode 100644 db/.gitignore create mode 120000 lib create mode 120000 public/css/page/common/global.css create mode 120000 public/css/page/common/jquery.datetimepicker.css create mode 100644 public/css/page/common/local.css create mode 120000 public/css/page/common/pdf.global.css create mode 120000 public/css/page/overview/overview.global.css create mode 100644 public/css/page/overview/overview.local.css create mode 120000 public/css/vendor create mode 120000 public/fonts create mode 120000 public/icon/famfamfam create mode 120000 public/icon/favicon.ico create mode 100644 public/icon/kirchturm.ico create mode 120000 public/icon/msg create mode 120000 public/icon/start create mode 120000 public/img/vendor create mode 100644 public/index.php create mode 120000 public/js/common create mode 120000 public/js/vendor create mode 100644 tools/generator/.gitignore create mode 120000 tools/generator/templates create mode 100644 tools/generator/terms.module create mode 100644 tools/generator/terms.snippets.php create mode 100644 tpl/email/newPwd.html create mode 100644 tpl/email/newPwd.txt create mode 100644 tpl/email/newUser.html create mode 100644 tpl/email/newUser.txt create mode 100644 tpl/email/pwdForgotten.html create mode 100644 tpl/email/pwdForgotten.txt diff --git a/.buildpath b/.buildpath new file mode 100644 index 0000000..8bcb4b5 --- /dev/null +++ b/.buildpath @@ -0,0 +1,5 @@ + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c04993d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/Deploy.sh +/do.not.deploy.list diff --git a/.project b/.project new file mode 100644 index 0000000..4053352 --- /dev/null +++ b/.project @@ -0,0 +1,28 @@ + + + webcal + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.dltk.core.scriptbuilder + + + + + + org.eclipse.php.core.PHPNature + org.eclipse.wst.common.project.facet.core.nature + + diff --git a/app/common b/app/common new file mode 120000 index 0000000..32c2db8 --- /dev/null +++ b/app/common @@ -0,0 +1 @@ +../../skeleton/app/common \ No newline at end of file diff --git a/app/configurations b/app/configurations new file mode 120000 index 0000000..1fba546 --- /dev/null +++ b/app/configurations @@ -0,0 +1 @@ +../../skeleton/app/configurations \ No newline at end of file diff --git a/app/locals/build/common/locals.common.config.php b/app/locals/build/common/locals.common.config.php new file mode 100644 index 0000000..47e1c1a --- /dev/null +++ b/app/locals/build/common/locals.common.config.php @@ -0,0 +1,9 @@ + '', + 'local_css' => '', + 'local_pageType' => 'base', + 'local_title' => 'Lokales', +); diff --git a/app/locals/build/common/locals.common.snippets.html b/app/locals/build/common/locals.common.snippets.html new file mode 100644 index 0000000..4ec94e0 --- /dev/null +++ b/app/locals/build/common/locals.common.snippets.html @@ -0,0 +1,15 @@ +SNIPPET_NAV_START: + + +
  • + +SNIPPET_NAV_END: +
    + +
    + +END: diff --git a/app/locals/build/common/locals.frame.snippets.html b/app/locals/build/common/locals.frame.snippets.html new file mode 100644 index 0000000..293fe12 --- /dev/null +++ b/app/locals/build/common/locals.frame.snippets.html @@ -0,0 +1,259 @@ +SNIPPET_ROOT: + + + + +###seo### + + + ###global_title### - ###local_title### + + + + + + + +###local_css### + + +
    + +
    +
    + ###CONTENT### +
    + + + + + + + + + + + + + + + + + +SNIPPET_LINK: + + +SNIPPET_COMMON_LEGEND: +###txt_commonLegend### (###SNIPPET_COMMON_FILTER_ACTIVE###) ###count### ###txt_records### + +SNIPPET_COMMON_LEGEND_PAGED: +###txt_commonLegend### (###SNIPPET_COMMON_FILTER_ACTIVE###) ###filtered### ###txt_records### (###txt_of### ###unfiltered###) + +SNIPPET_COMMON_PAGING_DATA: +###txt_page### ###page### ###txt_of### ###pages### + +SNIPPET_COMMON_FILTER_INACTIVE: +###txt_commonFilterInActive### + +SNIPPET_COMMON_FILTER_ACTIVE: +###txt_commonFilterActive### + +SNIPPET_PDF_FRAME: + + + + + + + + + +###local_css### + + +
    + ###CONTENT### +
    +
    + + + + + + + + + + + + + + +
    ###pdf.company.large###
    ###pdf.company.normal######pdf.phone###
    ###pdf.fax###
    ###pdf.email###
    ###pdf.site###
    ###pdf.address######pdf.mobile######pdf.ushd###
    + + + + +SNIPPET_EXCEL_FRAME: + + + + + + + ###CONTENT### + + + +SNIPPET_COMMON_IMG_EDIT: +###iconEdit### + +SNIPPET_SORT_BUTTON: +###arg_1### + +SNIPPET_COMMON_IMG_EDIT_TABLE: +###iconEdit### +###iconChange### + + + +SNIPPET_COMMON_IN_TABLE_CONTROL: + + + + +SNIPPET_COMMON_MESSAGE_IN_TABLE: +###txt_helpEditInTable### + +SNIPPET_COMMON_PAGING: +
    + + + + + + + +
    ###txt_Filtered###: !filtered! ###txt_Unfiltered###: !unfiltered!   +  ###txt_linesPerPage### +
    +
    +
      +###ITEMS### +
    +
    +
    +
    +
    + +SNIPPET_COMMON_PAGING_ITEM: +
  • ###no###
  • + +SNIPPET_COMMON_PAGING_ITEM_ACTIVE: +
  • ###no###
  • + +SNIPPET_COMMON_PAGING_GAP: +
  • ...
  • + +SNIPPET_LEAVE_PAGE: + + + + + + + + +
    +
    +

    Es gibt noch ungesicherte Daten.

    +###ITEMS### +
    +
    +
     
    +
    +
     
    +
    +
    +
    + + + +SNIPPET_LEAVE_PAGE_ITEM: +
    ###label###
    +
    ###value###
    + +SNIPPET_GENERAL_TABLE: + + +~heads~ + +~rows~ +
    + +SNIPPET_CALENDAR: + + + + + + + + +###ROWS### + +
    ###mon######tue######wed######thu######fri######sat######sun###
    + +SNIPPET_CALENDAR_ROW: +###COLS### + + +SNIPPET_CALENDAR_COL: +###DATE######SEP######INFO### + +END: diff --git a/app/locals/locals.controller.php b/app/locals/locals.controller.php new file mode 100644 index 0000000..ba53ec3 --- /dev/null +++ b/app/locals/locals.controller.php @@ -0,0 +1,82 @@ +, ) pairs from $references. + * + * @param string $references + * a blank separated list of keys + * @param array $config + * a map containing the values (with the same key) + * @return array|NULL + */ + public function buildPlaceholderMap(string $references, array &$config): ?array + { + return null; + } + + /** + * Sets the "breadcrumb" info line in a HTML text. + * + * @precondition: a macro ###breadcrumb### exists in the HTML text + * + * @param array $data + * a list of pairs [name, url], e.g. [['Projekte' FULL_URL_APP_PREFIX . '/projects/overview'], ['Neuanlage', '#']] + * @param string $html + * the HTML text with the expanded macro + */ + public function setBreadcrumb(array $data, string $html, string $moduleType = 'std') + { + if (($ixMax = count($data) - 1) < 0) { + $html2 = ''; + } else { + $html2 = "
      \n"; + $container = LN\Config::get('main_sys')['app'][APP_NAME]; + $name1 = 'urlBreadcrumb' . LN\StringUtils::capitalize($moduleType); + $name2 = 'labelBreadcrumb' . LN\StringUtils::capitalize($moduleType); + if (! array_key_exists($name1, $container)) { + $url = FULL_URL_APP_PREFIX . '/overview/base'; + $text = 'Start'; + } else { + $url = LN\Config::get('main_sys')['app'][APP_NAME][$name1]; + $text = LN\Config::get('main_sys')['app'][APP_NAME][$name2]; + } + $html2 .= "
    1. $text
    2. \n"; + for ($ix = 0; $ix < $ixMax; $ix ++) { + $text = $data[$ix][0]; + if ($text[0] === '#'){ + $text = $this->translate($text); + } else { + $text = LN\StringUtils::textToHtml($text2); + } + $url = $data[$ix][1]; + if (! empty($text)) { + $html2 .= "
    3. $text
    4. \n"; + } + } + $text = LN\StringUtils::textToHtml($data[$ixMax][0]); + $html2 .= "
    5. $text
    6. \n"; + $html2 .= "
    \n"; + } + $html = str_replace('###breadcrumb###', $html2, $html); + return $html; + } +} diff --git a/app/locals/locals.model.php b/app/locals/locals.model.php new file mode 100644 index 0000000..571bb2b --- /dev/null +++ b/app/locals/locals.model.php @@ -0,0 +1,79 @@ +__initSQL(); + } + + /** + * Adds a member to a term (table userterm). + * + * @param int $member + * the member to add + * @param int $term + * the related term + */ + public function addMember(int $member, int $term) + { + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_INSERT_USERTERM'); + $this->_db->prepareAndExecute($sql, [ + ':member' => $member, + ':term' => $term, + ':user' => $_SESSION['shortname'] + ]); + } + + /** + * Deletes a member of a term (table userterm). + * + * @param int $member + * the member to add + * @param int $term + * the related term + */ + public function subMember(int $member, int $term) + { + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_DELETE_USERTERM'); + $this->_db->prepareAndExecute($sql, [ + ':member' => $member, + ':term' => $term + ]); + } + + /** + * Assembles all members as a text. + * + * @param int $term + * the members related to this term will be assembled + * @return string the display names of the members, delimited by ' ' + */ + public function membersOfTerm(int $term): string + { + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_USERTERM_BY_TERM'); + $recs = $this->_db->readall($sql, [ + ':term' => $term + ], false); + $rc = ''; + foreach ($recs as &$rec) { + if (! empty($rc)) { + $rc .= ', '; + } + $rc .= $rec['user_displayname']; + } + return $rc; + } +} diff --git a/app/locals/locals.service.php b/app/locals/locals.service.php new file mode 100644 index 0000000..46bcfa0 --- /dev/null +++ b/app/locals/locals.service.php @@ -0,0 +1,168 @@ +daemon($argv); + } + /** + * Prints an error message. + * + * @param string $message + */ + private function error(string $message) + { + echo "+++ $message\n"; + } + + /** + * Offers services outside of the web interface (as command line tool). + * + * @param array $argv + * the program arguments, e.g. ['create-charge', '19'] + */ + public function service(array $argv) + { + if (\count($argv) < 1) { + $this->usage("zu wenig Argumente"); + } else { + $script = \array_shift($argv); + $cmd = \array_shift($argv); + switch ($cmd) { + case 'help': + $this->usage(null); + break; + case 'version': + require_once ROOT . 'config/changes/version.php'; + echo 'Version: ' . APP_VERSION . "\nSkeleton-Version: " . SKELETON_VERSION . "\n"; + break; + case 'test': + $this->test($argv); + break; + case 'daemon': + $this->daemon($argv); + break; + default: + echo "unknown subcommand: $cmd\nUse 'service help' for help\n"; + break; + } + } + } + + /** + * A test whether the service is working. + * + * Counts from + * + * @param array $argv + * expected: [, ] + */ + private function test(array $argv) + { + if (count($argv) < 2) { + $this->argError('too few arguments)'); + } elseif (($count = intval($argv[1])) == 0) { + LN\Service::progressWrite($argv[0], 0, 100, 100, 100); + $this->argError('invalid : ' . $argv[0]); + } else { + $id = $argv[0]; + for ($ix = 0; $ix < $count; $ix++){ + LN\Service::progressWrite($id, 0, 100, $ix, $count); + \sleep(3); + } + LN\Service::progressWrite($id, 0, 100, 1, 1); + } + } +/** + * Handles the tasks of this service. + * + * @param string $task + * the task to do, e.g. 'charge' + * @param array $args + * the task arguments, e.g. ['19'] + * @return bool true: the task could be handled false: unknown task + */ + public function taskHandler(string $task, array $args): bool + { + $locals = Controller::getInstance(); + $rc = true; + echo "task found: $task\n"; + switch ($task) { + case 'test': + $locals->test($args); + break; + default: + $rc = false; + break; + } + return $rc; + } + + + /** + * Displays the usage info. + * + * @param string $message + * null or the error message + */ + private function usage(?string $message) + { + echo "usage: service \n"; + echo ":\n"; + echo " charge \n"; + echo " creates the pools, tokens and qrcodes of a charge\n"; + echo " daemon\n"; + echo " starts an daemon waiting for tasks given by task files in a directory\n"; + echo " help\n"; + echo " displays this info\n"; + echo "..test \n"; + echo "....counts from 0 to (for testing purpose)\n"; + echo " version\n"; + echo " displays the program version\n"; + if ($message != null) { + echo "+++ $message\n"; + } + } +} diff --git a/app/locals/locals.view.php b/app/locals/locals.view.php new file mode 100644 index 0000000..ff757d9 --- /dev/null +++ b/app/locals/locals.view.php @@ -0,0 +1,32 @@ + [ + 'name' => 'common', + 'site' => 1, + 'config' => 1 + ] + ]; + + /** + * Adapts the full page in a application depending way. + * + * @param string $content + * IN/OUT: the full page, may be changed + */ + public function adaptFullPage(string &$content) + { + // do nothing + } + +} diff --git a/app/locals/sql/locals.snippets.sql b/app/locals/sql/locals.snippets.sql new file mode 100644 index 0000000..6ff8c6d --- /dev/null +++ b/app/locals/sql/locals.snippets.sql @@ -0,0 +1,26 @@ +SQL_INSERT_USERTERM: +insert into userterms + (userterm_user, userterm_term, created, createdby) +values + (:member, :term, now(), :user) +; + +SQL_DELETE_USERTERM: +delete + from userterms +where + userterm_term=:term and userterm_user=:member +; + +SQL_USERTERM_BY_TERM: +select + u.user_displayname +from + userterms tt + left join loginusers u on u.user_id=tt.userterm_user +where + userterm_term=:term +order by user_displayname +; + +END: \ No newline at end of file diff --git a/app/login b/app/login new file mode 120000 index 0000000..dd40685 --- /dev/null +++ b/app/login @@ -0,0 +1 @@ +../../skeleton/app/login \ No newline at end of file diff --git a/app/logs b/app/logs new file mode 120000 index 0000000..30e3dc2 --- /dev/null +++ b/app/logs @@ -0,0 +1 @@ +../../skeleton/app/logs \ No newline at end of file diff --git a/app/overview b/app/overview new file mode 120000 index 0000000..be7e20d --- /dev/null +++ b/app/overview @@ -0,0 +1 @@ +../../skeleton/app/overview \ No newline at end of file diff --git a/app/roles b/app/roles new file mode 120000 index 0000000..9ac17a1 --- /dev/null +++ b/app/roles @@ -0,0 +1 @@ +../../skeleton/app/roles \ No newline at end of file diff --git a/app/sessions b/app/sessions new file mode 120000 index 0000000..0b0850d --- /dev/null +++ b/app/sessions @@ -0,0 +1 @@ +../../skeleton/app/sessions \ No newline at end of file diff --git a/app/settings b/app/settings new file mode 120000 index 0000000..fd009af --- /dev/null +++ b/app/settings @@ -0,0 +1 @@ +../../skeleton/app/settings \ No newline at end of file diff --git a/app/starters b/app/starters new file mode 120000 index 0000000..83e3139 --- /dev/null +++ b/app/starters @@ -0,0 +1 @@ +../../skeleton/app/starters \ No newline at end of file diff --git a/app/sysflags b/app/sysflags new file mode 120000 index 0000000..f182201 --- /dev/null +++ b/app/sysflags @@ -0,0 +1 @@ +../../skeleton/app/sysflags \ No newline at end of file diff --git a/app/terms/build/base/terms.base.config.php b/app/terms/build/base/terms.base.config.php new file mode 100644 index 0000000..c0906e4 --- /dev/null +++ b/app/terms/build/base/terms.base.config.php @@ -0,0 +1,15 @@ + '', + 'local_css' => '', + 'local_pageType' => 'base', + 'local_title' => 'Termine', + 'hasFilter' => TC\Controller::getInstance()->configurationAsBool('terms', 'filter:switch'), + + // PHP_HOOK_CONFIG_BASE + '!EoA!' => '' +); diff --git a/app/terms/build/base/terms.base.snippets.html b/app/terms/build/base/terms.base.snippets.html new file mode 100644 index 0000000..3f3f14a --- /dev/null +++ b/app/terms/build/base/terms.base.snippets.html @@ -0,0 +1,58 @@ +SNIPPET_ROOT: +
    ###breadcrumb###
    + +
    + + +
    + +
    +
    + +###SNIPPET_IF_2### +
    + + +###SNIPPET_COMMON_PAGING### + + + + + + + + + + + + + +###ROWS### + +
    Id###COMMON_SNIPPET[SNIPPET_SORT_BUTTON,sort_term_id]###Datum###COMMON_SNIPPET[SNIPPET_SORT_BUTTON,sort_term_date]###Bezeichnung###COMMON_SNIPPET[SNIPPET_SORT_BUTTON,sort_term_name]###PlatzanweiserBemerkung
    +
    +
    + + +SNIPPET_IF_2: +
    + + +SNIPPET_ROW: + + ###alt_edit### + + ###term_id### + ###term_date### + ###term_name### + ###members### + ###term_info### + ###alt_delete### + + + + +SNIPPET_DUMMY_FOR_HOOK: + + +END: diff --git a/app/terms/build/common/terms.common.config.php b/app/terms/build/common/terms.common.config.php new file mode 100644 index 0000000..4d0e492 --- /dev/null +++ b/app/terms/build/common/terms.common.config.php @@ -0,0 +1,13 @@ + '', + 'local_css' => '', + 'data' => 'Daten', 'parent_title' => 'Termine', + + // PHP_HOOK_CONFIG_COMMON + '!EoA!' => '' +); diff --git a/app/terms/build/common/terms.common.snippets.html b/app/terms/build/common/terms.common.snippets.html new file mode 100644 index 0000000..6e42e03 --- /dev/null +++ b/app/terms/build/common/terms.common.snippets.html @@ -0,0 +1,8 @@ +SNIPPET_FIELDS: + + + +SNIPPET_DUMMY_FOR_HOOK: + + +END: diff --git a/app/terms/build/delete/terms.delete.config.php b/app/terms/build/delete/terms.delete.config.php new file mode 100644 index 0000000..7e8df43 --- /dev/null +++ b/app/terms/build/delete/terms.delete.config.php @@ -0,0 +1,14 @@ + '', + 'local_css' => '', + 'local_pageType' => 'delete', + 'local_title' => 'Termin löschen', + + // PHP_HOOK_CONFIG_DELETE + '!EoA!' => '' +); diff --git a/app/terms/build/delete/terms.delete.snippets.html b/app/terms/build/delete/terms.delete.snippets.html new file mode 100644 index 0000000..2187d9b --- /dev/null +++ b/app/terms/build/delete/terms.delete.snippets.html @@ -0,0 +1,27 @@ +SNIPPET_ROOT: +
    + ###breadcrumb### +
    +
    + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    + +SNIPPET_DUMMY_FOR_HOOK: + + +END: diff --git a/app/terms/build/edit/terms.edit.config.php b/app/terms/build/edit/terms.edit.config.php new file mode 100644 index 0000000..afe55fe --- /dev/null +++ b/app/terms/build/edit/terms.edit.config.php @@ -0,0 +1,14 @@ + '', + 'local_css' => '', + 'local_pageType' => 'edit', + 'local_title' => 'Termin ändern', + + // PHP_HOOK_CONFIG_EDIT + '!EoA!' => '' +); diff --git a/app/terms/build/edit/terms.edit.snippets.html b/app/terms/build/edit/terms.edit.snippets.html new file mode 100644 index 0000000..01c3cbe --- /dev/null +++ b/app/terms/build/edit/terms.edit.snippets.html @@ -0,0 +1,41 @@ +SNIPPET_ROOT: +
    + ###breadcrumb### +
    +
    + + + + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +###SNIPPET_IF_2### +###SNIPPET_IF_3### +
    +
    + +
    + + +SNIPPET_IF_2: +###errors### +
    +
    + +SNIPPET_IF_3: +
    + +SNIPPET_DUMMY_FOR_HOOK: + + +END: diff --git a/app/terms/build/new/terms.new.config.php b/app/terms/build/new/terms.new.config.php new file mode 100644 index 0000000..da46f2f --- /dev/null +++ b/app/terms/build/new/terms.new.config.php @@ -0,0 +1,14 @@ + '', + 'local_css' => '', + 'local_pageType' => 'new', + 'local_title' => 'Neuer Termin', + + // PHP_HOOK_CONFIG_NEW + '!EoA!' => '' +); diff --git a/app/terms/build/new/terms.new.snippets.html b/app/terms/build/new/terms.new.snippets.html new file mode 100644 index 0000000..02c155d --- /dev/null +++ b/app/terms/build/new/terms.new.snippets.html @@ -0,0 +1,27 @@ +SNIPPET_ROOT: +
    + ###breadcrumb### +
    +
    + + + + +
    +
    + +
    +
    +
    +###errors### +
    +
    +
    +
    + +
    + +SNIPPET_DUMMY_FOR_HOOK: + + +END: diff --git a/app/terms/sql/terms.snippets.sql b/app/terms/sql/terms.snippets.sql new file mode 100644 index 0000000..bbac8f9 --- /dev/null +++ b/app/terms/sql/terms.snippets.sql @@ -0,0 +1,85 @@ +SQL_SUFFIX_GETALL: +ORDER BY + !order! +!paging! +; + +SQL_SUFFIX_GETALL_COUNT: +; + +SQL_TERM_BY_NAME: +SELECT + * +FROM + terms +WHERE + term_name=:name +; + +SQL_BY_ID_TERM: +SELECT + * +FROM + terms +WHERE + term_id = :termID +; + +SQL_DELETE_BY_ID_TERM: +DELETE FROM + terms +WHERE + term_id = :termID +; + +SQL_TERMS_DEFAULT_ORDER: +term_date + +SQL_TERMS_BASE_GETALL: +SELECT + tt.*,'dummy' as members +FROM + terms tt +WHERE + tt.deletedat is null + +SQL_TERMS_BASE_GETALL_COUNT: +SELECT + count(*) +FROM + terms tt +WHERE + tt.deletedat is null + +SQL_TERMS_NEW_INSERT: +INSERT INTO terms ( + created, + createdby, + term_name, + term_date, + term_info +) VALUES ( + now(), + :loggeduser, + :name, + :date, + :info +); + + + +SQL_TERMS_EDIT_UPDATE: +UPDATE terms set + changed=now(), + changedby=:loggeduser, + term_name = :name, + term_date = :date, + term_info = :info +WHERE + term_id = :termID +; + + + + +END: diff --git a/app/terms/sql/terms.sql b/app/terms/sql/terms.sql new file mode 100644 index 0000000..19e0612 --- /dev/null +++ b/app/terms/sql/terms.sql @@ -0,0 +1,64 @@ +drop table if exists terms; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE terms( + term_id int(10) unsigned NOT NULL AUTO_INCREMENT, + term_name varchar(32), + term_date timestamp, + term_info text, + created timestamp NULL, + createdby varchar(16), + changed timestamp NULL, + changedby varchar(16), + deletedat timestamp NULL, + deletedby varchar(16), + PRIMARY KEY (term_id) +); + +-- ! if no records in select * from configurations where configuration_scope='terms' and configuration_property='required:base' +INSERT INTO configurations +(configuration_scope, configuration_property, configuration_order, configuration_type, configuration_value, configuration_description, configuration_changed_by) +VALUES +('terms', 'required:base', 0, 'string', 'term_id,term_name', 'Pflichtfelder bei terms. Trennung mit Komma', 'wk'); +-- ! endif +insert into starters (starter_name, starter_label, starter_parent, starter_image, starter_link) +values ( +'terms', 'Terms', 'start', 'start/sysflag.png', '/webcal/configurations/base' +); +insert into rolestarter (starter_id, role_id, order_no) +values((select max(starter_id) from starters where starter_name='terms'), 1, 1000), + ((select max(starter_id) from starters where starter_name='terms'), 2, 1000), + ((select max(starter_id) from starters where starter_name='terms'), 3, 1000) +; + + +drop table if exists userterms; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE userterms( + term_id int(10) unsigned NOT NULL AUTO_INCREMENT, + userterm_term int(10) unsigned, + userterm_user int(10) unsigned, + created timestamp NULL, + createdby varchar(16), + changed timestamp NULL, + changedby varchar(16), + deletedat timestamp NULL, + deletedby varchar(16), + PRIMARY KEY (term_id) +); + +-- ! if no records in select * from configurations where configuration_scope='userterms' and configuration_property='required:base' +INSERT INTO configurations +(configuration_scope, configuration_property, configuration_order, configuration_type, configuration_value, configuration_description, configuration_changed_by) +VALUES +('terms', 'required:base', 0, 'string', 'term_id,userterm_term,userterm_user,created,createdby,changed,changedby,deletedat,deletedby', 'Pflichtfelder bei terms. Trennung mit Komma', 'wk'); +-- ! endif +insert into starters (starter_name, starter_label, starter_parent, starter_image, starter_link) +values ( +'terms', 'Terms', 'start', 'start/sysflag.png', '/webcal/configurations/base' +); +insert into rolestarter (starter_id, role_id, order_no) +values((select max(starter_id) from starters where starter_name='terms'), 1, 1000), + ((select max(starter_id) from starters where starter_name='terms'), 2, 1000), + ((select max(starter_id) from starters where starter_name='terms'), 3, 1000) +; + diff --git a/app/terms/terms.controller.php b/app/terms/terms.controller.php new file mode 100644 index 0000000..0d31369 --- /dev/null +++ b/app/terms/terms.controller.php @@ -0,0 +1,23 @@ +__initSQL(); + // PHP_HOOK_CONTROLLER_CONSTRUCTOR + } + // PHP_HOOK_CONTROLLER_CUSTOMIZED_METHODS +} + +?> \ No newline at end of file diff --git a/app/terms/terms.model.php b/app/terms/terms.model.php new file mode 100644 index 0000000..1e154c9 --- /dev/null +++ b/app/terms/terms.model.php @@ -0,0 +1,205 @@ +_sqlSnippetsModel->getSnippet('SQL_TERM_BY_NAME'); + $rc = $this->_db->readSingleRecord($sql, [ + ':name' => $term_name + ], true); + LN\DB::changeDateColumn($rc, 'term_date', $this->dateTimeFormat, true); + LN\DB::changeDateColumn($rc, 'created', $this->dateTimeFormat, true); + LN\DB::changeDateColumn($rc, 'changed', $this->dateTimeFormat, true); + LN\DB::changeDateColumn($rc, 'deletedat', $this->dateTimeFormat, true); + return $rc; + } + + /** + * Returns the db record given by id. + * + * @param int $termID + * primary key + * @return array the database record + */ + public function termByID(int $termID) + { + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_BY_ID_TERM'); + $rc = $this->_db->readSingleRecord($sql, [ + ':termID' => $termID + ]); + LN\DB::changeDateColumn($rc, 'term_date', $this->dateTimeFormat, true); + LN\DB::changeDateColumn($rc, 'created', $this->dateTimeFormat, true); + LN\DB::changeDateColumn($rc, 'changed', $this->dateTimeFormat, true); + LN\DB::changeDateColumn($rc, 'deletedat', $this->dateTimeFormat, true); + return $rc; + } + /** + * Deletes a record given by its primary key. + * + * @param int $id + * primary key + * return bool true: success + */ + public function deleteTermById(int $id, array &$record) + { + $common = TC\Controller::getInstance(); + $common->putToLogDelete('terms', 'term_id', $record); + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_DELETE_BY_ID_TERM'); + $rc = $this->_db->prepareAndExecute($sql, [ + ':termID' => $id + ]); + return $rc !== FALSE; + } + /** + * Returns all records filtered by scope and property. + * + * @param string $sqlReplacement + * null or a string with (search replacement) pairs preceeded by + * Example: ':!idList!:1,2,4:!order!:name' + * @param LN\PagingData $pagingData + * Info about sorting and paging + * @return array the records matching the filter expressions + */ + public function getAllTermsBase(?string $sqlReplacement, LN\PagingData &$pagingData, array &$record) + { + // PHP_HOOK_MODEL_TERMS_BASE_BODY_GETALL + PHP_HOOK_SQL_TERMS_BASE_ALL + PHP_HOOK_SQL_TERMS_BASE_ALL_COUNT + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_TERMS_BASE_GETALL'); + $sql .= "\n" . $this->_sqlSnippetsModel->getSnippet('SQL_SUFFIX_GETALL'); + $search = null; + // PHP_HOOK_MODEL_TERMS_BASE_GETALL_FIX_ARGS + if ($sqlReplacement != null){ + $parts = explode($sqlReplacement[0], substr($sqlReplacement, 1)); + $search = []; + $replacement = []; + for ($ix = 0; $ix < count($parts) / 2; $ix++){ + array_push($search, $parts[2*$ix]); + array_push($replacement, $parts[2*$ix+1]); + } + } + + $sqlCount = $this->_sqlSnippetsModel->getSnippet('SQL_TERMS_BASE_GETALL_COUNT'); + + $sqlCount .= "\n" . $this->_sqlSnippetsModel->getSnippet('SQL_SUFFIX_GETALL_COUNT'); + if ($search != null){ + $sqlCount = str_replace($search, $replacement, $sqlCount); + } + // PHP_HOOK_MODEL_TERMS_BASE_GETALL_START + $params = [ + ]; + // PHP_HOOK_MODEL_TERMS_BASE_GETALL_PARAM_FIX + $countFiltered = intval($this->_db->readUniqueValue($sqlCount, $params)); + $pagingData->setFilteredRecords($countFiltered); + $order = $this->_sqlSnippetsModel->getSnippet('SQL_TERMS_DEFAULT_ORDER'); + // PHP_HOOK_MODEL_TERMS_BASE_PATCH_ORDER + $order = $pagingData->getOrder($order); + $sql = str_replace('!order!', $order, $sql); + + $size = $pagingData->pagingSize; + if ($size <= 0){ + $sql = str_replace('!paging!', '', $sql); + } else { + $offset = max(0, $pagingData->pagingIndex * $size); + $sql = str_replace('!paging!', "limit $offset, $size", $sql); + } + // PHP_HOOK_MODEL_TERMS_BASE_GETALL + if ($search != null){ + $sql = str_replace($search, $replacement, $sql); + } + $rc = $this->_db->readAll($sql, $params, FALSE); + $pagingData->unfilteredRecords = $this->_db->countOfAll('terms'); + if (count($rc) > 0 && \array_key_exists('term_date', $rc[0])) { + LN\DB::changeDateColumn($rc, 'term_date', $this->dateTimeFormat); + } + if (count($rc) > 0 && \array_key_exists('created', $rc[0])) { + LN\DB::changeDateColumn($rc, 'created', $this->dateTimeFormat); + } + if (count($rc) > 0 && \array_key_exists('changed', $rc[0])) { + LN\DB::changeDateColumn($rc, 'changed', $this->dateTimeFormat); + } + if (count($rc) > 0 && \array_key_exists('deletedat', $rc[0])) { + LN\DB::changeDateColumn($rc, 'deletedat', $this->dateTimeFormat); + } + + // PHP_HOOK_MODEL_TERMS_BASE_GETALL_ADAPTION + return $rc; + } + /** + * Creates a new db record. + * + * @param array $record + * the record data as map: column_name -> value + * @return int primary key + */ + public function insertByRecordNewTerm(array &$record) + { + $common = TC\Controller::getInstance(); + $id = 0; + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_TERMS_NEW_INSERT'); + $params = [ + ':loggeduser' => $_SESSION['shortname'], + ':name' => $record['term_name'], + ':date' => $record['term_date'] != null ? LN\DB::dateTimeToDbDateTime($record['term_date']) : null, + ':info' => $record['term_info'], + ]; + // PHP_HOOK_MODEL_NEW_TERMS_INSERT_NEW + if ($this->_db->prepareAndExecute($sql, $params)) { + $id = $this->_db->lastInsertId(); + if ($record != null){ + $common->putToLogInsert('terms', 'term_id', $id); + } + } + return $id; + } + /** + * Updates a database record. + * + * @param int $termID + * primary key + * @param array $record + * the record data as map: column_name -> value + */ + public function updateByRecordEditTerm(int $termID, array &$record) + { + $common = TC\Controller::getInstance(); + $sql = $this->_sqlSnippetsModel->getSnippet('SQL_TERMS_EDIT_UPDATE'); + $params = [ + ':loggeduser' => $_SESSION['shortname'], + ':termID' => $record['termID'], + ':name' => $record['term_name'], + ':date' => $record['term_date'] != null ? LN\DB::dateTimeToDbDateTime($record['term_date']) : null, + ':info' => $record['term_info'], + ]; + // PHP_HOOK_MODEL_EDIT_TERMS_UPDATE + if ($record != null){ + $common->putToLogUpdate('terms', 'term_id', $termID, $record, null, ['termID']); + } + return $this->_db->prepareAndExecute($sql, $params); + } + + + + // PHP_HOOK_MODEL_METHODS +} + +?> \ No newline at end of file diff --git a/app/terms/terms.view.php b/app/terms/terms.view.php new file mode 100644 index 0000000..7062541 --- /dev/null +++ b/app/terms/terms.view.php @@ -0,0 +1,622 @@ + [ + 'name' => 'base', + 'site' => 1, + 'config' => 1 + ], + 'new' => [ + 'name' => 'new', + 'site' => 1, + 'config' => 1 + ], + 'edit' => [ + 'name' => 'edit', + 'site' => 1, + 'config' => 1 + ], + 'delete' => [ + 'name' => 'delete', + 'site' => 1, + 'config' => 1 + ] + ]; + public $_moduleType = 'backend'; + /** + * Returns the configuration of the common page. + * + * @return array the configuration + */ + public function getCommonConfig() + { + // common config is included in edit config: + $config = $this->_getConfiguration($this->_build['edit'], 'edit'); + return $config; + } + /** + * Handles AJAX requests. + */ + public function ajax() + { + [ + $snippets, + $config + ] = $this->_getSnippetsAndConfig($this->_build['edit'], 'edit'); + $common = TC\Controller::getInstance(); + $fieldSet = $this->buildCommonFieldSet('edit', URL_DOMAIN_APP_PREFIX . '/terms/ajax'); + $answer = ''; + if (! \array_key_exists('ajaxMode', $_POST)) { + error_log('Terms::ajax(): Missing argument "ajaxMode"'); + } else { + switch ($_POST['ajaxMode']) { + case 'newChanged': + $answer = $common->testNewChanged($fieldSet); + break; + case 'editChanged': + $record = $this->termById($_POST['termID']); + $answer = $common->testNewChanged($fieldSet); + break; + default: + error_log('Terms::ajax(): unknown mode: ' . $_POST['ajaxMode']); + break; + } + } + $this->answerAjax($answer ?? ''); + } + // PHP_HOOK_VIEW_METHODS + + /** + * Returns the HTML text of the base page (without frame). + * + * @return string the HTML text of the base page (overview table) + */ + public function buildBase(): string + { + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + // PHP_HOOK_BASE_INIT + [ + $snippets, + $config + ] = $this->_getSnippetsAndConfig($this->_build['base'], 'base'); + $content = $snippets->getSnippet('SNIPPET_ROOT', $config); + $breadcrumbs = [ + [ + $config['local_title'], + '#' + ] + ]; + // PHP_HOOK_BASE_BREADCRUMB + $content = $this->_setBreadcrumb($breadcrumbs, $content, $this->_moduleType); + $validator = new TermsValidator($this); + $urlAction = FULL_URL_APP_PREFIX . '/terms/base'; + $fieldSet = new LN\FieldSet('base', $config, $urlAction, $validator); + $common->addPagingAndSortingFields($fieldSet); + + // PHP_HOOK_BASE_FIELDS + $fieldSet->setFromPost(); + // PHP_HOOK_BASE_START + $storage = TSE\Controller::getInstance()->getStorage($_SESSION['hash'], 'terms', 'base'); + $fieldSet->setFromArray($storage->getData()); + // use all fields: + $storageFields = null; + // PHP_HOOK_BASE_SET_STORAGE_FIELDS + $storage->fetchFromFieldset($fieldSet, $storageFields); + if (count($_POST) == 0){ + // First call + // PHP_HOOK_BASE_FIRST_CALL + } + // PHP_HOOK_BASE_FIELDS_READY + $pagingData = $common->getPagingAndSortingData($fieldSet, $storage); + $empty = false; + if (\array_key_exists('buttonNew', $_POST)) { + $linkPage = '/terms/new'; + // PHP_HOOK_BASE_REDIRECT_BUTTONNEW + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + // PHP_HOOK_BASE_BUTTONS + } else { + $templateRow = $snippets->getSnippet('SNIPPET_ROW', []); + // PHP_HOOK_BASE_TEMPLATE_ROW + $rows = ''; + $record = []; + $sqlReplacement = ''; + // PHP_HOOK_BASE_BEFORE_GET_ALL + $records = $this->getAllTermsBase($sqlReplacement, $pagingData, $record); + $content = $common->setLegendWithPages($pagingData, $content, ! $empty); + $editAllowed = true; + $deleteAllowed = true; + // === start PHP_HOOK_BASE_TABLE_RECORDS_ADAPTION + $deleteAllowed = $_SESSION['roleID'] <= 2; + // === end PHP_HOOK_BASE_TABLE_RECORDS_ADAPTION + $rowNo = 0; + foreach ($records as &$rec) { + $rowNo++; + // === start PHP_HOOK_BASE_TABLE_ROW_ADAPTION + $rec['members'] = $locals->membersOfTerm($rec['term_id']); + // === end PHP_HOOK_BASE_TABLE_ROW_ADAPTION + $html = $common->rowFromDatabase($templateRow, $rec); + if (! $editAllowed){ + $html = $common->deleteEditIcon($html); + } + if (! $deleteAllowed){ + $html = $common->deleteDeleteIcon($html); + } + $rows .= $html; + } + $content = str_replace('###ROWS###', $rows, $content); + // PHP_HOOK_BASE_HTML + $common->switchConditional($content, 'SNIPPET_IF_2', null, 'role', '1,2', false, $snippets, $config); + $dummyStr = null; + $map = $locals->buildPlaceholderMap('', $config); + // PHP_HOOK_BASE_HTML_REPLACEMENT + $content = $common->replaceInHtmlWithErrors($content, 'terms', $fieldSet, $map, $dummyStr, $pagingData, $storage); + } + // PHP_HOOK_BASE_EXIT + return $content; + } + + /** + * Builds the html text for creation in page new (without frame). + * + * @return string the HTML text of the "new" page + */ + public function buildNew(): string + { + $sysflags = TS\Controller::getInstance(); + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + // PHP_HOOK_NEW_INIT + [ + $snippets, + $config + ] = $this->_getSnippetsAndConfig($this->_build['new'], 'new'); + // PHP_HOOK_NEW_FIELDSET_START + $content = null; + $validator = new TermsValidator($this); + $urlAction = FULL_URL_APP_PREFIX . '/terms/new'; + $fieldSet = new LN\FieldSet('new', $config, $urlAction, $validator); + $fieldTerm_id = new LN\InputField($fieldSet, "term_id", ':db:hidden:', 'int', null, 'Id'); + $fieldName = new LN\InputField($fieldSet, "term_name", ':db:', 'text', null, 'Bezeichnung'); + $fieldDate = new LN\InputField($fieldSet, "term_date", ':db:', 'datetime', null, 'Datum'); + $fieldInfo = new LN\InputField($fieldSet, "term_info", ':db:', 'text', null, 'Bemerkungen'); + // PHP_HOOK_NEW_FIELDSET_COMPLETE_FIELDS + $fieldSet->setFromPost(); + // PHP_HOOK_NEW_START + $errorMessages = ''; + if (\array_key_exists('buttonClose', $_POST)) { + $linkPage = '/terms/base'; + // PHP_HOOK_NEW_REDIRECT_BUTTONCLOSE + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + } elseif (\array_key_exists('buttonSave', $_POST)) { + if (! $common->validate('terms.new.store', $fieldSet)) { + $errorMessages = $fieldSet->errorsAsHtml(); + } else { + $record = []; + $record['term_name'] = $fieldSet->getField('term_name')->value; + $record['term_date'] = LN\StringUtils::stringToDateTime($fieldSet->getField('term_date')->value, $error); + $record['term_info'] = $fieldSet->getField('term_info')->value; + // PHP_HOOK_NEW_BEFORE_INSERT + $term_id = $this->insertByRecordNewTerm($record); + $_POST['term_id'] = $term_id; + // PHP_HOOK_NEW_AFTER_INSERT + $linkPage = '/terms/edit?termID='; + $linkPage = str_replace('', \array_key_exists('term_id', $_GET) ? $_GET['term_id'] : $_POST['term_id'], $linkPage); + // PHP_HOOK_NEW_REDIRECT_BUTTONSAVE + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + // PHP_HOOK_NEW_STORE_END + } + } else { + if (! isset($_POST['term_name'])) { + // first entry: + // PHP_HOOK_NEW_FIRST_CALL + } else { + // PHP_HOOK_NEW_NOT_FIRST_CALL + if (! $common->validate('terms.new', $fieldSet)) { + $errorMessages = $fieldSet->errorsAsHtml(); + } else { + // PHP_HOOK_NEW_VALIDATED + } + } + } + if ($content === null) { + $breadcrumbs = [ + [ + $config['parent_title'], + 'base' + ], + [ + $config['local_title'], + '#' + ] + ]; + $content = $snippets->getSnippet('SNIPPET_ROOT', $config); + // PHP_HOOK_NEW_BREADCRUMBS + $content = $this->_setBreadcrumb($breadcrumbs, $content, $this->_moduleType); + $include = $snippets->getSnippet('SNIPPET_FIELDS', $config, ''); + $content = str_replace('###SNIPPET_FIELDS###', $include, $content); + // PHP_HOOK_NEW_HTML + $map = $locals->buildPlaceholderMap('', $config); + // PHP_HOOK_NEW_HTML_REPLACEMENT + $content = $common->replaceInHtmlWithErrors($content, 'terms', $fieldSet, $map, $errorMessages); + } + // PHP_HOOK_NEW_EXIT + return $content; + } + + /** + * Builds the html text for editing in page edit (without frame). + * + * @return string the HTML text of the "edit" page + */ + public function buildEdit(): string + { + $sysflags = TS\Controller::getInstance(); + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + // PHP_HOOK_EDIT_INIT + $termID = isset($_GET['termID']) ? $_GET['termID'] : (isset($_POST['term_id']) ? $_POST['term_id'] : -1); + [ + $snippets, + $config + ] = $this->_getSnippetsAndConfig($this->_build['edit'], 'edit'); + // PHP_HOOK_EDIT_FIELDSET_START + $content = null; + $validator = new TermsValidator($this); + $urlAction = FULL_URL_APP_PREFIX . '/terms/edit'; + $fieldSet = new LN\FieldSet('edit', $config, $urlAction, $validator); + $fieldTerm_id = new LN\InputField($fieldSet, "term_id", ':db:hidden:', 'int'); + $fieldName = new LN\InputField($fieldSet, "term_name", ':db:', 'text', null, 'Bezeichnung'); + $fieldDate = new LN\InputField($fieldSet, "term_date", ':db:', 'datetime', null, 'Datum'); + $fieldInfo = new LN\InputField($fieldSet, "term_info", ':db:', 'text', null, 'Bemerkungen'); + $fieldMembers = new LN\InputField($fieldSet, "members", ':readonly:', 'text', null, 'Platzanweiser'); + $fieldMembersShdw = new LN\InputField($fieldSet, "membersShdw", ':isshadow:hidden:', 'text'); + $fieldMember = new LN\InputField($fieldSet, "member", ':undef:', 'combobox', null, 'Ändern'); + // === start PHP_HOOK_EDIT_FIELDSET_COMPLETE_FIELDS + $common->fillUserCombobox($fieldMember, [1, 27, 30], false); + // === end PHP_HOOK_EDIT_FIELDSET_COMPLETE_FIELDS + $fieldSet->setFromPost(); + // PHP_HOOK_EDIT_START + if (isset($_POST['term_name'])) { + $termID = \array_key_exists('term_id', $_POST) ? $_POST['term_id'] : -1; + } else { + if (! \array_key_exists('termID', $_GET) || $_GET['termID'] <= 0) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . '/terms/base'); + } + if (! isset($record)){ + $record = $this->termById($termID); + } + $fieldSet->setFromRecord($record); + // === start PHP_HOOK_EDIT_FIRST_CALL_EARLY + $fieldMember->value = $_SESSION['userID']; + // === end PHP_HOOK_EDIT_FIRST_CALL_EARLY + } + // PHP_HOOK_EDIT_START2 + $errorMessages = ''; + if (\array_key_exists('buttonClose', $_POST)) { + $linkPage = '/terms/base'; + // PHP_HOOK_EDIT_REDIRECT_BUTTONCLOSE + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + } elseif (\array_key_exists('buttonSave', $_POST)) { + if (! $common->validate('terms.edit.store', $fieldSet)) { + $errorMessages = $fieldSet->errorsAsHtml(); + } else { + $record = []; + $id = LN\StringUtils::intOrNull($fieldSet->getField('term_id')->value); + $record['termID'] = $id; + $record['term_name'] = $fieldSet->getField('term_name')->value; + $record['term_date'] = LN\StringUtils::stringToDateTime($fieldSet->getField('term_date')->value, $error); + $record['term_info'] = $fieldSet->getField('term_info')->value; + // PHP_HOOK_EDIT_BEFORE_UPDATE + $this->updateByRecordEditTerm($id, $record); + // PHP_HOOK_EDIT_REDIRECT_AFTER_UPDATE + $linkPage = '/terms/base'; + // PHP_HOOK_EDIT_REDIRECT_BUTTONSAVE + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + // PHP_HOOK_EDIT_STORE_END + } + } else { + if (! isset($_POST['term_name'])) { + // first entry: + // PHP_HOOK_EDIT_FIRST_CALL + } else { + // PHP_HOOK_EDIT_NOT_FIRST_CALL + if (! $common->validate('terms.edit', $fieldSet)) { + $errorMessages = $fieldSet->errorsAsHtml(); + } else { + // === start PHP_HOOK_EDIT_VALIDATED + if (\array_key_exists('buttonAdd', $_POST)){ + $locals->addMember($fieldMember->value, $termID); + } elseif (\array_key_exists('buttonSub', $_POST)){ + $locals->subMember($fieldMember->value, $termID); + } + // === end PHP_HOOK_EDIT_VALIDATED + } + } + } + if ($content === null) { + $breadcrumbs = [ + [ + $config['parent_title'], + 'base' + ], + [ + $config['local_title'], + '#' + ] + ]; + $content = $snippets->getSnippet('SNIPPET_ROOT', $config); + // PHP_HOOK_EDIT_BREADCRUMBS + $content = $this->_setBreadcrumb($breadcrumbs, $content, $this->_moduleType); + $include = $snippets->getSnippet('SNIPPET_FIELDS', $config, ''); + $content = str_replace('###SNIPPET_FIELDS###', $include, $content); + $storageAllowed = true; + $buttonName = 'buttonSave'; + // === start PHP_HOOK_EDIT_HTML + $fieldMembers->value = $locals->membersOfTerm($termID); + // === end PHP_HOOK_EDIT_HTML + $common->switchConditional($content, 'SNIPPET_IF_2', null, 'role', '1,2', false, $snippets, $config); + $common->switchConditional($content, 'SNIPPET_IF_3', null, 'role', '3,4', false, $snippets, $config); + if (! $storageAllowed) { + $content = $common->deleteButton($content, $buttonName); + } + $map = $locals->buildPlaceholderMap('', $config); + // PHP_HOOK_EDIT_HTML_REPLACEMENT + $content = $common->replaceInHtmlWithErrors($content, 'terms', $fieldSet, $map, $errorMessages); + } + // PHP_HOOK_EDIT_EXIT + return $content; + } + + /** + * Handles the deletion request of a record. + * + * Deletion can also be done with changing a state property. + * + * @return string the HTML text of the deletion dialog + */ + private function buildDelete(): ?string + { + // PHP_HOOK_DELETE_INIT + [ + $snippets, + $config + ] = $this->_getSnippetsAndConfig($this->_build['delete'], 'delete'); + $sysflags = TS\Controller::getInstance(); + $record = null; + if (\array_key_exists('termID', $_GET)){ + $termID = $_GET['termID']; + $record = $this->termById($termID); + + } else { + $termID = \array_key_exists('term_id', $_POST) ? $_POST['term_id'] : -1; + + } + if ($record == null){ + $record = $this->termById($termID); + } + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + $content = $snippets->getSnippet('SNIPPET_ROOT', $config); + $breadcrumbs = [ + [ + $config['parent_title'], + 'base' + ], + [ + $config['local_title'], + '#' + ] + ]; + // PHP_HOOK_DELETE_BREADCRUMBS + $content = $this->_setBreadcrumb($breadcrumbs, $content, $this->_moduleType); + // PHP_HOOK_DELETE_START + $validator = null; + $urlAction = FULL_URL_APP_PREFIX . '/terms/delete'; + $fieldSet = new LN\FieldSet('delete', $config, $urlAction, $validator); + $fieldId = new LN\InputField($fieldSet, "term_id", ':hidden:'); + $fieldTerm_id = new LN\InputField($fieldSet, "term_id", ':db:hidden:', 'int', null, 'Id'); + $fieldName = new LN\InputField($fieldSet, "term_name", ':db:', 'text', null, 'Bezeichnung'); + $fieldDate = new LN\InputField($fieldSet, "term_date", ':db:', 'datetime', null, 'Datum'); + $fieldInfo = new LN\InputField($fieldSet, "term_info", ':db:', 'text', null, 'Bemerkungen'); + // PHP_HOOK_DELETE_FIELDSET_COMPLETE_FIELDS + $fieldSet->setAttributeForAll('readonly'); + $fieldSet->setFromPost(); + // PHP_HOOK_DELETE_START + if ($record != null){ + $fieldSet->setFromRecord($record); + } + $fieldId->value = $termID; + if (\array_key_exists('buttonClose', $_POST)) { + $linkPage = '/terms/base'; + // PHP_HOOK_DELETE_REDIRECT_BUTTONCLOSE + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + } elseif (isset($_POST['buttonDelete'])) { + $this->deleteTermById(intval($termID), $record); + $linkPage = '/terms/base'; + // PHP_HOOK_DELETE_REDIRECT_BUTTONDELETE + if ($linkPage != null) { + LN\Bootstrap::redirectUrl(URL_DOMAIN_APP_PREFIX . $linkPage); + $content = null; + } + } + $deleteAllowed = true; + $buttonName = 'buttonDelete'; + // PHP_HOOK_DELETE_HTML + if (! $deleteAllowed) { + $content = $common->deleteButton($content, $buttonName); + } + $map = $locals->buildPlaceholderMap('', $config); + // PHP_HOOK_DELETE_HTML_REPLACEMENT + $content = $common->replaceInHtmlWithErrors($content, 'terms', $fieldSet, $map); + // PHP_HOOK_DELETE_EXIT + return $content; + } + + /** + * Builds and displays the "base" page. + * Method will be called by URL. + * + * @return string the html text of the full page + * only used for unit testing + */ + public function base() + { + // PHP_HOOK_VIEW_BUILD_METHOD_BASE + $html = $this->buildBase(); + + $macros = $this->_getConfiguration($this->_build['base'], 'base'); + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + $html = $common->buildFullPage($macros, $html); + $locals->adaptFullPage($html); + $this->_showHTML($html); + return $html; + } + + /** + * Builds and displays the "new" page. + * Method will be called by URL. + * + * @return string the html text of the full page + * only used for unit testing + */ + public function new() + { + // PHP_HOOK_VIEW_BUILD_METHOD_NEW + $html = $this->buildNew(); + + $macros = $this->_getConfiguration($this->_build['new'], 'new'); + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + $html = $common->buildFullPage($macros, $html); + $locals->adaptFullPage($html); + $this->_showHTML($html); + return $html; + } + + /** + * Builds and displays the "edit" page. + * Method will be called by URL. + * + * @return string the html text of the full page + * only used for unit testing + */ + public function edit() + { + // PHP_HOOK_VIEW_BUILD_METHOD_EDIT + $html = $this->buildEdit(); + + $macros = $this->_getConfiguration($this->_build['edit'], 'edit'); + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + $html = $common->buildFullPage($macros, $html); + $locals->adaptFullPage($html); + $this->_showHTML($html); + return $html; + } + + /** + * Builds and displays the "delete" page. + * Method will be called by URL. + * + * @return string the html text of the full page + * only used for unit testing + */ + public function delete() + { + // PHP_HOOK_VIEW_BUILD_METHOD_DELETE + $html = $this->buildDelete(); + + $macros = $this->_getConfiguration($this->_build['delete'], 'delete'); + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + $html = $common->buildFullPage($macros, $html); + $locals->adaptFullPage($html); + $this->_showHTML($html); + return $html; + } + +} +class TermsValidator implements LN\IFieldValidator +{ + private $_controller; + private $_parent; + /** + * Constructor. + * + * @param Controller $controller + * the controller of the abbreviations module + */ + public function __construct(Controller $controller) + { + $this->_controller = $controller; + $parent = new TC\Validator(); + $this->setValidatorParent($parent); + } + /** + * + * {@inheritdoc} + * @see \lib\native\IFieldValidator::getValidatorParent() + */ + public function getValidatorParent(): ?IFieldValidator + { + return $this->_parent; + } + + /** + * + * {@inheritdoc} + * @see \lib\native\IFieldValidator::setValidatorParent() + */ + public function setValidatorParent(IFieldValidator $parent): void + { + $this->_parent = $parent; + } + /** + * + * {@inheritdoc} + * @see \lib\native\IFieldValidator::validateInputField() + */ + public function validateInputField(InputField $field): bool + { + $rc = true; + $common = TC\Controller::getInstance(); + $locals = LOC\Controller::getInstance(); + // PHP_HOOK_VALIDATION_START + // PHP_HOOK_VALIDATE_INPUT_FIELD + return $rc; + } +} +?> + diff --git a/app/users b/app/users new file mode 120000 index 0000000..e59009f --- /dev/null +++ b/app/users @@ -0,0 +1 @@ +../../skeleton/app/users \ No newline at end of file diff --git a/config/changes/skeletonversion.php b/config/changes/skeletonversion.php new file mode 120000 index 0000000..859d9fe --- /dev/null +++ b/config/changes/skeletonversion.php @@ -0,0 +1 @@ +../../../skeleton/config/changes/skeletonversion.php \ No newline at end of file diff --git a/config/changes/version.php b/config/changes/version.php new file mode 100644 index 0000000..e6db836 --- /dev/null +++ b/config/changes/version.php @@ -0,0 +1,22 @@ + diff --git a/config/sys/.gitignore b/config/sys/.gitignore new file mode 100644 index 0000000..8a71748 --- /dev/null +++ b/config/sys/.gitignore @@ -0,0 +1 @@ +/main.php diff --git a/config/sys/error.php b/config/sys/error.php new file mode 120000 index 0000000..4c84964 --- /dev/null +++ b/config/sys/error.php @@ -0,0 +1 @@ +../../../skeleton/config/sys/error.php \ No newline at end of file diff --git a/config/sys/loader.php b/config/sys/loader.php new file mode 120000 index 0000000..04111f1 --- /dev/null +++ b/config/sys/loader.php @@ -0,0 +1 @@ +../../../skeleton/config/sys/loader.php \ No newline at end of file diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..31cbb99 --- /dev/null +++ b/db/.gitignore @@ -0,0 +1 @@ +/webcal.sql.gz diff --git a/lib b/lib new file mode 120000 index 0000000..183f052 --- /dev/null +++ b/lib @@ -0,0 +1 @@ +../skeleton/lib \ No newline at end of file diff --git a/public/css/page/common/global.css b/public/css/page/common/global.css new file mode 120000 index 0000000..046e7c4 --- /dev/null +++ b/public/css/page/common/global.css @@ -0,0 +1 @@ +../../../../../skeleton/public/css/page/common/global.css \ No newline at end of file diff --git a/public/css/page/common/jquery.datetimepicker.css b/public/css/page/common/jquery.datetimepicker.css new file mode 120000 index 0000000..4851126 --- /dev/null +++ b/public/css/page/common/jquery.datetimepicker.css @@ -0,0 +1 @@ +../../../../../skeleton/public/css/page/common/jquery.datetimepicker.css \ No newline at end of file diff --git a/public/css/page/common/local.css b/public/css/page/common/local.css new file mode 100644 index 0000000..de23d49 --- /dev/null +++ b/public/css/page/common/local.css @@ -0,0 +1,133 @@ +@charset "UTF-8"; + +a { + color: #859319; +} + +fieldset { + background-color: #e4eda3; + border-radius: 4px; +} + +legend { + font-size: 0.9em; +} + +input { + border-radius: 3px; + margin-bottom: 0.5em; +} + +select { + border-radius: 3px; + margin-bottom: 0.5em; + height: 1.8em; +} + +button { + border-radius: 3px; +} + +label, .pseudo-label { + text-align: left; +} + +.page-item.active .page-link { + background-color: #B1C903 +} +/* Hintergrundfarbe der Navigation-Menue-Leiste */ +nav.navbar { + background-color: #B1C903; +} +/* Schrift in Menüleiste */ +.navbar a.nav-link { + color: #EEE; + /* background-color: #e4eda3; */ +} + +.tabs-modules { + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.tab-module-link { + display: block; + text-decoration: none; +} + +.tab-pane.active { + background-color: #e4eda3; +} + +.tabs-modules a.tab-module-link { + background-color: #f0f0f0; + border-color: #111; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + border: solid 1px black; + border-bottom: none; + padding: 0.5em; +} + +.tabs-modules a.tab-module-link, .tabs-modules a:link.tab-module-link, + .tabs-modules a:visited.tab-module-link, .tabs-modules a:active.tab-module-link, + .tabs-modules a:hover.tab-module-link { + text-decoration: none; + color: #859319; +} + +.tabs-modules a.tab-module-link.active { + background-color: #e4eda3; +} + +.tabs-modules a:hover.tab-module-link { + font-weight: bold; + color: #7c841e; +} + +.tabs-modules a:hover.tab-module-link.active { + text-decoration: none; + font-weight: normal; +} + +.tabs-modules a:hover.nav-link { + color: #444; + font-weight: bold; +} + +.page-item.active .page-link { + border-color: #879901; +} + +.page-link { + color: #B1C903; +} + +.page-link:hover { + color: #0; +} + +.paging-text { + font-size: 0.8em; +} + +.editdatetime, .edittextmiddle, .editselectshort, .edittextshort, + .editnumber { + width: 100%; +} + +.readonly { + background-color: #e4eda3; + border: 1px solid #B1C903; +} + +input, .pseudo-field { + width: 100%; +} + +.filtered-text { + background-color: #e4eda3; +} \ No newline at end of file diff --git a/public/css/page/common/pdf.global.css b/public/css/page/common/pdf.global.css new file mode 120000 index 0000000..88c8b9b --- /dev/null +++ b/public/css/page/common/pdf.global.css @@ -0,0 +1 @@ +../../../../../skeleton/public/css/page/common/pdf.global.css \ No newline at end of file diff --git a/public/css/page/overview/overview.global.css b/public/css/page/overview/overview.global.css new file mode 120000 index 0000000..5e78b45 --- /dev/null +++ b/public/css/page/overview/overview.global.css @@ -0,0 +1 @@ +../../../../../skeleton/public/css/page/overview/overview.global.css \ No newline at end of file diff --git a/public/css/page/overview/overview.local.css b/public/css/page/overview/overview.local.css new file mode 100644 index 0000000..ffd5d70 --- /dev/null +++ b/public/css/page/overview/overview.local.css @@ -0,0 +1,13 @@ +@charset "UTF-8"; + +a.overview-cell, a:visited.overview-cell, a:link.overview-cell, a:active.overview-cell, + .dashboard-link a, .dashboard-link a:visited, .dashboard-link a:link, + .dashboard-link a:active { + border: 1px solid #B1C903; + color: #859319; + box-shadow: 0 0 5px 0 #88961e; +} + +a:hover.overview-cell { + background-color: rgba(177, 201, 3, 0.5); +} \ No newline at end of file diff --git a/public/css/vendor b/public/css/vendor new file mode 120000 index 0000000..f174506 --- /dev/null +++ b/public/css/vendor @@ -0,0 +1 @@ +../../../skeleton/public/css/vendor \ No newline at end of file diff --git a/public/fonts b/public/fonts new file mode 120000 index 0000000..152b0c7 --- /dev/null +++ b/public/fonts @@ -0,0 +1 @@ +../../skeleton/public/fonts \ No newline at end of file diff --git a/public/icon/famfamfam b/public/icon/famfamfam new file mode 120000 index 0000000..21973d5 --- /dev/null +++ b/public/icon/famfamfam @@ -0,0 +1 @@ +../../../skeleton/public/icon/famfamfam \ No newline at end of file diff --git a/public/icon/favicon.ico b/public/icon/favicon.ico new file mode 120000 index 0000000..b2d1e8a --- /dev/null +++ b/public/icon/favicon.ico @@ -0,0 +1 @@ +kirchturm.ico \ No newline at end of file diff --git a/public/icon/kirchturm.ico b/public/icon/kirchturm.ico new file mode 100644 index 0000000000000000000000000000000000000000..c0bacdcd753ca4da26c9fbcaaeb11d5f7837005e GIT binary patch literal 8830 zcmV-^B7xli0096206;(h009690B9lr02TlM0EtjeM-2)Z3IG5A4M|8uQUCw|KmY&$ zKnMl^0063Kaozv`AOJ~3K~#90b(>kQBdn85=2}(RKP%zg^G%fBx@N;=g|XdI2!TaDFsRyFFJpq?9D12_bB+3nA1Cf+WWH z&}Sip?YS}Lp|t@-9%-5efP~$CuC+$tQA&|g0$>ycqYW*BPj7xg5j~Gx+b8FYlo9|b z)pm`X)AsM2)AXLF>*V(D^K&ioI0;&|H$fUuN=-M|APETPX{97PkC&o;Cq!b5D8P@J zS<|p_ks=j(Qle35s{l{^tt=M|4=7`604+InlBH@uL6V*}TL=SLDK5|Vs)BP}PZE$) z5tKlbx=v9o!HH>g`HbZ2bHTfr?Y9g;qK`s`_P{mjzR7JPa+&Z0bu1 z8l4H*FgFca8^+Y5l)~mhTLjT4)VyceMv7SD@`y18pA>!Hvu6aBi;${bWl2~Xowu*^ z-!`RT&xi-EZCExPAKg0UjaUARy*6{YIbug_*tkL}4~JKFg6sq#8-^SS*>HE`@kwnz zGpSTXNQFGNc-IJa`ovD3m^W1^)rBKQ28I;LIiYZPDezJ-in5LO4fT4f645AhFSo*K zt+(p|C_GwgPP43n8%>gavbKImAcZ3^vN}8F2d})wzxlU+h-&5xLX&7}Zc-NtGcu5* zujj^KWMFAp*13A8$`++Ba)#F0kaHp=%|KnqBvAzi1`HTTfI)2&iq(k_FOsKEirhev zEzA5sk_3Wqtdqi;#3oFN6^=`dWyE81K}t!$ZWU}yA-E~wrp)J``w}mF!y7x7;@x98=n2*S4c*2Z{xQfX^de#R;A|k1{ES+3KGrM05%uyZv57G z=b@sqMGqKS+2FiKN=2g^WN{>|2(h|jlmk5q7X(Pj?p!0BN71k}a2iIM3|&`~P>hj1 zBXG{4wZR2j6{RVwSugJWM(`G!Jeu4#GQ_~sW^x{B5mB@^04&+BO_Tr2yCoU+Lrg|e+K4^|-Ub+>i#K?z9E z3J{a^127^nSremYq(@OTd=6Nere^Bnd=DE(oQ5$w5P(r!(u(^oVbug|02wvG2yEOS zWs6afj6!Keim4`C8@DmN8WNjiNOwNuBe&vD{?{M#=;M#@+-Dx)Fbu@32}q18_%JeS zBx^Uhyo4s#^6VSK7zE&|0a_tRB$QTM}OR!BnjtaHTZTCd3sMh#d-{J5fRJ3e{$ zHJ<$J=V@(A@=eX?X&~o3-B7I(=Z6ZBBHJm^X&_-#BvF+wqXr61+rl_<>*J5O{^OT9 z{@@)hUAx4;{MY}A_m4n^07heJ@nNJv5jPp-&M2~_m;|&G*&+h$nSyhUL0WW*3E38i z{~zgr6cZsE8eh<|kZ2h5n&=WiX2!d>A5k^ZO z1C~)aT2mOMr8S8-WJcrAp_XVr8j>n>NVL)llOx(dOp%cF-%@~45zw?<;v^PCKE%`0 z6oZgGLovMkf4|GOe)G3j+ejir=@Nv#EM3U6VkXbHg zeC4_4K+f<vMM)a3r)+~NA8RRd$U3W6g^iY93S83dq4OAZ@v5- zZhi7Tez=D<4fDNSR!7H}W{0Pr{VbpT>}LtV(>FU9cY+r!Zb*!7ply0i+))kRrpMt} zxO3%bEU?#hjDSu?VRHpNUP2nn*6njnjFgJe0i-5vJV6B3S<&Q(O(S~*(&c>~xzZ4C zRiTYBBrOqc#5qVZ0*;s+PEs>;j?A@1;<)qaJN)pCH+l7??=#%`n8V{W%RWOcNFtll zdvqdm@8pCpfBUQK%v(+)NC}I1&#gOWoUT3AXht_siY3H>g&hgv0*V_M>1|6^36esK zs7b}u8vj6So*%u`#2hAIQ4@s@2~8ql*_}7M{`wt;qYwCc?nq_HtUKULW~39eO@nie z_&{hi?g-=#Pgud-x8LH&ufD=duY8Ykbe|+6J~$d18B@b-)}eESwwq$P`p7OXe({S0 zB`5@ff~L#dU)O7VI8SB~qkB#r9PBn287J3oFvc*`4SP$0uF1z>?2i-`VBA|Iz>E{zmYdzx@x%en3WrPYOtcRM)X8(JO;i8{U8G zuX*j2SGaZkEspLSF{CqEQ;^aj4Nw$$TvLn%QLJE$zUVDjGU-~}x4sTJ8?vq_0 z`eWL@=fNY0M5{B#Xgbqzd~}Fh^nC8CU&g3RNF!hv$?Pv0_Qe^8RKZHIoI1@xmoRNZ z*LD~qu|=ZWf|LPcEh#3nC?iF*Rd^LyIg3;iM9mjnR)_&r1T)=`rv5&J+P<97({@)m zcA8GJEjIwydboAxChxrdGVfe}k56xWKv>@cK*&U-Ap4%yD8`V`&Z1Q!DQMM#lwg$t zSvNfLXp99MAsY;}x@l=&Y8BpUj5%6FovkSj_@5iJdwAw(2{wg?Cjs|uzxtW&L< z3t$}`+CEG-0Z4a(Z6Y^s+~+S|{w`;S_j%{-x7nFXIwKH5;Kmh3TBK2wvZer0fR!zx z1WMLKKsN?TCWKf4%ls<8_Kg>jr6#-igfo)&3@PyVwOu~Ec}CHR-PuIPO?+h2w3S|? zx_(mxSyiKHH;yDaNCQzRS}D2j66c6bxbK7|wfX#qnl^Rj@idW5=!d*&DC&{u@8z_~;W(?|w>a6pfA)F%m+d zNC9-p9@nS@jgF`UZ47j(AY?<%8ZRZrXo`{i>X*L2)#V<^uSh8&ePm1$ zW#?=}{jFXk4tA>-G;K@Mw(Pfxd4JABBsv4##G&>=vrrj%nkAl*4V5$~LoIQhWhFd| z#(RfquU4LKeTd!JV{`Wg@4o&+F3l1yoN?wHCPzwk%qO7$8lf1|F;+-aD)l`VI#mFV z+yqoA_)x8$T|jBYX3RusS;xXRU-)%OV<@6UDMc}fzxW^jjV3y};)%sDlndW3lShTD z5mD3HLKY1}i3}yuO^x4KlE|fLYm5&W9TMIueRqQSIZj_@!nx)nxq2S?r`gaUvT~PS4hJV&7_1=x2eh~0#gE}1gwzE)KpDG zB9JLTVvtks4o%Y#lSHe`X3P{LDMd4+z||+8=AZtPf5hXL4geU*G;PDKhNf-!<*kp= zr9qd57$Qa|HdbJ#zCgBxh027ix9~ZC871A#Hud>drZ9QcN5URWZ3J%mZ6hN_S|bk+Q`aicenGyL*X$ z_y_-j-}~*~Wk?Z|D?oE&^`M2VQW#@6K04;`_z-}nuI}T@1`{?clSKcGeTJb#HWO}J zsEibSi|AWI2psve?V9GMVb3azh!_#EGff#rPVV03*7dj0?i5L6+^jiuo2}r3s6vXA zi77rLG{A94WId6t!cdIFmB`9h!ET+cIZcwC<$}Na&9AY}Q$wa|{CAB&*oqZQ7AQ00 zCvRWp=RbWNfPQxuKdzwB2%EOy0C40pz0lhn5VA(E4%ZlY-a<}YS6Cy=j8HDLXNHk| z6L{(6?=l?SqbXCOks2Xw zAXbUjXl#a=yr9I)14$6z%HEP!Uww@auD?lZ6M5q>lXYAyNFC36lfPwk868Z})fhzx ziNoQL(FJ^h#eB{a&pge}-WBY;XV&#Jx^VNxC(JKDLa%2CH!{LRr(3@Mjc@Skt8env z=fB0JkROIf4|0P>Mvf2faQ(+G z)B8Yl16P(y#?6}5rh0;ig=RvV=T4xz1#xpm)(x&iLMfaLBclsQ0++8oN;lu-@|DZX z_pSh7jltRmJ6X{rKtqrMg@RH|_`qB6SYg#?y(QEsBdg~Beq&FQ* zA+QOYJNfp|X0p1GiL>(r(>4!;1@w!{y!X?;f@&V^4B6o-p6Fn6N^z1QNQORU?{uFGoJJXC*~P+U(e5O;ZdFpwHH8+HPkn zIMfPYs8wOsN_yqF{^OUC(Nkok?HbnW0Up>%I44nEDOe#morJFI8QQMrVDEr~N3PN@ z7PMXMGiJ*PTi7|;7z_qSrfFM}tQDjY9dROVv@uP0WS?rH|MiguhH)<*+00l{f)(PQ8zq*#-4MK6M#yEK{kAP zlKF<3u?k1DN)d%4Mzh^!iy<~M6FYv1n;R#o5wb^Cu6>-2~QxVp2;;aOyt6)UH>yjR^) zn8=;C-sRpeUZqhZ>j2AUMrS(itxqUEaI!feWrde5ZDUyOJ@$~BFRf)M4Qal_YehE! zn0^w#aRF6jGJv9(Kr(yW8#A4nF*FJrUER8ug6@G*8?(U&U#m=lP6mvzoKo0qjzR9= z8cp(oh0Uat7?hzQBAuQS;|9Ih zpCMgfK5yC4g8O4&XRe5&;QG&h!qLa?AVS7v7^2|*>X4bXtfOcD>Jwa<^;~=WX_h-n zT&%o7x3^n!i8Y9ju(askn=~?B%rPcr$-){KP zcm9OcxS`XQJ9lp4P%M_aH2p45O>Vx}y^JWHcK?7DP%&XFYVfh8 zo2Yy@I*N{j%>x5~Kp7K*JEQG(fnzofQmMliLynanl!BZy+Ngy0nIa@b))w+R|MP$G zpZ~)jQqstB=Mua7*B%nQ2usrln%yPJ2dp(nRk6KFe#`MC49x@c02xckBTV}W#i%Lq z)zX)#iO_jZV=e0W`STggr0UCsH1SPhE9-?g_cwE_Vu-kDwjwl6V zG$<^AI(-J9o2EghL^2r>HAnY8<$Hhj$Lt+k;nGe=zgV!G5?j+YTfib@Tc=4TMm4DF zz8PCBt3VM*snpN#lzd@bB_(;v1tBS%vNWlBNM}K*%1o!BFq(`O0bLr#xUMXZlEe^+ z!eL~g(-x0nB-0g-2TUq-CUfWT9&-LHeJcpwlXb*LMSEUYvuNlA9Or@EYX^Mc>o4%> zhaa-Ps8I6qa*m(oZ-p}WD0#5qGSg1$gGZA*DQ9BZaB^~w9Z_iaE>D)%+oT8}sTBEn zf&|D3&PR-E0t{%QA%Ku0MhmjA5McDD1Sv43fUpE9u%-@r_Pe{-8=qiHWbk!P*hfV# zH91eSD6%+)qS$SEhO_%9+q1XaVY$;GR7U``lw=h#7{mj^$>$aml| z^UlxT=k_Nz(0$L}`8&^Y<=PXZl!!_IfiTtnbL&GLf!m+WCuJo5rDGUg5och)}`dUc> z<~w};^IzGPGGTHRXi8*chf!%;x5*A821?q19B9rrAhP51_=MBL8w#1>0Y`&mK-Fn-l|T)3E`16mqY~0A2~iQE zVikPt1%x9DOW3T5;~78y>FX#vr)va#BiIOANm4b(q(Ux+r>^dEdGB#tl-OK|(rpJo zbXzKV_Y!=Gw84{$LB$02Vl4e{9w{Z1lpNl=#XE0SI_lm>H~7l0eVNl7h~pW?T4K?h zomRz+$)ZYytcg_T4<vO!2k;&jgfZ;x(xatL1Vvsd=JkZnM`0#^T4#$z>o1bv` z+0PNAKuBNd@c>D6I9VXoxx|Pg=Tx5?Sm#iAz^LhkW|R$5gzd0o#ys?bTC$=N#IWY@ zY(o*2&B+;WzjvMg@tyBcghh3iwk_}KEK#zhnb1eZZcAbi5JX)Qs9vQ&$QBVIMKs$o zsEyu+tLbKB*)VLX@IUy`5BcNod>7|V5m6&`kBA!6)i7)F1rG4BPL8MZAWSJCi>o(Kl|xVx&7h$T)+NHv#O0 z<(FUL)}5P}<(yx>`z`>x8p`M>&79%*m}VOGIG1zC@xlXu?dg;-~DdJ=brf$W>VAUOj`tp>&>+3n^>buH}jSD)_RiP(7#~c^*?nR=W87fh3@2Y$`raDPg7#t{61|87Q)0Kr!FlC3P*SyNGMqHWcMq z&MjvrHxUGm4-au;-P4QHLlsI&v@zR6=)A`VL0WGZ+{h~UEd$i6O5q1tQ1dxm*JHXF zW;v&~H6(K}Xc;h_B#jQ0HZ<{+RXE!!>U?rs8x@hNCbXC$ovAsXs7Ml!lbz6>ooaQ1 z<04_rXLFA4)`j~b8N`LvH^(O&-?>jI1HbyE=h;2DM8CX@G?pGuRy{U5JPj~1q{uuD zNV6b^GrHjD{m4=`49Q_~;b`z&zy3>(?;Ub^#}GxuCnmQD-OzV+BiEW8kP+23ByaE{ z(#e)HcTBJ6w9*sZX|1T|jHw0O#HpqA1}4U~dWoWhN*7B4V}ay6Qh024L4~``$jy&# zaD3-Jn{lLTTR#87H`(9cXJ#x>!p3_#TP+=mN1MW22FM0m6!?L8KjZydH#q#{UG}bg zksTTa0(pJHcyx<5Ui}fb4^R2+-~0PK_V}ZG`paL|uqf37&$r0W4_iD(qQTPEXBebp zrh8;a)uql8i&QhD2aAY!ug@$f#NiLT5ftGi#?YXqS$L_%;zVgEJ zeC0P@9eQA0j-qULg7ZPnI`6trPj#W04XFIg~W%jEmtSE@AAR*_t}gik3D&fYmYxe z*A@;gJxUUO${`6yM)w`Tt*}`!rh$2Zxo)|2bV%8(Sg%jGdFu|VqhtQr@BI$x-iMst zxXxRXV!!qeexIF##~_b9{n+FD?BplB@ci@Kx^avD@}K^Q<<3=R%O$3p;Z$K)NJ=Mx zz|m0+6J=(kpg^;IY)`MErxU3@5))hYW|>^f775y*@KWJ?qO%FB>S*mSCO)|SKD!5( z_{?&L`C>ueDoitH7&Fd8Q3HL_G)h(BOTvW#wLaz6-8w9JdgnH3TydHtOO;v96i;4V z@YXM`b8@zZ8`rT4Zhd$ifZ^_Kn&MDX|G(!3fy)2@ z0wYO8K~yxB&Dn+*Uwi>K4%~kKJ+3b1+#Wsm#}VFqgAbp1nx~$7mXirgest%fntZS9 z@|(Z;Eq?Ldhy38B?{W3uX}-GuYYYX77W8__PMaA6j6u;fElO5SLdF=U$5rYhDtUU` zOqSZ_wiDImC^!nzogzY{4Vi_8-pnD_?r(i|AK5lsnhhK*EnOHzFhjpHhZ{G&s=dXPKp~QA}<`GUZ z+&u>1nP;ElS3ma*fAQ!4o8jm#MrBN{aN5Z_DWdR<`C{i=2PNo4jq{C;fZc{bD$q%X zo3MeBk_`RiBnHqojLx-dt7?zDSq;^w|V*}uX6c`3a`86oPG+0H{ZL?wa4~( z;rZv;`S=bWe|(*t%a<6v2MldqW2B`^}c_!E}4UVC!3 z;_0WJvX;BBLn$KcS|ybvX1?ZvX%Q07*qoM6N<$f)&lb AR{#J2 literal 0 HcmV?d00001 diff --git a/public/icon/msg b/public/icon/msg new file mode 120000 index 0000000..a474549 --- /dev/null +++ b/public/icon/msg @@ -0,0 +1 @@ +../../../skeleton/public/icon/msg \ No newline at end of file diff --git a/public/icon/start b/public/icon/start new file mode 120000 index 0000000..fca59e8 --- /dev/null +++ b/public/icon/start @@ -0,0 +1 @@ +../../../skeleton/public/icon/start \ No newline at end of file diff --git a/public/img/vendor b/public/img/vendor new file mode 120000 index 0000000..2408d6c --- /dev/null +++ b/public/img/vendor @@ -0,0 +1 @@ +../../../skeleton/public/img/vendor \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..94ed55f --- /dev/null +++ b/public/index.php @@ -0,0 +1,72 @@ +errorHandler($error['type'], $error['message'], $error['file'], $error['line'], debug_backtrace()); + } + + session_write_close(); + + if (LN\Config::get('main_sys')['profiler']['logAtShutdown']) { + LN\Profiler::getInstance()->end(); + } +}); +define('AJAX', LN\Tool::isAJAX()); +define('DOMAIN', LN\Config::getHostConfig('main_sys:domain', 'covid.infeos.eu')); + +// If changed: change root.definitions.php also! +LN\SemaphorePool::init(array( + "singleton" => 47 +)); + +LN\Error::getInstance(); + +LN\Session::getInstance(); +if (LN\Config::get('main_sys')['autoLogin']) { + $_SESSION['roleID'] = ROLE_MANAGER; + $_SESSION['userID'] = 4; + $_SESSION['shortname'] = 'wk'; +} + +LN\Bootstrap::getInstance(); + +?> diff --git a/public/js/common b/public/js/common new file mode 120000 index 0000000..58acc78 --- /dev/null +++ b/public/js/common @@ -0,0 +1 @@ +../../../skeleton/public/js/common \ No newline at end of file diff --git a/public/js/vendor b/public/js/vendor new file mode 120000 index 0000000..4f48350 --- /dev/null +++ b/public/js/vendor @@ -0,0 +1 @@ +../../../skeleton/public/js/vendor \ No newline at end of file diff --git a/tools/generator/.gitignore b/tools/generator/.gitignore new file mode 100644 index 0000000..62ad278 --- /dev/null +++ b/tools/generator/.gitignore @@ -0,0 +1,2 @@ +/generator.root.def.php +/rungenerator.php diff --git a/tools/generator/templates b/tools/generator/templates new file mode 120000 index 0000000..3dfdcb1 --- /dev/null +++ b/tools/generator/templates @@ -0,0 +1 @@ +../../../skeleton/tools/generator/templates \ No newline at end of file diff --git a/tools/generator/terms.module b/tools/generator/terms.module new file mode 100644 index 0000000..ddeba02 --- /dev/null +++ b/tools/generator/terms.module @@ -0,0 +1,102 @@ +module Terms Term + option.module use:terms.snippets.php + option.module project:webcal + option.module type:backend + + dbtable terms term + dbfield term_id "Id" int primary + dbfield term_name "Bezeichnung" text size:32 secondary + dbfield term_date "Datum" datetime + dbfield term_info "Bemerkungen" text size:4000 rows:3 + option.dbtable default.order:term_date + end.dbtable + + dbtable userterms userterm + option.dbtable make.sql + dbfield term_id "Id" int primary + dbfield userterm_term " " int ref:terms.term_id + dbfield userterm_user " " int ref:loginusers.user_id + end.dbtable + + dbtable loginusers user + dbfield user_id "Id" int primary + dbfield user_name "Kennung" text size:200 secondary notnull unique width:2:4 + dbfield user_displayname "Anzeigename" text size:32 notnull unique width:2:4 + dbfield user_shortname "Kürzel" text size:20 notnull unique width:2:4 + dbfield user_login "E-Mail" text size:100 notnull unique width:2:4 + dbfield user_gender "Geschlecht" text size:1 notnull field.option:undef combobox width:2:4 + dbfield user_status "Status" int ref:sysflags.sysflag_id field.option:undef width:2:4 + dbfield user_info "Info" text size:128 width:2:10 + dbfield role_id "Rolle" int ref:roles.role_id field.option:undef width:2:4 + dbfield user_hourssat "Stunden Sa" float width:2:1 + dbfield user_hourssun "So" float width:1:1 + dbfield user_hoursmon "Stunden Mo" float width:2:1 + dbfield user_hourstue "Di" float width:1:1 + dbfield user_hourswed "Mi" float width:1:1 + dbfield user_hoursthu "Do" float width:1:1 + dbfield user_hoursfri "Fr" float width:1:1 + dbfield user_pass "Passwort" text size:200 hidden + dbfield user_token "Token" text size:100 hidden + dbfield user_tokenstamp "Tokenzeit" datetime hidden + dbfield changed "Geändert" datetime update now hidden + dbfield changedby "Geändert von" text size:20 auto.user hidden + dbfield created "Erzeugt" datetime update now hidden + dbfield createdby "Erzeugt von" text size:20 auto.user hidden + end.dbtable + + page base "Termine" + option.page sql.getall:PHP_HOOK_SQL_GET_ALL + option.page sql.getall.count:PHP_HOOK_SQL_GET_ALL_COUNT + section panel.fields + empty.line + if role in 1,2 + button buttonNew "Neuer Termin" 0 12 redirect:*.new + empty.line + end.if + end.section + section table + option.table viewed:term_id:term_date:term_name:members:term_info + option.table sorted:term_id:term_date:term_name + option.table heads:"Id":"Datum":"Bezeichnung":"Platzanweiser":"Bemerkung" + option.table edit.by.dialog + option.table delete.by.dialog + end.section + end.page + + page new "Neuer Termin" + section panel.fieldgroup + fill.from.db.table terms + button buttonSave "Speichern" 2 4 save.and.edit + button buttonClose "Schließen" 2 4 close + end.section + end.page + + page edit "Termin ändern" + section panel.fieldgroup + dbreference term_name 2 4 + dbreference term_date 2 4 + dbreference term_info 2 10 + field members "Platzanweiser" text 2 10 rows:3 readonly no.storage + field member "Ändern" int 2 4 combobox undef no.storage + button buttonAdd "Hinzufügen" 0 3 none + button buttonSub "Entfernen" 0 3 none + empty.line + if role in 1,2 + button buttonSave "Speichern" 2 4 save.and.exit + end.if + if role in 3,4 + filler 6 + end.if + button buttonClose "Schließen" 0 3 close + end.section + end.page + + page delete "Termin löschen" + section panel.fieldgroup + fill.from.db.table terms + button buttonDelete "Löschen" 2 4 delete.direct + button buttonClose "Schließen" 2 4 close + end.section + end.page + +end.module diff --git a/tools/generator/terms.snippets.php b/tools/generator/terms.snippets.php new file mode 100644 index 0000000..8aecdc0 --- /dev/null +++ b/tools/generator/terms.snippets.php @@ -0,0 +1,39 @@ +PHP_HOOK_SQL_GET_ALL: +SELECT + tt.*,'dummy' as members +FROM + terms tt +WHERE + tt.deletedat is null + +PHP_HOOK_SQL_GET_ALL_COUNT: +SELECT + count(*) +FROM + terms tt +WHERE + tt.deletedat is null + +PHP_HOOK_EDIT_FIELDSET_COMPLETE_FIELDS: + $common->fillUserCombobox($fieldMember, [1, 27, 30], false); + +PHP_HOOK_EDIT_VALIDATED: + if (\array_key_exists('buttonAdd', $_POST)){ + $locals->addMember($fieldMember->value, $termID); + } elseif (\array_key_exists('buttonSub', $_POST)){ + $locals->subMember($fieldMember->value, $termID); + } + +PHP_HOOK_EDIT_HTML: + $fieldMembers->value = $locals->membersOfTerm($termID); + +PHP_HOOK_BASE_TABLE_ROW_ADAPTION: + $rec['members'] = $locals->membersOfTerm($rec['term_id']); + +PHP_HOOK_EDIT_FIRST_CALL_EARLY: + $fieldMember->value = $_SESSION['userID']; + +PHP_HOOK_BASE_TABLE_RECORDS_ADAPTION: + $deleteAllowed = $_SESSION['roleID'] <= 2; + +END: \ No newline at end of file diff --git a/tpl/email/newPwd.html b/tpl/email/newPwd.html new file mode 100644 index 0000000..f9c805b --- /dev/null +++ b/tpl/email/newPwd.html @@ -0,0 +1,16 @@ + + + + + +

    [&&SALUTATION] [&&PERSON],

    +

    Ihr neues Passwort lautet: [&&PASSWORD]

    +

    Mit freundlichen Grüßen

    +

    [&&EMAIL_SIGNATURE]

    + + \ No newline at end of file diff --git a/tpl/email/newPwd.txt b/tpl/email/newPwd.txt new file mode 100644 index 0000000..11deb5f --- /dev/null +++ b/tpl/email/newPwd.txt @@ -0,0 +1,7 @@ +[&&SALUTATION] [&&PERSON], + +Ihr neues Passwort lautet: [&&PASSWORD] + +Mit freundlichen Grüßen + +[&&EMAIL_SIGNATURE] \ No newline at end of file diff --git a/tpl/email/newUser.html b/tpl/email/newUser.html new file mode 100644 index 0000000..e66bbb0 --- /dev/null +++ b/tpl/email/newUser.html @@ -0,0 +1,26 @@ + + + + + +

    [&&SALUTATION] [&&PERSON],

    +

    Sie wurden auf dem Webportal - TimeTracking angelegt: [&&LINK]

    + + + + + + + + + +
    Benutzername:[&&EMAIL]
    Passwort:[&&PASSWORD]
    +

    Mit freundlichen Grüßen

    +

    [&&EMAIL_SIGNATURE]

    + + \ No newline at end of file diff --git a/tpl/email/newUser.txt b/tpl/email/newUser.txt new file mode 100644 index 0000000..d95eb4f --- /dev/null +++ b/tpl/email/newUser.txt @@ -0,0 +1,10 @@ +[&&SALUTATION] [&&PERSON], + +Sie wurden auf dem Webportal - TimeTracking angelegt: [&&LINK] + +Benutzername: [&&EMAIL] +Passwort: [&&PASSWORD] + +Mit freundlichen Grüßen + +[&&EMAIL_SIGNATURE] \ No newline at end of file diff --git a/tpl/email/pwdForgotten.html b/tpl/email/pwdForgotten.html new file mode 100644 index 0000000..6e29ef1 --- /dev/null +++ b/tpl/email/pwdForgotten.html @@ -0,0 +1,17 @@ + + + + + +

    [&&SALUTATION] [&&PERSON],

    +

    klicken Sie bitte auf den Link um Ihr Passwort zu ändern. Die Sitzung ist in [&&TIMEOUT] Minuten abgelaufen:

    +

    Passwort ändern

    +

    Mit freundlichen Grüßen

    +

    [&&EMAIL_SIGNATURE]

    + + \ No newline at end of file diff --git a/tpl/email/pwdForgotten.txt b/tpl/email/pwdForgotten.txt new file mode 100644 index 0000000..61a9a87 --- /dev/null +++ b/tpl/email/pwdForgotten.txt @@ -0,0 +1,9 @@ +[&&SALUTATION] [&&PERSON], + +klicken Sie bitte auf den Link um Ihr Passwort zu ändern. Die Sitzung ist [&&TIMEOUT] Minuten abgelaufen: + +[&&LINK] + +Mit freundlichen Grüßen + +[&&EMAIL_SIGNATURE] \ No newline at end of file -- 2.39.5