Newer
Older
<?php
/**
* Copyright Maarch since 2008 under licence GPLv3.
* See LICENCE.txt file at the root folder for more details.
* This file is part of Maarch software.
*
*/
/**
* @brief Resource Controller
* @author dev@maarch.org
*/
namespace Document\controllers;
use Attachment\controllers\AttachmentController;
use setasign\Fpdi\Tcpdf\Fpdi;
use Document\models\DocumentModel;
use Slim\Http\Request;
use Slim\Http\Response;
use SrcCore\models\DatabaseModel;
use SrcCore\models\ValidatorModel;
use Status\models\StatusModel;
use User\controllers\UserController;
use History\controllers\HistoryController;
class DocumentController
{
public function get(Request $request, Response $response)
{
$queryParams = $request->getQueryParams();
$queryParams['offset'] = empty($queryParams['offset']) ? 0 : (int)$queryParams['offset'];
$queryParams['limit'] = empty($queryParams['limit']) ? 0 : (int)$queryParams['limit'];
$status = StatusModel::getByReference(['select' => ['id'], 'reference' => 'NEW']);
$where = ['processing_user = ?', 'status = ?'];
if (!empty($queryParams['mode'])) {
$dataGet[] = $queryParams['mode'];
$secondMode = ($queryParams['mode'] == 'SIGN' ? 'NOTE' : 'SIGN');
$documents = DocumentModel::get([
'select' => ['count(1) OVER()'],
'where' => $where,
'data' => [$GLOBALS['id'], $status['id'], $secondMode]
]);
$count[$secondMode] = empty($documents[0]['count']) ? 0 : $documents[0]['count'];
'select' => ['id', 'title', 'reference', 'status', 'mode', 'count(1) OVER()'],
'limit' => $queryParams['limit'],
'offset' => $queryParams['offset'],
$count[$queryParams['mode']] = empty($documents[0]['count']) ? 0 : $documents[0]['count'];
foreach ($documents as $key => $document) {
$status = StatusModel::getById(['select' => ['label'], 'id' => $document['status']]);
$documents[$key]['statusDisplay'] = $status['label'];
return $response->withJson(['documents' => $documents, 'count' => $count]);
public function getById(Request $request, Response $response, array $args)
{
if (!DocumentController::hasRightById(['id' => $args['id'], 'userId' => $GLOBALS['id']]) && !UserController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_documents'])) {
return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
}
$document = DocumentModel::getById(['select' => ['*'], 'id' => $args['id']]);
if (empty($document)) {
return $response->withStatus(400)->withJson(['errors' => 'Document does not exist']);
}
'where' => ['main_document_id = ?', 'type = ?'],
'data' => [$args['id'], 'DOC']
]);
$docserver = DocserverModel::getByType(['type' => 'DOC', 'select' => ['path']]);
if (empty($docserver['path']) || !file_exists($docserver['path'])) {
return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
}
$pathToDocument = $docserver['path'] . $adr[0]['path'] . $adr[0]['filename'];
if (!file_exists($pathToDocument)) {
return $response->withStatus(404)->withJson(['errors' => 'Document not found on docserver']);
}
$fingerprint = DocserverController::getFingerPrint(['path' => $pathToDocument]);
if ($adr[0]['fingerprint'] != $fingerprint) {
return $response->withStatus(404)->withJson(['errors' => 'Fingerprints do not match']);
}
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
$formattedDocument = [
'id' => $document['id'],
'title' => $document['title'],
'reference' => $document['reference'],
'description' => $document['description'],
'mode' => $document['mode'],
'sender' => $document['sender'],
'metadata' => json_decode($document['metadata']),
'creationDate' => $document['creation_date'],
'modificationDate' => $document['modification_date']
];
if (!empty($document['deadline'])) {
$date = new \DateTime($document['deadline']);
$formattedDocument['deadline'] = $date->format('d-m-Y H:i');
}
$formattedDocument['status'] = StatusModel::getById(['select' => ['*'], 'id' => $document['status']]);
$processingUser = UserModel::getById(['select' => ['firstname', 'lastname', 'login'], 'id' => $document['processing_user']]);
$formattedDocument['processingUser'] = $processingUser['login'];
$formattedDocument['processingUserDisplay'] = "{$processingUser['firstname']} {$processingUser['lastname']}";
$creator = UserModel::getById(['select' => ['firstname', 'lastname', 'login'], 'id' => $document['creator']]);
$formattedDocument['creator'] = $creator['login'];
$formattedDocument['creatorDisplay'] = "{$creator['firstname']} {$creator['lastname']}";
$formattedDocument['encodedDocument'] = base64_encode(file_get_contents($pathToDocument));
$actions = ActionModel::get(['select' => ['id'], 'where' => ['mode = ?', 'status_id = ?'], 'data' => [$document['mode'], $document['status']], 'orderBy' => ['id']]);
foreach ($actions as $action) {
$formattedDocument['actionsAllowed'][] = $action['id'];
}
$attachments = AttachmentModel::getByDocumentId(['select' => ['id'], 'documentId' => $args['id']]);
foreach ($attachments as $attachment) {
$formattedDocument['attachments'][] = $attachment['id'];
}
HistoryController::add([
'tableName' => 'main_documents',
'recordId' => $args['id'],
'eventType' => 'VIEW',
'info' => "documentViewed {$document['title']}"
return $response->withJson(['document' => $formattedDocument]);
public function create(Request $request, Response $response)
{
if (!UserController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_documents'])) {
return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']);
}
$body = $request->getParsedBody();
if (empty($body)) {
return $response->withStatus(400)->withJson(['errors' => 'Body is not set or empty']);
} elseif (!Validator::notEmpty()->validate($body['encodedDocument'])) {
return $response->withStatus(400)->withJson(['errors' => 'Body encodedDocument is empty']);
} elseif (!Validator::stringType()->notEmpty()->validate($body['title'])) {
return $response->withStatus(400)->withJson(['errors' => 'Body title is empty or not a string']);
} elseif (!Validator::stringType()->notEmpty()->validate($body['mode'])) {
return $response->withStatus(400)->withJson(['errors' => 'Body mode is empty or not a string']);
} elseif (!Validator::stringType()->notEmpty()->validate($body['processingUser'])) {
return $response->withStatus(400)->withJson(['errors' => 'Body processingUser is empty or not a string']);
} elseif (!Validator::stringType()->notEmpty()->validate($body['sender'])) {
return $response->withStatus(400)->withJson(['errors' => 'Body sender is empty or not a string']);
$body['attachments'] = empty($body['attachments']) ? [] : $body['attachments'];
foreach ($body['attachments'] as $key => $attachment) {
if (!Validator::notEmpty()->validate($attachment['encodedDocument'])) {
return $response->withStatus(400)->withJson(['errors' => "Body attachments[{$key}] encodedDocument is empty"]);
} elseif (!Validator::stringType()->notEmpty()->validate($attachment['title'])) {
return $response->withStatus(400)->withJson(['errors' => "Body attachments[{$key}] title is empty"]);
$processingUser = UserModel::getByLogin(['select' => ['id'], 'login' => $body['processingUser']]);
if (empty($processingUser)) {
return $response->withStatus(400)->withJson(['errors' => 'Processing user does not exist']);
}
$encodedDocument = DocumentController::getEncodedDocumentFromEncodedZip(['encodedZipDocument' => $body['encodedDocument']]);
if (!empty($encodedDocument['errors'])) {
return $response->withStatus(500)->withJson(['errors' => $encodedDocument['errors']]);
}
$storeInfos = DocserverController::storeResourceOnDocServer([
'encodedFile' => $encodedDocument['encodedDocument'],
'format' => 'pdf',
'docserverType' => 'DOC'
]);
if (!empty($storeInfos['errors'])) {
return $response->withStatus(500)->withJson(['errors' => $storeInfos['errors']]);
}
$status = StatusModel::get(['select' => ['id'], 'where' => ['reference = ?'], 'data' => ['NEW']]);
DatabaseModel::beginTransaction();
$id = DocumentModel::create([
'title' => $body['title'],
'reference' => empty($body['reference']) ? null : $body['reference'],
'description' => empty($body['description']) ? null : $body['description'],
'mode' => $body['mode'] == 'SIGN' ? 'SIGN' : 'NOTE',
'status' => $status[0]['id'],
'processing_user' => $processingUser['id'],
'sender' => $body['sender'],
'deadline' => empty($body['deadline']) ? null : $body['deadline'],
'metadata' => empty($body['metadata']) ? '{}' : json_encode($body['metadata']),
'creator' => $GLOBALS['id']
]);
AdrModel::createDocumentAdr([
'documentId' => $id,
'type' => 'DOC',
'path' => $storeInfos['path'],
'filename' => $storeInfos['filename'],
'fingerprint' => $storeInfos['fingerprint']
]);
foreach ($body['attachments'] as $key => $value) {
$value['mainDocumentId'] = $id;
$attachment = AttachmentController::create($value);
if (!empty($attachment['errors'])) {
DatabaseModel::rollbackTransaction();
return $response->withStatus(500)->withJson(['errors' => "An error occured for attachment {$key} : {$attachment['errors']}"]);
}
}
HistoryController::add([
'tableName' => 'main_documents',
'recordId' => $id,
'eventType' => 'CREATION',
'info' => "documentAdded {$body['subject']}"
DatabaseModel::commitTransaction();
return $response->withJson(['id' => $id]);
public function setAction(Request $request, Response $response, array $args)
if (!DocumentController::hasRightById(['id' => $args['id'], 'userId' => $GLOBALS['id']])) {
return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
}
$document = DocumentModel::getById(['select' => ['mode', 'status'], 'id' => $args['id']]);
$action = ActionModel::get([
'select' => ['next_status_id'],
'where' => ['mode = ?', 'status_id = ?', 'id = ?'],
'data' => [$document['mode'], $document['status'], $args['actionId']]
]);
if (empty($action[0])) {
return $response->withStatus(400)->withJson(['errors' => 'Action does not exist']);
$data = $request->getParams();
if (!empty($data['signatures'])) {
foreach ($data['signatures'] as $signature) {
foreach (['encodedImage', 'width', 'positionX', 'positionY', 'page', 'type'] as $value) {
if (!isset($signature[$value])) {
return $response->withStatus(400)->withJson(['errors' => $value . ' is empty']);
}
}
}
$adr = AdrModel::getDocumentsAdr([
'select' => ['path', 'filename'],
'where' => ['main_document_id = ?', 'type = ?'],
'data' => [$args['id'], 'DOC']
]);
if (empty($adr)) {
return $response->withStatus(400)->withJson(['errors' => 'Document does not exist']);
}
$docserver = DocserverModel::getByType(['type' => 'DOC', 'select' => ['path']]);
if (empty($docserver['path']) || !file_exists($docserver['path'])) {
return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
}
$pathToDocument = $docserver['path'] . $adr[0]['path'] . $adr[0]['filename'];
if (!file_exists($pathToDocument)) {
return $response->withStatus(404)->withJson(['errors' => 'Document not found on docserver']);
}
$tmpFilename = $tmpPath . $GLOBALS['id'] . '_' . rand() . '_' . $adr[0]['filename'];
copy($pathToDocument, $tmpFilename);
$pdf = new Fpdi('P');
$nbPages = $pdf->setSourceFile($tmpFilename);
$pdf->setPrintHeader(false);
for ($i = 1; $i <= $nbPages; $i++) {
$page = $pdf->importPage($i);
$size = $pdf->getTemplateSize($page);
$pdf->AddPage($size['orientation'], $size);
$pdf->useImportedPage($page);
$pdf->SetAutoPageBreak(false, 0);
$pdf->SetMargins(0, 0, 0);
$pdf->SetAutoPageBreak(false, 0);
foreach ($data['signatures'] as $signature) {
if ($signature['page'] == $i) {
if ($signature['positionX'] == 0 && $signature['positionY'] == 0) {
$signWidth = $size['width'];
$signPosX = 0;
$signPosY = 0;
} else {
$signWidth = ($signature['width'] * $size['width']) / 100;
$signPosX = ($signature['positionX'] * $size['width']) / 100;
$signPosY = ($signature['positionY'] * $size['height']) / 100;
}
$image = str_replace('data:image/svg+xml;base64,', '', $signature['encodedImage']);
$image = base64_decode($image);
if ($image === false) {
return $response->withStatus(400)->withJson(['errors' => 'base64_decode failed']);
$imageTmpPath = $tmpPath . $GLOBALS['id'] . '_' . rand() . '_writing.svg';
file_put_contents($imageTmpPath, $image);
$pdf->ImageSVG($imageTmpPath, $signPosX, $signPosY, $signWidth);
if ($image === false) {
return $response->withStatus(400)->withJson(['errors' => 'base64_decode failed']);
}
$imageTmpPath = $tmpPath . $GLOBALS['id'] . '_' . rand() . '_writing.png';
file_put_contents($imageTmpPath, $image);
$pdf->Image($imageTmpPath, $signPosX, $signPosY, $signWidth);
}
$fileContent = $pdf->Output('', 'S');
$storeInfos = DocserverController::storeResourceOnDocServer([
'encodedFile' => base64_encode($fileContent),
'format' => 'pdf',
'docserverType' => 'HANDWRITTEN'
]);
AdrModel::createDocumentAdr([
'documentId' => $args['id'],
'type' => 'HANDWRITTEN',
'path' => $storeInfos['path'],
'filename' => $storeInfos['filename'],
'fingerprint' => $storeInfos['fingerprint']
]);
HistoryController::add([
'tableName' => 'main_documents',
'recordId' => $args['id'],
'eventType' => 'UP',
]);
return $response->withJson(['success' => 'success']);
}
public function getProcessedDocumentById(Request $request, Response $response, array $args)
if (!DocumentController::hasRightById(['id' => $args['id'], 'userId' => $GLOBALS['id']]) && !UserController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_documents'])) {
return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
$adr = AdrModel::getDocumentsAdr([
'select' => ['path', 'filename', 'fingerprint'],
'where' => ['main_document_id = ?', 'type = ?'],
'data' => [$args['id'], 'HANDWRITTEN']
]);
if (empty($adr[0])) {
return $response->withJson(['encodedDocument' => null]);
}
$docserver = DocserverModel::getByType(['type' => 'HANDWRITTEN', 'select' => ['path']]);
if (empty($docserver['path']) || !file_exists($docserver['path'])) {
return $response->withStatus(400)->withJson(['errors' => 'Docserver does not exist']);
}
$pathToDocument = $docserver['path'] . $adr[0]['path'] . $adr[0]['filename'];
if (!file_exists($pathToDocument)) {
return $response->withStatus(404)->withJson(['errors' => 'Document not found on docserver']);
}
$fingerprint = DocserverController::getFingerPrint(['path' => $pathToDocument]);
if ($adr[0]['fingerprint'] != $fingerprint) {
return $response->withStatus(400)->withJson(['errors' => 'Fingerprints do not match']);
}
return $response->withJson(['encodedDocument' => base64_encode(file_get_contents($pathToDocument))]);
}
public function getStatusById(Request $request, Response $response, array $args)
{
if (!DocumentController::hasRightById(['id' => $args['id'], 'userId' => $GLOBALS['id']]) && !UserController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_documents'])) {
return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
$document = DocumentModel::getById(['select' => ['status', 'mode'], 'id' => $args['id']]);
if (empty($document)) {
return $response->withStatus(400)->withJson(['errors' => 'Document does not exist']);
}
$status = StatusModel::getById(['select' => ['id', 'reference', 'label'], 'id' => $document['status']]);
return $response->withJson(['status' => $status]);
public static function hasRightById(array $args)
{
ValidatorModel::notEmpty($args, ['id', 'userId']);
ValidatorModel::intVal($args, ['id', 'userId']);
$document = DocumentModel::get(['select' => [1], 'where' => ['processing_user = ?', 'id = ?'], 'data' => [$args['userId'], $args['id']]]);
if (empty($document)) {
return false;
}
return true;
}
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
public static function getEncodedDocumentFromEncodedZip(array $args)
{
ValidatorModel::notEmpty($args, ['encodedZipDocument']);
ValidatorModel::stringType($args, ['encodedZipDocument']);
$tmpPath = CoreConfigModel::getTmpPath();
$zipDocumentOnTmp = $tmpPath . mt_rand() . '_parapheur.zip';
file_put_contents($zipDocumentOnTmp, base64_decode($args['encodedZipDocument']));
$zipArchive = new \ZipArchive();
$open = $zipArchive->open($zipDocumentOnTmp);
if ($open != true) {
return ['errors' => "getDocumentFromEncodedZip : $open"];
}
$dirOnTmp = $tmpPath . mt_rand() . '_parapheur';
if (!$zipArchive->extractTo($dirOnTmp)) {
return ['errors' => "getDocumentFromEncodedZip : Extract failed"];
}
$filesOnTmp = scandir($dirOnTmp);
foreach ($filesOnTmp as $fileOnTmp) {
if ($fileOnTmp != '.' && $fileOnTmp != '..') {
return ['encodedDocument' => base64_encode(file_get_contents("{$dirOnTmp}/{$fileOnTmp}"))];
}
}
return ['errors' => "getDocumentFromEncodedZip : No document was found in Zip"];
}