2016-12-12 14:19:47 +00:00
< ? php
2025-01-07 14:31:41 +00:00
2025-06-09 16:15:59 +00:00
/* Copyright ( C ) 2016 Xebax Christy < xebax @ wanadoo . fr >
* Copyright ( C ) 2016 Laurent Destailleur < eldy @ users . sourceforge . net >
* Copyright ( C ) 2016 Jean - François Ferry < jfefe @ aternatik . fr >
* Copyright ( C ) 2023 Romain Neil < contact @ romain - neil . fr >
2025-04-16 17:55:44 +00:00
* Copyright ( C ) 2024 - 2025 Frédéric France < frederic . france @ free . fr >
2026-07-23 14:09:22 +00:00
* Copyright ( C ) 2025 - 2026 MDW < mdeweerd @ users . noreply . github . com >
2025-06-09 16:15:59 +00:00
* Copyright ( C ) 2025 William Mead < william @ m34d . com >
2026-01-29 21:55:38 +00:00
* Copyright ( C ) 2025 - 2026 Charlene Benke < charlene @ patas - monkey . com >
2016-12-12 14:19:47 +00:00
*
* 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
2019-09-23 19:55:30 +00:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2016-12-12 14:19:47 +00:00
*/
use Luracast\Restler\RestException ;
require_once DOL_DOCUMENT_ROOT . '/main.inc.php' ;
2023-10-26 10:22:54 +00:00
require_once DOL_DOCUMENT_ROOT . '/api/class/api.class.php' ;
2017-09-28 10:14:49 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
2016-12-12 14:19:47 +00:00
/**
* API class for receive files
*
2025-06-13 09:44:10 +00:00
* @ since 6.0 . 0 Initial implementation
*
2016-12-12 14:19:47 +00:00
* @ access protected
* @ class Documents { @ requires user , external }
*/
class Documents extends DolibarrApi
{
2017-10-06 00:42:32 +00:00
/**
* Constructor
*/
2019-02-25 19:35:59 +00:00
public function __construct ()
2017-10-06 00:42:32 +00:00
{
global $db ;
$this -> db = $db ;
}
/**
2026-07-20 12:57:23 +00:00
* Download a given document
2017-11-06 10:06:31 +00:00
*
* Note that , this API is similar to using the wrapper link " documents.php " to download a file ( used for
* internal HTML links of documents into application ), but with no need to have a session cookie ( the token is used instead ) .
2017-10-06 00:42:32 +00:00
*
2025-06-13 09:44:10 +00:00
* @ since 7.0 . 0 Initial implementation
*
2019-08-25 14:38:09 +00:00
* @ param string $modulepart Name of module or area concerned by file download ( 'facture' , ... )
2017-10-06 00:42:32 +00:00
* @ param string $original_file Relative path with filename , relative to modulepart ( for example : IN201701 - 999 / IN201701 - 999. pdf )
* @ return array List of documents
2025-03-02 14:10:25 +00:00
* @ phan - return array { filename : string , content - type : string , filesize : false | int , content : string , encoding : string }
* @ phpstan - return array { filename : string , content - type : string , filesize : false | int , content : string , encoding : string }
2017-10-06 00:42:32 +00:00
*
2017-11-06 10:06:31 +00:00
* @ url GET / download
2024-01-13 18:34:51 +00:00
*
2024-01-14 11:26:37 +00:00
* @ throws RestException 400 Bad value for parameter modulepart or original_file
2024-02-01 18:16:58 +00:00
* @ throws RestException 403 Access denied
2024-01-13 18:34:51 +00:00
* @ throws RestException 404 File not found
2017-10-06 00:42:32 +00:00
*/
2019-08-25 14:38:09 +00:00
public function index ( $modulepart , $original_file = '' )
2017-10-06 00:42:32 +00:00
{
2023-08-06 10:26:27 +00:00
global $conf ;
2017-10-05 08:21:52 +00:00
2019-08-25 14:38:09 +00:00
if ( empty ( $modulepart )) {
2023-12-04 10:41:14 +00:00
throw new RestException ( 400 , 'bad value for parameter modulepart' );
2017-10-06 00:42:32 +00:00
}
if ( empty ( $original_file )) {
2017-12-27 14:48:20 +00:00
throw new RestException ( 400 , 'bad value for parameter original_file' );
2017-10-05 08:21:52 +00:00
}
2017-10-04 13:59:54 +00:00
2025-10-07 18:48:58 +00:00
// Normalize modulepart for project_task
if ( $modulepart == 'task' || $modulepart == 'project_task' ) {
$modulepart = 'project_task' ;
}
2017-10-05 08:21:52 +00:00
//--- Finds and returns the document
2019-11-22 14:13:30 +00:00
$entity = $conf -> entity ;
2017-10-04 13:59:54 +00:00
2020-02-25 13:59:47 +00:00
// Special cases that need to use get_exdir to get real dir of object
// If future, all object should use this to define path of documents.
/*
$tmpreldir = '' ;
if ( $modulepart == 'supplier_invoice' ) {
$tmpreldir = get_exdir ( $object -> id , 2 , 0 , 0 , $object , 'invoice_supplier' );
}
$relativefile = $tmpreldir . dol_sanitizeFileName ( $object -> ref ); */
$relativefile = $original_file ;
$check_access = dol_check_secure_access_document ( $modulepart , $relativefile , $entity , DolibarrApiAccess :: $user , '' , 'read' );
2019-02-25 19:35:59 +00:00
$accessallowed = $check_access [ 'accessallowed' ];
2017-10-05 08:21:52 +00:00
$sqlprotectagainstexternals = $check_access [ 'sqlprotectagainstexternals' ];
2019-02-25 19:35:59 +00:00
$original_file = $check_access [ 'original_file' ];
2017-09-28 10:14:49 +00:00
2019-02-25 19:35:59 +00:00
if ( preg_match ( '/\.\./' , $original_file ) || preg_match ( '/[<>|]/' , $original_file )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-10-07 11:09:31 +00:00
}
if ( ! $accessallowed ) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-10-07 11:09:31 +00:00
}
2026-03-02 03:25:53 +00:00
if ( DolibarrApiAccess :: $user -> socid > 0 ) {
if ( $sqlprotectagainstexternals ) {
$resql = $this -> db -> query ( $sqlprotectagainstexternals );
if ( $resql ) {
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
while ( $i < $num ) {
$obj = $this -> db -> fetch_object ( $resql );
if ( DolibarrApiAccess :: $user -> socid != $obj -> fk_soc ) {
throw new RestException ( 403 , 'Not allowed to download documents with such a ref' );
}
$i ++ ;
}
}
}
}
2017-12-27 14:48:20 +00:00
$filename = basename ( $original_file );
2019-11-22 14:13:30 +00:00
$original_file_osencoded = dol_osencode ( $original_file ); // New file name encoded in OS encoding charset
2017-12-27 14:48:20 +00:00
2021-02-23 16:44:43 +00:00
if ( ! file_exists ( $original_file_osencoded )) {
2019-08-25 14:38:09 +00:00
dol_syslog ( " Try to download not found file " . $original_file_osencoded , LOG_WARNING );
2017-12-27 14:48:20 +00:00
throw new RestException ( 404 , 'File not found' );
}
2017-10-07 11:09:31 +00:00
2019-11-22 14:13:30 +00:00
$file_content = file_get_contents ( $original_file_osencoded );
2025-01-07 14:31:41 +00:00
return array ( 'filename' => $filename , 'content-type' => dol_mimetype ( $filename ), 'filesize' => filesize ( $original_file ), 'content' => base64_encode ( $file_content ), 'encoding' => 'base64' );
2017-12-27 14:48:20 +00:00
}
/**
2025-06-13 09:44:10 +00:00
* Build a document
2017-12-27 14:48:20 +00:00
*
2020-12-09 15:26:31 +00:00
* Test sample 1 : { " modulepart " : " invoice " , " original_file " : " FA1701-001/FA1701-001.pdf " , " doctemplate " : " crabe " , " langcode " : " fr_FR " } .
2017-12-27 14:48:20 +00:00
*
2025-06-13 09:44:10 +00:00
* Supported modules : invoice , order , proposal , contract , supplier invoice , shipment , mrp
*
* @ since 7.0 . 0 Initial implementation , support for invoice , order and proposal documents
* @ since 18.0 . 0 Added support for contract and suppliers invoice documents
* @ since 19.0 . 0 Added support for shipment documents
* @ since 20.0 . 0 Added support for mrp documents
2025-12-14 17:21:39 +00:00
* @ since 23.0 . 0 Added support for expense report documents
2025-12-14 17:20:29 +00:00
* @ since 23.0 . 0 Added support for product documents
2023-05-10 10:23:32 +00:00
*
2021-10-06 16:50:29 +00:00
* @ param string $modulepart Name of module or area concerned by file download ( 'thirdparty' , 'member' , 'proposal' , 'supplier_proposal' , 'order' , 'supplier_order' , 'invoice' , 'supplier_invoice' , 'shipment' , 'project' , ... )
2017-12-27 14:48:20 +00:00
* @ param string $original_file Relative path with filename , relative to modulepart ( for example : IN201701 - 999 / IN201701 - 999. pdf ) .
* @ param string $doctemplate Set here the doc template to use for document generation ( If not set , use the default template ) .
* @ param string $langcode Language code like 'en_US' , 'fr_FR' , 'es_ES' , ... ( If not set , use the default language ) .
* @ return array List of documents
2025-03-02 14:10:25 +00:00
* @ phan - return array { filename : string , content - type : string , filesize : false | int , content : string , langcode : string , template : ? string , encoding : string }
* @ phpstan - return array { filename : string , content - type : string , filesize : false | int , content : string , langcode : string , template : ? string , encoding : string }
2017-12-27 14:48:20 +00:00
*
* @ url PUT / builddoc
2024-01-13 18:34:51 +00:00
*
2024-01-14 11:26:37 +00:00
* @ throws RestException 400 Bad value for parameter modulepart or original_file
2024-02-01 18:16:58 +00:00
* @ throws RestException 403 Access denied
2024-01-13 18:34:51 +00:00
* @ throws RestException 404 Invoice , Order , Proposal , Contract or Shipment not found
* @ throws RestException 500 Error generating document
* @ throws RestException 501 File not found
2017-12-27 14:48:20 +00:00
*/
2019-08-25 14:38:09 +00:00
public function builddoc ( $modulepart , $original_file = '' , $doctemplate = '' , $langcode = '' )
2017-12-27 14:48:20 +00:00
{
global $conf , $langs ;
2019-08-25 14:38:09 +00:00
if ( empty ( $modulepart )) {
2017-12-27 14:48:20 +00:00
throw new RestException ( 400 , 'bad value for parameter modulepart' );
}
if ( empty ( $original_file )) {
throw new RestException ( 400 , 'bad value for parameter original_file' );
}
$outputlangs = $langs ;
2021-02-23 16:44:43 +00:00
if ( $langcode && $langs -> defaultlang != $langcode ) {
2019-11-22 14:13:30 +00:00
$outputlangs = new Translate ( '' , $conf );
2017-12-27 14:48:20 +00:00
$outputlangs -> setDefaultLang ( $langcode );
}
//--- Finds and returns the document
2019-11-22 14:13:30 +00:00
$entity = $conf -> entity ;
2017-12-27 14:48:20 +00:00
2020-02-25 13:59:47 +00:00
// Special cases that need to use get_exdir to get real dir of object
// If future, all object should use this to define path of documents.
/*
$tmpreldir = '' ;
if ( $modulepart == 'supplier_invoice' ) {
$tmpreldir = get_exdir ( $object -> id , 2 , 0 , 0 , $object , 'invoice_supplier' );
}
$relativefile = $tmpreldir . dol_sanitizeFileName ( $object -> ref ); */
$relativefile = $original_file ;
$check_access = dol_check_secure_access_document ( $modulepart , $relativefile , $entity , DolibarrApiAccess :: $user , '' , 'write' );
2017-12-27 14:48:20 +00:00
$accessallowed = $check_access [ 'accessallowed' ];
$sqlprotectagainstexternals = $check_access [ 'sqlprotectagainstexternals' ];
$original_file = $check_access [ 'original_file' ];
2019-02-25 19:35:59 +00:00
if ( preg_match ( '/\.\./' , $original_file ) || preg_match ( '/[<>|]/' , $original_file )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-12-27 14:48:20 +00:00
}
if ( ! $accessallowed ) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-12-27 14:48:20 +00:00
}
2026-03-02 03:25:53 +00:00
if ( DolibarrApiAccess :: $user -> socid > 0 ) {
if ( $sqlprotectagainstexternals ) {
$resql = $this -> db -> query ( $sqlprotectagainstexternals );
if ( $resql ) {
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
while ( $i < $num ) {
$obj = $this -> db -> fetch_object ( $resql );
if ( DolibarrApiAccess :: $user -> socid != $obj -> fk_soc ) {
throw new RestException ( 403 , 'Not allowed to download documents with such a ref' );
}
$i ++ ;
}
}
}
}
2017-12-27 14:48:20 +00:00
// --- Generates the document
2023-10-24 15:00:13 +00:00
$hidedetails = ! getDolGlobalString ( 'MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS' ) ? 0 : 1 ;
$hidedesc = ! getDolGlobalString ( 'MAIN_GENERATE_DOCUMENTS_HIDE_DESC' ) ? 0 : 1 ;
$hideref = ! getDolGlobalString ( 'MAIN_GENERATE_DOCUMENTS_HIDE_REF' ) ? 0 : 1 ;
2017-12-27 14:48:20 +00:00
2019-11-22 14:13:30 +00:00
$templateused = '' ;
2017-12-27 14:48:20 +00:00
2021-02-23 16:44:43 +00:00
if ( $modulepart == 'facture' || $modulepart == 'invoice' ) {
2017-12-27 14:48:20 +00:00
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php' ;
2023-08-06 10:26:27 +00:00
$tmpobject = new Facture ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
2019-11-22 14:13:30 +00:00
if ( ! $result ) {
2017-12-27 14:48:20 +00:00
throw new RestException ( 404 , 'Invoice not found' );
2017-10-07 11:09:31 +00:00
}
2017-11-10 15:42:06 +00:00
2023-08-06 10:26:27 +00:00
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2019-11-22 14:13:30 +00:00
if ( $result <= 0 ) {
2017-12-27 14:48:20 +00:00
throw new RestException ( 500 , 'Error generating document' );
}
2023-05-10 12:30:51 +00:00
} elseif ( $modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier' ) {
2023-05-10 12:27:51 +00:00
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php' ;
2023-08-06 10:26:27 +00:00
$tmpobject = new FactureFournisseur ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
2023-05-10 12:27:51 +00:00
if ( ! $result ) {
throw new RestException ( 404 , 'Supplier invoice not found' );
}
2023-08-06 10:26:27 +00:00
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2023-05-10 12:27:51 +00:00
if ( $result < 0 ) {
throw new RestException ( 500 , 'Error generating document' );
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'commande' || $modulepart == 'order' ) {
2017-12-27 14:48:20 +00:00
require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php' ;
2023-08-06 10:26:27 +00:00
$tmpobject = new Commande ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
2019-11-22 14:13:30 +00:00
if ( ! $result ) {
2017-12-27 14:48:20 +00:00
throw new RestException ( 404 , 'Order not found' );
}
2023-08-06 10:26:27 +00:00
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2019-11-22 14:13:30 +00:00
if ( $result <= 0 ) {
2017-12-27 14:48:20 +00:00
throw new RestException ( 500 , 'Error generating document' );
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'propal' || $modulepart == 'proposal' ) {
2018-01-04 20:14:45 +00:00
require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php' ;
2023-08-06 10:26:27 +00:00
$tmpobject = new Propal ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
2019-11-22 14:13:30 +00:00
if ( ! $result ) {
2018-01-04 20:14:45 +00:00
throw new RestException ( 404 , 'Proposal not found' );
}
2023-08-06 10:26:27 +00:00
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2019-11-22 14:13:30 +00:00
if ( $result <= 0 ) {
2018-01-04 20:14:45 +00:00
throw new RestException ( 500 , 'Error generating document' );
}
2023-05-01 20:11:27 +00:00
} elseif ( $modulepart == 'contrat' || $modulepart == 'contract' ) {
require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php' ;
2023-08-06 10:26:27 +00:00
$tmpobject = new Contrat ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
2023-05-01 20:11:27 +00:00
if ( ! $result ) {
throw new RestException ( 404 , 'Contract not found' );
}
2023-08-06 10:26:27 +00:00
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2023-05-01 20:11:27 +00:00
2023-10-16 13:50:23 +00:00
if ( $result <= 0 ) {
2025-12-17 12:41:41 +00:00
throw new RestException ( 500 , 'Error generating document' );
2023-10-16 13:50:23 +00:00
}
} elseif ( $modulepart == 'expedition' || $modulepart == 'shipment' ) {
require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php' ;
2023-10-20 00:20:26 +00:00
$tmpobject = new Expedition ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
2023-10-16 13:50:23 +00:00
if ( ! $result ) {
throw new RestException ( 404 , 'Shipment not found' );
}
2023-10-20 00:20:26 +00:00
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2023-10-16 13:50:23 +00:00
2024-07-31 13:43:13 +00:00
if ( $result <= 0 ) {
2025-12-17 12:41:41 +00:00
throw new RestException ( 500 , 'Error generating document' );
2024-07-31 13:43:13 +00:00
}
} elseif ( $modulepart == 'mrp' ) {
require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php' ;
$tmpobject = new Mo ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
if ( ! $result ) {
throw new RestException ( 404 , 'MO not found' );
}
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2025-12-13 16:44:14 +00:00
if ( $result <= 0 ) {
2025-12-17 12:41:41 +00:00
throw new RestException ( 500 , 'Error generating document' );
2025-12-13 16:44:14 +00:00
}
} elseif ( $modulepart == 'expensereport' ) {
require_once DOL_DOCUMENT_ROOT . '/expensereport/class/expensereport.class.php' ;
$tmpobject = new ExpenseReport ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
if ( ! $result ) {
2025-12-17 12:41:41 +00:00
throw new RestException ( 404 , 'Expense report not found' );
}
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2026-01-29 21:55:38 +00:00
if ( $result <= 0 ) {
throw new RestException ( 500 , 'Error generating document' );
}
} elseif ( $modulepart == 'holiday' ) {
require_once DOL_DOCUMENT_ROOT . '/holiday/class/holiday.class.php' ;
$tmpobject = new Holiday ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
if ( ! $result ) {
throw new RestException ( 404 , 'Holiday not found' );
}
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2025-12-17 12:41:41 +00:00
if ( $result <= 0 ) {
throw new RestException ( 500 , 'Error generating document' );
2025-12-15 12:59:56 +00:00
}
2025-12-14 17:20:29 +00:00
} elseif ( $modulepart == 'product' ) {
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php' ;
$tmpobject = new Product ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
if ( ! $result ) {
throw new RestException ( 404 , 'Product not found' );
2025-12-13 16:44:14 +00:00
}
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2025-12-17 08:07:32 +00:00
if ( $result <= 0 ) {
2025-12-17 12:41:41 +00:00
throw new RestException ( 500 , 'Error generating document' );
2025-12-17 08:07:32 +00:00
}
2025-12-17 08:08:00 +00:00
} elseif ( $modulepart == 'stock' || $modulepart == 'entrepot' ) {
2025-12-17 08:07:32 +00:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php' ;
$tmpobject = new Entrepot ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
if ( ! $result ) {
throw new RestException ( 404 , 'Warehouse not found' );
}
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2025-12-13 16:44:14 +00:00
2023-05-01 20:11:27 +00:00
if ( $result <= 0 ) {
2025-12-17 18:15:44 +00:00
throw new RestException ( 500 , 'Error generating document' );
2023-05-01 20:11:27 +00:00
}
2025-12-17 15:59:04 +00:00
} elseif ( $modulepart == 'fichinter' || $modulepart == 'intervention' ) {
require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php' ;
$tmpobject = new Fichinter ( $this -> db );
$result = $tmpobject -> fetch ( 0 , preg_replace ( '/\.[^\.]+$/' , '' , basename ( $original_file )));
if ( ! $result ) {
throw new RestException ( 404 , 'Intervention not found' );
}
$templateused = $doctemplate ? $doctemplate : $tmpobject -> model_pdf ;
$result = $tmpobject -> generateDocument ( $templateused , $outputlangs , $hidedetails , $hidedesc , $hideref );
2025-12-13 16:44:14 +00:00
2023-05-01 20:11:27 +00:00
if ( $result <= 0 ) {
2025-12-17 12:41:41 +00:00
throw new RestException ( 500 , 'Error generating document' );
2023-05-01 20:11:27 +00:00
}
2020-10-31 08:03:09 +00:00
} else {
2017-12-27 14:48:20 +00:00
throw new RestException ( 403 , 'Generation not available for this modulepart' );
2017-10-05 08:21:52 +00:00
}
2017-09-28 10:14:49 +00:00
2017-10-05 08:21:52 +00:00
$filename = basename ( $original_file );
2019-11-22 14:13:30 +00:00
$original_file_osencoded = dol_osencode ( $original_file ); // New file name encoded in OS encoding charset
2017-09-28 10:14:49 +00:00
2021-02-23 16:44:43 +00:00
if ( ! file_exists ( $original_file_osencoded )) {
2017-10-07 11:09:31 +00:00
throw new RestException ( 404 , 'File not found' );
2017-10-05 08:21:52 +00:00
}
2017-09-28 10:14:49 +00:00
2019-11-22 14:13:30 +00:00
$file_content = file_get_contents ( $original_file_osencoded );
2025-01-07 14:31:41 +00:00
return array ( 'filename' => $filename , 'content-type' => dol_mimetype ( $filename ), 'filesize' => filesize ( $original_file ), 'content' => base64_encode ( $file_content ), 'langcode' => $outputlangs -> defaultlang , 'template' => $templateused , 'encoding' => 'base64' );
2017-10-07 11:09:31 +00:00
}
2017-10-12 10:28:10 +00:00
/**
2026-07-20 12:57:23 +00:00
* List all documents of an element
2017-10-12 10:28:10 +00:00
*
2025-06-13 09:44:10 +00:00
* Use element ID or Ref .
2025-10-07 18:48:58 +00:00
* Supported modules : thirdparty , user , member , proposal , order , supplier_order , shipment , invoice , supplier_invoice , product , event , expensereport , knowledgemanagement , category , contract , project , project_task
2023-05-10 10:23:32 +00:00
*
2025-06-13 09:44:10 +00:00
* @ since 7.0 . 0 Initial implementation
*
2025-10-07 18:48:58 +00:00
* @ param string $modulepart Name of module or area concerned ( 'thirdparty' , 'member' , 'proposal' , 'order' , 'invoice' , 'supplier_invoice' , 'shipment' , 'project' , 'project_task' , ... )
2017-10-16 06:52:00 +00:00
* @ param int $id ID of element
2017-10-12 10:28:10 +00:00
* @ param string $ref Ref of element
2017-10-16 06:52:00 +00:00
* @ param string $sortfield Sort criteria ( '' , 'fullname' , 'relativename' , 'name' , 'date' , 'size' )
* @ param string $sortorder Sort order ( 'asc' or 'desc' )
2025-06-04 09:10:59 +00:00
* @ param int $limit List limit
* @ param int $page Page number
* @ param string $content_type Filter on content - type ( example 'application/pdf' or 'application/pdf,image/jpeg' ))
* @ param bool $pagination_data If this parameter is set to true the response will include pagination data . Default value is false . Page starts from 0 *
2017-10-16 06:52:00 +00:00
* @ return array Array of documents with path
2026-07-23 14:09:22 +00:00
* @ phan - return array { data : array < mixed , array { name : string , path : string , level1name : string , relativename : string , fullname : string , date : string , size : int , perm : int , type : string } > , pagination : array { total : int , page : int , page_count : int , limit : int }} | array < mixed , array { name : string , path : string , level1name : string , relativename : string , fullname : string , date : string , size : int , perm : int , type : string } >
2025-03-02 14:10:25 +00:00
* @ phpstan - return array < array < string , int | string >>
2017-10-12 10:28:10 +00:00
*
2017-11-06 10:06:31 +00:00
* @ url GET /
2024-01-13 18:34:51 +00:00
*
2024-01-14 11:26:37 +00:00
* @ throws RestException 400 Bad value for parameter modulepart , id or ref
2024-02-01 18:16:58 +00:00
* @ throws RestException 403 Access denied
2026-07-20 12:57:23 +00:00
* @ throws RestException 404 Object ( Thirdparty , User , Member , Order , Invoice , Proposal ... ) not found
2024-01-13 18:34:51 +00:00
* @ throws RestException 500 Error while fetching object
2026-07-23 14:09:22 +00:00
* @ throws RestException 503 Error when retrieving ecm list
2017-10-12 10:28:10 +00:00
*/
2025-06-04 09:10:59 +00:00
public function getDocumentsListByElement ( $modulepart , $id = 0 , $ref = '' , $sortfield = '' , $sortorder = '' , $limit = 100 , $page = 0 , $content_type = '' , $pagination_data = false )
2017-10-12 10:28:10 +00:00
{
if ( empty ( $modulepart )) {
throw new RestException ( 400 , 'bad value for parameter modulepart' );
}
if ( empty ( $id ) && empty ( $ref )) {
throw new RestException ( 400 , 'bad value for parameter id or ref' );
}
2019-11-22 14:13:30 +00:00
$id = ( empty ( $id ) ? 0 : $id );
2017-10-12 10:28:10 +00:00
2017-11-17 10:44:52 +00:00
2026-07-20 12:57:23 +00:00
// Define $object
$object = fetchObjectByElement ( $id , $modulepart , $ref );
if ( ! is_object ( $object )) {
throw new RestException ( 404 , 'Object with (id, ref) = (' . $id . ', ' . $ref . ') not found or not allowed for modulepart = ' . $modulepart );
}
// Define $upload_dir to scan
$upload_dir = getMultidirOutput ( $object , '' , 1 );
// Check object-level permissions
$ok = checkUserAccessToObject ( DolibarrApiAccess :: $user , array ( $object -> element ), $object , $object -> table_element , '' );
if ( empty ( $ok )) {
throw new RestException ( 403 , 'Access not allowed to this object (refused by checkUserAccessToObject)' );
}
// Check permission on module
if ( $modulepart == 'societe' || $modulepart == 'thirdparty' ) {
2022-09-10 09:00:38 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'societe' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-10-12 10:28:10 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'user' ) {
2020-02-18 21:49:53 +00:00
// Can get doc if has permission to read all user or if it is user itself
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'user' , 'user' , 'lire' ) && DolibarrApiAccess :: $user -> id != $id ) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2020-02-15 19:33:12 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'adherent' || $modulepart == 'member' ) {
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'adherent' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-10-12 10:28:10 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'propal' || $modulepart == 'proposal' ) {
2023-06-19 21:27:24 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'propal' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-12-22 18:49:31 +00:00
}
2021-10-06 16:50:29 +00:00
} elseif ( $modulepart == 'supplier_proposal' ) {
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'supplier_proposal' , 'read' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2021-10-06 16:50:29 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'commande' || $modulepart == 'order' ) {
2023-06-19 21:27:24 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'commande' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-12-22 18:49:31 +00:00
}
2021-10-06 16:50:29 +00:00
} elseif ( $modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order' ) {
$modulepart = 'supplier_order' ;
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'fournisseur' , 'commande' , 'lire' ) && ! DolibarrApiAccess :: $user -> hasRight ( 'supplier_order' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2021-10-06 16:50:29 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'shipment' || $modulepart == 'expedition' ) {
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'expedition' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-12-22 18:49:31 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'facture' || $modulepart == 'invoice' ) {
2023-06-19 21:18:13 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'facture' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2017-12-22 18:49:31 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice' ) {
2020-02-25 13:47:05 +00:00
$modulepart = 'supplier_invoice' ;
2024-02-01 18:16:58 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'fournisseur' , 'facture' , 'lire' ) && ! DolibarrApiAccess :: $user -> hasRight ( 'supplier_invoice' , 'lire' )) {
throw new RestException ( 403 );
2020-02-25 13:47:05 +00:00
}
2025-08-11 17:09:12 +00:00
} elseif ( $modulepart == 'produit' || $modulepart == 'product' || $modulepart == 'service' ) {
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'produit' , 'lire' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2019-02-26 23:48:13 +00:00
}
2025-12-19 15:26:35 +00:00
} elseif ( $modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event' || $modulepart == 'actioncomm' ) {
2024-02-09 14:58:49 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'agenda' , 'myactions' , 'read' ) && ! DolibarrApiAccess :: $user -> hasRight ( 'agenda' , 'allactions' , 'read' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2018-07-13 14:07:19 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'expensereport' ) {
2025-06-09 15:42:02 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'expensereport' , 'read' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2020-02-25 13:36:05 +00:00
}
2026-01-29 21:55:38 +00:00
} elseif ( $modulepart == 'holiday' ) {
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'holiday' , 'read' )) {
throw new RestException ( 403 );
}
2025-08-11 17:09:12 +00:00
} elseif ( $modulepart == 'ticket' ) {
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'ticket' , 'read' )) {
throw new RestException ( 403 );
}
2022-04-14 19:47:35 +00:00
} elseif ( $modulepart == 'knowledgemanagement' ) {
2025-06-28 14:46:52 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'knowledgemanagement' , 'knowledgerecord' , 'read' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2022-04-14 19:47:35 +00:00
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'categorie' || $modulepart == 'category' ) {
2024-02-01 18:16:58 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'categorie' , 'lire' )) {
throw new RestException ( 403 );
2020-04-05 09:20:24 +00:00
}
2020-10-31 08:03:09 +00:00
} elseif ( $modulepart == 'ecm' ) {
2020-12-01 01:41:19 +00:00
throw new RestException ( 500 , 'Modulepart Ecm not implemented yet.' );
2024-02-09 14:58:49 +00:00
// if (!DolibarrApiAccess::$user->hasRight('ecm', 'read')) {
2024-02-01 18:16:58 +00:00
// throw new RestException(403);
2020-10-31 08:03:09 +00:00
// }
2023-05-01 18:11:31 +00:00
} elseif ( $modulepart == 'contrat' || $modulepart == 'contract' ) {
2023-05-01 18:10:48 +00:00
$modulepart = 'contrat' ;
2026-07-13 13:50:21 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'contrat' , 'lire' )) {
throw new RestException ( 403 );
}
2025-06-25 17:25:57 +00:00
} elseif ( $modulepart == 'intervention' || $modulepart == 'ficheinter' ) {
$modulepart = 'ficheinter' ;
2026-07-13 13:50:21 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'ficheinter' , 'lire' )) {
throw new RestException ( 403 );
}
2023-07-25 21:24:11 +00:00
} elseif ( $modulepart == 'projet' || $modulepart == 'project' ) {
$modulepart = 'project' ;
2026-07-13 13:50:21 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'projet' , 'lire' )) {
throw new RestException ( 403 );
}
2025-10-07 18:48:58 +00:00
} elseif ( $modulepart == 'task' || $modulepart == 'project_task' ) {
$modulepart = 'project_task' ;
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'projet' , 'lire' )) {
throw new RestException ( 403 );
}
2024-07-31 13:43:13 +00:00
} elseif ( $modulepart == 'mrp' ) {
$modulepart = 'mrp' ;
2026-07-13 13:50:21 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'mrp' , 'read' )) {
throw new RestException ( 403 );
}
2025-08-04 09:10:49 +00:00
} elseif ( $modulepart == 'contact' || $modulepart == 'socpeople' ) {
$modulepart = 'contact' ;
2026-07-13 13:50:21 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'societe' , 'contact' , 'lire' )) {
throw new RestException ( 403 );
}
2025-12-17 07:39:46 +00:00
} elseif ( $modulepart == 'stock' ) {
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'stock' , 'lire' )) {
throw new RestException ( 403 );
}
2020-10-31 08:03:09 +00:00
} else {
2017-10-12 10:28:10 +00:00
throw new RestException ( 500 , 'Modulepart ' . $modulepart . ' not implemented yet.' );
}
2026-07-20 12:57:23 +00:00
// Scan files into directory
$recursive = 0 ;
$type = 'files' ;
2022-11-25 23:02:17 +00:00
$objectType = $modulepart ;
2022-12-01 16:46:13 +00:00
if ( ! empty ( $object -> id ) && ! empty ( $object -> table_element )) {
$objectType = $object -> table_element ;
}
2022-11-25 23:02:17 +00:00
2026-07-23 14:09:22 +00:00
$filearray = dol_dir_list ( $upload_dir , $type , $recursive , '' , '(\.meta|_preview.*\.png)$' , $sortfield , ( strtolower ( $sortorder ) == 'desc' ? SORT_DESC : SORT_ASC ), 1 );
$countarray = is_array ( $filearray ) ? count ( $filearray ) : 0 ;
2026-07-20 15:42:20 +00:00
2017-10-12 10:28:10 +00:00
if ( empty ( $filearray )) {
2020-10-31 08:03:09 +00:00
throw new RestException ( 404 , 'Search for modulepart ' . $modulepart . ' with Id ' . $object -> id . ( ! empty ( $object -> ref ) ? ' or Ref ' . $object -> ref : '' ) . ' does not return any document.' );
2020-12-11 09:21:10 +00:00
} else {
2026-07-23 14:09:22 +00:00
$filearray = array_slice ( $filearray , $limit * $page , $limit );
2020-12-11 09:21:10 +00:00
if (( $object -> id ) > 0 && ! empty ( $modulepart )) {
2021-10-25 20:07:31 +00:00
require_once DOL_DOCUMENT_ROOT . '/ecm/class/ecmfiles.class.php' ;
2020-12-11 09:21:10 +00:00
$ecmfile = new EcmFiles ( $this -> db );
2022-11-25 23:02:17 +00:00
$result = $ecmfile -> fetchAll ( '' , '' , 0 , 0 , array ( 't.src_object_type' => $objectType , 't.src_object_id' => $object -> id ));
2020-12-11 09:21:10 +00:00
if ( $result < 0 ) {
2021-10-25 20:07:31 +00:00
throw new RestException ( 503 , 'Error when retrieve ecm list : ' . $this -> db -> lasterror ());
2020-12-11 09:21:10 +00:00
} elseif ( is_array ( $ecmfile -> lines ) && count ( $ecmfile -> lines ) > 0 ) {
2026-07-23 14:09:22 +00:00
foreach ( $filearray as & $fileitem ) {
2024-05-31 13:24:31 +00:00
foreach ( $ecmfile -> lines as $line ) {
2026-07-23 14:09:22 +00:00
if ( $fileitem [ 'name' ] == $line -> filename ) {
2025-03-02 14:10:25 +00:00
// Next line converts EcmFilesLine properties to array
2026-07-23 14:09:22 +00:00
//$fileitem = array_merge($fileitem, (array) $line);
$fileitem [ 'ref' ] = $line -> ref ;
$fileitem [ 'label' ] = $line -> label ;
$fileitem [ 'filepath' ] = $line -> filepath ;
$fileitem [ 'filename' ] = $line -> filename ;
$fileitem [ 'fullpath_orig' ] = $line -> fullpath_orig ;
$fileitem [ 'position' ] = $line -> position ;
$fileitem [ 'gen_or_uploaded' ] = $line -> gen_or_uploaded ;
$fileitem [ 'description' ] = $line -> desc ;
$fileitem [ 'keywords' ] = $line -> keywords ;
$fileitem [ 'cover' ] = $line -> cover ;
$fileitem [ 'share' ] = $line -> share ;
$fileitem [ 'date_c' ] = $line -> date_c ;
$fileitem [ 'agenda_id' ] = $line -> agenda_id ;
$fileitem [ 'fk_user_c' ] = $line -> fk_user_c ;
$fileitem [ 'fk_user_m' ] = $line -> fk_user_m ;
$fileitem [ 'note_private' ] = $line -> note_private ;
$fileitem [ 'note_public' ] = $line -> note_public ;
2024-05-31 13:24:31 +00:00
}
2023-10-30 23:46:53 +00:00
}
2026-07-23 14:09:22 +00:00
if ( isset ( $fileitem [ 'relativename' ])) {
$fileitem [ 'content-type' ] = dol_mimetype (( string ) $fileitem [ 'relativename' ]);
2025-06-04 09:10:59 +00:00
}
2022-11-25 23:02:17 +00:00
}
2026-07-23 14:09:22 +00:00
// Select only files that match the requested $content_type, if provided
$arraycontenttype = explode ( " , " , $content_type );
if ( ! empty ( $arraycontenttype )) {
$filearray = array_filter (
$filearray ,
/**
* @ param array { name : string , path : string , level1name : string , relativename : string , fullname : string , date : string , size : int , perm : int , type : string , content - type ? : string } $fileitem Item to check for content type ( for filtering )
* @ return bool True if file matches a content type
*/
static function ( $fileitem ) use ( & $arraycontenttype ) {
return in_array (( $fileitem [ 'content-type' ] ? : 'UNKNOWN' ), $arraycontenttype );
}
);
}
2020-12-11 09:21:10 +00:00
}
}
2017-10-12 10:28:10 +00:00
}
2025-06-04 09:10:59 +00:00
//if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
if ( $pagination_data ) {
2026-07-23 14:09:22 +00:00
$filearray = [
'data' => $filearray ,
'pagination' => [
'total' => ( int ) $countarray ,
'page' => $page , // count starts from 0
'page_count' => ( int ) ceil (( int ) $countarray / $limit ),
'limit' => $limit
]
2025-06-04 09:10:59 +00:00
];
}
2017-10-12 10:28:10 +00:00
return $filearray ;
}
2017-10-07 11:09:31 +00:00
/**
* Return a document .
*
* @ param int $id ID of document
* @ return array Array with data of file
*
* @ throws RestException
*/
/*
2021-02-23 16:44:43 +00:00
public function get ( $id ) {
return array ( 'note' => 'xxx' );
} */
2017-10-05 08:21:52 +00:00
2017-10-07 11:09:31 +00:00
/**
2025-06-13 09:44:10 +00:00
* Upload a document
2017-11-06 10:06:31 +00:00
*
2020-02-24 23:51:06 +00:00
* Test sample for invoice : { " filename " : " mynewfile.txt " , " modulepart " : " invoice " , " ref " : " FA1701-001 " , " subdir " : " " , " filecontent " : " content text " , " fileencoding " : " " , " overwriteifexists " : " 0 " } .
* Test sample for supplier invoice : { " filename " : " mynewfile.txt " , " modulepart " : " supplier_invoice " , " ref " : " FA1701-001 " , " subdir " : " " , " filecontent " : " content text " , " fileencoding " : " " , " overwriteifexists " : " 0 " } .
* Test sample for medias file : { " filename " : " mynewfile.txt " , " modulepart " : " medias " , " ref " : " " , " subdir " : " image/mywebsite " , " filecontent " : " Y29udGVudCB0ZXh0Cg== " , " fileencoding " : " base64 " , " overwriteifexists " : " 0 " } .
2017-10-07 11:09:31 +00:00
*
2023-05-10 10:23:32 +00:00
* Supported modules : invoice , order , supplier_order , task / project_task , product / service , expensereport , fichinter , member , propale , agenda , contact
*
2025-06-13 09:44:10 +00:00
* @ since 6.0 . 0 Initial implementation
*
2020-12-16 01:33:21 +00:00
* @ param string $filename Name of file to create ( 'FA1705-0123.txt' )
2021-10-06 14:19:36 +00:00
* @ param string $modulepart Name of module or area concerned by file upload ( 'product' , 'service' , 'invoice' , 'proposal' , 'project' , 'project_task' , 'supplier_invoice' , 'expensereport' , 'member' , ... )
2025-12-14 11:06:41 +00:00
* @ param string $ref Reference of object ( This will define subdir automatically and store submitted file into it ) . For third party use object ID not name .
2025-05-15 00:51:45 +00:00
* @ param string $subdir Subdirectory ( Only if $ref is not provided )
2020-12-16 01:33:21 +00:00
* @ 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 )
* @ param int $overwriteifexists Overwrite file if exists ( 1 by default )
* @ param int $createdirifnotexists Create subdirectories if the doesn ' t exists ( 1 by default )
2024-09-30 14:49:38 +00:00
* @ param int $position Position
* @ param string $cover Cover info
2025-05-15 00:51:45 +00:00
* @ param array $array_options Array for extrafields of ECM index table
* @ param int $generateThumbs 1 = Will generate the small and mini thumbs if applicable
* @ return string
*
2025-03-02 19:40:15 +00:00
* @ phan - param array < string , string > $array_options
* @ phpstan - param array < string , string > $array_options
2017-11-06 10:06:31 +00:00
*
2017-12-27 14:48:20 +00:00
* @ url POST / upload
2024-01-13 18:34:51 +00:00
*
* @ throws RestException 400 Bad Request
2024-02-01 18:16:58 +00:00
* @ throws RestException 403 Access denied
2024-01-13 18:34:51 +00:00
* @ throws RestException 404 Object not found
2024-09-30 14:49:38 +00:00
* @ throws RestException 500 Error on file operation
2017-10-07 11:09:31 +00:00
*/
2025-05-15 00:51:45 +00:00
public function post ( $filename , $modulepart , $ref = '' , $subdir = '' , $filecontent = '' , $fileencoding = '' , $overwriteifexists = 0 , $createdirifnotexists = 1 , $position = 0 , $cover = '' , $array_options = [], $generateThumbs = 0 )
2017-10-07 11:09:31 +00:00
{
2023-08-06 10:26:27 +00:00
global $conf ;
2017-10-07 11:09:31 +00:00
2023-10-30 23:46:53 +00:00
$modulepartorig = $modulepart ;
2021-02-23 16:44:43 +00:00
if ( empty ( $modulepart )) {
2017-10-08 21:26:35 +00:00
throw new RestException ( 400 , 'Modulepart not provided.' );
}
2016-12-12 14:19:47 +00:00
2017-10-07 11:09:31 +00:00
$newfilecontent = '' ;
2021-02-23 16:44:43 +00:00
if ( empty ( $fileencoding )) {
$newfilecontent = $filecontent ;
}
if ( $fileencoding == 'base64' ) {
$newfilecontent = base64_decode ( $filecontent );
}
2016-12-12 14:19:47 +00:00
2017-05-20 13:52:36 +00:00
$original_file = dol_sanitizeFileName ( $filename );
2025-01-07 14:31:41 +00:00
$relativefile = 'UNSET' ;
2016-12-12 14:19:47 +00:00
2017-05-20 13:52:36 +00:00
// Define $uploadir
$object = null ;
2017-10-16 07:29:10 +00:00
$entity = DolibarrApiAccess :: $user -> entity ;
2021-02-23 16:44:43 +00:00
if ( empty ( $entity )) {
$entity = 1 ;
}
2020-12-16 01:33:21 +00:00
2021-02-23 16:44:43 +00:00
if ( $ref ) {
2019-11-22 14:13:30 +00:00
$tmpreldir = '' ;
2023-03-17 20:07:30 +00:00
$fetchbyid = false ;
2017-10-16 07:29:10 +00:00
2021-02-23 16:44:43 +00:00
if ( $modulepart == 'facture' || $modulepart == 'invoice' ) {
2019-11-22 14:13:30 +00:00
$modulepart = 'facture' ;
2017-11-17 10:44:52 +00:00
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php' ;
2017-10-08 21:26:35 +00:00
$object = new Facture ( $this -> db );
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice' ) {
2020-02-24 23:51:06 +00:00
$modulepart = 'supplier_invoice' ;
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php' ;
$object = new FactureFournisseur ( $this -> db );
2022-04-25 23:00:10 +00:00
} elseif ( $modulepart == 'commande' || $modulepart == 'order' ) {
2023-12-04 10:41:14 +00:00
$modulepart = 'commande' ;
2022-04-25 23:00:10 +00:00
2023-12-04 10:41:14 +00:00
require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php' ;
$object = new Commande ( $this -> db );
2022-04-25 23:00:10 +00:00
} elseif ( $modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order' ) {
2023-12-04 10:41:14 +00:00
$modulepart = 'supplier_order' ;
2022-04-25 23:00:10 +00:00
2023-12-04 10:41:14 +00:00
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php' ;
$object = new CommandeFournisseur ( $this -> db );
2023-07-25 21:24:11 +00:00
} elseif ( $modulepart == 'projet' || $modulepart == 'project' ) {
2017-11-17 10:44:52 +00:00
require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php' ;
2017-10-08 21:26:35 +00:00
$object = new Project ( $this -> db );
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'task' || $modulepart == 'project_task' ) {
2017-10-08 21:26:35 +00:00
$modulepart = 'project_task' ;
2017-11-17 10:44:52 +00:00
require_once DOL_DOCUMENT_ROOT . '/projet/class/task.class.php' ;
2017-10-08 21:26:35 +00:00
$object = new Task ( $this -> db );
2024-07-31 16:54:52 +00:00
$task_result = $object -> fetch ( 0 , $ref );
2017-10-08 21:26:35 +00:00
2017-12-27 14:48:20 +00:00
// Fetching the tasks project is required because its out_dir might be a sub-directory of the project
2021-02-23 16:44:43 +00:00
if ( $task_result > 0 ) {
2024-10-26 20:43:44 +00:00
$project_result = $object -> fetchProject ();
2017-10-08 21:26:35 +00:00
2021-02-23 16:44:43 +00:00
if ( $project_result >= 0 ) {
2026-01-20 15:46:14 +00:00
$tmpreldir = dol_sanitizeFileName (( string ) $object -> project -> ref ) . '/' ;
2017-10-08 21:26:35 +00:00
}
2020-10-31 08:03:09 +00:00
} else {
2017-10-08 21:26:35 +00:00
throw new RestException ( 500 , 'Error while fetching Task ' . $ref );
}
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service' ) {
2019-11-08 18:54:38 +00:00
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php' ;
$object = new Product ( $this -> db );
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'expensereport' ) {
2020-02-25 13:36:05 +00:00
require_once DOL_DOCUMENT_ROOT . '/expensereport/class/expensereport.class.php' ;
$object = new ExpenseReport ( $this -> db );
2026-01-29 21:55:38 +00:00
} elseif ( $modulepart == 'holiday' ) {
require_once DOL_DOCUMENT_ROOT . '/holiday/class/holiday.class.php' ;
$object = new Holiday ( $this -> db );
2025-06-25 17:25:57 +00:00
} elseif ( $modulepart == 'ficheinter' || $modulepart == 'intervention' ) {
2022-01-23 11:06:40 +00:00
require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php' ;
$object = new Fichinter ( $this -> db );
2025-07-18 00:45:38 +00:00
} elseif ( $modulepart == 'shipment' || $modulepart == 'expedition' ) {
require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php' ;
$object = new Expedition ( $this -> db );
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'adherent' || $modulepart == 'member' ) {
2020-06-16 20:46:36 +00:00
$modulepart = 'adherent' ;
2020-06-14 12:42:54 +00:00
require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php' ;
$object = new Adherent ( $this -> db );
2021-02-23 16:44:43 +00:00
} elseif ( $modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale' ) {
2020-10-28 00:47:25 +00:00
$modulepart = 'propale' ;
require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php' ;
$object = new Propal ( $this -> db );
2023-05-01 20:11:35 +00:00
} elseif ( $modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event' ) {
$modulepart = 'agenda' ;
require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php' ;
$object = new ActionComm ( $this -> db );
2023-03-15 15:00:20 +00:00
} elseif ( $modulepart == 'contact' || $modulepart == 'socpeople' ) {
$modulepart = 'contact' ;
require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php' ;
$object = new Contact ( $this -> db );
$fetchbyid = true ;
2025-10-09 03:45:01 +00:00
} elseif ( $modulepart == 'societe' || $modulepart == 'company' ) {
$modulepart = 'societe' ;
require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php' ;
$object = new Societe ( $this -> db );
$fetchbyid = true ;
2026-07-23 14:09:22 +00:00
} elseif ( $modulepart == 'knowledgemanagement' ) {
2025-10-11 11:39:43 +00:00
$modulepart = 'knowledgemanagement' ;
require_once DOL_DOCUMENT_ROOT . '/knowledgemanagement/class/knowledgerecord.class.php' ;
$object = new KnowledgeRecord ( $this -> db );
$fetchbyid = true ;
2026-07-23 14:09:22 +00:00
} elseif ( $modulepart == 'ticket' ) {
2025-10-09 03:45:01 +00:00
$modulepart = 'ticket' ;
require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php' ;
$object = new Ticket ( $this -> db );
$fetchbyid = true ;
2023-05-01 17:45:33 +00:00
} elseif ( $modulepart == 'contrat' || $modulepart == 'contract' ) {
$modulepart = 'contrat' ;
require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php' ;
$object = new Contrat ( $this -> db );
2024-07-31 13:43:13 +00:00
} elseif ( $modulepart == 'mrp' ) {
$modulepart = 'mrp' ;
require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php' ;
$object = new Mo ( $this -> db );
2025-12-18 08:41:43 +00:00
} elseif ( $modulepart == 'stock' ) {
$modulepart = 'stock' ;
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php' ;
$object = new Entrepot ( $this -> db );
2025-06-25 19:36:36 +00:00
} elseif ( $modulepart == 'ecm' ) {
throw new RestException ( 500 , 'Using a non empty "ref" is not compatible with using modulepart = ' . $modulepart );
2020-10-31 08:03:09 +00:00
} else {
2020-12-01 01:41:19 +00:00
// TODO Implement additional moduleparts
2017-10-08 21:26:35 +00:00
throw new RestException ( 500 , 'Modulepart ' . $modulepart . ' not implemented yet.' );
}
2025-10-08 19:32:49 +00:00
// at this step $object is always an object
if ( $fetchbyid ) {
// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
$result = $object -> fetch (( int ) $ref );
} else {
$result = $object -> fetch ( 0 , $ref );
}
2017-10-08 21:26:35 +00:00
2025-10-08 19:32:49 +00:00
if ( $result == 0 ) {
throw new RestException ( 404 , " Object with ref ' " . $ref . " ' was not found. " );
} elseif ( $result < 0 ) {
throw new RestException ( 500 , 'Error while fetching object: ' . $object -> error );
2017-10-06 00:42:32 +00:00
}
2020-12-16 01:33:21 +00:00
if ( ! ( $object -> id > 0 )) {
2021-02-23 16:44:43 +00:00
throw new RestException ( 404 , 'The object ' . $modulepart . " with ref ' " . $ref . " ' was not found. " );
2017-10-06 00:42:32 +00:00
}
2020-02-24 23:51:06 +00:00
// Special cases that need to use get_exdir to get real dir of object
2022-04-25 23:00:10 +00:00
// In future, all object should use this to define path of documents.
2020-02-24 23:51:06 +00:00
if ( $modulepart == 'supplier_invoice' ) {
$tmpreldir = get_exdir ( $object -> id , 2 , 0 , 0 , $object , 'invoice_supplier' );
}
2023-10-26 10:22:54 +00:00
// Test on permissions
2025-06-25 19:36:36 +00:00
//if ($modulepart != 'ecm') { // Here $modulepart is always != 'ecm'
2025-12-14 12:47:53 +00:00
if ( $modulepart == 'societe' ) {
2025-12-14 11:49:34 +00:00
$relativefile = $tmpreldir . dol_sanitizeFileName (( string ) $object -> id );
2025-12-14 10:54:09 +00:00
} else {
2026-01-20 13:01:09 +00:00
$relativefile = $tmpreldir . dol_sanitizeFileName (( string ) $object -> ref );
2025-12-14 10:54:09 +00:00
}
2025-06-25 19:36:36 +00:00
$tmp = dol_check_secure_access_document ( $modulepart , $relativefile , $entity , DolibarrApiAccess :: $user , $ref , 'write' );
2026-07-13 14:13:51 +00:00
if ( empty ( $tmp [ 'accessallowed' ])) {
throw new RestException ( 403 , 'Access not allowed to upload file into this directory' );
}
2025-06-25 19:36:36 +00:00
$upload_dir = $tmp [ 'original_file' ]; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
/* } else {
2023-10-26 10:22:54 +00:00
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'ecm' , 'upload' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 , 'Missing permission to upload files in ECM module' );
2023-10-26 10:22:54 +00:00
}
$upload_dir = $conf -> medias -> multidir_output [ $conf -> entity ];
2025-06-25 19:36:36 +00:00
} */
2017-10-06 00:42:32 +00:00
2021-02-23 16:44:43 +00:00
if ( empty ( $upload_dir ) || $upload_dir == '/' ) {
2020-12-16 01:33:21 +00:00
throw new RestException ( 500 , 'This value of modulepart (' . $modulepart . ') does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.' );
2017-10-06 00:42:32 +00:00
}
2020-10-31 08:03:09 +00:00
} else {
2021-02-23 16:44:43 +00:00
if ( $modulepart == 'invoice' ) {
$modulepart = 'facture' ;
}
if ( $modulepart == 'member' ) {
$modulepart = 'adherent' ;
}
2017-10-05 08:21:52 +00:00
2023-10-26 10:22:54 +00:00
// Test on permissions
if ( $modulepart != 'ecm' ) {
$relativefile = $subdir ;
$tmp = dol_check_secure_access_document ( $modulepart , $relativefile , $entity , DolibarrApiAccess :: $user , '' , 'write' );
2026-07-13 14:13:51 +00:00
if ( empty ( $tmp [ 'accessallowed' ])) {
throw new RestException ( 403 , 'Access not allowed to upload file into this directory' );
}
2023-10-26 10:22:54 +00:00
$upload_dir = $tmp [ 'original_file' ]; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
} else {
if ( ! DolibarrApiAccess :: $user -> hasRight ( 'ecm' , 'upload' )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 , 'Missing permission to upload files in ECM module' );
2023-10-26 10:22:54 +00:00
}
$upload_dir = $conf -> medias -> multidir_output [ $conf -> entity ];
}
2017-05-20 13:52:36 +00:00
2020-12-16 01:33:21 +00:00
if ( empty ( $upload_dir ) || $upload_dir == '/' ) {
if ( ! empty ( $tmp [ 'error' ])) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 , 'Error returned by dol_check_secure_access_document: ' . $tmp [ 'error' ]);
2020-12-16 01:33:21 +00:00
} else {
2024-01-13 18:34:51 +00:00
throw new RestException ( 400 , 'This value of modulepart (' . $modulepart . ') is not allowed with this value of subdir (' . $relativefile . ')' );
2020-12-16 01:33:21 +00:00
}
2017-10-06 00:42:32 +00:00
}
2016-12-12 14:19:47 +00:00
}
2017-12-27 14:48:20 +00:00
// $original_file here is still value of filename without any dir.
2017-10-05 08:21:52 +00:00
2017-05-20 13:52:36 +00:00
$upload_dir = dol_sanitizePathName ( $upload_dir );
2019-11-08 18:58:49 +00:00
2020-12-16 01:33:21 +00:00
if ( ! empty ( $createdirifnotexists )) {
if ( dol_mkdir ( $upload_dir ) < 0 ) { // needed by products
2020-12-23 16:25:38 +00:00
throw new RestException ( 500 , 'Error while trying to create directory ' . $upload_dir );
2020-12-16 01:33:21 +00:00
}
2019-11-08 18:54:38 +00:00
}
2017-10-05 08:21:52 +00:00
2019-11-22 14:13:30 +00:00
$destfile = $upload_dir . '/' . $original_file ;
$destfiletmp = DOL_DATA_ROOT . '/admin/temp/' . $original_file ;
2017-05-21 12:06:43 +00:00
dol_delete_file ( $destfiletmp );
2017-12-27 14:48:20 +00:00
//var_dump($original_file);exit;
2017-10-05 08:21:52 +00:00
2017-12-27 14:48:20 +00:00
if ( ! dol_is_dir ( dirname ( $destfile ))) {
2024-01-13 18:34:51 +00:00
throw new RestException ( 400 , 'Directory does not exists : ' . dirname ( $destfile ));
2017-10-06 00:42:32 +00:00
}
2017-10-05 08:21:52 +00:00
2020-12-16 01:33:21 +00:00
if ( ! $overwriteifexists && dol_is_file ( $destfile )) {
2024-01-13 18:34:51 +00:00
throw new RestException ( 400 , " File with name ' " . $original_file . " ' already exists. " );
2017-10-06 00:42:32 +00:00
}
2017-10-05 08:21:52 +00:00
2023-05-02 03:58:18 +00:00
// in case temporary directory admin/temp doesn't exist
if ( ! dol_is_dir ( dirname ( $destfiletmp ))) {
dol_mkdir ( dirname ( $destfiletmp ));
2023-05-01 20:11:35 +00:00
}
2017-10-06 00:42:32 +00:00
$fhandle = @ fopen ( $destfiletmp , 'w' );
2020-10-31 08:08:07 +00:00
if ( $fhandle ) {
2017-10-06 00:42:32 +00:00
$nbofbyteswrote = fwrite ( $fhandle , $newfilecontent );
fclose ( $fhandle );
2023-02-17 18:30:50 +00:00
dolChmod ( $destfiletmp );
2020-10-31 08:03:09 +00:00
} else {
2017-10-06 00:42:32 +00:00
throw new RestException ( 500 , " Failed to open file ' " . $destfiletmp . " ' for write " );
}
2016-12-12 14:19:47 +00:00
2023-07-12 20:56:27 +00:00
$disablevirusscan = 0 ;
$src_file = $destfiletmp ;
$dest_file = $destfile ;
// Security:
// If we need to make a virus scan
if ( empty ( $disablevirusscan ) && file_exists ( $src_file )) {
2024-01-09 20:37:53 +00:00
$checkvirusarray = dolCheckVirus ( $src_file , $dest_file );
2023-07-12 20:56:27 +00:00
if ( count ( $checkvirusarray )) {
Qual: Apply automatic phan fixes (deprecations, unneeded imports) (#28154)
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
2024-02-13 20:46:12 +00:00
dol_syslog ( 'Files.lib::dol_move_uploaded_file File "' . $src_file . '" (target name "' . $dest_file . '") KO with antivirus: errors=' . implode ( ',' , $checkvirusarray ), LOG_WARNING );
throw new RestException ( 500 , 'ErrorFileIsInfectedWithAVirus: ' . implode ( ',' , $checkvirusarray ));
2023-07-12 20:56:27 +00:00
}
}
// Security:
// Disallow file with some extensions. We rename them.
// Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
2023-10-24 15:00:13 +00:00
if ( isAFileWithExecutableContent ( $dest_file ) && ! getDolGlobalString ( 'MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED' )) {
2023-07-12 20:56:27 +00:00
// $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
$publicmediasdirwithslash = $conf -> medias -> multidir_output [ $conf -> entity ];
if ( ! preg_match ( '/\/$/' , $publicmediasdirwithslash )) {
$publicmediasdirwithslash .= '/' ;
}
if ( strpos ( $upload_dir , $publicmediasdirwithslash ) !== 0 || ! getDolGlobalInt ( " MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR " )) { // We never add .noexe on files into media directory
$dest_file .= '.noexe' ;
}
}
// Security:
// We refuse cache files/dirs, upload using .. and pipes into filenames.
if ( preg_match ( '/^\./' , basename ( $src_file )) || preg_match ( '/\.\./' , $src_file ) || preg_match ( '/[<>|]/' , $src_file )) {
dol_syslog ( " Refused to deliver file " . $src_file , LOG_WARNING );
throw new RestException ( 500 , " Refused to deliver file " . $src_file );
}
// Security:
// We refuse cache files/dirs, upload using .. and pipes into filenames.
if ( preg_match ( '/^\./' , basename ( $dest_file )) || preg_match ( '/\.\./' , $dest_file ) || preg_match ( '/[<>|]/' , $dest_file )) {
dol_syslog ( " Refused to deliver file " . $dest_file , LOG_WARNING );
throw new RestException ( 500 , " Refused to deliver file " . $dest_file );
}
2023-10-30 23:46:53 +00:00
$moreinfo = array ( 'note_private' => 'File uploaded using API /documents from IP ' . getUserRemoteIP ());
2025-10-08 19:32:49 +00:00
// $object may be null
if ( is_object ( $object ) && $object -> id > 0 ) {
2023-10-31 09:44:58 +00:00
$moreinfo [ 'src_object_type' ] = $object -> table_element ;
2023-10-30 23:46:53 +00:00
$moreinfo [ 'src_object_id' ] = $object -> id ;
}
2024-09-30 14:49:38 +00:00
if ( ! empty ( $array_options )) {
$moreinfo = array_merge ( $moreinfo , [ " array_options " => $array_options ]);
}
if ( ! empty ( $position )) {
$moreinfo = array_merge ( $moreinfo , [ " position " => $position ]);
}
if ( ! empty ( $cover )) {
$moreinfo = array_merge ( $moreinfo , [ " cover " => $cover ]);
}
2025-05-19 07:45:31 +00:00
$moreinfo [ 'gen_or_uploaded' ] = 'api' ;
2023-10-30 23:46:53 +00:00
// Move the temporary file at its final emplacement
2024-09-05 14:05:37 +00:00
$result = dol_move ( $destfiletmp , $dest_file , '0' , $overwriteifexists , 1 , 1 , $moreinfo );
2020-10-31 08:08:07 +00:00
if ( ! $result ) {
2024-09-26 01:46:21 +00:00
throw new RestException ( 500 , " Failed to move file into ' " . $dest_file . " ' " );
2017-12-27 14:48:20 +00:00
}
2017-10-06 00:42:32 +00:00
2025-05-15 00:51:45 +00:00
if ( is_object ( $object ) && $generateThumbs ) {
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
if ( image_format_supported ( $dest_file )) {
$object -> addThumbs ( $dest_file );
}
}
2017-12-27 14:48:20 +00:00
return dol_basename ( $destfile );
2017-10-06 00:42:32 +00:00
}
2019-11-08 23:48:46 +00:00
2019-11-08 23:47:03 +00:00
/**
2025-06-13 09:44:10 +00:00
* Delete a document
*
* @ since 11.0 . 0 Initial implementation
2019-11-08 23:47:03 +00:00
*
2025-10-07 18:48:58 +00:00
* @ param string $modulepart Name of module or area concerned by file download ( 'product' , 'project' , 'project_task' , ... )
2019-11-08 23:47:03 +00:00
* @ param string $original_file Relative path with filename , relative to modulepart ( for example : PRODUCT - REF - 999 / IMAGE - 999. jpg )
2025-03-02 14:10:25 +00:00
* @ return array Success code
* @ phan - return array { success : array { code : int , message : string }}
* @ phpstan - return array { success : array { code : int , message : string }}
2019-11-08 23:47:03 +00:00
*
2019-11-09 10:52:03 +00:00
* @ url DELETE /
2024-01-13 18:34:51 +00:00
*
* @ throws RestException 400 Bad value for parameter modulepart
* @ throws RestException 400 Bad value for parameter original_file
2024-02-01 18:16:58 +00:00
* @ throws RestException 403 Access denied
2024-01-13 18:34:51 +00:00
* @ throws RestException 404 File not found
* @ throws RestException 500 Error on file operation
2019-11-08 23:47:03 +00:00
*/
2019-11-09 18:01:03 +00:00
public function delete ( $modulepart , $original_file )
2019-11-08 23:47:03 +00:00
{
2025-05-15 00:51:45 +00:00
global $conf ;
2019-11-08 23:48:46 +00:00
2020-10-31 13:32:18 +00:00
if ( empty ( $modulepart )) {
throw new RestException ( 400 , 'bad value for parameter modulepart' );
}
if ( empty ( $original_file )) {
throw new RestException ( 400 , 'bad value for parameter original_file' );
}
2019-11-08 23:48:46 +00:00
2025-10-07 18:48:58 +00:00
// Normalize modulepart for project_task
if ( $modulepart == 'task' ) {
$modulepart = 'project_task' ;
}
2020-10-31 13:32:18 +00:00
//--- Finds and returns the document
$entity = $conf -> entity ;
2019-11-08 23:48:46 +00:00
2020-10-31 13:32:18 +00:00
// Special cases that need to use get_exdir to get real dir of object
// If future, all object should use this to define path of documents.
/*
2021-02-23 16:44:43 +00:00
$tmpreldir = '' ;
if ( $modulepart == 'supplier_invoice' ) {
$tmpreldir = get_exdir ( $object -> id , 2 , 0 , 0 , $object , 'invoice_supplier' );
}
2020-02-25 13:59:47 +00:00
2021-02-23 16:44:43 +00:00
$relativefile = $tmpreldir . dol_sanitizeFileName ( $object -> ref ); */
2020-10-31 13:32:18 +00:00
$relativefile = $original_file ;
2020-02-25 13:59:47 +00:00
2026-06-29 11:31:23 +00:00
$check_access = dol_check_secure_access_document ( $modulepart , $relativefile , $entity , DolibarrApiAccess :: $user , '' , 'write' );
2020-10-31 13:32:18 +00:00
$accessallowed = $check_access [ 'accessallowed' ];
$sqlprotectagainstexternals = $check_access [ 'sqlprotectagainstexternals' ];
$original_file = $check_access [ 'original_file' ];
2019-11-08 23:48:46 +00:00
2020-10-31 13:32:18 +00:00
if ( preg_match ( '/\.\./' , $original_file ) || preg_match ( '/[<>|]/' , $original_file )) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2020-10-31 13:32:18 +00:00
}
if ( ! $accessallowed ) {
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2020-10-31 13:32:18 +00:00
}
2019-11-08 23:48:46 +00:00
2026-03-02 03:25:53 +00:00
if ( DolibarrApiAccess :: $user -> socid > 0 ) {
if ( $sqlprotectagainstexternals ) {
$resql = $this -> db -> query ( $sqlprotectagainstexternals );
if ( $resql ) {
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
while ( $i < $num ) {
$obj = $this -> db -> fetch_object ( $resql );
if ( DolibarrApiAccess :: $user -> socid != $obj -> fk_soc ) {
throw new RestException ( 403 , 'Not allowed to download documents with such a ref' );
}
$i ++ ;
}
}
}
}
2020-10-31 13:32:18 +00:00
$filename = basename ( $original_file );
$original_file_osencoded = dol_osencode ( $original_file ); // New file name encoded in OS encoding charset
2019-11-08 23:48:46 +00:00
2021-02-23 16:44:43 +00:00
if ( ! file_exists ( $original_file_osencoded )) {
2020-10-31 13:32:18 +00:00
dol_syslog ( " Try to download not found file " . $original_file_osencoded , LOG_WARNING );
throw new RestException ( 404 , 'File not found' );
}
2019-11-08 23:48:46 +00:00
2020-10-31 13:32:18 +00:00
if ( @ unlink ( $original_file_osencoded )) {
return array (
'success' => array (
'code' => 200 ,
'message' => 'Document deleted'
)
);
}
2019-11-08 23:48:46 +00:00
2024-02-01 18:16:58 +00:00
throw new RestException ( 403 );
2019-11-08 23:47:03 +00:00
}
2016-12-12 14:19:47 +00:00
}