';
$tmpaction = 'edit';
- $parameters = array('fieldlist' => $fieldlist, 'tabname' => $tabname[$id]);
+ $parameters = array('fieldlist' => $fieldlist, 'tabname' => $tabname[25]);
$reshook = $hookmanager->executeHooks('editEmailTemplateFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error;
$errors = $hookmanager->errors;
@@ -1089,7 +1106,7 @@ if ($num) {
}
// Show main fields
if (empty($reshook)) {
- fieldList($fieldlist, $obj, $tabname[$id], $action);
+ fieldList($fieldlist, $obj, $tabname[25], $action);
}
// Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
@@ -1122,23 +1139,23 @@ if ($num) {
if ($showfield) {
// Show line for topic, joinfiles and content
if ($tmpfieldlist == 'topic') {
- print ''.$form->textwithpicto($langs->trans("Topic"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
+ print ''.$form->textwithpicto($langs->trans("Topic"), $tabhelp[25][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
print '';
print '
'."\n";
}
if ($tmpfieldlist == 'email_from') {
- print ''.$form->textwithpicto($langs->trans("MailFrom"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
+ print ''.$form->textwithpicto($langs->trans("MailFrom"), $tabhelp[25][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
print '';
print '
'."\n";
}
if ($tmpfieldlist == 'joinfiles') {
- print ''.$form->textwithpicto($langs->trans("FilesAttachedToEmail"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
+ print ''.$form->textwithpicto($langs->trans("FilesAttachedToEmail"), $tabhelp[25][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
print $form->selectyesno($tmpfieldlist.'-'.$rowid, (isset($obj->$tmpfieldlist) ? $obj->$tmpfieldlist : '0'), 1, ($action != 'edit'), 0, 1);
print '
'."\n";
}
if ($tmpfieldlist == 'content') {
- print $form->textwithpicto($langs->trans("Content"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
+ print $form->textwithpicto($langs->trans("Content"), $tabhelp[25][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
$okforextended = true;
if (!getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
$okforextended = false;
@@ -1148,7 +1165,7 @@ if ($num) {
}
if ($tmpfieldlist == 'content_lines') {
print '
'."\n";
- print $form->textwithpicto($langs->trans("ContentForLines"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
+ print $form->textwithpicto($langs->trans("ContentForLines"), $tabhelp[25][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'
';
$okforextended = true;
if (!getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) {
$okforextended = false;
@@ -1221,7 +1238,7 @@ if ($num) {
}
$tmpaction = 'view';
- $parameters = array('fieldlist' => $fieldlist, 'tabname' => $tabname[$id]);
+ $parameters = array('fieldlist' => $fieldlist, 'tabname' => $tabname[25]);
$reshook = $hookmanager->executeHooks('viewEmailTemplateFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error;
@@ -1380,7 +1397,7 @@ function fieldList($fieldlist, $obj = null, $tabname = '', $context = '')
} elseif ($value == 'fk_user') {
print '';
if ($user->admin && $context != 'preview') {
- print $form->select_dolusers(empty($obj->$value) ? '' : $obj->$value, 'fk_user', 1, null, 0, ($user->admin ? '' : 'hierarchyme'), null, 0, 0, 0, '', 0, '', 'minwidth75 maxwidth100');
+ print $form->select_dolusers(GETPOSTISSET('fk_user') ? GETPOSTINT('fk_user') : (empty($obj->$value) ? '' : $obj->$value), 'fk_user', 1, null, 0, ($user->admin ? '' : 'hierarchyme'), null, 0, 0, 0, '', 0, '', 'minwidth75 maxwidth100');
} else {
if ($context == 'add') { // I am not admin and we show the add form
print $user->getNomUrl(-1); // Me
@@ -1467,10 +1484,10 @@ function fieldList($fieldlist, $obj = null, $tabname = '', $context = '')
if ($value == 'private' && $context != 'preview') {
if (empty($user->admin)) {
// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
- print $form->selectyesno($value, '1', 1);
+ print $form->selectyesno($value, GETPOSTISSET($value) ? GETPOSTINT($value) : (($context != 'add' && isset($obj->$value)) ? $obj->$value : '1'), 1, false, 0, 1);
} else {
// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
- print $form->selectyesno($value, (isset($obj->$value) ? $obj->$value : ''), 1);
+ print $form->selectyesno($value, (isset($obj->$value) ? $obj->$value : ''), 1, false, 0, 1);
}
} else {
print '';
diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php
index 96e6f47f360..d82fdde2891 100644
--- a/htdocs/comm/action/card.php
+++ b/htdocs/comm/action/card.php
@@ -1275,14 +1275,13 @@ if ($action == 'create') {
// Full day
print ' |
| ';
- print ' ';
+ print ' ';
print img_picto($langs->trans("Recurrence"), 'recurring', 'style="margin-left: 6px" class="paddingright2"');
print ' ';
diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php
index f02a738e2cb..89221999e63 100644
--- a/htdocs/comm/action/class/actioncomm.class.php
+++ b/htdocs/comm/action/class/actioncomm.class.php
@@ -1693,31 +1693,35 @@ class ActionComm extends CommonObject
$result = '';
// Set label of type
- $labeltype = '';
- if ($this->type_code) {
- $langs->load("commercial");
- $labeltype = ($langs->transnoentities("Action".$this->type_code) != "Action".$this->type_code) ? $langs->transnoentities("Action".$this->type_code) : $this->type_label;
- }
- if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
- if ($this->type_code != 'AC_OTH_AUTO') {
- $labeltype = $langs->trans('ActionAC_MANUAL');
- }
- }
+ $labeltype = $this->getTypeLabel(1);
$tooltip = img_picto('', $this->picto).' '.$langs->trans('Action').'';
+
+ $tooltip .= ' - '.$this->getTypePicto('pictofixedwidth paddingright valignmiddle').$labeltype;
if (!empty($this->ref)) {
$tooltip .= ' '.$langs->trans('Ref').': '.dol_escape_htmltag($this->ref);
}
if (!empty($label)) {
$tooltip .= ' '.$langs->trans('Title').': '.dol_escape_htmltag($label);
}
- if (!empty($labeltype)) {
- $tooltip .= ' '.$langs->trans('Type').': '.dol_escape_htmltag($labeltype);
- }
if (!empty($this->location)) {
$tooltip .= ' '.$langs->trans('Location').': '.dol_escape_htmltag($this->location);
}
- if (isset($this->transparency)) {
+
+ $tooltip .= ' '.$langs->trans('Date').': '.dol_print_date($this->datep, 'dayhourreduceformat', 'tzuserrel');
+ if ($this->datef) {
+ $tmpa = dol_getdate($this->datep);
+ $tmpb = dol_getdate($this->datef);
+ if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
+ if ($tmpa['hours'] != $tmpb['hours'] || $tmpa['minutes'] != $tmpb['minutes']) {
+ $tooltip .= '-'.dol_print_date($this->datef, 'hour', 'tzuserrel');
+ }
+ } else {
+ $tooltip .= '-'.dol_print_date($this->datef, 'dayhourreduceformat', 'tzuserrel');
+ }
+ }
+
+ if ($this->datef && $this->datep != $this->datef && isset($this->transparency)) {
$tooltip .= ' '.$langs->trans('Busy').': '.yn($this->transparency);
}
if (!empty($this->email_msgid)) {
@@ -1889,6 +1893,49 @@ class ActionComm extends CommonObject
}
+ /**
+ * Return label of type of event
+ *
+ * @param string $mode 0=Mode short, 1=Mode long
+ * @return string HTML String
+ */
+ public function getTypeLabel($mode = 0)
+ {
+ global $conf, $langs;
+
+ // If cache for array of types unknown, we load it
+ if (!empty($conf->cache['actioncommgetypelabel'])) {
+ $arraylist = $conf->cache['actioncommgetypelabel'];
+ } else {
+ require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
+ $caction = new CActionComm($this->db);
+ $arraylist = $caction->liste_array(1, 'code', '', (getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 0 : 1), '', 1);
+ $conf->cache['actioncommgetypelabel'] = $arraylist;
+ }
+
+ $labeltype = $this->type_code;
+ if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
+ $labeltype = 'AC_OTH';
+ }
+ if (preg_match('/^TICKET_MSG/', $this->code)) {
+ $labeltype = $langs->trans("Message");
+ } else {
+ if (!empty($arraylist[$labeltype])) {
+ $labeltype = $arraylist[$labeltype];
+ }
+ if ($this->type_code == 'AC_OTH_AUTO' && ($this->type_code != $this->code) && $labeltype && !empty($arraylist[$this->code])) {
+ $labeltype .= ' - '.$arraylist[$this->code]; // Use code in priority over type_code
+ }
+ }
+
+ if ($this->type == 'systemauto' && $mode == 1) {
+ $labeltype .= ' ('.$langs->trans("auto").')';
+ }
+
+
+ return $labeltype;
+ }
+
/**
* Sets object to supplied categories.
*
diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php
index b33b51daa94..5e8f0c95453 100644
--- a/htdocs/comm/propal/card.php
+++ b/htdocs/comm/propal/card.php
@@ -2520,7 +2520,7 @@ if ($action == 'create') {
$morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
$morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
// Thirdparty
- $morehtmlref .= ' '.$langs->trans('ThirdParty').' : '.$soc->getNomUrl(1, 'customer');
+ $morehtmlref .= ' '.$soc->getNomUrl(1, 'customer');
if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
$morehtmlref .= ' ( '.$langs->trans("OtherProposals").')';
}
diff --git a/htdocs/contact/ajax/contact.php b/htdocs/contact/ajax/contact.php
index ef0b50411b4..4a447a4ddca 100644
--- a/htdocs/contact/ajax/contact.php
+++ b/htdocs/contact/ajax/contact.php
@@ -128,18 +128,30 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
$prefix = getDolGlobalString('CONTACT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if CONTACT_DONOTSEARCH_ANYWHERE is on
- $filter = "(lastname:like:'".$prefix.$searchkey."%') OR (firstname:like:'".$prefix.$searchkey."%')";
- if ($showsoc) {
- $filter .= " OR (s.nom:like:'".$prefix.$searchkey."%')";
+ $nbchar = 0;
+ $filter = '';
+ $listofsearchkey = preg_split('/\s+/', $searchkey);
+ foreach ($listofsearchkey as $searchkey) {
+ $nbchar += strlen($searchkey);
+
+ $filter .= ($filter ? ' AND ' : '');
+ $filter .= '(';
+ $filter .= "(lastname:like:'".$prefix.$searchkey."%') OR (firstname:like:'".$prefix.$searchkey."%')";
+ if ($showsoc) {
+ $filter .= " OR (s.nom:like:'".$prefix.$searchkey."%')";
+ }
+ $filter .= ')';
}
- // FIXME
// If CONTACT_USE_SEARCH_TO_SELECT is set, check that nb of chars in $filter is >= to avoid DOS attack
+ if (getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT') && $nbchar < getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT')) {
+ print json_encode(array());
+ } else {
+ $arrayresult = $form->selectcontacts($socid, array(), $htmlname, 1, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty, $filter);
- $arrayresult = $form->selectcontacts($socid, array(), $htmlname, 1, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty, $filter);
-
- if ($outjson) {
- print json_encode($arrayresult);
+ if ($outjson) {
+ print json_encode($arrayresult);
+ }
}
}
diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
index 5e34411373c..d2b9f43c71a 100644
--- a/htdocs/core/class/html.form.class.php
+++ b/htdocs/core/class/html.form.class.php
@@ -1746,8 +1746,7 @@ class Form
* @param string $htmlid Html id to use instead of htmlname
* @param bool $multiple add [] in the name of element and add 'multiple' attribute
* @param integer $disableifempty Set tag 'disabled' on select if there is no choice
- * @param string $filter Optional filters criteras. WARNING: To avoid SQL injection, only few chars [.a-z0-9 =<>] are allowed here, example: 's.rowid <> x'
- * If you need parenthesis, use the Universal Filter Syntax, example: '(s.client:in:1,3)'
+ * @param string $filter Optional filters criteras. You must use the USF (Universal Search Filter) syntax, example: '(s.client:in:1,3)'
* Do not use a filter coming from input of users.
* @return int|string|array Return integer <0 if KO, HTML with select string if OK.
*/
@@ -1793,8 +1792,8 @@ class Form
}
} else {
// If not, we do nothing. We already know that there is no parenthesis
- // TODO Disallow this case in a future.
- dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
+ // TODO Disallow this case in a future by returning an error here.
+ dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
}
}
diff --git a/htdocs/core/class/html.formactions.class.php b/htdocs/core/class/html.formactions.class.php
index 30c5ac70fd9..337f211f182 100644
--- a/htdocs/core/class/html.formactions.class.php
+++ b/htdocs/core/class/html.formactions.class.php
@@ -172,7 +172,7 @@ class FormActions
*/
public function showactions($object, $typeelement, $socid = 0, $forceshowtitle = 0, $morecss = 'listactions', $max = 0, $moreparambacktopage = '', $morehtmlcenter = '', $assignedtouser = 0)
{
- global $langs, $conf, $user, $hookmanager;
+ global $langs, $user, $hookmanager;
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
@@ -185,10 +185,6 @@ class FormActions
dol_print_error($this->db, 'FailedToGetActions');
}
- require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
- $caction = new CActionComm($this->db);
- $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
-
$num = count($listofactions);
if ($num || $forceshowtitle) {
$title = $langs->trans("LatestLinkedEvents", $max ? $max : '');
@@ -308,27 +304,12 @@ class FormActions
}
print ' | ';
- $actionstatic = $actioncomm;
-
// Example: Email sent from invoice card
//$actionstatic->code = 'AC_BILL_SENTBYMAIL
//$actionstatic->type_code = 'AC_OTHER_AUTO'
// Type
- $labeltype = $actionstatic->type_code;
- if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
- $labeltype = 'AC_OTH';
- }
- if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
- $labeltype = $langs->trans("Message");
- } else {
- if (!empty($arraylist[$labeltype])) {
- $labeltype = $arraylist[$labeltype];
- }
- if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
- $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
- }
- }
+ $labeltype = $actioncomm->getTypeLabel(0);
print '';
print $actioncomm->getTypePicto();
print $labeltype;
diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php
index 0b8f66126f5..2461ee36919 100644
--- a/htdocs/core/class/html.formmail.class.php
+++ b/htdocs/core/class/html.formmail.class.php
@@ -499,7 +499,7 @@ class FormMail extends Form
$modelmail_array = array();
if ($this->param['models'] != 'none') {
- $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs);
+ $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); // Fill $this->lines_model
if ($result < 0) {
setEventMessages($this->error, $this->errors, 'errors');
}
@@ -1591,7 +1591,7 @@ class FormMail extends Form
return -1;
}
- $ret = new ModelMail();
+ $ret = new ModelMail($dbs);
$languagetosearch = (is_object($outputlangs) ? $outputlangs->defaultlang : '');
// Define $languagetosearchmain to fall back on main language (for example to get 'es_ES' for 'es_MX')
@@ -1601,7 +1601,7 @@ class FormMail extends Form
$languagetosearchmain = '';
}
- $sql = "SELECT rowid, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
+ $sql = "SELECT rowid, entity, module, label, type_template, topic, email_from, joinfiles, content, content_lines, lang, email_from, email_to, email_tocc, email_tobcc";
$sql .= " FROM ".$dbs->prefix().'c_email_templates';
$sql .= " WHERE (type_template = '".$dbs->escape($type_template)."' OR type_template = 'all')";
$sql .= " AND entity IN (".getEntity('c_email_templates').")";
@@ -1624,6 +1624,7 @@ class FormMail extends Form
if ($id == -1) {
$sql .= " AND position = 0";
}
+ $sql .= " AND entity IN(".getEntity('c_email_templates', 1).")";
if ($languagetosearch) {
$sql .= $dbs->order("position,lang,label", "ASC,DESC,ASC"); // We want line with lang set first, then with lang null or ''
} else {
@@ -1750,7 +1751,7 @@ class FormMail extends Form
}
/**
- * Find if template exists and are available for current user, then set them into $this->lines_module.
+ * Find if template exists and are available for current user, then set them into $this->lines_model.
* Search into table c_email_templates
*
* @param string $type_template Get message for key module
@@ -1761,7 +1762,7 @@ class FormMail extends Form
*/
public function fetchAllEMailTemplate($type_template, $user, $outputlangs, $active = 1)
{
- global $conf;
+ global $db, $conf;
$sql = "SELECT rowid, module, label, topic, content, content_lines, lang, fk_user, private, position";
$sql .= " FROM ".$this->db->prefix().'c_email_templates';
@@ -1788,7 +1789,7 @@ class FormMail extends Form
}
}
- $line = new ModelMail();
+ $line = new ModelMail($db);
$line->id = $obj->rowid;
$line->label = $obj->label;
$line->lang = $obj->lang;
@@ -1986,13 +1987,61 @@ class FormMail extends Form
}
+require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
+
/**
- * ModelMail
- *
* Object of table llx_c_email_templates
+ *
+ * TODO Move this class into a file cemailtemplate.class.php
*/
-class ModelMail
+class ModelMail extends CommonObject
{
+ /**
+ * @var string ID to identify managed object.
+ */
+ public $element = 'email_template';
+
+ /**
+ * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management (so extrafields know the link to the parent table).
+ */
+ public $table_element = 'c_email_templates';
+
+
+ // BEGIN MODULEBUILDER PROPERTIES
+ /**
+ * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
+ */
+ public $fields=array(
+ "rowid" => array("type"=>"integer", "label"=>"TechnicalID", "enabled"=>"1", 'position'=>10, 'notnull'=>1, "visible"=>"-1",),
+ "module" => array("type"=>"varchar(32)", "label"=>"Module", "enabled"=>"1", 'position'=>20, 'notnull'=>0, "visible"=>"-1",),
+ "type_template" => array("type"=>"varchar(32)", "label"=>"Typetemplate", "enabled"=>"1", 'position'=>25, 'notnull'=>0, "visible"=>"-1",),
+ "lang" => array("type"=>"varchar(6)", "label"=>"Lang", "enabled"=>"1", 'position'=>30, 'notnull'=>0, "visible"=>"-1",),
+ "private" => array("type"=>"smallint(6)", "label"=>"Private", "enabled"=>"1", 'position'=>35, 'notnull'=>1, "visible"=>"-1",),
+ "fk_user" => array("type"=>"integer:User:user/class/user.class.php", "label"=>"Fkuser", "enabled"=>"1", 'position'=>40, 'notnull'=>0, "visible"=>"-1", "css"=>"maxwidth500 widthcentpercentminusxx", "csslist"=>"tdoverflowmax150",),
+ "datec" => array("type"=>"datetime", "label"=>"DateCreation", "enabled"=>"1", 'position'=>45, 'notnull'=>0, "visible"=>"-1",),
+ "tms" => array("type"=>"timestamp", "label"=>"DateModification", "enabled"=>"1", 'position'=>50, 'notnull'=>1, "visible"=>"-1",),
+ "label" => array("type"=>"varchar(255)", "label"=>"Label", "enabled"=>"1", 'position'=>55, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1", "css"=>"minwidth300", "cssview"=>"wordbreak", "csslist"=>"tdoverflowmax150",),
+ "position" => array("type"=>"smallint(6)", "label"=>"Position", "enabled"=>"1", 'position'=>60, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "active" => array("type"=>"integer", "label"=>"Active", "enabled"=>"1", 'position'=>65, 'notnull'=>1, "visible"=>"-1", "alwayseditable"=>"1",),
+ "topic" => array("type"=>"text", "label"=>"Topic", "enabled"=>"1", 'position'=>70, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "content" => array("type"=>"mediumtext", "label"=>"Content", "enabled"=>"1", 'position'=>75, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "content_lines" => array("type"=>"text", "label"=>"Contentlines", "enabled"=>"1", 'position'=>80, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "enabled" => array("type"=>"varchar(255)", "label"=>"Enabled", "enabled"=>"1", 'position'=>85, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "joinfiles" => array("type"=>"varchar(255)", "label"=>"Joinfiles", "enabled"=>"1", 'position'=>90, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "email_from" => array("type"=>"varchar(255)", "label"=>"Emailfrom", "enabled"=>"1", 'position'=>95, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "email_to" => array("type"=>"varchar(255)", "label"=>"Emailto", "enabled"=>"1", 'position'=>100, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "email_tocc" => array("type"=>"varchar(255)", "label"=>"Emailtocc", "enabled"=>"1", 'position'=>105, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "email_tobcc" => array("type"=>"varchar(255)", "label"=>"Emailtobcc", "enabled"=>"1", 'position'=>110, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ "defaultfortype" => array("type"=>"smallint(6)", "label"=>"Defaultfortype", "enabled"=>"1", 'position'=>115, 'notnull'=>0, "visible"=>"-1", "alwayseditable"=>"1",),
+ );
+ public $rowid;
+ public $type_template;
+ public $datec;
+ public $tms;
+ public $active;
+ public $enabled;
+ public $defaultfortype;
+
/**
* @var int ID
*/
@@ -2040,4 +2089,71 @@ class ModelMail
* @var int Position of template in a combo list
*/
public $position;
+ // END MODULEBUILDER PROPERTIES
+
+
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct(DoliDB $db)
+ {
+ global $langs;
+
+ $this->db = $db;
+ $this->ismultientitymanaged = 0;
+ $this->isextrafieldmanaged = 1;
+
+ if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) {
+ $this->fields['rowid']['visible'] = 0;
+ }
+ if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
+ $this->fields['entity']['enabled'] = 0;
+ }
+
+ // Example to show how to set values of fields definition dynamically
+ /*if ($user->hasRight('test', 'mailtemplate', 'read')) {
+ $this->fields['myfield']['visible'] = 1;
+ $this->fields['myfield']['noteditable'] = 0;
+ }*/
+
+ // Unset fields that are disabled
+ foreach ($this->fields as $key => $val) {
+ if (isset($val['enabled']) && empty($val['enabled'])) {
+ unset($this->fields[$key]);
+ }
+ }
+
+ // Translate some data of arrayofkeyval
+ if (is_object($langs)) {
+ foreach ($this->fields as $key => $val) {
+ if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
+ foreach ($val['arrayofkeyval'] as $key2 => $val2) {
+ $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Load object in memory from the database
+ *
+ * @param int $id Id object
+ * @param string $ref Ref
+ * @param int $noextrafields 0=Default to load extrafields, 1=No extrafields
+ * @param int $nolines 0=Default to load extrafields, 1=No extrafields
+ * @return int Return integer <0 if KO, 0 if not found, >0 if OK
+ */
+ public function fetch($id, $ref = null, $noextrafields = 0, $nolines = 0)
+ {
+ $result = $this->fetchCommon($id, $ref, '', $noextrafields);
+ if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) {
+ $this->fetchLines($noextrafields);
+ }
+ return $result;
+ }
}
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index bb21df70aea..bbbb770ff2d 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -2063,9 +2063,10 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta
$result = str_ireplace('__SRCHTTPIMG', 'src="http:', $result);
$result = str_ireplace('__SRCHTTPSIMG', 'src="https:', $result);
$result = str_ireplace('__DOUBLEQUOTE', '"', $result);
- $result = str_ireplace('__SIMPLEQUOTE', ''', $result);
}
+ $result = str_ireplace('__SIMPLEQUOTE', ''', $result);
+
//$result="\n\n\n".var_export($tmp, true)."\n\n\n".var_export($result, true);
return $result;
@@ -6339,7 +6340,7 @@ function print_barre_liste($title, $page, $file, $options = '', $sortfield = '',
print ' ';
print $title; // $title may contains HTML
if (!empty($title) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
- print '('.$totalnboflines.')';
+ print '('.$totalnboflines.')';
}
print ' | ';
@@ -6471,9 +6472,10 @@ function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $be
if (empty($hidenavigation)) {
if ((int) $limit > 0 && empty($hideselectlimit)) {
$pagesizechoices = '10:10,15:15,20:20,25:25,50:50,100:100,250:250,500:500,1000:1000';
- $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
- //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
- //$pagesizechoices.=',2:2';
+ $pagesizechoices .= ',5000:5000,10000:10000';
+ //$pagesizechoices .= ',20000:20000'; // Memory trouble on browsers
+ //$pagesizechoices .= ',0:'.$langs->trans("All"); // Not yet supported
+ //$pagesizechoices .= ',2:2';
if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
$pagesizechoices = getDolGlobalString('MAIN_PAGESIZE_CHOICES');
}
@@ -10283,7 +10285,7 @@ function verifCond($strToEvaluate, $onlysimplestring = '1')
* '1' (most common use)=Accept only simple string with char 'a-z0-9\s^$_+-.*>&|=!?():"\',/@';',
* '2' (used for example for the compute property of extrafields)=Accept also '[]'
* @return void|string Nothing or return result of eval (even if type can be int, it is safer to assume string and find all potential typing issues as abs(dol_eval(...)).
- * @see verifCond()
+ * @see verifCond(), checkPHPCode() to see sanitizing rules that should be very close.
* @phan-suppress PhanPluginUnsafeEval
*/
function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1')
@@ -10310,6 +10312,8 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
// We must accept with 1: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
// We must accept with 1: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
// We must accept with 2: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
+
+ // Check if there is dynamic call (first we check chars are all into use a whitelist chars)
$specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
if ($onlysimplestring == '2') {
$specialcharsallowed .= '[]';
@@ -10321,17 +10325,29 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
if ($returnvalue) {
return 'Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s;
} else {
- dol_syslog('Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s);
+ dol_syslog('Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s, LOG_WARNING);
return '';
}
}
+
+ // Check if there is dynamic call (first we use black list patterns)
+ if (preg_match('/\$[\w]*\s*\(/', $s)) {
+ if ($returnvalue) {
+ return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found a call using of "$abc(" or "$abc (" instead of using the direct name of the function): '.$s;
+ } else {
+ dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found a call using of "$abc(" or "$abc (" instead of using the direct name of the function): '.$s, LOG_WARNING);
+ return '';
+ }
+ }
+
+ // Now we check if we try dynamic call (by removing white list pattern of using parenthesis then testing if a parenthesis exists)
$savescheck = '';
$scheck = $s;
while ($scheck && $savescheck != $scheck) {
$savescheck = $scheck;
$scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
$scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
- $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
+ $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... (' like in 'if ($a == 1)'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
$scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
$scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
$scheck = preg_replace('/(\^|\')\(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
@@ -10341,22 +10357,28 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
if ($returnvalue) {
return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s;
} else {
- dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s);
+ dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s, LOG_WARNING);
return '';
}
}
+
// TODO
// We can exclude $ char that are not:
// $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
}
if (is_array($s) || $s === 'Array') {
- return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
+ if ($returnvalue) {
+ return 'Bad string syntax to evaluate (value is Array): '.var_export($s, true);
+ } else {
+ dol_syslog('Bad string syntax to evaluate (value is Array): '.var_export($s, true), LOG_WARNING);
+ return '';
+ }
}
if (strpos($s, '::') !== false) {
if ($returnvalue) {
return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
} else {
- dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
+ dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s, LOG_WARNING);
return '';
}
}
@@ -10364,7 +10386,7 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
if ($returnvalue) {
return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
} else {
- dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
+ dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s, LOG_WARNING);
return '';
}
}
@@ -10372,22 +10394,24 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
if ($returnvalue) {
return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
} else {
- dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
+ dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s, LOG_WARNING);
return '';
}
}
// We block use of php exec or php file functions
- $forbiddenphpstrings = array('$$');
+ $forbiddenphpstrings = array('$$', '$_', '}[');
$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
- $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
- $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
+ $forbiddenphpfunctions = array();
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_compress_dir", "dol_decode", "dol_delete_file", "dol_delete_dir", "dol_delete_dir_recursive", "dol_copy", "archiveOrBackupFile")); // more dolibarr functions
@@ -10405,6 +10429,7 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
//$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\(/i', '', $s); // Remove $function( call and $mycall->mymethod(
} while ($oldstringtoclean != $s);
+
if (strpos($s, '__forbiddenstring__') !== false) {
dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
if ($returnvalue) {
diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php
index 7046fa435a0..37492666269 100644
--- a/htdocs/core/lib/website2.lib.php
+++ b/htdocs/core/lib/website2.lib.php
@@ -688,7 +688,7 @@ function showWebsiteTemplates(Website $website)
* @param string $phpfullcodestringold PHP old string (before the change). For example ""
* @param string $phpfullcodestring PHP new string. For example ""
* @return int Error or not
- * @see dolKeepOnlyPhpCode()
+ * @see dolKeepOnlyPhpCode(), dol_eval() to see sanitizing rules that should be very close.
*/
function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
{
@@ -710,20 +710,46 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
// Then check forbidden commands
if (!$error) {
- $forbiddenphpcommands = array("override_function", "session_id", "session_create_id", "session_regenerate_id");
+ $forbiddenphpstrings = array('$$', '}[');
+ $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('ReflectionFunction'));
+
+ $forbiddenphpfunctions = array();
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("call_user_func"));
+ //$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
if (!getDolGlobalString('WEBSITE_PHP_ALLOW_EXEC')) { // If option is not on, we disallow functions to execute commands
- $forbiddenphpcommands = array_merge($forbiddenphpcommands, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
}
if (!getDolGlobalString('WEBSITE_PHP_ALLOW_WRITE')) { // If option is not on, we disallow functions to write files
- $forbiddenphpcommands = array_merge($forbiddenphpcommands, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "unlink", "mkdir", "rmdir", "symlink", "touch", "umask"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
}
- foreach ($forbiddenphpcommands as $forbiddenphpcommand) {
+
+ $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
+
+ foreach ($forbiddenphpstrings as $forbiddenphpstring) {
+ if (preg_match('/'.preg_quote($forbiddenphpstring, '/').'/ms', $phpfullcodestring)) {
+ $error++;
+ setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpstring), null, 'errors');
+ break;
+ }
+ }
+ foreach ($forbiddenphpfunctions as $forbiddenphpcommand) {
if (preg_match('/'.$forbiddenphpcommand.'\s*\(/ms', $phpfullcodestring)) {
$error++;
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpcommand), null, 'errors');
break;
}
}
+ foreach ($forbiddenphpmethods as $forbiddenphpmethod) {
+ if (preg_match('/->'.$forbiddenphpmethod.'/ms', $phpfullcodestring)) {
+ $error++;
+ setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpmethod), null, 'errors');
+ break;
+ }
+ }
}
// This char can be used to execute RCE for example using with echo `ls`
diff --git a/htdocs/core/tpl/card_presend.tpl.php b/htdocs/core/tpl/card_presend.tpl.php
index 53313f06e90..6731ceb67e4 100644
--- a/htdocs/core/tpl/card_presend.tpl.php
+++ b/htdocs/core/tpl/card_presend.tpl.php
@@ -27,6 +27,7 @@
* $defaulttopic and $defaulttopiclang
* $diroutput
* $arrayoffamiliestoexclude=array('system', 'mycompany', 'object', 'objectamount', 'date', 'user', ...);
+ * $file
*/
// Protection to avoid direct call of template
@@ -134,7 +135,7 @@ if ($action == 'presend') {
$formmail = new FormMail($db);
$formmail->param['langsmodels'] = (empty($newlang) ? $langs->defaultlang : $newlang);
- $formmail->fromtype = (GETPOST('fromtype') ? GETPOST('fromtype') : (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') ? $conf->global->MAIN_MAIL_DEFAULT_FROMTYPE : 'user'));
+ $formmail->fromtype = (GETPOST('fromtype') ? GETPOST('fromtype') : getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE', 'user'));
if ($formmail->fromtype === 'user') {
$formmail->fromid = $user->id;
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index f86fa611b85..d79347c8c4c 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -2536,3 +2536,4 @@ MainAuthenticationOidcLoginClaimName=Login claim
MainAuthenticationOidcLoginClaimDesc=OpenID Connect claim matching the Dolibarr user login. If not set or empty, defaults to email
BlackListWords=Black list of words
AddBlackList=Add to black list
+AnOwnerMustBeSetIfEmailTemplateIsPrivate=An owner must be set if the email template is set as private
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index 18dc30a2c5f..81a316b7f68 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -1299,3 +1299,4 @@ AllEntities=All entities
TranslationOfKey=Translation of the key AnyTranslationKey
SignedStatus=Signed status
NbRecordQualified=Number of qualified records
+auto=auto
diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php
index 21581173871..7a11b824eca 100644
--- a/htdocs/modulebuilder/template/class/myobject.class.php
+++ b/htdocs/modulebuilder/template/class/myobject.class.php
@@ -35,17 +35,17 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
class MyObject extends CommonObject
{
/**
- * @var string ID of module.
+ * @var string ID of module.
*/
public $module = 'mymodule';
/**
- * @var string ID to identify managed object.
+ * @var string ID to identify managed object.
*/
public $element = 'myobject';
/**
- * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management (so extrafields know the link to the parent table).
+ * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management (so extrafields know the link to the parent table).
*/
public $table_element = 'mymodule_myobject';
@@ -55,7 +55,7 @@ class MyObject extends CommonObject
//public $element_for_permission = 'mymodule';
/**
- * @var string String with name of icon for myobject. Must be a 'fa-xxx' fontawesome code (or 'fa-xxx_fa_color_size') or 'myobject@mymodule' if picto is file 'img/object_myobject.png'.
+ * @var string String with name of icon for myobject. Must be a 'fa-xxx' fontawesome code (or 'fa-xxx_fa_color_size') or 'myobject@mymodule' if picto is file 'img/object_myobject.png'.
*/
public $picto = 'fa-file';
diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php
index 98f91d85ce4..de5f62dd8f9 100644
--- a/htdocs/projet/card.php
+++ b/htdocs/projet/card.php
@@ -1444,7 +1444,9 @@ if ($action == 'create' && $user->hasRight('projet', 'creer')) {
// Description
print ''.$langs->trans("Description").' | ';
- print dol_htmlentitiesbr($object->description);
+ print ' ';
+ print dolPrintHTML($object->description);
+ print ' ';
print ' |
';
// Categories
diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php
index db8ac3132c1..31278757e57 100644
--- a/htdocs/societe/list.php
+++ b/htdocs/societe/list.php
@@ -1226,19 +1226,21 @@ if ($search_all) {
print '