Fix API was loading definition of all APIs at each call.

This commit is contained in:
Laurent Destailleur 2017-06-25 17:09:08 +02:00
parent 025db4ac97
commit 63dcdc3a03
6 changed files with 272 additions and 173 deletions

View File

@ -40,7 +40,7 @@ class Login
* *
* @param string $login User login * @param string $login User login
* @param string $password User password * @param string $password User password
* @param int $entity Entity (when multicompany module is used). Empty means 1=first company. * @param string $entity Entity (when multicompany module is used). '' means 1=first company.
* @param int $reset Reset token (0=get current token, 1=ask a new token and canceled old token. This means access using current existing API token of user will fails: new token will be required for new access) * @param int $reset Reset token (0=get current token, 1=ask a new token and canceled old token. This means access using current existing API token of user will fails: new token will be required for new access)
* @return array Response status and user token * @return array Response status and user token
* *
@ -49,7 +49,7 @@ class Login
* @url GET / * @url GET /
* @url POST / * @url POST /
*/ */
public function index($login, $password, $entity=0, $reset=0) { public function index($login, $password, $entity='', $reset=0) {
global $conf, $dolibarr_main_authentication, $dolibarr_auto_user; global $conf, $dolibarr_main_authentication, $dolibarr_auto_user;
@ -62,6 +62,8 @@ class Login
// Set authmode // Set authmode
$authmode = explode(',', $dolibarr_main_authentication); $authmode = explode(',', $dolibarr_main_authentication);
if ($entity == '') $entity=1;
include_once DOL_DOCUMENT_ROOT . '/core/lib/security2.lib.php'; include_once DOL_DOCUMENT_ROOT . '/core/lib/security2.lib.php';
$login = checkLoginPassEntity($login, $password, $entity, $authmode); $login = checkLoginPassEntity($login, $password, $entity, $authmode);
if (empty($login)) if (empty($login))
@ -72,7 +74,7 @@ class Login
$token = 'failedtogenerateorgettoken'; $token = 'failedtogenerateorgettoken';
$tmpuser=new User($this->db); $tmpuser=new User($this->db);
$tmpuser->fetch(0, $login); $tmpuser->fetch(0, $login, 0, 0, $entity);
// Renew the hash // Renew the hash
if (empty($tmpuser->api_key) || $reset) if (empty($tmpuser->api_key) || $reset)
@ -102,6 +104,7 @@ class Login
'success' => array( 'success' => array(
'code' => 200, 'code' => 200,
'token' => $token, 'token' => $token,
'entity' => $tmpuser->entity,
'message' => 'Welcome ' . $login.($reset?' - Token is new':' - This is your token (generated by a previous call). You can use it to make any REST API call, or enter it into the DOLAPIKEY field to use the Dolibarr API explorer.') 'message' => 'Welcome ' . $login.($reset?' - Token is new':' - This is your token (generated by a previous call). You can use it to make any REST API call, or enter it into the DOLAPIKEY field to use the Dolibarr API explorer.')
) )
); );

View File

