diff --git a/.gitattributes b/.gitattributes index d1002263778..de9ce3303a9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,12 +11,14 @@ *.htm text eol=lf *.html text eol=lf *.js text eol=lf +*.json text eol=lf *.css text eol=lf *.lang text eol=lf *.txt text eol=lf *.md text eol=lf *.pp text eol=lf *.sh text eol=lf +*.yml text eol=lf *.yaml text eol=lf *.conf text eol=lf @@ -24,15 +26,16 @@ # Denote all files that are truly binary and should not be modified. *.bmp binary -*.ico binary -*.png binary -*.jpg binary -*.jpeg binary -*.odt binary -*.odf binary *.frm binary +*.ico binary +*.jpeg binary +*.jpg binary *.MYD binary *.MYI binary +*.odf binary +*.odt binary +*.png binary + # Export ignores to generate clean production tarballs /build export-ignore diff --git a/COPYRIGHT b/COPYRIGHT index 21e37f39f1d..b133b05b2cf 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -23,7 +23,7 @@ PEAR Mail_MIME 1.8.9 BSD Yes ParseDown 1.6 MIT License Yes Markdown parser PCLZip 2.8.4 LGPL-3+ Yes Library to zip/unzip files PHPDebugBar 1.15.1 MIT License Yes Used only by the module "debugbar" for developers -PHPSpreadSheet ? LGPL-2.1+ Yes Read/Write XLS files, read ODS files +PHPSpreadSheet 1.8.2 LGPL-2.1+ Yes Read/Write XLS files, read ODS files php-iban 1.4.7 LGPL-3+ Yes Parse and validate IBAN (and IIBAN) bank account information in PHP PHPoAuthLib 0.8.2 MIT License Yes Library to provide oauth1 and oauth2 to different service PHPPrintIPP 1.3 GPL-2+ Yes Library to send print IPP requests diff --git a/composer.json b/composer.json index f9d06530c9a..130fda34945 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "ckeditor/ckeditor" : "4.12.1", "mike42/escpos-php" : "2.2", "mobiledetect/mobiledetectlib" : "2.8.34", + "phpoffice/phpexcel" : "1.8.2", "restler/framework" : "3.0.0-RC6", "tecnickcom/tcpdf" : "6.3.2", "nnnick/chartjs" : "^2.9", diff --git a/composer.lock b/composer.lock index c588bc7783f..3e867f8f186 100644 --- a/composer.lock +++ b/composer.lock @@ -328,6 +328,63 @@ }, "time": "2020-03-23T09:12:05+00:00" }, + { + "name": "phpoffice/phpexcel", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PHPExcel.git", + "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/1441011fb7ecdd8cc689878f54f8b58a6805f870", + "reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "php": "^5.2|^7.0" + }, + "require-dev": { + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "autoload": { + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "http://blog.maartenballiauw.be" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Franck Lefevre", + "homepage": "http://rootslabs.net" + }, + { + "name": "Mark Baker", + "homepage": "http://markbakeruk.net" + } + ], + "description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PHPExcel", + "keywords": [ + "OpenXML", + "excel", + "xlsx" + ], + "abandoned": "phpoffice/phpspreadsheet", + "time": "2018-11-22T23:07:24+00:00" + }, { "name": "restler/framework", "version": "3.0.0-RC6", diff --git a/dev/setup/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf b/dev/setup/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf new file mode 100644 index 00000000000..d5922909ba9 --- /dev/null +++ b/dev/setup/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf @@ -0,0 +1,20 @@ +# Fail2Ban configuration file +# +# Regexp to catch known spambots and software alike. Please verify +# that it is your intent to block IPs which were driven by +# above mentioned bots. + + +[Definition] + +# To test, you can inject this example into log +# echo `date +'%Y-%m-%d %H:%M:%S'`" INFO 1.2.3.4 functions_dolibarr::check_user_password_abcd Authentication KO" >> /mypath/documents/dolibarr.log +# +# then +# fail2ban-client status web-dol-bruteforce +# +# To test rule file on a existing log file +# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf + +failregex = ^ [A-Z\s]+ \s+functions_dolibarr::check_user_password_.* Authentication KO +ignoreregex = diff --git a/dev/setup/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf b/dev/setup/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf new file mode 100644 index 00000000000..edc2ca68092 --- /dev/null +++ b/dev/setup/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf @@ -0,0 +1,20 @@ +# Fail2Ban configuration file +# +# Regexp to catch known spambots and software alike. Please verify +# that it is your intent to block IPs which were driven by +# above mentioned bots. + + +[Definition] + +# To test, you can inject this example into log +# echo `date +'%Y-%m-%d %H:%M:%S'`" INFO 1.2.3.4 --- Access to GET /passwordforgotten.php - action=buildnewpassword, massaction=" >> /mypath/documents/dolibarr.log +# +# then +# fail2ban-client status web-dol-passforgotten +# +# To test rule file on a existing log file +# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf + +failregex = ^ [A-Z\s]+ \s+--- Access to .*/passwordforgotten.php - action=buildnewpassword +ignoreregex = diff --git a/dev/setup/fail2ban/jail.local b/dev/setup/fail2ban/jail.local new file mode 100644 index 00000000000..bd506e20812 --- /dev/null +++ b/dev/setup/fail2ban/jail.local @@ -0,0 +1,28 @@ +# +# Examle of rule you can add to fail2ban to restrict bruteforce attacks. +# + +[web-dol-passforgotten] + +; rule against call of passwordforgottenpage +enabled = true +port = http,https +filter = web-dolibarr-rulespassforgotten +logpath = >> /mypath/documents/documents/dolibarr.log +action = %(action_mw)s +bantime = 4320000 ; 50 days +findtime = 86400 ; 1 day +maxretry = 10 + +[web-dol-bruteforce] + +; rule against bruteforce hacking (login + api) +enabled = true +port = http,https +filter = web-dolibarr-rulesbruteforce +logpath = >> /mypath/documents/documents/dolibarr.log +action = %(action_mw)s +bantime = 86400 ; 1 day +findtime = 3600 ; 1 hour +maxretry = 10 + diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index e7c5d106ddf..6220904dbe8 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -200,7 +200,7 @@ class BookKeeping extends CommonObject $error = 0; - // Clean parameters + // Clean parameters if (isset($this->doc_type)) { $this->doc_type = trim($this->doc_type); } @@ -296,7 +296,7 @@ class BookKeeping extends CommonObject $sql .= " WHERE doc_type = '".$this->db->escape($this->doc_type)."'"; $sql .= " AND fk_doc = ".$this->fk_doc; if (!empty($conf->global->ACCOUNTANCY_ENABLE_FKDOCDET)) { - // DO NOT USE THIS IN PRPDUCTION. This will generate a lot of trouble into reports and will corrupt database (by generating duplicate entries. + // DO NOT USE THIS IN PRPDUCTION. This will generate a lot of trouble into reports and will corrupt database (by generating duplicate entries. $sql .= " AND fk_docdet = " . $this->fk_docdet; // This field can be 0 if record is for several lines } $sql .= " AND numero_compte = '".$this->db->escape($this->numero_compte)."'"; diff --git a/htdocs/adherents/admin/member.php b/htdocs/adherents/admin/member.php index 3d40f8d758b..03f161e6926 100644 --- a/htdocs/adherents/admin/member.php +++ b/htdocs/adherents/admin/member.php @@ -8,7 +8,8 @@ * Copyright (C) 2011-2012 Juanjo Menent * Copyright (C) 2012 J. Fernando Lagrange * Copyright (C) 2015 Jean-François Ferry - * Copyright (C) 2020-2021 Frédéric France + * Copyright (C) 2020-2021 Frédéric France + * Copyright (C) 2021 Waël Almoman * * 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 @@ -33,6 +34,7 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/member.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php'; // Load translation files required by the page $langs->loadLangs(array("admin", "members")); @@ -101,11 +103,12 @@ if ($action == 'set_default') { } } elseif ($action == 'updateall') { $db->begin(); - $res1 = $res2 = $res3 = $res4 = $res5 = $res6 = 0; + $res1 = $res2 = $res3 = $res4 = $res5 = $res6 = $res7 = 0; $res1 = dolibarr_set_const($db, 'ADHERENT_LOGIN_NOT_REQUIRED', GETPOST('ADHERENT_LOGIN_NOT_REQUIRED', 'alpha') ? 0 : 1, 'chaine', 0, '', $conf->entity); $res2 = dolibarr_set_const($db, 'ADHERENT_MAIL_REQUIRED', GETPOST('ADHERENT_MAIL_REQUIRED', 'alpha'), 'chaine', 0, '', $conf->entity); $res3 = dolibarr_set_const($db, 'ADHERENT_DEFAULT_SENDINFOBYMAIL', GETPOST('ADHERENT_DEFAULT_SENDINFOBYMAIL', 'alpha'), 'chaine', 0, '', $conf->entity); $res4 = dolibarr_set_const($db, 'ADHERENT_BANK_USE', GETPOST('ADHERENT_BANK_USE', 'alpha'), 'chaine', 0, '', $conf->entity); + $res7 = dolibarr_set_const($db, "MEMBER_SUBSCRIPTION_AMOUNT_BY_TYPE", json_encode(GETPOST('MEMBER_SUBSCRIPTION_AMOUNT_BY_TYPE')), 'array', 0, '', $conf->entity); // Use vat for invoice creation if ($conf->facture->enabled) { $res4 = dolibarr_set_const($db, 'ADHERENT_VAT_FOR_SUBSCRIPTIONS', GETPOST('ADHERENT_VAT_FOR_SUBSCRIPTIONS', 'alpha'), 'chaine', 0, '', $conf->entity); @@ -217,6 +220,18 @@ print ''.$langs->trans("MemberSendInformationByMailByDef print $form->selectyesno('ADHERENT_DEFAULT_SENDINFOBYMAIL', (!empty($conf->global->ADHERENT_DEFAULT_SENDINFOBYMAIL) ? $conf->global->ADHERENT_DEFAULT_SENDINFOBYMAIL : 0), 1); print "\n"; + +// Amount by member type +$adht = new AdherentType($db); +$amountbytype = empty($conf->global->MEMBER_SUBSCRIPTION_AMOUNT_BY_TYPE) ? -1 : json_decode($conf->global->MEMBER_SUBSCRIPTION_AMOUNT_BY_TYPE, true); +print ''.$langs->trans("DefineAmountMemberType").''; +foreach ($adht->liste_array(1) as $typeid => $type) { + print $type .' : '; + print ''; + print '
'; +} +print "\n"; + // Insert subscription into bank account print ''.$langs->trans("MoreActionsOnSubscription").''; $arraychoices = array('0'=>$langs->trans("None")); diff --git a/htdocs/adherents/admin/website.php b/htdocs/adherents/admin/website.php index d4f2df25c0c..8b32e79526d 100644 --- a/htdocs/adherents/admin/website.php +++ b/htdocs/adherents/admin/website.php @@ -177,7 +177,7 @@ if (!empty($conf->global->MEMBER_ENABLE_PUBLIC)) { print $langs->trans("ForceMemberType"); print ''; $listofval = array(); - $listofval += $adht->liste_array(); + $listofval += $adht->liste_array(1); $forcetype = empty($conf->global->MEMBER_NEWFORM_FORCETYPE) ? -1 : $conf->global->MEMBER_NEWFORM_FORCETYPE; print $form->selectarray("MEMBER_NEWFORM_FORCETYPE", $listofval, $forcetype, count($listofval) > 1 ? 1 : 0); print "\n"; diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index 79fef823883..0299b32663c 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -13,7 +13,7 @@ * Copyright (C) 2018-2019 Thibault FOUCART * Copyright (C) 2019 Nicolas ZABOURI * Copyright (C) 2020 Josep Lluís Amador - * Copyright (C) 2021 Waël Almoman + * Copyright (C) 2021 Waël Almoman * * 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 @@ -1490,9 +1490,10 @@ class Adherent extends CommonObject * @param string $emetteur_nom Name of cheque writer * @param string $emetteur_banque Name of bank of cheque * @param int $datesubend Date end subscription + * @param int $fk_type Member type id * @return int rowid of record added, <0 if KO */ - public function subscription($date, $amount, $accountid = 0, $operation = '', $label = '', $num_chq = '', $emetteur_nom = '', $emetteur_banque = '', $datesubend = 0) + public function subscription($date, $amount, $accountid = 0, $operation = '', $label = '', $num_chq = '', $emetteur_nom = '', $emetteur_banque = '', $datesubend = 0, $fk_type = null) { global $conf, $langs, $user; @@ -1523,6 +1524,7 @@ class Adherent extends CommonObject $subscription->amount = $amount; $subscription->note = $label; // deprecated $subscription->note_public = $label; + $subscription->fk_type = $fk_type; $rowid = $subscription->create($user); if ($rowid > 0) { diff --git a/htdocs/admin/eventorganization.php b/htdocs/admin/eventorganization.php index e142acedf8f..c1d0fe61e67 100644 --- a/htdocs/admin/eventorganization.php +++ b/htdocs/admin/eventorganization.php @@ -60,6 +60,7 @@ $arrayofparameters = array( 'EVENTORGANIZATION_TEMPLATE_EMAIL_AFT_SUBS_EVENT'=>array('type'=>'emailtemplate:eventorganization_send', 'enabled'=>1), 'EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_SPEAKER'=>array('type'=>'emailtemplate:eventorganization_send', 'enabled'=>1), 'EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_ATTENDES'=>array('type'=>'emailtemplate:eventorganization_send', 'enabled'=>1), + 'EVENTORGANIZATION_SECUREKEY'=>array('type'=>'securekey', 'enabled'=>1), ); $error = 0; @@ -74,6 +75,7 @@ if ((float) DOL_VERSION >= 6) { include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; } + if ($action == 'updateMask') { $maskconstorder = GETPOST('maskconstorder', 'alpha'); $maskorder = GETPOST('maskorder', 'alpha'); @@ -196,7 +198,6 @@ print dol_get_fiche_head($head, 'settings', $langs->trans($page_name), -1, 'even // Setup page goes here echo ''.$langs->trans("EventOrganizationSetupPage").'

