<?php


//Déclaration d'un item de menu dans le menu principal
function document_menu(&$menuItems){
	global $myUser;

	if(!$myUser->can('document','read')) return;
	$menuItems[] = array(
		'sort'=>4,
		'url'=>'index.php?module=document',
		'label'=>'Documents',
		'icon'=> 'far fa-copy',
		'color'=> '#FFBA00'
	);
}

//Cette fonction va generer une page quand on clique sur document dans menu
function document_page(){
	global $_;
	if(!isset($_['module']) || $_['module'] !='document') return;
	$page = !isset($_['page']) ? 'list' : $_['page'];
	$file = __DIR__.SLASH.'page.'.$page.'.php';
	if(!file_exists($file)) throw new Exception("Page ".$page." inexistante");
	require_once($file);
}

//Fonction executée lors de l'activation du plugin
function document_install($id){
	if($id != 'fr.core.document') return;
	Entity::install(__DIR__);
	if(!file_exists(Element::root()))
		mkdir(Element::root(),0755,true);

	if(!file_exists(__DIR__.SLASH.'logs'))
		mkdir(__DIR__.SLASH.'logs',0755,true);

	global $conf;
	$conf->put('document_allowed_extensions','csv,xls,xlsx,doc,docx,dotm,dotx,pdf,png,jpg,jpeg,gif,tif,svg,bmp,txt,zip,gzip,msg');
	$conf->put('document_allowed_size',10485760);
}

//Fonction executée lors de la désactivation du plugin
function document_uninstall($id){
	if($id != 'fr.core.document') return;
	Entity::uninstall(__DIR__);
}

//Déclaration des sections de droits du plugin
//Déclaration des sections de droits du plugin
Right::register('document',array('label'=>'Gestion des droits sur le plugin document'));



//Déclaration du menu de réglages
function document_menu_setting(&$settingMenu){
	global  $myUser;

	if($myUser->can('document','configure')) {
		$settingMenu[]= array(
			'sort' =>4,
			'url' => 'setting.php?section=document',
			'icon' => 'fas fa-angle-right',
			'label' => 'Documents'
		);
	}
}

//Déclaration des pages de réglages
function document_content_setting(){
	global $_;
	if(file_exists(__DIR__.SLASH.'setting.'.$_['section'].'.php'))
		require_once(__DIR__.SLASH.'setting.'.$_['section'].'.php');
}

//Vérifie qu'un nom de fichier ou de dossier ne contient pas des caractères interdits par l'os (?:*|<>/\)
function document_check_element_name($element){
	preg_match('/[?:*|<>\/\\\\]/', $element, $match);
	return !empty($match) ? $match[0] : '';
}