@ -21,9 +21,7 @@
* \defgroup api Module DolibarrApi * \defgroup api Module DolibarrApi
* \brief API loader * \brief API loader
* Search files htdocs/<module>/class/api_<module>.class.php * Search files htdocs/<module>/class/api_<module>.class.php
* \file htdocs/api/indexphp * \file htdocs/api/index.php
*
* @todo User authentication with api_key
*/ */
if (! defined("NOLOGIN")) define("NOLOGIN",'1'); if (! defined("NOLOGIN")) define("NOLOGIN",'1');
@ -79,15 +77,32 @@ $api->r->addAuthenticationClass('DolibarrApiAccess','');
// Define accepted mime types // Define accepted mime types
UploadFormat::$allowedMimeTypes = array('image/jpeg', 'image/png', 'text/plain', 'application/octet-stream'); UploadFormat::$allowedMimeTypes = array('image/jpeg', 'image/png', 'text/plain', 'application/octet-stream');
$listofapis = array();
$modulesdir = dolGetModulesDirs(); // Analyze URLs
foreach ($modulesdir as $dir) // index.php/explorer do a redirect to index.php/explorer/
// index.php/explorer/ called by swagger to build explorer page
// index.php/explorer/.../....png|.css|.js called by swagger for resources to build explorer page
// index.php/explorer/resources.json called by swagger to get list of all services
// index.php/explorer/resources.json/xxx called by swagger to get detail of services xxx
// index.php/xxx called by any REST client to run API
preg_match('/index\.php\/([^\/]+)(.*)$/', $_SERVER["PHP_SELF"], $reg);
// .../index.php/categories?sortfield=t.rowid&sortorder=ASC
// Call Explorer file for all APIs definitions
if (! empty($reg[1]) && $reg[1] == 'explorer' && ($reg[2] == '/resources.json' || $reg[2] == '/resources.json/root'))
{ {
/* // Scan all API files to load them
* Search available module
*/ $listofapis = array();
//dol_syslog("Scan directory ".$dir." for API modules");
$modulesdir = dolGetModulesDirs();
foreach ($modulesdir as $dir)
{
// Search available module
dol_syslog("Scan directory ".$dir." for module descriptor to after search for API files");
$handle=@opendir(dol_osencode($dir)); $handle=@opendir(dol_osencode($dir));
if (is_resource($handle)) if (is_resource($handle))
@ -97,40 +112,10 @@ foreach ($modulesdir as $dir)
if (is_readable($dir.$file) && preg_match("/^mod(.*)\.class\.php$/i",$file,$reg)) if (is_readable($dir.$file) && preg_match("/^mod(.*)\.class\.php$/i",$file,$reg))
{ {
$module = strtolower($reg[1]); $module = strtolower($reg[1]);
$moduledirforclass = $module; $moduledirforclass = getModuleDirForApiClass($module);
$moduleforperm = $module; $moduleforperm = $module;
if ($module == 'propale') { $moduleforperm='propal'; }
if ($module == 'propale') {
$moduledirforclass = 'comm/propal';
$moduleforperm='propal';
}
elseif ($module == 'agenda') {
$moduledirforclass = 'comm/action';
}
elseif ($module == 'adherent') {
$moduledirforclass = 'adherents';
}
elseif ($module == 'banque') {
$moduledirforclass = 'compta/bank';
}
elseif ($module == 'categorie') {
$moduledirforclass = 'categories';
}
elseif ($module == 'facture') {
$moduledirforclass = 'compta/facture';
}
elseif ($module == 'project') {
$moduledirforclass = 'projet';
}
elseif ($module == 'task') {
$moduledirforclass = 'projet';
}
elseif ($module == 'stock') {
$moduledirforclass = 'product/stock';
}
elseif ($module == 'fournisseur') {
$moduledirforclass = 'fourn';
}
//dol_syslog("Found module file ".$file." - module=".$module." - moduledirforclass=".$moduledirforclass); //dol_syslog("Found module file ".$file." - module=".$module." - moduledirforclass=".$moduledirforclass);
// Defined if module is enabled // Defined if module is enabled
@ -139,13 +124,9 @@ foreach ($modulesdir as $dir)
if ($enabled) if ($enabled)
{ {
/* // If exists, load the API class for enable module
* If exists, load the API class for enable module // Search files named api_<object>.class.php into /htdocs/<module>/class directory
* // @todo : use getElementProperties() function ?
* Search files named api_<object>.class.php into /htdocs/<module>/class directory
*
* @todo : use getElementProperties() function ?
*/
$dir_part = dol_buildpath('/'.$moduledirforclass.'/class/'); $dir_part = dol_buildpath('/'.$moduledirforclass.'/class/');
$handle_part=@opendir(dol_osencode($dir_part)); $handle_part=@opendir(dol_osencode($dir_part));
@ -191,20 +172,62 @@ foreach ($modulesdir as $dir)
} }
} }
} }
}
// Sort the classes before adding them to Restler. The Restler API Explorer
// shows the classes in the order they are added and it's a mess if they are not sorted.
sort($listofapis);
//var_dump($listofapis);
foreach ($listofapis as $classname)
{
$api->r->addAPIClass($classname);
}
} }
// Sort the classes before adding them to Restler. The Restler API Explorer // Call one APIs or one definition of an API
// shows the classes in the order they are added and it's a mess if they are if (! empty($reg[1]) && ($reg[1] != 'explorer' || ($reg[2] != '/resources.json' && preg_match('/^\/resources.json\/(.+)$/', $reg[2], $regbis))))
// not sorted.
sort($listofapis);
//var_dump($listofapis);
foreach ($listofapis as $classname)
{ {
$api->r->addAPIClass($classname); $module = $reg[1];
if ($module == 'explorer') // If we call page to explore details of a service
{
$module = $regbis[1];
}
// Load a dedicated API file
dol_syslog("Load a dedicated API file");
$module=strtolower($module);
$moduledirforclass = getModuleDirForApiClass($module);
if (in_array($module, array('category','contact','customer','invoice','order','product','thirdparty','user'))) // Old Apis
{
$classfile = $module;
if ($module == 'customer') { $classfile = 'thirdparty'; }
if ($module == 'order') { $classfile = 'commande'; }
$dir_part_file = dol_buildpath('/'.$moduledirforclass.'/class/api_deprecated_'.$classfile.'.class.php');
$classname=ucwords($module);
if ($module == 'customer') { $classname='Thirdparty'; }
if ($module == 'order') { $classname='Commande'; }
//var_dump($classfile);var_dump($classname);exit;
require_once $dir_part_file;
if (class_exists($classname.'Api')) $api->r->addAPIClass($classname.'Api', '/');
}
else
{
$classfile = str_replace('_', '', $module);
if ($module == 'supplierinvoices') $classfile = 'supplier_invoices';
$dir_part_file = dol_buildpath('/'.$moduledirforclass.'/class/api_'.$classfile.'.class.php');
$classname=ucwords($module);
require_once $dir_part_file;
if (class_exists($classname)) $api->r->addAPIClass($classname);
}
} }
// TODO If not found, redirect to explorer // TODO If not found, redirect to explorer
//var_dump($api); //var_dump($api);
//exit;
// Call API (we suppose we found it) // Call API (we suppose we found it)
$api->r->handle(); $api->r->handle();