'; - if ($action == 'edit') { print '
'; print ''; @@ -206,12 +207,12 @@ if ($action == 'edit') { print ''.$langs->trans("Parameter").''.$langs->trans("Value").''; foreach ($arrayofparameters as $constname => $val) { - if ($val['enabled']==1) { - $setupnotempty++; - print ''; - $tooltiphelp = (($langs->trans($constname . 'Tooltip') != $constname . 'Tooltip') ? $langs->trans($constname . 'Tooltip') : ''); - print ''.$form->textwithpicto($langs->trans($constname), $tooltiphelp, 1, 'info', '', 0, 3, 'tootips'.$constname).''; - print ''; + if ($val['enabled']==1) { + $setupnotempty++; + print ''; + $tooltiphelp = (($langs->trans($constname . 'Tooltip') != $constname . 'Tooltip') ? $langs->trans($constname . 'Tooltip') : ''); + print ''.$form->textwithpicto($langs->trans($constname), $tooltiphelp, 1, 'info', '', 0, 3, 'tootips'.$constname).''; + print ''; if ($val['type'] == 'textarea') { print ''; + + /*print '
'.$langs->trans("or").'
'; print '
'; - print 'Scan a product lot or serial number
'; print '     Qty
'; - + */ print '
'; + print '
'; + print '
'; + print ''.$langs->trans("FeatureNotYetAvailable").''; // TODO Add javascript so each scan will add qty into the inventory page + an ajax save. + print '
'; print ''; + print '
'; } @@ -603,13 +615,13 @@ if ($object->id > 0) { print ''; } - print ''; + print ''; print $obj->qty_stock; print ''; print ''; if ($object->status == $object::STATUS_VALIDATED) { $qty_view = GETPOST("id_".$obj->rowid) ? GETPOST("id_".$obj->rowid) : $obj->qty_view; - print ''; + print ''; print ''; print ''; print ''.img_delete().''; diff --git a/htdocs/projet/ajax/index.html b/htdocs/projet/ajax/index.html new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/htdocs/projet/ajax/index.html @@ -0,0 +1 @@ + diff --git a/htdocs/projet/class/api_projects.class.php b/htdocs/projet/class/api_projects.class.php index 47536986a80..6a08aa7a4bd 100644 --- a/htdocs/projet/class/api_projects.class.php +++ b/htdocs/projet/class/api_projects.class.php @@ -103,6 +103,10 @@ class Projects extends DolibarrApi { global $db, $conf; + if (!DolibarrApiAccess::$user->rights->projet->lire) { + throw new RestException(401); + } + $obj_ret = array(); // case of external user, $thirdparty_ids param is ignored and replaced by user's socid diff --git a/htdocs/projet/class/api_tasks.class.php b/htdocs/projet/class/api_tasks.class.php index 748d9ce2594..cd6df68d590 100644 --- a/htdocs/projet/class/api_tasks.class.php +++ b/htdocs/projet/class/api_tasks.class.php @@ -109,6 +109,10 @@ class Tasks extends DolibarrApi { global $db, $conf; + if (!DolibarrApiAccess::$user->rights->projet->lire) { + throw new RestException(401); + } + $obj_ret = array(); // case of external user, $thirdparty_ids param is ignored and replaced by user's socid diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index d8c25bbebbb..e6b7a3e7a38 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -218,7 +218,7 @@ if (empty($reshook) && $action == 'add') { $error++; $errmsg .= $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Lastname"))."
\n"; } - if (GETPOST("firstname")) { + if (!GETPOST("firstname")) { $error++; $errmsg .= $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Firstname"))."
\n"; } diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index 486223b0293..8931ce1ceed 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -4,6 +4,7 @@ * Copyright (C) 2009-2012 Regis Houssin * Copyright (C) 2018 Juanjo Menent * Copyright (C) 2018-2019 Thibault FOUCART + * Copyright (C) 2021 Waël Almoman * * 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 @@ -1438,6 +1439,39 @@ if ($source == 'membersubscription') { } } + if ($member->type) { + // Last member type + print ''.$langs->trans("LastMemberType"); + print ''.dol_escape_htmltag($member->type); + print "\n"; + } + + if (!empty($conf->global->MEMBER_SUBSCRIPTION_AMOUNT_BY_TYPE)) { + // Amount by member type + $amountbytype = json_decode($conf->global->MEMBER_SUBSCRIPTION_AMOUNT_BY_TYPE, true); + // Set the member type + $member->typeid = (int) (GETPOSTISSET("typeid") ? GETPOST("typeid", 'int') : $member->typeid); + // If we change the type of membership, we set also label of new type + $member->type = dol_getIdFromCode($db, $member->typeid, 'adherent_type', 'rowid', 'libelle'); + // Set amount for the subscription + $amount = $amountbytype[$member->typeid] ? $amountbytype[$member->typeid] : $member->last_subscription_amount; + // list member type + require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php'; + $adht = new AdherentType($db); + if ( !$action) { + $form = new Form($db); // so wecan call method selectarray + print ''.$langs->trans("NewSubscription"); + print ''; + print $form->selectarray("typeid", $adht->liste_array(1), $member->typeid, 0, 0, 0, 'onchange="window.location.replace(\''.$urlwithroot.'/public/payment/newpayment.php?source='.$source.'&ref='.$ref.'&amount='.$amount.'&typeid=\' + this.value + \'&securekey='.$SECUREKEY.'\');"', 0, 0, 0, '', '', 1); + print "\n"; + } elseif ($action == dopayment) { + print ''.$langs->trans("NewMemberType"); + print ''.dol_escape_htmltag($member->type); + print ''; + print "\n"; + } + } + // Amount print ''.$langs->trans("Amount"); if (empty($amount)) { diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index 99a97e0c321..1942635001f 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -2,6 +2,7 @@ /* Copyright (C) 2001-2002 Rodolphe Quiedeville * Copyright (C) 2006-2013 Laurent Destailleur * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2021 Waël Almoman * * 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 @@ -98,10 +99,11 @@ $FULLTAG = GETPOST('FULLTAG'); if (empty($FULLTAG)) { $FULLTAG = GETPOST('fulltag'); } -$source = GETPOST('s', 'alpha') ?GETPOST('s', 'alpha') : GETPOST('source', 'alpha'); +$source = GETPOST('s', 'alpha') ? GETPOST('s', 'alpha') : GETPOST('source', 'alpha'); $ref = GETPOST('ref'); $suffix = GETPOST("suffix", 'aZ09'); +$membertypeid = GETPOST("membertypeid", 'int'); // Detect $paymentmethod @@ -339,7 +341,8 @@ if ($ispaymentok) { $user->rights->facture = new stdClass(); } if (empty($user->rights->adherent)) { - $user->rights->adherent = new stdClass(); $user->rights->adherent->cotisation = new stdClass(); + $user->rights->adherent = new stdClass(); + $user->rights->adherent->cotisation = new stdClass(); } $user->rights->societe->creer = 1; $user->rights->facture->creer = 1; @@ -460,7 +463,7 @@ if ($ispaymentok) { if (!$error) { dol_syslog("Call ->subscription to create subscription", LOG_DEBUG, 0, '_payment'); - $crowid = $object->subscription($datesubscription, $amount, $accountid, $operation, $label, $num_chq, $emetteur_nom, $emetteur_banque, $datesubend); + $crowid = $object->subscription($datesubscription, $amount, $accountid, $operation, $label, $num_chq, $emetteur_nom, $emetteur_banque, $datesubend, $membertypeid); if ($crowid <= 0) { $error++; $errmsg = $object->error; diff --git a/htdocs/societe/class/api_contacts.class.php b/htdocs/societe/class/api_contacts.class.php index 3993ad38e5f..5a6513ef6e5 100644 --- a/htdocs/societe/class/api_contacts.class.php +++ b/htdocs/societe/class/api_contacts.class.php @@ -74,6 +74,7 @@ class Contacts extends DolibarrApi if (!DolibarrApiAccess::$user->rights->societe->contact->lire) { throw new RestException(401, 'No permission to read contacts'); } + if ($id == 0) { $result = $this->contact->initAsSpecimen(); } else { @@ -117,6 +118,7 @@ class Contacts extends DolibarrApi if (!DolibarrApiAccess::$user->rights->societe->contact->lire) { throw new RestException(401, 'No permission to read contacts'); } + if (empty($email)) { $result = $this->contact->initAsSpecimen(); } else { diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index f5eae0be948..b0b486459b1 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -132,6 +132,10 @@ class Thirdparties extends DolibarrApi { $obj_ret = array(); + if (!DolibarrApiAccess::$user->rights->societe->lire) { + throw new RestException(401); + } + // case of external user, we force socids $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : ''; @@ -1842,9 +1846,11 @@ class Thirdparties extends DolibarrApi private function _fetch($rowid, $ref = '', $ref_ext = '', $barcode = '', $idprof1 = '', $idprof2 = '', $idprof3 = '', $idprof4 = '', $idprof5 = '', $idprof6 = '', $email = '', $ref_alias = '') { global $conf; + if (!DolibarrApiAccess::$user->rights->societe->lire) { throw new RestException(401); } + if ($rowid === 0) { $result = $this->company->initAsSpecimen(); } else { diff --git a/htdocs/supplier_proposal/class/api_supplier_proposals.class.php b/htdocs/supplier_proposal/class/api_supplier_proposals.class.php index 1368cce7811..3e38ac10b41 100644 --- a/htdocs/supplier_proposal/class/api_supplier_proposals.class.php +++ b/htdocs/supplier_proposal/class/api_supplier_proposals.class.php @@ -98,6 +98,10 @@ class Supplierproposals extends DolibarrApi { global $db, $conf; + if (!DolibarrApiAccess::$user->rights->supplier_proposal->lire) { + throw new RestException(401); + } + $obj_ret = array(); // case of external user, $thirdparty_ids param is ignored and replaced by user's socid diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index dc9fa7b6047..4cf7bc0de34 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -987,7 +987,7 @@ div.div-for-modal { div.div-for-modal-topright { /* display: none; */ - position:absolute; + position: fixed; top: 0; right: 0; width:50%; /* adjust as per your needs */ diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index c5cd7da18c7..e807ae62234 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1072,7 +1072,7 @@ div.div-for-modal { div.div-for-modal-topright { /* display: none; */ - position:absolute; + position: fixed; top: 0; right: 0; width:50%; /* adjust as per your needs */ diff --git a/htdocs/ticket/class/api_tickets.class.php b/htdocs/ticket/class/api_tickets.class.php index d8e36933ea6..f814beb3398 100644 --- a/htdocs/ticket/class/api_tickets.class.php +++ b/htdocs/ticket/class/api_tickets.class.php @@ -232,6 +232,10 @@ class Tickets extends DolibarrApi { global $db, $conf; + if (!DolibarrApiAccess::$user->rights->ticket->read) { + throw new RestException(403); + } + $obj_ret = array(); if (!$socid && DolibarrApiAccess::$user->socid) { diff --git a/htdocs/user/class/api_users.class.php b/htdocs/user/class/api_users.class.php index 803b517a354..e29506db93b 100644 --- a/htdocs/user/class/api_users.class.php +++ b/htdocs/user/class/api_users.class.php @@ -30,7 +30,6 @@ require_once DOL_DOCUMENT_ROOT.'/user/class/usergroup.class.php'; class Users extends DolibarrApi { /** - * * @var array $FIELDS Mandatory fields, checked when create and update object */ static $FIELDS = array( @@ -71,12 +70,12 @@ class Users extends DolibarrApi { global $db, $conf; - $obj_ret = array(); - if (!DolibarrApiAccess::$user->rights->user->user->lire) { throw new RestException(401, "You are not allowed to read list of users"); } + $obj_ret = array(); + // case of external user, $societe param is ignored and replaced by user's socid //$socid = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $societe; @@ -150,9 +149,10 @@ class Users extends DolibarrApi */ public function get($id, $includepermissions = 0) { - //if (!DolibarrApiAccess::$user->rights->user->user->lire) { - //throw new RestException(401); - //} + if (empty(DolibarrApiAccess::$user->rights->user->user->lire)) { + throw new RestException(401, 'Not allowed'); + } + if ($id == 0) { $result = $this->useraccount->initAsSpecimen(); } else { @@ -187,9 +187,9 @@ class Users extends DolibarrApi */ public function getByLogin($login, $includepermissions = 0) { - //if (!DolibarrApiAccess::$user->rights->user->user->lire) { - //throw new RestException(401); - //} + if (empty(DolibarrApiAccess::$user->rights->user->user->lire)) { + throw new RestException(401, 'Not allowed'); + } $result = $this->useraccount->fetch('', $login); if (!$result) { @@ -221,9 +221,9 @@ class Users extends DolibarrApi */ public function getByEmail($email, $includepermissions = 0) { - //if (!DolibarrApiAccess::$user->rights->user->user->lire) { - //throw new RestException(401); - //} + if (empty(DolibarrApiAccess::$user->rights->user->user->lire)) { + throw new RestException(401, 'Not allowed'); + } $result = $this->useraccount->fetch('', '', '', 0, -1, $email); if (!$result) { @@ -242,18 +242,22 @@ class Users extends DolibarrApi } /** - * Get properties of user connected + * Get more properties of a user * * @url GET /info * - * @param int $includepermissions Set this to 1 to have the array of permissions loaded (not done by default for performance purpose) - * @return array|mixed Data without useless information + * @param int $includepermissions Set this to 1 to have the array of permissions loaded (not done by default for performance purpose) + * @return array|mixed Data without useless information * * @throws RestException 401 Insufficient rights * @throws RestException 404 User or group not found */ public function getInfo($includepermissions = 0) { + if (empty(DolibarrApiAccess::$user->rights->user->user->lire)) { + throw new RestException(401, 'Not allowed'); + } + $apiUser = DolibarrApiAccess::$user; $result = $this->useraccount->fetch($apiUser->id); @@ -285,13 +289,16 @@ class Users extends DolibarrApi * * @param array $request_data New user data * @return int + * + * @throws RestException 401 Not allowed */ public function post($request_data = null) { - // check user authorization - //if(! DolibarrApiAccess::$user->rights->user->creer) { - // throw new RestException(401, "User creation not allowed"); - //} + // Check user authorization + if (empty(DolibarrApiAccess::$user->rights->user->user->creer)) { + throw new RestException(401, "User creation not allowed for login ".DolibarrApiAccess::$user->login); + } + // check mandatory fields /*if (!isset($request_data["login"])) throw new RestException(400, "login field missing"); @@ -299,9 +306,23 @@ class Users extends DolibarrApi throw new RestException(400, "password field missing"); if (!isset($request_data["lastname"])) throw new RestException(400, "lastname field missing");*/ + //assign field values foreach ($request_data as $field => $value) { - $this->useraccount->$field = $value; + if (in_array($field, array('pass_crypted', 'pass_indatabase', 'pass_indatabase_crypted', 'pass_temp', 'api_key'))) { + // This properties can't be set/modified with API + throw new RestException(401, 'The property '.$field." can't be set/modified using the APIs"); + continue; + } + /*if ($field == 'pass') { + if (empty(DolibarrApiAccess::$user->rights->user->user->password)) { + throw new RestException(401, 'You are not allowed to modify/set password of other users'); + continue; + } + } + */ + + $this->useraccount->$field = $value; } if ($this->useraccount->create(DolibarrApiAccess::$user) < 0) { @@ -312,7 +333,7 @@ class Users extends DolibarrApi /** - * Update account + * Update user account * * @param int $id Id of account to update * @param array $request_data Datas @@ -324,9 +345,10 @@ class Users extends DolibarrApi */ public function put($id, $request_data = null) { - //if (!DolibarrApiAccess::$user->rights->user->user->creer) { - //throw new RestException(401); - //} + // Check user authorization + if (empty(DolibarrApiAccess::$user->rights->user->creer)) { + throw new RestException(401, "User update not allowed"); + } $result = $this->useraccount->fetch($id); if (!$result) { @@ -341,6 +363,33 @@ class Users extends DolibarrApi if ($field == 'id') { continue; } + if (in_array($field, array('pass_crypted', 'pass_indatabase', 'pass_indatabase_crypted', 'pass_temp', 'api_key'))) { + // This properties can't be set/modified with API + throw new RestException(401, 'The property '.$field." can't be set/modified using the APIs"); + continue; + } + if ($field == 'pass') { + if ($this->useraccount->id != DolibarrApiAccess::$user->id && empty(DolibarrApiAccess::$user->rights->user->user->password)) { + throw new RestException(401, 'You are not allowed to modify password of other users'); + continue; + } + if ($this->useraccount->id == DolibarrApiAccess::$user->id && empty(DolibarrApiAccess::$user->rights->user->self->password)) { + throw new RestException(401, 'You are not allowed to modify your own password'); + continue; + } + } + if (DolibarrApiAccess::$user->admin) { // If user for API is admin + if ($field == 'admin' && $value != $this->useraccount->admin && empty($value)) { + throw new RestException(401, 'Reseting the admin status of a user is not possible using the API'); + } + } else { + if ($field == 'admin' && $value != $this->useraccount->admin) { + throw new RestException(401, 'Only an admin user can modify the admin status of another user'); + } + } + if ($field == 'entity' && $value != $this->useraccount->entity) { + throw new RestException(401, 'Changing entity of a user using the APIs is not possible'); + } // The status must be updated using setstatus() because it // is not handled by the update() method. if ($field == 'statut') { @@ -376,12 +425,12 @@ class Users extends DolibarrApi */ public function getGroups($id) { - $obj_ret = array(); - if (!DolibarrApiAccess::$user->rights->user->user->lire) { throw new RestException(403); } + $obj_ret = array(); + $user = new User($this->db); $result = $user->fetch($id); if (!$result) { @@ -406,16 +455,20 @@ class Users extends DolibarrApi * @param int $entity Entity ID (valid only for superadmin in multicompany transverse mode) * @return int 1 if success * + * @throws RestException 401 Not allowed + * @throws RestException 404 User not found + * @throws RestException 500 Error + * * @url GET {id}/setGroup/{group} */ public function setGroup($id, $group, $entity = 1) { - global $conf; - //if (!DolibarrApiAccess::$user->rights->user->user->supprimer) { - //throw new RestException(401); - //} + if (empty(DolibarrApiAccess::$user->rights->user->user->creer)) { + throw new RestException(401); + } + $result = $this->useraccount->fetch($id); if (!$result) { throw new RestException(404, 'User not found'); @@ -455,6 +508,9 @@ class Users extends DolibarrApi * @param string $group_ids Groups ids filter field. Example: '1' or '1,2,3' {@pattern /^[0-9,]*$/i} * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" * @return array Array of User objects + * + * @throws RestException 404 User not found + * @throws RestException 503 Error */ public function listGroups($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $group_ids = 0, $sqlfilters = '') { @@ -462,8 +518,9 @@ class Users extends DolibarrApi $obj_ret = array(); - if (!DolibarrApiAccess::$user->rights->user->group_advance->read) { - throw new RestException(401, "You are not allowed to read list of groups"); + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty(DolibarrApiAccess::$user->rights->user->user->lire)) || + !empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty(DolibarrApiAccess::$user->rights->user->group_advance->read)) { + throw new RestException(401, "You are not allowed to read groups"); } // case of external user, $societe param is ignored and replaced by user's socid @@ -527,12 +584,16 @@ class Users extends DolibarrApi * @param int $group ID of group * @param int $load_members Load members list or not {@min 0} {@max 1} * @return array Array of User objects + * + * @throws RestException 401 Not allowed + * @throws RestException 404 User not found */ public function infoGroups($group, $load_members = 0) { global $db, $conf; - if (!DolibarrApiAccess::$user->rights->user->group_advance->read) { + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty(DolibarrApiAccess::$user->rights->user->user->lire)) || + !empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty(DolibarrApiAccess::$user->rights->user->group_advance->read)) { throw new RestException(401, "You are not allowed to read groups"); } @@ -547,16 +608,19 @@ class Users extends DolibarrApi } /** - * Delete account + * Delete account/user * * @param int $id Account ID * @return array + * + * @throws RestException 401 Not allowed + * @throws RestException 404 User not found */ public function delete($id) { - //if (!DolibarrApiAccess::$user->rights->user->user->supprimer) { - //throw new RestException(401); - //} + if (empty(DolibarrApiAccess::$user->rights->user->user->supprimer)) { + throw new RestException(401, 'Not allowed'); + } $result = $this->useraccount->fetch($id); if (!$result) { throw new RestException(404, 'User not found'); diff --git a/htdocs/website/class/websitepage.class.php b/htdocs/website/class/websitepage.class.php index 32c8c0b8688..f22a5200148 100644 --- a/htdocs/website/class/websitepage.class.php +++ b/htdocs/website/class/websitepage.class.php @@ -426,7 +426,7 @@ class WebsitePage extends CommonObject } $listoflang[] = "'".$this->db->escape(substr(str_replace("'", '', $tmpvalue), 0, 2))."'"; } - $stringtouse = $key." IN (".$this->db->sanitize(join(',', $listoflang)).")"; + $stringtouse = $key." IN (".$this->db->sanitize(join(',', $listoflang), 1).")"; if ($foundnull) { $stringtouse = '('.$stringtouse.' OR '.$key.' IS NULL)'; } diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 26ca6df9bf8..1e1e4849bc9 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/website2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formwebsite.class.php'; @@ -680,7 +681,7 @@ if ($action == 'addcontainer' && $usercanedit) { } if (!$error) { - $tmp = getURLContent($urltograb); + $tmp = getURLContent($urltograb, 'GET', '', 1, array(), array('http', 'https'), 0); if ($tmp['curl_error_no']) { $error++; setEventMessages('Error getting '.$urltograb.': '.$tmp['curl_error_msg'], null, 'errors'); @@ -795,7 +796,7 @@ if ($action == 'addcontainer' && $usercanedit) { } /* - $tmpgeturl = getURLContent($urltograbbis); + $tmpgeturl = getURLContent($urltograbbis, 'GET', '', 1, array(), array('http', 'https'), 0); if ($tmpgeturl['curl_error_no']) { $error++; @@ -860,7 +861,7 @@ if ($action == 'addcontainer' && $usercanedit) { continue; } - $tmpgeturl = getURLContent($urltograbbis); + $tmpgeturl = getURLContent($urltograbbis, 'GET', '', 1, array(), array('http', 'https'), 0); if ($tmpgeturl['curl_error_no']) { $errorforsubresource++; setEventMessages('Error getting link tag url '.$urltograbbis.': '.$tmpgeturl['curl_error_msg'], null, 'errors'); @@ -1313,6 +1314,37 @@ if ($action == 'updatecss' && $usercanedit) { } } + if (!$error) { + if (($_FILES['addedfile']["name"] != '')) { + $uploadfolder = $conf->website->dir_output.'/'.$websitekey; + if ($_FILES['addedfile']['type'] != 'image/png') { + $error++; + setEventMessages($langs->trans('ErrorFaviconType'), array(), 'errors'); + } + $filetoread = realpath(dol_osencode($_FILES['addedfile']['tmp_name'])); + $filesize = getimagesize($filetoread); + if ($filesize[0] != 32 || $filesize[1] != 32) { + $error++; + setEventMessages($langs->trans('ErrorFaviconSize'), array(), 'errors'); + } + if (!$error) { + dol_add_file_process($uploadfolder, 1, 0, 'addedfile', 'favicon.png'); + } + } + if ($error) { + if (!GETPOSTISSET('updateandstay')) { // If we click on "Save And Stay", we don not make the redirect + $action = 'preview'; + if ($backtopage) { + $backtopage = preg_replace('/searchstring=[^&]*/', '', $backtopage); // Clean backtopage url + header("Location: ".$backtopage); + exit; + } + } else { + $action = 'editcss'; + } + } + } + if (!$error) { // Save master.inc.php file dol_syslog("Save master file ".$filemaster); @@ -2231,6 +2263,36 @@ if ($action == 'generatesitemaps' && $usercanedit) { $action = 'preview'; } +$imagefolder = $conf->website->dir_output.'/'.$websitekey.'/medias/image/'.$websitekey.'/'; + +if ($action == 'convertimgwebp' && $usercanedit) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; + + $regeximgext = getListOfPossibleImageExt(); + + $filelist = dol_dir_list($imagefolder, "all", 1, $regeximgext); + + foreach ($filelist as $filename) { + $filepath = $filename['fullname']; + if (!(substr_compare($filepath, 'webp', -strlen('webp')) === 0)) { + if (image_format_supported($filepath) == 1) { + $filepathnoext = preg_replace("/\..*/", "", $filepath); + $result = dol_imageResizeOrCrop($filepath, 0, 0, 0, 0, 0, $filepathnoext.'.webp'); + if (!dol_is_file($result)) { + $error++; + setEventMessages($result, null, 'errors'); + } + } + } + if ($error) { + break; + } + } + if (!$error) { + setEventMessages($langs->trans('SucessConvertImgWebp'), null); + } + $action = 'preview'; +} /* * View @@ -2246,7 +2308,10 @@ if ($action == 'confirmgeneratesitemaps') { $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?website='.$website->ref, $langs->trans('ConfirmSitemapsCreation'), $langs->trans('ConfirmGenerateSitemaps', $object->ref), 'generatesitemaps', '', "yes", 1); $action = 'preview'; } - +if ($action == 'confirmconvertimgwebp') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?website='.$website->ref, $langs->trans('ConfirmImgWebpCreation'), $langs->trans('ConfirmGenerateImgWebp', $object->ref), 'convertimgwebp', '', "yes", 1); + $action = 'preview'; +} $helpurl = 'EN:Module_Website|FR:Module_Website_FR|ES:Módulo_Website'; $arrayofjs = array( @@ -2465,6 +2530,7 @@ if (!GETPOST('hide_websitemenu')) { // Generate site map print 'ref.'" class="button bordertransp"'.$disabled.' title="'.dol_escape_htmltag($langs->trans("GenerateSitemaps")).'">'; + print 'ref.'" class="button bordertransp"'.$disabled.' title="'.dol_escape_htmltag($langs->trans("GenerateImgWebp")).'">'; print '   '; print 'ref.'" class="button bordertransp"'.$disabled.' title="'.dol_escape_htmltag($langs->trans("ReplaceWebsiteContent")).'">'; @@ -3118,6 +3184,13 @@ if ($action == 'editcss') { print ''; print ''; + // Favicon + print ''; + print $form->textwithpicto($langs->trans('ImportFavicon'), $langs->trans('FaviconTooltip')); + print ''; + print ''; + print ''; + // CSS file print ''; $htmlhelp = $langs->trans("CSSContentTooltipHelp"); diff --git a/htdocs/zapier/class/api_zapier.class.php b/htdocs/zapier/class/api_zapier.class.php index ebf62d115ab..c141588a7f9 100644 --- a/htdocs/zapier/class/api_zapier.class.php +++ b/htdocs/zapier/class/api_zapier.class.php @@ -104,6 +104,7 @@ class ZapierApi extends DolibarrApi if (!DolibarrApiAccess::$user->rights->zapier->read) { throw new RestException(401); } + $arraychoices = array( 'invoices' => 'Invoices', 'orders' => 'Orders', @@ -143,6 +144,10 @@ class ZapierApi extends DolibarrApi { global $db, $conf; + if (!DolibarrApiAccess::$user->rights->zapier->read) { + throw new RestException(401); + } + $obj_ret = array(); $socid = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : ''; @@ -242,6 +247,7 @@ class ZapierApi extends DolibarrApi if (!DolibarrApiAccess::$user->rights->zapier->write) { throw new RestException(401); } + // Check mandatory fields $fields = array( 'url', @@ -313,6 +319,7 @@ class ZapierApi extends DolibarrApi if (!DolibarrApiAccess::$user->rights->zapier->delete) { throw new RestException(401); } + $result = $this->hook->fetch($id); if (!$result) { throw new RestException(404, 'Hook not found');