mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2025-12-05 09:08:09 +01:00
Merge pull request #33156 from Daoud-mohamed/init-external-modules-class
NEW Init externalModules Class to Fetch Modules from Multiple Sources
This commit is contained in:
@@ -42,6 +42,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/admin/remotestore/class/dolistore.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/admin/remotestore/class/externalModules.class.php';
|
||||
|
||||
'
|
||||
@phan-var-force string $dolibarr_main_url_root_alt
|
||||
@@ -81,15 +82,15 @@ $search_version = GETPOST('search_version', 'alpha');
|
||||
|
||||
|
||||
// For remotestore search
|
||||
$options = array();
|
||||
$options['per_page'] = 10;
|
||||
$options['categorie'] = ((int) (GETPOSTINT('categorie') ? GETPOSTINT('categorie') : 0));
|
||||
$options['start'] = ((int) (GETPOSTINT('start') ? GETPOSTINT('start') : 0));
|
||||
$options['end'] = ((int) (GETPOSTINT('end') ? GETPOSTINT('end') : 0));
|
||||
$options['search'] = GETPOST('search_keyword', 'alpha');
|
||||
|
||||
$remotestore = new Dolistore(false);
|
||||
$options = array();
|
||||
$options['per_page'] = 10;
|
||||
$options['no_page'] = ((int) GETPOSTINT('no_page') ? GETPOSTINT('no_page') : 1);
|
||||
$options['categorie'] = ((int) (GETPOSTINT('categorie') ? GETPOSTINT('categorie') : 0));
|
||||
$options['search'] = GETPOST('search_keyword', 'alpha');
|
||||
$options['source'] = GETPOST('source', 'alpha');
|
||||
|
||||
//$remotestore = new Dolistore(false);
|
||||
$remotestore = new ExternalModules();
|
||||
|
||||
if (!$user->admin) {
|
||||
accessforbidden();
|
||||
@@ -1246,7 +1247,7 @@ if ($mode == 'marketplace') {
|
||||
|
||||
print '<br>';
|
||||
|
||||
// Marketplace
|
||||
// Marketplace and community modules
|
||||
print '<div class="div-table-responsive-no-min">';
|
||||
print '<table summary="list_of_modules" class="noborder centpercent">'."\n";
|
||||
print '<tr class="liste_titre">'."\n";
|
||||
@@ -1255,6 +1256,7 @@ if ($mode == 'marketplace') {
|
||||
print '<td>'.$langs->trans("URL").'</td>';
|
||||
print '</tr>';
|
||||
|
||||
// Marketplace
|
||||
print '<tr class="oddeven">'."\n";
|
||||
$url = 'https://www.dolistore.com';
|
||||
print '<td class="hideonsmartphone"><a href="'.$url.'" target="_blank" rel="noopener noreferrer external"><img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolistore_logo.png"></a></td>';
|
||||
@@ -1262,6 +1264,14 @@ if ($mode == 'marketplace') {
|
||||
print '<td><a href="'.$url.'" target="_blank" rel="noopener noreferrer external">'.$url.'</a></td>';
|
||||
print '</tr>';
|
||||
|
||||
// Community
|
||||
print '<tr class="oddeven">'."\n";
|
||||
$url = 'https://github.com/Dolibarr/dolibarr-community-modules';
|
||||
print '<td class="hideonsmartphone"><a href="'.$url.'" target="_blank" rel="noopener noreferrer external"><img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolibarr_logo.png"></a></td>';
|
||||
print '<td><span class="opacitymedium">'.$langs->trans("CommunityModulesDesc").'</span></td>';
|
||||
print '<td><a href="'.$url.'" target="_blank" rel="noopener noreferrer external">'.$url.'</a></td>';
|
||||
print '</tr>';
|
||||
|
||||
print "</table>\n";
|
||||
print '</div>';
|
||||
|
||||
@@ -1278,11 +1288,16 @@ if ($mode == 'marketplace') {
|
||||
$nbmaxtoshow = $options['per_page'];
|
||||
$options['per_page']++;
|
||||
|
||||
$remotestore->getRemoteCategories();
|
||||
$remotestore->getRemoteProducts($options);
|
||||
//$remotestore->getRemoteCategories();
|
||||
//$remotestore->getRemoteProducts($options);
|
||||
|
||||
print '<span class="opacitymedium">'.$langs->trans('DOLISTOREdescriptionLong').'</span><br><br>';
|
||||
|
||||
//$previouslink = $remotestore->get_previous_link();
|
||||
//$nextlink = $remotestore->get_next_link();
|
||||
|
||||
$categories_tree = $remotestore->getCategories();
|
||||
$products_list = $remotestore->getProducts($options);
|
||||
$previouslink = $remotestore->get_previous_link();
|
||||
$nextlink = $remotestore->get_next_link();
|
||||
|
||||
@@ -1292,7 +1307,14 @@ if ($mode == 'marketplace') {
|
||||
<input type="hidden" name="token" value="<?php echo newToken(); ?>">
|
||||
<input type="hidden" name="mode" value="marketplace">
|
||||
<div class="divsearchfield">
|
||||
<input name="search_keyword" placeholder="<?php echo $langs->trans('Keyword') ?>" id="search_keyword" type="text" class="minwidth200" value="<?php echo dol_escape_htmltag($options['search']) ?>"><br>
|
||||
<input name="search_keyword" placeholder="<?php echo $langs->trans('Keyword') ?>" id="search_keyword" type="text" class="minwidth200" value="<?php echo dol_escape_htmltag($options['search']) ?>">
|
||||
<!-- Add a check box to filter by source -->
|
||||
<!-- <input type="checkbox" name="search_source" id="search_source_dolistore" value="dolistore" <?php if ($options['source'] == 'dolistore') { echo 'checked'; } ?>>
|
||||
<label for="search_source_dolistore"><?php echo "Dolistore"; ?></label>
|
||||
<input type="checkbox" name="search_source" id="search_source_github" value="github" <?php if ($options['source'] == 'github') { echo 'checked'; } ?>>
|
||||
<label for="search_source_github"><?php echo "Github"; ?></label> -->
|
||||
<br>
|
||||
|
||||
</div>
|
||||
<div class="divsearchfield">
|
||||
<input class="button buttongen" value="<?php echo $langs->trans('Rechercher') ?>" type="submit">
|
||||
@@ -1311,15 +1333,16 @@ if ($mode == 'marketplace') {
|
||||
|
||||
<div id="category-tree-left">
|
||||
<ul class="tree">
|
||||
<?php
|
||||
echo $remotestore->get_categories(); // Do not use dol_escape_htmltag here, it is already a structured content?>
|
||||
<?php
|
||||
print $categories_tree; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="listing-content">
|
||||
<table summary="list_of_modules" id="list_of_modules" class="productlist centpercent">
|
||||
<tbody id="listOfModules">
|
||||
<?php echo $remotestore->get_products($nbmaxtoshow); ?>
|
||||
<?php //echo $remotestore->get_products($nbmaxtoshow); ?>
|
||||
<?php print $products_list; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
526
htdocs/admin/remotestore/class/externalModules.class.php
Normal file
526
htdocs/admin/remotestore/class/externalModules.class.php
Normal file
@@ -0,0 +1,526 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2025 Mohamed DAOUD <mdaoud@dolicloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modifyion 2.0 (the "License");
|
||||
* it under the terms of the GNU General Public License as published bypliance with the License.
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* or see https://www.gnu.org/
|
||||
*/
|
||||
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
||||
|
||||
/**
|
||||
* Class ExternalModules
|
||||
*/
|
||||
class ExternalModules
|
||||
{
|
||||
/**
|
||||
* @var int Pagination: current page
|
||||
*/
|
||||
public $no_page;
|
||||
|
||||
/**
|
||||
* @var int Pagination: display per page
|
||||
*/
|
||||
public $per_page;
|
||||
/**
|
||||
* @var int The current categorie
|
||||
*/
|
||||
public $categorie;
|
||||
|
||||
/**
|
||||
* @var string The search keywords
|
||||
*/
|
||||
public $search;
|
||||
|
||||
// setups
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $url; // the url of this page
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $shop_url; // the url of the shop
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $lang; // the integer representing the lang in the store
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $debug_api; // useful if no dialog
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $dolistore_api_url;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $dolistore_api_key;
|
||||
|
||||
/**
|
||||
* @var array<int, mixed>|null
|
||||
*/
|
||||
public $products;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param boolean $debug Enable debug of request on screen
|
||||
*/
|
||||
public function __construct($debug = false)
|
||||
{
|
||||
global $langs;
|
||||
|
||||
$this->dolistore_api_url = getDolGlobalString('MAIN_MODULE_DOLISTORE_API_SRV');
|
||||
$this->dolistore_api_key = getDolGlobalString('MAIN_MODULE_DOLISTORE_API_KEY');
|
||||
|
||||
$this->url = DOL_URL_ROOT.'/admin/modules.php?mode=marketplace';
|
||||
$this->shop_url = 'https://www.dolistore.com/product.php?id=';
|
||||
$this->debug_api = $debug;
|
||||
|
||||
$lang = $langs->defaultlang;
|
||||
$lang_array = array('en_US', 'fr_FR', 'es_ES', 'it_IT', 'de_DE');
|
||||
if (!in_array($lang, $lang_array)) {
|
||||
$lang = 'en_US';
|
||||
}
|
||||
$this->lang = $lang;
|
||||
|
||||
// TODO check access to all remote sources and define valid one
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if we can access to remote Dolistore market place.
|
||||
*
|
||||
* @param string $resource Resource name
|
||||
* @param array<string, mixed>|false $options Options for the request
|
||||
*
|
||||
* @return array{status_code:int,response:?string,header:string}
|
||||
*/
|
||||
public function callApi($resource, $options = false)
|
||||
{
|
||||
|
||||
// If no dolistore_api_key is set, we can't access the API
|
||||
if (empty($this->dolistore_api_key) || empty($this->dolistore_api_url)) {
|
||||
return array('status_code' => 0, 'response' => null, 'header' => '');
|
||||
}
|
||||
|
||||
$curl = curl_init();
|
||||
$httpheader = ['DOLAPIKEY: '.$this->dolistore_api_key];
|
||||
|
||||
// Add basic auth if needed
|
||||
$basicAuthLogin = getDolGlobalString('MAIN_MODULE_DOLISTORE_BASIC_LOGIN');
|
||||
$basicAuthPassword = getDolGlobalString('MAIN_MODULE_DOLISTORE_BASIC_PASSWORD');
|
||||
|
||||
if (!empty($basicAuthLogin) && !empty($basicAuthPassword)) {
|
||||
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
$login = getDolGlobalString('MAIN_MODULE_DOLISTORE_BASIC_LOGIN');
|
||||
$password = getDolGlobalString('MAIN_MODULE_DOLISTORE_BASIC_PASSWORD');
|
||||
curl_setopt($curl, CURLOPT_USERPWD, $login . ':' . $password);
|
||||
}
|
||||
|
||||
$url = $this->dolistore_api_url . $resource;
|
||||
|
||||
if ($options) {
|
||||
$url .= '?' . http_build_query($options);
|
||||
}
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $httpheader);
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
if ($response === false) {
|
||||
return array('status_code' => 0, 'response' => 'CURL Error: ' . curl_error($curl), 'header' => '');
|
||||
}
|
||||
|
||||
$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($response, 0, $header_size);
|
||||
$body = substr($response, $header_size);
|
||||
|
||||
// convert body to array if it is json
|
||||
if (strpos($header, 'Content-Type: application/json') !== false) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
$status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
curl_close($curl);
|
||||
|
||||
return array('status_code' => $status_code, 'response' => $body, 'header' => $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTML for categories and their children.
|
||||
*
|
||||
* @return string HTML string representing the categories and their children.
|
||||
*/
|
||||
public function getCategories()
|
||||
{
|
||||
$organized_tree = array();
|
||||
$html = '';
|
||||
|
||||
$data = [
|
||||
'lang' => $this->lang
|
||||
];
|
||||
|
||||
$resCategories = $this->callApi('categories', $data);
|
||||
if (isset($resCategories['response']) && is_array($resCategories['response'])) {
|
||||
$organized_tree = $resCategories['response'];
|
||||
} else {
|
||||
return $html ;
|
||||
}
|
||||
|
||||
// TODO call all sources and merge them
|
||||
|
||||
$html = '';
|
||||
foreach ($organized_tree as $key => $value) {
|
||||
if ($value['label'] != "Versions" && $value['label'] != "Specials") {
|
||||
$html .= '<li>';
|
||||
$html .= '<a href="?mode=marketplace&categorie=' . $value['rowid'] . '">' . $value['label'] . '</a>';
|
||||
if (isset($value['children'])) {
|
||||
$html .= '<ul>';
|
||||
usort($value['children'], $this->buildSorter('position'));
|
||||
foreach ($value['children'] as $key_children => $value_children) {
|
||||
$html .= '<li>';
|
||||
$html .= '<a href="?mode=marketplace&categorie=' . $value_children['rowid'] . '" title="' . dol_escape_htmltag(strip_tags($value_children['description'])) . '">' . $value_children['label'] . '</a>';
|
||||
$html .= '</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
}
|
||||
$html .= '</li>';
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTML for products.
|
||||
* @param array<string, mixed> $options Options for the request
|
||||
* @return string|null HTML string representing the products.
|
||||
*/
|
||||
public function getProducts($options)
|
||||
{
|
||||
|
||||
global $langs;
|
||||
|
||||
// TODO call all sources and merge them
|
||||
|
||||
$html = "";
|
||||
$last_month = dol_now() - (30 * 24 * 60 * 60);
|
||||
$dolibarrversiontouse = DOL_VERSION;
|
||||
$urldolibarrmodules = 'https://www.dolistore.com';
|
||||
|
||||
$this->products = array();
|
||||
|
||||
$this->categorie = $options['categorie'] ?? 0;
|
||||
$this->per_page = $options['per_page'] ?? 11;
|
||||
$this->no_page = $options['no_page'] ?? 1;
|
||||
$this->search = $options['search'] ?? '';
|
||||
|
||||
$data = [
|
||||
'categorieid' => $this->categorie,
|
||||
'limit' => $this->per_page,
|
||||
'page' => $this->no_page,
|
||||
'search' => $this->search,
|
||||
'lang' => $this->lang
|
||||
];
|
||||
|
||||
$resProducts = $this->callApi('products', $data);
|
||||
if (!isset($resProducts['response']) || !is_array($resProducts['response']) || ($resProducts['status_code'] != 200 && $resProducts['status_code'] != 201)) {
|
||||
$html = $this->checkStatusCode($resProducts);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
$this->products = $resProducts['response'];
|
||||
|
||||
$i = 0;
|
||||
foreach ($this->products as $product) {
|
||||
$i++;
|
||||
|
||||
// check new product ?
|
||||
$newapp = '';
|
||||
if ($last_month < strtotime($product['datec'])) {
|
||||
$newapp .= '<span class="newApp">'.$langs->trans('New').'</span> ';
|
||||
}
|
||||
|
||||
// check updated ?
|
||||
if ($last_month < strtotime($product['tms']) && $newapp == '') {
|
||||
$newapp .= '<span class="updatedApp">'.$langs->trans('Updated').'</span> ';
|
||||
}
|
||||
|
||||
// add image or default ?
|
||||
if ($product["cover_photo_url"] != '') {
|
||||
$images = '<a href="'.$product["cover_photo_url"].'" class="documentpreview" target="_blank" rel="noopener noreferrer" mime="image/png" title="'.dol_escape_htmltag($product["label"].', '.$langs->trans('Version').' '.$product["module_version"]).'">';
|
||||
$images .= '<img class="imgstore" src="'.$urldolibarrmodules.$product["cover_photo_url"].'" alt="" /></a>';
|
||||
} else {
|
||||
$images = '<img class="imgstore" src="'.DOL_URL_ROOT.'/admin/dolistore/img/NoImageAvailable.png" />';
|
||||
}
|
||||
|
||||
// free or pay ?
|
||||
if ($product["price_ttc"] > 0) {
|
||||
$price = '<h3>'.price(price2num($product["price_ttc"], 'MT'), 0, $langs, 1, -1, -1, 'EUR').' '.$langs->trans("TTC").'</h3>';
|
||||
$download_link = '<a target="_blank" href="'.$this->shop_url.urlencode($product['id']).'"><img width="32" src="'.DOL_URL_ROOT.'/admin/remotestore/img/follow.png" /></a>';
|
||||
} else {
|
||||
$price = '<h3>'.$langs->trans('Free').'</h3>';
|
||||
$download_link = '<a class="paddingleft paddingright" target="_blank" href="'.$this->shop_url.urlencode($product["id"]).'"><img width="32" src="'.DOL_URL_ROOT.'/admin/remotestore/img/follow.png" /></a>';
|
||||
$download_link .= '<a class="paddingleft paddingright" target="_blank" href="'.$urldolibarrmodules.$product["download_link"].'" rel="noopener noreferrer"><img width="32" src="'.DOL_URL_ROOT.'/admin/remotestore/img/Download-128.png" /></a>';
|
||||
}
|
||||
|
||||
// Set and check version
|
||||
$version = '';
|
||||
if ($this->version_compare($product["dolibarr_min"], $dolibarrversiontouse) <= 0) {
|
||||
if ($this->version_compare($product["dolibarr_max"], $dolibarrversiontouse) >= 0) {
|
||||
//compatible
|
||||
$version = '<span class="compatible">'.$langs->trans(
|
||||
'CompatibleUpTo',
|
||||
$product["dolibarr_max"],
|
||||
$product["dolibarr_min"],
|
||||
$product["dolibarr_max"]
|
||||
).'</span>';
|
||||
$compatible = '';
|
||||
} else {
|
||||
//never compatible, module expired
|
||||
$version = '<span class="notcompatible">'.$langs->trans(
|
||||
'NotCompatible',
|
||||
$dolibarrversiontouse,
|
||||
$product["dolibarr_min"],
|
||||
$product["dolibarr_max"]
|
||||
).'</span>';
|
||||
$compatible = 'NotCompatible';
|
||||
}
|
||||
} else {
|
||||
//need update
|
||||
$version = '<span class="compatibleafterupdate">'.$langs->trans(
|
||||
'CompatibleAfterUpdate',
|
||||
$dolibarrversiontouse,
|
||||
$product["dolibarr_min"],
|
||||
$product["dolibarr_max"]
|
||||
).'</span>';
|
||||
$compatible = 'NotCompatible';
|
||||
}
|
||||
|
||||
//output template
|
||||
$html .= '<tr class="app oddeven '.dol_escape_htmltag($compatible).'">';
|
||||
$html .= '<td class="center" width="160"><div class="newAppParent">';
|
||||
$html .= $newapp.$images; // No dol_escape_htmltag, it is already escape html
|
||||
$html .= '</div></td>';
|
||||
$html .= '<td class="margeCote"><h2 class="appTitle">';
|
||||
$html .= dol_escape_htmltag(dol_string_nohtmltag($product["label"]));
|
||||
$html .= '<br><small>';
|
||||
$html .= $version; // No dol_escape_htmltag, it is already escape html
|
||||
$html .= '</small></h2>';
|
||||
$html .= '<small> '.dol_print_date(dol_stringtotime($product['tms']), 'dayhour').' - '.$langs->trans('Ref').': '.dol_escape_htmltag($product["ref"]).' - '.dol_escape_htmltag($langs->trans('Id')).': '.((int) $product["id"]).'</small><br>';
|
||||
$html .= '<br>'.dol_escape_htmltag(dol_string_nohtmltag($product["description"]));
|
||||
$html.= '</td>';
|
||||
// do not load if display none
|
||||
$html .= '<td class="margeCote center amount">';
|
||||
$html .= $price;
|
||||
$html .= '</td>';
|
||||
$html .= '<td class="margeCote nowraponall">'.$download_link.'</td>';
|
||||
$html .= '</tr>';
|
||||
}
|
||||
|
||||
if (empty($this->products)) {
|
||||
$html .= '<tr class=""><td colspan="3" class="center">';
|
||||
$html .= '<br><br>';
|
||||
$langs->load("website");
|
||||
$html .= $langs->trans("noResultsWereFound").'...';
|
||||
$html .= '<br><br>';
|
||||
$html .= '</td></tr>';
|
||||
}
|
||||
|
||||
if (count($this->products) > $data['limit']) {
|
||||
$html .= '<tr class=""><td colspan="3" class="center">';
|
||||
$html .= '<br><br>';
|
||||
$html .= $langs->trans("ThereIsMoreThanXAnswers", $data["limit"]).'...';
|
||||
$html .= '<br><br>';
|
||||
$html .= '</td></tr>';
|
||||
}
|
||||
|
||||
|
||||
return $html ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort an array by a key
|
||||
* @param string $key Key to sort by
|
||||
*
|
||||
* @return Closure(array<string, mixed>, array<string, mixed>): int
|
||||
*/
|
||||
public function buildSorter(string $key): Closure
|
||||
{
|
||||
return
|
||||
/**
|
||||
* @param array<string, mixed> $a
|
||||
* @param array<string, mixed> $b
|
||||
* @return int
|
||||
*/
|
||||
function (array $a, array $b) use ($key) {
|
||||
$valA = isset($a[$key]) && is_scalar($a[$key]) ? (string) $a[$key] : '';
|
||||
$valB = isset($b[$key]) && is_scalar($b[$key]) ? (string) $b[$key] : '';
|
||||
|
||||
return strnatcmp($valA, $valB);
|
||||
};
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||
/**
|
||||
* version compare
|
||||
*
|
||||
* @param string $v1 version 1
|
||||
* @param string $v2 version 2
|
||||
* @return int result of compare
|
||||
*/
|
||||
public function version_compare($v1, $v2)
|
||||
{
|
||||
// phpcs:enable
|
||||
$v1 = explode('.', $v1);
|
||||
$v2 = explode('.', $v2);
|
||||
$ret = 0;
|
||||
$level = 0;
|
||||
$count1 = count($v1);
|
||||
$count2 = count($v2);
|
||||
$maxcount = max($count1, $count2);
|
||||
while ($level < $maxcount) {
|
||||
$operande1 = isset($v1[$level]) ? $v1[$level] : 'x';
|
||||
$operande2 = isset($v2[$level]) ? $v2[$level] : 'x';
|
||||
$level++;
|
||||
if (strtoupper($operande1) == 'X' || strtoupper($operande2) == 'X' || $operande1 == '*' || $operande2 == '*') {
|
||||
break;
|
||||
}
|
||||
if ($operande1 < $operande2) {
|
||||
$ret = -$level;
|
||||
break;
|
||||
}
|
||||
if ($operande1 > $operande2) {
|
||||
$ret = $level;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//print join('.',$versionarray1).'('.count($versionarray1).') / '.join('.',$versionarray2).'('.count($versionarray2).') => '.$ret.'<br>'."\n";
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||
/**
|
||||
* get previous link
|
||||
*
|
||||
* @param string $text symbol previous
|
||||
* @return string html previous link
|
||||
*/
|
||||
public function get_previous_link($text = '<<')
|
||||
{
|
||||
// phpcs:enable
|
||||
return '<a href="'.$this->get_previous_url().'" class="button">'.dol_escape_htmltag($text).'</a>';
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||
/**
|
||||
* get next link
|
||||
*
|
||||
* @param string $text symbol next
|
||||
* @return string html next link
|
||||
*/
|
||||
public function get_next_link($text = '>>')
|
||||
{
|
||||
// phpcs:enable
|
||||
return '<a href="'.$this->get_next_url().'" class="button">'.dol_escape_htmltag($text).'</a>';
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||
/**
|
||||
* get previous url
|
||||
*
|
||||
* @return string previous url
|
||||
*/
|
||||
public function get_previous_url()
|
||||
{
|
||||
// phpcs:enable
|
||||
$param_array = array();
|
||||
if ($this->no_page > 1) {
|
||||
$sub = 1;
|
||||
} else {
|
||||
$sub = 0;
|
||||
}
|
||||
$param_array['no_page'] = $this->no_page - $sub;
|
||||
if ($this->categorie != 0) {
|
||||
$param_array['categorie'] = $this->categorie;
|
||||
}
|
||||
$param = http_build_query($param_array);
|
||||
return $this->url."&".$param;
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||
/**
|
||||
* get next url
|
||||
*
|
||||
* @return string next url
|
||||
*/
|
||||
public function get_next_url()
|
||||
{
|
||||
// phpcs:enable
|
||||
$param_array = array();
|
||||
if ($this->products !== null && count($this->products) < $this->per_page) {
|
||||
$add = 0;
|
||||
} else {
|
||||
$add = 1;
|
||||
}
|
||||
$param_array['no_page'] = $this->no_page + $add;
|
||||
if ($this->categorie != 0) {
|
||||
$param_array['categorie'] = $this->categorie;
|
||||
}
|
||||
$param = http_build_query($param_array);
|
||||
return $this->url."&".$param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the status code of the request
|
||||
*
|
||||
* @param array{status_code:int,response:null|string|array{errors:array{code:int,message:string}[]},header:string} $request Response elements of CURL request
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function checkStatusCode($request)
|
||||
{
|
||||
// Define error messages
|
||||
$error_messages = [
|
||||
204 => 'No content',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
500 => 'Internal Server Error',
|
||||
];
|
||||
|
||||
// If status code is 200 or 201, return an empty string
|
||||
if ($request['status_code'] === 200 || $request['status_code'] === 201) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the predefined error message or use a default one
|
||||
$error_message = $error_messages[$request['status_code']] ?? 'Unexpected HTTP status: ' . $request['status_code'];
|
||||
|
||||
// Append error details if available
|
||||
if (!empty($request['response']) && isset($request['response']['errors']) && is_array($request['response']['errors'])) {
|
||||
foreach ($request['response']['errors'] as $error) {
|
||||
$error_message .= ' - (Code ' . $error['code'] . '): ' . $error['message'];
|
||||
}
|
||||
}
|
||||
|
||||
// Return the formatted error message
|
||||
return sprintf('This call to the API failed and returned an HTTP status of %d. That means: %s.', $request['status_code'], $error_message);
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ div.divsearchfield {
|
||||
margin: 0px 0px 0px 0px;
|
||||
padding:0px;
|
||||
list-style: none; line-height: 2em; font-family: Arial;
|
||||
margin-left: 15px;
|
||||
}
|
||||
.tree li{
|
||||
font-size: 16px;
|
||||
|
||||
@@ -234,6 +234,7 @@ Updated=Updated
|
||||
AchatTelechargement=Buy / Download
|
||||
GoModuleSetupArea=To deploy/install a new module, go to the Module setup area: <a href="%s">%s</a>.
|
||||
DoliStoreDesc=DoliStore, the official market place for Dolibarr ERP/CRM external modules
|
||||
CommunityModulesDesc=dolibarr-community-modules, This repository contains all community modules for Dolibarr ERP CRM.
|
||||
DoliPartnersDesc=List of companies providing custom-developed modules or features.<br>Note: since Dolibarr is an open source application, <i>anyone</i> experienced in PHP programming should be able to develop a module.
|
||||
WebSiteDesc=External websites for more add-on (non-core) modules...
|
||||
DevelopYourModuleDesc=Some solutions to develop your own module...
|
||||
|
||||
Reference in New Issue
Block a user