mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2025-02-20 13:46:52 +01:00
Merge branch 'develop' into develop
This commit is contained in:
commit
575c59f2e6
|
|
@ -1546,8 +1546,8 @@ if ($action == 'create') {
|
|||
$listofuserid[$firstelem['id']]['transparency'] = (GETPOSTISSET('transparency') ? GETPOST('transparency', 'alpha') : 0); // 0 by default when refreshing
|
||||
}
|
||||
}
|
||||
print '<div class="assignedtouser">';
|
||||
print $form->select_dolusers_forevent(($action == 'create' ? 'add' : 'update'), 'assignedtouser', 1, array(), 0, '', array(), 0, 0, 0, 'AND u.statut != 0', 1, $listofuserid, $listofcontactid, $listofotherid);
|
||||
print '<!-- list of user to assign --><div class="assignedtouser">';
|
||||
print $form->select_dolusers_forevent(($action == 'create' ? 'add' : 'update'), 'assignedtouser', 1, array(), 0, '', array(), 0, 0, 0, 'u.statut:<>:0', 1, $listofuserid, $listofcontactid, $listofotherid);
|
||||
print '</div>';
|
||||
print '</td></tr>';
|
||||
|
||||
|
|
@ -1811,7 +1811,7 @@ if ($action == 'create') {
|
|||
|
||||
print "\n".'<script type="text/javascript">';
|
||||
print '$(document).ready(function () {
|
||||
const reminderDefaultEventTypes = '.$reminderDefaultEventTypes.';
|
||||
const reminderDefaultEventTypes = \''.dol_escape_js($reminderDefaultEventTypes).'\';
|
||||
$("#actioncode").change(function(){
|
||||
var selected_event_type = $("#actioncode option:selected").val();
|
||||
|
||||
|
|
@ -1820,9 +1820,9 @@ if ($action == 'create') {
|
|||
$("#addreminder").prop("checked", true);
|
||||
|
||||
// Set period with default reminder period
|
||||
$("[name=\"offsetvalue\"]").val("' . $reminderDefaultOffset . '");
|
||||
$("[name=\"offsetvalue\"]").val(\'' . dol_escape_js($reminderDefaultOffset) . '\');
|
||||
$("#select_offsetunittype_duration").select2("destroy");
|
||||
$("#select_offsetunittype_duration").val("'.$reminderDefaultUnit.'");
|
||||
$("#select_offsetunittype_duration").val(\''.dol_escape_js($reminderDefaultUnit).'\');
|
||||
$("#select_offsetunittype_duration").select2();
|
||||
|
||||
$("#selectremindertype").select2("destroy");
|
||||
|
|
@ -1832,7 +1832,7 @@ if ($action == 'create') {
|
|||
// Set default reminder mail model
|
||||
$("#select_actioncommsendmodel_mail").closest("tr").show();
|
||||
$("#select_actioncommsendmodel_mail").select2("destroy");
|
||||
$("#select_actioncommsendmodel_mail").val("'.$reminderDefaultEmailModel.'");
|
||||
$("#select_actioncommsendmodel_mail").val(\''.dol_escape_js($reminderDefaultEmailModel).'\');
|
||||
$("#select_actioncommsendmodel_mail").select2();
|
||||
}
|
||||
});
|
||||
|
|
@ -1955,6 +1955,8 @@ if ($id > 0) {
|
|||
}
|
||||
|
||||
if ($action == 'edit') {
|
||||
$caneditdateorowner = ($object->type != 'systemauto');
|
||||
|
||||
if (!empty($conf->use_javascript_ajax)) {
|
||||
print "\n".'<script type="text/javascript">';
|
||||
print '$(document).ready(function () {
|
||||
|
|
@ -1972,7 +1974,9 @@ if ($id > 0) {
|
|||
$(".fulldayendmin").prop("disabled", true).val("59");
|
||||
}
|
||||
}
|
||||
setdatefields();
|
||||
|
||||
'.($caneditdateorowner ? ' setdatefields();' : '').'
|
||||
|
||||
$("#fullday").change(function() {
|
||||
setdatefields();
|
||||
});
|
||||
|
|
@ -2052,7 +2056,8 @@ if ($id > 0) {
|
|||
print '<tr><td'.(!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? ' class="fieldrequired titlefieldcreate"' : '').'>'.$langs->trans("Title").'</td><td colspan="3"><input type="text" name="label" class="soixantepercent" value="'.$object->label.'"></td></tr>';
|
||||
|
||||
// Full day event
|
||||
print '<tr><td><span class="fieldrequired">'.$langs->trans("Date").'</span></td><td colspan="3" class="valignmiddle height30 small"><input type="checkbox" id="fullday" name="fullday" '.($object->fulldayevent ? ' checked' : '').'>';
|
||||
print '<tr><td><span class="fieldrequired">'.$langs->trans("Date").'</span></td><td colspan="3" class="valignmiddle height30 small">';
|
||||
print '<input '.($caneditdateorowner ? '' : ' disabled').' type="checkbox" id="fullday" name="fullday" '.($object->fulldayevent ? ' checked' : '').'>';
|
||||
print '<label for="fullday">'.$langs->trans("EventOnFullDay").'</label>';
|
||||
|
||||
// // Recurring event
|
||||
|
|
@ -2123,9 +2128,9 @@ if ($id > 0) {
|
|||
*/
|
||||
print '</td><td td colspan="3">';
|
||||
$tzforfullday = getDolGlobalString('MAIN_STORE_FULL_EVENT_IN_GMT');
|
||||
print $form->selectDate($datep ? $datep : $object->datep, 'ap', 1, 1, 0, "action", 1, 2, 0, 'fulldaystart', '', '', '', 1, '', '', $object->fulldayevent ? ($tzforfullday ? $tzforfullday : 'tzuserrel') : 'tzuserrel');
|
||||
print $form->selectDate($datep ? $datep : $object->datep, 'ap', 1, 1, 0, "action", 1, 2, ($caneditdateorowner ? 0 : 1), 'fulldaystart', '', '', '', 1, '', '', $object->fulldayevent ? ($tzforfullday ? $tzforfullday : 'tzuserrel') : 'tzuserrel');
|
||||
print ' <span class="hideonsmartphone"> - </span> ';
|
||||
print $form->selectDate($datef ? $datef : $object->datef, 'p2', 1, 1, 1, "action", 1, 2, 0, 'fulldayend', '', '', '', 1, '', '', $object->fulldayevent ? ($tzforfullday ? $tzforfullday : 'tzuserrel') : 'tzuserrel');
|
||||
print $form->selectDate($datef ? $datef : $object->datef, 'p2', 1, 1, 1, "action", 1, 2, ($caneditdateorowner ? 0 : 1), 'fulldayend', '', '', '', 1, '', '', $object->fulldayevent ? ($tzforfullday ? $tzforfullday : 'tzuserrel') : 'tzuserrel');
|
||||
print '</td></tr>';
|
||||
|
||||
print '<tr><td class=""> </td><td></td></tr>';
|
||||
|
|
@ -2164,7 +2169,7 @@ if ($id > 0) {
|
|||
|
||||
print '<tr><td class="tdtop nowrap fieldrequired">'.$langs->trans("ActionAssignedTo").'</td><td colspan="3">';
|
||||
print '<div class="assignedtouser">';
|
||||
print $form->select_dolusers_forevent(($action == 'create' ? 'add' : 'update'), 'assignedtouser', 1, array(), 0, '', array(), 0, 0, 0, 'AND u.statut != 0', 1, $listofuserid, $listofcontactid, $listofotherid);
|
||||
print $form->select_dolusers_forevent(($action == 'create' ? 'add' : 'update'), 'assignedtouser', 1, array(), 0, '', array(), 0, 0, 0, 'u.statut:<>:0', 1, $listofuserid, $listofcontactid, $listofotherid, $caneditdateorowner);
|
||||
print '</div>';
|
||||
/*if (in_array($user->id,array_keys($listofuserid)))
|
||||
{
|
||||
|
|
@ -2414,7 +2419,7 @@ if ($id > 0) {
|
|||
|
||||
print "\n".'<script type="text/javascript">';
|
||||
print '$(document).ready(function () {
|
||||
const reminderDefaultEventTypes = '.$reminderDefaultEventTypes.';
|
||||
const reminderDefaultEventTypes = \''.dol_escape_js($reminderDefaultEventTypes).'\';
|
||||
$("#actioncode").change(function(){
|
||||
var selected_event_type = $("#actioncode option:selected").val();
|
||||
|
||||
|
|
@ -2423,9 +2428,9 @@ if ($id > 0) {
|
|||
$("#addreminder").prop("checked", true);
|
||||
|
||||
// Set period with default reminder period
|
||||
$("#offsetvalue").val('.$reminderDefaultOffset.');
|
||||
$("#offsetvalue").val(\''.dol_escape_js($reminderDefaultOffset).'\');
|
||||
$("#select_offsetunittype_duration").select2("destroy");
|
||||
$("#select_offsetunittype_duration").val("'.$reminderDefaultUnit.'");
|
||||
$("#select_offsetunittype_duration").val(\''.dol_escape_js($reminderDefaultUnit).'\');
|
||||
$("#select_offsetunittype_duration").select2();
|
||||
|
||||
$("#selectremindertype").select2("destroy");
|
||||
|
|
@ -2435,7 +2440,7 @@ if ($id > 0) {
|
|||
// Set default reminder mail model
|
||||
$("#select_actioncommsendmodel_mail").closest("tr").show();
|
||||
$("#select_actioncommsendmodel_mail").select2("destroy");
|
||||
$("#select_actioncommsendmodel_mail").val("'.$reminderDefaultEmailModel.'");
|
||||
$("#select_actioncommsendmodel_mail").val(\''.dol_escape_js($reminderDefaultEmailModel).'\');
|
||||
$("#select_actioncommsendmodel_mail").select2();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -569,12 +569,12 @@ $viewmode .= '<span class="marginrightonly"></span>'; // To add a space before t
|
|||
$newparam = '';
|
||||
$newcardbutton = '';
|
||||
if ($user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create')) {
|
||||
$tmpforcreatebutton = dol_getdate(dol_now(), true);
|
||||
$tmpforcreatebutton = dol_getdate(dol_now('tzuserrel'), true);
|
||||
|
||||
$newparam .= '&month='.((int) $month).'&year='.((int) $tmpforcreatebutton['year']).'&mode='.urlencode($mode);
|
||||
|
||||
//$param='month='.$monthshown.'&year='.$year;
|
||||
$hourminsec = dol_print_date(dol_mktime(10, 0, 0, 1, 1, 1970, 'gmt'), '%H', 'gmt').'0000'; // Set $hourminsec to '100000' to auto set hour to 10:00 at creation
|
||||
//$hourminsec = dol_print_date(dol_mktime(10, 0, 0, 1, 1, 1970, 'gmt'), '%H', 'gmt').'0000'; // Set $hourminsec to '100000' to auto set hour to 10:00 at creation
|
||||
|
||||
$urltocreateaction = DOL_URL_ROOT.'/comm/action/card.php?action=create';
|
||||
$urltocreateaction .= '&apyear='.$tmpforcreatebutton['year'].'&apmonth='.$tmpforcreatebutton['mon'].'&apday='.$tmpforcreatebutton['mday'].'&aphour='.$tmpforcreatebutton['hours'].'&apmin='.$tmpforcreatebutton['minutes'];
|
||||
|
|
|
|||
|
|
@ -736,13 +736,13 @@ $viewmode .= '</div>';
|
|||
|
||||
$viewmode .= '<span class="marginrightonly"></span>';
|
||||
|
||||
|
||||
$tmpforcreatebutton = dol_getdate(dol_now(), true);
|
||||
$tmpforcreatebutton = dol_getdate(dol_now('tzuserrel'), true);
|
||||
|
||||
$newparam = '&month='.str_pad((string) $month, 2, "0", STR_PAD_LEFT).'&year='.$tmpforcreatebutton['year'];
|
||||
|
||||
$url = DOL_URL_ROOT.'/comm/action/card.php?action=create';
|
||||
$url .= '&apyear='.$tmpforcreatebutton['year'].'&apmonth='.$tmpforcreatebutton['mon'].'&apday='.$tmpforcreatebutton['mday'].'&aphour='.$tmpforcreatebutton['hours'].'&apmin='.$tmpforcreatebutton['minutes'];
|
||||
$url .= '&apyear='.$tmpforcreatebutton['year'].'&apmonth='.$tmpforcreatebutton['mon'].'&apday='.$tmpforcreatebutton['mday'];
|
||||
$url .= '&aphour='.$tmpforcreatebutton['hours'].'&apmin='.$tmpforcreatebutton['minutes'];
|
||||
$url .= '&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam ? '?'.$newparam : ''));
|
||||
|
||||
$newcardbutton = dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, '', (int) ($user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create')));
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ $viewmode .= '<span class="marginrightonly"></span>';
|
|||
$newparam = '';
|
||||
$newcardbutton = '';
|
||||
if ($user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create')) {
|
||||
$tmpforcreatebutton = dol_getdate(dol_now(), true);
|
||||
$tmpforcreatebutton = dol_getdate(dol_now('tzuserrel'), true);
|
||||
|
||||
$newparam .= '&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$tmpforcreatebutton['year'];
|
||||
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ $viewmode .= '<span class="marginrightonly"></span>';
|
|||
$newparam = '';
|
||||
$newcardbutton = '';
|
||||
if ($user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create')) {
|
||||
$tmpforcreatebutton = dol_getdate(dol_now(), true);
|
||||
$tmpforcreatebutton = dol_getdate(dol_now('tzuserrel'), true);
|
||||
|
||||
$newparam .= '&month='.urlencode(str_pad((string) $month, 2, "0", STR_PAD_LEFT)).'&year='.((int) $tmpforcreatebutton['year']);
|
||||
if ($begin_h !== '') {
|
||||
|
|
|
|||
|
|
@ -1712,35 +1712,37 @@ if ($object->id > 0) {
|
|||
}
|
||||
|
||||
// Add invoice
|
||||
if ($user->socid == 0) {
|
||||
if (isModEnabled('deplacement') && $object->status == 1) {
|
||||
$langs->load("trips");
|
||||
print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/compta/deplacement/card.php?socid='.$object->id.'&action=create">'.$langs->trans("AddTrip").'</a></div>';
|
||||
}
|
||||
if (isModEnabled('deplacement') && $object->status == 1) {
|
||||
$langs->load("trips");
|
||||
print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/compta/deplacement/card.php?socid='.$object->id.'&action=create">'.$langs->trans("AddTrip").'</a></div>';
|
||||
}
|
||||
|
||||
if (isModEnabled('invoice') && $object->status == 1) {
|
||||
if (!$user->hasRight('facture', 'creer')) {
|
||||
$langs->load("bills");
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("NotAllowed")).'" href="#">'.$langs->trans("AddBill").'</a></div>';
|
||||
if (isModEnabled('invoice') && $object->status == 1) {
|
||||
if (!$user->hasRight('facture', 'creer')) {
|
||||
$langs->load("bills");
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("NotAllowed")).'" href="#">'.$langs->trans("AddBill").'</a></div>';
|
||||
} else {
|
||||
$langs->loadLangs(array("orders", "bills"));
|
||||
|
||||
if ($object->client != 0 && $object->client != 2) {
|
||||
print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/card.php?action=create&socid='.$object->id.'">'.$langs->trans("AddBill").'</a></div>';
|
||||
} else {
|
||||
$langs->loadLangs(array("orders", "bills"));
|
||||
|
||||
if (isModEnabled('order')) {
|
||||
if ($object->client != 0 && $object->client != 2) {
|
||||
if (!empty($orders2invoice) && $orders2invoice > 0) {
|
||||
print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/commande/list.php?socid='.$object->id.'&search_billed=0&autoselectall=1">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>';
|
||||
} else {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("NoOrdersToInvoice")).'" href="#">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>';
|
||||
}
|
||||
} else {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("ThirdPartyMustBeEditAsCustomer")).'" href="#">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>';
|
||||
}
|
||||
}
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("ThirdPartyMustBeEditAsCustomer")).'" href="#">'.$langs->trans("AddBill").'</a></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isModEnabled('invoice') && $object->status == 1) {
|
||||
if ($user->hasRight('facture', 'creer')) {
|
||||
if (isModEnabled('order')) {
|
||||
if ($object->client != 0 && $object->client != 2) {
|
||||
print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/card.php?action=create&socid='.$object->id.'">'.$langs->trans("AddBill").'</a></div>';
|
||||
if (!empty($orders2invoice) && $orders2invoice > 0) {
|
||||
print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/commande/list.php?socid='.$object->id.'&search_billed=0&autoselectall=1">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>';
|
||||
} else {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("NoOrdersToInvoice")).'" href="#">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>';
|
||||
}
|
||||
} else {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("ThirdPartyMustBeEditAsCustomer")).'" href="#">'.$langs->trans("AddBill").'</a></div>';
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" title="'.dol_escape_js($langs->trans("ThirdPartyMustBeEditAsCustomer")).'" href="#">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1149,15 +1149,16 @@ class Form
|
|||
* Return list of types of lines (product or service)
|
||||
* Example: 0=product, 1=service, 9=other (for external module)
|
||||
*
|
||||
* @param string $selected Preselected type
|
||||
* @param string $htmlname Name of field in html form
|
||||
* @param int<0,1>|string $showempty Add an empty field
|
||||
* @param int $hidetext Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
|
||||
* @param integer $forceall 1=Force to show products and services in combo list, whatever are activated modules, 0=No force, 2=Force to show only Products, 3=Force to show only services, -1=Force none (and set hidden field to 'service')
|
||||
* @param string $morecss More css
|
||||
* @param string $selected Preselected type
|
||||
* @param string $htmlname Name of field in html form
|
||||
* @param int<0,1>|string $showempty Add an empty field
|
||||
* @param int $hidetext Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
|
||||
* @param integer $forceall 1=Force to show products and services in combo list, whatever are activated modules, 0=No force, 2=Force to show only Products, 3=Force to show only services, -1=Force none (and set hidden field to 'service')
|
||||
* @param string $morecss More css
|
||||
* @param int $useajaxcombo 1=Use ajaxcombo
|
||||
* @return void
|
||||
*/
|
||||
public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "")
|
||||
public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
|
||||
{
|
||||
// phpcs:enable
|
||||
global $langs;
|
||||
|
|
@ -1166,11 +1167,11 @@ class Form
|
|||
if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
|
||||
|| (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
|
||||
if (empty($hidetext)) {
|
||||
print $langs->trans("Type") . ': ';
|
||||
print $langs->trans("Type").'...';
|
||||
}
|
||||
print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
|
||||
if ($showempty) {
|
||||
print '<option value="-1"';
|
||||
print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
|
||||
if ($selected == -1) {
|
||||
print ' selected';
|
||||
}
|
||||
|
|
@ -1196,7 +1197,10 @@ class Form
|
|||
print '>' . $langs->trans("Service");
|
||||
|
||||
print '</select>';
|
||||
print ajax_combobox('select_' . $htmlname);
|
||||
|
||||
if ($useajaxcombo) {
|
||||
print ajax_combobox('select_' . $htmlname);
|
||||
}
|
||||
//if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
|
||||
}
|
||||
if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
|
||||
|
|
@ -2228,7 +2232,13 @@ class Form
|
|||
$sql .= " AND u.fk_soc IS NULL";
|
||||
}
|
||||
if (!empty($morefilter)) {
|
||||
$sql .= " " . $morefilter;
|
||||
$errormessage = '';
|
||||
$sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
|
||||
if ($errormessage) {
|
||||
$this->errors[] = $errormessage;
|
||||
dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Add hook to filter on user (for example on usergroup define in custom modules)
|
||||
|
|
@ -2425,28 +2435,29 @@ class Form
|
|||
* Return select list of users. Selected users are stored into session.
|
||||
* List of users are provided into $_SESSION['assignedtouser'].
|
||||
*
|
||||
* @param string $action Value for $action
|
||||
* @param string $htmlname Field name in form
|
||||
* @param int<0,1> $show_empty 0=list without the empty value, 1=add empty value
|
||||
* @param int[] $exclude Array list of users id to exclude
|
||||
* @param int<0,1> $disabled If select list must be disabled
|
||||
* @param int[]|string $include Array list of users id to include or 'hierarchy' to have only supervised users
|
||||
* @param int[]|int $enableonly Array list of users id to be enabled. All other must be disabled
|
||||
* @param string $force_entity '0' or Ids of environment to force
|
||||
* @param int $maxlength Maximum length of string into list (0=no limit)
|
||||
* @param int<0,1> $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
|
||||
* @param string $morefilter Add more filters into sql request
|
||||
* @param int $showproperties Show properties of each attendees
|
||||
* @param int[] $listofuserid Array with properties of each user
|
||||
* @param int[] $listofcontactid Array with properties of each contact
|
||||
* @param int[] $listofotherid Array with properties of each other contact
|
||||
* @return string HTML select string
|
||||
* @param string $action Value for $action
|
||||
* @param string $htmlname Field name in form
|
||||
* @param int<0,1> $show_empty 0=list without the empty value, 1=add empty value
|
||||
* @param int[] $exclude Array list of users id to exclude
|
||||
* @param int<0,1> $disabled If select list must be disabled
|
||||
* @param int[]|''|'hierarchy'|'hierarchyme' $include Array list of users id to include or 'hierarchy' to have only supervised users
|
||||
* @param int[]|int $enableonly Array list of users id to be enabled. All other must be disabled
|
||||
* @param string $force_entity '0' or Ids of environment to force
|
||||
* @param int $maxlength Maximum length of string into list (0=no limit)
|
||||
* @param int<0,1> $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
|
||||
* @param string $morefilter Add more filters into sql request (Example: '(employee:=:1)'). This value must not come from user input.
|
||||
* @param int $showproperties Show properties of each attendees
|
||||
* @param int[] $listofuserid Array with properties of each user
|
||||
* @param int[] $listofcontactid Array with properties of each contact
|
||||
* @param int[] $listofotherid Array with properties of each other contact
|
||||
* @param int $canremoveowner 1 if we can remove owner, 0=no way
|
||||
* @return string HTML select string
|
||||
* @see select_dolgroups()
|
||||
*/
|
||||
public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
|
||||
public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array(), $canremoveowner = 1)
|
||||
{
|
||||
// phpcs:enable
|
||||
global $langs;
|
||||
global $langs, $user;
|
||||
|
||||
$userstatic = new User($this->db);
|
||||
$out = '';
|
||||
|
|
@ -2479,8 +2490,25 @@ class Form
|
|||
$ownerid = $value['id'];
|
||||
$out .= ' (' . $langs->trans("Owner") . ')';
|
||||
}
|
||||
// Add picto to delete owner/assignee
|
||||
if ($nbassignetouser > 1 && $action != 'view') {
|
||||
$out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
|
||||
$canremoveassignee = 1;
|
||||
if ($i == 0) {
|
||||
// We are on the owner of the event
|
||||
if (!$canremoveowner) {
|
||||
$canremoveassignee = 0;
|
||||
}
|
||||
if (!$user->hasRight('agenda', 'allactions', 'create')) {
|
||||
$canremoveassignee = 0; // Can't remove the owner
|
||||
}
|
||||
} else {
|
||||
// We are not on the owner of the event but on a secondary assignee
|
||||
}
|
||||
if ($canremoveassignee) {
|
||||
// If user has all permission, he should be ableto remove a assignee.
|
||||
// If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
|
||||
$out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
|
||||
}
|
||||
}
|
||||
// Show my availability
|
||||
if ($showproperties) {
|
||||
|
|
@ -7404,6 +7432,7 @@ class Form
|
|||
$hourend = $hourstart;
|
||||
}
|
||||
}
|
||||
|
||||
// Show hour
|
||||
$retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
|
||||
if ($emptyhours) {
|
||||
|
|
@ -7426,7 +7455,7 @@ class Form
|
|||
|
||||
if ($m) {
|
||||
// Show minutes
|
||||
$retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
|
||||
$retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
|
||||
if ($emptyhours) {
|
||||
$retstring .= '<option value="-1"> </option>';
|
||||
}
|
||||
|
|
@ -7444,7 +7473,7 @@ class Form
|
|||
}
|
||||
|
||||
// Add a "Now" link
|
||||
if (!empty($conf->use_javascript_ajax) && $addnowlink) {
|
||||
if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
|
||||
// Script which will be inserted in the onClick of the "Now" link
|
||||
$reset_scripts = "";
|
||||
if ($addnowlink == 2) { // local computer time
|
||||
|
|
@ -7531,7 +7560,7 @@ class Form
|
|||
}
|
||||
|
||||
// Add a "Plus one hour" link
|
||||
if ($conf->use_javascript_ajax && $addplusone) {
|
||||
if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
|
||||
// Script which will be inserted in the onClick of the "Add plusone" link
|
||||
$reset_scripts = "";
|
||||
|
||||
|
|
@ -7569,7 +7598,7 @@ class Form
|
|||
}
|
||||
|
||||
// Add a link to set data
|
||||
if ($conf->use_javascript_ajax && !empty($adddateof)) {
|
||||
if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
|
||||
if (!is_array($adddateof)) {
|
||||
$arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1557,11 +1557,13 @@ if (!getDolGlobalString('MAIN_DISABLE_SELECT2_FOCUS_PROTECTION') && !defined('DI
|
|||
* TODO: Recheck with the select2 GH issue and remove once this is fixed on their side
|
||||
*/
|
||||
$(document).on('select2:open', (e) => {
|
||||
console.log("Execute the focus (click on combo or use space when on component");
|
||||
console.log("Execute the focus (click on combo or use space when on component)");
|
||||
const target = $(e.target);
|
||||
if (target && target.length) {
|
||||
let id = target[0].id || target[0].name;
|
||||
if (id.substr(-2) == "[]") id = id.substr(0,id.length-2);
|
||||
if (id.substr(-2) == "[]") {
|
||||
id = id.substr(0,id.length-2);
|
||||
}
|
||||
document.querySelector('input[aria-controls*='+id+']').focus();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10586,6 +10586,7 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
|
|||
while ($scheck && $savescheck != $scheck) {
|
||||
$savescheck = $scheck;
|
||||
$scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
|
||||
$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 '... (' 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('
|
||||
|
|
@ -10646,22 +10647,26 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
|
|||
$forbiddenphpstrings = array('$$', '$_', '}[');
|
||||
$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
|
||||
|
||||
// We list all forbidden function as keywords we don't want to see (we don't mind it if is "kewyord(" or just "keyword", we don't want "keyword" at all)
|
||||
$forbiddenphpfunctions = array();
|
||||
// @phpcs:ignore
|
||||
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64"."_"."decode", "rawurl"."decode", "url"."decode", "str"."_rot13", "hex"."2bin")); // name of forbidden functions are split to avoid false positive
|
||||
$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("function", "call_user_func", "call_user_func_array"));
|
||||
$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
|
||||
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
|
||||
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include"));
|
||||
|
||||
$forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
|
||||
|
||||
$forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
|
||||
$forbiddenphpregex = 'global\s*\$';
|
||||
$forbiddenphpregex .= '|';
|
||||
$forbiddenphpregex .= '\b('.implode('|', $forbiddenphpfunctions).')\b';
|
||||
|
||||
$forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
|
||||
|
||||
|
|
|
|||
|
|
@ -694,8 +694,8 @@ function showWebsiteTemplates(Website $website)
|
|||
|
||||
/**
|
||||
* Check a new string containing only php code (including <php tag)
|
||||
* - Block if bad code in the new string.
|
||||
* - Block also if user has no permission to change PHP code.
|
||||
* - Block if user has no permission to change PHP code.
|
||||
* - Block also if bad code found in the new string.
|
||||
*
|
||||
* @param string $phpfullcodestringold PHP old string (before the change). For example "<?php echo 'a' ?><php echo 'b' ?>"
|
||||
* @param string $phpfullcodestring PHP new string. For example "<?php echo 'a' ?><php echo 'c' ?>"
|
||||
|
|
@ -722,13 +722,15 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
|
|||
|
||||
// Then check forbidden commands
|
||||
if (!$error) {
|
||||
$forbiddenphpstrings = array('$$', '}[');
|
||||
$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('ReflectionFunction'));
|
||||
$forbiddenphpstrings = array('$$', '$_', '}[');
|
||||
//$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
|
||||
$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', 'ReflectionFunction'));
|
||||
|
||||
$forbiddenphpfunctions = array();
|
||||
//$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64"."_"."decode", "rawurl"."decode", "url"."decode", "str"."_rot13", "hex"."2bin")); // name of forbidden functions are split to avoid false positive
|
||||
$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("call_user_func", "call_user_func_array"));
|
||||
//$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
|
||||
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
|
||||
|
|
@ -736,27 +738,38 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
|
|||
$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
|
||||
$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
|
||||
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
|
||||
}
|
||||
//$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include"));
|
||||
|
||||
$forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
|
||||
|
||||
foreach ($forbiddenphpstrings as $forbiddenphpstring) {
|
||||
if (preg_match('/'.preg_quote($forbiddenphpstring, '/').'/ms', $phpfullcodestring)) {
|
||||
if (preg_match('/'.preg_quote($forbiddenphpstring, '/').'/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpstring), null, 'errors');
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($forbiddenphpfunctions as $forbiddenphpcommand) {
|
||||
if (preg_match('/'.$forbiddenphpcommand.'\s*\(/ms', $phpfullcodestring)) {
|
||||
/* replaced with next block
|
||||
foreach ($forbiddenphpfunctions as $forbiddenphpfunction) { // Check "function(" but also "'function'(" and "function ("
|
||||
if (preg_match('/'.$forbiddenphpfunction.'[\'\s]*\(/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpcommand), null, 'errors');
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpfunction), null, 'errors');
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
foreach ($forbiddenphpfunctions as $forbiddenphpfunction) { // Check "function" whatever is "function(" or "function'(" or "function (" or "function"
|
||||
if (preg_match('/\b'.$forbiddenphpfunction.'\b/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpfunction), null, 'errors');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($forbiddenphpmethods as $forbiddenphpmethod) {
|
||||
if (preg_match('/->'.$forbiddenphpmethod.'/ms', $phpfullcodestring)) {
|
||||
if (preg_match('/->'.$forbiddenphpmethod.'/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpmethod), null, 'errors');
|
||||
break;
|
||||
|
|
@ -764,14 +777,14 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
|
|||
}
|
||||
}
|
||||
|
||||
// This char can be used to execute RCE for example using with echo `ls`
|
||||
// This char can be used to execute RCE for example by using echo `ls`
|
||||
if (!$error) {
|
||||
$forbiddenphpchars = array();
|
||||
if (!getDolGlobalString('WEBSITE_PHP_ALLOW_DANGEROUS_CHARS')) { // If option is not on, we disallow functions to execute commands
|
||||
$forbiddenphpchars = array("`");
|
||||
}
|
||||
foreach ($forbiddenphpchars as $forbiddenphpchar) {
|
||||
if (preg_match('/'.$forbiddenphpchar.'/ms', $phpfullcodestring)) {
|
||||
if (preg_match('/'.$forbiddenphpchar.'/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", $forbiddenphpchar), null, 'errors');
|
||||
break;
|
||||
|
|
@ -779,23 +792,31 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
|
|||
}
|
||||
}
|
||||
|
||||
// Deny dynamic functions '${a}(' or '$a[b](' => So we refuse '}(' and ']('
|
||||
// Deny code to call a function obfuscated with comment, like "exec/*...*/ ('ls')";
|
||||
if (!$error) {
|
||||
if (preg_match('/[}\]]\(/ims', $phpfullcodestring)) {
|
||||
if (preg_match('/\*\/\s*\(/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", "exec/*...*/ ('ls')"), null, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
// Deny dynamic functions '${a}(' or '$a[b](' => So we refuse '}(' and ']('
|
||||
if (!$error) {
|
||||
if (preg_match('/[}\]]\s*\(/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", ']('), null, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
// Deny dynamic functions '$xxx('
|
||||
// Deny dynamic functions '$xxx(' or '$xxx (' or '$xxx" ('
|
||||
if (!$error) {
|
||||
if (preg_match('/\$[a-z0-9_\-\/\*]+\(/ims', $phpfullcodestring)) {
|
||||
if (preg_match('/\$[a-z0-9_\-\/\*\"]+\s*\(/ims', $phpfullcodestring)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("DynamicPHPCodeContainsAForbiddenInstruction", '$...('), null, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
// No need to block $conf->global->aaa() because PHP try to run method aaa an not function into $conf->global->aaa.
|
||||
// No need to block $conf->global->aaa() because PHP try to run the method aaa of $conf->global and not the function into $conf->global->aaa.
|
||||
|
||||
// Then check if installmodules does not block dynamic PHP code change.
|
||||
if ($phpfullcodestringold != $phpfullcodestring) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -375,7 +375,7 @@ if ($step == 1 || !$datatoimport) {
|
|||
$label = $objimport->array_import_label[$key];
|
||||
print '<div class="twolinesmax-normallineheight minwidth200onall">';
|
||||
print img_object($objimport->array_import_module[$key]['module']->getName(), $entityicon, 'class="pictofixedwidth"');
|
||||
print dolPrintHtml($label);
|
||||
print dolPrintHTML($label);
|
||||
print '</div>';
|
||||
print '</td><td style="text-align: right">';
|
||||
if ($objimport->array_import_perms[$key]) {
|
||||
|
|
|
|||
|
|
@ -798,7 +798,7 @@ Notes=Notes
|
|||
AddNewLine=Add new line
|
||||
AddFile=Add file
|
||||
FreeZone=Free-text product
|
||||
FreeLineOfType=Free-text item, type:
|
||||
FreeLineOfType=Free-text item, type
|
||||
CloneMainAttributes=Clone object with its main attributes
|
||||
ReGeneratePDF=Re-generate PDF
|
||||
PDFMerge=PDF Merge
|
||||
|
|
|
|||
|
|
@ -1960,7 +1960,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
|
|||
print '<td>'.$form->editfieldkey('AllocateCommercial', 'commercial_id', '', $object, 0).'</td>';
|
||||
print '<td colspan="3" class="maxwidthonsmartphone">';
|
||||
// TODO Use select_doluser in multiselect mode
|
||||
$userlist = $form->select_dolusers($selected, '', 0, null, 0, '', '', '0', 0, 0, 'AND u.statut = 1', 0, '', '', 0, 2);
|
||||
$userlist = $form->select_dolusers($selected, '', 0, null, 0, '', '', '0', 0, 0, 'u.statut:=:1', 0, '', '', 0, 2);
|
||||
// Note: If user has no right to "see all thirdparties", we force selection of sale representative to him, so after creation he can see the record.
|
||||
$selected = (GETPOSTISARRAY('commercial') ? GETPOST('commercial', 'array:int') : (GETPOSTINT('commercial') > 0 ? array(GETPOSTINT('commercial')) : array($user->id)));
|
||||
print img_picto('', 'user').$form->multiselectarray('commercial', $userlist, $selected, 0, 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
|
||||
|
|
@ -2812,7 +2812,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio
|
|||
print '<tr>';
|
||||
print '<td>'.$form->editfieldkey('AllocateCommercial', 'commercial_id', '', $object, 0).'</td>';
|
||||
print '<td colspan="3" class="maxwidthonsmartphone">';
|
||||
$userlist = $form->select_dolusers('', '', 0, null, 0, '', '', 0, 0, 0, 'AND u.statut = 1', 0, '', '', 0, 1);
|
||||
$userlist = $form->select_dolusers('', '', 0, null, 0, '', '', 0, 0, 0, 'u.statut:=:1', 0, '', '', 0, 1);
|
||||
$arrayselected = GETPOST('commercial', 'array');
|
||||
if (empty($arrayselected)) {
|
||||
$arrayselected = $object->getSalesRepresentatives($user, 1);
|
||||
|
|
|
|||
|
|
@ -1290,7 +1290,7 @@ if (empty($type) || $type == 'f') {
|
|||
}
|
||||
|
||||
// If the user can view prospects other than his'
|
||||
$userlist = $form->select_dolusers('', '', 0, null, 0, '', '', 0, 0, 0, 'AND u.statut = 1', 0, '', '', 0, 1);
|
||||
$userlist = $form->select_dolusers('', '', 0, null, 0, '', '', 0, 0, 0, 'u.statut:=:1', 0, '', '', 0, 1);
|
||||
$userlist[-2] = $langs->trans("NoSalesRepresentativeAffected");
|
||||
if ($user->hasRight("societe", "client", "voir") || $socid) {
|
||||
$moreforfilter .= '<div class="divsearchfield">';
|
||||
|
|
|
|||
|
|
@ -748,8 +748,12 @@ input:-webkit-autofill {
|
|||
|
||||
/* CSS for placeholder */
|
||||
.placeholder { color: #ccc; }
|
||||
select.placeholder { color: #ccc; }
|
||||
::-webkit-input-placeholder { color: #ccc; }
|
||||
input:-moz-placeholder { color: #ccc; }
|
||||
select.placeholder option:not(.opacitymediumbycolor):not(.opacitymedium) {
|
||||
color: var(--colortext);
|
||||
}
|
||||
|
||||
input[name=price], input[name=weight], input[name=volume], input[name=surface], input[name=sizeheight], input[name=net_measure], select[name=incoterm_id] { margin-right: 6px; }
|
||||
fieldset {
|
||||
|
|
@ -766,6 +770,7 @@ input#onlinepaymenturl, input#directdownloadlink {
|
|||
opacity: 0.7;
|
||||
}
|
||||
|
||||
|
||||
.formconsumeproduce {
|
||||
background: #f3f3f3;
|
||||
padding: 20px 0px 0px 0px;
|
||||
|
|
|
|||
|
|
@ -933,11 +933,15 @@ input[type=checkbox], input[type=radio] {
|
|||
|
||||
/* CSS for placeholder */
|
||||
.placeholder { color: #ccc; }
|
||||
select.placeholder { color: #ccc; }
|
||||
::-webkit-input-placeholder { color:#ccc; }
|
||||
:-moz-placeholder { color:#bbb; } /* firefox 18- */
|
||||
::-moz-placeholder { color:#bbb; } /* firefox 19+ */
|
||||
:-ms-input-placeholder { color:#ccc; } /* ie */
|
||||
input:-moz-placeholder { color:#ccc; }
|
||||
select.placeholder option:not(.opacitymediumbycolor):not(.opacitymedium) {
|
||||
color: var(--colortext);
|
||||
}
|
||||
|
||||
input[name=price], input[name=weight], input[name=volume], input[name=surface], input[name=sizeheight], input[name=net_measure], select[name=incoterm_id] { margin-right: 6px; }
|
||||
fieldset {
|
||||
|
|
@ -4490,7 +4494,7 @@ tr.liste_titre_filter td.liste_titre {
|
|||
padding-top: 4px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
.liste_titre_create td, .liste_titre_create th, .liste_titre_create .tagtd
|
||||
.liste_titre_create td:not(.linecoldescription), .liste_titre_create th, .liste_titre_create .tagtd
|
||||
{
|
||||
border-top-width: 1px;
|
||||
border-top-color: var(--colortopbordertitle1);
|
||||
|
|
@ -4512,6 +4516,10 @@ tr#trlinefordates td {
|
|||
border-top-style: solid;
|
||||
}
|
||||
|
||||
td.linecoldescription {
|
||||
padding: 6px 10px 6px 12px !important; /* t r b l */
|
||||
}
|
||||
|
||||
table.liste th, table.noborder th, table.noborder tr.liste_titre td, table.noborder tr.box_titre td {
|
||||
padding: 8px 8px 8px 10px; /* t r b l */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ class AllTests
|
|||
$suite->addTestSuite('SecurityTest');
|
||||
require_once dirname(__FILE__).'/SecurityGETPOSTTest.php';
|
||||
$suite->addTestSuite('SecurityGETPOSTTest');
|
||||
require_once dirname(__FILE__).'/SecurityLoginTest.php';
|
||||
$suite->addTestSuite('SecurityLoginTest');
|
||||
|
||||
require_once dirname(__FILE__).'/UserTest.php';
|
||||
$suite->addTestSuite('UserTest');
|
||||
|
|
|
|||
106
test/phpunit/SecurityLoginTest.php
Normal file
106
test/phpunit/SecurityLoginTest.php
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
/* Copyright (C) 2010 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
* Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
|
||||
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* or see https://www.gnu.org/
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file test/phpunit/SecurityTest.php
|
||||
* \ingroup test
|
||||
* \brief PHPUnit test
|
||||
* \remarks To run this script as CLI: phpunit filename.php
|
||||
*/
|
||||
|
||||
global $conf,$user,$langs,$db;
|
||||
//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver
|
||||
//require_once 'PHPUnit/Autoload.php';
|
||||
|
||||
if (! defined('NOREQUIRESOC')) {
|
||||
define('NOREQUIRESOC', '1');
|
||||
}
|
||||
if (! defined('NOCSRFCHECK')) {
|
||||
define('NOCSRFCHECK', '1');
|
||||
}
|
||||
if (! defined('NOTOKENRENEWAL')) {
|
||||
define('NOTOKENRENEWAL', '1');
|
||||
}
|
||||
if (! defined('NOREQUIREMENU')) {
|
||||
define('NOREQUIREMENU', '1'); // If there is no menu to show
|
||||
}
|
||||
if (! defined('NOREQUIREHTML')) {
|
||||
define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php
|
||||
}
|
||||
if (! defined('NOREQUIREAJAX')) {
|
||||
define('NOREQUIREAJAX', '1');
|
||||
}
|
||||
if (! defined("NOLOGIN")) {
|
||||
define("NOLOGIN", '1'); // If this page is public (can be called outside logged session)
|
||||
}
|
||||
if (! defined("NOSESSION")) {
|
||||
define("NOSESSION", '1');
|
||||
}
|
||||
|
||||
require_once dirname(__FILE__).'/../../htdocs/main.inc.php'; // We force include of main.inc.php instead of master.inc.php even if we are in CLI mode because it contains a lot of security components we want to test.
|
||||
require_once dirname(__FILE__).'/../../htdocs/core/lib/security.lib.php';
|
||||
require_once dirname(__FILE__).'/../../htdocs/core/lib/security2.lib.php';
|
||||
require_once dirname(__FILE__).'/CommonClassTest.class.php';
|
||||
|
||||
if (empty($user->id)) {
|
||||
print "Load permissions for admin user nb 1\n";
|
||||
$user->fetch(1);
|
||||
$user->loadRights();
|
||||
}
|
||||
$conf->global->MAIN_DISABLE_ALL_MAILS = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Class for PHPUnit tests
|
||||
*
|
||||
* @backupGlobals disabled
|
||||
* @backupStaticAttributes enabled
|
||||
* @remarks backupGlobals must be disabled to have db,conf,user and lang not erased.
|
||||
*/
|
||||
class SecurityLoginTest extends CommonClassTest
|
||||
{
|
||||
/**
|
||||
* testCheckLoginPassEntity
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCheckLoginPassEntity()
|
||||
{
|
||||
$login = checkLoginPassEntity('loginbidon', 'passwordbidon', 1, array('dolibarr'));
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, '');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'passwordbidon', 1, array('dolibarr'));
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, '');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'admin', 1, array('dolibarr')); // Should works because admin/admin exists
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, 'admin', 'The test to check if pass of user "admin" is "admin" has failed');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'admin', 1, array('http','dolibarr')); // Should work because of second authentication method
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, 'admin');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'admin', 1, array('forceuser'));
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals('', $login, 'Error'); // Expected '' because should failed because login 'auto' does not exists
|
||||
}
|
||||
}
|
||||
|
|
@ -636,13 +636,13 @@ class SecurityTest extends CommonClassTest
|
|||
$this->assertEquals('Bad string syntax to evaluate: new __forbiddenstring__(\'abc\')', $result);
|
||||
|
||||
|
||||
$result = (string) dol_eval('$a=function() { }; $a;', 1, 1, '0');
|
||||
print "result5 = ".$result."\n";
|
||||
$this->assertStringContainsString('Bad string syntax to evaluate', $result);
|
||||
$result = dol_eval('$a=function() { }; $a', 1, 1, '0'); // result of dol_eval may be an object Closure
|
||||
print "result5 = ".json_encode($result)."\n";
|
||||
$this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result));
|
||||
|
||||
$result = (string) dol_eval('$a=function() { }; $a;', 1, 1, '1');
|
||||
print "result6 = ".$result."\n";
|
||||
$this->assertStringContainsString('Bad string syntax to evaluate', $result);
|
||||
$result = dol_eval('$a=function() { }; $a();', 1, 1, '1');
|
||||
print "result6 = ".json_encode($result)."\n";
|
||||
$this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result));
|
||||
|
||||
$result = (string) dol_eval('$a=exec("ls");', 1, 1);
|
||||
print "result7 = ".$result."\n";
|
||||
|
|
@ -723,6 +723,11 @@ class SecurityTest extends CommonClassTest
|
|||
$result = (string) dol_eval('($a = "ex") && ($b = "ec") && ($cmd = "$a$b") && $cmd ("curl localhost:5555")', 1, 0);
|
||||
print "result22 = ".$result."\n";
|
||||
$this->assertStringContainsString('Bad string syntax to evaluate', $result, 'Test 22');
|
||||
|
||||
|
||||
$result = (string) dol_eval('\'exec\'("aaa")', 1, 0);
|
||||
print "result1 = ".$result."\n";
|
||||
$this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result), 'Cant find the string Bad string syntaxwhen i should');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -966,33 +971,4 @@ class SecurityTest extends CommonClassTest
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* testCheckLoginPassEntity
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCheckLoginPassEntity()
|
||||
{
|
||||
$login = checkLoginPassEntity('loginbidon', 'passwordbidon', 1, array('dolibarr'));
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, '');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'passwordbidon', 1, array('dolibarr'));
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, '');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'admin', 1, array('dolibarr')); // Should works because admin/admin exists
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, 'admin', 'The test to check if pass of user "admin" is "admin" has failed');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'admin', 1, array('http','dolibarr')); // Should work because of second authentication method
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals($login, 'admin');
|
||||
|
||||
$login = checkLoginPassEntity('admin', 'admin', 1, array('forceuser'));
|
||||
print __METHOD__." login=".$login."\n";
|
||||
$this->assertEquals('', $login, 'Error'); // Expected '' because should failed because login 'auto' does not exists
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,11 +65,11 @@ if (empty($user->id)) {
|
|||
print "Load permissions for admin user nb 1\n";
|
||||
$user->fetch(1);
|
||||
$user->loadRights();
|
||||
|
||||
if (empty($user->rights->website)) {
|
||||
$user->rights->website = new stdClass();
|
||||
}
|
||||
}
|
||||
if (empty($user->rights->website)) {
|
||||
$user->rights->website = new stdClass();
|
||||
}
|
||||
|
||||
$conf->global->MAIN_DISABLE_ALL_MAILS = 1;
|
||||
|
||||
|
||||
|
|
@ -132,22 +132,61 @@ class WebsiteTest extends CommonClassTest
|
|||
*/
|
||||
public function testCheckPHPCode()
|
||||
{
|
||||
global $user;
|
||||
global $conf, $user;
|
||||
|
||||
// Force permission so this is not the permission that will affect result of checkPHPCode
|
||||
$user->rights->website->writephp = 1;
|
||||
|
||||
// Legitimate
|
||||
|
||||
$t = '';
|
||||
$s = '<?php execu ?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 0, 'checkPHPCode detect string as dangerous when it is legitimate');
|
||||
|
||||
|
||||
// Dangerous
|
||||
|
||||
$t = '';
|
||||
$s = '<?php exec("eee"); ?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 1, 'checkPHPCode did not detect the string was dangerous');
|
||||
|
||||
$t = '';
|
||||
$s = '<?php eXec ("eee"); ?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 1, 'checkPHPCode did not detect the string was dangerous');
|
||||
|
||||
$t = '';
|
||||
$s = '<?php $a="xec"; "e$a" ("ee"); ?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 1, 'checkPHPCode did not detect the string was dangerous');
|
||||
|
||||
$t = '';
|
||||
$s = '<?php $a=\'exec\'("ee"); ?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 1, 'checkPHPCode did not detect the string was dangerous');
|
||||
|
||||
$t = '';
|
||||
$s = '<?php $_="{"; $_=($_^"<").($_^">;").($_^"/"); ?><?=${\'_\'.$_}["_"](${\'_\'.$_}["__"]);?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 1, 'checkPHPCode did not detect the string was dangerous');
|
||||
|
||||
// Dangerous but legitimate due to option WEBSITE_PHP_ALLOW_EXEC
|
||||
|
||||
$conf->global->WEBSITE_PHP_ALLOW_EXEC = 1;
|
||||
|
||||
$t = '';
|
||||
$s = '<?php exec("eee"); ?>';
|
||||
$result = checkPHPCode($t, $s);
|
||||
print __METHOD__." result checkPHPCode=".$result."\n";
|
||||
$this->assertEquals($result, 0, 'checkPHPCode did not accept the exec. it should when WEBSITE_PHP_ALLOW_EXEC is set.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user