diff --git a/composer.json b/composer.json index a4d74d5..4978860 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "jbroadway/urlify": "1.1.3", "laminas/laminas-permissions-acl": "^2.10", "akrabat/proxy-detection-middleware": "^1.0.0", - "gregwar/captcha": "1.*" + "gregwar/captcha": "master" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 0918dfa..5adb12f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0cc1a21b272d67b53b9e5f448c2960ac", + "content-hash": "841b98a23a247d8faad15d86df8cbeba", "packages": [ { "name": "akrabat/proxy-detection-middleware", @@ -223,16 +223,16 @@ }, { "name": "gregwar/captcha", - "version": "v1.2.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/Gregwar/Captcha.git", - "reference": "6e5b61b66ac89885b505153f4ef9a74ffa5b3074" + "reference": "5b8323637b502d3dbcbe28a74633dad8aed63452" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/6e5b61b66ac89885b505153f4ef9a74ffa5b3074", - "reference": "6e5b61b66ac89885b505153f4ef9a74ffa5b3074", + "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/5b8323637b502d3dbcbe28a74633dad8aed63452", + "reference": "5b8323637b502d3dbcbe28a74633dad8aed63452", "shasum": "" }, "require": { @@ -244,6 +244,7 @@ "require-dev": { "phpunit/phpunit": "^6.4" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -274,9 +275,9 @@ ], "support": { "issues": "https://github.com/Gregwar/Captcha/issues", - "source": "https://github.com/Gregwar/Captcha/tree/v1.2.0" + "source": "https://github.com/Gregwar/Captcha/tree/master" }, - "time": "2023-03-24T22:12:41+00:00" + "time": "2023-05-08T15:17:31+00:00" }, { "name": "jbroadway/urlify", diff --git a/content/00-welcome/05-todos.md b/content/00-welcome/05-todos.md index e3abce2..cfb60a8 100644 --- a/content/00-welcome/05-todos.md +++ b/content/00-welcome/05-todos.md @@ -9,6 +9,8 @@ * DONE: License feature * DONE: Enhance with plugins +[:contactform :] + ---- ## Visual Editor @@ -93,20 +95,20 @@ ## Open tasks * DONE: Sitemap and ping -* SVG checker -* Version check +* DONE: Version check +* DONE: Proxy support +* DONE: SVG checker: https://github.com/TribalSystems/SVG-Sanitizer +* NEARLY DONE: Backend form builder * Markdown secure rendering * Responsive design -* Backend form builder -* Proxy support * Image generation on the fly * Captcha integration -* Clear cache -* Show security Log +* Fix error api systemnavi * Reference feature * Typemill Utilities +* Clear cache +* Show security Log * User search only for +10 users -* Fix error api systemnavi ## Cleanups: diff --git a/content/00-welcome/05-todos.txt b/content/00-welcome/05-todos.txt index 8ae8731..7b4b3ad 100644 --- a/content/00-welcome/05-todos.txt +++ b/content/00-welcome/05-todos.txt @@ -1 +1 @@ -["# ToDos Version 2","[TOC]","## System settings","* DONE: Migrate from backend to frontend with vue and api\n* DONE: Redesign\n* DONE: License feature\n* DONE: Enhance with plugins","----","## Visual Editor","* DONE: Refactor and redesign\n* DONE: Fix toc component in new block\n* DONE: Fix hr component in new block\n* DONE: finish shortcode component\n* DONE: Fix inline formats\n* DONE: fix lenght of page\n* DONE: Fix design of new block at the end (background color)\n* DONE: Move Block\n* DONE: Fix headline design\n* DONE: Fix save on two enter\n* DONE: fix quote design\n* DONE: Fix toc preview\n* DONE: disable enable \n* DONE: Add load sign (from navigation)\n* DONE: File is not published from tmp to media\/files if you save the block.\n* ToDo: Customfields not styled yet.\n* ToDo: Warn if open another block\n* ToDo: finish youtube component","## Raw Editor","* DONE: Refactor and redesign\n* DONE: Integrate highlighting","## Navigation","* DONE: Refactor and redesign\n* DONE: fix status in navigation\n* DONE: refresh navigation after changes\n* ToDo: fix error messages\n* ToDo: Wrong frontend navigation if unpublished pages","## Publish Controller","* DONE: Refactor and redesign\n* DONE: Create \n* DONE: publish\n* DONE: unpublish\n* DONE: discard\n* DONE: delete\n* DONE: save draft\n* DONE: switch to raw","## Meta Tabs","* DONE: Refactor and redesign\n* DONE: Enhance with plugins","## Medialib","* DONE: Refactor and redesign","## Posts","* DONE: Refactor and redesign","## Plugins","* Asset Class in progress","## Frontend","* DONE: Refactor\n* DONE: Test restrictions","## Other big tasks","* DONE: System setup\n* DONE: Recover Password","## Medium tasks","* DONE: Merge processAssets modell\n* DONE: Table of content duplicated for published pages\n* DONE: Session handling: csrf fail and session start error if restrictions are active\n* DONE: Image and files for meta","## Open tasks","* DONE: Sitemap and ping\n* DONE: Version check\n* DONE: Proxy support\n* DONE: SVG checker: https:\/\/github.com\/TribalSystems\/SVG-Sanitizer\n* Markdown secure rendering\n* Responsive design\n* Backend form builder\n* Image generation on the fly\n* Captcha integration\n* Fix error api systemnavi\n* Reference feature\n* Typemill Utilities\n* Clear cache\n* Show security Log\n* User search only for +10 users","## Cleanups:","* DONE: Events\n* Error messages\n* Translations","## Info: Select userroles","* Userroles for file restriction: in vue-blox-components loaded via api\n* Userroles for userfields: in php model user getUserFields()\n* Userroles for meta: in php controller apiAuthorMeta getMeta()\n* Plugins and themes: in php model extension getThemeDefinitions()","## Info: License Check","* On activation in apiControllerExtension. It checks the license in yaml.\n* In plugin php code with setPremiumLicense\n* In static plugins, it checks manual premium list and method setPremiumLicense and more "] \ No newline at end of file +["# ToDos Version 2","[TOC]","## System settings","* DONE: Migrate from backend to frontend with vue and api\n* DONE: Redesign\n* DONE: License feature\n* DONE: Enhance with plugins","[:contactform :]","----","## Visual Editor","* DONE: Refactor and redesign\n* DONE: Fix toc component in new block\n* DONE: Fix hr component in new block\n* DONE: finish shortcode component\n* DONE: Fix inline formats\n* DONE: fix lenght of page\n* DONE: Fix design of new block at the end (background color)\n* DONE: Move Block\n* DONE: Fix headline design\n* DONE: Fix save on two enter\n* DONE: fix quote design\n* DONE: Fix toc preview\n* DONE: disable enable \n* DONE: Add load sign (from navigation)\n* DONE: File is not published from tmp to media\/files if you save the block.\n* ToDo: Customfields not styled yet.\n* ToDo: Warn if open another block\n* ToDo: finish youtube component","## Raw Editor","* DONE: Refactor and redesign\n* DONE: Integrate highlighting","## Navigation","* DONE: Refactor and redesign\n* DONE: fix status in navigation\n* DONE: refresh navigation after changes\n* ToDo: fix error messages\n* ToDo: Wrong frontend navigation if unpublished pages","## Publish Controller","* DONE: Refactor and redesign\n* DONE: Create \n* DONE: publish\n* DONE: unpublish\n* DONE: discard\n* DONE: delete\n* DONE: save draft\n* DONE: switch to raw","## Meta Tabs","* DONE: Refactor and redesign\n* DONE: Enhance with plugins","## Medialib","* DONE: Refactor and redesign","## Posts","* DONE: Refactor and redesign","## Plugins","* Asset Class in progress","## Frontend","* DONE: Refactor\n* DONE: Test restrictions","## Other big tasks","* DONE: System setup\n* DONE: Recover Password","## Medium tasks","* DONE: Merge processAssets modell\n* DONE: Table of content duplicated for published pages\n* DONE: Session handling: csrf fail and session start error if restrictions are active\n* DONE: Image and files for meta","## Open tasks","* DONE: Sitemap and ping\n* DONE: Version check\n* DONE: Proxy support\n* DONE: SVG checker: https:\/\/github.com\/TribalSystems\/SVG-Sanitizer\n* DONE: Backend form builder\n* Handle formdata centrally ???\n* Image generation on the fly\n* Markdown secure rendering\n* Responsive design\n* Captcha integration\n* Fix error api systemnavi\n* Reference feature\n* Typemill Utilities\n* Clear cache\n* Show security Log\n* User search only for +10 users","## Cleanups:","* DONE: Events\n* Error messages\n* Translations","## Info: Select userroles","* Userroles for file restriction: in vue-blox-components loaded via api\n* Userroles for userfields: in php model user getUserFields()\n* Userroles for meta: in php controller apiAuthorMeta getMeta()\n* Plugins and themes: in php model extension getThemeDefinitions()","## Info: License Check","* On activation in apiControllerExtension. It checks the license in yaml.\n* In plugin php code with setPremiumLicense\n* In static plugins, it checks manual premium list and method setPremiumLicense and more "] \ No newline at end of file diff --git a/content/00-welcome/05-todos.yaml b/content/00-welcome/05-todos.yaml index 1a374d9..77a04a6 100644 --- a/content/00-welcome/05-todos.yaml +++ b/content/00-welcome/05-todos.yaml @@ -6,7 +6,7 @@ meta: heroimagealt: null owner: Sebastian author: null - allowedrole: contributor + allowedrole: '' alloweduser: null manualdate: null modified: '2023-06-19' diff --git a/system/Extensions/ParsedownExtension.php b/system/Extensions/ParsedownExtension.php index 11c38b0..dafb157 100644 --- a/system/Extensions/ParsedownExtension.php +++ b/system/Extensions/ParsedownExtension.php @@ -736,6 +736,7 @@ class ParsedownExtension extends \ParsedownExtra protected function blockShortcode($Line) { + if ($this->dispatcher && preg_match('/^\[:.*:\]/', $Line['text'], $matches)) { return $this->createShortcodeArray($matches,$block = true); diff --git a/system/typemill/Controllers/ControllerApiAuthorArticle.php b/system/typemill/Controllers/ControllerApiAuthorArticle.php index 64efa77..782a7f8 100644 --- a/system/typemill/Controllers/ControllerApiAuthorArticle.php +++ b/system/typemill/Controllers/ControllerApiAuthorArticle.php @@ -59,7 +59,7 @@ class ControllerApiAuthorArticle extends Controller } # publish content - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); $publish = $content->publishMarkdown($item, $draftMarkdown); if($publish !== true) @@ -141,7 +141,7 @@ class ControllerApiAuthorArticle extends Controller } # publish content - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); $content->unpublishMarkdown($item, $draftMarkdown); @@ -218,7 +218,7 @@ class ControllerApiAuthorArticle extends Controller } # save draft content - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $markdown = $params['title'] . PHP_EOL . PHP_EOL . $params['body']; $markdownArray = $content->markdownTextToArray($markdown); $content->saveDraftMarkdown($item, $markdownArray); @@ -281,7 +281,7 @@ class ControllerApiAuthorArticle extends Controller } # save draft content - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $markdown = $params['title'] . PHP_EOL . PHP_EOL . $params['body']; $markdownArray = $content->markdownTextToArray($markdown); $content->publishMarkdown($item, $markdownArray); @@ -361,7 +361,7 @@ class ControllerApiAuthorArticle extends Controller } # publish content - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $content->deleteDraft($item); # refresh navigation and item @@ -896,7 +896,7 @@ class ControllerApiAuthorArticle extends Controller return $response->withHeader('Content-Type', 'application/json')->withStatus(404); } - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); # check if it is a folder and if the folder has published pages. if($item->elementType == 'folder') diff --git a/system/typemill/Controllers/ControllerApiAuthorBlock.php b/system/typemill/Controllers/ControllerApiAuthorBlock.php index 4e187b0..d81b497 100644 --- a/system/typemill/Controllers/ControllerApiAuthorBlock.php +++ b/system/typemill/Controllers/ControllerApiAuthorBlock.php @@ -50,7 +50,7 @@ class ControllerApiAuthorBlock extends Controller return $response->withHeader('Content-Type', 'application/json')->withStatus(404); } - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); # if it is a new content-block @@ -154,7 +154,7 @@ class ControllerApiAuthorBlock extends Controller return $response->withHeader('Content-Type', 'application/json')->withStatus(404); } - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); @@ -247,7 +247,7 @@ class ControllerApiAuthorBlock extends Controller return $response->withHeader('Content-Type', 'application/json')->withStatus(404); } - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); @@ -353,7 +353,7 @@ class ControllerApiAuthorBlock extends Controller return $response->withHeader('Content-Type', 'application/json')->withStatus(404); } - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); diff --git a/system/typemill/Controllers/ControllerWebAuthor.php b/system/typemill/Controllers/ControllerWebAuthor.php index 0d53ffc..0ba16ca 100644 --- a/system/typemill/Controllers/ControllerWebAuthor.php +++ b/system/typemill/Controllers/ControllerWebAuthor.php @@ -7,7 +7,6 @@ use Psr\Http\Message\ResponseInterface as Response; use Slim\Routing\RouteContext; use Typemill\Models\Navigation; use Typemill\Models\Content; -use Typemill\Models\SvgSanitizer; use Typemill\Events\OnPagetreeLoaded; use Typemill\Events\OnItemLoaded; use Typemill\Events\OnMarkdownLoaded; @@ -17,10 +16,7 @@ use Typemill\Events\OnPageReady; class ControllerWebAuthor extends Controller { public function showBlox(Request $request, Response $response, $args) - { - - $svg = new SvgSanitizer(); - + { # get url for requested page $url = isset($args['route']) ? '/' . $args['route'] : '/'; $urlinfo = $this->c->get('urlinfo'); @@ -65,7 +61,7 @@ class ControllerWebAuthor extends Controller $mainNavigation = $navigation->getMainNavigation($request->getAttribute('c_userrole'), $this->c->get('acl'), $urlinfo, $this->settings['editor']); - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); $draftMarkdown = $this->c->get('dispatcher')->dispatch(new OnMarkdownLoaded($draftMarkdown), 'onMarkdownLoaded')->getData(); @@ -134,7 +130,7 @@ class ControllerWebAuthor extends Controller $mainNavigation = $navigation->getMainNavigation($request->getAttribute('c_userrole'), $this->c->get('acl'), $urlinfo, $this->settings['editor']); - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $draftMarkdown = $content->getDraftMarkdown($item); $draftMarkdown = $this->c->get('dispatcher')->dispatch(new OnMarkdownLoaded($draftMarkdown), 'onMarkdownLoaded')->getData(); diff --git a/system/typemill/Controllers/ControllerWebFrontend.php b/system/typemill/Controllers/ControllerWebFrontend.php index ebfef03..67c7add 100644 --- a/system/typemill/Controllers/ControllerWebFrontend.php +++ b/system/typemill/Controllers/ControllerWebFrontend.php @@ -90,7 +90,7 @@ class ControllerWebFrontend extends Controller # GET THE CONTENT - $content = new Content($urlinfo['baseurl']); + $content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher')); $liveMarkdown = $content->getLiveMarkdown($item); $liveMarkdown = $this->c->get('dispatcher')->dispatch(new OnMarkdownLoaded($liveMarkdown), 'onMarkdownLoaded')->getData(); $markdownArray = $content->markdownTextToArray($liveMarkdown); diff --git a/system/typemill/Extensions/ParsedownExtension.php b/system/typemill/Extensions/ParsedownExtension.php index 7f557f3..2c6037d 100644 --- a/system/typemill/Extensions/ParsedownExtension.php +++ b/system/typemill/Extensions/ParsedownExtension.php @@ -361,7 +361,7 @@ class ParsedownExtension extends \ParsedownExtra } $text = trim($Line['text'], '#'); - $headline = Slug::createSlug($Line['text'], $this->settings); + $headline = Slug::createSlug($Line['text'], $this->settings['langattr']); if ($this->strictMode and isset($text[0]) and $text[0] !== ' ') { @@ -815,7 +815,7 @@ class ParsedownExtension extends \ParsedownExtra } } - $html = $this->dispatcher->dispatch('onShortcodeFound', new OnShortcodeFound($shortcode))->getData(); + $html = $this->dispatcher->dispatch(new OnShortcodeFound($shortcode), 'onShortcodeFound')->getData(); # if no shortcode has been processed, add the original string if(is_array($html) OR is_object($html)) diff --git a/system/typemill/Extensions/TwigCaptchaExtension.php b/system/typemill/Extensions/TwigCaptchaExtension.php new file mode 100644 index 0000000..a0a208f --- /dev/null +++ b/system/typemill/Extensions/TwigCaptchaExtension.php @@ -0,0 +1,46 @@ +build(); + + $error = ''; + if(isset($_SESSION['captcha']) && $_SESSION['captcha'] === 'error') + { + $error = 'The captcha was wrong.'; + } + + $_SESSION['phrase'] = $builder->getPhrase(); + + $_SESSION['captcha'] = true; + + $template = '
' . + '' . + '' . + $error . + '' . + '
'; + + return $template; + } + } +} \ No newline at end of file diff --git a/system/typemill/Models/Content.php b/system/typemill/Models/Content.php index 8290268..a517c5b 100644 --- a/system/typemill/Models/Content.php +++ b/system/typemill/Models/Content.php @@ -9,10 +9,10 @@ class Content { private $storage; - public function __construct($baseurl = NULL) + public function __construct($baseurl = NULL, $settings = NULL, $dispatcher = NULL) { $this->storage = new StorageWrapper('\Typemill\Models\Storage'); - $this->parsedown = new ParsedownExtension($baseurl); + $this->parsedown = new ParsedownExtension($baseurl, $settings, $dispatcher); } public function getDraftMarkdown($item) diff --git a/system/typemill/Models/Extension.php b/system/typemill/Models/Extension.php index 77c40a2..c07fc04 100644 --- a/system/typemill/Models/Extension.php +++ b/system/typemill/Models/Extension.php @@ -70,8 +70,8 @@ class Extension 'description' => 'You can overwrite the theme-css with your own css here.' ]; - # add image preview file - $themeSettings['preview'] = 'http://localhost/typemill/themes/' . $themeName . '/' . $themeName . '.png'; +# add image preview file + $themeSettings['preview'] = '/themes/' . $themeName . '/' . $themeName . '.png'; return $themeSettings; } diff --git a/system/typemill/Models/Field.php b/system/typemill/Models/Field.php new file mode 100644 index 0000000..2f06fa0 --- /dev/null +++ b/system/typemill/Models/Field.php @@ -0,0 +1,289 @@ +setName($fieldName); + + $type = isset($fieldConfigs['type']) ? $fieldConfigs['type'] : false; + $this->setType($type); + + $label = isset($fieldConfigs['label']) ? $fieldConfigs['label'] : false; + $this->setLabel($label); + + $checkboxlabel = isset($fieldConfigs['checkboxlabel']) ? $fieldConfigs['checkboxlabel'] : false; + $this->setCheckboxLabel($checkboxlabel); + + $options = isset($fieldConfigs['options']) ? $fieldConfigs['options'] : array(); + $this->setOptions($options); + + $this->setAttributes($fieldConfigs); + + $this->setAttributeValues($fieldConfigs); + + $this->setHelpers($fieldConfigs); + } + + private function setName($name) + { + $this->name = $name; + } + + public function getName() + { + return $this->name; + } + + private function setType($type) + { + if(in_array($type, $this->types)) + { + $this->type = $type; + } + } + + public function getType() + { + return $this->type; + } + + public function setLabel($label) + { + $this->label = $label; + } + + public function getLabel() + { + return $this->label; + } + + public function setCheckboxLabel($label) + { + $this->checkboxLabel = $label; + } + + public function getCheckboxLabel() + { + return $this->checkboxLabel; + } + + public function setContent($content) + { + $this->content = $content; + } + + public function getContent() + { + return $this->content; + } + + private function setOptions(array $options) + { + foreach($options as $key => $value) + { + $this->options[$key] = $value; + } + } + + public function getOptions() + { + if(isset($this->options)) + { + return $this->options; + } + return false; + } + + private function setAttributes($fieldConfigs) + { + foreach($fieldConfigs as $key => $value) + { + if(is_string($key) && in_array($key, $this->attr)) + { + $this->attributes[$key] = $value; + } + } + } + + /* get all attributes of the field and return them as a string. For usage in templates */ + public function getAttributes() + { + $string = false; + + foreach($this->attributes as $key => $attribute) + { + $string .= ' ' . $key; + } + + return $string; + } + + /* set a single attribute. Used e.g. in controller to change the value */ + public function setAttribute($key, $value) + { + $this->attributes[$key] = $value; + } + + public function unsetAttribute($key) + { + unset($this->attributes[$key]); + } + + /* get a single attribute, if it is defined. For usage in templates like getAttribute('required') */ + public function getAttribute($key) + { + if(isset($this->attributes[$key])) + { + return $this->attributes[$key]; + } + + return false; + } + + private function setAttributeValues($fieldConfigs) + { + foreach($fieldConfigs as $key => $value) + { + if(is_string($key) && in_array($key, $this->attrValues)) + { + $this->attributeValues[$key] = $value; + } + } + } + + /* get all attributes as string. For usage in template */ + public function getAttributeValues() + { + $string = false; + + foreach($this->attributeValues as $key => $attribute) + { + $string .= ' ' . $key . '="' . $attribute . '"'; + } + + return $string; + } + + public function setAttributeValue($key, $value) + { + /* pretty dirty, but you should not add a value for a simple checkbox */ + if($key == 'value' && $this->type == 'checkbox') + { + return; + } + + $this->attributeValues[$key] = $value; + } + + public function getAttributeValue($key) + { + if(isset($this->attributeValues[$key])) + { + return $this->attributeValues[$key]; + } + + return false; + } + + + public function setHelpers($fieldConfigs) + { + foreach($fieldConfigs as $key => $config) + { + if(is_string($key) && in_array($key, $this->helpers)) + { + $this->$key = $config; + } + } + } + + public function getHelper($helperName) + { + if(isset($this->$helperName)) + { + return $this->$helperName; + } + return false; + } +} \ No newline at end of file diff --git a/system/typemill/Models/Fields.php b/system/typemill/Models/Fields.php new file mode 100644 index 0000000..1657b22 --- /dev/null +++ b/system/typemill/Models/Fields.php @@ -0,0 +1,138 @@ +c = $c; + } + + public function getFields($userSettings, $objectType, $objectName, $objectSettings, $formType = false) + { + # hold all fields in array + $fields = array(); + + # formtype are backend forms or public forms, only relevant for plugins for now + $formType = $formType ? $formType : 'forms'; + + # iterate through all fields of the objectSetting (theme or plugin) + foreach($objectSettings[$formType]['fields'] as $fieldName => $fieldConfigurations) + { + if($fieldConfigurations['type'] == 'fieldset') + { + # if it is a fieldset, then create a subset for the containing field and read them with a recursive function + $subSettings = $objectSettings; + $subSettings['forms'] = $fieldConfigurations; + + $fieldset = array(); + $fieldset['type'] = 'fieldset'; + $fieldset['legend'] = $fieldConfigurations['legend']; + $fieldset['fields'] = $this->getFields($userSettings, $objectType, $objectName, $subSettings, $formType); + $fields[] = $fieldset; + } + else + { + # For label, helptext and description you can use the value of another field. This is useful e.g. to localize the label of public forms via plugin settings. + if(isset($fieldConfigurations['label']) && isset($userSettings[$objectType][$objectName][$fieldConfigurations['label']])) + { + $fieldConfigurations['label'] = $userSettings[$objectType][$objectName][$fieldConfigurations['label']]; + } + if(isset($fieldConfigurations['help']) && isset($userSettings[$objectType][$objectName][$fieldConfigurations['help']])) + { + $fieldConfigurations['help'] = $userSettings[$objectType][$objectName][$fieldConfigurations['help']]; + } + if(isset($fieldConfigurations['description']) && isset($userSettings[$objectType][$objectName][$fieldConfigurations['description']])) + { + $fieldConfigurations['description'] = $userSettings[$objectType][$objectName][$fieldConfigurations['description']]; + } + + # check if the field is a select field with dataset = userroles + if(isset($this->c) && isset($fieldConfigurations['type']) && ($fieldConfigurations['type'] == 'select' ) && isset($fieldConfigurations['dataset']) && ($fieldConfigurations['dataset'] == 'userroles' ) ) + { + $userroles = [null => null]; + foreach($this->c->acl->getRoles() as $userrole) + { + $userroles[$userrole] = $userrole; + } + $fieldConfigurations['options'] = $userroles; + } + + # for each field generate a new field object with the field name and the field configurations + $field = new Field($fieldName, $fieldConfigurations); + + # handle the value for the field + $userValue = false; + + # first, add the default value from the original plugin or theme settings + if(isset($objectSettings['settings'][$fieldName])) + { + $userValue = $objectSettings['settings'][$fieldName]; + } + + # now overwrite the default values with the user values stored in the user settings + if(isset($userSettings[$objectType][$objectName][$fieldName])) + { + $userValue = $userSettings[$objectType][$objectName][$fieldName]; + } + + # now overwrite user-values, if there are old-input values from the actual form (e.g. after input error) + if(isset($_SESSION['old'][$objectName][$fieldName])) + { + $userValue = $_SESSION['old'][$objectName][$fieldName]; + } + + # Now prepopulate the field object with the value */ + if($field->getType() == "textarea") + { + if($fieldName == "publicformdefinitions" && $userValue == '') + { + $userValue = $objectSettings['settings'][$fieldName]; + } + if($userValue) + { + $field->setContent($userValue); + } + } + elseif($field->getType() == 'paragraph') + { + if(isset($fieldConfigurations['value'])) + { + $field->setContent($fieldConfigurations['value']); + } + if($userValue) + { + $field->setContent($userValue); + } + } + elseif($field->getType() == "checkbox") + { + # checkboxes need a special treatment, because field does not exist in settings if unchecked by user + if(isset($userSettings[$objectType][$objectName][$fieldName])) + { + $field->setAttribute('checked', 'true'); + } + else + { + $field->unsetAttribute('checked'); + } + } + else + { + $field->setAttributeValue('value', $userValue); + } + + # add the field to the field-List + $fields[] = $field; + + } + } + return $fields; + } +} \ No newline at end of file diff --git a/system/typemill/Models/Settings.php b/system/typemill/Models/Settings.php index 38ee952..5e353e9 100644 --- a/system/typemill/Models/Settings.php +++ b/system/typemill/Models/Settings.php @@ -106,7 +106,7 @@ class Settings return false; } - + public function getObjectSettings($objectType, $objectName) { $objectSettings = $this->storage->getYaml($objectType, $objectName, $objectName . '.yaml'); diff --git a/system/typemill/Plugin.php b/system/typemill/Plugin.php index 1e50191..125b846 100644 --- a/system/typemill/Plugin.php +++ b/system/typemill/Plugin.php @@ -4,10 +4,10 @@ namespace Typemill; use \Symfony\Component\EventDispatcher\EventSubscriberInterface; use DI\Container; -# use Typemill\Models\Fields; use Typemill\Models\StorageWrapper; use Typemill\Models\Extension; use Typemill\Models\Validation; +use Typemill\Models\Fields; use Typemill\Extensions\ParsedownExtension; abstract class Plugin implements EventSubscriberInterface @@ -22,11 +22,7 @@ abstract class Plugin implements EventSubscriberInterface public function __construct(Container $container) { -/* - echo '
';
-		echo '

FIRST

'; - print_r($container); -*/ + $this->container = $container; $this->urlinfo = $this->container->get('urlinfo'); $this->route = $this->urlinfo['route']; @@ -281,23 +277,27 @@ abstract class Plugin implements EventSubscriberInterface return false; } - protected function generateForm($pluginName, $routename) + protected function generateForm($routename, $pluginname = NULL) { - $fieldsModel = new Fields(); - - $settings = $this->getSettings(); $form = false; - $pluginDefinitions = \Typemill\Settings::getObjectSettings('plugins', $pluginName); - if(isset($settings['plugins'][$pluginName]['publicformdefinitions']) && $settings['plugins'][$pluginName]['publicformdefinitions'] != '') + $fieldsModel = new Fields(); + $extensionModel = new Extension(); + + $pluginSettings = $this->getPluginSettings(); + $pluginName = $this->getPluginName($pluginname); + $pluginDefinitions = $extensionModel->getPluginDefinition($pluginName); + + # add field-definitions entered into author interface + if(isset($pluginSettings['publicformdefinitions']) && $pluginSettings['publicformdefinitions'] != '') { - $arrayFromYaml = \Symfony\Component\Yaml\Yaml::parse($settings['plugins'][$pluginName]['publicformdefinitions']); + $arrayFromYaml = \Symfony\Component\Yaml\Yaml::parse($pluginSettings['publicformdefinitions']); $pluginDefinitions['public']['fields'] = $arrayFromYaml; } - $buttonlabel = isset($settings['plugins'][$pluginName]['button_label']) ? $settings['plugins'][$pluginName]['button_label'] : false; - $captchaoptions = isset($settings['plugins'][$pluginName]['captchaoptions']) ? $settings['plugins'][$pluginName]['captchaoptions'] : false; - $recaptcha = isset($settings['plugins'][$pluginName]['recaptcha']) ? $settings['plugins'][$pluginName]['recaptcha_webkey'] : false; + $buttonlabel = isset($pluginSettings['button_label']) ? $pluginSettings['button_label'] : false; + $captchaoptions = isset($pluginSettings['captchaoptions']) ? $pluginSettings['captchaoptions'] : false; + $recaptcha = isset($pluginSettings['recaptcha']) ? $pluginSettings['recaptcha_webkey'] : false; if($captchaoptions == 'disabled') { @@ -308,7 +308,9 @@ abstract class Plugin implements EventSubscriberInterface $fieldsModel = new Fields(); if(isset($pluginDefinitions['public']['fields'])) - { + { + $settings = $this->container->get('settings'); + # get all the fields and prefill them with the dafault-data, the user-data or old input data $fields = $fieldsModel->getFields($settings, 'plugins', $pluginName, $pluginDefinitions, 'public'); @@ -326,7 +328,7 @@ abstract class Plugin implements EventSubscriberInterface 'recaptcha_webkey' => $recaptcha, ]); } - + return $form; } diff --git a/system/typemill/author/js/vue-blox-components.js b/system/typemill/author/js/vue-blox-components.js index 23d0a13..1365d2c 100644 --- a/system/typemill/author/js/vue-blox-components.js +++ b/system/typemill/author/js/vue-blox-components.js @@ -2293,7 +2293,7 @@ bloxeditor.component('shortcode-component', { { params: { - 'url': data.urlinfo.route, + 'url': data.urlinfo.route, } }) .then(function (response) @@ -2359,7 +2359,7 @@ bloxeditor.component('shortcode-component', { this.compmarkdown = '[:' + shortcodename + attributes + ' :]'; - this.$emit('updatedMarkdown', this.compmarkdown); + this.$emit('updateMarkdownEvent', this.compmarkdown); }, selectsearch: function(item,attribute) { diff --git a/system/typemill/author/partials/fields.twig b/system/typemill/author/partials/fields.twig new file mode 100644 index 0000000..232ded1 --- /dev/null +++ b/system/typemill/author/partials/fields.twig @@ -0,0 +1,103 @@ +
+ + + + {% if field.type == 'image' %} +
+
+
+ +
+
+
+
+ +
{{ translate('Upload an image') }}
+
+
+ +
+ + +
+
+ {% if errors[itemName][field.name] %} +
{{ errors[itemName][field.name] | first }}
+ {% endif %} + + {% if field.description %}
{{ translate(field.description) }}
{% endif %} + +
+
+ + {% else %} + + {% if field.type == 'textarea' %} + + + + {% elseif (field.type == 'paragraph') and (field.getContent() != '') %} + + {{ markdown(field.getContent()) }} + + {% elseif field.type == 'checkbox' %} + + + + {% elseif field.type == 'checkboxlist' %} + + {% set options = field.getOptions() %} + + {% for value,label in options %} + + + + {% endfor %} + + {% elseif field.type == 'select' %} + + {% set options = field.getOptions() %} + + + + {% elseif field.type == 'radio' %} + + {% set options = field.getOptions() %} + + {% for value,label in options %} + + + + {% endfor %} + + {% else %} + + + + {% endif %} + + {% if field.description %}
{{ translate(field.description) }}
{% endif %} + + {% if errors[itemName][field.name] %} + {{ errors[itemName][field.name] | first }} + {% endif %} + + {% endif %} + +
\ No newline at end of file diff --git a/system/typemill/author/partials/form.twig b/system/typemill/author/partials/form.twig new file mode 100644 index 0000000..d0bfca1 --- /dev/null +++ b/system/typemill/author/partials/form.twig @@ -0,0 +1,56 @@ +{% if recaptcha_webkey %} + + + +{% endif %} +
+ +
+ + {% for field in fields %} + + {% if field.type == 'fieldset' %} + +
+ {{ field.legend }} + {% for field in field.fields %} + + {% include '/partials/fields.twig' with {'itemName' : itemName, 'object' : object } %} + + {% endfor %} +
+ + {% else %} + + {% include '/partials/fields.twig' with {'itemName' : itemName, 'object' : object } %} + + {% endif %} + + {% endfor %} + +
+ + +
+ + {% if captchaoptions == 'disabled' %} + + {% elseif captchaoptions == 'aftererror' %} + + {{ captcha(old) }} + + {% else %} + + {{ captcha(true) }} + + {% endif %} + + {% if recaptcha_webkey %} +

+ {% endif %} + + + + +
+
\ No newline at end of file diff --git a/system/typemill/system.php b/system/typemill/system.php index 56193f8..1afa309 100644 --- a/system/typemill/system.php +++ b/system/typemill/system.php @@ -32,6 +32,7 @@ use Typemill\Extensions\TwigUrlExtension; use Typemill\Extensions\TwigUserExtension; use Typemill\Extensions\TwigLanguageExtension; use Typemill\Extensions\TwigMarkdownExtension; +use Typemill\Extensions\TwigCaptchaExtension; $timer = []; $timer['start'] = microtime(true); @@ -301,6 +302,7 @@ $container->set('view', function() use ($settings, $csrf, $urlinfo, $translation $twig->addExtension(new TwigUrlExtension($urlinfo)); $twig->addExtension(new TwigLanguageExtension( $translations )); $twig->addExtension(new TwigMarkdownExtension()); + $twig->addExtension(new TwigCaptchaExtension()); # start csrf only if session is active /*