Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur
2023-02-09 19:37:33 +01:00
54 changed files with 898 additions and 395 deletions

View File

@@ -240,7 +240,10 @@ Following changes may create regressions for some external modules, but were nec
* Deprecated method set_billed() on shipment and reception class has been removed. Use setBilled() instead.
* Tables llx_prelevement_facture and llx_prelevement_facture_demande have been renamed into llx_prelevement and llx_prelevement_demande.
* Rename MAIN_LIST_ALLOW_NOTES into MAIN_LIST_HIDE_NOTES and rename MAIN_LIST_ALLOW_PRIVATE_NOTES into MAIN_LIST_HIDE_PRIVATE_NOTES
* Rename the substitution for project label instead of project title in substitution variables
* Rename the substitution for "project label" instead of "project title" in substitution variables
* You must use "$objectoffield" to manipulate the current object inside the formulare of computed custom extrafields instead of $obj/$object.
* Making a global search is sending the parameter using always the name search_all (instead of sometimes sall and search_all)
***** ChangeLog for 16.0.4 compared to 16.0.3 *****

View File

@@ -58,7 +58,7 @@ if ($action == 'setMEMBER_ENABLE_PUBLIC') {
if ($action == 'update') {
$public = GETPOST('MEMBER_ENABLE_PUBLIC');
$amount = price2num(GETPOST('MEMBER_NEWFORM_AMOUNT'), 'MT', 2);
$editamount = GETPOST('MEMBER_NEWFORM_EDITAMOUNT');
$minamount = GETPOST('MEMBER_MIN_AMOUNT');
$publiccounters = GETPOST('MEMBER_COUNTERS_ARE_PUBLIC');
$payonline = GETPOST('MEMBER_NEWFORM_PAYONLINE');
$forcetype = GETPOST('MEMBER_NEWFORM_FORCETYPE', 'int');
@@ -66,7 +66,7 @@ if ($action == 'update') {
$res = dolibarr_set_const($db, "MEMBER_ENABLE_PUBLIC", $public, 'chaine', 0, '', $conf->entity);
$res = dolibarr_set_const($db, "MEMBER_NEWFORM_AMOUNT", $amount, 'chaine', 0, '', $conf->entity);
$res = dolibarr_set_const($db, "MEMBER_NEWFORM_EDITAMOUNT", $editamount, 'chaine', 0, '', $conf->entity);
$res = dolibarr_set_const($db, "MEMBER_MIN_AMOUNT", $minamount, 'chaine', 0, '', $conf->entity);
$res = dolibarr_set_const($db, "MEMBER_COUNTERS_ARE_PUBLIC", $publiccounters, 'chaine', 0, '', $conf->entity);
$res = dolibarr_set_const($db, "MEMBER_NEWFORM_PAYONLINE", $payonline, 'chaine', 0, '', $conf->entity);
if ($forcetype < 0) {
@@ -232,11 +232,11 @@ if (!empty($conf->global->MEMBER_ENABLE_PUBLIC)) {
print '<input type="text" class="right width50" id="MEMBER_NEWFORM_AMOUNT" name="MEMBER_NEWFORM_AMOUNT" value="'.(!empty($conf->global->MEMBER_NEWFORM_AMOUNT) ? $conf->global->MEMBER_NEWFORM_AMOUNT : '').'">';
print "</td></tr>\n";
// Can edit
// Min amount
print '<tr class="oddeven" id="tredit"><td>';
print $langs->trans("CanEditAmountDetail");
print $langs->trans("MinimumAmount");
print '</td><td>';
print $form->selectyesno("MEMBER_NEWFORM_EDITAMOUNT", (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT) ? $conf->global->MEMBER_NEWFORM_EDITAMOUNT : 0), 1);
print '<input type="text" class="right width50" id="MEMBER_MIN_AMOUNT" name="MEMBER_MIN_AMOUNT" value="'.(!empty($conf->global->MEMBER_MIN_AMOUNT) ? $conf->global->MEMBER_MIN_AMOUNT : '').'">';
print "</td></tr>\n";
// SHow counter of validated members publicly

View File

@@ -37,7 +37,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
// Load translation files required by the page
$langs->loadLangs(array("members", "companies"));
$langs->loadLangs(array("members", "companies", "categories"));
// Get parameters

View File

@@ -107,6 +107,7 @@ $permissiondellink = $user->admin; // Used by the include of actions_dellink.inc
$permissiontoadd = $user->admin; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
$debuginfo = '';
$error = 0;
/*
@@ -121,8 +122,6 @@ if ($reshook < 0) {
}
if (empty($reshook)) {
$error = 0;
$permissiontoadd = 1;
$permissiontodelete = 1;
if (empty($backtopage)) {
@@ -397,14 +396,12 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
$connectstringsource = '';
$connectstringtarget = '';
if (function_exists('imap_open')) {
// Note: $object->host has been loaded by the fetch
$usessl = 1;
$connectstringserver = $object->getConnectStringIMAP($usessl);
if ($action == 'scan') {
$nbemail = '';
if (!empty($conf->global->MAIN_IMAP_USE_PHPIMAP)) {
if ($object->acces_type == 1) {
// Mode OAUth2 with PHP-IMAP
@@ -424,10 +421,13 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
//$debugtext = "Host: ".$this->host."<br>Port: ".$this->port."<br>Login: ".$this->login."<br>Password: ".$this->password."<br>access type: ".$this->acces_type."<br>oauth service: ".$this->oauth_service."<br>Max email per collect: ".$this->maxemailpercollect;
//dol_syslog($debugtext);
$storage = new DoliStorage($db, $conf);
$token = '';
$storage = new DoliStorage($db, $conf, $keyforprovider);
try {
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
$expire = true;
// Is token expired or will token expire in the next 30 seconds
// if (is_object($tokenobj)) {
@@ -442,11 +442,15 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
);
$serviceFactory = new \OAuth\ServiceFactory();
$oauthname = explode('-', $OAUTH_SERVICENAME);
// ex service is Google-Emails we need only the first part Google
$apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, array());
// We have to save the token because Google give it only once
$refreshtoken = $tokenobj->getRefreshToken();
//var_dump($tokenobj);
$tokenobj = $apiService->refreshAccessToken($tokenobj);
$tokenobj->setRefreshToken($refreshtoken);
$storage->storeAccessToken($OAUTH_SERVICENAME, $tokenobj);
}
@@ -454,11 +458,17 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
if (is_object($tokenobj)) {
$token = $tokenobj->getAccessToken();
} else {
$object->error = "Token not found";
return -1;
$error++;
$morehtml .= "Token not found";
}
} catch (Exception $e) {
print $e->getMessage();
$error++;
$morehtml .= $e->getMessage();
}
if (empty($object->login)) {
$error++;
$morehtml .= 'Error: Login is empty. Must be email owner when using MAIN_IMAP_USE_PHPIMAP and OAuth.';
}
$cm = new ClientManager();
@@ -486,15 +496,28 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
'authentication' => "login",
]);
}
if (!$error) {
try {
// To emulate the command connect, you can run
// openssl s_client -crlf -connect outlook.office365.com:993
// TAG1 AUTHENTICATE XOAUTH2 dXN...
// TO Get debug log, you can set protected $debug = true; in Protocol.php file
//
// A MS bug make this not working !
// See https://github.com/MicrosoftDocs/office-developer-exchange-docs/issues/100
// See github.com/MicrosoftDocs/office-developer-exchange-docs/issues/87
// See github.com/Webklex/php-imap/issues/81
$client->connect();
} catch (ConnectionFailedException $e) {
print $e->getMessage();
}
$f = $client->getFolders(false, $object->source_directory);
$nbemail = $f[0]->examine()["exists"];
$morehtml .= $nbemail;
} catch (ConnectionFailedException $e) {
$morehtml .= 'ConnectionFailedException '.$e->getMessage();
}
}
} else {
if (function_exists('imap_open')) {
try {
if ($sourcedir) {
//$connectstringsource = $connectstringserver.imap_utf7_encode($sourcedir);
@@ -521,37 +544,33 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
//dol_syslog("end imap_open connection=".var_export($connection, true));
} catch (Exception $e) {
print $e->getMessage();
$morehtml .= $e->getMessage();
}
if (!$connection) {
$nbemail .= 'Failed to open IMAP connection '.$connectstringsource;
$morehtml .= 'Failed to open IMAP connection '.$connectstringsource;
if (function_exists('imap_last_error')) {
$nbemail .= '<br>'.imap_last_error();
$morehtml .= '<br>'.imap_last_error();
}
dol_syslog("Error ".$morehtml, LOG_WARNING);
//var_dump(imap_errors())
} else {
dol_syslog("Imap connected. Now we call imap_num_msg()");
$nbemail .= imap_num_msg($connection);
$morehtml .= imap_num_msg($connection);
}
if ($connection) {
dol_syslog("Imap close");
imap_close($connection);
}
}
}
$morehtml .= $form->textwithpicto($langs->trans("NbOfEmailsInInbox"), 'connect string '.$connectstringserver).': ';
$morehtml .= ($nbemail != '' ? $nbemail : '?');
$morehtml .= ' &nbsp; <a class="flat paddingleft marginleftonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=scan&token='.newToken().'">'.img_picto('', 'refresh', 'class="paddingrightonly"').$langs->trans("Refresh").'</a>';
} else {
$morehtml .= $langs->trans("NbOfEmailsInInbox").': ';
$morehtml .= 'IMAP functions not available on your PHP. ';
}
}
}
$morehtml = $form->textwithpicto($langs->trans("NbOfEmailsInInbox"), 'connect string '.$connectstringserver).': '.($morehtml ? $morehtml : '?');
$morehtml .= '<a class="flat paddingleft marginleftonly" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=scan&token='.newToken().'">'.img_picto('', 'refresh', 'class="paddingrightonly"').$langs->trans("Refresh").'</a>';
dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref.'<div class="refidno">'.$morehtml.'</div>', '', 0, '', '', 0, '');
@@ -671,7 +690,6 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
$arrayoftypes = array(
'loadthirdparty' => $langs->trans('LoadThirdPartyFromName', $langs->transnoentities("ThirdPartyName")),
'loadandcreatethirdparty' => $langs->trans('LoadThirdPartyFromNameOrCreate', $langs->transnoentities("ThirdPartyName")),
'loadandcreatecontact' => $langs->trans('LoadContactFromEmailOrCreate', $langs->transnoentities("Email")),
'recordjoinpiece' => 'AttachJoinedDocumentsToObject',
'recordevent' => 'RecordEvent'
);

View File

@@ -273,25 +273,6 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
$parameters = array();
$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
$sql .= $hookmanager->resPrint;
/* If a group by is required
$sql.= " GROUP BY ";
foreach ($object->fields as $key => $val) {
$sql .= "t.".$db->escape($key).", ";
}
// Add fields from extrafields
if (!empty($extrafields->attributes[$object->table_element]['label'])) {
foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
$sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : '');
}
}
// Add where from hooks
$parameters=array();
$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook
$sql .= $hookmanager->resPrint;
$sql = preg_replace('/,\s*$/', '', $sql);
*/
// Count total nb of records
$nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
@@ -333,6 +314,22 @@ if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $
llxHeader('', $title, $help_url, '', 0, 0, $morejs, $morecss, '', '');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($title, $linkback, 'title_setup');
$head = array();
$h = 0;
$head[$h][0] = DOL_URL_ROOT."/admin/emailcollector_list.php";
$head[$h][1] = $langs->trans("Setup");
$head[$h][2] = 'common';
$h++;
print dol_get_fiche_head($head, 'common', '', -1);
$arrayofselected = is_array($toselect) ? $toselect : array();
$param = '';
@@ -388,11 +385,9 @@ print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', 'emailcollector_card.php?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd);
print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'email', 0, $newcardbutton.' '.$linkback, '', $limit, 0, 0, 1);
print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'email', 0, $newcardbutton, '', $limit, 0, 0, 1);
// Add code for pre mass action (confirmation or email presend form)
/*$topicmail="";
@@ -699,7 +694,22 @@ print '<td>'.$langs->trans("Parameter").'</td>';
print '<td></td>';
print "</tr>\n";
// Hide e-mail headers from collected messages
// MAIN_IMAP_USE_PHPIMAP: Enable use of the PHP Imap library
print '<tr class="oddeven"><td>';
//print $form->textwithpicto($langs->trans("MAIN_IMAP_USE_PHPIMAP"), $langs->transnoentitiesnoconv("MAIN_IMAP_USE_PHPIMAPDesc"));
print $langs->trans("MAIN_IMAP_USE_PHPIMAP");
print '</td>';
print '<td class="left">';
if ($conf->use_javascript_ajax) {
print ajax_constantonoff('MAIN_IMAP_USE_PHPIMAP');
} else {
$arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes"));
print $form->selectarray("MAIN_IMAP_USE_PHPIMAP", $arrval, $conf->global->MAIN_IMAP_USE_PHPIMAP);
}
print '</td>';
print '</tr>';
// MAIN_EMAILCOLLECTOR_MAIL_WITHOUT_HEADER: Hide e-mail headers from collected messages
print '<tr class="oddeven"><td>'.$form->textwithpicto($langs->trans("EmailCollectorHideMailHeaders"), $langs->transnoentitiesnoconv("EmailCollectorHideMailHeadersHelp")).'</td>';
print '<td class="left">';
if ($conf->use_javascript_ajax) {
@@ -738,6 +748,10 @@ if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $n
print $formfile->showdocuments('massfilesarea_emailcollector', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty);
}
dol_get_fiche_end();
// End of page
llxFooter();
$db->close();

View File

@@ -0,0 +1,137 @@
<?php
/* Copyright (C) 2007-2020 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2013 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2016 Jonathan TISSEAU <jonathan.tisseau@86dev.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/>.
*/
/**
* \file htdocs/admin/mails_ingoing.php
* \brief Page to setup emails entry
*/
// Load Dolibarr environment
require '../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
// Load translation files required by the page
$langs->loadLangs(array("companies", "products", "admin", "mails", "other", "errors"));
$action = GETPOST('action', 'aZ09');
$cancel = GETPOST('cancel', 'aZ09');
$trackid = GETPOST('trackid');
if (!$user->admin) {
accessforbidden();
}
/*
* Actions
*/
if ($action == 'update' && !$cancel) {
}
/*
* View
*/
$form = new Form($db);
$linuxlike = 1;
if (preg_match('/^win/i', PHP_OS)) {
$linuxlike = 0;
}
if (preg_match('/^mac/i', PHP_OS)) {
$linuxlike = 0;
}
//$wikihelp = 'EN:Setup_EMails|FR:Paramétrage_EMails|ES:Configuración_EMails';
$wikihelp = '';
llxHeader('', $langs->trans("Setup"), $wikihelp);
print load_fiche_titre($langs->trans("EMailsSetup"), '', 'title_setup');
$head = email_admin_prepare_head();
// List of sending methods
$listofmethods = array();
$listofmethods['mail'] = 'PHP mail function';
$listofmethods['smtps'] = 'SMTP/SMTPS socket library';
if (version_compare(phpversion(), '7.0', '>=')) {
$listofmethods['swiftmailer'] = 'Swift Mailer socket library';
}
// List of oauth services
$oauthservices = array();
foreach ($conf->global as $key => $val) {
if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) {
$key = preg_replace('/^OAUTH_/', '', $key);
$key = preg_replace('/_ID$/', '', $key);
if (preg_match('/^.*-/', $key)) {
$name = preg_replace('/^.*-/', '', $key);
} else {
$name = $langs->trans("NoName");
}
$provider = preg_replace('/-.*$/', '', $key);
$provider = ucfirst(strtolower($provider));
$oauthservices[$key] = $name." (".$provider.")";
}
}
print dol_get_fiche_head($head, 'common_ingoing', '', -1);
print '<br>';
print '<span class="opacitymedium">'.$langs->trans("EMailsInGoingDesc", $langs->transnoentitiesnoconv("EmailCollector"))."</span><br>\n";
print "<br><br>\n";
/*
print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><td class="titlefieldmiddle">'.$langs->trans("Parameter").'</td><td>'.$langs->trans("Value").'</td></tr>';
print '<br>';
print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
print '<table class="noborder centpercent">';
// SMTPS oauth service
if (in_array(getDolGlobalString('MAIN_MAIL_SENDMODE', 'mail'), array('smtps', 'swiftmailer')) && getDolGlobalString('MAIN_MAIL_SMTPS_AUTH_TYPE') === "XOAUTH2") {
$text = $oauthservices[$conf->global->MAIN_MAIL_SMTPS_OAUTH_SERVICE];
if (empty($text)) {
$text = $langs->trans("Undefined").img_warning();
}
print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_SMTPS_OAUTH_SERVICE").'</td><td>'.$text.'</td></tr>';
}
print '</table>';
print '</div>';
*/
print dol_get_fiche_end();
// End of page
llxFooter();
$db->close();

