From 4e2c51c303d9653e56eeeeb361dd8b6789832cf2 Mon Sep 17 00:00:00 2001 From: Llewellyn van der Merwe Date: Mon, 14 Jan 2019 17:32:23 +0200 Subject: [PATCH] Resolved gh-360 by adding the blob data type as an option for data types. Resolved gh-362 by adding the nested subform compatibility to subforms in JCB. Resolved gh-365 by improving the customscript validation search of save of custom code area. Added email validation to the email helper script. --- README.md | 4 +- admin/README.txt | 4 +- admin/compiler/joomla_3/Helper_email.php | 106 +++++++++++++++++- admin/helpers/compiler/c_Fields.php | 51 +++++++-- admin/helpers/compiler/e_Interpretation.php | 2 +- admin/helpers/componentbuilder.php | 15 ++- admin/helpers/componentbuilderemail.php | 106 +++++++++++++++++- .../en-GB/en-GB.com_componentbuilder.ini | 4 + admin/models/custom_code.php | 18 +-- admin/models/fields.php | 4 + admin/models/fieldtype.php | 4 + admin/models/forms/field.xml | 8 ++ componentbuilder.xml | 2 +- site/helpers/componentbuilder.php | 15 ++- 14 files changed, 310 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index f7b5416f2..4c75aa759 100644 --- a/README.md +++ b/README.md @@ -144,11 +144,11 @@ TODO + *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) + *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder) + *First Build*: 30th April, 2015 -+ *Last Build*: 29th December, 2018 ++ *Last Build*: 14th January, 2019 + *Version*: 2.9.8 + *Copyright*: Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + *License*: GNU General Public License version 2 or later; see LICENSE.txt -+ *Line count*: **195665** ++ *Line count*: **195803** + *Field count*: **1087** + *File count*: **1275** + *Folder count*: **201** diff --git a/admin/README.txt b/admin/README.txt index f7b5416f2..4c75aa759 100644 --- a/admin/README.txt +++ b/admin/README.txt @@ -144,11 +144,11 @@ TODO + *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) + *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder) + *First Build*: 30th April, 2015 -+ *Last Build*: 29th December, 2018 ++ *Last Build*: 14th January, 2019 + *Version*: 2.9.8 + *Copyright*: Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + *License*: GNU General Public License version 2 or later; see LICENSE.txt -+ *Line count*: **195665** ++ *Line count*: **195803** + *Field count*: **1087** + *File count*: **1275** + *Folder count*: **201** diff --git a/admin/compiler/joomla_3/Helper_email.php b/admin/compiler/joomla_3/Helper_email.php index ea9701a30..16b52e3b1 100644 --- a/admin/compiler/joomla_3/Helper_email.php +++ b/admin/compiler/joomla_3/Helper_email.php @@ -19,6 +19,13 @@ defined('_JEXEC') or die('Restricted access'); */ abstract class ###Component###Email { + /** + * The active recipient + * + * @var activeRecipient (array) + */ + public static $active = array(); + /** * Configuraiton object * @@ -54,6 +61,44 @@ abstract class ###Component###Email return self::$config; } + /** + * Returns the global mailer object, only creating it if it doesn't already exist. + * + */ + public static function getMailerInstance() + { + if (!self::$mailer) + { + self::$mailer = self::createMailer(); + } + + return self::$mailer; + } + + /** + * Check that a string looks like an email address. + * @param string $address The email address to check + * @param string|callable $patternselect A selector for the validation pattern to use : + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * @return boolean + * @static + * @access public + */ + public static function validateAddress($address, $patternselect = null) + { + return self::getMailerInstance()->validateAddress($address, $patternselect); + } + /** * Get a mailer object. * @@ -282,13 +327,70 @@ abstract class ###Component###Email if (method_exists('###Component###Helper','storeMessage')) { - // store the massage if the method is set - ###Component###Helper::storeMessage($sendmail, $recipient, $subject, $body, $textonly, $mode, 'email'); + // if we have active recipient details + if (isset(self::$active[$recipient])) + { + // store the massage if the method is set + ###Component###Helper::storeMessage($sendmail, self::$active[$recipient], $subject, $body, $textonly, $mode, 'email'); + // clear memory + unset(self::$active[$recipient]); + } + else + { + // store the massage if the method is set + ###Component###Helper::storeMessage($sendmail, $recipient, $subject, $body, $textonly, $mode, 'email'); + } } return $sendmail; } + /** + * Set html text (in a row) and subject (as title) to a email table. + * do not use