function document_dav_document($requested){
	global $conf,$myUser;
	$requested = trim($requested, '/');

	if(substr($requested, 0,13)!='dav/documents') return;
	if(empty($requested)) throw new Exception("Unspecified DAV path");

	if($conf->get('document_enable_dav') != "1"){
		header('HTTP/1.1 501 Method not implemented');
	    header('Content-Type: text/html; charset=utf-8');
		throw new Exception('Mode Webdav désactivé, veuillez débloquer le Webdav dans les paramétrages pour accéder à cette fonctionnalité');
	}

	require_once(__ROOT__.'common.php');
	require_once(__DIR__.SLASH.'Element.class.php');
	require_once(__DIR__.SLASH.'WebDav.class.php');

	$projectPath = preg_replace('|https?\:\/\/'.$_SERVER['HTTP_HOST'].'|i', '', ROOT_URL);

	$server = new WebDav();
	$server->logs = WebDav::logPath().SLASH.'dav-logs.txt';
	$server->lockfile = WebDav::logPath().SLASH.'dav-lock.json';
	$server->root = str_replace('//','/',$projectPath.'/dav/documents/');
	$server->folder = Element::root();

	//Windows cherche desktop.ini a chaque ouverture de dossier pour le custom
	$server->ignoreFiles[] = 'desktop.ini';
	//Tortoise et autre client git d'explorer cherchent les .git a chaques ouverture
	$server->ignoreFiles[] = '.git';

	if($conf->get('document_enable_dav_logs') == "1"){
		$server->on['log'] = function($message){
			Log::put(nl2br($message),'DAV');
		};
	}

	$server->do['login'] = function($login,$password){
		global $myUser;

		if($myUser->login !=''){

			return $myUser;
		}


		$myUser = User::check($login,$password);

		if(!$myUser)
			throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur",401);

		if(file_exists('enabled.maintenance') && $myUser->superadmin != 1)
			throw new Exception('Seul un compte Super Admin peut se connecter en mode maintenance',401);

		if(!$myUser->connected())
			throw new Exception('Identifiant ou mot de passe incorrect',401);

		if(is_numeric($myUser->preference('default_firm')) && $myUser->haveFirm($myUser->preference('default_firm'))){
			$_SESSION['firm'] = serialize(Firm::getById($myUser->preference('default_firm')));
			if(!$_SESSION['firm'])
				throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur",401);

		}else if(count($myUser->firms)!=0){
			$_SESSION['firm'] = serialize(reset($myUser->firms));
			if(!$_SESSION['firm'])
				throw new Exception(" Problème lors de la connexion, veuillez contacter l'administrateur",401);
		}else{
			throw new Exception('Ce compte n\'est actif sur aucune firm',401);
		}

		$myFirm = isset($_SESSION['firm']) ? unserialize($_SESSION['firm']) : new Firm();
		if(!$myFirm)
			throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur",401);

		$_SESSION['currentUser'] = serialize($myUser);
		if(!$_SESSION['currentUser'])
			throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur",401);
	};

	$server->do['delete'] = function($isoPath){
		global $myUser,$conf;
		$utf8Path = utf8_encode($isoPath);
		Element::remove($utf8Path);
		if($conf->get('document_enable_logs')) Log::put('Suppression de '.$utf8Path,'document');
	};

	$server->do['download'] = function($isoPath){
		global $myUser,$_,$conf;
		$utf8Path = utf8_encode($isoPath);

		//pour verfiier si le fichier existe, on récupere son chemin système avec le bon encodage
		$osPath = get_OS() === 'WIN' ? $isoPath: $utf8Path;

		if(!file_exists($osPath))  throw new Exception("Fichier inexistant",404);
	    if(!is_file($osPath)) throw new Exception("Méthode non autorisée sur autre chose qu'un fichier",501);

		$stream = Element::download($utf8Path);

		if($conf->get('document_enable_logs_verbose')) Log::put('Téléchargement de '.$utf8Path,'document');

		return $stream;
	};

	$server->do['edit'] = function($isoPath,$body,$type){
		global $myUser,$conf;
		User::check_access('document','edit');
		$utf8Path = utf8_encode($isoPath);

		if($type=='file'){
			$maxSize = $conf->get('document_allowed_size');
			$extension = getExt($utf8Path);
			$extensions = explode(',',str_replace(' ', '', $conf->get('document_allowed_extensions')));
			if(strlen($body) > $maxSize) throw new Exception("Taille du fichier  trop grande, taille maximum :".readable_size($maxSize).' ('.$maxSize.' octets)',406);
			if(!in_array($extension , $extensions)) throw new Exception("Extension '".$extension."' du fichier ".$path." non permise, autorisé :".implode(', ',$extensions),415);
			$element = Element::addFile($utf8Path, $body);
			if($conf->get('document_enable_logs') || $conf->get('document_enable_logs_verbose')) Log::put('Enregistrement fichier '.$utf8Path,'document');
		}else{
			Element::addFolder($utf8Path);
			if($conf->get('document_enable_logs') || $conf->get('document_enable_logs_verbose')) Log::put('Enregistrement dossier '.$utf8Path,'document');
		}

		$element = Element::fromPath($utf8Path);
		$baseElement = Element::load(array('path'=>$element->path));
		if(is_object($baseElement) && $baseElement->id!=0) $element->id = $baseElement->id;
		$element->save();
	};

	$server->do['move'] = function($isoPath,$isoTo){
		global $myUser,$conf;
		$utf8Path = utf8_encode($isoPath);
		$utf8To = utf8_encode($isoTo);
		User::check_access('document','edit');
		$char = document_check_element_name(mt_basename($utf8To));
		if(!empty($char)) throw new Exception("Caractères interdits : ".$char);

		Element::move($utf8Path,$utf8To);
		if($conf->get('document_enable_logs') || $conf->get('document_enable_logs_verbose')) Log::put('Déplacement de '.$utf8Path.' dans '.$utf8To,'document');
	};

	$server->do['copy'] = function($isoPath,$isoTo){
		global $myUser,$conf;
		$utf8Path = utf8_encode($isoPath);
		$utf8To = utf8_encode($isoTo);
		User::check_access('document','edit');
		$char = document_check_element_name(mt_basename($utf8To));
		if(!empty($char)) throw new Exception("Caractères interdits : ".$char);

		Element::copy($utf8Path,$utf8To);
		if($conf->get('document_enable_logs') || $conf->get('document_enable_logs_verbose')) Log::put('Copie de '.$utf8Path.' dans '.$utf8To,'document');
	};

	$server->do['list'] = function($isoPath,$depth =0){
		global $myUser,$conf;
		$utf8Path = utf8_encode($isoPath);
		User::check_access('document','read');

		//pour verfier si le fichier existe, on récupere son chemin système avec le bon encodage
		$osPath = get_OS() === 'WIN' ? $isoPath: $utf8Path;
		if(!file_exists($osPath)) throw new Exception("Not found", 404);

		$files = array();

		//Si la cible est la racine dav, on la retourne sous forme d'element fictif, sinon on utilise le systeme d'element standard
		if($utf8Path == Element::root()){
			$file = new Element();
			$file->label = '';
			$file->type = 'directory';
			$file->path = '';
			$toScan = array($file);
		}else{
			$toScan = array(Element::fromPath($utf8Path));
		}

		if($conf->get('document_enable_logs_verbose')) Logs::put('visualisation de '.$utf8Path,'document');

		//Si le dav demande un scan en profondeur du dossier, on scan les enfants du dossier ciblé
		if($depth>0)
			$toScan = array_merge($toScan,Element::browse($utf8Path.SLASH.'*'));

		foreach($toScan as $element){
			//on convertis l'utf8 de l'element pour passer en iso webdav windows si le serveur est sous windows
			$path = Element::root().(get_OS() === 'WIN' ? utf8_decode( $element->path) : $element->path );

		    $file = array(
				'type' => $element->type,
				'label' =>  $element->label
		    );

		    if($element->type == 'directory'){
		    	$stat = stat($path);
				$file['create_time']  = $stat['ctime'];
				$file['update_time']  = $stat['mtime'];
				$file['length'] =  $stat['size'];
			}else{
				$file['create_time']  =  filectime($path);
				$file['update_time']  =  filemtime($path);
				$file['length'] =  filesize($path);
			}

			$files[] = $file;
		}

		return $files;
	};

	$server->start();
}