View File

@@ -1101,7 +1101,7 @@ if ($mode == 'marketplace') {
print '<div class="liste_titre liste_titre_bydiv centpercent"><div class="divsearchfield">';
print '<form method="POST" class="centpercent" id="searchFormList" action="'.urlencode($dolistore->url).'">';
print '<form method="POST" class="centpercent" id="searchFormList" action="'.$dolistore->url.'">';
?>
<input type="hidden" name="token" value="<?php echo newToken(); ?>">
<input type="hidden" name="mode" value="marketplace">

View File

@@ -95,6 +95,11 @@ if ($action == 'update') {
$error++;
}
}
if (GETPOSTISSET($constvalue.'_TENANT')) {
if (!dolibarr_set_const($db, $constvalue.'_TENANT', GETPOST($constvalue.'_TENANT'), 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
if (GETPOSTISSET($constvalue.'_SCOPE')) {
if (is_array(GETPOST($constvalue.'_SCOPE'))) {
$scopestring = implode(',', GETPOST($constvalue.'_SCOPE'));
@@ -171,6 +176,8 @@ if ($action == 'confirm_delete') {
$callbacktodel .= '/core/modules/oauth/stripelive_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
} elseif ($label == 'OAUTH_STRIPE_TEST') {
$callbacktodel .= '/core/modules/oauth/stripetest_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
} elseif ($label == 'OAUTH_MICROSOFT') {
$callbacktodel .= '/core/modules/oauth/microsoft_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
} elseif ($label == 'OAUTH_OTHER') {
$callbacktodel .= '/core/modules/oauth/generic_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
}
@@ -285,8 +292,10 @@ if (count($listinsetup) > 0) {
$keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
$keybeforeprovider = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
} else {
$keybeforeprovider = $keyforsupportedoauth2array;
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
@@ -385,6 +394,16 @@ if (count($listinsetup) > 0) {
print '<td></td>';
print '</tr>';
// Tenant
if ($keybeforeprovider == 'MICROSOFT') {
print '<tr class="oddeven value">';
print '<td><label for="'.$key[2].'">'.$langs->trans("OAUTH_TENANT").'</label></td>';
print '<td><input type="text" size="100" id="OAUTH_'.$keybeforeprovider.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT" name="OAUTH_'.$keybeforeprovider.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT" value="'.getDolGlobalString('OAUTH_'.$keybeforeprovider.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT').'">';
print '</td>';
print '<td></td>';
print '</tr>';
}
// TODO Move this into token generation ?
if ($supported) {
if ($keyforsupportedoauth2array == 'OAUTH_OTHER_NAME') {
@@ -434,7 +453,7 @@ if (count($listinsetup) > 0) {
print '</div>';
print $form->buttonsSaveCancel("Modify", '');
print $form->buttonsSaveCancel("Save", '');
print '</form>';
}

View File

@@ -162,8 +162,10 @@ if ($mode == 'setup' && $user->admin) {
$keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
$keybeforeprovider = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
} else {
$keybeforeprovider = $keyforsupportedoauth2array;
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
@@ -179,13 +181,12 @@ if ($mode == 'setup' && $user->admin) {
$state = $shortscope; // TODO USe a better state
// Define $urltorenew, $urltodelete, $urltocheckperms
// TODO Use array $supportedoauth2array
if ($keyforsupportedoauth2array == 'OAUTH_GITHUB_NAME') {
// List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
// We pass this param list in to 'state' because we need it before and after the redirect.
// Note: github does not accept csrf key inside the state parameter (only known values)
$urltorenew = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.$shortscope.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltorenew = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($shortscope).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltocheckperms = 'https://github.com/settings/applications/';
} elseif ($keyforsupportedoauth2array == 'OAUTH_GOOGLE_NAME') {
@@ -195,17 +196,9 @@ if ($mode == 'setup' && $user->admin) {
$urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'-'.$oauthstateanticsrf.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltocheckperms = 'https://security.google.com/settings/security/permissions';
} elseif ($keyforsupportedoauth2array == 'OAUTH_STRIPE_TEST_NAME') {
$urltorenew = $urlwithroot.'/core/modules/oauth/stripetest_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = '';
$urltocheckperms = '';
} elseif ($keyforsupportedoauth2array == 'OAUTH_STRIPE_LIVE_NAME') {
$urltorenew = $urlwithroot.'/core/modules/oauth/stripelive_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = '';
$urltocheckperms = '';
} elseif ($keyforsupportedoauth2array = 'OAUTH_OTHER_NAME') {
$urltorenew = $urlwithroot.'/core/modules/oauth/generic_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = '';
} elseif (!empty($supportedoauth2array[$keyforsupportedoauth2array]['returnurl'])) {
$urltorenew = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltocheckperms = '';
} else {
$urltorenew = '';
@@ -220,17 +213,22 @@ if ($mode == 'setup' && $user->admin) {
$urltodelete .= '&keyforprovider='.urlencode($keyforprovider);
}
// Show value of token
$tokenobj = null;
// Token
require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
try {
// $OAUTH_SERVICENAME is for example 'Google-keyforprovider'
print '<!-- '.$OAUTH_SERVICENAME.' -->'."\n";
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
//print $storage->token.'<br>';
//print $tokenobj->getExtraParams()['id_token'].'<br>';
//print $tokenobj->getAccessToken().'<br>';
} catch (Exception $e) {
// Return an error if token not found
//print $e->getMessage();
}
// Set other properties
@@ -321,7 +319,11 @@ if ($mode == 'setup' && $user->admin) {
// Links to delete/checks token
if (is_object($tokenobj)) {
//test on $storage->hasAccessToken($OAUTH_SERVICENAME) ?
if ($urltodelete) {
print '<a class="button smallpaddingimp" href="'.$urltodelete.'">'.$langs->trans('DeleteAccess').'</a><br>';
} else {
print '<span class="opacitymedium">'.$langs->trans('GoOnTokenProviderToDeleteToken').'</span><br>';
}
}
// Request remote token
if ($urltorenew) {
@@ -343,7 +345,6 @@ if ($mode == 'setup' && $user->admin) {
print '<td colspan="2">';
if (is_object($tokenobj)) {
//var_dump($tokenobj);
$tokentoshow = $tokenobj->getAccessToken();
print '<span class="" title="'.dol_escape_htmltag($tokentoshow).'">'.showValueWithClipboardCPButton($tokentoshow, 1, dol_trunc($tokentoshow, 32)).'</span><br>';
//print 'Refresh: '.$tokenobj->getRefreshToken().'<br>';

View File

@@ -1,5 +1,6 @@
<?php
/* Copyright (C) 2019 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.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
@@ -1365,9 +1366,13 @@ class BOM extends CommonObject
$line->unit_cost = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
if (empty($line->unit_cost)) {
if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
if ($productFournisseur->fourn_remise_percent != "0") {
$line->unit_cost = $productFournisseur->fourn_unitprice_with_discount;
} else {
$line->unit_cost = $productFournisseur->fourn_unitprice;
}
}
}
$line->total_cost = price2num($line->qty * $line->unit_cost, 'MT');

View File

@@ -312,7 +312,11 @@ if ($id) {
print img_object($langs->trans("ShowBill"), "bill");
print '</a>&nbsp;';
if ($type == 'bank-transfer') {
print '<a href="'.DOL_URL_ROOT.'/fourn/facture/card.php?facid='.$obj->facid.'">'.$obj->ref."</a></td>\n";
} else {
print '<a href="'.DOL_URL_ROOT.'/compta/facture/card.php?facid='.$obj->facid.'">'.$obj->ref."</a></td>\n";
}
print '<td><a href="'.DOL_URL_ROOT.'/comm/card.php?socid='.$obj->socid.'">';
print img_object($langs->trans("ShowCompany"), "company").' '.$obj->name."</a></td>\n";

View File

@@ -908,7 +908,7 @@ class CMailFile
require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
try {
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
$expire = false;
@@ -1030,7 +1030,7 @@ class CMailFile
require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
try {
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);

View File

@@ -1272,7 +1272,7 @@ class FormTicket
$langs->loadLangs(array('other', 'mails'));
// Clear temp files. Must be done at beginning, before call of triggers
if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
$this->clear_attached_files();
}
@@ -1310,8 +1310,8 @@ class FormTicket
$keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
}
//var_dump($keytoavoidconflict);
if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
if (!empty($arraydefaultmessage->joinfiles) && is_array($this->param['fileinit'])) {
if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
foreach ($this->param['fileinit'] as $file) {
$formmail->add_attached_files($file, basename($file), dol_mimetype($file));
}

View File

@@ -2058,6 +2058,11 @@ function email_admin_prepare_head()
$head[$h][2] = 'templates';
$h++;
$head[$h][0] = DOL_URL_ROOT."/admin/mails_ingoing.php";
$head[$h][1] = $langs->trans("InGoingEmailSetup", $langs->transnoentitiesnoconv("EMailing"));
$head[$h][2] = 'common_ingoing';
$h++;
complete_head_from_modules($conf, $langs, null, $head, $h, 'email_admin', 'remove');
return $head;

View File

@@ -3534,7 +3534,7 @@ function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addli
$type = 'AC_FAX';
}
if (!empty($conf->global->AGENDA_ADDACTIONFORPHONE)) {
$link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
$link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage='. urlencode($_SERVER['REQUEST_URI']) .'&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
}
if ($link) {
$newphone = '<div>'.$newphone.' '.$link.'</div>';
@@ -4102,7 +4102,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
'stock', 'resize', 'service', 'stats', 'trip',
'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench',
'github', 'google', 'jabber', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
@@ -4123,7 +4123,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
$fa = 'far';
}
if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
$fa = 'fab';
}

View File

@@ -281,8 +281,8 @@ function getNumberInvoicesPieChart($mode)
{
global $conf, $db, $langs, $user;
if (($mode == 'customers' && isModEnabled('facture') && !empty($user->rights->facture->lire))
|| ($mode == 'suppliers' && (isModEnabled('fournisseur') || isModEnabled('supplier_invoice')) && !empty($user->rights->facture->lire))
if (($mode == 'customers' && isModEnabled('facture') && $user->hasRight('facture', 'lire'))
|| ($mode == 'suppliers' && (isModEnabled('fournisseur') || isModEnabled('supplier_invoice')) && $user->hasRight('fournisseur', 'facture', 'lire'))
) {
include DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/theme_vars.inc.php';

View File

@@ -25,15 +25,17 @@
// Supported OAUTH (a provider is supported when a file xxx_oauthcallback.php is available into htdocs/core/modules/oauth)
$supportedoauth2array = array(
'OAUTH_GOOGLE_NAME'=>array('callbackfile' => 'google', 'picto' => 'google', 'urlforapp' => 'OAUTH_GOOGLE_DESC', 'name'=>'Google', 'urlforcredentials'=>'https://console.developers.google.com/', 'availablescopes'=> 'userinfo_email,userinfo_profile,openid,email,profile,cloud_print,admin_directory_user,gmail_full'),
'OAUTH_GOOGLE_NAME'=>array('callbackfile' => 'google', 'picto' => 'google', 'urlforapp' => 'OAUTH_GOOGLE_DESC', 'name'=>'Google', 'urlforcredentials'=>'https://console.developers.google.com/', 'availablescopes'=> 'userinfo_email,userinfo_profile,openid,email,profile,cloud_print,admin_directory_user,gmail_full', 'returnurl'=>'/core/modules/oauth/google_oauthcallback.php'),
);
if (isModEnabled('stripe')) {
$supportedoauth2array['OAUTH_STRIPE_TEST_NAME'] = array('callbackfile' => 'stripetest', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeTest', 'urlforcredentials'=>'', 'availablescopes'=>'read_write');
$supportedoauth2array['OAUTH_STRIPE_LIVE_NAME'] = array('callbackfile' => 'stripelive', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeLive', 'urlforcredentials'=>'', 'availablescopes'=>'read_write');
$supportedoauth2array['OAUTH_STRIPE_TEST_NAME'] = array('callbackfile' => 'stripetest', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeTest', 'urlforcredentials'=>'', 'availablescopes'=>'read_write', 'returnurl'=>'/core/modules/oauth/stripetest_oauthcallback.php');
$supportedoauth2array['OAUTH_STRIPE_LIVE_NAME'] = array('callbackfile' => 'stripelive', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeLive', 'urlforcredentials'=>'', 'availablescopes'=>'read_write', 'returnurl'=>'/core/modules/oauth/stripelive_oauthcallback.php');
}
$supportedoauth2array['OAUTH_GITHUB_NAME'] = array('callbackfile' => 'github', 'picto' => 'github', 'urlforapp' => 'OAUTH_GITHUB_DESC', 'name'=>'GitHub', 'urlforcredentials'=>'https://github.com/settings/developers', 'availablescopes'=>'user,public_repo');
$supportedoauth2array['OAUTH_GITHUB_NAME'] = array('callbackfile' => 'github', 'picto' => 'github', 'urlforapp' => 'OAUTH_GITHUB_DESC', 'name'=>'GitHub', 'urlforcredentials'=>'https://github.com/settings/developers', 'availablescopes'=>'user,public_repo', 'returnurl'=>'/core/modules/oauth/github_oauthcallback.php');
$supportedoauth2array['OAUTH_MICROSOFT_NAME'] = array('callbackfile' => 'microsoft', 'picto' => 'microsoft', 'urlforapp' => 'OAUTH_MICROSOFT_DESC', 'name'=>'Microsoft', 'urlforcredentials'=>'https://portal.azure.com/', 'availablescopes'=>'openid,offline_access,profile,email,User.Read,https://outlook.office365.com/IMAP.AccessAsUser.All,https://outlook.office365.com/SMTP.Send', 'returnurl'=>'/core/modules/oauth/microsoft_oauthcallback.php');
if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
$supportedoauth2array['OAUTH_OTHER_NAME'] = array('callbackfile' => 'generic', 'picto' => 'generic', 'urlforapp' => 'OAUTH_OTHER_DESC', 'name'=>'Other', 'urlforcredentials'=>'', 'availablescopes'=>'Standard');
$supportedoauth2array['OAUTH_OTHER_NAME'] = array('callbackfile' => 'generic', 'picto' => 'generic', 'urlforapp' => 'OAUTH_OTHER_DESC', 'name'=>'Other', 'urlforcredentials'=>'', 'availablescopes'=>'Standard', 'returnurl'=>'/core/modules/oauth/generic_oauthcallback.php');
// See https://learn.microsoft.com/fr-fr/azure/active-directory/develop/quickstart-register-app#register-an-application
}

View File

@@ -119,6 +119,7 @@ function dolGetRandomBytes($length)
function dolEncrypt($chain, $key = '', $ciphering = "AES-256-CTR")
{
global $dolibarr_main_instance_unique_id;
global $dolibarr_disable_dolcrypt_for_debug;
if ($chain === '' || is_null($chain)) {
return '';
@@ -136,7 +137,7 @@ function dolEncrypt($chain, $key = '', $ciphering = "AES-256-CTR")
$newchain = $chain;
if (function_exists('openssl_encrypt')) {
if (function_exists('openssl_encrypt') && empty($dolibarr_disable_dolcrypt_for_debug)) {
$ivlen = 16;
if (function_exists('openssl_cipher_iv_length')) {
$ivlen = openssl_cipher_iv_length($ciphering);

View File

@@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2015 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2016-2022 Philippe Grand <philippe.grand@atoo-net.com>
* Copyright (C) 2016-2023 Philippe Grand <philippe.grand@atoo-net.com>
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2018 Francis Appels <francis.appels@z-application.com>
* Copyright (C) 2019 Markus Welters <markus@welters.de>
@@ -92,6 +92,8 @@ class pdf_standard extends ModeleExpenseReport
public $posxtva;
public $posxup;
public $posxqty;
public $posxtype;
public $posxprojet;
public $postotalht;
public $postotalttc;

View File

@@ -51,7 +51,7 @@ class modOauth extends DolibarrModules
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i', '', get_class($this));
// Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
$this->description = "Enable OAuth authentication";
$this->description = "Enable OAuth2 authentication";
// Possible values for version are: 'development', 'experimental', 'dolibarr' or 'dolibarr_deprecated' or version
$this->version = 'dolibarr';
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);

View File

@@ -66,7 +66,7 @@ $httpClient = new \OAuth\Common\Http\Client\CurlClient();
$serviceFactory->setHttpClient($httpClient);
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
@@ -77,9 +77,11 @@ $credentials = new Credentials(
$currentUri->getAbsoluteUri()
);
$state = GETPOST('state');
$requestedpermissionsarray = array();
if (GETPOST('state')) {
$requestedpermissionsarray = explode(',', GETPOST('state')); // Example: 'user'. 'state' parameter is standard to retrieve some parameters back
if ($state) {
$requestedpermissionsarray = explode(',', $state); // Example: 'user'. 'state' parameter is standard to retrieve some parameters back
}
if ($action != 'delete' && empty($requestedpermissionsarray)) {
print 'Error, parameter state is not defined';
@@ -88,7 +90,8 @@ if ($action != 'delete' && empty($requestedpermissionsarray)) {
//var_dump($requestedpermissionsarray);exit;
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
$apiService = $serviceFactory->createService($genericstring, $credentials, $storage, $requestedpermissionsarray);
// ucfirst(strtolower($genericstring)) must be the name of a class into OAuth/OAuth2/Services/Xxxx
$apiService = $serviceFactory->createService(ucfirst(strtolower($genericstring)), $credentials, $storage, $requestedpermissionsarray);
/*
var_dump($genericstring.($keyforprovider ? '-'.$keyforprovider : ''));
@@ -128,35 +131,25 @@ if ($action == 'delete') {
exit();
}
if (GETPOST('code')) { // We are coming from oauth provider page
if (GETPOST('code') || GETPOST('error')) { // We are coming from oauth provider page
// We should have
//$_GET=array('code' => string 'aaaaaaaaaaaaaa' (length=20), 'state' => string 'user,public_repo' (length=16))
dol_syslog("We are coming from the oauth provider page");
//llxHeader('',$langs->trans("OAuthSetup"));
//$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
//print load_fiche_titre($langs->trans("OAuthSetup"),$linkback,'title_setup');
//print dol_get_fiche_head();
// retrieve the CSRF state parameter
$state = GETPOSTISSET('state') ? GETPOST('state') : null;
//print '<table>';
dol_syslog("We are coming from the oauth provider page code=".dol_trunc(GETPOST('code'), 5)." error=".GETPOST('error'));
// This was a callback request from service, get the token
try {
//var_dump($_GET['code']);
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\GitHub
//var_dump($apiService); // OAuth\OAuth2\Service\Xxx
if (GETPOST('error')) {
setEventMessages(GETPOST('error').' '.GETPOST('error_description'), null, 'errors');
} else {
//$token = $apiService->requestAccessToken(GETPOST('code'), $state);
$token = $apiService->requestAccessToken(GETPOST('code'));
// Github is a service that does not need state to be stored.
// Into constructor of GitHub, the call
// parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri)
// has not the ending parameter to true like the Google class constructor.
setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token
}
$backtourl = $_SESSION["backtourlsavedbeforeoauthjump"];
unset($_SESSION["backtourlsavedbeforeoauthjump"]);
@@ -166,15 +159,17 @@ if (GETPOST('code')) { // We are coming from oauth provider page
} catch (Exception $e) {
print $e->getMessage();
}
} else { // If entry on page with no parameter, we arrive here
} else {
// If we enter this page without 'code' parameter, we arrive here. This is the case when we want to get the redirect
// to the OAuth provider login page.
$_SESSION["backtourlsavedbeforeoauthjump"] = $backtourl;
$_SESSION["oauthkeyforproviderbeforeoauthjump"] = $keyforprovider;
$_SESSION['oauthstateanticsrf'] = $state;
// This may create record into oauth_state before the header redirect.
// Creation of record with state in this tables depend on the Provider used (see its constructor).
if (GETPOST('state')) {
$url = $apiService->getAuthorizationUri(array('state' => GETPOST('state')));
if ($state) {
$url = $apiService->getAuthorizationUri(array('state' => $state));
} else {
$url = $apiService->getAuthorizationUri(); // Parameter state will be randomly generated
}

View File

@@ -65,7 +65,7 @@ $httpClient = new \OAuth\Common\Http\Client\CurlClient();
$serviceFactory->setHttpClient($httpClient);
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_GITHUB'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
@@ -115,30 +115,21 @@ if ($action == 'delete') {
exit();
}
if (!empty($_GET['code'])) { // We are coming from oauth provider page
if (GETPOST('code')) { // We are coming from oauth provider page
// We should have
//$_GET=array('code' => string 'aaaaaaaaaaaaaa' (length=20), 'state' => string 'user,public_repo' (length=16))
dol_syslog("We are coming from the oauth provider page");
//llxHeader('',$langs->trans("OAuthSetup"));
//$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
//print load_fiche_titre($langs->trans("OAuthSetup"),$linkback,'title_setup');
//print dol_get_fiche_head();
// retrieve the CSRF state parameter
$state = isset($_GET['state']) ? $_GET['state'] : null;
//print '<table>';
dol_syslog("We are coming from the oauth provider page code=".dol_trunc(GETPOST('code'), 5));
// This was a callback request from service, get the token
try {
//var_dump($_GET['code']);
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\GitHub
//$token = $apiService->requestAccessToken($_GET['code'], $state);
$token = $apiService->requestAccessToken($_GET['code']);
// Github is a service that does not need state to be stored.
//$token = $apiService->requestAccessToken(GETPOST('code'), $state);
$token = $apiService->requestAccessToken(GETPOST('code'));
// Github is a service that does not need state to be stored as second paramater of requestAccessToken
// Into constructor of GitHub, the call
// parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri)
// has not the ending parameter to true like the Google class constructor.

View File

@@ -137,7 +137,7 @@ if ($action == 'delete') {
}
if (GETPOST('code')) { // We are coming from oauth provider page.
dol_syslog("We are coming from the oauth provider page keyforprovider=".$keyforprovider);
dol_syslog("We are coming from the oauth provider page keyforprovider=".$keyforprovider." code=".dol_trunc(GETPOST('code'), 5));
// We must validate that the $state is the same than the one into $_SESSION['oauthstateanticsrf'], return error if not.
if (isset($_SESSION['oauthstateanticsrf']) && $state != $_SESSION['oauthstateanticsrf']) {
@@ -146,7 +146,6 @@ if (GETPOST('code')) { // We are coming from oauth provider page.
} else {
// This was a callback request from service, get the token
try {
//var_dump($_GET['code']);
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\Google
@@ -193,7 +192,7 @@ if (GETPOST('code')) { // We are coming from oauth provider page.
}
}
} else {
// If we enter this page without 'code' parameter, we arrive here. this is the case when we want to get the redirect
// If we enter this page without 'code' parameter, we arrive here. This is the case when we want to get the redirect
// to the OAuth provider login page.
$_SESSION["backtourlsavedbeforeoauthjump"] = $backtourl;
$_SESSION["oauthkeyforproviderbeforeoauthjump"] = $keyforprovider;
@@ -218,6 +217,8 @@ if (GETPOST('code')) { // We are coming from oauth provider page.
//$url .= 'hd=xxx';
}
//var_dump($url);exit;
// we go on oauth provider authorization page
header('Location: '.$url);
exit();

View File

@@ -0,0 +1,214 @@
<?php
/* Copyright (C) 2022 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2015 Frederic 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/>.
*/
/**
* \file htdocs/core/modules/oauth/microsoft_oauthcallback.php
* \ingroup oauth
* \brief Page to get oauth callback
*/
// Load Dolibarr environment
require '../../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
use OAuth\Common\Storage\DoliStorage;
use OAuth\Common\Consumer\Credentials;
use OAuth\OAuth2\Service\GitHub;
// Define $urlwithroot
$urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
$urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
$action = GETPOST('action', 'aZ09');
$backtourl = GETPOST('backtourl', 'alpha');
$keyforprovider = GETPOST('keyforprovider', 'aZ09');
if (empty($keyforprovider) && !empty($_SESSION["oauthkeyforproviderbeforeoauthjump"]) && (GETPOST('code') || $action == 'delete')) {
$keyforprovider = $_SESSION["oauthkeyforproviderbeforeoauthjump"];
}
$genericstring = 'MICROSOFT';
/**
* Create a new instance of the URI class with the current URI, stripping the query string
*/
$uriFactory = new \OAuth\Common\Http\Uri\UriFactory();
//$currentUri = $uriFactory->createFromSuperGlobalArray($_SERVER);
//$currentUri->setQuery('');
$currentUri = $uriFactory->createFromAbsolute($urlwithroot.'/core/modules/oauth/microsoft_oauthcallback.php');
/**
* Load the credential for the service
*/
/** @var $serviceFactory \OAuth\ServiceFactory An OAuth service factory. */
$serviceFactory = new \OAuth\ServiceFactory();
$httpClient = new \OAuth\Common\Http\Client\CurlClient();
// TODO Set options for proxy and timeout
// $params=array('CURLXXX'=>value, ...)
//$httpClient->setCurlParameters($params);
$serviceFactory->setHttpClient($httpClient);
// Dolibarr storage
$storage = new DoliStorage($db, $conf, $keyforprovider);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
$keyforparamsecret = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_SECRET';
$keyforparamtenant = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT';
$credentials = new Credentials(
getDolGlobalString($keyforparamid),
getDolGlobalString($keyforparamsecret),
$currentUri->getAbsoluteUri()
);
$state = GETPOST('state');
$requestedpermissionsarray = array();
if ($state) {
$requestedpermissionsarray = explode(',', $state); // Example: 'user'. 'state' parameter is standard to retrieve some parameters back
}
if ($action != 'delete' && empty($requestedpermissionsarray)) {
print 'Error, parameter state is not defined';
exit;
}
//var_dump($requestedpermissionsarray);exit;
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
// ucfirst(strtolower($genericstring)) must be the name of a class into OAuth/OAuth2/Services/Xxxx
// $requestedpermissionsarray contains list of scopes.
// Conversion into URL is done by Reflection on constant with name SCOPE_scope_in_uppercase
try {
$apiService = $serviceFactory->createService(ucfirst(strtolower($genericstring)), $credentials, $storage, $requestedpermissionsarray);
} catch (Exception $e) {
print $e->getMessage();
exit;
}
/*
var_dump($genericstring.($keyforprovider ? '-'.$keyforprovider : ''));
var_dump($credentials);
var_dump($storage);
var_dump($requestedpermissionsarray);
*/
if (empty($apiService)) {
print 'Error, failed to create serviceFactory';
exit;
}
// access type needed to have oauth provider refreshing token
//$apiService->setAccessType('offline');
$langs->load("oauth");
if (!getDolGlobalString($keyforparamid)) {
accessforbidden('Setup of service is not complete. Customer ID is missing');
}
if (!getDolGlobalString($keyforparamsecret)) {
accessforbidden('Setup of service is not complete. Secret key is missing');
}
/*
* Actions
*/
if ($action == 'delete') {
$storage->clearToken($genericstring);
setEventMessages($langs->trans('TokenDeleted'), null, 'mesgs');
header('Location: '.$backtourl);
exit();
}
//dol_syslog("GET=".join(',', $_GET));
if (GETPOST('code') || GETPOST('error')) { // We are coming from oauth provider page
// We should have
//$_GET=array('code' => string 'aaaaaaaaaaaaaa' (length=20), 'state' => string 'user,public_repo' (length=16))
dol_syslog("We are coming from the oauth provider page code=".dol_trunc(GETPOST('code'), 5)." error=".GETPOST('error'));
// This was a callback request from service, get the token
try {
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\Microsoft
if (GETPOST('error')) {
setEventMessages(GETPOST('error').' '.GETPOST('error_description'), null, 'errors');
} else {
//print GETPOST('code');exit;
//$token = $apiService->requestAccessToken(GETPOST('code'), $state);
$token = $apiService->requestAccessToken(GETPOST('code'));
// Microsoft is a service that does not need state to be stored as second paramater of requestAccessToken
//print $token->getAccessToken().'<br><br>';
//print $token->getExtraParams()['id_token'].'<br>';
//print $token->getRefreshToken().'<br>';exit;
setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token
}
$backtourl = $_SESSION["backtourlsavedbeforeoauthjump"];
unset($_SESSION["backtourlsavedbeforeoauthjump"]);
header('Location: '.$backtourl);
exit();
} catch (Exception $e) {
print $e->getMessage();
}
} else {
// If we enter this page without 'code' parameter, we arrive here. This is the case when we want to get the redirect
// to the OAuth provider login page.
$_SESSION["backtourlsavedbeforeoauthjump"] = $backtourl;
$_SESSION["oauthkeyforproviderbeforeoauthjump"] = $keyforprovider;
$_SESSION['oauthstateanticsrf'] = $state;
//if (!preg_match('/^forlogin/', $state)) {
// $apiService->setApprouvalPrompt('auto');
//}
// This may create record into oauth_state before the header redirect.
// Creation of record with state in this tables depend on the Provider used (see its constructor).
if ($state) {
$url = $apiService->getAuthorizationUri(array('state' => $state));
} else {
$url = $apiService->getAuthorizationUri(); // Parameter state will be randomly generated
}
// Show url to get authorization
//var_dump((string) $url);exit;
dol_syslog("Redirect to url=".$url);
// we go on oauth provider authorization page
header('Location: '.$url);
exit();
}
/*
* View
*/
// No view at all, just actions
$db->close();

View File

@@ -65,7 +65,7 @@ $httpClient = new \OAuth\Common\Http\Client\CurlClient();
$serviceFactory->setHttpClient($httpClient);
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_STRIPE_LIVE'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
@@ -121,33 +121,20 @@ if ($action == 'delete') {
exit();
}
if (!empty($_GET['code'])) { // We are coming from oauth provider page
if (GETPOST('code')) { // We are coming from oauth provider page
// We should have
//$_GET=array('code' => string 'aaaaaaaaaaaaaa' (length=20), 'state' => string 'user,public_repo' (length=16))
dol_syslog("We are coming from the oauth provider page");
//llxHeader('',$langs->trans("OAuthSetup"));
//$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
//print load_fiche_titre($langs->trans("OAuthSetup"),$linkback,'title_setup');
//print dol_get_fiche_head();
// retrieve the CSRF state parameter
$state = isset($_GET['state']) ? $_GET['state'] : null;
//print '<table>';
dol_syslog("We are coming from the oauth provider page code=".dol_trunc(GETPOST('code'), 5));
// This was a callback request from service, get the token
try {
//var_dump($_GET['code']);
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\GitHub
//var_dump($apiService); // OAuth\OAuth2\Service\Stripe
//$token = $apiService->requestAccessToken($_GET['code'], $state);
$token = $apiService->requestAccessToken($_GET['code']);
// Github is a service that does not need state to be stored.
// Into constructor of GitHub, the call
// parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri)
// has not the ending parameter to true like the Google class constructor.
//$token = $apiService->requestAccessToken(GETPOST('code'), $state);
$token = $apiService->requestAccessToken(GETPOST('code'));
// Stripe is a service that does not need state to be stored as second paramater of requestAccessToken
setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token

View File

@@ -65,7 +65,7 @@ $httpClient = new \OAuth\Common\Http\Client\CurlClient();
$serviceFactory->setHttpClient($httpClient);
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_STRIPE_TEST'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
@@ -121,33 +121,20 @@ if ($action == 'delete') {
exit();
}
if (!empty($_GET['code'])) { // We are coming from oauth provider page
if (GETPOST('code')) { // We are coming from oauth provider page
// We should have
//$_GET=array('code' => string 'aaaaaaaaaaaaaa' (length=20), 'state' => string 'user,public_repo' (length=16))
dol_syslog("We are coming from the oauth provider page");
//llxHeader('',$langs->trans("OAuthSetup"));
//$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
//print load_fiche_titre($langs->trans("OAuthSetup"),$linkback,'title_setup');
//print dol_get_fiche_head();
// retrieve the CSRF state parameter
$state = isset($_GET['state']) ? $_GET['state'] : null;
//print '<table>';
dol_syslog("We are coming from the oauth provider page code=".dol_trunc(GETPOST('code'), 5));
// This was a callback request from service, get the token
try {
//var_dump($_GET['code']);
//var_dump($state);
//var_dump($apiService); // OAuth\OAuth2\Service\GitHub
//var_dump($apiService); // OAuth\OAuth2\Service\Stripe
//$token = $apiService->requestAccessToken($_GET['code'], $state);
$token = $apiService->requestAccessToken($_GET['code']);
// Github is a service that does not need state to be stored.
// Into constructor of GitHub, the call
// parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri)
// has not the ending parameter to true like the Google class constructor.
//$token = $apiService->requestAccessToken(GETPOST('code'), $state);
$token = $apiService->requestAccessToken(GETPOST('code'));
// Stripe is a service that does not need state to be stored as second paramater of requestAccessToken
setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token

View File

@@ -116,10 +116,12 @@ class printing_printgcp extends PrintingDriver
'type'=>'info',
);
} else {
$keyforprovider = ''; // @FIXME
$this->google_id = getDolGlobalString('OAUTH_GOOGLE_ID');
$this->google_secret = getDolGlobalString('OAUTH_GOOGLE_SECRET');
// Token storage
$storage = new DoliStorage($this->db, $this->conf);
$storage = new DoliStorage($this->db, $this->conf, $keyforprovider);
//$storage->clearToken($this->OAUTH_SERVICENAME_GOOGLE);
// Setup the credentials for the requests
$credentials = new Credentials(
@@ -254,8 +256,11 @@ class printing_printgcp extends PrintingDriver
public function getlistAvailablePrinters()
{
$ret = array();
$keyforprovider = ''; // @FIXME
// Token storage
$storage = new DoliStorage($this->db, $this->conf);
$storage = new DoliStorage($this->db, $this->conf, $keyforprovider);
// Setup the credentials for the requests
$credentials = new Credentials(
$this->google_id,
@@ -392,8 +397,11 @@ class printing_printgcp extends PrintingDriver
'content' => base64_encode($contents), // encode file content as base64
'contentType' => $contenttype,
);
$keyforprovider = ''; // @FIXME
// Dolibarr Token storage
$storage = new DoliStorage($this->db, $this->conf);
$storage = new DoliStorage($this->db, $this->conf, $keyforprovider);
// Setup the credentials for the requests
$credentials = new Credentials(
$this->google_id,
@@ -441,8 +449,11 @@ class printing_printgcp extends PrintingDriver
$error = 0;
$html = '';
$keyforprovider = ''; // @FIXME
// Token storage
$storage = new DoliStorage($this->db, $this->conf);
$storage = new DoliStorage($this->db, $this->conf, $keyforprovider);
// Setup the credentials for the requests
$credentials = new Credentials(
$this->google_id,

View File

@@ -1097,10 +1097,13 @@ class EmailCollector extends CommonObject
//$debugtext = "Host: ".$this->host."<br>Port: ".$this->port."<br>Login: ".$this->login."<br>Password: ".$this->password."<br>access type: ".$this->acces_type."<br>oauth service: ".$this->oauth_service."<br>Max email per collect: ".$this->maxemailpercollect;
//dol_syslog($debugtext);
$storage = new DoliStorage($db, $conf);
$token = '';
$storage = new DoliStorage($db, $conf, $keyforprovider);
try {
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
$expire = true;
// Is token expired or will token expire in the next 30 seconds
// if (is_object($tokenobj)) {
@@ -1137,7 +1140,6 @@ class EmailCollector extends CommonObject
return -1;
}
$cm = new ClientManager();
$client = $cm->make([
'host' => $this->host,
@@ -2414,7 +2416,7 @@ class EmailCollector extends CommonObject
'ticket' => array('table' => 'ticket',
'fields' => array('ref'),
'class' => 'ticket/class/ticket.class.php',
'object' => ' Ticket'),
'object' => 'Ticket'),
'knowledgemanagement' => array('table' => 'knowledgemanagement_knowledgerecord',
'fields' => array('ref'),
'class' => 'knowledgemanagement/class/knowledgemanagement.class.php',

View File

@@ -133,6 +133,21 @@ class ExpenseReport extends CommonObject
public $statuts_short = array();
public $statuts_logo;
// Multicurrency
/**
* @var int Currency ID
*/
public $fk_multicurrency;
/**
* @var string multicurrency code
*/
public $multicurrency_code;
public $multicurrency_tx;
public $multicurrency_total_ht;
public $multicurrency_total_tva;
public $multicurrency_total_ttc;
/**
* Draft status
@@ -2790,6 +2805,21 @@ class ExpenseReportLine extends CommonObjectLine
public $total_localtax1;
public $total_localtax2;
// Multicurrency
/**
* @var int Currency ID
*/
public $fk_multicurrency;
/**
* @var string multicurrency code
*/
public $multicurrency_code;
public $multicurrency_tx;
public $multicurrency_total_ht;
public $multicurrency_total_tva;
public $multicurrency_total_ttc;
/**
* @var int ID into llx_ecm_files table to link line to attached file
*/

View File

@@ -57,6 +57,7 @@ class StreamClient extends AbstractClient
}
$extraHeaders['Content-length'] = 'Content-length: '.strlen($requestBody);
//var_dump($requestBody); var_dump($extraHeaders);var_dump($method);exit;
$context = $this->generateStreamContext($requestBody, $extraHeaders, $method);
$level = error_reporting(0);

View File

@@ -59,6 +59,8 @@ class DoliStorage implements TokenStorageInterface
private $key;
//private $stateKey;
private $keyforprovider;
public $token;
private $tenant;
public $state;
public $date_creation;
@@ -75,6 +77,7 @@ class DoliStorage implements TokenStorageInterface
$this->db = $db;
$this->conf = $conf;
$this->keyforprovider = $keyforprovider;
$this->token = '';
$this->tokens = array();
$this->states = array();
//$this->key = $key;
@@ -98,7 +101,7 @@ class DoliStorage implements TokenStorageInterface
/**
* {@inheritDoc}
*/
public function storeAccessToken($service, TokenInterface $token)
public function storeAccessToken($service, TokenInterface $tokenobj)
{
global $conf;
@@ -106,16 +109,25 @@ class DoliStorage implements TokenStorageInterface
//var_dump($token);
dol_syslog("storeAccessToken service=".$service);
include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
$serializedToken = dolEncrypt(serialize($token));
$servicepluskeyforprovider = $service;
if (!empty($this->keyforprovider)) {
// We clean the keyforprovider after the - to be sure it is not present
$servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider);
// Now we add the keyforprovider
$servicepluskeyforprovider .= '-'.$this->keyforprovider;
}
$this->tokens[$service] = $token;
include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
$serializedToken = serialize($tokenobj);
if (!is_array($this->tokens)) {
$this->tokens = array();
}
$this->tokens[$service] = $tokenobj;
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token";
$sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
$sql .= " WHERE service = '".$this->db->escape($servicepluskeyforprovider)."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
if (! $resql) {
@@ -125,16 +137,22 @@ class DoliStorage implements TokenStorageInterface
if ($obj) {
// update
$sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token";
$sql.= " SET token = '".$this->db->escape($serializedToken)."'";
$sql.= " SET token = '".$this->db->escape(dolEncrypt($serializedToken))."'";
$sql.= " WHERE rowid = ".((int) $obj['rowid']);
$resql = $this->db->query($sql);
if (!$resql) {
dol_print_error($this->db);
}
} else {
// save
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, token, entity, datec)";
$sql .= " VALUES ('".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."', '".$this->db->escape($serializedToken)."', ".((int) $conf->entity).", ";
$sql .= " VALUES ('".$this->db->escape($servicepluskeyforprovider)."', '".$this->db->escape(dolEncrypt($serializedToken))."', ".((int) $conf->entity).", ";
$sql .= " '".$this->db->idate(dol_now())."'";
$sql .= ")";
$resql = $this->db->query($sql);
if (!$resql) {
dol_print_error($this->db);
}
}
//print $sql;
@@ -143,15 +161,26 @@ class DoliStorage implements TokenStorageInterface
}
/**
* {@inheritDoc}
* Load token and other data from a $service
* Note: Token load are cumulated into array ->tokens when other properties are erased by last loaded token.
*
* @return void
*/
public function hasAccessToken($service)
{
// get from db
dol_syslog("hasAccessToken service=".$service);
$servicepluskeyforprovider = $service;
if (!empty($this->keyforprovider)) {
// We clean the keyforprovider after the - to be sure it is not present
$servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider);
// Now we add the keyforprovider
$servicepluskeyforprovider .= '-'.$this->keyforprovider;
}
$sql = "SELECT token, datec, tms, state FROM ".MAIN_DB_PREFIX."oauth_token";
$sql .= " WHERE service = '".$this->db->escape($service.(empty($this->keyforprovider) ? '' : '-'.$this->keyforprovider))."'";
$sql .= " WHERE service = '".$this->db->escape($servicepluskeyforprovider)."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
if (! $resql) {
@@ -160,18 +189,20 @@ class DoliStorage implements TokenStorageInterface
$result = $this->db->fetch_array($resql);
if ($result) {
include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
$token = unserialize(dolDecrypt($result['token']));
$tokenobj = unserialize(dolDecrypt($result['token']));
$this->token = dolDecrypt($result['token']);
$this->date_creation = $this->db->jdate($result['datec']);
$this->date_modification = $this->db->jdate($result['tms']);
$this->state = $result['state'];
} else {
$token = '';
$tokenobj = '';
$this->token = '';
$this->date_creation = null;
$this->date_modification = null;
$this->state = '';
}
$this->tokens[$service] = $token;
$this->tokens[$service] = $tokenobj;
return is_array($this->tokens)
&& isset($this->tokens[$service])
@@ -327,4 +358,18 @@ class DoliStorage implements TokenStorageInterface
// allow chaining
return $this;
}
/**
* Return the token
*
* @return string String for the tenant used to create the token
*/
public function getTenant()
{
// Set/Reset tenant now so it will be defined for.
// TODO We must store it into the table llx_oauth_token
$this->tenant = getDolGlobalString('OAUTH_MICROSOFT'.($this->keyforprovider ? '-'.$this->keyforprovider : '').'_TENANT');
return $this->tenant;
}
}

View File

@@ -223,6 +223,8 @@ abstract class AbstractService extends BaseAbstractService implements ServiceInt
$parameters,
$this->getExtraOAuthHeaders()
);
//print $responseBody;exit; // We must have a result "{"token_type":"Bearer","scope...
$token = $this->parseAccessTokenResponse($responseBody);
$this->storage->storeAccessToken($this->service(), $token);

View File

@@ -12,30 +12,40 @@ use OAuth\Common\Http\Uri\UriInterface;
class Microsoft extends AbstractService
{
const SCOPE_BASIC = 'wl.basic';
const SCOPE_OFFLINE = 'wl.offline_access';
const SCOPE_SIGNIN = 'wl.signin';
const SCOPE_BIRTHDAY = 'wl.birthday';
const SCOPE_CALENDARS = 'wl.calendars';
const SCOPE_CALENDARS_UPDATE = 'wl.calendars_update';
const SCOPE_CONTACTS_BIRTHDAY = 'wl.contacts_birthday';
const SCOPE_CONTACTS_CREATE = 'wl.contacts_create';
const SCOPE_CONTACTS_CALENDARS = 'wl.contacts_calendars';
const SCOPE_CONTACTS_PHOTOS = 'wl.contacts_photos';
const SCOPE_CONTACTS_SKYDRIVE = 'wl.contacts_skydrive';
const SCOPE_EMAILS = 'wl.emails';
const SCOPE_EVENTS_CREATE = 'wl.events_create';
const SCOPE_MESSENGER = 'wl.messenger';
const SCOPE_PHONE_NUMBERS = 'wl.phone_numbers';
const SCOPE_PHOTOS = 'wl.photos';
const SCOPE_POSTAL_ADDRESSES = 'wl.postal_addresses';
const SCOPE_SHARE = 'wl.share';
const SCOPE_SKYDRIVE = 'wl.skydrive';
const SCOPE_SKYDRIVE_UPDATE = 'wl.skydrive_update';
const SCOPE_WORK_PROFILE = 'wl.work_profile';
const SCOPE_APPLICATIONS = 'wl.applications';
const SCOPE_APPLICATIONS_CREATE = 'wl.applications_create';
const SCOPE_IMAP = 'wl.imap';
const SCOPE_BASIC = 'basic';
const SCOPE_OFFLINE_ACCESS = 'offline_access';
const SCOPE_SIGNIN = 'signin';
const SCOPE_BIRTHDAY = 'birthday';
const SCOPE_CALENDARS = 'calendars';
const SCOPE_CALENDARS_UPDATE = 'calendars_update';
const SCOPE_CONTACTS_BIRTHDAY = 'contacts_birthday';
const SCOPE_CONTACTS_CREATE = 'contacts_create';
const SCOPE_CONTACTS_CALENDARS = 'contacts_calendars';
const SCOPE_CONTACTS_PHOTOS = 'contacts_photos';
const SCOPE_CONTACTS_SKYDRIVE = 'contacts_skydrive';
const SCOPE_EMAIL = 'email';
const SCOPE_EVENTS_CREATE = 'events_create';
const SCOPE_MESSENGER = 'messenger';
const SCOPE_OPENID = 'openid';
const SCOPE_PHONE_NUMBERS = 'phone_numbers';
const SCOPE_PHOTOS = 'photos';
const SCOPE_POSTAL_ADDRESSES = 'postal_addresses';
const SCOPE_PROFILE = 'profile';
const SCOPE_SHARE = 'share';
const SCOPE_SKYDRIVE = 'skydrive';
const SCOPE_SKYDRIVE_UPDATE = 'skydrive_update';
const SCOPE_WORK_PROFILE = 'work_profile';
const SCOPE_APPLICATIONS = 'applications';
const SCOPE_APPLICATIONS_CREATE = 'applications_create';
const SCOPE_IMAP = 'imap';
const SOCPE_IMAP_ACCESSASUSERALL = 'https://outlook.office365.com/IMAP.AccessAsUser.All';
const SOCPE_SMTPSEND = 'https://outlook.office365.com/SMTP.Send';
const SOCPE_USERREAD = 'User.Read';
const SOCPE_MAILREAD = 'Mail.Read';
const SOCPE_MAILSEND = 'Mail.Send';
protected $storage;
/**
* MS uses some magical not officialy supported scope to get even moar info like full emailaddresses.
@@ -48,7 +58,8 @@ class Microsoft extends AbstractService
*
* Considering this scope is not officially supported: use with care
*/
const SCOPE_CONTACTS_EMAILS = 'wl.contacts_emails';
const SCOPE_CONTACTS_EMAILS = 'contacts_emails';
public function __construct(
CredentialsInterface $credentials,
@@ -59,6 +70,8 @@ class Microsoft extends AbstractService
) {
parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
$this->storage = $storage;
if (null === $baseApiUri) {
$this->baseApiUri = new Uri('https://apis.live.net/v5.0/');
}
@@ -69,7 +82,11 @@ class Microsoft extends AbstractService
*/
public function getAuthorizationEndpoint()
{
return new Uri('https://login.live.com/oauth20_authorize.srf');
$tenant = $this->storage->getTenant();
//return new Uri('https://login.live.com/oauth20_authorize.srf');
//return new Uri('https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize');
return new Uri('https://login.microsoftonline.com/'.$tenant.'/oauth2/v2.0/authorize');
}
/**
@@ -77,7 +94,11 @@ class Microsoft extends AbstractService
*/
public function getAccessTokenEndpoint()
{
return new Uri('https://login.live.com/oauth20_token.srf');
$tenant = $this->storage->getTenant();
//return new Uri('https://login.live.com/oauth20_token.srf');
//return new Uri('https://login.microsoftonline.com/organizations/oauth2/v2.0/token');
return new Uri('https://login.microsoftonline.com/'.$tenant.'/oauth2/v2.0/token');
}
/**
@@ -100,6 +121,7 @@ class Microsoft extends AbstractService
} elseif (isset($data['error'])) {
throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
}
//print $data['access_token'];exit;
$token = new StdOAuth2Token();
$token->setAccessToken($data['access_token']);

View File

@@ -152,12 +152,12 @@ class Odf
}
/**
* Replaces html tags in odt tags and returns a compatible string
* Replaces html tags found into the $value with ODT compatible tags and return the converted compatible string
*
* @param string $value Replacement value
* @param bool $encode If true, special XML characters are encoded
* @param string $charset Charset
* @return string
* @return string String in ODTsyntax format
*/
public function convertVarToOdf($value, $encode = true, $charset = 'ISO-8859')
{
@@ -203,13 +203,16 @@ class Odf
}
}
$this->contentXml = str_replace('</office:font-face-decls>', $fonts . '</office:font-face-decls>', $this->contentXml);
} else $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "<text:line-break/>", $value);
} else {
$convertedValue = preg_replace('/(\r\n|\r|\n)/i', "<text:line-break/>", $value);
}
return $convertedValue;
}
/**
* Replaces html tags in with odt tags and returns an odt string
*
* @param array $tags An array with html tags generated by the getDataFromHtml() function
* @param array $customStyles An array of style defenitions that should be included inside the odt file
* @param array $fontDeclarations An array of font declarations that should be included inside the odt file

View File

@@ -353,6 +353,7 @@ class Client {
} catch (Exceptions\RuntimeException $e) {
throw new ConnectionFailedException("connection setup failed - run exception", 0, $e);
}
$this->authenticate();
return $this;

View File

@@ -190,7 +190,7 @@ abstract class Protocol implements ProtocolInterface {
STREAM_CLIENT_CONNECT,
stream_context_create($this->defaultSocketOptions($transport))
);
stream_set_timeout($stream, $timeout);
//stream_set_timeout($stream, $timeout); // Hang id $strem empty and already done line 199
if (!$stream) {
throw new ConnectionFailedException($errstr, $errno);

View File

@@ -688,7 +688,7 @@ ALTER TABLE llx_actioncomm MODIFY COLUMN note mediumtext;
DELETE FROM llx_boxes WHERE box_id IN (select rowid FROM llx_boxes_def WHERE file IN ('box_bom.php@bom', 'box_bom.php', 'box_members.php', 'box_last_modified_ticket', 'box_members_last_subscriptions', 'box_members_last_modified', 'box_members_subscriptions_by_year'));
DELETE FROM llx_boxes_def WHERE file IN ('box_bom.php@bom', 'box_bom.php', 'box_members.php', 'box_last_modified_ticket', 'box_members_last_subscriptions', 'box_members_last_modified', 'box_members_subscriptions_by_year');
ALTER TABLE llx_takepos_floor_tables ADD UNIQUE uk_takepos_floor_tables (entity,label);
ALTER TABLE llx_takepos_floor_tables ADD UNIQUE INDEX uk_takepos_floor_tables (entity,label);
ALTER TABLE llx_partnership ADD COLUMN url_to_check varchar(255);
ALTER TABLE llx_c_partnership_type ADD COLUMN keyword varchar(128);

View File

@@ -39,6 +39,9 @@
ALTER TABLE llx_accounting_system CHANGE COLUMN fk_pays fk_country integer;
ALTER TABLE llx_commande_fournisseurdet MODIFY COLUMN ref varchar(128);
ALTER TABLE llx_facture_fourn_det MODIFY COLUMN ref varchar(128);
-- v18

View File

@@ -13,4 +13,4 @@
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see https://www.gnu.org/licenses/.
ALTER TABLE llx_takepos_floor_tables ADD UNIQUE(entity,label);
ALTER TABLE llx_takepos_floor_tables ADD UNIQUE INDEX uk_takepos_floor_tables(entity,label);

View File

@@ -451,7 +451,7 @@ ExtrafieldCheckBox=Checkboxes
ExtrafieldCheckBoxFromList=Checkboxes from table
ExtrafieldLink=Link to an object
ComputedFormula=Computed field
ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: <strong>$db, $conf, $langs, $mysoc, $user, $object</strong>.<br><strong>WARNING</strong>: Only some properties of $object may be available. If you need a properties not loaded, just fetch yourself the object into your formula like in the second example.<br>Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.<br><br>Example of formula:<br>$object->id < 10 ? round($object->id / 2, 2): ($object->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)<br><br>Example to reload object<br>(($reloadedobj = new Societe($db)) && ($reloadedobj->fetchNoCompute($obj->id ? $obj->id: ($obj->rowid ? $obj->rowid: $object->id)) > 0)) ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5: '-1'<br><br>Other example of formula to force load of object and its parent object:<br>(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: 'Parent project not found'
ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: <strong>$db, $conf, $langs, $mysoc, $user, $objectoffield</strong>.<br><strong>WARNING</strong>: If you need properties of an object not loaded, just fetch yourself the object into your formula like in the second example.<br>Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.<br><br>Example of formula:<br>$objectoffield->id < 10 ? round($objectoffield->id / 2, 2): ($objectoffield->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)<br><br>Example to reload object<br>(($reloadedobj = new Societe($db)) && ($reloadedobj->fetchNoCompute($objectoffield->id) > 0 ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5: '-1')<br><br>Other example of formula to force load of object and its parent object:<br>(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($objectoffield->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: 'Parent project not found'
Computedpersistent=Store computed field
ComputedpersistentDesc=Computed extra fields will be stored in the database, however, the value will only be recalculated when the object of this field is changed. If the computed field depends on other objects or global data this value might be wrong!!
ExtrafieldParamHelpPassword=Leaving this field blank means this value will be stored without encryption (field must be only hidden with star on screen).<br>Set 'auto' to use the default encryption rule to save password into database (then value read will be the hash only, no way to retrieve original value)
@@ -704,6 +704,8 @@ Module62000Name=Incoterms
Module62000Desc=Add features to manage Incoterms
Module63000Name=Resources
Module63000Desc=Manage resources (printers, cars, rooms, ...) for allocating to events
Module66000Name=Enable OAuth2 authentication
Module66000Desc=Provide a tool to generate and manage OAuth2 tokens. The token can then be used by some other modules.
Module94160Name=Receptions
Permission11=Read customer invoices (and payments)
Permission12=Create/modify customer invoices
@@ -2368,4 +2370,5 @@ Reload=Reload
ConfirmReload=Confirm module reload
WarningModuleHasChangedLastVersionCheckParameter=Warning: the module %s has set a parameter to check its version at each page access. This is a bad and not allowed practice that may make the page to administer modules instable. Please contact author of module to fix this.
WarningModuleHasChangedSecurityCsrfParameter=Warning: the module %s has disabled the CSRF security of your instance. This action is suspect and your installation may no more be secured. Please contact the author of the module for explanation.
EMailsInGoingDesc=Incoming emails are managed by the module %s. You must enable and configure it if you need to support ingoing emails.
MAIN_IMAP_USE_PHPIMAP=Use the PHP-IMAP library for IMAP instead of native PHP IMAP. This also allows the use of an OAuth2 connection for IMAP (module OAuth must also be activated).

View File

@@ -206,7 +206,8 @@ SubscriptionsStatistics=Contributions statistics
NbOfSubscriptions=Number of contributions
AmountOfSubscriptions=Amount collected from contributions
TurnoverOrBudget=Turnover (for a company) or Budget (for a foundation)
DefaultAmount=Default amount of contribution
DefaultAmount=Default amount of contribution (used only if no amount is defined at member type level)
MinimumAmount=Minimum amount (used only when contribution amount is free)
CanEditAmount=Subscription amount is free
CanEditAmountDetail=Visitor can choose/edit amount of its contribution regardless of the member type
AmountIsLowerToMinimumNotice=sur un dû total de %s

View File

@@ -31,8 +31,9 @@ OAUTH_GITHUB_SECRET=OAuth GitHub Secret
OAUTH_URL_FOR_CREDENTIAL=Go to <a class="notasortlink" href="%s" target="_blank" rel="noopener noreferrer external">this page<span class="fas fa-external-link-alt paddingleft"></span></a> to create or get your OAuth ID and Secret
OAUTH_STRIPE_TEST_NAME=OAuth Stripe Test
OAUTH_STRIPE_LIVE_NAME=OAuth Stripe Live
OAUTH_ID=OAuth ID
OAUTH_ID=OAuth Client ID
OAUTH_SECRET=OAuth secret
OAUTH_TENANT=OAuth tenant
OAuthProviderAdded=OAuth provider added
AOAuthEntryForThisProviderAndLabelAlreadyHasAKey=An OAuth entry for this provider and label already exists
URLOfServiceForAuthorization=URL provided by OAuth service for authentication

View File

@@ -2768,7 +2768,7 @@ function top_menu_search()
$buttonList .= '</div>';
$searchInput = '<input name="sall" id="top-global-search-input" class="dropdown-search-input" placeholder="'.$langs->trans('Search').'" autocomplete="off" >';
$searchInput = '<input name="search_all" id="top-global-search-input" class="dropdown-search-input" placeholder="'.$langs->trans('Search').'" autocomplete="off" >';
$dropDownHtml = '<form id="top-menu-action-search" name="actionsearch" method="GET" action="'.$defaultAction.'" >';

View File

@@ -201,13 +201,15 @@ if ($mode == 'setup' && $user->admin) {
$i++;
if ($key['varname'] == 'PRINTGCP_TOKEN_ACCESS') {
$keyforprovider = ''; // @BUG This must be set
// Token
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Token").'</td>';
print '<td colspan="2">';
$tokenobj = null;
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
$storage = new DoliStorage($db, $conf, $keyforprovider);
try {
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME_GOOGLE);
} catch (Exception $e) {

View File

@@ -684,7 +684,7 @@ print load_fiche_titre($langs->trans("NewRegistration"), '', '', 0, 0, 'center')
print '<div align="center">';
print '<div id="divsubscribe">';
print '<div class="center subscriptionformhelptext">';
print '<div class="center subscriptionformhelptext opacitymedium justify">';
// Welcome message

View File

@@ -30,11 +30,10 @@
*
* Note that you can add following constant to change behaviour of page
* MEMBER_NEWFORM_AMOUNT Default amount for auto-subscribe form
* MEMBER_NEWFORM_EDITAMOUNT 0 or 1 = Amount can be edited
* MEMBER_MIN_AMOUNT Minimum amount
* MEMBER_NEWFORM_PAYONLINE Suggest payment with paypal, paybox or stripe
* MEMBER_NEWFORM_DOLIBARRTURNOVER Show field turnover (specific for dolibarr foundation)
* MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once subscribe submitted
* MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once registration form has been submitted (hidden option, by default we just show a message on same page or redirect to the payment page)
* MEMBER_NEWFORM_FORCETYPE Force type of member
* MEMBER_NEWFORM_FORCEMORPHY Force nature of member (mor/phy)
* MEMBER_NEWFORM_FORCECOUNTRYCODE Force country
@@ -71,11 +70,12 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
// Init vars
$backtopage = GETPOST('backtopage', 'alpha');
$action = GETPOST('action', 'aZ09');
$errmsg = '';
$num = 0;
$error = 0;
$backtopage = GETPOST('backtopage', 'alpha');
$action = GETPOST('action', 'aZ09');
// Load translation files
$langs->loadLangs(array("main", "members", "companies", "install", "other", "errors"));
@@ -439,7 +439,7 @@ if (empty($reshook) && $action == 'add') {
}
if (!empty($conf->global->MEMBER_NEWFORM_PAYONLINE) && $conf->global->MEMBER_NEWFORM_PAYONLINE != '-1') {
if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { // If edition of amount not allowed
if (empty($adht->caneditamount)) { // If edition of amount not allowed
// TODO Check amount is same than the amount required for the type of member or if not defined as the defeault amount into $conf->global->MEMBER_NEWFORM_AMOUNT
// It is not so important because a test is done on return of payment validation.
}
@@ -457,15 +457,6 @@ if (empty($reshook) && $action == 'add') {
$urlback .= '&entity='.((int) $entity);
}
}
}
if (!empty($backtopage)) {
$urlback = $backtopage;
dol_syslog("member ".$adh->ref." was created, we redirect to ".$urlback);
} elseif (!empty($conf->global->MEMBER_URL_REDIRECT_SUBSCRIPTION)) {
$urlback = $conf->global->MEMBER_URL_REDIRECT_SUBSCRIPTION;
// TODO Make replacement of __AMOUNT__, etc...
dol_syslog("member ".$adh->ref." was created, we redirect to ".$urlback);
} else {
$error++;
$errmsg .= join('<br>', $adh->errors);
@@ -485,7 +476,7 @@ if (empty($reshook) && $action == 'add') {
}
// Action called after a submitted was send and member created successfully
// If MEMBER_URL_REDIRECT_SUBSCRIPTION is set to url we never go here because a redirect was done to this url.
// If MEMBER_URL_REDIRECT_SUBSCRIPTION is set to an url, we never go here because a redirect was done to this url. Same if we ask to redirect to the payment page.
// backtopage parameter with an url was set on member submit page, we never go here because a redirect was done to this url.
if (empty($reshook) && $action == 'added') {
@@ -522,7 +513,7 @@ print load_fiche_titre($langs->trans("NewSubscription"), '', '', 0, 0, 'center')
print '<div align="center">';
print '<div id="divsubscribe">';
print '<div class="center subscriptionformhelptext justify">';
print '<div class="center subscriptionformhelptext opacitymedium justify">';
if (!empty($conf->global->MEMBER_NEWFORM_TEXT)) {
print $langs->trans($conf->global->MEMBER_NEWFORM_TEXT)."<br>\n";
} else {
@@ -782,7 +773,7 @@ if (!empty($conf->global->MEMBER_SKIP_TABLE) || !empty($conf->global->MEMBER_NEW
$amount = $conf->global->MEMBER_NEWFORM_AMOUNT;
}
if (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT) || $caneditamount) {
if ($caneditamount) {
print '<input type="text" name="amount" id="amount" class="flat amount width50" value="'.$showedamount.'">';
print ' '.$langs->trans("Currency".$conf->currency).'<span class="opacitymedium"> ';
print $amount > 0 ? $langs->trans("AnyAmountWithAdvisedAmount", price($amount, 0, $langs, 1, -1, -1, $conf->currency)): $langs->trans("AnyAmountWithoutAdvisedAmount");
@@ -864,7 +855,7 @@ if (!empty($conf->global->MEMBER_SKIP_TABLE) || !empty($conf->global->MEMBER_NEW
$i = 0;
while ($i < $num) {
$objp = $db->fetch_object($result);
$objp = $db->fetch_object($result); // Load the member type and information on it
print '<tr class="oddeven">';
print '<td>'.dol_escape_htmltag($objp->label).'</td>';
@@ -874,7 +865,7 @@ if (!empty($conf->global->MEMBER_SKIP_TABLE) || !empty($conf->global->MEMBER_NEW
print '</td>';
print '<td class="center"><span class="amount nowrap">';
$displayedamount = max(intval($objp->amount), intval(getDolGlobalInt("MEMBER_MIN_AMOUNT")));
$caneditamount = !empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT) || $objp->caneditamount;
$caneditamount = $objp->caneditamount;
if ($objp->subscription) {
if ($displayedamount > 0 || !$caneditamount) {
print $displayedamount.' '.strtoupper($conf->currency);

View File

@@ -542,7 +542,7 @@ print load_fiche_titre($langs->trans("NewPartnershipRequest"), '', '', 0, 0, 'ce
print '<div align="center">';
print '<div id="divsubscribe">';
print '<div class="center subscriptionformhelptext justify">';
print '<div class="center subscriptionformhelptext opacitymedium justify">';
if (!empty($conf->global->PARTNERSHIP_NEWFORM_TEXT)) {
print $langs->trans($conf->global->PARTNERSHIP_NEWFORM_TEXT)."<br>\n";
} else {

View File

@@ -1635,7 +1635,7 @@ if ($source == 'member' || $source == 'membersubscription') {
$amount = max(0, $conf->global->MEMBER_MIN_AMOUNT, $amount);
}
print '<b class="amount">'.price($amount, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
$caneditamount = !empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT) || $adht->caneditamount;
$caneditamount = $adht->caneditamount;
$minimumamount = empty($conf->global->MEMBER_MIN_AMOUNT)? $adht->amount : max($conf->global->MEMBER_MIN_AMOUNT, $adht->amount > $amount);
if (!$caneditamount && $minimumamount > $amount) {
print ' '. $langs->trans("AmountIsLowerToMinimumNotice", price($adht->amount, 1, $langs, 1, -1, -1, $currency));
@@ -1753,13 +1753,13 @@ if ($source == 'donation') {
// Amount
print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
if (empty($amount)) {
if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
if (empty($conf->global->DONATION_NEWFORM_AMOUNT)) {
print ' ('.$langs->trans("ToComplete");
}
if (!empty($conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO)) {
print ' - <a href="'.$conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO.'" rel="external" target="_blank" rel="noopener noreferrer">'.$langs->trans("SeeHere").'</a>';
if (!empty($conf->global->DONATION_EXT_URL_SUBSCRIPTION_INFO)) {
print ' - <a href="'.$conf->global->DONATION_EXT_URL_SUBSCRIPTION_INFO.'" rel="external" target="_blank" rel="noopener noreferrer">'.$langs->trans("SeeHere").'</a>';
}
if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
if (empty($conf->global->DONATION_NEWFORM_AMOUNT)) {
print ')';
}
}
@@ -1769,21 +1769,21 @@ if ($source == 'donation') {
$valtoshow = price2num(GETPOST("newamount", 'alpha'), 'MT');
// force default subscription amount to value defined into constant...
if (empty($valtoshow)) {
if (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) {
if (!empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
$valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT;
if (!empty($conf->global->DONATION_NEWFORM_EDITAMOUNT)) {
if (!empty($conf->global->DONATION_NEWFORM_AMOUNT)) {
$valtoshow = $conf->global->DONATION_NEWFORM_AMOUNT;
}
} else {
if (!empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
$amount = $conf->global->MEMBER_NEWFORM_AMOUNT;
if (!empty($conf->global->DONATION_NEWFORM_AMOUNT)) {
$amount = $conf->global->DONATION_NEWFORM_AMOUNT;
}
}
}
}
if (empty($amount) || !is_numeric($amount)) {
//$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT');
if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) {
$valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow);
if (!empty($conf->global->DONATION_MIN_AMOUNT) && $valtoshow) {
$valtoshow = max($conf->global->DONATION_MIN_AMOUNT, $valtoshow);
}
print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
print '<input class="flat maxwidth75" type="text" name="newamount" value="'.$valtoshow.'">';
@@ -1791,8 +1791,8 @@ if ($source == 'donation') {
print ' <b>'.$langs->trans("Currency".$currency).'</b>';
} else {
$valtoshow = $amount;
if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) {
$valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow);
if (!empty($conf->global->DONATION_MIN_AMOUNT) && $valtoshow) {
$valtoshow = max($conf->global->DONATION_MIN_AMOUNT, $valtoshow);
$amount = $valtoshow;
}
print '<b class="amount">'.price($valtoshow, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency

View File

@@ -452,7 +452,7 @@ if ($ispaymentok) {
// Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time)
if (!empty($FinalPaymentAmt) && $paymentTypeId > 0) {
// Security protection:
if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { // If we didn't allow members to choose their membership amount (if free amount is allowed, no need to check)
if (empty($adht->caneditamount)) { // If we didn't allow members to choose their membership amount (if the amount is allowed in edit mode, no need to check)
if ($object->status == $object::STATUS_DRAFT) { // If the member is not yet validated, we check that the amount is the same as expected.
$typeid = $object->typeid;

View File

@@ -414,7 +414,6 @@ if (empty($reshook) && $action == 'add') {
}
// Action called after a submitted was send and member created successfully
// If MEMBER_URL_REDIRECT_SUBSCRIPTION is set to url we never go here because a redirect was done to this url.
// backtopage parameter with an url was set on member submit page, we never go here because a redirect was done to this url.
if (empty($reshook) && $action == 'added') {
llxHeaderVierge($langs->trans("NewLeadForm"));
@@ -449,7 +448,7 @@ print load_fiche_titre($langs->trans("NewContact"), '', '', 0, 0, 'center');
print '<div align="center">';
print '<div id="divsubscribe">';
print '<div class="center subscriptionformhelptext justify">';
print '<div class="center subscriptionformhelptext opacitymedium justify">';
if (!empty($conf->global->PROJECT_NEWFORM_TEXT)) {
print $langs->trans($conf->global->PROJECT_NEWFORM_TEXT)."<br>\n";
} else {

View File

@@ -562,7 +562,7 @@ print load_fiche_titre($langs->trans("NewSuggestionOfBooth"), '', '', 0, 0, 'cen
print '<div align="center">';
print '<div id="divsubscribe">';
print '<div class="center subscriptionformhelptext justify">';
print '<div class="center subscriptionformhelptext opacitymedium justify">';
dol_htmloutput_errors($errmsg);

View File

@@ -495,7 +495,7 @@ print load_fiche_titre($langs->trans("NewSuggestionOfConference"), '', '', 0, 0,
print '<div align="center">';
print '<div id="divsubscribe">';
print '<div class="center subscriptionformhelptext justify">';
print '<div class="center subscriptionformhelptext opacitymedium justify">';
dol_htmloutput_errors($errmsg, $errors);

View File

@@ -2295,7 +2295,7 @@ class Ticket extends CommonObject
$maxheightmini = 72;
$formmail = new FormMail($this->db);
$formmail->trackid = 'tic'.$this->id;
$attachedfiles = $formmail->get_attached_files();
$filepath = $attachedfiles['paths'];
@@ -2469,7 +2469,7 @@ class Ticket extends CommonObject
$assigned_user = new User($this->db);
$assigned_user->fetch($this->fk_user_assign);
if (!empty($assigned_user->email)) {
$sendto[] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
$sendto[$assigned_user->email] = $assigned_user->getFullName($langs)." <".$assigned_user->email.">";
} else {
$assigned_user_dont_have_email = $assigned_user->getFullName($langs);
}
@@ -2491,17 +2491,17 @@ class Ticket extends CommonObject
if (empty($sendto)) {
if (!empty($conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL)) {
$sendto[] = $conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL;
$sendto[$conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL] = $conf->global->TICKET_PUBLIC_NOTIFICATION_NEW_MESSAGE_DEFAULT_EMAIL;
} elseif (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
$sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
$sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
}
}
// Add global email address recipient
if (!empty($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS) &&
!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)
!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO) && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)
) {
$sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
$sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
}
if (!empty($sendto)) {
@@ -2585,7 +2585,7 @@ class Ticket extends CommonObject
if ($info_sendto['email'] != '') {
if (!empty($info_sendto['email'])) {
$sendto[] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
$sendto[$info_sendto['email']] = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'])." <".$info_sendto['email'].">";
}
// Contact type
@@ -2601,9 +2601,9 @@ class Ticket extends CommonObject
$message .= '<br>'.$langs->trans('TicketNotificationEmailBodyInfosTrackUrlinternal').' : <a href="'.$url_internal_ticket.'">'.$object->track_id.'</a><br>';
// Add global email address recipient
if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
$sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
$sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
}
}
@@ -2664,7 +2664,7 @@ class Ticket extends CommonObject
if ($info_sendto['email'] != '' && $info_sendto['email'] != $object->origin_email) {
if (!empty($info_sendto['email'])) {
$sendto[] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
$sendto[$info_sendto['email']] = trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">";
}
$recipient = dolGetFirstLastname($info_sendto['firstname'], $info_sendto['lastname'], '-1').' ('.strtolower($info_sendto['libelle']).')';
@@ -2684,21 +2684,21 @@ class Ticket extends CommonObject
$message .= '<br>'.$message_signature;
if (!empty($object->origin_email)) {
$sendto[] = $object->origin_email;
$sendto[$object->origin_email] = $object->origin_email;
}
if ($object->fk_soc > 0 && !in_array($object->origin_email, $sendto)) {
if ($object->fk_soc > 0 && !array_key_exists($object->origin_email, $sendto)) {
$object->socid = $object->fk_soc;
$object->fetch_thirdparty();
if (!empty($object->thirdparty->email)) {
$sendto[] = $object->thirdparty->email;
$sendto[$object->thirdparty->email] = $object->thirdparty->email;
}
}
// Add global email address recipient
if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !in_array($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
if ($conf->global->TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS && !array_key_exists($conf->global->TICKET_NOTIFICATION_EMAIL_TO, $sendto)) {
if (!empty($conf->global->TICKET_NOTIFICATION_EMAIL_TO)) {
$sendto[] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
$sendto[$conf->global->TICKET_NOTIFICATION_EMAIL_TO] = $conf->global->TICKET_NOTIFICATION_EMAIL_TO;
}
}

View File

@@ -2803,7 +2803,7 @@ if (!GETPOST('hide_websitemenu')) {
$atleastonepage = (is_array($array) && count($array) > 0);
$websitepage = new WebSitePage($db);
if ($pageid > 0 && ($action == 'preview' || $action == 'createfromclone' || $action == 'createpagefromclone')) {
if ($pageid > 0) {
$websitepage->fetch($pageid);
}