FOSSology  4.6.0
Open Source License Compliance by Open Source Software
ReportController.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2018, 2021 Siemens AG
4  Author: Gaurav Mishra <mishra.gaurav@siemens.com>
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
13 namespace Fossology\UI\Api\Controllers;
14 
32 use Psr\Http\Message\ServerRequestInterface;
33 use Slim\Psr7\Factory\StreamFactory;
34 use Slim\Psr7\Request as SlimRequest;
35 use Slim\Psr7\UploadedFile as SlimUploadedFile;
36 use Symfony\Component\HttpFoundation\File\UploadedFile;
37 use Symfony\Component\HttpFoundation\Request;
38 
44 {
45 
50  private $reportsAllowed = array(
51  'dep5',
52  'spdx2',
53  'spdx2tv',
54  'readmeoss',
55  'unifiedreport',
56  'clixml',
57  'decisionexporter',
58  'cyclonedx',
59  'spdx3json',
60  'spdx3rdf',
61  'spdx3jsonld'
62  );
63 
68  private $importAllowed = [
69  'decisionimporter',
70  'spdxrdf'
71  ];
72 
82  public function getReport($request, $response, $args)
83  {
84  $apiVersion = ApiVersion::getVersion($request);
85  $uploadId = null;
86  $reportFormat = null;
87  if ($apiVersion == ApiVersion::V2) {
88  $query = $request->getQueryParams();
89  $uploadId = $query['uploadId'];
90  $reportFormat = $query['reportFormat'];
91  } else {
92  $uploadId = $request->getHeaderLine('uploadId');
93  $reportFormat = $request->getHeaderLine('reportFormat');
94  }
95 
96  if (! in_array($reportFormat, $this->reportsAllowed)) {
97  throw new HttpBadRequestException(
98  "reportFormat must be from [" . implode(",", $this->reportsAllowed) .
99  "]");
100  }
101  $upload = $this->getUpload($uploadId);
102  if (get_class($upload) === Info::class) {
103  return $response->withJson($upload->getArray(), $upload->getCode());
104  }
105  $jobId = null;
106  $jobQueueId = null;
107 
108  switch ($reportFormat) {
109  case $this->reportsAllowed[0]:
110  case $this->reportsAllowed[1]:
111  case $this->reportsAllowed[2]:
113  $spdxGenerator = $this->restHelper->getPlugin('ui_spdx2');
114  list ($jobId, $jobQueueId, $error) = $spdxGenerator->scheduleAgent(
115  $this->restHelper->getGroupId(), $upload, $reportFormat);
116  break;
117  case $this->reportsAllowed[3]:
119  $readmeGenerator = $this->restHelper->getPlugin('ui_readmeoss');
120  list ($jobId, $jobQueueId, $error) = $readmeGenerator->scheduleAgent(
121  $this->restHelper->getGroupId(), $upload);
122  break;
123  case $this->reportsAllowed[4]:
125  $unifiedGenerator = $this->restHelper->getPlugin('agent_founifiedreport');
126  list ($jobId, $jobQueueId, $error) = $unifiedGenerator->scheduleAgent(
127  $this->restHelper->getGroupId(), $upload);
128  break;
129  case $this->reportsAllowed[5]:
131  $clixmlGenerator = $this->restHelper->getPlugin('ui_clixml');
132  list ($jobId, $jobQueueId) = $clixmlGenerator->scheduleAgent(
133  $this->restHelper->getGroupId(), $upload);
134  break;
135  case $this->reportsAllowed[6]:
137  $decisionExporter = $this->restHelper->getPlugin('agent_fodecisionexporter');
138  list($jobId, $jobQueueId) = $decisionExporter->scheduleAgent(
139  $this->restHelper->getGroupId(), $upload);
140  break;
141  case $this->reportsAllowed[7]:
143  $cyclonedxGenerator = $this->restHelper->getPlugin('ui_cyclonedx');
144  list ($jobId, $jobQueueId) = $cyclonedxGenerator->scheduleAgent(
145  $this->restHelper->getGroupId(), $upload);
146  break;
147  case $this->reportsAllowed[8]:
148  case $this->reportsAllowed[9]:
149  case $this->reportsAllowed[10]:
151  $spdx3Generator = $this->restHelper->getPlugin('ui_spdx3');
152  list ($jobId, $jobQueueId, $error) = $spdx3Generator->scheduleAgent(
153  $this->restHelper->getGroupId(), $upload, $reportFormat);
154  break;
155  default:
156  throw new HttpInternalServerErrorException("Some error occured!");
157  }
158  $download_path = $this->buildDownloadPath($request, $jobId);
159  $info = new Info(201, $download_path, InfoType::INFO);
160  return $response->withJson($info->getArray(), $info->getCode());
161  }
162 
170  private function getUpload($uploadId)
171  {
172  if (empty($uploadId) || ! is_numeric($uploadId) || $uploadId <= 0) {
173  throw new HttpBadRequestException("uploadId must be a positive integer!");
174  }
175  $uploadDao = $this->restHelper->getUploadDao();
176  if (! $uploadDao->isAccessible($uploadId, $this->restHelper->getGroupId())) {
177  throw new HttpForbiddenException("Upload is not accessible!");
178  }
179  $upload = $uploadDao->getUpload($uploadId);
180  if ($upload === null) {
181  throw new HttpNotFoundException("Upload does not exists!");
182  }
183  return $upload;
184  }
185 
192  public static function buildDownloadPath($request, $jobId)
193  {
194  $url_parts = $request->getUri();
195  $download_path = "";
196  if (!empty($url_parts->getScheme())) {
197  $download_path .= $url_parts->getScheme() . "://";
198  }
199  if (!empty($url_parts->getHost())) {
200  $download_path .= $url_parts->getHost();
201  }
202  if (!empty($url_parts->getPort())) {
203  $download_path .= ':' . $url_parts->getPort();
204  }
205  $endpoint = substr($url_parts->getPath(), 0, strpos($url_parts->getPath(),
206  $GLOBALS["apiBasePath"]) + strlen($GLOBALS["apiBasePath"]));
207  if (substr($endpoint, -1) !== '/') {
208  $endpoint .= '/';
209  }
210  $endpoint .= "report/" . $jobId;
211  $download_path .= $endpoint;
212  return $download_path;
213  }
214 
224  public function downloadReport($request, $response, $args)
225  {
226  $id = $args['id'];
227  $this->checkReport($id);
229  $ui_download = $this->restHelper->getPlugin('download');
230  $responseFile = $ui_download->getReport($args['id']);
231  $responseContent = $responseFile->getFile();
232  $newResponse = $response->withHeader('Content-Description',
233  'File Transfer')
234  ->withHeader('Content-Type',
235  $responseContent->getMimeType())
236  ->withHeader('Content-Disposition',
237  $responseFile->headers->get('Content-Disposition'))
238  ->withHeader('Cache-Control', 'must-revalidate')
239  ->withHeader('Pragma', 'private')
240  ->withHeader('Content-Length', filesize($responseContent->getPathname()));
241  $sf = new StreamFactory();
242  return $newResponse->withBody(
243  $sf->createStreamFromFile($responseContent->getPathname())
244  );
245  }
246 
254  private function checkReport($id)
255  {
256  $dbManager = $this->dbHelper->getDbManager();
257  $row = $dbManager->getSingleRow(
258  'SELECT jq_type FROM jobqueue WHERE jq_job_fk = $1', array(
259  $id
260  ), "reportValidity");
261  if (! in_array($row['jq_type'], $this->reportsAllowed)) {
262  throw new HttpNotFoundException(
263  "No report scheduled with given job id.");
264  }
265  $row = $dbManager->getSingleRow('SELECT job_upload_fk FROM job WHERE job_pk = $1',
266  array($id), "reportFileUpload");
267  $uploadId = intval($row['job_upload_fk']);
268  $uploadDao = $this->restHelper->getUploadDao();
269  if (! $uploadDao->isAccessible($uploadId, $this->restHelper->getGroupId())) {
270  throw new HttpForbiddenException("Report is not accessible!");
271  }
272  $row = $dbManager->getSingleRow('SELECT * FROM reportgen WHERE job_fk = $1',
273  array($id), "reportFileName");
274  if (empty($row)) {
276  "Report is not ready. Retry after 10s."))
277  ->setHeaders(['Retry-After' => '10']);
278  }
279  // Everything went well
280  return true;
281  }
282 
292  public function importReport(ServerRequestInterface $request,
293  ResponseHelper $response, array $args): ResponseHelper
294  {
295  $query = $request->getQueryParams();
296  if (!array_key_exists("upload", $query)) {
297  throw new HttpBadRequestException("Missing query param 'upload'");
298  }
299  if (!array_key_exists("reportFormat", $query) ||
300  !in_array($query["reportFormat"], $this->importAllowed)) {
301  throw new HttpBadRequestException(
302  "Missing or wrong query param 'reportFormat'");
303  }
304  $upload_pk = intval($query['upload']);
305  // checking if the scheduler is running or not
306  $commu_status = fo_communicate_with_scheduler('status',
307  $response_from_scheduler, $error_info);
308  if (!$commu_status) {
309  throw new HttpServiceUnavailableException("Scheduler is not running!");
310  }
311  $files = $request->getUploadedFiles();
312 
313  $this->uploadAccessible($upload_pk);
314  if (empty($files['report'])) {
315  throw new HttpBadRequestException("No file uploaded");
316  }
318  $slimFile = $files['report'];
319 
320  $reportFormat = $query["reportFormat"];
321  switch ($reportFormat) {
322  case $this->importAllowed[0]:
323  $returnVal = $this->importDecisionJson($request, $response,
324  $upload_pk, $slimFile);
325  break;
326  case $this->importAllowed[1]:
327  $returnVal = $this->importSpdxReport($request, $response, $upload_pk,
328  $slimFile);
329  break;
330  default:
331  throw new HttpBadRequestException(
332  "Report format $reportFormat not supported. Supported formats are [" .
333  implode(", ", $this->importAllowed) . "]");
334  }
335  return $returnVal;
336  }
337 
348  private function importDecisionJson(ServerRequestInterface $request,
349  ResponseHelper $response, int $uploadId,
350  SlimUploadedFile $slimFile): ResponseHelper
351  {
352  $this->throwNotAdminException();
354  $decisionImporter = $this->restHelper->getPlugin("ui_fodecisionimporter");
355  $symfonyRequest = new Request();
356 
357  $reqBody = $this->getParsedBody($request);
358 
359  if (!array_key_exists("importerUser", $reqBody)) {
360  throw new HttpBadRequestException("Missing parameter 'importerUser'");
361  }
362 
363  $importerUser = intval($reqBody["importerUser"]);
364  if (empty($importerUser)) {
365  $importerUser = $this->restHelper->getUserId();
366  }
367 
368  $uploadedFile = new UploadedFile($slimFile->getFilePath(),
369  $slimFile->getClientFilename(), $slimFile->getClientMediaType());
370 
371  $symfonyRequest->files->set('report', $uploadedFile);
372  $symfonyRequest->request->set('uploadselect', $uploadId);
373  $symfonyRequest->request->set('userselect', $importerUser);
374 
375  $agentResp = $decisionImporter->handleRequest($symfonyRequest);
376 
377  if ($agentResp === false) {
378  throw new HttpBadRequestException("Missing required fields");
379  }
380  $info = new Info(201, intval($agentResp[0]), InfoType::INFO);
381  return $response->withJson($info->getArray(), $info->getCode());
382  }
383 
393  public function importSpdxReport(ServerRequestInterface $request,
394  ResponseHelper $response, int $upload_pk,
395  SlimUploadedFile $slimFile): ResponseHelper
396  {
397  $reqBody = $this->getParsedBody($request);
399  $reportImport = $this->restHelper->getPlugin('ui_reportImport');
400  $symfonyRequest = new Request();
401 
402  // moving the uploaded file to the ReportImport Directory
403  global $SysConf;
404  $fileBase = $SysConf['FOSSOLOGY']['path'] . "/ReportImport/";
405  if (!is_dir($fileBase)) {
406  mkdir($fileBase, 0755, true);
407  }
408  $targetFile = time() . '_' . rand() . '_' . $slimFile->getClientFilename();
409  $slimFile->moveTo($fileBase . $targetFile);
410 
411  // Get default values for parameters
412  $addNewLicensesAs = "candidate";
413  $addLicenseInfoFromInfoInFile = "true";
414  $addLicenseInfoFromConcluded = "false";
415  $addConcludedAsDecisions = "true";
416  $addConcludedAsDecisionsTBD = "true";
417  $addCopyrights = "false";
418  if (array_key_exists("addNewLicensesAs", $reqBody) &&
419  $reqBody["addNewLicensesAs"] === "license") {
420  $addNewLicensesAs = "license";
421  }
422  if (array_key_exists("addLicenseInfoFromInfoInFile", $reqBody) &&
423  !filter_var($reqBody["addLicenseInfoFromInfoInFile"],
424  FILTER_VALIDATE_BOOLEAN)) {
425  $addLicenseInfoFromInfoInFile = "false";
426  }
427  if (array_key_exists("addLicenseInfoFromConcluded", $reqBody) &&
428  filter_var($reqBody["addLicenseInfoFromConcluded"],
429  FILTER_VALIDATE_BOOLEAN)) {
430  $addLicenseInfoFromConcluded = "true";
431  }
432  if (array_key_exists("addConcludedAsDecisions", $reqBody) &&
433  !filter_var($reqBody["addConcludedAsDecisions"],
434  FILTER_VALIDATE_BOOLEAN)) {
435  $addConcludedAsDecisions = "false";
436  }
437  if (array_key_exists("addConcludedAsDecisionsTBD", $reqBody) &&
438  !filter_var($reqBody["addConcludedAsDecisionsTBD"],
439  FILTER_VALIDATE_BOOLEAN)) {
440  $addConcludedAsDecisionsTBD = "false";
441  }
442  if (array_key_exists("addCopyrights", $reqBody) &&
443  filter_var($reqBody["addCopyrights"],
444  FILTER_VALIDATE_BOOLEAN)) {
445  $addCopyrights = "true";
446  }
447 
448  // translating values for symfony request
449  $symfonyRequest->request->set('addNewLicensesAs', $addNewLicensesAs);
450  $symfonyRequest->request->set('addLicenseInfoFromInfoInFile',
451  $addLicenseInfoFromInfoInFile);
452  $symfonyRequest->request->set('addLicenseInfoFromConcluded',
453  $addLicenseInfoFromConcluded);
454  $symfonyRequest->request->set('addConcludedAsDecisions',
455  $addConcludedAsDecisions);
456  $symfonyRequest->request->set('addConcludedAsDecisionsTBD',
457  $addConcludedAsDecisionsTBD);
458  $symfonyRequest->request->set('addCopyrights', $addCopyrights);
459 
460  $agentResp = $reportImport->runImport($upload_pk, $targetFile, $symfonyRequest);
461  $returnVal = new Info(201, intval($agentResp[0]), InfoType::INFO);
462  return $response->withJson($returnVal->getArray(), $returnVal->getCode());
463  }
464 }
FOSSology Decision Exporter UI plugin.
Agent plugin for Readme_OSS agent.
Call SPDX3 agent to generate report from UI.
Base controller for REST calls.
getParsedBody(ServerRequestInterface $request)
Parse request body as JSON and return associative PHP array.
Override Slim response for withJson function.
static getVersion(ServerRequestInterface $request)
Definition: ApiVersion.php:29
Different type of infos provided by REST.
Definition: InfoType.php:16
Info model to contain general error and return values.
Definition: Info.php:19
fo_communicate_with_scheduler($input, &$output, &$error_msg)
Communicate with scheduler, send commands to the scheduler, then get the output.