FOSSology  4.4.0
Open Source License Compliance by Open Source Software
ClearingDao.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2018, 2020-2022 Siemens AG
4  Author: Johannes Najjar
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 namespace Fossology\Lib\Dao;
10 
24 use Monolog\Logger;
25 
27 {
29  private $dbManager;
31  private $logger;
33  private $uploadDao;
35  private $copyrightDao;
37  private $licenseRefCache;
38 
43  function __construct(DbManager $dbManager, UploadDao $uploadDao)
44  {
45  $this->dbManager = $dbManager;
46  $this->logger = new Logger(self::class);
47  $this->uploadDao = $uploadDao;
48  $this->licenseRefCache = array();
49  global $container;
50  $this->copyrightDao = $container->get('dao.copyright');
51  }
52 
53  private function getRelevantDecisionsCte(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent, &$statementName, &$params, $condition="")
54  {
55  $uploadTreeTable = $itemTreeBounds->getUploadTreeTableName();
56  $uploadId = $itemTreeBounds->getUploadId();
57 
58  $params[] = DecisionTypes::WIP; $p1 = "$". count($params);
59  $params[] = $groupId; $p2 = "$". count($params);
60 
61  $sql_upload = "";
62  if ('uploadtree' === $uploadTreeTable || 'uploadtree_a' === $uploadTreeTable) {
63  $params[] = $uploadId; $p = "$". count($params);
64  $sql_upload = " AND ut.upload_fk=$p";
65  }
66  if (!empty($condition)) {
67  $statementName .= ".(".$condition.")";
68  $condition = " AND $condition";
69  }
70 
71  $filterClause = $onlyCurrent ? "DISTINCT ON(itemid)" : "";
72  $sortClause = $onlyCurrent ? "ORDER BY itemid, scope, id DESC" : "";
73 
74  $statementName .= "." . $uploadTreeTable . ($onlyCurrent ? ".current": "");
75 
76  $globalScope = DecisionScopes::REPO;
77  $localScope = DecisionScopes::ITEM;
78 
79  $applyGlobal = $this->uploadDao->getGlobalDecisionSettingsFromInfo($uploadId);
80  if (!empty($applyGlobal)) {
81  $applyGlobal = "(ut.pfile_fk = cd.pfile_fk AND cd.scope = $globalScope) OR
82  (ut.uploadtree_pk = cd.uploadtree_fk
83  AND cd.scope = $localScope AND cd.group_fk = $p2)";
84  $statementName .= "WithGlobal";
85  } else {
86  $applyGlobal = "(ut.uploadtree_pk = cd.uploadtree_fk
87  AND cd.group_fk = $p2)";
88  $statementName .= "WithoutGlobal";
89  }
90 
91  return "WITH decision AS (
92  SELECT
93  $filterClause
94  cd.clearing_decision_pk AS id,
95  cd.pfile_fk AS pfile_id,
96  ut.uploadtree_pk AS itemid,
97  cd.user_fk AS user_id,
98  cd.decision_type AS type_id,
99  cd.scope AS scope,
100  EXTRACT(EPOCH FROM cd.date_added) AS ts_added
101  FROM clearing_decision cd
102  INNER JOIN $uploadTreeTable ut
103  ON ( $applyGlobal )
104  $sql_upload $condition
105  WHERE cd.decision_type != $p1
106  $sortClause
107  )";
108  }
109 
115  function getClearedLicenses(ItemTreeBounds $itemTreeBounds, $groupId)
116  {
117  $statementName = __METHOD__;
118 
119  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
120  $condition = "ut.lft BETWEEN $1 AND $2";
121 
122  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent=true, $statementName, $params, $condition);
123  $params[] = DecisionTypes::IRRELEVANT;
124  $sql = "$decisionsCte
125  SELECT
126  lr.rf_pk AS license_id,
127  lr.rf_shortname AS shortname,
128  lr.rf_spdx_id AS spdx_id,
129  lr.rf_fullname AS fullname
130  FROM decision
131  INNER JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
132  INNER JOIN clearing_event ce ON
133  (ce.clearing_event_pk = cde.clearing_event_fk AND NOT ce.removed)
134  INNER JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
135  WHERE type_id != $".count($params)."
136  GROUP BY license_id,shortname,fullname,spdx_id";
137 
138  $this->dbManager->prepare($statementName, $sql);
139 
140  $res = $this->dbManager->execute($statementName, $params);
141 
142  $licenses = array();
143  while ($row = $this->dbManager->fetchArray($res)) {
144  $licenses[] = new LicenseRef($row['license_id'], $row['shortname'], $row['fullname'], $row['spdx_id']);
145  }
146  $this->dbManager->freeResult($res);
147 
148  return $licenses;
149  }
150 
151 
159  function getFileClearings(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $forClearingHistory=false)
160  {
161  $this->dbManager->begin();
162 
163  $statementName = __METHOD__;
164 
165  $params = array($itemTreeBounds->getItemId());
166  $condition = "ut.uploadtree_pk = $1";
167 
168  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent, $statementName, $params, $condition);
169 
170  $clearingsWithLicensesArray = $this->getDecisionsFromCte($decisionsCte, $statementName, $params, $forClearingHistory);
171 
172  $this->dbManager->commit();
173  return $clearingsWithLicensesArray;
174  }
175 
183  function getFileClearingsFolder(ItemTreeBounds $itemTreeBounds, $groupId, $includeSubFolders=true, $onlyCurrent=true)
184  {
185  $this->dbManager->begin();
186 
187  $statementName = __METHOD__;
188 
189  if (!$includeSubFolders) {
190  $params = array($itemTreeBounds->getItemId());
191  $condition = "ut.realparent = $1";
192  } else {
193  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
194  $condition = "ut.lft BETWEEN $1 AND $2";
195  }
196 
197  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent, $statementName, $params, $condition);
198 
199  $clearingsWithLicensesArray = $this->getDecisionsFromCte($decisionsCte, $statementName, $params);
200 
201  $this->dbManager->commit();
202  return $clearingsWithLicensesArray;
203  }
204 
211  private function getDecisionsFromCte($decisionsCte, $statementName, $params, $forClearingHistory=false)
212  {
213  $sql = "$decisionsCte
214  SELECT
215  decision.*,
216  users.user_name AS user_name,
217  ce.clearing_event_pk as event_id,
218  ce.user_fk as event_user_id,
219  ce.group_fk as event_group_id,
220  lr.rf_pk AS license_id,
221  lr.rf_spdx_id AS spdx_id,
222  lr.rf_shortname AS shortname,
223  lr.rf_fullname AS fullname,
224  ce.removed AS removed,
225  ce.type_fk AS event_type_id,
226  ce.reportinfo AS reportinfo,
227  ce.comment AS comment,
228  ce.acknowledgement AS acknowledgement
229  FROM decision
230  LEFT JOIN users ON decision.user_id = users.user_pk
231  LEFT JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
232  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
233  LEFT JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
234  ORDER BY decision.id DESC, event_id ASC";
235 
236  $this->dbManager->prepare($statementName, $sql);
237 
238  $result = $this->dbManager->execute($statementName, $params);
239  $clearingsWithLicensesArray = array();
240 
241  $previousClearingId = -1;
242  $previousItemId = -1;
243  $clearingEvents = array();
244  $clearingEventCache = array();
245  $clearingDecisionBuilder = ClearingDecisionBuilder::create();
246  $firstMatch = true;
247  while ($row = $this->dbManager->fetchArray($result)) {
248  $clearingId = $row['id'];
249  $itemId = $row['itemid'];
250  $licenseId = $row['license_id'];
251  $eventId = $row['event_id'];
252  $licenseSpdxId = $row['spdx_id'];
253  $licenseShortName = $row['shortname'];
254  $licenseName = $row['fullname'];
255  $licenseIsRemoved = $row['removed'];
256 
257  $eventType = $row['event_type_id'];
258  $eventUserId = $row['event_user_id'];
259  $eventGroupId = $row['event_group_id'];
260  $comment = $row['comment'];
261  $reportInfo = $row['reportinfo'];
262  $acknowledgement = $row['acknowledgement'];
263 
264  if ($clearingId !== $previousClearingId && $itemId !== $previousItemId) {
265  //store the old one
266  if (!$firstMatch) {
267  $clearingsWithLicensesArray[] = $clearingDecisionBuilder->setClearingEvents($clearingEvents)->build();
268  }
269 
270  $firstMatch = false;
271  //prepare the new one
272  if ($forClearingHistory) {
273  $previousClearingId = $clearingId;
274  } else {
275  $previousItemId = $itemId;
276  }
277  $clearingEvents = array();
278  $clearingDecisionBuilder = ClearingDecisionBuilder::create()
279  ->setClearingId($row['id'])
280  ->setUploadTreeId($itemId)
281  ->setPfileId($row['pfile_id'])
282  ->setUserName($row['user_name'])
283  ->setUserId($row['user_id'])
284  ->setType(intval($row['type_id']))
285  ->setScope(intval($row['scope']))
286  ->setTimeStamp($row['ts_added']);
287  }
288 
289  if ($licenseId !== null) {
290  if (!array_key_exists($eventId, $clearingEventCache)) {
291  if (!array_key_exists($licenseId, $this->licenseRefCache)) {
292  $this->licenseRefCache[$licenseId] = new LicenseRef($licenseId, $licenseShortName, $licenseName, $licenseSpdxId);
293  }
294  $licenseRef = $this->licenseRefCache[$licenseId];
295  $clearingEventCache[$eventId] = $this->buildClearingEvent($eventId, $eventUserId, $eventGroupId, $licenseRef, $licenseIsRemoved, $eventType, $reportInfo, $comment, $acknowledgement);
296  }
297  $clearingEvents[] = $clearingEventCache[$eventId];
298  }
299  }
300 
302  if (!$firstMatch) {
303  $clearingsWithLicensesArray[] = $clearingDecisionBuilder->setClearingEvents($clearingEvents)->build();
304  }
305  $this->dbManager->freeResult($result);
306 
307  return $clearingsWithLicensesArray;
308  }
314  public function getRelevantClearingDecision(ItemTreeBounds $itemTreeBounds, $groupId)
315  {
316  $clearingDecisions = $this->getFileClearings($itemTreeBounds, $groupId);
317  if (count($clearingDecisions) > 0) {
318  return $clearingDecisions[0];
319  }
320  return null;
321  }
322 
327  public function removeWipClearingDecision($uploadTreeId, $groupId)
328  {
329  $sql = "DELETE FROM clearing_decision WHERE uploadtree_fk=$1 AND group_fk=$2 AND decision_type=$3";
330  $this->dbManager->prepare($stmt = __METHOD__, $sql);
331  $this->dbManager->freeResult($this->dbManager->execute($stmt, array($uploadTreeId, $groupId, DecisionTypes::WIP)));
332  }
333 
341  public function createDecisionFromEvents($uploadTreeId, $userId, $groupId, $decType, $scope, $eventIds)
342  {
343  if ( ($scope == DecisionScopes::REPO) &&
344  !empty($this->getCandidateLicenseCountForCurrentDecisions($uploadTreeId))) {
345  throw new \Exception( _("Cannot add candidate license as global decision\n") );
346  }
347 
348  $itemTreeBounds = $this->uploadDao->getItemTreeBounds($uploadTreeId);
349  $uploadId = $itemTreeBounds->getUploadId();
350  $uploadTreeTable = $this->uploadDao->getUploadtreeTableName($uploadId);
351  $itemTreeBounds = $this->uploadDao->getItemTreeBounds($uploadTreeId, $uploadTreeTable);
352 
353  if ($this->isDecisionCheck($uploadTreeId, $groupId, DecisionTypes::IRRELEVANT)) {
354  $this->copyrightDao->updateTable($itemTreeBounds, '', '', $userId, 'copyright', 'rollback');
355  } else if ($decType == DecisionTypes::IRRELEVANT) {
356  $this->copyrightDao->updateTable($itemTreeBounds, '', '', $userId, 'copyright', 'delete', '2');
357  }
358 
359  $this->dbManager->begin();
360 
361  $this->removeWipClearingDecision($uploadTreeId, $groupId);
362 
363  $statementName = __METHOD__;
364  $this->dbManager->prepare($statementName,
365  "
366 INSERT INTO clearing_decision (
367  uploadtree_fk,
368  pfile_fk,
369  user_fk,
370  group_fk,
371  decision_type,
372  scope
373 ) VALUES (
374  $1,
375  (SELECT pfile_fk FROM uploadtree WHERE uploadtree_pk=$1),
376  $2,
377  $3,
378  $4,
379  $5) RETURNING clearing_decision_pk
380  ");
381  $res = $this->dbManager->execute($statementName,
382  array($uploadTreeId, $userId, $groupId, $decType, $scope));
383  $result = $this->dbManager->fetchArray($res);
384  $clearingDecisionId = $result['clearing_decision_pk'];
385  $this->dbManager->freeResult($res);
386 
387  $statementNameClearingDecisionEventInsert = __METHOD__ . ".insertClearingDecisionEvent";
388  $this->dbManager->prepare($statementNameClearingDecisionEventInsert,
389  "INSERT INTO clearing_decision_event (clearing_decision_fk, clearing_event_fk) VALUES($1, $2)"
390  );
391 
392  foreach ($eventIds as $eventId) {
393  $this->dbManager->freeResult($this->dbManager->execute($statementNameClearingDecisionEventInsert, array($clearingDecisionId, $eventId)));
394  }
395 
396  $this->dbManager->commit();
397  }
398 
404  public function getRelevantClearingEvents($itemTreeBounds, $groupId, $includeSubFolders=true)
405  {
406  $decision = $this->getFileClearingsFolder($itemTreeBounds, $groupId, $includeSubFolders, $onlyCurrent=true);
407  $events = array();
408  $date = 0;
409 
410  if (count($decision)) {
411  foreach ($decision[0]->getClearingEvents() as $event) {
412  $events[$event->getLicenseId()] = $event;
413  }
414  $date = $decision[0]->getTimeStamp();
415  }
416 
417  $stmt = __METHOD__;
418  $sql = 'SELECT rf_fk,rf_shortname,rf_spdx_id,rf_fullname,clearing_event_pk,comment,type_fk,removed,reportinfo,acknowledgement, EXTRACT(EPOCH FROM date_added) AS ts_added
419  FROM clearing_event LEFT JOIN license_ref ON rf_fk=rf_pk
420  WHERE uploadtree_fk=$1 AND group_fk=$2 AND date_added>to_timestamp($3)
421  ORDER BY clearing_event_pk ASC';
422  $this->dbManager->prepare($stmt, $sql);
423  $res = $this->dbManager->execute($stmt,array($itemTreeBounds->getItemId(),$groupId,$date));
424 
425  while ($row = $this->dbManager->fetchArray($res)) {
426  $licenseRef = new LicenseRef($row['rf_fk'],$row['rf_shortname'],$row['rf_fullname'],$row['rf_spdx_id']);
427  $events[$row['rf_fk']] = ClearingEventBuilder::create()
428  ->setEventId($row['clearing_event_pk'])
429  ->setComment($row['comment'])
430  ->setTimeStamp($row['ts_added'])
431  ->setEventType($row['type_fk'])
432  ->setLicenseRef($licenseRef)
433  ->setRemoved($this->dbManager->booleanFromDb($row['removed']))
434  ->setReportinfo($row['reportinfo'])
435  ->setAcknowledgement($row['acknowledgement'])
436  ->setUploadTreeId($itemTreeBounds->getItemId())
437  ->build();
438  }
439  $this->dbManager->freeResult($res);
440  return $events;
441  }
442 
451  public function updateClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $what, $changeTo)
452  {
453  $this->dbManager->begin();
454 
455  $statementGetOldata = "SELECT * FROM clearing_event WHERE uploadtree_fk=$1 AND rf_fk=$2 AND group_fk=$3 ORDER BY clearing_event_pk DESC LIMIT 1";
456  $statementName = __METHOD__ . 'getOld';
457  $params = array($uploadTreeId, $licenseId, $groupId);
458  $row = $this->dbManager->getSingleRow($statementGetOldata, $params, $statementName);
459 
460  if (!$row) { //The license was not added as user decision yet -> we promote it here
461  $type = ClearingEventTypes::USER;
462  $row['type_fk'] = $type;
463  $row['comment'] = "";
464  $row['reportinfo'] = "";
465  $row['acknowledgement'] = "";
466  }
467 
468  $changeTo = StringOperation::replaceUnicodeControlChar($changeTo, false);
469  if ($what == 'reportinfo') {
470  $reportInfo = $changeTo;
471  $comment = $row['comment'];
472  $acknowledgement = $row['acknowledgement'];
473  } elseif ($what == 'comment') {
474  $reportInfo = $row['reportinfo'];
475  $comment = $changeTo;
476  $acknowledgement = $row['acknowledgement'];
477  } else {
478  $reportInfo = $row['reportinfo'];
479  $comment = $row['comment'];
480  $acknowledgement = $changeTo;
481  }
482  $this->insertClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, false, $row['type_fk'], $reportInfo, $comment, $acknowledgement);
483 
484  $this->dbManager->commit();
485 
486  }
487 
488  public function copyEventIdTo($eventId, $itemId, $userId, $groupId)
489  {
490  $stmt = __METHOD__;
491  $this->dbManager->prepare($stmt,
492  "INSERT INTO clearing_event(uploadtree_fk, user_fk, group_fk, type_fk, rf_fk, removed, reportinfo, comment, acknowledgement)
493  SELECT $2, $3, $4, type_fk, rf_fk, removed, reportinfo, comment, acknowledgement FROM clearing_event WHERE clearing_event_pk = $1"
494  );
495 
496  $this->dbManager->freeResult($this->dbManager->execute($stmt, array($eventId, $itemId, $userId, $groupId)));
497  }
498 
511  public function insertClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $isRemoved, $type = ClearingEventTypes::USER, $reportInfo = '', $comment = '', $acknowledgement = '', $jobId=0)
512  {
513  $insertIsRemoved = $this->dbManager->booleanToDb($isRemoved);
514 
515  $reportInfo = StringOperation::replaceUnicodeControlChar($reportInfo);
516  $comment = StringOperation::replaceUnicodeControlChar($comment);
517  $acknowledgement = StringOperation::replaceUnicodeControlChar($acknowledgement);
518 
519  $stmt = __METHOD__;
520  $params = array($uploadTreeId, $userId, $groupId, $type, $licenseId, $insertIsRemoved, $reportInfo, $comment, $acknowledgement);
521  $columns = "uploadtree_fk, user_fk, group_fk, type_fk, rf_fk, removed, reportinfo, comment, acknowledgement";
522  $values = "$1,$2,$3,$4,$5,$6,$7,$8,$9";
523 
524  if ($jobId > 0) {
525  $stmt.= ".jobId";
526  $params[] = $jobId;
527  $columns .= ", job_fk";
528  $values .= ",$".count($params);
529  } else {
530  $this->markDecisionAsWip($uploadTreeId, $userId, $groupId);
531  }
532 
533  $this->dbManager->prepare($stmt, "INSERT INTO clearing_event ($columns) VALUES($values) RETURNING clearing_event_pk");
534  $res = $this->dbManager->execute($stmt, $params);
535 
536  $row = $this->dbManager->fetchArray($res);
537  $this->dbManager->freeResult($res);
538 
539  return intval($row['clearing_event_pk']);
540  }
541 
546  public function getEventIdsOfJob($jobId)
547  {
548  $statementName = __METHOD__;
549  $this->dbManager->prepare(
550  $statementName,
551  "SELECT uploadtree_fk, clearing_event_pk, rf_fk FROM clearing_event WHERE job_fk = $1"
552  );
553 
554  $res = $this->dbManager->execute($statementName, array($jobId));
555 
556  $events = array();
557  while ($row = $this->dbManager->fetchArray($res)) {
558  $itemId = intval($row['uploadtree_fk']);
559  $eventId = intval($row['clearing_event_pk']);
560  $licenseId = intval($row['rf_fk']);
561 
562  $events[$itemId][$licenseId] = $eventId;
563  }
564  $this->dbManager->freeResult($res);
565 
566  return $events;
567  }
568 
581  protected function buildClearingEvent($eventId, $userId, $groupId, $licenseRef, $licenseIsRemoved, $type, $reportInfo, $comment, $acknowledgement)
582  {
583  $removed = $this->dbManager->booleanFromDb($licenseIsRemoved);
584 
585  return ClearingEventBuilder::create()
586  ->setEventId($eventId)
587  ->setUserId($userId)
588  ->setGroupId($groupId)
589  ->setEventType($type)
590  ->setLicenseRef($licenseRef)
591  ->setRemoved($removed)
592  ->setReportInfo($reportInfo)
593  ->setAcknowledgement($acknowledgement)
594  ->setComment($comment)
595  ->build();
596  }
597 
603  public function markDecisionAsWip($uploadTreeId, $userId, $groupId)
604  {
605  $statementName = __METHOD__;
606 
607  $this->dbManager->prepare($statementName,
608  "INSERT INTO clearing_decision (uploadtree_fk,pfile_fk,user_fk,group_fk,decision_type,scope) VALUES (
609  $1, (SELECT pfile_fk FROM uploadtree WHERE uploadtree_pk=$1), $2, $3, $4, $5)");
610  $res = $this->dbManager->execute($statementName,
611  array($uploadTreeId, $userId, $groupId, DecisionTypes::WIP, DecisionScopes::ITEM));
612  $this->dbManager->freeResult($res);
613  }
614 
620  public function isDecisionCheck($uploadTreeId, $groupId, $decisionType)
621  {
622  $columns = "decision_type";
623  if (!in_array($decisionType,
624  [DecisionTypes::WIP, DecisionTypes::TO_BE_DISCUSSED,
625  DecisionTypes::DO_NOT_USE, DecisionTypes::IRRELEVANT,
626  DecisionTypes::NON_FUNCTIONAL])
627  ) {
628  $columns = "decision_type, scope";
629  }
630  $sql = "SELECT $columns FROM clearing_decision
631  WHERE uploadtree_fk=$1 AND group_fk = $2
632  ORDER BY clearing_decision_pk DESC LIMIT 1";
633  $latestDec = $this->dbManager->getSingleRow($sql,
634  array($uploadTreeId, $groupId), $sqlLog = __METHOD__);
635 
636  if ($latestDec === false) {
637  return false;
638  } else if ($decisionType !== "") {
639  return ($latestDec['decision_type'] == $decisionType);
640  } else {
641  return $latestDec;
642  }
643  }
644 
651  public function getBulkHistory(ItemTreeBounds $itemTreeBound, $groupId, $onlyTried = true)
652  {
653  $uploadTreeTableName = $itemTreeBound->getUploadTreeTableName();
654  $itemId = $itemTreeBound->getItemId();
655  $uploadId = $itemTreeBound->getUploadId();
656  $left = $itemTreeBound->getLeft();
657 
658  $params = array($uploadId, $itemId, $left, $groupId);
659  $stmt = __METHOD__ . "." . $uploadTreeTableName;
660 
661  $triedExpr = "$3 between ut2.lft and ut2.rgt";
662  $triedFilter = "";
663  if ($onlyTried) {
664  $triedFilter = "and " . $triedExpr;
665  $stmt .= ".tried";
666  }
667 
668  $sql = "WITH alltried AS (
669  SELECT lr.lrb_pk, ce.clearing_event_pk ce_pk, lr.rf_text, ce.uploadtree_fk,
670  $triedExpr AS tried
671  FROM license_ref_bulk lr
672  LEFT JOIN highlight_bulk h ON lrb_fk = lrb_pk
673  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = h.clearing_event_fk
674  LEFT JOIN $uploadTreeTableName ut ON ut.uploadtree_pk = ce.uploadtree_fk
675  INNER JOIN $uploadTreeTableName ut2 ON ut2.uploadtree_pk = lr.uploadtree_fk
676  WHERE ut2.upload_fk = $1 AND lr.group_fk = $4
677  $triedFilter
678  ORDER BY lr.lrb_pk
679  ), aggregated_tried AS (
680  SELECT DISTINCT ON(lrb_pk) lrb_pk, ce_pk, rf_text AS text, tried, matched
681  FROM (
682  SELECT DISTINCT ON(lrb_pk) lrb_pk, ce_pk, rf_text, tried, true AS matched FROM alltried WHERE uploadtree_fk = $2
683  UNION ALL
684  SELECT DISTINCT ON(lrb_pk) lrb_pk, ce_pk, rf_text, tried, false AS matched FROM alltried WHERE uploadtree_fk != $2 OR uploadtree_fk IS NULL
685  ) AS result ORDER BY lrb_pk, matched DESC)
686  SELECT lrb_pk, text, rf_shortname, removing, tried, ce_pk, matched
687  FROM aggregated_tried
688  INNER JOIN license_set_bulk lsb ON lsb.lrb_fk = lrb_pk
689  INNER JOIN license_ref lrf ON lsb.rf_fk = lrf.rf_pk
690  ORDER BY lrb_pk";
691 
692  $this->dbManager->prepare($stmt, $sql);
693  $res = $this->dbManager->execute($stmt, $params);
694 
695  $bulks = array();
696  while ($row = $this->dbManager->fetchArray($res)) {
697  $bulkRun = $row['lrb_pk'];
698  if (!array_key_exists($bulkRun, $bulks)) {
699  $bulks[$bulkRun] = array(
700  "bulkId" => $row['lrb_pk'],
701  "id" => $row['ce_pk'],
702  "text" => $row['text'],
703  "matched" => $this->dbManager->booleanFromDb($row['matched']),
704  "tried" => $this->dbManager->booleanFromDb($row['tried']),
705  "removedLicenses" => array(),
706  "addedLicenses" => array());
707  }
708  $key = $this->dbManager->booleanFromDb($row['removing']) ? 'removedLicenses' : 'addedLicenses';
709  $bulks[$bulkRun][$key][] = $row['rf_shortname'];
710  }
711 
712  $this->dbManager->freeResult($res);
713  return $bulks;
714  }
715 
716 
717  public function getBulkMatches($bulkId, $groupId)
718  {
719  $stmt = __METHOD__;
720  $sql = "SELECT uploadtree_fk AS itemid
721  FROM clearing_event ce
722  INNER JOIN highlight_bulk h
723  ON ce.clearing_event_pk = h.clearing_event_fk
724  WHERE lrb_fk = $1 AND group_fk = $2";
725 
726  $this->dbManager->prepare($stmt, $sql);
727  $res = $this->dbManager->execute($stmt, array($bulkId, $groupId));
728 
729  $result = $this->dbManager->fetchAll($res);
730  $this->dbManager->freeResult($res);
731  return $result;
732  }
733 
739  function getClearedLicenseIdAndMultiplicities(ItemTreeBounds $itemTreeBounds, $groupId)
740  {
741  $statementName = __METHOD__;
742 
743  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
744  $condition = "ut.lft BETWEEN $1 AND $2";
745 
746  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent=true, $statementName, $params, $condition);
747  $params[] = DecisionTypes::IRRELEVANT;
748  $sql = "$decisionsCte
749  SELECT
750  COUNT(DISTINCT itemid) AS count,
751  lr.rf_shortname AS shortname,
752  lr.rf_spdx_id AS spdx_id,
753  rf_pk
754  FROM decision
755  LEFT JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
756  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
757  LEFT JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
758  WHERE (NOT ce.removed OR clearing_event_pk IS NULL) AND type_id!=$".count($params)."
759  GROUP BY shortname,rf_pk,spdx_id";
760 
761  $this->dbManager->prepare($statementName, $sql);
762  $res = $this->dbManager->execute($statementName, $params);
763  $multiplicity = array();
764  while ($row = $this->dbManager->fetchArray($res)) {
765  $shortname = empty($row['rf_pk']) ? LicenseDao::NO_LICENSE_FOUND : $row['shortname'];
766  $row['spdx_id'] = LicenseRef::convertToSpdxId($shortname, $row['spdx_id']);
767  $multiplicity[$shortname] = $row;
768  }
769  $this->dbManager->freeResult($res);
770 
771  return $multiplicity;
772  }
773 
778  public function getDecisionType($decisionType)
779  {
780  if ($decisionType == "doNotUse" || $decisionType == "deleteDoNotUse") {
781  return DecisionTypes::DO_NOT_USE;
782  } else if ($decisionType == "irrelevant" || $decisionType == "deleteIrrelevant") {
783  return DecisionTypes::IRRELEVANT;
784  } else {
785  return DecisionTypes::NON_FUNCTIONAL;
786  }
787  }
788 
795  public function markDirectoryAsDecisionType(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
796  {
797  $decisionMark = $this->getDecisionType($decisionMark);
798  $this->markDirectoryAsDecisionTypeRec($itemTreeBounds, $groupId, $userId, false, $decisionMark);
799  }
800 
807  public function deleteDecisionTypeFromDirectory(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
808  {
809  $decisionMark = $this->getDecisionType($decisionMark);
810  $this->markDirectoryAsDecisionTypeRec($itemTreeBounds, $groupId, $userId, true, $decisionMark);
811  }
812 
820  protected function markDirectoryAsDecisionTypeRec(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $removeDecision=false, $decisionMark=DecisionTypes::IRRELEVANT)
821  {
822  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
823  $params[] = $groupId;
824  $a = count($params);
825  $options = array(UploadTreeProxy::OPT_SKIP_THESE=>'noLicense',
826  UploadTreeProxy::OPT_ITEM_FILTER=>' AND (lft BETWEEN $1 AND $2)',
827  UploadTreeProxy::OPT_GROUP_ID=>'$'.$a);
828  $uploadTreeProxy = new UploadTreeProxy($itemTreeBounds->getUploadId(), $options, $itemTreeBounds->getUploadTreeTableName());
829  if (!$removeDecision) {
830  $sql = $uploadTreeProxy->asCTE() .
831  ' SELECT uploadtree_pk FROM UploadTreeView;';
832  $itemRows = $this->dbManager->getRows($sql, $params,
833  __METHOD__ . ".getRevelantItems");
834  $uploadTreeTableName = $itemTreeBounds->getUploadTreeTableName();
836  $clearingDecisionEventProcessor = $GLOBALS['container']->get(
837  'businessrules.clearing_decision_processor');
838  foreach ($itemRows as $itemRow) {
839  $itemBounds = $this->uploadDao->getItemTreeBounds(
840  $itemRow['uploadtree_pk'], $uploadTreeTableName);
841  $clearingDecisionEventProcessor->makeDecisionFromLastEvents(
842  $itemBounds, $userId, $groupId, $decisionMark, DecisionScopes::ITEM);
843  }
844  } else {
845  $this->dbManager->begin();
846  $params[] = $decisionMark;
847  $sql = $uploadTreeProxy->asCTE() .
848  ' DELETE FROM clearing_decision WHERE clearing_decision_pk IN (
849  SELECT clearing_decision_pk FROM clearing_decision cd
850  INNER JOIN (
851  SELECT MAX(date_added) AS date_added, uploadtree_fk
852  FROM clearing_decision WHERE uploadtree_fk IN (
853  SELECT uploadtree_pk FROM UploadTreeView)
854  GROUP BY uploadtree_fk) cd2
855  ON cd.uploadtree_fk = cd2.uploadtree_fk
856  AND cd.date_added = cd2.date_added
857  AND decision_type = $' . ($a + 1) . ')
858  RETURNING clearing_decision_pk;';
859  $clearingDecisionRows = $this->dbManager->getRows($sql, $params,
860  __METHOD__ . ".getRelevantDecisions");
861  $clearingDecisions = array_map(function($x) {
862  return $x['clearing_decision_pk'];
863  }, $clearingDecisionRows);
864  $clearingDecisions = "{" . join(",", $clearingDecisions) . "}";
865 
866  $delEventSql = "DELETE FROM clearing_event WHERE clearing_event_pk IN (" .
867  "SELECT clearing_event_fk FROM clearing_decision_event " .
868  "WHERE clearing_decision_fk = ANY($1::int[]));";
869  $this->dbManager->getSingleRow($delEventSql, array($clearingDecisions),
870  __METHOD__ . ".deleteEvent");
871 
872  $delCdEventSql = "DELETE FROM clearing_decision_event WHERE " .
873  "clearing_decision_fk = ANY($1::int[]);";
874  $this->dbManager->getSingleRow($delCdEventSql, array($clearingDecisions),
875  __METHOD__ . ".deleteCdEvent");
876  $this->dbManager->commit();
877  $this->copyrightDao->updateTable($itemTreeBounds, '', '', $userId,
878  'copyright', 'rollback');
879  }
880  }
881 
887  public function getMainLicenseIds($uploadId, $groupId)
888  {
889  $stmt = __METHOD__;
890  $sql = "SELECT rf_fk FROM upload_clearing_license WHERE upload_fk=$1 AND group_fk=$2";
891  $this->dbManager->prepare($stmt, $sql);
892  $res = $this->dbManager->execute($stmt,array($uploadId,$groupId));
893  $ids = array();
894  while ($row = $this->dbManager->fetchArray($res)) {
895  $ids[$row['rf_fk']] = $row['rf_fk'];
896  }
897  $this->dbManager->freeResult($res);
898  return $ids;
899  }
900 
906  public function makeMainLicense($uploadId, $groupId, $licenseId)
907  {
908  $this->dbManager->insertTableRow('upload_clearing_license',
909  array('upload_fk'=>$uploadId,'group_fk'=>$groupId,'rf_fk'=>$licenseId));
910  }
911 
917  public function removeMainLicense($uploadId, $groupId, $licenseId)
918  {
919  $this->dbManager->getSingleRow('DELETE FROM upload_clearing_license WHERE upload_fk=$1 AND group_fk=$2 AND rf_fk=$3',
920  array($uploadId,$groupId,$licenseId));
921  }
922 
930  function getFilesForDecisionTypeFolderLevel(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $decisionMark="")
931  {
932  $decisionMark = $this->getDecisionType($decisionMark);
933  $statementName = __METHOD__;
934  $params = array();
935  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent, $statementName, $params);
936  $params[] = $decisionMark;
937  $sql = "$decisionsCte
938  SELECT
939  itemid as uploadtree_pk,
940  lr.rf_shortname AS shortname,
941  lr.rf_spdx_id AS spdx_id,
942  comment
943  FROM decision
944  LEFT JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
945  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
946  LEFT JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
947  WHERE type_id=$".count($params);
948  $this->dbManager->prepare($statementName, $sql);
949  $res = $this->dbManager->execute($statementName, $params);
950  $irrelevantFiles = $this->dbManager->fetchAll($res);
951  $this->dbManager->freeResult($res);
952  return $irrelevantFiles;
953  }
954 
960  public function getPreviousBulkIds($uploadId, $groupId, $userId, $onlyCount=0)
961  {
962  $stmt = __METHOD__;
963  $bulkIds = array();
964  $sql = "SELECT jq_args FROM upload_reuse, jobqueue, job
965  WHERE upload_fk=$1 AND group_fk=$2
966  AND EXISTS(SELECT * FROM group_user_member gum WHERE gum.group_fk=upload_reuse.group_fk AND gum.user_fk=$3)
967  AND jq_type=$4 AND jq_job_fk=job_pk
968  AND job_upload_fk=reused_upload_fk AND job_group_fk=reused_group_fk";
969  $this->dbManager->prepare($stmt, $sql);
970  $res = $this->dbManager->execute($stmt,array($uploadId, $groupId, $userId,'monkbulk'));
971  while ($row= $this->dbManager->fetchArray($res)) {
972  $bulkIds = array_merge($bulkIds,explode("\n", $row['jq_args']));
973  }
974  $this->dbManager->freeResult($res);
975  if (empty($onlyCount)) {
976  return array_unique($bulkIds);
977  } else {
978  return count(array_unique($bulkIds));
979  }
980  }
981 
986  public function getCandidateLicenseCountForCurrentDecisions($uploadTreeId, $uploadId=0)
987  {
988  $params = array();
989  if (!empty($uploadId)) {
990  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
991  $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId, $uploadTreeTableName);
992  $params[] = $itemTreeBounds->getLeft();
993  $params[] = $itemTreeBounds->getRight();
994  $condition = "UT.lft BETWEEN $1 AND $2";
995  $uploadtreeStatement = " uploadtree_fk IN (SELECT uploadtree_pk FROM $uploadTreeTableName UT WHERE $condition)";
996  } else {
997  $params = array($uploadTreeId);
998  $uploadtreeStatement = " uploadtree_fk = $1";
999  }
1000 
1001  $sql = "WITH latestEvents AS (
1002  SELECT rf_fk, date_added, removed FROM (
1003  SELECT rf_fk, date_added, removed, row_number()
1004  OVER (PARTITION BY rf_fk ORDER BY date_added DESC) AS ROWNUM
1005  FROM clearing_event WHERE $uploadtreeStatement) SORTABLE
1006  WHERE ROWNUM = 1 ORDER BY rf_fk)
1007  SELECT count(*) FROM license_candidate WHERE license_candidate.rf_pk IN
1008  (SELECT rf_fk FROM latestEvents WHERE removed=false);";
1009  $countCandidate = $this->dbManager->getSingleRow($sql,
1010  $params, $sqlLog = __METHOD__);
1011 
1012  return $countCandidate['count'];
1013  }
1014 
1019  public function marklocalDecisionsAsGlobal($uploadId)
1020  {
1021  $statementName = __METHOD__ . $uploadId;
1022 
1023  $sql = "WITH latestDecisions AS (
1024  SELECT clearing_decision_pk FROM (
1025  SELECT clearing_decision_pk, uploadtree_fk, date_added, row_number()
1026  OVER (PARTITION BY uploadtree_fk ORDER BY date_added DESC) AS ROWNUM
1027  FROM clearing_decision WHERE uploadtree_fk IN
1028  (SELECT uploadtree_pk FROM uploadtree WHERE upload_fk = $1)) SORTABLE
1029  WHERE ROWNUM = $2 ORDER BY uploadtree_fk)
1030  UPDATE clearing_decision SET scope = $2 WHERE clearing_decision_pk IN (
1031  SELECT clearing_decision_pk FROM latestDecisions) RETURNING clearing_decision_pk";
1032 
1033  $countUpdated = $this->dbManager->getSingleRow($sql,
1034  array($uploadId, DecisionScopes::REPO), $statementName);
1035 
1036  return count($countUpdated);
1037  }
1038 }
Utility functions to process ClearingDecision.
buildClearingEvent($eventId, $userId, $groupId, $licenseRef, $licenseIsRemoved, $type, $reportInfo, $comment, $acknowledgement)
getFileClearings(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $forClearingHistory=false)
deleteDecisionTypeFromDirectory(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
updateClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $what, $changeTo)
markDirectoryAsDecisionType(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
createDecisionFromEvents($uploadTreeId, $userId, $groupId, $decType, $scope, $eventIds)
getClearedLicenses(ItemTreeBounds $itemTreeBounds, $groupId)
markDecisionAsWip($uploadTreeId, $userId, $groupId)
removeMainLicense($uploadId, $groupId, $licenseId)
getRelevantClearingDecision(ItemTreeBounds $itemTreeBounds, $groupId)
isDecisionCheck($uploadTreeId, $groupId, $decisionType)
makeMainLicense($uploadId, $groupId, $licenseId)
getRelevantClearingEvents($itemTreeBounds, $groupId, $includeSubFolders=true)
getMainLicenseIds($uploadId, $groupId)
getPreviousBulkIds($uploadId, $groupId, $userId, $onlyCount=0)
__construct(DbManager $dbManager, UploadDao $uploadDao)
Definition: ClearingDao.php:43
getBulkHistory(ItemTreeBounds $itemTreeBound, $groupId, $onlyTried=true)
getFileClearingsFolder(ItemTreeBounds $itemTreeBounds, $groupId, $includeSubFolders=true, $onlyCurrent=true)
getClearedLicenseIdAndMultiplicities(ItemTreeBounds $itemTreeBounds, $groupId)
getDecisionsFromCte($decisionsCte, $statementName, $params, $forClearingHistory=false)
getCandidateLicenseCountForCurrentDecisions($uploadTreeId, $uploadId=0)
getFilesForDecisionTypeFolderLevel(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $decisionMark="")
insertClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $isRemoved, $type=ClearingEventTypes::USER, $reportInfo='', $comment='', $acknowledgement='', $jobId=0)
removeWipClearingDecision($uploadTreeId, $groupId)
static convertToSpdxId($shortname, $spdxId)
Given a license's shortname and spdx id, give out spdx id to use in reports.
Definition: LicenseRef.php:106
static replaceUnicodeControlChar($input, $replace="")
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16