diff --git a/build/phpstan/tmp/.gitkeep b/.github/tmp/.gitkeep
similarity index 100%
rename from build/phpstan/tmp/.gitkeep
rename to .github/tmp/.gitkeep
diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml
index e8e3b0430ba..4b52bb51c45 100644
--- a/.github/workflows/phpstan.yml
+++ b/.github/workflows/phpstan.yml
@@ -44,7 +44,7 @@ jobs:
- name: Restore phpstan cache
uses: actions/cache/restore@v3
with:
- path: ./tmp
+ path: ./github/tmp
key: "phpstan-cache-PR-${{ matrix.php-version }}-${{ github.run_id }}"
restore-keys: |
phpstan-cache-PR-${{ matrix.php-version }}-
@@ -57,5 +57,5 @@ jobs:
uses: actions/cache/save@v3
if: always()
with:
- path: ./tmp
+ path: ./github/tmp
key: "phpstan-cache-PR-${{ matrix.php-version }}-${{ github.run_id }}"
diff --git a/build/phpstan/bootstrap.php b/build/phpstan/bootstrap.php
index 2a3131b6f5a..b0cb9f90ef0 100644
--- a/build/phpstan/bootstrap.php
+++ b/build/phpstan/bootstrap.php
@@ -15,5 +15,6 @@ if (!defined("NOSESSION")) {
if (!defined("NOHTTPSREDIRECT")) {
define("NOHTTPSREDIRECT", '1');
}
+
global $conf, $langs, $user, $db;
include_once __DIR__ . '/../../htdocs/main.inc.php';
diff --git a/build/phpstan/bootstrap_action.php b/build/phpstan/bootstrap_action.php
index f56067d66d8..e40a132ead3 100644
--- a/build/phpstan/bootstrap_action.php
+++ b/build/phpstan/bootstrap_action.php
@@ -1,4 +1,5 @@
update_nb($mailing_id);
}
+
+
+ /**
+ * Return list of widget. Function used by admin page htdoc/admin/widget.
+ * List is sorted by widget filename so by priority to run.
+ *
+ * @param array $forcedir null=All default directories. This parameter is used by modulebuilder module only.
+ * @return array Array list of widget
+ */
+ public static function getEmailingSelectorsList($forcedir = null)
+ {
+ global $langs, $db;
+
+ $files = array();
+ $fullpath = array();
+ $relpath = array();
+ $iscoreorexternal = array();
+ $modules = array();
+ $orders = array();
+ $i = 0;
+
+ $dirwidget = array('/core/emailings/'); // $conf->modules_parts['emailings'] is not required
+ if (is_array($forcedir)) {
+ $dirwidget = $forcedir;
+ }
+
+ foreach ($dirwidget as $reldir) {
+ $dir = dol_buildpath($reldir, 0);
+ $newdir = dol_osencode($dir);
+
+ // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
+ if (!is_dir($newdir)) {
+ continue;
+ }
+
+ $handle = opendir($newdir);
+ if (is_resource($handle)) {
+ while (($file = readdir($handle)) !== false) {
+ $reg = array();
+ if (is_readable($newdir.'/'.$file) && preg_match('/^(.+)\.php/', $file, $reg)) {
+ if (preg_match('/\.back$/', $file) || preg_match('/^(.+)\.disabled\.php/', $file)) {
+ continue;
+ }
+
+ $part1 = $reg[1];
+
+ $modName = ucfirst($reg[1]);
+ //print "file=$file"; print "modName=$modName"; exit;
+ if (in_array($modName, $modules)) {
+ $langs->load("errors");
+ print '
'.$langs->trans("Error").' : '.$langs->trans("ErrorDuplicateWidget", $modName, "").'
';
+ } else {
+ try {
+ include_once $newdir.'/'.$file;
+ } catch (Exception $e) {
+ print $e->getMessage();
+ }
+ }
+
+ $files[$i] = $file;
+ $fullpath[$i] = $dir.'/'.$file;
+ $relpath[$i] = preg_replace('/^\//', '', $reldir).'/'.$file;
+ $iscoreorexternal[$i] = ($reldir == '/core/boxes/' ? 'internal' : 'external');
+ $modules[$i] = $modName;
+ $orders[$i] = $part1; // Set sort criteria value
+
+ $i++;
+ }
+ }
+ closedir($handle);
+ }
+ }
+ //echo "";print_r($modules);echo "
";
+
+ asort($orders);
+
+ $widget = array();
+ $j = 0;
+
+ // Loop on each widget
+ foreach ($orders as $key => $value) {
+ $modName = $modules[$key];
+ if (empty($modName)) {
+ continue;
+ }
+
+ if (!class_exists($modName)) {
+ print 'Error: A widget file was found but its class "'.$modName.'" was not found.'."
\n";
+ continue;
+ }
+
+ $objMod = new $modName($db);
+ if (is_object($objMod)) {
+ // Define disabledbyname and disabledbymodule
+ $disabledbyname = 0;
+ $disabledbymodule = 0; // TODO Set to 2 if module is not enabled
+ $module = '';
+
+ // Check if widget file is disabled by name
+ if (preg_match('/NORUN$/i', $files[$key])) {
+ $disabledbyname = 1;
+ }
+
+ // We set info of modules
+ $widget[$j]['picto'] = (empty($objMod->picto) ? (empty($objMod->boximg) ? img_object('', 'generic') : $objMod->boximg) : img_object('', $objMod->picto));
+ $widget[$j]['file'] = $files[$key];
+ $widget[$j]['fullpath'] = $fullpath[$key];
+ $widget[$j]['relpath'] = $relpath[$key];
+ $widget[$j]['iscoreorexternal'] = $iscoreorexternal[$key];
+ $widget[$j]['version'] = empty($objMod->version) ? '' : $objMod->version;
+ $widget[$j]['status'] = img_picto($langs->trans("Active"), 'tick');
+ if ($disabledbyname > 0 || $disabledbymodule > 1) {
+ $widget[$j]['status'] = '';
+ }
+
+ $text = ''.$langs->trans("Description").':
';
+ $text .= $objMod->boxlabel.'
';
+ $text .= '
'.$langs->trans("Status").':
';
+ if ($disabledbymodule == 2) {
+ $text .= $langs->trans("WidgetDisabledAsModuleDisabled", $module).'
';
+ }
+
+ $widget[$j]['info'] = $text;
+ }
+ $j++;
+ }
+
+ return $widget;
+ }
}
diff --git a/htdocs/langs/en_US/modulebuilder.lang b/htdocs/langs/en_US/modulebuilder.lang
index 291cbd93837..193032ec900 100644
--- a/htdocs/langs/en_US/modulebuilder.lang
+++ b/htdocs/langs/en_US/modulebuilder.lang
@@ -183,3 +183,7 @@ DictionaryDeleted=Dictionary %s removed successfully
PropertyModuleUpdated=Property %s has been update successfully
InfoForApiFile=* When you generate file for the first time then all methods will be created for each object.
* When you click in remove you just remove all methods for the selected object.
SetupFile=Page for module setup
+EmailingSelectors=Emailings selectors
+EmailingSelectorDesc=You can generate and edit here the class files to provide new email target selectors for the mass emailing module
+EmailingSelectorFile=Emails selector file
+NoEmailingSelector=No emails selector file
\ No newline at end of file
diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php
index a51210c3b66..85c5f27a81a 100644
--- a/htdocs/modulebuilder/index.php
+++ b/htdocs/modulebuilder/index.php
@@ -3299,6 +3299,7 @@ if ($module == 'initmodule') {
$countMenus = count($moduleobj->menu);
$countTriggers = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/triggers");
$countWidgets = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/boxes");
+ $countEmailingSelectors = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/core/emailings");
$countCss = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/css");
$countJs = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/js");
$countCLI = countItemsInDirectory(dol_buildpath($modulelowercase, 0)."/scripts");
@@ -3357,6 +3358,11 @@ if ($module == 'initmodule') {
$head2[$h][2] = 'widgets';
$h++;
+ $head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=emailings&module='.$module.($forceddirread ? '@'.$dirread : '');
+ $head2[$h][1] = ($countEmailingSelectors <= 0 ? $langs->trans("EmailingSelectors") : $langs->trans("EmailingSelectors").''.$countEmailingSelectors."");
+ $head2[$h][2] = 'emailings';
+ $h++;
+
$head2[$h][0] = $_SERVER["PHP_SELF"].'?tab=exportimport&module='.$module.($forceddirread ? '@'.$dirread : '');
$head2[$h][1] = $langs->trans("Export").'-'.$langs->trans("Import");
$head2[$h][2] = 'exportimport';
@@ -5937,6 +5943,58 @@ if ($module == 'initmodule') {
}
}
+ if ($tab == 'emailings') {
+ print ''."\n";
+ require_once DOL_DOCUMENT_ROOT.'/core/modules/mailings/modules_mailings.php';
+
+ $emailingselectors = MailingTargets::getEmailingSelectorsList(array('/'.strtolower($module).'/core/mailings'));
+
+ if ($action != 'editfile' || empty($file)) {
+ print ''.$langs->trans("EmailingSelectorDesc").'
';
+ print '
';
+
+ print '';
+ } else {
+ $fullpathoffile = dol_buildpath($file, 0);
+
+ $content = file_get_contents($fullpathoffile);
+
+ // New module
+ print '';
+ }
+ }
+
if ($tab == 'exportimport') {
print ''."\n";
$pathtofile = $listofmodules[strtolower($module)]['moduledescriptorrelpath'];
diff --git a/phpstan_action.neon b/phpstan_action.neon
index 82ea3e4a0a0..1f1e6c6309f 100644
--- a/phpstan_action.neon
+++ b/phpstan_action.neon
@@ -1,7 +1,7 @@
parameters:
bootstrapFiles:
- build/phpstan/bootstrap_action.php
- tmpDir: ./build/phpstan/tmp
+ tmpDir: ./github/tmp
parallel:
jobSize: 20
processTimeout: 600.0