FOSSology  4.5.1
Open Source License Compliance by Open Source Software
UploadTreeController.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2023 Samuel Dushimimana <dushsam100@gmail.com>
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
13 namespace Fossology\UI\Api\Controllers;
14 
36 use Psr\Http\Message\ServerRequestInterface;
37 use Symfony\Component\HttpFoundation\Response;
38 
44 {
46  private $clearingDao;
47 
52  private $licenseDao;
53 
58  private $highlightDao;
59 
61  private $clearingDecisionEventProcessor;
62 
67  private $decisionTypes;
68 
69 
70  public function __construct($container)
71  {
72  parent::__construct($container);
73  $this->clearingDao = $this->container->get('dao.clearing');
74  $this->licenseDao = $this->container->get('dao.license');
75  $this->highlightDao = $this->container->get("dao.highlight");
76  $this->clearingDecisionEventProcessor = $this->container->get('businessrules.clearing_decision_processor');
77  $this->decisionTypes = $this->container->get('decision.types');
78  }
79 
89  public function viewLicenseFile($request, $response, $args)
90  {
91  $uploadId = intval($args['id']);
92  $itemId = intval($args['itemId']);
93 
94  $this->uploadAccessible($uploadId);
95  $this->isItemExists($uploadId, $itemId);
96 
98  $view = $this->restHelper->getPlugin('view');
99 
100  $inputFile = @fopen(RepPathItem($itemId), "rb");
101  if (empty($inputFile)) {
102  global $Plugins;
103  $reunpackPlugin = &$Plugins[plugin_find_id("ui_reunpack")];
104  $state = $reunpackPlugin->CheckStatus($uploadId, "reunpack", "ununpack");
105  if ($state != 0 && $state != 2) {
106  $errorMess = _("Reunpack job is running: you can see it in");
107  } else {
108  $errorMess = _("File contents are not available in the repository.");
109  }
110  throw new HttpInternalServerErrorException($errorMess);
111  }
112  rewind($inputFile);
113 
114  $res = $view->getText($inputFile, 0, 0, -1, null, false, true);
115  $response->getBody()->write($res);
116  return $response->withHeader("Content-Type", "text/plain")
117  ->withHeader("Cache-Control", "max-age=1296000, must-revalidate")
118  ->withHeader("Etag", md5($response->getBody()));
119  }
120 
130  public function setClearingDecision($request, $response, $args)
131  {
132  $uploadId = intval($args['id']);
133  $this->uploadAccessible($uploadId);
134 
135  $body = $this->getParsedBody($request);
136  $decisionType = $body['decisionType'];
137  $global = $body['globalDecision'];
138 
139  // check if the given globalDecision value is a boolean
140  if ($global !== null && !is_bool($global)) {
141  throw new HttpBadRequestException("GlobalDecision should be a boolean");
142  }
143 
144  $uploadTreeId = intval($args['itemId']);
145 
146  // check if the given key exists in the known decision types
147  if (!array_key_exists($decisionType, $this->decisionTypes->getMap())) {
148  throw new HttpBadRequestException(
149  "Decision Type should be one of the following keys: " .
150  implode(", ", array_keys($this->decisionTypes->getMap())));
151  }
152  $this->isItemExists($uploadId, $uploadTreeId);
153 
155  $viewLicensePlugin = $this->restHelper->getPlugin('view-license');
156  $_GET['clearingTypes'] = $decisionType;
157  $_GET['globalDecision'] = $global ? 1 : 0;
158  $viewLicensePlugin->updateLastItem($this->restHelper->getUserId(), $this->restHelper->getGroupId(), $uploadTreeId, $uploadTreeId);
159  $returnVal = new Info(200, "Successfully set decision", InfoType::INFO);
160  return $response->withJson($returnVal->getArray(), $returnVal->getCode());
161  }
162 
172  public function getNextPreviousItem($request, $response, $args)
173  {
174  $uploadTreeId = intval($args['itemId']);
175  $uploadId = intval($args['id']);
176  $query = $request->getQueryParams();
177  $uploadDao = $this->restHelper->getUploadDao();
178  $selection = "";
179 
180  $this->uploadAccessible($uploadId);
181  $this->isItemExists($uploadId, $uploadTreeId);
182 
183  if ($query['selection'] !== null) {
184  $selection = $query['selection'];
185  if ($selection != "withLicenses" && $selection != "noClearing") {
186  throw new HttpBadRequestException(
187  "selection should be either 'withLicenses' or 'noClearing'");
188  }
189  }
190 
191  $options = array('skipThese' => $selection == "withLicenses" ? "noLicense" : ($selection == "noClearing" ? "alreadyCleared" : ""), 'groupId' => $this->restHelper->getGroupId());
192 
193  $prevItem = $uploadDao->getPreviousItem($uploadId, $uploadTreeId, $options);
194  $prevItemId = $prevItem ? $prevItem->getId() : null;
195 
196  $nextItem = $uploadDao->getNextItem($uploadId, $uploadTreeId, $options);
197  $nextItemId = $nextItem ? $nextItem->getId() : null;
198 
199  $res = [
200  "prevItemId" => $prevItemId,
201  "nextItemId" => $nextItemId
202  ];
203  return $response->withJson($res, 200);
204  }
205 
215  public function getBulkHistory($request, $response, $args)
216  {
217  $uploadTreeId = intval($args['itemId']);
218  $uploadId = intval($args['id']);
219  $uploadDao = $this->restHelper->getUploadDao();
220  $clearingDao = $this->container->get('dao.clearing');
221 
222  $this->uploadAccessible($uploadId);
223  $this->isItemExists($uploadId, $uploadTreeId);
224 
225  $uploadTreeTableName = $uploadDao->getUploadtreeTableName($uploadId);
226  $itemTreeBounds = $uploadDao->getItemTreeBounds($uploadTreeId, $uploadTreeTableName);
227 
228  $res = $clearingDao->getBulkHistory($itemTreeBounds, $this->restHelper->getGroupId());
229  $updatedRes = [];
230 
231  foreach ($res as $value) {
232  $obj = new BulkHistory(
233  intval($value['bulkId']),
234  intval($value['id']),
235  $value['text'],
236  $value['matched'],
237  $value['tried'],
238  $value['addedLicenses'],
239  $value['removedLicenses']);
240  $updatedRes[] = $obj->getArray();
241  }
242  return $response->withJson($updatedRes, 200);
243  }
244 
254  public function getClearingHistory($request, $response, $args)
255  {
256  $itemId = intval($args['itemId']);
257  $uploadId = intval($args['id']);
258  $uploadDao = $this->restHelper->getUploadDao();
259  $clearingDao = $this->container->get('dao.clearing');
260 
261  $this->uploadAccessible($uploadId);
262  $this->isItemExists($uploadId, $itemId);
263 
264  $itemTreeBounds = $uploadDao->getItemTreeBoundsFromUploadId($itemId, $uploadId);
265  $clearingDecWithLicenses = $clearingDao->getFileClearings($itemTreeBounds, $this->restHelper->getGroupId(), false, true);
266 
267  $data = [];
268  $scope = new DecisionScopes();
269 
270  foreach ($clearingDecWithLicenses as $clearingDecision) {
271  $removedLicenses = [];
272  $addedLicenses = [];
273 
274  foreach ($clearingDecision->getClearingLicenses() as $lic) {
275  $shortName = $lic->getShortName();
276  $lic->isRemoved() ? $removedLicenses[] = $shortName : $addedLicenses[] = $shortName;
277  }
278  ksort($removedLicenses, SORT_STRING);
279  ksort($addedLicenses, SORT_STRING);
280  $obj = new ClearingHistory(
281  date('Y-m-d', $clearingDecision->getTimeStamp()),
282  $clearingDecision->getUserName(),
283  $scope->getTypeName($clearingDecision->getScope()),
284  $this->decisionTypes->getConstantNameFromKey($clearingDecision->getType()),
285  $addedLicenses, $removedLicenses);
286  $data[] = $obj->getArray();
287  }
288  return $response->withJson($data, 200);
289  }
290 
300  public function getHighlightEntries($request, $response, $args)
301  {
302  $uploadTreeId = intval($args['itemId']);
303  $uploadId = intval($args['id']);
304  $query = $request->getQueryParams();
305  $uploadDao = $this->restHelper->getUploadDao();
306 
307  $this->uploadAccessible($uploadId);
308  $this->isItemExists($uploadId, $uploadTreeId);
309 
310  $agentId = $query['agentId'] ?? null;
311  $highlightId = $query['highlightId'] ?? null;
312  $licenseId = $query['licenseId'] ?? null;
313  $clearingId = $query['clearingId'] ?? null;
314 
315  if ($licenseId !== null && !$this->dbHelper->doesIdExist("license_ref", "rf_pk", $licenseId)) {
316  throw new HttpNotFoundException("License does not exist");
317  }
318  if ($highlightId !== null && !$this->dbHelper->doesIdExist("highlight", "fl_fk", $highlightId)) {
319  throw new HttpNotFoundException("Highlight does not exist");
320  }
321  if ($agentId !== null && !$this->dbHelper->doesIdExist("agent", "agent_pk", $agentId)) {
322  throw new HttpNotFoundException("Agent does not exist");
323  }
324  if ($clearingId !== null && !$this->dbHelper->doesIdExist("clearing_event", "clearing_event_pk", $clearingId)) {
325  throw new HttpNotFoundException("Clearing does not exist");
326  }
327 
328  $uploadTreeTableName = $uploadDao->getUploadtreeTableName($uploadId);
329  $itemTreeBounds = $uploadDao->getItemTreeBounds($uploadTreeId, $uploadTreeTableName);
331  $viewLicensePlugin = $this->restHelper->getPlugin('view-license');
332  $res = $viewLicensePlugin->getSelectedHighlighting($itemTreeBounds, $licenseId,
333  $agentId, $highlightId, $clearingId, $uploadId);
334 
335  $transformedRes = [];
336  foreach ($res as $value) {
337  $transformedRes[] = $value->getArray();
338  }
339  return $response->withJson($transformedRes, 200);
340  }
341 
351  public function getTreeView($request, $response, $args)
352  {
353  $uploadTreeId = intval($args['itemId']);
354  $uploadId = intval($args['id']);
355  $query = $request->getQueryParams();
356 
357  $queryKeys = array_keys($query);
358  $allowedKeys = ['showQuick', 'agentId', 'flatten', 'scanLicenseFilter', 'editedLicenseFilter', 'sort', 'page', 'limit', 'tagId', 'search', 'filterOpen'];
359  $diff = array_diff($queryKeys, $allowedKeys);
360  if (count($diff) > 0) {
361  throw new HttpBadRequestException("Invalid query parameter(s) : " . implode(",", $diff));
362  }
363 
364  $agentId = $query['agentId'] ?? null;
365  $flatten = $query['flatten'] ?? null;
366  $scanFilter = $query['scanLicenseFilter'] ?? null;
367  $editedFilter = $query['editedLicenseFilter'] ?? null;
368  $sortDir = $query['sort'] ?? null;
369  if (ApiVersion::getVersion($request) == ApiVersion::V2) {
370  $page = $query['page'] ?? null;
371  $limit = $query['limit'] ?? null;
372  } else {
373  $page = $request->getHeaderLine('page');
374  $limit = $request->getHeaderLine('limit');
375  }
376  $tagId = $query['tagId'] ?? null;
377  $sSearch = $query['search'] ?? null;
378  $openCBoxFilter = $query['filterOpen'] ?? null;
379  $show = ($query['showQuick'] !== null && $query['showQuick'] !== 'false') ? true : null;
380  $licenseDao = $this->container->get('dao.license');
381 
382  $uploadDao = $this->restHelper->getUploadDao();
383 
384  $this->uploadAccessible($uploadId);
385  $this->isItemExists($uploadId, $uploadTreeId);
386 
387  if ($agentId !== null && !$this->dbHelper->doesIdExist("agent", "agent_pk", $agentId)) {
388  throw new HttpNotFoundException("Agent does not exist");
389  }
390  if ($tagId !== null && !$this->dbHelper->doesIdExist("tag", "tag_pk", $tagId)) {
391  throw new HttpNotFoundException("Tag does not exist");
392  }
393  if ($openCBoxFilter !== null && ($openCBoxFilter !== 'true' && $openCBoxFilter !== 'false')) {
394  throw new HttpBadRequestException("openCBoxFilter must be a boolean value");
395  }
396  if ($flatten !== null && ($flatten !== 'true' && $flatten !== 'false')) {
397  throw new HttpBadRequestException("flatten must be a boolean value");
398  }
399  if ($sortDir != null && !($sortDir == "asc" || $sortDir == "desc")) {
400  throw new HttpBadRequestException("sortDirection must be asc or desc");
401  }
402  if ($page != null && (!is_numeric($page) || intval($page) < 1)) {
403  throw new HttpBadRequestException("page should be positive integer Greater or Equal to 1");
404  }
405  if ($show != null && $show != 'true' && $show != 'false') {
406  throw new HttpBadRequestException("show must be a boolean value");
407  }
408  if ($limit != null && (!is_numeric($limit) || intval($limit) < 1)) {
409  throw new HttpBadRequestException("limit should be positive integer Greater or Equal to 1");
410  }
411 
412  if ($editedFilter !== null) {
413  $license = $licenseDao->getLicenseByShortName($editedFilter, $this->restHelper->getGroupId());
414  if ($license === null) {
415  throw new HttpNotFoundException("Edited License filter $editedFilter does not exist");
416  }
417  $editedFilter = $license->getId();
418  }
419 
420  if ($scanFilter !== null) {
421  $license = $licenseDao->getLicenseByShortName($scanFilter, $this->restHelper->getGroupId());
422  if ($license === null) {
423  throw new HttpNotFoundException("Scan License filter $scanFilter does not exist");
424  }
425  $scanFilter = $license->getId();
426  }
427 
428  if ($page == null) {
429  $page = 1;
430  }
431  if ($limit == null) {
432  $limit = 50;
433  }
434 
435  if ($show) {
436  $uploadTreeId = $uploadDao->getFatItemId($uploadTreeId, $uploadId, $uploadDao->getUploadtreeTableName($uploadId));
437  }
438 
440  $ajaxExplorerPlugin = $this->restHelper->getPlugin('ajax_explorer');
441  $symfonyRequest = new \Symfony\Component\HttpFoundation\Request();
442  $symfonyRequest->request->set('agentId', $agentId);
443  $symfonyRequest->request->set('tag', $tagId);
444  $symfonyRequest->request->set('item', $uploadTreeId);
445  $symfonyRequest->request->set('upload', $uploadId);
446  $symfonyRequest->request->set('fromRest', true);
447  $symfonyRequest->request->set('flatten', ($flatten !== null && $flatten !== 'false') ? true : null);
448  $symfonyRequest->request->set('openCBoxFilter', $openCBoxFilter);
449  $symfonyRequest->request->set('show', $show ? "quick" : null);
450  $symfonyRequest->request->set('iSortingCols', "1");
451  $symfonyRequest->request->set('bSortable_0', "true");
452  $symfonyRequest->request->set('iSortCol_0', "0");
453  $symfonyRequest->request->set('sSortDir_0', $sortDir != null ? $sortDir : 'asc');
454  $symfonyRequest->request->set('iDisplayStart', (intval($page) - 1) * intval($limit));
455  $symfonyRequest->request->set('iDisplayLength', intval($limit));
456  $symfonyRequest->request->set("sSearch", $sSearch);
457  $symfonyRequest->request->set("conFilter", $editedFilter);
458  $symfonyRequest->request->set("scanFilter", $scanFilter);
459 
460  $res = $ajaxExplorerPlugin->handle($symfonyRequest);
461 
462  return $response->withJson(json_decode($res->getContent(), true)["aaData"], 200);
463  }
464 
474  public function getLicenseDecisions($request, $response, $args)
475  {
476  $uploadTreeId = intval($args['itemId']);
477  $uploadPk = intval($args['id']);
478  $uploadDao = $this->restHelper->getUploadDao();
479  $licenses = [];
480 
481  $this->uploadAccessible($uploadPk);
482  $this->isItemExists($uploadPk, $uploadTreeId);
483 
484  $itemTreeBounds = $uploadDao->getItemTreeBoundsFromUploadId($uploadTreeId, $uploadPk);
485  if ($itemTreeBounds->containsFiles()) {
486  throw new HttpBadRequestException("Item expected to be a file, container sent.");
487  }
488 
489  list ($addedClearingResults, $removedLicenses) = $this->clearingDecisionEventProcessor->getCurrentClearings(
490  $itemTreeBounds, $this->restHelper->getGroupId(), LicenseMap::CONCLUSION);
491  $licenseEventTypes = new ClearingEventTypes();
492 
493  $mergedArray = [];
494 
495  foreach ($addedClearingResults as $item) {
496  $mergedArray[] = ['item' => $item, 'isRemoved' => false];
497  }
498 
499  foreach ($removedLicenses as $item) {
500  $mergedArray[] = ['item' => $item, 'isRemoved' => true];
501  }
502 
503  $mainLicIds = $this->clearingDao->getMainLicenseIds($uploadPk, $this->restHelper->getGroupId());
504 
505  foreach ($mergedArray as $item) {
506  $clearingResult = $item['item'];
507  $licenseShortName = $clearingResult->getLicenseShortName();
508  $licenseId = $clearingResult->getLicenseId();
509 
510  $types = $this->getAgentInfo($clearingResult);
511  $reportInfo = "";
512  $comment = "";
513  $acknowledgement = "";
514 
515  if ($clearingResult->hasClearingEvent()) {
516  $licenseDecisionEvent = $clearingResult->getClearingEvent();
517  $types[] = $this->getEventInfo($licenseDecisionEvent, $licenseEventTypes);
518  $reportInfo = $licenseDecisionEvent->getReportinfo();
519  $comment = $licenseDecisionEvent->getComment();
520  $acknowledgement = $licenseDecisionEvent->getAcknowledgement();
521  }
522 
523  $obligations = $this->licenseDao->getLicenseObligations([$licenseId], false);
524  $obligations = array_merge($obligations, $this->licenseDao->getLicenseObligations([$licenseId], true));
525  $obligationList = [];
526  foreach ($obligations as $obligation) {
527  $obligationList[] = new Obligation(
528  $obligation['ob_pk'],
529  $obligation['ob_topic'],
530  $obligation['ob_type'],
531  $obligation['ob_text'],
532  $obligation['ob_classification'],
533  $obligation['ob_comment']
534  );
535  }
536  $license = $this->licenseDao->getLicenseById($licenseId);
537  $licenseObj = new LicenseDecision(
538  $license->getId(),
539  $licenseShortName,
540  $license->getFullName(),
541  $item['isRemoved'] ? '-' : (!empty($reportInfo) ? $reportInfo : $license->getText()),
542  $license->getUrl(),
543  $types,
544  $item['isRemoved'] ? '-' : $acknowledgement,
545  $item['isRemoved'] ? '-' : $comment,
546  in_array($license->getId(), $mainLicIds),
547  $obligationList,
548  $license->getRisk(),
549  $item['isRemoved']
550  );
551  $licenses[] = $licenseObj->getArray();
552  }
553  return $response->withJson($licenses, 200);
554  }
555 
560  private function getAgentInfo(ClearingResult $licenseDecisionResult)
561  {
562  $agentResults = array();
563  foreach ($licenseDecisionResult->getAgentDecisionEvents() as $agentDecisionEvent) {
564  $agentId = $agentDecisionEvent->getAgentId();
565  $matchId = $agentDecisionEvent->getMatchId();
566  $highlightRegion = $this->highlightDao->getHighlightRegion($matchId);
567  $page = null;
568  $percentage = $agentDecisionEvent->getPercentage();
569  if ($highlightRegion[0] != "" && $highlightRegion[1] != "") {
570  $page = $this->highlightDao->getPageNumberOfHighlightEntry($matchId);
571  }
572  $result = array(
573  'name' => $agentDecisionEvent->getAgentName(),
574  'clearingId' => null,
575  'agentId' => $agentId,
576  'highlightId' => $matchId,
577  'page' => intval($page),
578  'percentage' => $percentage
579  );
580  $agentResults[] = $result;
581  }
582  return $agentResults;
583  }
584 
585  private function getEventInfo($licenseDecisionEvent, $licenseEventTypes)
586  {
587  $type = $licenseEventTypes->getTypeName($licenseDecisionEvent->getEventType());
588  $eventId = null;
589  if ($licenseDecisionEvent->getEventType() == ClearingEventTypes::BULK) {
590  $eventId = $licenseDecisionEvent->getEventId();
591  }
592  return array(
593  'name' => $type,
594  'clearingId' => $eventId,
595  'agentId' => null,
596  'highlightId' => null,
597  'page' => null,
598  'percentage' => null
599  );
600  }
601 
611  public function handleAddEditAndDeleteLicenseDecision($request, $response, $args)
612  {
613  $body = $this->getParsedBody($request);
614  $uploadTreeId = intval($args['itemId']);
615  $uploadId = intval($args['id']);
616  $uploadDao = $this->restHelper->getUploadDao();
617  $errors = [];
618  $success = [];
619 
620  $this->uploadAccessible($uploadId);
621  $this->isItemExists($uploadId, $uploadTreeId);
622 
623  if (empty($body)) {
624  throw new HttpBadRequestException("Request body is missing or empty.");
625  }
626  if (!is_array($body)) {
627  throw new HttpBadRequestException("Request body should be an array.");
628  }
630  $concludeLicensePlugin = $this->restHelper->getPlugin('conclude-license');
631  $res = $concludeLicensePlugin->getCurrentSelectedLicensesTableData($uploadDao->getItemTreeBoundsFromUploadId($uploadTreeId, $uploadId), $this->restHelper->getGroupId(), true);
632 
633  $existingLicenseIds = [];
634  foreach ($res as $license) {
635  $currId = $license['DT_RowId'];
636  $currId = explode(',', $currId)[1];
637  $existingLicenseIds[] = intval($currId);
638  }
639 
640  foreach (array_keys($body) as $index) {
641  $licenseReq = $body[$index];
642 
643  $shortName = $licenseReq['shortName'];
644  if (empty($shortName)) {
645  $error = new Info(400, "Short name missing from the request #" . ($index + 1), InfoType::ERROR);
646  $errors[] = $error->getArray();
647  continue;
648  }
649 
650  $existingLicense = $this->licenseDao->getLicenseByShortName($shortName, $this->restHelper->getGroupId());
651  if ($existingLicense === null) {
652  $error = new Info(404, "License file with short name '$shortName' not found.",
653  InfoType::ERROR);
654  $errors[] = $error->getArray();
655  continue;
656  }
657 
658  if (!isset($licenseReq['add'])) {
659  $error = new Info(400, "'add' property missing from the request #" . ($index + 1), InfoType::ERROR);
660  $errors[] = $error->getArray();
661  continue;
662  }
663 
664  if ($licenseReq['add']) {
665  $columnsToUpdate = [];
666  if (isset($licenseReq['text'])) {
667  $columnsToUpdate[] = [
668  'columnId' => 'reportinfo',
669  'value' => $licenseReq['text']
670  ];
671  }
672  if (isset($licenseReq['ack'])) {
673  $columnsToUpdate[] = [
674  'columnId' => 'acknowledgement',
675  'value' => $licenseReq['ack']
676  ];
677  }
678  if (isset($licenseReq['comment'])) {
679  $columnsToUpdate[] = [
680  'columnId' => 'comment',
681  'value' => $licenseReq['comment']
682  ];
683  }
684 
685  if (in_array($existingLicense->getId(), $existingLicenseIds)) {
686  $valText = "";
687  foreach (array_keys($columnsToUpdate) as $colIdx) {
688  $this->clearingDao->updateClearingEvent($uploadTreeId, $this->restHelper->getUserId(), $this->restHelper->getGroupId(), $existingLicense->getId(), $columnsToUpdate[$colIdx]['columnId'], $columnsToUpdate[$colIdx]['value']);
689  if ($colIdx == count($columnsToUpdate) - 1 && count($columnsToUpdate) > 1) {
690  $valText .= " and ";
691  } else if ($colIdx > 0 && count($columnsToUpdate) > 1) {
692  $valText .= ", ";
693  }
694  $valText .= $columnsToUpdate[$colIdx]['columnId'];
695  }
696  $val = new Info(200, "Successfully updated " . $shortName . "'s license " . $valText, InfoType::INFO);
697  } else {
698  $this->clearingDao->insertClearingEvent($uploadTreeId, $this->restHelper->getUserId(), $this->restHelper->getGroupId(), $existingLicense->getId(), false);
699  foreach (array_keys($columnsToUpdate) as $colIdx) {
700  $this->clearingDao->updateClearingEvent($uploadTreeId, $this->restHelper->getUserId(), $this->restHelper->getGroupId(), $existingLicense->getId(), $columnsToUpdate[$colIdx]['columnId'], $columnsToUpdate[$colIdx]['value']);
701  }
702  $val = new Info(200, "Successfully added " . $shortName . " as a new license decision.", InfoType::INFO);
703  }
704  } else {
705  if (!in_array($existingLicense->getId(), $existingLicenseIds)) {
706  $error = new Info(404, $shortName . " license does not exist on this item", InfoType::ERROR);
707  $errors[] = $error->getArray();
708  continue;
709  }
710  $this->clearingDao->insertClearingEvent($uploadTreeId, $this->restHelper->getUserId(), $this->restHelper->getGroupId(), $existingLicense->getId(), true);
711  $val = new Info(200, "Successfully deleted " . $shortName . " from license decision list.", InfoType::INFO);
712  }
713  $success[] = $val->getArray();
714  }
715 
716  return $response->withJson([
717  'success' => $success,
718  'errors' => $errors
719  ], 200);
720  }
721 
731  public function scheduleBulkScan($request, $response, $args)
732  {
733  $body = $this->getParsedBody($request);
734  $uploadTreeId = intval($args['itemId']);
735  $uploadId = intval($args['id']);
736  $licenseDao = $this->container->get('dao.license');
737 
738  $this->uploadAccessible($uploadId);
739  $this->isItemExists($uploadId, $uploadTreeId);
740 
741  $isValid = true;
742 
743  // Validation errors
744  $errors = [];
745 
746  // Verify if each element from $body was given in the request
747  $requiredFields = ['bulkActions', 'refText', 'bulkScope', 'forceDecision', 'ignoreIrre', 'delimiters', 'scanOnlyFindings'];
748 
749  foreach ($requiredFields as $field) {
750  if (!array_key_exists($field, $body)) {
751  $isValid = false;
752  $errors[] = "$field should be given";
753  }
754  }
755  // Additional validations for specific fields
756  if ($isValid) {
757  // Check if refText is not equal to ""
758  if ($body['refText'] === "") {
759  $isValid = false;
760  $errors[] = "refText should not be empty";
761  }
762  // Check if forceDecision and ignoreIrre are true or false
763  if (!in_array($body['forceDecision'], [true, false]) || !in_array($body['ignoreIrre'], [true, false]) || !in_array($body['scanOnlyFindings'], [true, false])) {
764  $isValid = false;
765  $errors[] = "forceDecision, ignoreIrre and scanOnlyFindings should be either true or false";
766  }
767  // Check if delimiters is a string
768  if (!is_string($body['delimiters'])) {
769  $isValid = false;
770  $errors[] = "delimiters should be a string";
771  }
772  // check if bulkScope value is either folder or upload
773  if (!in_array($body['bulkScope'], ["folder", "upload"])) {
774  $isValid = false;
775  $errors[] = "bulkScope should be either folder or upload";
776  }
777  // check if the bulkActions property is an array and if each element has a valid license id
778  if (!is_array($body['bulkActions'])) {
779  $isValid = false;
780  $errors[] = "bulkActions should be an array";
781  } else {
782  foreach ($body['bulkActions'] as &$license) {
783  $existingLicense = $licenseDao->getLicenseByShortName($license['licenseShortName'],
784  $this->restHelper->getGroupId());
785  if ($existingLicense == null) {
786  $isValid = false;
787  $errors[] = "License with short name " . $license['licenseShortName'] . " does not exist";
788  } else if ($license['licenseAction'] != null && !in_array($license['licenseAction'], ["ADD", "REMOVE"])) {
789  $isValid = false;
790  $errors[] = "License action should be either ADD or REMOVE";
791  }
792 
793  $license['licenseId'] = $existingLicense->getId();
794  $license['reportinfo'] = $license['licenseText'];
795  $license['action'] = $license['licenseAction'] == 'REMOVE' ? 'Remove' : 'Add';
796  }
797  }
798  }
799 
800  $errorMess = "";
801  if (!$isValid) {
802  foreach ($errors as $error) {
803  $errorMess = $error . "\n";
804  }
805  throw new HttpBadRequestException($errorMess);
806  }
807 
808  $symfonyRequest = new \Symfony\Component\HttpFoundation\Request();
809  $symfonyRequest->request->set('bulkAction', $body['bulkActions']);
810  $symfonyRequest->request->set('refText', $body['refText']);
811  $symfonyRequest->request->set('bulkScope', $body['bulkScope'] == "folder" ? 'f' : 'u');
812  $symfonyRequest->request->set('uploadTreeId', $uploadTreeId);
813  $symfonyRequest->request->set('forceDecision', $body['forceDecision'] ? 1 : 0);
814  $symfonyRequest->request->set('ignoreIrre', $body['ignoreIrre'] ? 1 : 0);
815  $symfonyRequest->request->set('delimiters', $body['delimiters']);
816  $symfonyRequest->request->set('scanOnlyFindings', $body['scanOnlyFindings'] ? 1 : 0);
817 
819  $changeLicenseBulk = $this->restHelper->getPlugin('change-license-bulk');
820  $res = $changeLicenseBulk->handle($symfonyRequest);
821  $status = $res->getStatusCode();
822 
823  if ($status != 200) {
824  if ($status == Response::HTTP_BAD_REQUEST) {
825  throw new HttpBadRequestException(
826  json_decode($res->getContent(), true)["error"]);
827  }
828  throw new HttpInternalServerErrorException(
829  json_decode($res->getContent(), true)["error"]);
830  }
831 
832  $info = new Info(201, json_decode($res->getContent(), true)["jqid"], InfoType::INFO);
833  return $response->withJson($info->getArray(), $info->getCode());
834  }
835 }
Utility functions to process ClearingDecision.
Wrapper class for license map.
Definition: LicenseMap.php:19
Base controller for REST calls.
isItemExists(int $uploadId, int $itemId)
getParsedBody(ServerRequestInterface $request)
Parse request body as JSON and return associative PHP array.
getAgentInfo(ClearingResult $licenseDecisionResult)
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
RepPathItem($Item, $Repo="files")
Given an uploadtree_pk, retrieve the pfile path.
Definition: common-repo.php:91