From fb8778bfba26a49832716783aa93a4102eb40dc2 Mon Sep 17 00:00:00 2001 From: doishub Date: Thu, 4 Jun 2020 12:12:57 +0200 Subject: [PATCH] - Adjusting the structure to a license child table - Bugfix: Considering the quantity of buyed products - Assigning a logged-in user --- README.md | 2 + src/EventListener/InsertTagsListener.php | 14 +- .../contao/classes/LicenseHandler.php | 48 +-- src/Resources/contao/config/config.php | 4 +- src/Resources/contao/dca/tl_license.php | 71 +--- src/Resources/contao/dca/tl_license_item.php | 328 ++++++++++++++++++ src/Resources/contao/languages/de/default.xlf | 10 +- .../contao/languages/de/tl_license.xlf | 16 +- .../contao/languages/de/tl_license_item.xlf | 38 ++ src/Resources/contao/languages/en/default.xlf | 6 +- .../contao/languages/en/tl_license_item.xlf | 27 ++ .../contao/models/LicenseItemModel.php | 54 +++ src/Resources/contao/models/LicenseModel.php | 4 +- 13 files changed, 513 insertions(+), 109 deletions(-) create mode 100644 src/Resources/contao/dca/tl_license_item.php create mode 100644 src/Resources/contao/languages/de/tl_license_item.xlf create mode 100644 src/Resources/contao/languages/en/tl_license_item.xlf create mode 100644 src/Resources/contao/models/LicenseItemModel.php diff --git a/README.md b/README.md index d727a07..00a70f1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This extension complements a license key management and its assignment to products which can then be picked up (via insert tags) and sent via the Notification Center. +> If a member is logged in, this member will automatically be assigned the license key. + The following insert tags are available: - `{{license_collection::*}}` - `{{license_product::*}}` diff --git a/src/EventListener/InsertTagsListener.php b/src/EventListener/InsertTagsListener.php index 5f518df..ea425ac 100644 --- a/src/EventListener/InsertTagsListener.php +++ b/src/EventListener/InsertTagsListener.php @@ -81,7 +81,10 @@ private function replaceLicenseInsertTags($insertTag, $intId) while($productsInCollection->next()) { - $arrProductIds[] = $productsInCollection->product_id; + for($i=0; $i<$productsInCollection->quantity; $i++) + { + $arrProductIds[] = $productsInCollection->product_id; + } } }else{ $arrProductIds[] = $intId; @@ -89,11 +92,12 @@ private function replaceLicenseInsertTags($insertTag, $intId) foreach ($arrProductIds as $productId) { - $product = LicenseModel::findOneByProduct($productId); + $objLicences = LicenseModel::findOneByProduct($productId); - $newLicense = LicenseHandler::getNextLicense($product); - - $arrProductLicenses[] = sprintf("%s: %s", $product->title, $newLicense); + if($newLicence = LicenseHandler::getNextLicense($objLicences)) + { + $arrProductLicenses[] = sprintf("%s: %s", $objLicences->title, $newLicence); + } } return implode("\n", $arrProductLicenses); diff --git a/src/Resources/contao/classes/LicenseHandler.php b/src/Resources/contao/classes/LicenseHandler.php index 3238e51..d9500f6 100644 --- a/src/Resources/contao/classes/LicenseHandler.php +++ b/src/Resources/contao/classes/LicenseHandler.php @@ -9,6 +9,8 @@ namespace Oveleon\IsotopeProductLicenses; use Contao\CoreBundle\Monolog\ContaoContext; +use Contao\FrontendUser; +use Contao\System; use Psr\Log\LogLevel; class LicenseHandler @@ -16,48 +18,52 @@ class LicenseHandler /** * Generate and return the next valid license of a product * - * @param int|object $product + * @param int|object $varProductLicence * * @return string */ - public static function getNextLicense($product) + public static function getNextLicense($varProductLicence) { - if(is_int($product)) + $logger = \System::getContainer()->get('monolog.logger.contao'); + + if(is_int($varProductLicence)) { - $product = LicenseModel::findOneByProduct($product); + $varProductLicence = LicenseModel::findOneByProduct($varProductLicence); } - $logger = \System::getContainer()->get('monolog.logger.contao'); + $objLicence = LicenseItemModel::findBy(['pid=?', 'published=?'], [$varProductLicence->id, 0]); - if($product !== null) + if($objLicence !== null) { - $arrValidLicenses = array_filter(\StringUtil::deserialize($product->listitems, true)); - $arrUsedLicenses = array_filter(\StringUtil::deserialize($product->useditems, true)); + $intCount = $objLicence->count(); - // ToDo: The number from when the warning is to be output should come from a configuration. - // ToDo: Send a warning e-mail to the administrator - if(count($arrValidLicenses) < 10 && !empty($arrValidLicenses)) + // Warning when licences are almost exhausted + if($intCount < 10) { - $logger->log(LogLevel::WARNING, sprintf($GLOBALS['TL_LANG']['ERR']['lowNumberOfLicenses'], $product->product), array('contao' => new ContaoContext('getNextLicense', 'WARNING'))); + $logger->log(LogLevel::WARNING, sprintf($GLOBALS['TL_LANG']['ERR']['lowNumberOfLicenses'], $intCount, $varProductLicence->product), array('contao' => new ContaoContext('getNextLicense', 'WARNING'))); } - elseif(empty($arrValidLicenses)) + // Warning when licences are exhausted + elseif($intCount === 0) { - $logger->log(LogLevel::ERROR, sprintf($GLOBALS['TL_LANG']['ERR']['noMoreLicenses'], $product->product), array('contao' => new ContaoContext('getNextLicense', 'ERROR'))); + $logger->log(LogLevel::ERROR, sprintf($GLOBALS['TL_LANG']['ERR']['noMoreLicenses'], $varProductLicence->product), array('contao' => new ContaoContext('getNextLicense', 'ERROR'))); return ''; } - $strNewLicense = array_shift($arrValidLicenses); - $arrUsedLicenses[] = $strNewLicense; + $objUser = System::importStatic(FrontendUser::class, 'Member'); - $product->listitems = serialize($arrValidLicenses); - $product->useditems = serialize($arrUsedLicenses); + if(FE_USER_LOGGED_IN) + { + $objLicence->member = $objUser->id; + } - $product->save(); + $objLicence->published = 1; + $objLicence->save(); - return $strNewLicense; + return $objLicence->licence; } - $logger->log(LogLevel::ERROR, $GLOBALS['TL_LANG']['ERR']['noLicenseFound'], array('contao' => new ContaoContext('getNextLicense', 'ERROR'))); + $logger->log(LogLevel::ERROR, sprintf($GLOBALS['TL_LANG']['ERR']['noLicenseFound'], $varProductLicence->product), array('contao' => new ContaoContext('getNextLicense', 'ERROR'))); + return ''; } } diff --git a/src/Resources/contao/config/config.php b/src/Resources/contao/config/config.php index 02850f6..339e0e8 100644 --- a/src/Resources/contao/config/config.php +++ b/src/Resources/contao/config/config.php @@ -8,12 +8,12 @@ array_insert($GLOBALS['BE_MOD']['isotope']['iso_license'], 0, array ( - 'tables' => array('tl_license'), - 'list' => array('Contao\CoreBundle\Controller\BackendCsvImportController', 'importListWizardAction') + 'tables' => array('tl_license', 'tl_license_item') )); // Register Model $GLOBALS['TL_MODELS']['tl_license'] = '\\Oveleon\\IsotopeProductLicenses\\LicenseModel'; +$GLOBALS['TL_MODELS']['tl_license_item'] = '\\Oveleon\\IsotopeProductLicenses\\LicenseItemModel'; // Register hooks $GLOBALS['TL_HOOKS']['replaceInsertTags'][] = array('isotope_product_licenses.listener.insert_tags', 'onReplaceInsertTags'); diff --git a/src/Resources/contao/dca/tl_license.php b/src/Resources/contao/dca/tl_license.php index 04ba494..9cd2c81 100644 --- a/src/Resources/contao/dca/tl_license.php +++ b/src/Resources/contao/dca/tl_license.php @@ -11,7 +11,9 @@ 'config' => array ( 'dataContainer' => 'Table', - 'enableVersioning' => true, + 'ctable' => array('tl_license_item'), + 'notCopyable' => true, + 'enableVersioning' => true, 'sql' => array ( 'keys' => array @@ -47,16 +49,16 @@ ), 'operations' => array ( - 'edit' => array - ( - 'href' => 'act=edit', - 'icon' => 'edit.svg' - ), - 'copy' => array - ( - 'href' => 'act=copy', - 'icon' => 'copy.svg' - ), + 'edit' => array + ( + 'href' => 'table=tl_license_item', + 'icon' => 'edit.svg', + ), + 'editheader' => array + ( + 'href' => 'act=edit', + 'icon' => 'header.svg', + ), 'delete' => array ( 'href' => 'act=delete', @@ -74,7 +76,7 @@ // Palettes 'palettes' => array ( - 'default' => '{title_legend},title,product;{license_legend},listitems,useditems', + 'default' => '{title_legend},title,product', ), // Fields @@ -102,49 +104,6 @@ 'inputType' => 'text', 'eval' => array('mandatory'=>true, 'tl_class'=>'w50'), 'sql' => "varchar(255) NOT NULL default ''" - ), - 'listitems' => array - ( - 'inputType' => 'listWizard', - 'eval' => array('mandatory'=>true, 'tl_class'=>'w50 clr'), - 'xlabel' => array - ( - array('tl_license', 'listImportWizard') - ), - 'sql' => "blob NULL" - ), - 'useditems' => array - ( - 'inputType' => 'listWizard', - 'eval' => array('tl_class'=>'w50 clr'), - 'sql' => "blob NULL" - ), + ) ) ); - -/** - * Provide miscellaneous methods that are used by the data configuration array. - * - * @author Daniele Sciannimanica - */ -class tl_license extends Contao\Backend -{ - /** - * Import the back end user object - */ - public function __construct() - { - parent::__construct(); - $this->import('Contao\BackendUser', 'User'); - } - - /** - * Add a link to the list items import wizard - * - * @return string - */ - public function listImportWizard() - { - return ' ' . Contao\Image::getHtml('tablewizard.svg', $GLOBALS['TL_LANG']['MSC']['tw_import'][0]) . ''; - } -} diff --git a/src/Resources/contao/dca/tl_license_item.php b/src/Resources/contao/dca/tl_license_item.php new file mode 100644 index 0000000..7eb5cd5 --- /dev/null +++ b/src/Resources/contao/dca/tl_license_item.php @@ -0,0 +1,328 @@ + array + ( + 'dataContainer' => 'Table', + 'ptable' => 'tl_license', + 'enableVersioning' => true, + 'sql' => array + ( + 'keys' => array + ( + 'id' => 'primary', + 'licence' => 'index' + ) + ) + ), + + // List + 'list' => array + ( + 'sorting' => array + ( + 'mode' => 4, + 'fields' => array('licence','tstamp'), + 'panelLayout' => 'limit', + 'headerFields' => array('title', 'product'), + 'child_record_callback' => array('tl_license_item', 'listLicence'), + 'disableGrouping' => true + ), + 'label' => array + ( + 'fields' => array('title', 'product'), + 'showColumns' => true + ), + 'global_operations' => array + ( + 'all' => array + ( + 'href' => 'act=select', + 'class' => 'header_edit_all', + 'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"' + ) + ), + 'operations' => array + ( + 'edit' => array + ( + 'href' => 'act=edit', + 'icon' => 'edit.svg' + ), + 'delete' => array + ( + 'href' => 'act=delete', + 'icon' => 'delete.svg', + 'attributes' => 'onclick="if(!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\'))return false;Backend.getScrollOffset()"' + ), + 'show' => array + ( + 'href' => 'act=show', + 'icon' => 'show.svg' + ), + 'toggle' => array + ( + 'icon' => 'visible.svg', + 'attributes' => 'onclick="Backend.getScrollOffset();return AjaxRequest.toggleVisibility(this,%s)"', + 'button_callback' => array('tl_license_item', 'toggleIcon'), + 'showInHeader' => true + ) + ) + ), + + // Palettes + 'palettes' => array + ( + '__selector__' => ['published'], + 'default' => '{licence_legend},licence;{publish_legend},published', + ), + + // Subpalettes + 'subpalettes' => array + ( + 'published' => 'member', + ), + + // Fields + 'fields' => array + ( + 'id' => array + ( + 'sql' => "int(10) unsigned NOT NULL auto_increment" + ), + 'pid' => array + ( + 'foreignKey' => 'tl_license.title', + 'sql' => "int(10) unsigned NOT NULL default 0", + 'relation' => array('type'=>'belongsTo', 'load'=>'lazy') + ), + 'tstamp' => array + ( + 'sql' => "int(10) unsigned NOT NULL default 0" + ), + 'licence' => array + ( + 'exclude' => true, + 'flag' => 1, + 'inputType' => 'text', + 'eval' => array('mandatory'=>true, 'maxlength'=>255, 'tl_class'=>'w50', 'unique'=>true), + 'sql' => "varchar(255) NOT NULL default ''" + ), + 'member' => array( + 'exclude' => true, + 'inputType' => 'select', + 'foreignKey' => 'tl_member.CONCAT(firstname," ",lastname)', + 'eval' => array('chosen'=>true, 'includeBlankOption'=>true, 'tl_class'=>'w50'), + 'sql' => "int(10) unsigned NOT NULL default 0", + ), + 'published' => array + ( + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => array('doNotCopy'=>true, 'submitOnChange' => true), + 'sql' => "char(1) NOT NULL default ''" + ) + ) +); + +/** + * Provide miscellaneous methods that are used by the data configuration array. + * + * @author Daniele Sciannimanica + */ +class tl_license_item extends Contao\Backend +{ + /** + * Import the back end user object + */ + public function __construct() + { + parent::__construct(); + $this->import('Contao\BackendUser', 'User'); + } + + /** + * Return the "toggle visibility" button + * + * @param array $row + * @param string $href + * @param string $label + * @param string $title + * @param string $icon + * @param string $attributes + * + * @return string + */ + public function toggleIcon($row, $href, $label, $title, $icon, $attributes) + { + if (Contao\Input::get('tid')) + { + $this->toggleVisibility(Contao\Input::get('tid'), (Contao\Input::get('state') == 1), (@func_get_arg(12) ?: null)); + $this->redirect($this->getReferer()); + } + + // Check permissions AFTER checking the tid, so hacking attempts are logged + if (!$this->User->hasAccess('tl_license_item::published', 'alexf')) + { + return ''; + } + + $href .= '&tid=' . $row['id'] . '&state=' . (!$row['published'] ? '' : 1); + + if ($row['published']) + { + $icon = 'invisible.svg'; + } + + $objPage = Contao\PageModel::findById($row['pid']); + + if (!$this->User->isAllowed(Contao\BackendUser::CAN_EDIT_ARTICLES, $objPage->row())) + { + if (!$row['published']) + { + $icon = preg_replace('/\.svg$/i', '_.svg', $icon); // see #8126 + } + + return Contao\Image::getHtml($icon) . ' '; + } + + return '' . Contao\Image::getHtml($icon, $label, 'data-state="' . (!$row['published'] ? 1 : 0) . '"') . ' '; + } + + /** + * List a single licence + * + * @param array $row + * + * @return string + */ + public function listLicence($row) + { + $len = strlen($row['licence']); + $rep = 0; + $cut = 0; + + if($len > 4) + { + $rep = $len - 4; + $cut = 4; + } + + return '
' . substr_replace($row['licence'], str_repeat('▪', $rep), 0, -$cut) . '
'; + } + + /** + * Disable/enable a user group + * + * @param integer $intId + * @param boolean $blnVisible + * @param Contao\DataContainer $dc + * + * @throws Contao\CoreBundle\Exception\AccessDeniedException + */ + public function toggleVisibility($intId, $blnVisible, Contao\DataContainer $dc=null) + { + // Set the ID and action + Contao\Input::setGet('id', $intId); + Contao\Input::setGet('act', 'toggle'); + + if ($dc) + { + $dc->id = $intId; // see #8043 + } + + // Trigger the onload_callback + if (is_array($GLOBALS['TL_DCA']['tl_license_item']['config']['onload_callback'])) + { + foreach ($GLOBALS['TL_DCA']['tl_license_item']['config']['onload_callback'] as $callback) + { + if (is_array($callback)) + { + $this->import($callback[0]); + $this->{$callback[0]}->{$callback[1]}($dc); + } + elseif (is_callable($callback)) + { + $callback($dc); + } + } + } + + // Check the field access + if (!$this->User->hasAccess('tl_license_item::published', 'alexf')) + { + throw new Contao\CoreBundle\Exception\AccessDeniedException('Not enough permissions to publish/unpublish article ID "' . $intId . '".'); + } + + // Set the current record + if ($dc) + { + $objRow = $this->Database->prepare("SELECT * FROM tl_license_item WHERE id=?") + ->limit(1) + ->execute($intId); + + if ($objRow->numRows) + { + $dc->activeRecord = $objRow; + } + } + + $objVersions = new Contao\Versions('tl_license_item', $intId); + $objVersions->initialize(); + + // Trigger the save_callback + if (is_array($GLOBALS['TL_DCA']['tl_license_item']['fields']['published']['save_callback'])) + { + foreach ($GLOBALS['TL_DCA']['tl_license_item']['fields']['published']['save_callback'] as $callback) + { + if (is_array($callback)) + { + $this->import($callback[0]); + $blnVisible = $this->{$callback[0]}->{$callback[1]}($blnVisible, $dc); + } + elseif (is_callable($callback)) + { + $blnVisible = $callback($blnVisible, $dc); + } + } + } + + $time = time(); + + // Update the database + $this->Database->prepare("UPDATE tl_license_item SET tstamp=$time, published='" . (!$blnVisible ? '1' : '') . "' WHERE id=?") + ->execute($intId); + + if ($dc) + { + $dc->activeRecord->tstamp = $time; + $dc->activeRecord->published = (!$blnVisible ? '1' : ''); + } + + // Trigger the onsubmit_callback + if (is_array($GLOBALS['TL_DCA']['tl_license_item']['config']['onsubmit_callback'])) + { + foreach ($GLOBALS['TL_DCA']['tl_license_item']['config']['onsubmit_callback'] as $callback) + { + if (is_array($callback)) + { + $this->import($callback[0]); + $this->{$callback[0]}->{$callback[1]}($dc); + } + elseif (is_callable($callback)) + { + $callback($dc); + } + } + } + + $objVersions->create(); + } +} diff --git a/src/Resources/contao/languages/de/default.xlf b/src/Resources/contao/languages/de/default.xlf index b14999d..71b1072 100644 --- a/src/Resources/contao/languages/de/default.xlf +++ b/src/Resources/contao/languages/de/default.xlf @@ -6,13 +6,13 @@ Lizenzen für das Produkt "%s" sind ausgeschöpft - No license could be found for the referenced product - Für das referenzierte Produkt konnte keine Lizenz gefunden werden + No license could be found for the product "%s" + Für das Produkt "%s" konnte keine Lizenz gefunden werden - Only a few licenses left for product "%s" - Nur noch wenige Lizenzen für Produkt "%s" + Only "%s" licenses left for product "%s" + Nur noch "%s" Lizenzen für Produkt "%s" - \ No newline at end of file + diff --git a/src/Resources/contao/languages/de/tl_license.xlf b/src/Resources/contao/languages/de/tl_license.xlf index 80f70a9..b8ce93f 100644 --- a/src/Resources/contao/languages/de/tl_license.xlf +++ b/src/Resources/contao/languages/de/tl_license.xlf @@ -1,14 +1,10 @@ - + Title and product Titel und Produkt - - Licenses - Lizenzen - Title Titel @@ -25,14 +21,6 @@ Here you can enter the ID of a product for which the licenses should be available. Hier kannst du die ID eines Produktes eintragen, für das die Lizenzen gelten sollen. - - Valid licenses - Gültige Lizenzen - - - Licenses in use. - Bereits verwendete Lizenzen. - - \ No newline at end of file + diff --git a/src/Resources/contao/languages/de/tl_license_item.xlf b/src/Resources/contao/languages/de/tl_license_item.xlf new file mode 100644 index 0000000..c10c969 --- /dev/null +++ b/src/Resources/contao/languages/de/tl_license_item.xlf @@ -0,0 +1,38 @@ + + + + + Licence + Lizenz + + + Valid + Gültigkeit + + + Licence + Lizenz + + + Enter a licence. + Geben Sie eine Lizenz ein. + + + Member + Mitglied + + + Here you can select a member to whom this license is assigned. + Hier kannst du ein Mitglied auswählen, welchem diese Lizenz zugewiesen ist. + + + In use + Vergeben + + + Please select whether the license has already been assigned. + Bitte wählen Sie, ob die Lizenz bereits vergeben wurde. + + + + diff --git a/src/Resources/contao/languages/en/default.xlf b/src/Resources/contao/languages/en/default.xlf index 614d54b..bd478c1 100644 --- a/src/Resources/contao/languages/en/default.xlf +++ b/src/Resources/contao/languages/en/default.xlf @@ -5,11 +5,11 @@ Licences for the product "%s" is exhausted - No license could be found for the referenced product + No license could be found for the product "%s" - Only a few licenses left for product "%s" + Only "%s" licenses left for product "%s" - \ No newline at end of file + diff --git a/src/Resources/contao/languages/en/tl_license_item.xlf b/src/Resources/contao/languages/en/tl_license_item.xlf new file mode 100644 index 0000000..a98f2ad --- /dev/null +++ b/src/Resources/contao/languages/en/tl_license_item.xlf @@ -0,0 +1,27 @@ + + + + + Licence + + + Valid + + + Licence + + + Enter a licence. + + + Member + + + Here you can select a member to whom this license is assigned. + + + Valid / Not used + + + + diff --git a/src/Resources/contao/models/LicenseItemModel.php b/src/Resources/contao/models/LicenseItemModel.php new file mode 100644 index 0000000..ce45469 --- /dev/null +++ b/src/Resources/contao/models/LicenseItemModel.php @@ -0,0 +1,54 @@ + + */ +class LicenseItemModel extends \Model +{ + /** + * Table name + * @var string + */ + protected static $strTable = 'tl_license_item'; + +} diff --git a/src/Resources/contao/models/LicenseModel.php b/src/Resources/contao/models/LicenseModel.php index 4c821b8..2130b34 100644 --- a/src/Resources/contao/models/LicenseModel.php +++ b/src/Resources/contao/models/LicenseModel.php @@ -9,13 +9,11 @@ namespace Oveleon\IsotopeProductLicenses; /** - * Reads and writes members + * Reads and writes licences * * @property integer $id * @property string $title * @property string $product - * @property string $listitems - * @property string $useditems * * @method static LicenseModel|null findById($id, array $opt=array()) * @method static LicenseModel|null findByPk($id, array $opt=array())