View File

@ -2145,3 +2145,70 @@ function cartesianArray(array $input) {
return $result; return $result;
} }
/**
* Get name of directory where the api_...class.php file is stored
*
* @param string $module Module name
* @return string Directory name
*/
function getModuleDirForApiClass($module)
{
$moduledirforclass=$module;
if (in_array($module, array('login', 'access', 'status', 'documents'))) {
$moduledirforclass = 'api';
}
if (preg_match('/^dictionary/', $module)) {
$moduledirforclass = 'api';
}
if ($module == 'contact' || $module == 'contacts' || $module == 'customer' || $module == 'thirdparty' || $module == 'thirdparties') {
$moduledirforclass = 'societe';
}
if ($module == 'propale' || $module == 'proposals') {
$moduledirforclass = 'comm/propal';
}
elseif ($module == 'agenda' || $module == 'agendaevents') {
$moduledirforclass = 'comm/action';
}
elseif ($module == 'adherent' || $module == 'members' || $module == 'memberstypes' || $module == 'subscriptions') {
$moduledirforclass = 'adherents';
}
elseif ($module == 'banque' || $module == 'bankaccounts') {
$moduledirforclass = 'compta/bank';
}
elseif ($module == 'category' || $module == 'categorie') {
$moduledirforclass = 'categories';
}
elseif ($module == 'order' || $module == 'orders') {
$moduledirforclass = 'commande';
}
elseif ($module == 'facture' || $module == 'invoice' || $module == 'invoices') {
$moduledirforclass = 'compta/facture';
}
elseif ($module == 'products') {
$moduledirforclass = 'product';
}
elseif ($module == 'project' || $module == 'projects' || $module == 'tasks') {
$moduledirforclass = 'projet';
}
elseif ($module == 'task') {
$moduledirforclass = 'projet';
}
elseif ($module == 'stock' || $module == 'stockmovements' || $module == 'warehouses') {
$moduledirforclass = 'product/stock';
}
elseif ($module == 'fournisseur' || $module == 'supplierinvoices') {
$moduledirforclass = 'fourn';
}
elseif ($module == 'expensereports') {
$moduledirforclass = 'expensereport';
}
elseif ($module == 'users') {
$moduledirforclass = 'user';
}
return $moduledirforclass;
}

View File

@ -47,6 +47,9 @@ class Contacts extends DolibarrApi
{ {
global $db, $conf; global $db, $conf;
$this->db = $db; $this->db = $db;
include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
$this->contact = new Contact($this->db); $this->contact = new Contact($this->db);
} }

View File

@ -53,6 +53,8 @@ class ThirdpartyApi extends DolibarrApi
*/ */
function __construct() function __construct()
{ {
include_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
global $db, $conf; global $db, $conf;
$this->db = $db; $this->db = $db;
$this->company = new Societe($this->db); $this->company = new Societe($this->db);

View File

@ -221,7 +221,7 @@ class User extends CommonObject
if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
$sql.= " WHERE u.entity IS NOT NULL"; // multicompany is on in transverse mode or user making fetch is on entity 0, so user is allowed to fetch anywhere into database $sql.= " WHERE u.entity IS NOT NULL"; // multicompany is on in transverse mode or user making fetch is on entity 0, so user is allowed to fetch anywhere into database
else else
$sql.= " WHERE u.entity IN (0, ".$conf->entity.")"; $sql.= " WHERE u.entity IN (0, ".($entity!=''?$entity:$conf->entity).")"; // search in entity provided in parameter
} }
if ($sid) // permet une recherche du user par son SID ActiveDirectory ou Samba if ($sid) // permet une recherche du user par son SID ActiveDirectory ou Samba
@ -236,6 +236,7 @@ class User extends CommonObject
{ {
$sql.= " AND u.rowid = ".$id; $sql.= " AND u.rowid = ".$id;
} }
$sql.= " ORDER BY u.entity ASC"; // Avoid random result when there is 2 login in 2 different entities
$result = $this->db->query($sql); $result = $this->db->query($sql);
if ($result) if ($result)
@ -310,8 +311,8 @@ class User extends CommonObject
$this->fk_member = $obj->fk_member; $this->fk_member = $obj->fk_member;
$this->fk_user = $obj->fk_user; $this->fk_user = $obj->fk_user;
// Protection when module multicompany was set, admin was set to first entity and the module disabled, // Protection when module multicompany was set, admin was set to first entity and then, the module was disabled,
// then this admin user must be admin for all entities. // in such case, this admin user must be admin for ALL entities.
if (empty($conf->multicompany->enabled) && $this->admin && $this->entity == 1) $this->entity = 0; if (empty($conf->multicompany->enabled) && $this->admin && $this->entity == 1) $this->entity = 0;
// Retreive all extrafield for thirdparty // Retreive all extrafield for thirdparty