//Déclaration des settings de base
//Types possibles : text,select ( + "values"=> array('1'=>'Val 1'),password,checkbox. Un simple string définit une catégorie.
Configuration::setting('document',array(
    "Général",
    'document_allowed_extensions' => array("label"=>"Extensions autorisées","type"=>"text","legend"=>"(séparés par virgules)","placeholder"=>"csv,pdf,jpg,..."),
    'document_allowed_size' => array("label"=>"Taille maximum autorisée","type"=>"text","legend"=>"(en octets)","placeholder"=>"28060000","type"=>"number"),

    'document_enable_logs' => array("label"=>"Activer les logs standards","legend"=>"(ajout, supression, modifification d'un fichier ou dossier)","type"=>"boolean"),
    'document_enable_logs_verbose' => array("label"=>"Activer les logs avancés","legend"=>"(lecture ou téléchargement d'un fichier ou dossier)","type"=>"boolean"),
    "Options DAV <br><small style='font-size:65%;'>Adresse WebDAV : <code>".
    ( substr(ROOT_URL,-1) == '/' ? substr(ROOT_URL,0,(strlen(ROOT_URL)-1)) : ROOT_URL )
    ."/dav/documents</code><br>
    Les Identifiants sont identiques à ceux de l'erp<br>
    Si vous souhaitez vous connecter avec un lecteur réseau windows, vous devez installer un certificat https</small>",
    'document_enable_dav' => array("label"=>"Activer le WebDav","type"=>"boolean"),
    'document_enable_dav_logs' => array("label"=>"Activer les logs WebDav  ","type"=>"boolean"),
    'document_client_directory' => array("label"=>"Chemin vers le dossier document des clients","placeholder"=>"documents/Affaires/{{slug}}","type"=>"text"),
));



