diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php index 42e0b84228f..ccf8ae83ef5 100644 --- a/htdocs/adherents/card.php +++ b/htdocs/adherents/card.php @@ -1821,8 +1821,16 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $company = new Societe($db); $result = $company->fetch($object->socid); print $company->getNomUrl(1); + + // Show link to invoices + $tmparray = $company->getOutstandingBills('customer'); + if (!empty($tmparray['refs'])) { + print ' - '.img_picto($langs->trans("Invoices"), 'bill', 'class="paddingright"').''.$langs->trans("Invoices").': '.count($tmparray['refs']); + // TODO Add alert if warning on at least one invoice late + print ''; + } } else { - print $langs->trans("NoThirdPartyAssociatedToMember"); + print ''.$langs->trans("NoThirdPartyAssociatedToMember").''; } } print ''; @@ -1846,7 +1854,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { } print ''; - //VCard + // VCard print ''; print $langs->trans("VCard").''; print ''; diff --git a/htdocs/adherents/subscription.php b/htdocs/adherents/subscription.php index 7f8da3a33b3..3a967677e17 100644 --- a/htdocs/adherents/subscription.php +++ b/htdocs/adherents/subscription.php @@ -209,7 +209,7 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && ! // Subscription informations $datesubscription = 0; $datesubend = 0; - $paymentdate = 0; + $paymentdate = ''; // Do not use 0 here, default value is '' that means not filled where 0 means 1970-01-01 if (GETPOST("reyear", "int") && GETPOST("remonth", "int") && GETPOST("reday", "int")) { $datesubscription = dol_mktime(0, 0, 0, GETPOST("remonth", "int"), GETPOST("reday", "int"), GETPOST("reyear", "int")); } @@ -260,7 +260,7 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && ! } // Check if a payment is mandatory or not - if (!$error && $adht->subscription) { // Member type need subscriptions + if ($adht->subscription) { // Member type need subscriptions if (!is_numeric($amount)) { // If field is '' or not a numeric value $errmsg = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Amount")); @@ -268,28 +268,35 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && ! $error++; $action = 'addsubscription'; } else { + // If an amount has been provided, we check also fields that becomes mandatory when amount is not null. if (!empty($conf->banque->enabled) && GETPOST("paymentsave") != 'none') { if (GETPOST("subscription")) { if (!GETPOST("label")) { $errmsg = $langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")); + setEventMessages($errmsg, null, 'errors'); + $error++; + $action = 'addsubscription'; } if (GETPOST("paymentsave") != 'invoiceonly' && !GETPOST("operation")) { $errmsg = $langs->trans("ErrorFieldRequired", $langs->transnoentities("PaymentMode")); + setEventMessages($errmsg, null, 'errors'); + $error++; + $action = 'addsubscription'; } if (GETPOST("paymentsave") != 'invoiceonly' && !(GETPOST("accountid", 'int') > 0)) { $errmsg = $langs->trans("ErrorFieldRequired", $langs->transnoentities("FinancialAccount")); + setEventMessages($errmsg, null, 'errors'); + $error++; + $action = 'addsubscription'; } } else { - if (GETPOST("accountid")) { + if (GETPOST("accountid", 'int')) { $errmsg = $langs->trans("ErrorDoNotProvideAccountsIfNullAmount"); + setEventMessages($errmsg, null, 'errors'); + $error++; + $action = 'addsubscription'; } } - if ($errmsg) { - $error++; - setEventMessages($errmsg, null, 'errors'); - $error++; - $action = 'addsubscription'; - } } } } @@ -601,8 +608,16 @@ if ($rowid > 0) { $company = new Societe($db); $result = $company->fetch($object->fk_soc); print $company->getNomUrl(1); + + // Show link to invoices + $tmparray = $company->getOutstandingBills('customer'); + if (!empty($tmparray['refs'])) { + print ' - '.img_picto($langs->trans("Invoices"), 'bill', 'class="paddingright"').''.$langs->trans("Invoices").': '.count($tmparray['refs']); + // TODO Add alert if warning on at least one invoice late + print ''; + } } else { - print $langs->trans("NoThirdPartyAssociatedToMember"); + print ''.$langs->trans("NoThirdPartyAssociatedToMember").''; } } print ''; @@ -628,7 +643,7 @@ if ($rowid > 0) { if ($object->user_id) { $form->form_users($_SERVER['PHP_SELF'].'?rowid='.$object->id, $object->user_id, 'none'); } else { - print $langs->trans("NoDolibarrAccess"); + print ''.$langs->trans("NoDolibarrAccess").''; } } print ''; @@ -970,17 +985,18 @@ if ($rowid > 0) { print ''.$langs->trans('MoreActions'); print ''; print ''; - print ' '.$langs->trans("None").'
'; + print ''; + print '
'; // Add entry into bank accoun if (!empty($conf->banque->enabled)) { print ' '.$langs->trans("MoreActionBankDirect").'
'; + print '>
'; } // Add invoice with no payments if (!empty($conf->societe->enabled) && !empty($conf->facture->enabled)) { print 'fk_soc)) print ' disabled'; - print '> '.$langs->trans("MoreActionInvoiceOnly"); + print '>
'; } // Add invoice with payments if (!empty($conf->banque->enabled) && !empty($conf->societe->enabled) && !empty($conf->facture->enabled)) { print 'fk_soc)) print ' disabled'; - print '> '.$langs->trans("MoreActionBankViaInvoice"); + print '>
'; } print ''; diff --git a/htdocs/admin/agenda_xcal.php b/htdocs/admin/agenda_xcal.php index 59dd1bf1ac2..f42cb5c842f 100644 --- a/htdocs/admin/agenda_xcal.php +++ b/htdocs/admin/agenda_xcal.php @@ -165,24 +165,27 @@ $urlvcal = ''.$langs->trans("WebCalUrlForVCalExport", 'vcal', '').''); $message .= ''; +$message .= ajax_autoselect('onlinepaymenturl1'); $message .= '
'; $urlical = '
'; $urlical .= $urlwithroot.'/public/agenda/agendaexport.php?format=ical&type=event'.$getentity.'&exportkey='.($conf->global->MAIN_AGENDA_XCAL_EXPORTKEY ?urlencode($conf->global->MAIN_AGENDA_XCAL_EXPORTKEY) : 'KEYNOTDEFINED').''; $message .= img_picto('', 'globe').' '.str_replace('{url}', $urlical, ''.$langs->trans("WebCalUrlForVCalExport", 'ical/ics', '').''); $message .= ''; +$message .= ajax_autoselect('onlinepaymenturl2'); $message .= '
'; $urlrss = ''; $urlrss .= $urlwithroot.'/public/agenda/agendaexport.php?format=rss'.$getentity.'&exportkey='.($conf->global->MAIN_AGENDA_XCAL_EXPORTKEY ?urlencode($conf->global->MAIN_AGENDA_XCAL_EXPORTKEY) : 'KEYNOTDEFINED').''; $message .= img_picto('', 'globe').' '.str_replace('{url}', $urlrss, ''.$langs->trans("WebCalUrlForVCalExport", 'rss', '').''); $message .= ''; +$message .= ajax_autoselect('onlinepaymenturl3'); $message .= '
'; print $message; diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index 7d261f2d5ab..0204fd28922 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -272,6 +272,19 @@ function societe_prepare_head(Societe $object) $h++; } + if (getDolGlobalString('PARTNERSHIP_IS_MANAGED_FOR') == 'thirdparty') { + if (!empty($user->rights->partnership->read)) { + $nbPartnership = is_array($object->partnerships) ? count($object->partnerships) : 0; + $head[$h][0] = DOL_URL_ROOT.'/societe/partnership.php?socid='.$object->id; + $head[$h][1] = $langs->trans("Partnership"); + $head[$h][2] = 'partnership'; + if ($nbPartnership > 0) { + $head[$h][1] .= ''.$nbPartnership.''; + } + $h++; + } + } + // Show more tabs from modules // Entries must be declared in modules descriptor with line // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 2f3d534d7cc..496a1d1beb3 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -753,9 +753,9 @@ function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = $out = dol_string_nohtmltag($out, 0); // Remove also other dangerous string sequences // '"' is dangerous because param in url can close the href= or src= and add javascript functions. - // '../' is dangerous because it allows dir transversals + // '../' or '..\' is dangerous because it allows dir transversals // Note &, '&', '&'... is a simple char like '&' alone but there is no reason to accept such way to encode input data. - $out = str_ireplace(array('&', '&', '&', '"', '"', '"', '"', '"', '/', '/', '/', '../'), '', $out); + $out = str_ireplace(array('&', '&', '&', '"', '"', '"', '"', '"', '/', '/', '\', '\', '/', '../', '..\\'), '', $out); } while ($oldstringtoclean != $out); // keep lines feed } @@ -768,9 +768,9 @@ function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = // Remove html tags $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8'); // '"' is dangerous because param in url can close the href= or src= and add javascript functions. - // '../' is dangerous because it allows dir transversals + // '../' or '..\' is dangerous because it allows dir transversals // Note &, '&', '&'... is a simple char like '&' alone but there is no reason to accept such way to encode input data. - $out = str_ireplace(array('&', '&', '&', '"', '"', '"', '"', '"', '/', '/', '/', '../'), '', $out); + $out = str_ireplace(array('&', '&', '&', '"', '"', '"', '"', '"', '/', '/', '\', '\', '/', '../', '..\\'), '', $out); } while ($oldstringtoclean != $out); } break; @@ -1323,8 +1323,8 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta if (count($tmparrayoftags)) { foreach ($tmparrayoftags as $tagtoreplace) { - $tmp = str_replace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp); - $tmp = str_replace('', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp); + $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp); + $tmp = str_ireplace('', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp); } } @@ -1332,8 +1332,8 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta if (count($tmparrayoftags)) { foreach ($tmparrayoftags as $tagtoreplace) { - $result = str_replace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result); - $result = str_replace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '', $result); + $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result); + $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '', $result); } } diff --git a/htdocs/core/lib/member.lib.php b/htdocs/core/lib/member.lib.php index fc274e0d624..ed3b69752f1 100644 --- a/htdocs/core/lib/member.lib.php +++ b/htdocs/core/lib/member.lib.php @@ -63,9 +63,7 @@ function member_prepare_head(Adherent $object) $h++; } - $tabtoadd = (!empty(getDolGlobalString('PARTNERSHIP_IS_MANAGED_FOR')) && getDolGlobalString('PARTNERSHIP_IS_MANAGED_FOR') == 'member') ? 'member' : 'thirdparty'; - - if ($tabtoadd == 'member') { + if (getDolGlobalString('PARTNERSHIP_IS_MANAGED_FOR') == 'member') { if (!empty($user->rights->partnership->read)) { $nbPartnership = is_array($object->partnerships) ? count($object->partnerships) : 0; $head[$h][0] = DOL_URL_ROOT.'/adherents/partnership.php?rowid='.$object->id; @@ -76,20 +74,8 @@ function member_prepare_head(Adherent $object) } $h++; } - } else { - if (!empty($user->rights->partnership->read)) { - $nbPartnership = is_array($object->partnerships) ? count($object->partnerships) : 0; - $head[$h][0] = DOL_URL_ROOT.'/societe/partnership.php?socid='.$object->id; - $head[$h][1] = $langs->trans("Partnership"); - $head[$h][2] = 'partnership'; - if ($nbPartnership > 0) { - $head[$h][1] .= ''.$nbPartnership.''; - } - $h++; - } } - // Show more tabs from modules // Entries must be declared in modules descriptor with line // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab diff --git a/htdocs/document.php b/htdocs/document.php index 59501cc4701..3c06801c9a0 100644 --- a/htdocs/document.php +++ b/htdocs/document.php @@ -194,8 +194,9 @@ if (!in_array($type, array('text/x-javascript')) && !dolIsAllowedForPreview($ori $type = 'application/octet-stream'; } -// Security: Delete string ../ into $original_file -$original_file = str_replace("../", "/", $original_file); +// Security: Delete string ../ or ..\ into $original_file +$original_file = str_replace('../', '/', $original_file); +$original_file = str_replace('..\\', '/', $original_file); // Find the subdirectory name as the reference $refname = basename(dirname($original_file)."/"); diff --git a/htdocs/holiday/card.php b/htdocs/holiday/card.php index e8a059b84f8..a58806e2e4f 100644 --- a/htdocs/holiday/card.php +++ b/htdocs/holiday/card.php @@ -50,7 +50,7 @@ $ref = GETPOST('ref', 'alpha'); $fuserid = (GETPOST('fuserid', 'int') ?GETPOST('fuserid', 'int') : $user->id); // Load translation files required by the page -$langs->loadLangs(array("other", "holiday", "mails")); +$langs->loadLangs(array("other", "holiday", "mails", "trips")); $error = 0; @@ -264,6 +264,7 @@ if (empty($reshook)) { } } + // If update and we are an approver, we can update with another approver if ($action == 'update' && GETPOSTISSET('savevalidator') && !empty($user->rights->holiday->approve)) { $object->fetch($id); @@ -316,6 +317,8 @@ if (empty($reshook)) { // If this is the requestor or has read/write rights if ($cancreate) { $approverid = GETPOST('valideur', 'int'); + // TODO Check this approver user id has the permission for approval + $description = trim(GETPOST('description', 'restricthtml')); // If no start date @@ -743,8 +746,8 @@ if (empty($reshook)) { $object->fetch($id); // If status pending validation and validator = validator or user, or rights to do for others - if (($object->statut == Holiday::STATUS_VALIDATED || $object->statut == Holiday::STATUS_APPROVED) && ($user->id == $object->fk_validator || in_array($object->fk_user, $childids) - || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->holiday->writeall_advance)))) { + if (($object->statut == Holiday::STATUS_VALIDATED || $object->statut == Holiday::STATUS_APPROVED) && + (!empty($user->admin) || $user->id == $object->fk_validator || in_array($object->fk_user, $childids) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->holiday->writeall_advance)))) { $db->begin(); $oldstatus = $object->statut; @@ -1438,25 +1441,48 @@ if ((empty($id) && empty($ref)) || $action == 'create' || $action == 'add') { if ($cancreate && $object->statut == Holiday::STATUS_DRAFT) { print ''.$langs->trans("EditCP").''; } + if ($cancreate && $object->statut == Holiday::STATUS_DRAFT) { // If draft print ''.$langs->trans("Validate").''; } + if ($object->statut == Holiday::STATUS_VALIDATED) { // If validated + // Button Approve / Refuse if ($user->id == $object->fk_validator) { print ''.$langs->trans("Approve").''; print ''.$langs->trans("ActionRefuseCP").''; } else { print ''.$langs->trans("Approve").''; print ''.$langs->trans("ActionRefuseCP").''; + + // Button Cancel (because we can't approve) + if (in_array($object->fk_user, $childids) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->holiday->writeall_advance))) { + if (($object->date_debut > dol_now()) || !empty($user->admin)) { + print ''.$langs->trans("ActionCancelCP").''; + } else { + print 'trans("NotAllowed").'">'.$langs->trans("ActionCancelCP").''; + } + } } } - if (($user->id == $object->fk_validator || in_array($object->fk_user, $childids) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->holiday->writeall_advance))) && ($object->statut == 2 || $object->statut == 3)) { // Status validated or approved - if (($object->date_debut > dol_now()) || $user->admin) { - print ''.$langs->trans("ActionCancelCP").''; - } else { - print ''.$langs->trans("ActionCancelCP").''; + if ($object->statut == Holiday::STATUS_APPROVED) { // If validated or approved + if ($user->id == $object->fk_validator + || in_array($object->fk_user, $childids) + || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->holiday->writeall_advance))) { + if (($object->date_debut > dol_now()) || !empty($user->admin)) { + print ''.$langs->trans("ActionCancelCP").''; + } else { + print 'trans("NotAllowed").'">'.$langs->trans("ActionCancelCP").''; + } + } else { // I have no rights on the user of the holiday. + if (!empty($user->admin)) { // If current validator can't cancel an approved leave, we allow admin user + print ''.$langs->trans("ActionCancelCP").''; + } else { + print ''.$langs->trans("ActionCancelCP").''; + } } } + if ($cancreate && $object->statut == Holiday::STATUS_CANCELED) { print ''.$langs->trans("SetToDraft").''; } diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php index 003ac79ede8..41af59a751b 100644 --- a/htdocs/holiday/class/holiday.class.php +++ b/htdocs/holiday/class/holiday.class.php @@ -1664,6 +1664,7 @@ class Holiday extends CommonObject $sql .= " WHERE u.entity IN (".getEntity('user').")"; } $sql .= " AND u.statut > 0"; + $sql .= " AND u.employee = 1"; // We only want employee users for holidays if ($filters) { $sql .= $filters; } @@ -1754,6 +1755,7 @@ class Holiday extends CommonObject } $sql .= " AND u.statut > 0"; + $sql .= " AND u.employee = 1"; // We only want employee users for holidays if ($filters) { $sql .= $filters; } diff --git a/htdocs/societe/partnership.php b/htdocs/societe/partnership.php index 9cb065d2c3b..b1f0f24fbe1 100644 --- a/htdocs/societe/partnership.php +++ b/htdocs/societe/partnership.php @@ -50,6 +50,9 @@ $backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); $socid = GETPOST('socid', 'int'); if (!empty($user->socid)) { $socid = $user->socid; +} + +if (empty($id) && $socid && (empty($conf->global->PARTNERSHIP_IS_MANAGED_FOR) || $conf->global->PARTNERSHIP_IS_MANAGED_FOR == 'thirdparty')) { $id = $socid; } diff --git a/htdocs/viewimage.php b/htdocs/viewimage.php index 9c584f5b8bb..f514c7c0302 100644 --- a/htdocs/viewimage.php +++ b/htdocs/viewimage.php @@ -221,8 +221,9 @@ if (preg_match('/\.noexe$/i', $original_file)) { accessforbidden('Error: Using the image wrapper to output a file ending with .noexe is not allowed.', 0, 0, 1); } -// Security: Delete string ../ into $original_file -$original_file = str_replace("../", "/", $original_file); +// Security: Delete string ../ or ..\ into $original_file +$original_file = str_replace('../', '/', $original_file); +$original_file = str_replace('..\\', '/', $original_file); // Find the subdirectory name as the reference $refname = basename(dirname($original_file)."/"); diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php index 87edca884e4..81eff830b49 100644 --- a/test/phpunit/SecurityTest.php +++ b/test/phpunit/SecurityTest.php @@ -349,7 +349,8 @@ class SecurityTest extends PHPUnit\Framework\TestCase $_POST["param1"]="333"; $_GET["param2"]='a/b#e(pr)qq-rr\cc'; $_GET["param3"]='"na/b#e(pr)qq-rr\cc'; // Same than param2 + " and n - $_GET["param4"]='../dir'; + $_GET["param4a"]='../../dir'; + $_GET["param4b"]='..\..\dirwindows'; $_GET["param5"]="a_1-b"; $_POST["param6"]="">assertEquals($result, 'na/b#e(pr)qq-rr\cc', 'Test on param3'); - $result=GETPOST("param4", 'alpha'); // Must return string sanitized from ../ + $result=GETPOST("param4a", 'alpha'); // Must return string sanitized from ../ print __METHOD__." result=".$result."\n"; $this->assertEquals($result, 'dir'); + $result=GETPOST("param4b", 'alpha'); // Must return string sanitized from ../ + print __METHOD__." result=".$result."\n"; + $this->assertEquals($result, 'dirwindows'); + // Test with aZ09 $result=GETPOST("param1", 'aZ09'); @@ -412,7 +417,11 @@ class SecurityTest extends PHPUnit\Framework\TestCase print __METHOD__." result=".$result."\n"; $this->assertEquals($result, ''); - $result=GETPOST("param4", 'aZ09'); // Must return '' as string contains car not in aZ09 definition + $result=GETPOST("param4a", 'aZ09'); // Must return '' as string contains car not in aZ09 definition + print __METHOD__." result=".$result."\n"; + $this->assertEquals('', $result); + + $result=GETPOST("param4b", 'aZ09'); // Must return '' as string contains car not in aZ09 definition print __METHOD__." result=".$result."\n"; $this->assertEquals('', $result);