FOSSology  4.7.1
Open Source License Compliance by Open Source Software
UploadDao.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2018 Siemens AG
4  Authors: Andreas Würl, Steffen Weber
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 namespace Fossology\Lib\Dao;
10 
21 use Monolog\Logger;
22 use DateTime;
23 
24 require_once(dirname(dirname(__FILE__)) . "/common-dir.php");
25 
26 class UploadDao
27 {
28 
29  const REUSE_NONE = 0;
30  const REUSE_ENHANCED = 2;
31  const REUSE_MAIN = 4;
32  const REUSE_CONF = 16;
33  const REUSE_COPYRIGHT = 128;
34  const REUSE_BULK = 8;
35  const UNIFIED_REPORT_HEADINGS = array(
36  "assessment" => array("Assessment Summary" => true),
37  "compliancetasks" => array("Required license compliance tasks" => true),
38  "acknowledgements" => array("Acknowledgements" => true),
39  "exportrestrictions" => array("Export Restrictions" => true),
40  "intellectualProperty" => array("Patent Relevant Statements" => true),
41  "notes" => array("Notes" => true),
42  "scanresults" => array("Results of License Scan" => true),
43  "mainlicenses" => array("Main Licenses" => true),
44  "redlicense" => array("Other OSS Licenses (red) - Do not Use Licenses" => true),
45  "yellowlicense" => array("Other OSS Licenses (yellow) - additional obligations to common rules (e.g. copyleft)" => true),
46  "whitelicense" => array("Other OSS Licenses (white) - only common rules" => true),
47  "overviewwithwithoutobligations" => array("Overview of All Licenses with or without Obligations" => true),
48  "copyrights" => array("Copyrights" => true),
49  "copyrightsuf" => array("Copyrights (User Findings)" => true),
50  "bulkfindings" => array("Bulk Findings" => true),
51  "licensenf" => array("Non-Functional Licenses" => true),
52  "irrelevantfiles" => array("Irrelevant Files" => true),
53  "dnufiles" => array("Do not use Files" => true),
54  "changelog" => array("Clearing Protocol Change Log" => true)
55  );
56  const CLIXML_REPORT_HEADINGS = array(
57  "mainlicensesclixml" => array("Main Licenses" => true),
58  "licensepath" => array("License File Path" => true),
59  "licensehash" => array("License File Hash" => true),
60  "copyrightsclixml" => array("Copyrights" => true),
61  "copyrightpath" => array("Copyright File Path" => true),
62  "copyrighthash" => array("Copyright File Hash" => true),
63  "exportrestrictionsclixml" => array("Export Restrictions(ECC)" => true),
64  "eccpath" => array("ECC File Path" => true),
65  "ecchash" => array("ECC File Hash" => true),
66  "intellectualPropertyclixml" => array("Identified Patent Relevant Analysis(IPRA)" => true),
67  "iprapath" => array("IPRA File Path" => true),
68  "iprahash" => array("IPRA File Hash" => true),
69  "allobligations" => array("All Obligations" => true),
70  "acknowledgementsclixml" => array("Acknowledgements" => true),
71  "irrelevantfilesclixml" => array("Irrelevant Files" => true),
72  "dnufilesclixml" => array("Do not use Files" => true),
73  "notesclixml" => array("Additional Notes" => true)
74  );
76  private $dbManager;
78  private $logger;
80  private $permissionDao;
81 
82  public function __construct(DbManager $dbManager, Logger $logger, UploadPermissionDao $uploadPermissionDao)
83  {
84  $this->dbManager = $dbManager;
85  $this->logger = $logger;
86  $this->permissionDao = $uploadPermissionDao;
87  }
88 
89 
95  public function getUploadEntry($uploadTreeId, $uploadTreeTableName = "uploadtree")
96  {
97  $stmt = __METHOD__ . ".$uploadTreeTableName";
98  $uploadEntry = $this->dbManager->getSingleRow("SELECT * FROM $uploadTreeTableName WHERE uploadtree_pk = $1",
99  array($uploadTreeId), $stmt);
100  if ($uploadEntry) {
101  $uploadEntry['tablename'] = $uploadTreeTableName;
102  }
103  return $uploadEntry;
104  }
105 
112  public function getUploadtreeIdFromPfile($uploadFk, $pfileFk)
113  {
114  $uploadTreeTableName = $this->getUploadtreeTableName($uploadFk);
115  $stmt = __METHOD__ . ".$uploadTreeTableName";
116  $uploadEntry = $this->dbManager->getSingleRow("SELECT uploadtree_pk " .
117  "FROM $uploadTreeTableName " .
118  "WHERE upload_fk = $1 AND pfile_fk = $2",
119  array($uploadFk, $pfileFk), $stmt);
120  return intval($uploadEntry['uploadtree_pk']);
121  }
122 
127  public function getUpload($uploadId)
128  {
129  $stmt = __METHOD__;
130  $row = $this->dbManager->getSingleRow("SELECT * FROM upload WHERE upload_pk = $1",
131  array($uploadId), $stmt);
132 
133  return $row ? Upload::createFromTable($row) : null;
134  }
135 
136  public function getActiveUploadsArray()
137  {
138  $stmt = __METHOD__;
139  $queryResult = $this->dbManager->getRows("SELECT * FROM upload where pfile_fk IS NOT NULL",
140  array(), $stmt);
141 
142  $results = array();
143  foreach ($queryResult as $row) {
144  $results[] = Upload::createFromTable($row);
145  }
146 
147  return $results;
148  }
149 
155  public function getAccessibleUploads($groupId)
156  {
157  $stmt = __METHOD__;
158  $permNone = Auth::PERM_NONE;
159  $sql = "SELECT u.* FROM upload u
160  LEFT JOIN perm_upload p ON p.upload_fk = u.upload_pk AND p.group_fk = $1
161  WHERE u.pfile_fk IS NOT NULL
162  AND (p.perm > $permNone OR u.public_perm > $permNone)";
163 
164  $queryResult = $this->dbManager->getRows($sql, array($groupId), $stmt);
165 
166  $results = array();
167  foreach ($queryResult as $row) {
168  $results[] = Upload::createFromTable($row);
169  }
170 
171  return $results;
172  }
173 
179  public function getItemTreeBounds($itemId, $uploadTreeTableName = "uploadtree")
180  {
181  $uploadEntryData = $this->getUploadEntry($itemId, $uploadTreeTableName);
182  return $this->createItemTreeBounds($uploadEntryData, $uploadTreeTableName);
183  }
184 
190  public function getItemTreeBoundsFromUploadId($uploadTreeId, $uploadId)
191  {
192  $uploadTreeTableName = $this->getUploadtreeTableName($uploadId);
193  return $this->getItemTreeBounds($uploadTreeId, $uploadTreeTableName);
194  }
195 
202  public function getParentItemBounds($uploadId, $uploadTreeTableName = null)
203  {
204  if ($uploadTreeTableName === null) {
205  $uploadTreeTableName = $this->getUploadtreeTableName($uploadId);
206  }
207 
208  $stmt = __METHOD__ . ".$uploadTreeTableName";
209  $parameters = array();
210  $uploadCondition = $this->handleUploadIdForTable($uploadTreeTableName, $uploadId, $parameters);
211 
212  $uploadEntryData = $this->dbManager->getSingleRow("SELECT * FROM $uploadTreeTableName
213  WHERE parent IS NULL
214  $uploadCondition
215  ",
216  $parameters, $stmt);
217 
218  return $uploadEntryData ? $this->createItemTreeBounds($uploadEntryData, $uploadTreeTableName) : false;
219  }
220 
225  public function countPlainFiles(ItemTreeBounds $itemTreeBounds)
226  {
227  $uploadTreeTableName = $itemTreeBounds->getUploadTreeTableName();
228 
229  $stmt = __METHOD__ . ".$uploadTreeTableName";
230  $parameters = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
231  $uploadCondition = $this->handleUploadIdForTable($uploadTreeTableName, $itemTreeBounds->getUploadId(), $parameters);
232 
233  $row = $this->dbManager->getSingleRow("SELECT count(*) as count FROM $uploadTreeTableName
234  WHERE lft BETWEEN $1 AND $2
235  $uploadCondition
236  AND ((ufile_mode & (3<<28))=0)
237  AND pfile_fk != 0",
238  $parameters, $stmt);
239  return intval($row["count"]);
240  }
241 
242  private function handleUploadIdForTable($uploadTreeTableName, $uploadId, &$parameters)
243  {
244  if ($uploadTreeTableName === "uploadtree" || $uploadTreeTableName === "uploadtree_a") {
245  $parameters[] = $uploadId;
246  return " AND upload_fk = $" . count($parameters) . " ";
247  } else {
248  return "";
249  }
250  }
251 
255  public function getStatusTypeMap()
256  {
257  global $container;
259  $uploadStatus = $container->get('upload_status.types');
260  return $uploadStatus->getMap();
261  }
262 
270  public function getStatus($uploadId, $groupId)
271  {
272  if ($this->isAccessible($uploadId, $groupId)) {
273  $row = $this->dbManager->getSingleRow("SELECT status_fk " .
274  "FROM upload_clearing WHERE upload_fk=$1 AND group_fk=$2;",
275  array($uploadId, $groupId));
276  if (false === $row) {
277  return 1;
278  }
279  return $row['status_fk'];
280  } else {
281  throw new \Exception("permission denied");
282  }
283  }
284 
285 
293  public function getAssignee($uploadId, $groupId)
294  {
295  if ($this->isAccessible($uploadId, $groupId)) {
296  $row = $this->dbManager->getSingleRow("SELECT assignee FROM upload_clearing WHERE upload_fk=$1 AND group_fk=$2;",
297  array($uploadId, $groupId));
298  if (false === $row) {
299  return 1;
300  }
301  return $row['assignee'];
302  } else {
303  throw new \Exception("permission denied");
304  }
305  }
306 
314  public function getAssigneeDate(int $uploadId): ?string
315  {
316  $sql = "SELECT MIN(event_ts) as event_ts FROM upload_events WHERE upload_fk = $1 " .
317  "AND event_type = " . UploadEvents::ASSIGNEE_EVENT;
318  $row = $this->dbManager->getSingleRow($sql, [$uploadId], __METHOD__);
319  if (empty($row) || empty($row["event_ts"])) {
320  return null;
321  }
322  return $row["event_ts"];
323  }
324 
331  public function getClosedDate(int $uploadId): ?string
332  {
333  $sql = "SELECT MAX(event_ts) as event_ts FROM upload_events WHERE upload_fk = $1 " .
334  "AND event_type = " . UploadEvents::UPLOAD_CLOSED_EVENT;
335  $row = $this->dbManager->getSingleRow($sql, [$uploadId], __METHOD__);
336  if (empty($row) || empty($row["event_ts"])) {
337  return null;
338  }
339  return $row["event_ts"];
340  }
341 
348  public function getClearingDuration(int $uploadId): array
349  {
350  $batch = $this->getClearingDurationsBatch(array($uploadId));
351  return $batch[$uploadId] ?? ['NA', 0];
352  }
353 
359  public function getClearingDurationsBatch(array $uploadIds): array
360  {
361  if (empty($uploadIds)) {
362  return array();
363  }
364 
365  $uploadIds = array_unique(array_filter($uploadIds));
366  if (empty($uploadIds)) {
367  return array();
368  }
369 
370  $results = array();
371  foreach ($uploadIds as $id) {
372  $results[(int)$id] = array("NA", 0);
373  }
374 
375  $uploadIdsStr = '{' . implode(',', array_map('intval', $uploadIds)) . '}';
376 
377  $sql = "SELECT upload_fk, " .
378  "MIN(CASE WHEN event_type = $2 THEN event_ts END) as assignee_ts, " .
379  "MAX(CASE WHEN event_type = $3 THEN event_ts END) as closed_ts " .
380  "FROM upload_events " .
381  "WHERE upload_fk = ANY($1::int[]) AND event_type IN ($2, $3) " .
382  "GROUP BY upload_fk";
383 
384  $rows = $this->dbManager->getRows($sql, array($uploadIdsStr, UploadEvents::ASSIGNEE_EVENT, UploadEvents::UPLOAD_CLOSED_EVENT), __METHOD__);
385 
386  foreach ($rows as $row) {
387  $id = (int)$row['upload_fk'];
388  $duration = "NA";
389  $durationSort = 0;
390 
391  if (!empty($row['assignee_ts']) && !empty($row['closed_ts'])) {
392  try {
393  $assignDate = new DateTime($row['assignee_ts']);
394  $closingDate = new DateTime($row['closed_ts']);
395  if ($assignDate < $closingDate) {
396  $duration = HumanDuration($closingDate->diff($assignDate));
397  $durationSort = $closingDate->getTimestamp() - $assignDate->getTimestamp();
398  }
399  } catch (\Exception $_) {
400  }
401  }
402  $results[$id] = array($duration, $durationSort);
403  }
404 
405  return $results;
406  }
415  public function getUploadtreeTableName($uploadId)
416  {
417  if (!empty($uploadId)) {
418  $statementName = __METHOD__;
419  $row = $this->dbManager->getSingleRow(
420  "SELECT uploadtree_tablename FROM upload WHERE upload_pk=$1",
421  array($uploadId),
422  $statementName
423  );
424  if (!empty($row['uploadtree_tablename'])) {
425  return $row['uploadtree_tablename'];
426  }
427  }
428  return "uploadtree";
429  }
430 
436  public function getNextItem($uploadId, $itemId, $options = null)
437  {
438  return $this->getItemByDirection($uploadId, $itemId, self::DIR_FWD, $options);
439  }
440 
447  public function getPreviousItem($uploadId, $itemId, $options = null)
448  {
449  return $this->getItemByDirection($uploadId, $itemId, self::DIR_BCK, $options);
450  }
451 
452  const DIR_FWD = 1;
453  const DIR_BCK = -1;
454  const NOT_FOUND = null;
455 
456 
464  public function getItemByDirection($uploadId, $itemId, $direction, $options)
465  {
466  $uploadTreeTableName = $this->getUploadtreeTableName($uploadId);
467  $originItem = $this->getUploadEntry($itemId, $uploadTreeTableName);
468  $originLft = $originItem['lft'];
469 
470  $options[UploadTreeProxy::OPT_ITEM_FILTER] = " AND ut.ufile_mode & (3<<28) = 0";
471  $uploadTreeViewName = 'items2care';
472 
473  if ($direction == self::DIR_FWD) {
474  $uploadTreeViewName .= 'fwd';
475  $options[UploadTreeProxy::OPT_ITEM_FILTER] .= " AND lft>$1";
476  $order = 'ASC';
477  } else {
478  $uploadTreeViewName .= 'bwd';
479  $options[UploadTreeProxy::OPT_ITEM_FILTER] .= " AND lft<$1";
480  $order = 'DESC';
481  }
482 
483  $uploadTreeView = new UploadTreeProxy($uploadId, $options, $uploadTreeTableName, $uploadTreeViewName);
484  $statementName = __METHOD__ . ".$uploadTreeViewName.";
485  $query = $uploadTreeView->getDbViewQuery()." ORDER BY lft $order";
486 
487  $newItemRow = $this->dbManager->getSingleRow("$query LIMIT 1", array($originLft), $statementName);
488  if ($newItemRow) {
489  return $this->createItem($newItemRow, $uploadTreeTableName);
490  } else {
491  return self::NOT_FOUND;
492  }
493  }
494 
495 
500  public function getUploadParent($uploadId)
501  {
502  $uploadTreeTableName = $this->getUploadtreeTableName($uploadId);
503  $statementname = __METHOD__ . $uploadTreeTableName;
504 
505  $parent = $this->dbManager->getSingleRow(
506  "SELECT uploadtree_pk
507  FROM $uploadTreeTableName
508  WHERE upload_fk=$1 AND parent IS NULL", array($uploadId), $statementname);
509  if (false === $parent) {
510  throw new \Exception("Missing upload tree parent for upload");
511  }
512  return $parent['uploadtree_pk'];
513  }
514 
515  public function getLeftAndRight($uploadtreeID, $uploadTreeTableName = "uploadtree")
516  {
517  $statementName = __METHOD__ . $uploadTreeTableName;
518  $leftRight = $this->dbManager->getSingleRow(
519  "SELECT lft,rgt FROM $uploadTreeTableName WHERE uploadtree_pk = $1",
520  array($uploadtreeID), $statementName
521  );
522 
523  return array($leftRight['lft'], $leftRight['rgt']);
524  }
525 
531  public function getContainingFileCount(ItemTreeBounds $itemTreeBounds, UploadTreeProxy $uploadTreeView)
532  {
533  $sql = "SELECT count(*) FROM " . $uploadTreeView->getDbViewName() . " WHERE lft BETWEEN $1 AND $2";
534  $result = $this->dbManager->getSingleRow($sql
535  , array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight()), __METHOD__ . $uploadTreeView->asCTE());
536  return $result['count'];
537  }
538 
545  public function getContainedItems(ItemTreeBounds $itemTreeBounds, $addCondition = "", $addParameters = array())
546  {
547  $uploadTreeTableName = $itemTreeBounds->getUploadTreeTableName();
548 
549  $statementName = __METHOD__ . ".$uploadTreeTableName";
550 
551  $view = new UploadTreeViewProxy($itemTreeBounds, array(UploadTreeViewProxy::CONDITION_PLAIN_FILES));
552 
553  $this->dbManager->prepare($statementName,
554  $view->asCTE() . " SELECT * FROM " . $view->getDbViewName() ." ut ".
555  ($addCondition ? " WHERE " . $addCondition : ''));
556  $res = $this->dbManager->execute($statementName, $addParameters);
557  $items = array();
558 
559  while ($row = $this->dbManager->fetchArray($res)) {
560  $items[] = $this->createItem($row, $uploadTreeTableName);
561  }
562  $this->dbManager->freeResult($res);
563  return $items;
564  }
565 
573  public function addReusedUpload($uploadId, $reusedUploadId, $groupId, $reusedGroupId, $reuseMode=0)
574  {
575  $this->dbManager->insertTableRow('upload_reuse',
576  array('upload_fk'=>$uploadId, 'group_fk'=> $groupId, 'reused_upload_fk'=>$reusedUploadId, 'reused_group_fk'=>$reusedGroupId,'reuse_mode'=>$reuseMode));
577  }
578 
585  public function getReusedUpload($uploadId, $groupId)
586  {
587  $statementName = __METHOD__;
588 
589  $this->dbManager->prepare($statementName,
590  "SELECT reused_upload_fk, reused_group_fk, reuse_mode FROM upload_reuse WHERE upload_fk = $1 AND group_fk=$2 ORDER BY date_added DESC");
591  $res = $this->dbManager->execute($statementName, array($uploadId, $groupId));
592  $reusedPairs = $this->dbManager->fetchAll($res);
593  $this->dbManager->freeResult($res);
594  return $reusedPairs;
595  }
596 
602  protected function createItem($uploadEntry, $uploadTreeTableName)
603  {
604  $itemTreeBounds = new ItemTreeBounds(
605  intval($uploadEntry['uploadtree_pk']),
606  $uploadTreeTableName,
607  intval($uploadEntry['upload_fk']),
608  intval($uploadEntry['lft']), intval($uploadEntry['rgt']));
609 
610  $parent = $uploadEntry['parent'];
611  return new Item(
612  $itemTreeBounds, $parent !== null ? intval($parent) : null, intval($uploadEntry['pfile_fk']), intval($uploadEntry['ufile_mode']), $uploadEntry['ufile_name']
613  );
614  }
615 
622  protected function createItemTreeBounds($uploadEntryData, $uploadTreeTableName)
623  {
624  if ($uploadEntryData === false) {
625  throw new Exception("did not find uploadTreeId in $uploadTreeTableName");
626  }
627  return new ItemTreeBounds(intval($uploadEntryData['uploadtree_pk']), $uploadTreeTableName, intval($uploadEntryData['upload_fk']), intval($uploadEntryData['lft']), intval($uploadEntryData['rgt']));
628  }
629 
635  public function countNonArtifactDescendants(ItemTreeBounds $itemTreeBounds, $isFlat=true)
636  {
637  $stmt=__METHOD__;
638  $sql = "SELECT count(*) FROM ".$itemTreeBounds->getUploadTreeTableName()." ut "
639  . "WHERE ut.upload_fk=$1";
640  $params = array($itemTreeBounds->getUploadId());
641  if (!$isFlat) {
642  $stmt = __METHOD__.'.parent';
643  $params[] = $itemTreeBounds->getItemId();
644  $sql .= " AND ut.ufile_mode & (1<<28) = 0 AND ut.realparent = $2";
645  } else {
646  $params[] = $itemTreeBounds->getLeft();
647  $params[] = $itemTreeBounds->getRight();
648  $sql .= " AND ut.ufile_mode & (3<<28) = 0 AND (ut.lft BETWEEN $2 AND $3)";
649  }
650 
651  $descendants = $this->dbManager->getSingleRow($sql,$params);
652  return $descendants['count'];
653  }
654 
655 
656  public function isAccessible($uploadId, $groupId)
657  {
658  return $this->permissionDao->isAccessible($uploadId, $groupId);
659  }
660 
661  public function isEditable($uploadId, $groupId)
662  {
663  return $this->permissionDao->isEditable($uploadId, $groupId);
664  }
665 
666  public function makeAccessibleToGroup($uploadId, $groupId, $perm=null)
667  {
668  $this->permissionDao->makeAccessibleToGroup($uploadId, $groupId, $perm);
669  }
670 
671  public function makeAccessibleToAllGroupsOf($uploadId, $userId, $perm=null)
672  {
673  $this->permissionDao->makeAccessibleToAllGroupsOf($uploadId, $userId, $perm);
674  }
675 
676  public function filterAccessibleUploads(array $uploadIds, $groupId)
677  {
678  return $this->permissionDao->filterAccessibleUploads($uploadIds, $groupId);
679  }
680 
685  public function getUploadHashes($uploadId)
686  {
687  $pfile = $this->dbManager->getSingleRow('SELECT pfile.* FROM upload, pfile WHERE upload_pk=$1 AND pfile_fk=pfile_pk',
688  array($uploadId), __METHOD__);
689  return array('sha1'=>$pfile['pfile_sha1'],'md5'=>$pfile['pfile_md5'],'sha256'=>$pfile['pfile_sha256']);
690  }
691 
698  public function getFatItemArray($itemId,$uploadId,$uploadtreeTablename)
699  {
700  $sqlChildrenOf = "SELECT COUNT(*) FROM $uploadtreeTablename s
701  WHERE ufile_mode&(1<<28)=0 and s.upload_fk=$2 AND s.realparent=";
702  $sql="WITH RECURSIVE item_path (item_id,num_children,depth,ufile_mode,ufile_name) AS (
703  SELECT uploadtree_pk item_id, ($sqlChildrenOf $1) num_children, 0 depth, ufile_mode, ufile_name
704  FROM $uploadtreeTablename WHERE upload_fk=$2 AND uploadtree_pk=$1
705  UNION
706  SELECT uploadtree_pk item_id, ($sqlChildrenOf ut.uploadtree_pk) num_children,
707  item_path.depth+1 depth, ut.ufile_mode, item_path.ufile_name||'/'||ut.ufile_name ufile_name
708  FROM $uploadtreeTablename ut INNER JOIN item_path ON item_id=ut.realparent
709  WHERE upload_fk=$2 AND ut.ufile_mode&(1<<28)=0 AND num_children<2
710  )
711  SELECT * FROM item_path WHERE num_children!=1 OR ufile_mode&(1<<29)=0 ORDER BY depth DESC LIMIT 1";
712  return $this->dbManager->getSingleRow($sql,array($itemId, $uploadId),__METHOD__.$uploadtreeTablename);
713  }
714 
721  public function getFatItemId($itemId,$uploadId,$uploadtreeTablename)
722  {
723  $itemRow = $this->getFatItemArray($itemId,$uploadId,$uploadtreeTablename);
724  return $itemRow['item_id'];
725  }
726 
731  public function getPFileDataPerFileName(ItemTreeBounds $itemTreeBounds)
732  {
733  $uploadTreeTableName = $itemTreeBounds->getUploadTreeTableName();
734  $statementName = __METHOD__ . '.' . $uploadTreeTableName;
735  $param = array();
736 
737  $param[] = $itemTreeBounds->getLeft();
738  $param[] = $itemTreeBounds->getRight();
739  $condition = " lft BETWEEN $1 AND $2";
740  $condition .= " AND (ufile_mode & (1<<28)) = 0";
741 
742  if ('uploadtree_a' == $uploadTreeTableName) {
743  $param[] = $itemTreeBounds->getUploadId();
744  $condition .= " AND upload_fk=$".count($param);
745  }
746 
747  $sql = "
748 SELECT ufile_name, uploadtree_pk, lft, rgt, ufile_mode,
749  pfile_pk, pfile_md5, pfile_sha1, pfile_sha256
750 FROM $uploadTreeTableName
751  LEFT JOIN pfile
752  ON pfile_fk = pfile_pk
753 WHERE $condition
754 ORDER BY lft asc
755 ";
756 
757  $this->dbManager->prepare($statementName, $sql);
758  $result = $this->dbManager->execute($statementName, $param);
759  $pfilePerFileName = array();
760 
761  $row = $this->dbManager->fetchArray($result);
762  $pathStack = array($row['ufile_name']);
763  $rgtStack = array($row['rgt']);
764  $lastLft = $row['lft'];
765  $this->addToPFilePerFileName($pfilePerFileName, $pathStack, $row);
766  while ($row = $this->dbManager->fetchArray($result)) {
767  if ($row['lft'] < $lastLft) {
768  continue;
769  }
770 
771  $this->updateStackState($pathStack, $rgtStack, $lastLft, $row);
772  $this->addToPFilePerFileName($pfilePerFileName, $pathStack, $row);
773  }
774  $this->dbManager->freeResult($result);
775  return $pfilePerFileName;
776  }
777 
778  private function updateStackState(&$pathStack, &$rgtStack, &$lastLft, $row)
779  {
780  if ($row['lft'] >= $lastLft) {
781  while (count($rgtStack) > 0 && $row['lft'] > $rgtStack[count($rgtStack)-1]) {
782  array_pop($pathStack);
783  array_pop($rgtStack);
784  }
785  if ($row['lft'] > $lastLft) {
786  $pathStack[] = $row['ufile_name'];
787  $rgtStack[] = $row['rgt'];
788  $lastLft = $row['lft'];
789  }
790  }
791  }
792 
793  private function addToPFilePerFileName(&$pfilePerFileName, $pathStack, $row)
794  {
795  if (($row['ufile_mode'] & (1 << 29)) == 0) {
796  $path = implode('/', $pathStack);
797  $pfilePerFileName[$path]['pfile_pk'] = $row['pfile_pk'];
798  $pfilePerFileName[$path]['uploadtree_pk'] = $row['uploadtree_pk'];
799  $pfilePerFileName[$path]['md5'] = $row['pfile_md5'];
800  $pfilePerFileName[$path]['sha1'] = $row['pfile_sha1'];
801  $pfilePerFileName[$path]['sha256'] = $row['pfile_sha256'];
802  }
803  }
804 
810  public function getPFilesDataPerHashAlgo(ItemTreeBounds $itemTreeBounds, $hashAlgo="sha1")
811  {
812  $uploadTreeTableName = $itemTreeBounds->getUploadTreeTableName();
813  $statementName = __METHOD__ . '.' . $uploadTreeTableName;
814  $param = array();
815 
816  $param[] = $itemTreeBounds->getLeft();
817  $param[] = $itemTreeBounds->getRight();
818  $condition = " lft BETWEEN $1 AND $2";
819  $condition .= " AND (ufile_mode & (1<<28)) = 0";
820 
821  if ('uploadtree_a' == $uploadTreeTableName) {
822  $param[] = $itemTreeBounds->getUploadId();
823  $condition .= " AND upload_fk=$".count($param);
824  }
825  $condition .= " AND pfile_$hashAlgo IS NOT NULL";
826 
827  $sql = "
828 SELECT pfile_fk, uploadtree_pk, ufile_mode, pfile_$hashAlgo as hash
829 FROM $uploadTreeTableName
830  LEFT JOIN pfile
831  ON pfile_fk = pfile_pk
832 WHERE $condition
833 ORDER BY lft asc
834 ";
835 
836  $this->dbManager->prepare($statementName, $sql);
837  $result = $this->dbManager->execute($statementName, $param);
838 
839  $pfilePerHashAlgo = array();
840  while ($row = $this->dbManager->fetchArray($result)) {
841  if (($row['ufile_mode']&(1<<29)) == 0) {
842  $pfilePerHashAlgo[strtolower($row['hash'])][] = array('pfile_pk' => $row['pfile_fk'],
843  'uploadtree_pk' => $row['uploadtree_pk']);
844  }
845  }
846  $this->dbManager->freeResult($result);
847  return $pfilePerHashAlgo;
848  }
849 
850 
851  /* @param int $uploadId
852  * @return array
853  */
854  public function getReportInfo($uploadId)
855  {
856  $stmt = __METHOD__;
857  $sql = "SELECT * FROM report_info WHERE upload_fk = $1";
858  $row = $this->dbManager->getSingleRow($sql, array($uploadId), $stmt);
859 
860  if (empty($row)) {
861  $this->dbManager->begin();
862  $stmt = __METHOD__.'ifempty';
863  $sql = "INSERT INTO report_info (upload_fk) VALUES ($1) RETURNING *";
864  $row = $this->dbManager->getSingleRow($sql, array($uploadId), $stmt);
865  $this->dbManager->commit();
866  }
867  return $row;
868  }
869 
875  private function getUserSPDXDefaultsForUpload($uploadId)
876  {
877  $stmt = __METHOD__ . '.getOwner';
878  $sql = "SELECT user_fk FROM upload WHERE upload_pk = $1";
879  $uploadOwner = $this->dbManager->getSingleRow($sql, array($uploadId), $stmt);
880 
881  if (empty($uploadOwner)) {
882  return "unchecked,unchecked,unchecked";
883  }
884 
885  $userId = $uploadOwner['user_fk'];
886 
887  $stmt = __METHOD__ . '.getUserDefaults';
888  $sql = "SELECT spdx_settings FROM users WHERE user_pk = $1";
889  $userDefaults = $this->dbManager->getSingleRow($sql, array($userId), $stmt);
890 
891  if (empty($userDefaults) || empty($userDefaults['spdx_settings'])) {
892  return "unchecked,unchecked,unchecked";
893  }
894 
895  $settings = explode(',', $userDefaults['spdx_settings']);
896  if (count($settings) < 3) {
897  $settings = array_pad($settings, 3, 'unchecked');
898  }
899 
900  $osselotExport = $settings[0];
901  $spdxLicenseComment = $settings[1];
902  $ignoreFilesWOInfo = $settings[2];
903 
904  $result = "$spdxLicenseComment,$ignoreFilesWOInfo,$osselotExport";
905 
906  return $result;
907  }
908 
914  public function getCyclonedxSettings($uploadId)
915  {
916  $stmt = __METHOD__ . '.getOwner';
917  $sql = "SELECT user_fk FROM upload WHERE upload_pk = $1";
918  $uploadOwner = $this->dbManager->getSingleRow($sql, array($uploadId), $stmt);
919 
920  if (empty($uploadOwner)) {
921  return "unchecked,unchecked,unchecked";
922  }
923 
924  $userId = $uploadOwner['user_fk'];
925 
926  $stmt = __METHOD__ . '.getUserDefaults';
927  $sql = "SELECT cyclonedx_settings FROM users WHERE user_pk = $1";
928  $userDefaults = $this->dbManager->getSingleRow($sql, array($userId), $stmt);
929 
930  if (empty($userDefaults) || empty($userDefaults['cyclonedx_settings'])) {
931  return "unchecked,unchecked,unchecked";
932  }
933 
934  $settings = explode(',', $userDefaults['cyclonedx_settings']);
935  if (count($settings) < 3) {
936  $settings = array_pad($settings, 3, 'unchecked');
937  }
938 
939  $osselotExport = $settings[0];
940  $cyclonedxLicenseComment = $settings[1];
941  $ignoreFilesWOInfo = $settings[2];
942 
943  $result = "$cyclonedxLicenseComment,$ignoreFilesWOInfo,$osselotExport";
944 
945  return $result;
946  }
947 
955  public function updateReportInfo($uploadId, $column, $value)
956  {
957  if ($column === "ri_unifiedcolumns") {
958  $value = json_decode($value, true);
959  $oldValues = $this->getReportInfo($uploadId)["ri_unifiedcolumns"];
960  if (!empty($oldValues)) {
961  $oldValues = json_decode($oldValues, true);
962  } else {
963  $oldValues = self::UNIFIED_REPORT_HEADINGS;
964  }
965  foreach ($value as $key => $val) {
966  $newValText = array_keys($val)[0];
967  $newValValue = array_values($val)[0];
968  $newValValue = ($newValValue === true || $newValValue == "true") ? "on" : null;
969  $oldValues[$key] = [$newValText => $newValValue];
970  }
971  $value = json_encode($oldValues);
972  } elseif ($column === "ri_excluded_obligations") {
973  $value = json_decode($value, true);
974  $oldValues = $this->getReportInfo($uploadId)["ri_excluded_obligations"];
975  if (!empty($oldValues)) {
976  $oldValues = json_decode($oldValues, true);
977  } else {
978  $oldValues = [];
979  }
980  foreach ($value as $key => $newValue) {
981  $oldValues[$key] = $newValue;
982  }
983  $value = json_encode($oldValues);
984  } elseif ($column === "ri_globaldecision") {
985  $value = filter_var($value, FILTER_VALIDATE_BOOL);
986  }
987 
988  $sql = "UPDATE report_info SET $column = $2 WHERE upload_fk = $1;";
989  $stmt = __METHOD__ . "updateReportInfo" . $column;
990  $this->dbManager->getSingleRow($sql, [$uploadId, $value], $stmt);
991  return true;
992  }
993 
994  /* @param int $uploadId
995  * @return int
996  */
997  public function getGlobalDecisionSettingsFromInfo($uploadId, $setGlobal=null)
998  {
999  $stmt = __METHOD__ . 'get';
1000  $sql = "SELECT ri_globaldecision, ri_spdx_selection FROM report_info WHERE upload_fk = $1";
1001  $row = $this->dbManager->getSingleRow($sql, array($uploadId), $stmt);
1002  if (empty($row)) {
1003  if ($setGlobal === null) {
1004  // Old upload, set default value to enable
1005  $setGlobal = 1;
1006  }
1007  $stmt = __METHOD__ . 'ifempty';
1008  $userSPDXDefaults = $this->getUserSPDXDefaultsForUpload($uploadId);
1009  $sql = "INSERT INTO report_info (upload_fk, ri_globaldecision, ri_spdx_selection) VALUES ($1, $2, $3) RETURNING ri_globaldecision";
1010  $row = $this->dbManager->getSingleRow($sql, array($uploadId, $setGlobal, $userSPDXDefaults), $stmt);
1011 
1012  }
1013 
1014  if (!empty($setGlobal)) {
1015  $stmt = __METHOD__ . 'update';
1016  $sql = "UPDATE report_info SET ri_globaldecision = $2 WHERE upload_fk = $1 RETURNING ri_globaldecision";
1017  $row = $this->dbManager->getSingleRow($sql, array($uploadId, $setGlobal), $stmt);
1018  }
1019 
1020  return $row['ri_globaldecision'];
1021  }
1022 
1028  public function getUploadHashesFromPfileId($pfilePk)
1029  {
1030  $stmt = __METHOD__."getUploadHashesFromPfileId";
1031  $sql = "SELECT * FROM pfile WHERE pfile_pk = $1";
1032  $row = $this->dbManager->getSingleRow($sql, array($pfilePk), $stmt);
1033 
1034  return ["sha1" => $row["pfile_sha1"], "md5" => $row["pfile_md5"], "sha256" => $row["pfile_sha256"]];
1035  }
1036 
1042  public function insertReportConfReuse($uploadId, $reusedUploadId)
1043  {
1044  $stmt = __METHOD__ . ".checkReused";
1045  $sql = "SELECT 1 AS exists FROM report_info WHERE upload_fk = $1 LIMIT 1;";
1046  $row = $this->dbManager->getSingleRow($sql, array($reusedUploadId), $stmt);
1047 
1048  if (empty($row['exists'])) {
1049  return false;
1050  }
1051 
1052  $this->dbManager->begin();
1053 
1054  $stmt = __METHOD__ . ".removeExists";
1055  $sql = "DELETE FROM report_info WHERE upload_fk = $1;";
1056  $this->dbManager->getSingleRow($sql, [$uploadId], $stmt);
1057 
1058  $stmt = __METHOD__ . ".getAllColumns";
1059  $sql = "SELECT string_agg(column_name, ',') AS columns
1060  FROM information_schema.columns
1061  WHERE table_name = 'report_info'
1062  AND column_name != 'ri_pk'
1063  AND column_name != 'upload_fk';";
1064  $row = $this->dbManager->getSingleRow($sql, [], $stmt);
1065  $columns = $row['columns'];
1066 
1067  $stmt = __METHOD__."CopyinsertReportConfReuse";
1068  $this->dbManager->prepare($stmt,
1069  "INSERT INTO report_info(upload_fk, $columns)
1070  SELECT $1, $columns
1071  FROM report_info WHERE upload_fk = $2"
1072  );
1073  $this->dbManager->freeResult($this->dbManager->execute(
1074  $stmt, array($uploadId, $reusedUploadId)
1075  ));
1076 
1077  $this->dbManager->commit();
1078  return true;
1079  }
1080 }
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
getUploadtreeIdFromPfile($uploadFk, $pfileFk)
Definition: UploadDao.php:112
getParentItemBounds($uploadId, $uploadTreeTableName=null)
Definition: UploadDao.php:202
getReusedUpload($uploadId, $groupId)
Definition: UploadDao.php:585
createItem($uploadEntry, $uploadTreeTableName)
Definition: UploadDao.php:602
addReusedUpload($uploadId, $reusedUploadId, $groupId, $reusedGroupId, $reuseMode=0)
Definition: UploadDao.php:573
countNonArtifactDescendants(ItemTreeBounds $itemTreeBounds, $isFlat=true)
Definition: UploadDao.php:635
getClearingDuration(int $uploadId)
Definition: UploadDao.php:348
createItemTreeBounds($uploadEntryData, $uploadTreeTableName)
Definition: UploadDao.php:622
getUploadHashesFromPfileId($pfilePk)
Get Pfile hashes from the pfile id.
Definition: UploadDao.php:1028
getCyclonedxSettings($uploadId)
Get cyclone dx settings for a user.
Definition: UploadDao.php:914
getPFileDataPerFileName(ItemTreeBounds $itemTreeBounds)
Definition: UploadDao.php:731
getContainingFileCount(ItemTreeBounds $itemTreeBounds, UploadTreeProxy $uploadTreeView)
Definition: UploadDao.php:531
getFatItemId($itemId, $uploadId, $uploadtreeTablename)
Definition: UploadDao.php:721
getItemTreeBoundsFromUploadId($uploadTreeId, $uploadId)
Definition: UploadDao.php:190
getAssigneeDate(int $uploadId)
Definition: UploadDao.php:314
getPFilesDataPerHashAlgo(ItemTreeBounds $itemTreeBounds, $hashAlgo="sha1")
Definition: UploadDao.php:810
getItemByDirection($uploadId, $itemId, $direction, $options)
Definition: UploadDao.php:464
getClearingDurationsBatch(array $uploadIds)
Definition: UploadDao.php:359
getFatItemArray($itemId, $uploadId, $uploadtreeTablename)
Definition: UploadDao.php:698
countPlainFiles(ItemTreeBounds $itemTreeBounds)
Definition: UploadDao.php:225
getNextItem($uploadId, $itemId, $options=null)
Definition: UploadDao.php:436
getClosedDate(int $uploadId)
Definition: UploadDao.php:331
updateReportInfo($uploadId, $column, $value)
Update report info for upload.
Definition: UploadDao.php:955
getPreviousItem($uploadId, $itemId, $options=null)
Definition: UploadDao.php:447
getItemTreeBounds($itemId, $uploadTreeTableName="uploadtree")
Definition: UploadDao.php:179
getUploadtreeTableName($uploadId)
Get the uploadtree table name for this upload_pk If upload_pk does not exist, return "uploadtree".
Definition: UploadDao.php:415
getAssignee($uploadId, $groupId)
Get the upload assignee id.
Definition: UploadDao.php:293
getUploadEntry($uploadTreeId, $uploadTreeTableName="uploadtree")
Definition: UploadDao.php:95
insertReportConfReuse($uploadId, $reusedUploadId)
Definition: UploadDao.php:1042
getUserSPDXDefaultsForUpload($uploadId)
Definition: UploadDao.php:875
getStatus($uploadId, $groupId)
Get the upload status.
Definition: UploadDao.php:270
This class contains the events for the upload_events table.
Fossology exception.
Definition: Exception.php:15
asCTE()
Common Table Expressions.
Definition: DbViewProxy.php:69
HumanDuration(DateInterval $duration)
Convert DateInterval to Human readable format.
Definition: common-ui.php:120
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16