function document_widget(&$widgets){
	global $myUser;
	require_once(__DIR__.SLASH.'..'.SLASH.'dashboard'.SLASH.'DashboardWidget.class.php');

	$modelWidget = new DashboardWidget();
	$modelWidget->model = 'document';
	$modelWidget->title = 'Documents';

	$modelWidget->icon = 'fas fa-file';
	$modelWidget->background = '#A3CB38';
	$modelWidget->callback = 'init_components';
	$modelWidget->load = 'action.php?action=document_widget_load';
	if($myUser->can('document','configure')){
		$modelWidget->configure = 'action.php?action=document_widget_configure';
		$modelWidget->configure_callback = 'document_widget_configure_save';
	}
	$modelWidget->js = [Plugin::url().'/js/widget.js?v='.time()];
	$modelWidget->css = [Plugin::url().'/css/widget.css?v=1'.time()];
	$modelWidget->description = "Affiche un espace document";

	$widgets[] = $modelWidget;
}


function document_client_menu(&$clientMenu,$client){
	global $myUser;
	if(!$myUser->can('document','read')) return;
	$menu = new MenuItem();
	$menu->label = 'Documents';
	$menu->url = '#tab=document';
	$menu->slug = 'document';
	$menu->sort = 10;
	$clientMenu[] = $menu;
}

function document_client_page($slug){
	if($slug != 'document') return;
	require_once(__DIR__.SLASH.'tab.client.php');
}



function document_client_merge($clientBase,$clientToMerge,&$logs){
	global $_,$myUser,$conf;
	Plugin::need('client/Client');
	require_once(__DIR__.SLASH.'Element.class.php');
	$logs[] = ' Migration des documents attaches ';



	$clientDirectoryTemplate = empty($conf->get('document_client_directory')) ? 'Clients'.SLASH.'{{slug}}' : $conf->get('document_client_directory');

	$toMergeRelativeDirectory = str_replace('{{slug}}',$clientToMerge->slug,$clientDirectoryTemplate);
	$toMergeDirectory = Element::root().$toMergeRelativeDirectory;

	if(!file_exists($toMergeDirectory)) return;

	$baseRelativeDirectory = str_replace('{{slug}}',$clientBase->slug,$clientDirectoryTemplate);
	$baseDirectory = Element::root().$baseRelativeDirectory;

	if(!file_exists($baseDirectory)) mkdir($baseDirectory,0755,true);
	File::merge($baseDirectory,$toMergeDirectory);
}