instead use
+ * in your html that you pass to this method + * since it is a table row it does not + * work well with paragraphs + * + * @return string on success + * + */ + public static function setBasicBody($html, $subject) + { + $body = array(); + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = "" . $subject . ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = $html; + $body[] = ""; + $body[] = ""; + + return implode("\n", $body); + } + /** * Set html text (in a row) and subject (as title) to a email table. * do not use

instead use
diff --git a/admin/helpers/compiler/c_Fields.php b/admin/helpers/compiler/c_Fields.php index c45d28f8c..34f689c2d 100644 --- a/admin/helpers/compiler/c_Fields.php +++ b/admin/helpers/compiler/c_Fields.php @@ -1427,18 +1427,18 @@ class Fields extends Structure elseif ($typeName === 'subform') { // now add to the field set - $field .= PHP_EOL . $this->_t(2) . ""; - $field .= PHP_EOL . $this->_t(2) . "_t(2) . $taber . ""; + $field .= PHP_EOL . $this->_t(2) . $taber . " $value) { if ($property != 'fields') { - $field .= PHP_EOL . $this->_t(3) . $property . '="' . $value . '"'; + $field .= PHP_EOL . $this->_t(3) . $taber . $property . '="' . $value . '"'; } } $field .= ">"; - $field .= PHP_EOL . $this->_t(3) . '

"; - $field .= PHP_EOL . $this->_t(2) . ""; + $field .= PHP_EOL . $this->_t(3) . $taber . ""; + $field .= PHP_EOL . $this->_t(2) . $taber . ""; } } elseif ($setType === 'custom') @@ -1862,6 +1880,25 @@ class Fields extends Structure // now add to the field set ComponentbuilderHelper::xmlAppend($form, $this->setField('plain', $r_fieldValues, $r_name, $r_typeName, $langView, $view_name_single, $view_name_list, $placeholders, $r_optionArray)); } + elseif ($r_typeName === 'subform') + { + // set nested depth + if (isset($fieldAttributes['nested_depth'])) + { + $r_fieldValues['nested_depth'] = ++$fieldAttributes['nested_depth']; + } + else + { + $r_fieldValues['nested_depth'] = 1; + } + // only continue if nest is bellow 20 (this should be a safe limit) + if ($r_fieldValues['nested_depth'] <= 20) + { + // now add to the field set + ComponentbuilderHelper::xmlAppend($form, $this->setField('special', $r_fieldValues, $r_name, $r_typeName, $langView, $view_name_single, $view_name_list, $placeholders, $r_optionArray)); + } + + } elseif (ComponentbuilderHelper::checkArray($r_fieldValues['custom'])) { // add to custom diff --git a/admin/helpers/compiler/e_Interpretation.php b/admin/helpers/compiler/e_Interpretation.php index 9f1557b95..2ed3331bb 100644 --- a/admin/helpers/compiler/e_Interpretation.php +++ b/admin/helpers/compiler/e_Interpretation.php @@ -614,7 +614,7 @@ class Interpretation extends Fields } // give notice of this issue $this->app->enqueueMessage(JText::_('

WHMCS Error

'), 'Error'); - $this->app->enqueueMessage(JText::sprintf('The WHMCS class could not be added to this component. You will need to enable the add-on in the Joomla Component area (Add WHMCS)->Yes.', $this->libraries[$id]->name), 'Error'); + $this->app->enqueueMessage(JText::sprintf('The WHMCS class could not be added to this component. You will need to enable the add-on in the Joomla Component area (Add WHMCS)->Yes. If you have done this, then please check that you have your own Basic Encryption set in the global settings of JCB. Then open and save this component again, making sure that your WHMCS settings are still correct.', $this->libraries[$id]->name), 'Error'); return "//" . $this->setLine(__LINE__) . " The WHMCS class could not be added to this component." . PHP_EOL . "//" . $this->setLine(__LINE__) . " Please note that you will need to enable the add-on in the Joomla Component area (Add WHMCS)->Yes."; } diff --git a/admin/helpers/componentbuilder.php b/admin/helpers/componentbuilder.php index ff73ecd9b..d01400bcc 100644 --- a/admin/helpers/componentbuilder.php +++ b/admin/helpers/componentbuilder.php @@ -1354,9 +1354,15 @@ abstract class ComponentbuilderHelper { $it = new RecursiveDirectoryIterator($dir); $it = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST); + // remove ending / + $dir = rtrim($dir, '/'); + // now loop the files & folders foreach ($it as $file) { if ('.' === $file->getBasename() || '..' === $file->getBasename()) continue; + // set file dir + $file_dir = $file->getPathname(); + // check if this is a dir or a file if ($file->isDir()) { $keeper = false; @@ -1364,7 +1370,7 @@ abstract class ComponentbuilderHelper { foreach ($ignore as $keep) { - if (strpos($file->getPathname(), $dir.'/'.$keep) !== false) + if (strpos($file_dir, $dir.'/'.$keep) !== false) { $keeper = true; } @@ -1374,7 +1380,7 @@ abstract class ComponentbuilderHelper { continue; } - JFolder::delete($file->getPathname()); + JFolder::delete($file_dir); } else { @@ -1383,7 +1389,7 @@ abstract class ComponentbuilderHelper { foreach ($ignore as $keep) { - if (strpos($file->getPathname(), $dir.'/'.$keep) !== false) + if (strpos($file_dir, $dir.'/'.$keep) !== false) { $keeper = true; } @@ -1393,9 +1399,10 @@ abstract class ComponentbuilderHelper { continue; } - JFile::delete($file->getPathname()); + JFile::delete($file_dir); } } + // delete the root folder if not ignore found if (!self::checkArray($ignore)) { return JFolder::delete($dir); diff --git a/admin/helpers/componentbuilderemail.php b/admin/helpers/componentbuilderemail.php index 5d0a3d525..84ff67380 100644 --- a/admin/helpers/componentbuilderemail.php +++ b/admin/helpers/componentbuilderemail.php @@ -14,6 +14,13 @@ */ abstract class ComponentbuilderEmail { + /** + * The active recipient + * + * @var activeRecipient (array) + */ + public static $active = array(); + /** * Configuraiton object * @@ -49,6 +56,44 @@ abstract class ComponentbuilderEmail return self::$config; } + /** + * Returns the global mailer object, only creating it if it doesn't already exist. + * + */ + public static function getMailerInstance() + { + if (!self::$mailer) + { + self::$mailer = self::createMailer(); + } + + return self::$mailer; + } + + /** + * Check that a string looks like an email address. + * @param string $address The email address to check + * @param string|callable $patternselect A selector for the validation pattern to use : + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * @return boolean + * @static + * @access public + */ + public static function validateAddress($address, $patternselect = null) + { + return self::getMailerInstance()->validateAddress($address, $patternselect); + } + /** * Get a mailer object. * @@ -277,13 +322,70 @@ abstract class ComponentbuilderEmail if (method_exists('ComponentbuilderHelper','storeMessage')) { - // store the massage if the method is set - ComponentbuilderHelper::storeMessage($sendmail, $recipient, $subject, $body, $textonly, $mode, 'email'); + // if we have active recipient details + if (isset(self::$active[$recipient])) + { + // store the massage if the method is set + ComponentbuilderHelper::storeMessage($sendmail, self::$active[$recipient], $subject, $body, $textonly, $mode, 'email'); + // clear memory + unset(self::$active[$recipient]); + } + else + { + // store the massage if the method is set + ComponentbuilderHelper::storeMessage($sendmail, $recipient, $subject, $body, $textonly, $mode, 'email'); + } } return $sendmail; } + /** + * Set html text (in a row) and subject (as title) to a email table. + * do not use

instead use
+ * in your html that you pass to this method + * since it is a table row it does not + * work well with paragraphs + * + * @return string on success + * + */ + public static function setBasicBody($html, $subject) + { + $body = array(); + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = "" . $subject . ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = ""; + $body[] = $html; + $body[] = ""; + $body[] = ""; + + return implode("\n", $body); + } + /** * Set html text (in a row) and subject (as title) to a email table. * do not use

instead use
diff --git a/admin/language/en-GB/en-GB.com_componentbuilder.ini b/admin/language/en-GB/en-GB.com_componentbuilder.ini index c469e0302..748a74c0e 100644 --- a/admin/language/en-GB/en-GB.com_componentbuilder.ini +++ b/admin/language/en-GB/en-GB.com_componentbuilder.ini @@ -4324,6 +4324,7 @@ COM_COMPONENTBUILDER_FIELD_ADD_JAVASCRIPT_VIEW_FOOTER_LABEL="Add JavaScript (vie COM_COMPONENTBUILDER_FIELD_BASESIXTY_FOUR="base64" COM_COMPONENTBUILDER_FIELD_BASIC_ENCRYPTION_LOCALDBKEY="Basic Encryption (local-DB-key)" COM_COMPONENTBUILDER_FIELD_BIGINT="BIGINT" +COM_COMPONENTBUILDER_FIELD_BLOB="BLOB" COM_COMPONENTBUILDER_FIELD_BSB_NOT_FOUND_IN_LOCAL_DATABASE_TABLE_S_SO_IMPORTED_OF_ITS_VALUES_FAILED_PLEASE_UPDATE_YOUR_JCB_INSTALL_AND_TRY_AGAIN="Field %s not found in local database table (%s) so imported of its values failed, please update your JCB install and try again." COM_COMPONENTBUILDER_FIELD_CATID_DESCRIPTION="select one of the following categories" COM_COMPONENTBUILDER_FIELD_CATID_LABEL="Category" @@ -4386,7 +4387,9 @@ COM_COMPONENTBUILDER_FIELD_JAVASCRIPT_VIEW_FOOTER_DESCRIPTION="Add JavaScript fo COM_COMPONENTBUILDER_FIELD_JAVASCRIPT_VIEW_FOOTER_LABEL="Javascript (edit view footer)" COM_COMPONENTBUILDER_FIELD_JSON="JSON" COM_COMPONENTBUILDER_FIELD_KEY="KEY" +COM_COMPONENTBUILDER_FIELD_LONGBLOB="LONGBLOB" COM_COMPONENTBUILDER_FIELD_LONGTEXT="LONGTEXT" +COM_COMPONENTBUILDER_FIELD_MEDIUMBLOB="MEDIUMBLOB" COM_COMPONENTBUILDER_FIELD_MEDIUMTEXT="MEDIUMTEXT" COM_COMPONENTBUILDER_FIELD_MEDIUM_ENCRYPTION_LOCALFILEKEY="Medium Encryption (local-file-key)" COM_COMPONENTBUILDER_FIELD_MODIFIED_BY_DESC="The last user that modified this Field." @@ -4526,6 +4529,7 @@ COM_COMPONENTBUILDER_FIELD_STORE_LABEL="Store Method" COM_COMPONENTBUILDER_FIELD_TEN="10" COM_COMPONENTBUILDER_FIELD_TEXT="TEXT" COM_COMPONENTBUILDER_FIELD_TIME="TIME" +COM_COMPONENTBUILDER_FIELD_TINYBLOB="TINYBLOB" COM_COMPONENTBUILDER_FIELD_TINYINT="TINYINT" COM_COMPONENTBUILDER_FIELD_TWO_HUNDRED_AND_FIFTY_FIVE="255" COM_COMPONENTBUILDER_FIELD_TWO_THOUSAND_AND_FORTY_EIGHT="2048" diff --git a/admin/models/custom_code.php b/admin/models/custom_code.php index a4611a277..3dab5e615 100644 --- a/admin/models/custom_code.php +++ b/admin/models/custom_code.php @@ -826,29 +826,31 @@ class ComponentbuilderModelCustom_code extends JModelAdmin } // few checks with the new option of using custom code in custom code - if (isset($data['code']) && ($placholders = ComponentbuilderHelper::getAllBetween($data['code'], '[CUSTOM' . 'CODE=', ']')) - && ComponentbuilderHelper::checkArray($placholders)) + if (isset($data['code']) && ($placeholders = ComponentbuilderHelper::getAllBetween($data['code'], '[CUSTOM' . 'CODE=', ']')) + && ComponentbuilderHelper::checkArray($placeholders)) { // make sure custom code as Hash (automation) target does not have other custom code placeholders if (isset($data['target']) && 1 == $data['target']) { - foreach ($placholders as $placholder) + foreach ($placeholders as $placeholder) { - $data['code'] = str_replace('[CUSTOM' . 'CODE=' . $placholder . ']', '', $data['code']); + $data['code'] = str_replace('[CUSTOM' . 'CODE=' . $placeholder . ']', '', $data['code']); } // set title - $title = (count($placholders) == 1) ? JText::_('COM_COMPONENTBUILDER_PLACEHOLDER_REMOVED') : JText::_('COM_COMPONENTBUILDER_PLACEHOLDERS_REMOVED'); + $title = (count($placeholders) == 1) ? JText::_('COM_COMPONENTBUILDER_PLACEHOLDER_REMOVED') : JText::_('COM_COMPONENTBUILDER_PLACEHOLDERS_REMOVED'); // show message that we have had to remove the custom placeholders JFactory::getApplication()->enqueueMessage(JText::sprintf('COM_COMPONENTBUILDER_HTHREESHTHREEPCUSTOM_CODE_CAN_ONLY_BE_USED_IN_OTHER_CUSTOM_CODE_IF_SET_AS_BJCB_MANUALB_YOU_CAN_NOT_ADD_THEM_TO_EMHASH_AUTOMATIONEM_CODE_AT_THIS_POINTP', $title), 'Warning'); } // make sure that the same custom code is not added to itself else { - foreach ($placholders as $placholder) + foreach ($placeholders as $placeholder) { - if (strpos($placholder, $data['function_name']) !== false) + // strip the placeholder down to just the function name + $_placeholder = (array) explode('+', $placeholder); + if ($_placeholder[0] === $data['function_name']) { - $data['code'] = str_replace('[CUSTOM' . 'CODE=' . $placholder . ']', '', $data['code']); + $data['code'] = str_replace('[CUSTOM' . 'CODE=' . $placeholder . ']', '', $data['code']); // show message that we have had to remove the custom placeholders JFactory::getApplication()->enqueueMessage(JText::_('COM_COMPONENTBUILDER_HTHREEPLACEHOLDER_REMOVEDHTHREEPBTHISB_CUSTOM_CODE_CAN_ONLY_BE_USED_IN_BOTHERB_CUSTOM_CODE_NOT_IN_IT_SELF_SINCE_THAT_WILL_CAUSE_A_INFINITE_LOOP_IN_THE_COMPILERP'), 'Warning'); // stop the loop :) diff --git a/admin/models/fields.php b/admin/models/fields.php index 8f1b91b7b..1a56973ec 100644 --- a/admin/models/fields.php +++ b/admin/models/fields.php @@ -171,6 +171,10 @@ class ComponentbuilderModelFields extends JModelList 'TEXT' => 'COM_COMPONENTBUILDER_FIELD_TEXT', 'MEDIUMTEXT' => 'COM_COMPONENTBUILDER_FIELD_MEDIUMTEXT', 'LONGTEXT' => 'COM_COMPONENTBUILDER_FIELD_LONGTEXT', + 'BLOB' => 'COM_COMPONENTBUILDER_FIELD_BLOB', + 'TINYBLOB' => 'COM_COMPONENTBUILDER_FIELD_TINYBLOB', + 'MEDIUMBLOB' => 'COM_COMPONENTBUILDER_FIELD_MEDIUMBLOB', + 'LONGBLOB' => 'COM_COMPONENTBUILDER_FIELD_LONGBLOB', 'DATETIME' => 'COM_COMPONENTBUILDER_FIELD_DATETIME', 'DATE' => 'COM_COMPONENTBUILDER_FIELD_DATE', 'TIME' => 'COM_COMPONENTBUILDER_FIELD_TIME', diff --git a/admin/models/fieldtype.php b/admin/models/fieldtype.php index 4ebaaab40..eb099db26 100644 --- a/admin/models/fieldtype.php +++ b/admin/models/fieldtype.php @@ -239,6 +239,10 @@ class ComponentbuilderModelFieldtype extends JModelAdmin 'TEXT' => 'COM_COMPONENTBUILDER_FIELD_TEXT', 'MEDIUMTEXT' => 'COM_COMPONENTBUILDER_FIELD_MEDIUMTEXT', 'LONGTEXT' => 'COM_COMPONENTBUILDER_FIELD_LONGTEXT', + 'BLOB' => 'COM_COMPONENTBUILDER_FIELD_BLOB', + 'TINYBLOB' => 'COM_COMPONENTBUILDER_FIELD_TINYBLOB', + 'MEDIUMBLOB' => 'COM_COMPONENTBUILDER_FIELD_MEDIUMBLOB', + 'LONGBLOB' => 'COM_COMPONENTBUILDER_FIELD_LONGBLOB', 'DATETIME' => 'COM_COMPONENTBUILDER_FIELD_DATETIME', 'DATE' => 'COM_COMPONENTBUILDER_FIELD_DATE', 'TIME' => 'COM_COMPONENTBUILDER_FIELD_TIME', diff --git a/admin/models/forms/field.xml b/admin/models/forms/field.xml index f76ee676d..24b41e53b 100644 --- a/admin/models/forms/field.xml +++ b/admin/models/forms/field.xml @@ -136,6 +136,14 @@ COM_COMPONENTBUILDER_FIELD_MEDIUMTEXT + + + +