NEW Add REST API to push a file.

This commit is contained in:
Laurent Destailleur 2017-05-20 15:52:36 +02:00
parent 864dc0d989
commit 80cbc28385
16 changed files with 126 additions and 72 deletions

View File

@ -929,7 +929,7 @@ if ($id)
{
print '<td align="center">';
if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin
print '</td>';
}
else print '<td>&nbsp;</td>';

View File

@ -676,7 +676,7 @@ if ($id)
{
print '<td align="center">';
if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin
print '</td>';
}
else print '<td>&nbsp;</td>';

View File

@ -1100,7 +1100,7 @@ if ($id)
$reshook=$hookmanager->executeHooks('createDictionaryFieldlist',$parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error=$hookmanager->error; $errors=$hookmanager->errors;
if ($id == 3) unset($fieldlist[2]); // Remove field ??? if dictionnary Regions
if ($id == 3) unset($fieldlist[2]); // Remove field ??? if dictionary Regions
if (empty($reshook))
{
@ -1555,7 +1555,7 @@ if ($id)
{
print '<td align="center">';
if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin
print '</td>';
}
else print '<td>&nbsp;</td>';

View File

@ -767,7 +767,7 @@ if ($resql)
{
print '<td align="center">';
if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin
print '</td>';
}
else print '<td>&nbsp;</td>';

View File

@ -14,6 +14,8 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @deprecated Old explorer. Not using Swagger. See instead explorer in htdocs/api/index.php.
*/
/**

View File

@ -27,7 +27,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/ccountry.class.php';
* @access protected
* @class DolibarrApiAccess {@requires user,external}
*/
class DictionnaryCountries extends DolibarrApi
class DictionaryCountries extends DolibarrApi
{
private $translations = null;
@ -93,7 +93,8 @@ class DictionnaryCountries extends DolibarrApi
if ($result) {
$num = $this->db->num_rows($result);
for ($i = 0; $i < min($num, ($limit <= 0 ? $num : $limit)); $i++) {
$min = min($num, ($limit <= 0 ? $num : $limit));
for ($i = 0; $i < $min; $i++) {
$obj = $this->db->fetch_object($result);
$country = new Ccountry($this->db);
if ($country->fetch($obj->rowid) > 0) {

View File

@ -27,7 +27,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/ccountry.class.php';
* @access protected
* @class DolibarrApiAccess {@requires user,external}
*/
class DictionnaryTowns extends DolibarrApi
class DictionaryTowns extends DolibarrApi
{
/**
* Constructor
@ -88,7 +88,8 @@ class DictionnaryTowns extends DolibarrApi
if ($result) {
$num = $this->db->num_rows($result);
for ($i = 0; $i < min($num, ($limit <= 0 ? $num : $limit)); $i++) {
$min = min($num, ($limit <= 0 ? $num : $limit));
for ($i = 0; $i < $min; $i++) {
$list[] = $this->db->fetch_object($result);
}
} else {

View File

@ -58,23 +58,33 @@ class Documents extends DolibarrApi
*
* @return array
* @throws RestException
*
*/
/*
public function get($module_part, $filename) {
}
}*/
/**
* Receive file
* Push a file.
* Test sample: { "filename": "mynewfile.txt", "modulepart": "facture", "ref": "FA1701-001", "subdir": "", "filecontent": "content text", "fileencoding": "" }
*
* @param array $request_data Request datas
*
* @return bool State of copy
* @param string $filename Name of file to create ('FA1705-0123')
* @param string $modulepart Module part ('facture', ...)
* @param string $ref Reference of object (This will define subdir automatically and store submited file into it)
* @param string $subdir Subdirectory (Only if refname not provided)
* @param string $filecontent File content (string with file content. An empty file will be created if this parameter is not provided)
* @param string $fileencoding File encoding (''=no encoding, 'base64'=Base 64)
* @return bool State of copy
* @throws RestException
*/
public function post($request_data) {
global $conf;
public function post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='') {
global $db, $conf;
/*var_dump($modulepart);
var_dump($filename);
var_dump($filecontent);
exit;*/
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
@ -82,46 +92,89 @@ class Documents extends DolibarrApi
throw new RestException(401);
}
// Suppression de la chaine de caractere ../ dans $original_file
$original_file = str_replace("../","/", $request_data['name']);
$refname = str_replace("../","/", $request_data['refname']);
$newfilecontent = '';
if (empty($fileencoding)) $newfilecontent = $filecontent;
if ($fileencoding == 'base64') $newfilecontent = base64_decode($filecontent);
// find the subdirectory name as the reference
if (empty($request_data['refname'])) $refname=basename(dirname($original_file)."/");
$original_file = dol_sanitizeFileName($filename);
// Define $uploadir
$object = null;
$entity = $user->entity;
if ($ref)
{
if ($modulepart == 'facture' || $modulepart == 'invoice')
{
$modulepart='facture';
$object=new Facture($db);
$result = $object->fetch('', $ref);
if (! ($result > 0))
{
throw new RestException(500, 'The object '.$modulepart." with ref '".$ref."' was not found.");
}
if (! empty($entity))
{
$tmpreldir = get_exdir(0, 0, 0, 0, $object, $modulepart);
$upload_dir = $conf->{$modulepart}->multidir_output[$entity].'/'.$tmpreldir.$object->ref;
}
else
{
$tmpreldir = get_exdir(0, 0, 0, 0, $object, $modulepart);
$upload_dir = $conf->{$modulepart}->dir_output.'/'.$tmpreldir.$object->ref;
}
}
if (empty($upload_dir) || $upload_dir == '/')
{
throw new RestException(500, 'This value of modulepart does not support yet usage of refname. Check modulepart parameter or try to use subdir parameter instead of ref.');
}
}
else
{
if ($modulepart == 'invoice') $modulepart ='facture';
if (empty($conf->{$modulepart}->dir_output))
{
throw new RestException(500, 'This value of modulepart is not supported with refname not defined.');
}
$upload_dir = $conf->{$modulepart}->multidir_output[$entity];
if (empty($upload_dir) || $upload_dir == '/')
{
throw new RestException(500, 'This value of modulepart is not yet supported.');
}
}
$upload_dir = dol_sanitizePathName($upload_dir);
// Security:
// On interdit les remontees de repertoire ainsi que les pipe dans
// les noms de fichiers.
if (preg_match('/\.\./',$original_file) || preg_match('/[<>|]/',$original_file))
{
throw new RestException(401,'Refused to deliver file '.$original_file);
}
if (preg_match('/\.\./',$refname) || preg_match('/[<>|]/',$refname))
{
throw new RestException(401,'Refused to deliver file '.$refname);
}
$modulepart = $request_data['modulepart'];
// TODO Use dol_check_secure_access_document
// Check mandatory fields
$result = $this->_validate_file($request_data);
//$result = $this->_validate_file($request_data);
$upload_dir = DOL_DATA_ROOT . '/' .$modulepart.'/'.dol_sanitizeFileName($refname);
$destfile = $upload_dir . $original_file;
$destfile = $upload_dir . '/' . $original_file;
if (!is_dir($upload_dir)) {
if (!dol_is_dir($upload_dir)) {
throw new RestException(401,'Directory not exists : '.$upload_dir);
}
$file = $_FILES['file'];
$srcfile = $file['tmp_name'];
$res = dol_move($srcfile, $destfile, 0, 1);
if (!$res) {
throw new RestException(500);
if (dol_is_file($destfile))
{
throw new RestException(500, "File with name '".$original_file."' already exists.");
}
return $res;
$fhandle = fopen($destfile, 'w');
if ($fhandle)
{
$nbofbyteswrote = fwrite($fhandle, $newfilecontent);
fclose($fhandle);
@chmod($destfile, octdec($conf->global->MAIN_UMASK));
}
else
{
throw new RestException(500, 'Failed to open file for write');
}
return true;
}
/**

View File

@ -36,7 +36,7 @@ class Login
*
* Request the API token for a couple username / password.
* Using method POST is recommanded for security reasons (method GET is often logged by default by web servers with parameters so with login and pass into server log file).
* Both method are provided for developer conveniance. Best is to not use at all the login API method and enter directly the "api_key" into field at the top right of page (Note: "api_key" can be found/set on the user page).
* Both methods are provided for developer conveniance. Best is to not use at all the login API method and enter directly the "api_key" into field at the top right of page (Note: "api_key" can be found/set on the user page).
*
* @param string $login User login
* @param string $password User password

View File

@ -2502,7 +2502,7 @@ class Form
}
if ($objp->supplier_reputation)
{
//TODO dictionnary
//TODO dictionary
$reputations=array(''=>$langs->trans('Standard'),'FAVORITE'=>$langs->trans('Favorite'),'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
$opt .= " - ".$reputations[$objp->supplier_reputation];

View File

@ -4555,8 +4555,8 @@ function yn($yesno, $case=1, $color=0)
/**
* Return a path to have a directory according to object.
* New usage: $conf->module->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'modulepart')
* or: $conf->module->dir_output.'/'.get_exdir(0, 0, 0, 1, $object, 'modulepart') if multidir_output not defined.
* New usage: $conf->module->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, $modulepart)
* or: $conf->module->dir_output.'/'.get_exdir(0, 0, 0, 1, $object, $modulepart) if multidir_output not defined.
* Old usage: '015' with level 3->"0/1/5/", '015' with level 1->"5/", 'ABC-1' with level 3 ->"0/0/1/"
*
* @param string $num Id of object (deprecated, $object will be used in future)

View File

@ -305,7 +305,7 @@ class modResource extends DolibarrModules
);
//$this->import_convertvalue_array[$r]=array('s.fk_soc'=>array('rule'=>'lastrowid',table='t');
$this->import_regex_array[$r]=array('s.datec'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]( [0-9][0-9]:[0-9][0-9]:[0-9][0-9])?$');
$this->import_examplevalues_array[$r]=array('r.ref'=>"REF1",'r.fk_code_type_resource'=>"Code from dictionnary resource type",'r.datec'=>"2017-01-01 or 2017-01-01 12:30:00");
$this->import_examplevalues_array[$r]=array('r.ref'=>"REF1",'r.fk_code_type_resource'=>"Code from dictionary resource type",'r.datec'=>"2017-01-01 or 2017-01-01 12:30:00");
$this->import_updatekeys_array[$r]=array('r.rf'=>'ResourceFormLabel_ref');
}

View File

@ -218,7 +218,7 @@ create table llx_user_employment
tms timestamp,
fk_user_creat integer,
fk_user_modif integer,
job varchar(128), -- job position. may be a dictionnary
job varchar(128), -- job position. may be a dictionary
status integer NOT NULL, -- draft, active, closed
salary double(24,8), -- last and current value stored into llx_user
salaryextra double(24,8), -- last and current value stored into llx_user

View File

@ -28,7 +28,7 @@ create table llx_user_employment
tms timestamp,
fk_user_creat integer,
fk_user_modif integer,
job varchar(128), -- job position. may be a dictionnary
job varchar(128), -- job position. may be a dictionary
status integer NOT NULL, -- draft, active, closed
salary double(24,8), -- last and current value stored into llx_user
salaryextra double(24,8), -- last and current value stored into llx_user

View File

@ -162,19 +162,19 @@ if (! empty($id) || ! empty($ref)) {
print_fiche_titre($langs->trans('ProductCombinationGenerator'));
$dictionnary_attr = array();
$dictionary_attr = array();
foreach ($prodattr->fetchAll() as $attr) {
$dictionnary_attr[$attr->id] = $attr;
$dictionary_attr[$attr->id] = $attr;
foreach ($prodattrval->fetchAllByProductAttribute($attr->id) as $attrval) {
$dictionnary_attr[$attr->id]->values[$attrval->id] = $attrval;
$dictionary_attr[$attr->id]->values[$attrval->id] = $attrval;
}
}
?>
<script>
dictionnary_attr = <?php echo json_encode($dictionnary_attr) ?>;
dictionary_attr = <?php echo json_encode($dictionary_attr) ?>;
weight_units = '<?php echo measuring_units_string($object->weight_units, 'weight') ?>';
attr_selected = {};
percentage_variation = jQuery('input#price_var_percent').prop('checked');
@ -191,7 +191,7 @@ if (! empty($id) || ! empty($ref)) {
if (!attr_selected.hasOwnProperty(attr)) {
var label = dictionnary_attr[attr].label;
var label = dictionary_attr[attr].label;
var table = jQuery(document.createElement('table'))
.attr('id', 'combinations_'+attr)
@ -239,7 +239,7 @@ if (! empty($id) || ! empty($ref)) {
}
html.append(
jQuery(document.createElement('td')).text(dictionnary_attr[attr].values[val].value),
jQuery(document.createElement('td')).text(dictionary_attr[attr].values[val].value),
jQuery(document.createElement('td')).css('text-align', 'center').append(
jQuery(document.createElement('input')).attr('type', 'text').css('width', '50px').attr('name', 'combinations[' + attr + '][' + val + '][price]').val(price),
percent_symbol_html
@ -350,7 +350,7 @@ if (! empty($id) || ! empty($ref)) {
<div style="float:left; width: 20%">
<select id="features" multiple style="width: 100%; height: 300px; overflow: auto">
<?php foreach ($dictionnary_attr as $attr): ?>
<?php foreach ($dictionary_attr as $attr): ?>
<optgroup label="<?php echo $attr->label ?>">
<?php foreach ($attr->values as $attrval): ?>
<option value="<?php echo $attr->id.':'.$attrval->id ?>"<?php

View File

@ -131,11 +131,11 @@ class RestAPIDocumentTest extends PHPUnit_Framework_TestCase
}
/**
* testRestReceiveDocument.
* testPushDocument.
*
* @return int
*/
public function testRestReceiveDocument()
public function testPushDocument()
{
global $conf,$user,$langs,$db;
@ -143,20 +143,17 @@ class RestAPIDocumentTest extends PHPUnit_Framework_TestCase
$fileName = 'img250x20.png';
$filePath = dirname(__FILE__).'/'.$fileName;
$mimetype = mime_content_type($filePath);
// Init Curl file object
// See https://wiki.php.net/rfc/curl-file-upload
$cfile = curl_file_create($filePath, $mimetype);
$mimetype = dol_mimetype($filePath);
echo __METHOD__.' Request POST url='.$url."\n";
// Send to existant directory
$data = array(
// Send to existant directory
$data = array(
'modulepart' => 'facture',
'file' => $cfile,
'file' => 'eeeeeee',
'refname' => 'AV1303-0003',
'name' => $fileName, // Name for destination
'type' => $mimetype, );
'mime' => $mimetype );
$result = getURLContent($url, 'POST', $data, 1);
@ -165,8 +162,8 @@ class RestAPIDocumentTest extends PHPUnit_Framework_TestCase
$this->assertEquals($result['curl_error_no'], '');
$this->assertEquals($result['content'], 'true');
// Send to unexistant directory
$data = array(
// Send to unexistant directory
$data = array(
'modulepart' => 'facture',
'file' => $cfile,
'name' => 'AV1303-0003STSEIUDEISRESIJLEU/'.$fileName, // Name for destination