$api = new Api("document", "Api de gestion des documents");
$api->route('element/search','retourne une liste de documents','GET',function($request,&$response){
	global $myUser,$_;
	$_ = $request['parameters'];
	if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
	Action::run('document_element_search',$response);
});
$api->route('element/upload','Upload un fichier dans la racine spécifiée','POST',function($request,&$response){
	global $myUser,$_;


	if(isset($_SERVER['CONTENT_TYPE'])){
	  if(preg_match('/multipart\/(related|form); boundary=(.*)/is', $_SERVER['CONTENT_TYPE'],$match)){
	  	$boundary = $match[2];
	   	$parts = explode('--'.$boundary, $request['body']);
	   	$parts = array_filter($parts);

	   	$contents = array();
	   	foreach ($parts as $part) {
	   		if(empty(trim($part))) continue;

	   		list($header,$body) = explode("\n\n",$part,2);
	   		$content = array(
	   			'header' => array(),
	   			'body'=>substr($body,0,-2)
	   		);
	   		foreach(explode("\n",substr($header,1)) as $header){
	   			$headerInfos = explode(':',$header);
	   			$content['header'][$headerInfos[0]] = $headerInfos[1];
	   		}
	   		$contents[] = $content;
	   	}

	  }
	}

	$i = 0;
	foreach($contents as $content){
		//fichier
		if(isset($content['header']['Content-Disposition']) && strpos($content['header']['Content-Disposition'], 'filename="') !==-1){
			preg_match('/filename="(.*)"/', $content['header']['Content-Disposition'],$matches);
			$_FILES['file']['name'][$i] = $matches[1];
			$_FILES['file']['size'][$i] = strlen($content['body']);
			$tmpfname = tempnam(sys_get_temp_dir(), 'up_');
			file_put_contents($tmpfname , $content['body']);
			$_FILES['file']['tmp_name'][$i] = $tmpfname;
			$i++;
		}

		if(strpos($content['header']['Content-Type'], 'application/json')!==false){
			$_ = json_decode($content['body'],true);
		}
	}

	if(!isset($contents)){
		$_ = json_decode($request['body'],true);
	}

	if(!$_) throw new Exception("Chaine json incorrecte ".$request['body']);
	if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
	Action::run('document_element_upload',$response);
});
$api->register();

//Cette fonction comprend toutes les actions du plugin qui ne nécessitent pas de vue html

require_once(__DIR__.SLASH.'action.php');


function document_cron($time){
	global $_;
	if(date('H:i', $time)!='03:00' && !isset($_['force-document'])) return;

	require_once(__DIR__.SLASH.'Element.class.php');
	require_once(__DIR__.SLASH.'ElementRight.class.php');

	$toDelete = array();
	$i = 0;
	$ids = array();
	foreach(Element::staticQuery('SELECT `id`,`path` FROM {{table}}')->fetchAll() as $row){
		$osPath = Element::root().str_replace('/',SLASH, $row['path']);
		if(file_exists($osPath)) continue;
		echo $row['path'].PHP_EOL;
		$ids[] = $row['id'];
		if($i>500){
			echo 'Delete pack'.PHP_EOL;
			Element::delete(array('id:IN'=>$ids));
			ElementRight::delete(array('element:IN'=>$ids));
			$ids = array();
			$i = 0;
		}
		$i++;
	}
}


//Déclation des assets
Plugin::addCss("/css/main.css");
Plugin::addCss("/css/document.api.css");
Plugin::addJs("/js/component.js",true);
Plugin::addJs("/js/document.api.js");
Plugin::addJs("/js/main.js");

//Mapping hook / fonctions
Plugin::addHook("widget", "document_widget");
Plugin::addHook("install", "document_install");
Plugin::addHook("uninstall", "document_uninstall");


Plugin::addHook("menu_main", "document_menu");
Plugin::addHook("page", "document_page");

Plugin::addHook("menu_setting", "document_menu_setting");
Plugin::addHook("content_setting", "document_content_setting");
Plugin::addHook("rewrite", "document_dav_document");
Plugin::addHook("cron", "document_cron");

Plugin::addHook("client_menu", "document_client_menu");
Plugin::addHook("client_page", "document_client_page");
Plugin::addHook("client_merge", "document_client_merge");
?>
