FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
ClearingDao.php
1 <?php
2 /*
3 Copyright (C) 2014-2018,2020, Siemens AG
4 Author: Johannes Najjar
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 
20 namespace Fossology\Lib\Dao;
21 
34 use Monolog\Logger;
36 
38 {
40  private $dbManager;
42  private $logger;
44  private $uploadDao;
46  private $licenseRefCache;
47 
52  function __construct(DbManager $dbManager, UploadDao $uploadDao)
53  {
54  $this->dbManager = $dbManager;
55  $this->logger = new Logger(self::class);
56  $this->uploadDao = $uploadDao;
57  $this->licenseRefCache = array();
58  }
59 
60  private function getRelevantDecisionsCte(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent, &$statementName, &$params, $condition="")
61  {
62  $uploadTreeTable = $itemTreeBounds->getUploadTreeTableName();
63 
64  $params[] = DecisionTypes::WIP; $p1 = "$". count($params);
65  $params[] = $groupId; $p2 = "$". count($params);
66 
67  $sql_upload = "";
68  if ('uploadtree' === $uploadTreeTable || 'uploadtree_a' === $uploadTreeTable) {
69  $params[] = $itemTreeBounds->getUploadId(); $p = "$". count($params);
70  $sql_upload = "ut.upload_fk=$p AND ";
71  }
72  if (!empty($condition)) {
73  $statementName .= ".(".$condition.")";
74  $condition .= " AND ";
75  }
76 
77  $filterClause = $onlyCurrent ? "DISTINCT ON(itemid)" : "";
78 
79  $statementName .= "." . $uploadTreeTable . ($onlyCurrent ? ".current": "");
80 
81  $globalScope = DecisionScopes::REPO;
82  $localScope = DecisionScopes::ITEM;
83 
84  return "WITH allDecs AS (
85  SELECT
86  cd.clearing_decision_pk AS id,
87  cd.pfile_fk AS pfile_id,
88  ut.uploadtree_pk AS itemid,
89  cd.user_fk AS user_id,
90  cd.decision_type AS type_id,
91  cd.scope AS scope,
92  EXTRACT(EPOCH FROM cd.date_added) AS ts_added,
93  CASE cd.scope WHEN $globalScope THEN 1 ELSE 0 END AS scopesort
94  FROM clearing_decision cd
95  INNER JOIN $uploadTreeTable ut
96  ON (ut.pfile_fk = cd.pfile_fk AND cd.scope = $globalScope)
97  OR (ut.uploadtree_pk = cd.uploadtree_fk
98  AND cd.scope = $localScope AND cd.group_fk = $p2)
99  WHERE $sql_upload $condition
100  cd.decision_type!=$p1),
101  decision AS (
102  SELECT $filterClause *
103  FROM allDecs
104  ORDER BY itemid, scopesort, id DESC
105  )";
106  }
107 
113  function getClearedLicenses(ItemTreeBounds $itemTreeBounds, $groupId)
114  {
115  $statementName = __METHOD__;
116 
117  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
118  $condition = "ut.lft BETWEEN $1 AND $2";
119 
120  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent=true, $statementName, $params, $condition);
121  $params[] = DecisionTypes::IRRELEVANT;
122  $sql = "$decisionsCte
123  SELECT
124  lr.rf_pk AS license_id,
125  lr.rf_shortname AS shortname,
126  lr.rf_fullname AS fullname
127  FROM decision
128  INNER JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
129  INNER JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
130  INNER JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
131  WHERE NOT ce.removed AND type_id!=$".count($params)."
132  GROUP BY license_id,shortname,fullname";
133 
134  $this->dbManager->prepare($statementName, $sql);
135 
136  $res = $this->dbManager->execute($statementName, $params);
137 
138  $licenses = array();
139  while ($row = $this->dbManager->fetchArray($res)) {
140  $licenses[] = new LicenseRef($row['license_id'], $row['shortname'], $row['fullname']);
141  }
142  $this->dbManager->freeResult($res);
143 
144  return $licenses;
145  }
146 
147 
154  function getFileClearings(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $forClearingHistory=false)
155  {
156  $this->dbManager->begin();
157 
158  $statementName = __METHOD__;
159 
160  $params = array($itemTreeBounds->getItemId());
161  $condition = "ut.uploadtree_pk = $1";
162 
163  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent, $statementName, $params, $condition);
164 
165  $clearingsWithLicensesArray = $this->getDecisionsFromCte($decisionsCte, $statementName, $params, $forClearingHistory);
166 
167  $this->dbManager->commit();
168  return $clearingsWithLicensesArray;
169  }
170 
178  function getFileClearingsFolder(ItemTreeBounds $itemTreeBounds, $groupId, $includeSubFolders=true, $onlyCurrent=true)
179  {
180  $this->dbManager->begin();
181 
182  $statementName = __METHOD__;
183 
184  if (!$includeSubFolders) {
185  $params = array($itemTreeBounds->getItemId());
186  $condition = "ut.realparent = $1";
187  } else {
188  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
189  $condition = "ut.lft BETWEEN $1 AND $2";
190  }
191 
192  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent, $statementName, $params, $condition);
193 
194  $clearingsWithLicensesArray = $this->getDecisionsFromCte($decisionsCte, $statementName, $params);
195 
196  $this->dbManager->commit();
197  return $clearingsWithLicensesArray;
198  }
199 
206  private function getDecisionsFromCte($decisionsCte, $statementName, $params, $forClearingHistory=false)
207  {
208  $sql = "$decisionsCte
209  SELECT
210  decision.*,
211  users.user_name AS user_name,
212  ce.clearing_event_pk as event_id,
213  ce.user_fk as event_user_id,
214  ce.group_fk as event_group_id,
215  lr.rf_pk AS license_id,
216  lr.rf_shortname AS shortname,
217  lr.rf_fullname AS fullname,
218  ce.removed AS removed,
219  ce.type_fk AS event_type_id,
220  ce.reportinfo AS reportinfo,
221  ce.comment AS comment,
222  ce.acknowledgement AS acknowledgement
223  FROM decision
224  LEFT JOIN users ON decision.user_id = users.user_pk
225  LEFT JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
226  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
227  LEFT JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
228  ORDER BY decision.id DESC, event_id ASC";
229 
230  $this->dbManager->prepare($statementName, $sql);
231 
232  $result = $this->dbManager->execute($statementName, $params);
233  $clearingsWithLicensesArray = array();
234 
235  $previousClearingId = -1;
236  $previousItemId = -1;
237  $clearingEvents = array();
238  $clearingEventCache = array();
239  $clearingDecisionBuilder = ClearingDecisionBuilder::create();
240  $firstMatch = true;
241  while ($row = $this->dbManager->fetchArray($result)) {
242  $clearingId = $row['id'];
243  $itemId = $row['itemid'];
244  $licenseId = $row['license_id'];
245  $eventId = $row['event_id'];
246  $licenseShortName = $row['shortname'];
247  $licenseName = $row['fullname'];
248  $licenseIsRemoved = $row['removed'];
249 
250  $eventType = $row['event_type_id'];
251  $eventUserId = $row['event_user_id'];
252  $eventGroupId = $row['event_group_id'];
253  $comment = $row['comment'];
254  $reportInfo = $row['reportinfo'];
255  $acknowledgement = $row['acknowledgement'];
256 
257  if ($clearingId !== $previousClearingId && $itemId !== $previousItemId) {
258  //store the old one
259  if (!$firstMatch) {
260  $clearingsWithLicensesArray[] = $clearingDecisionBuilder->setClearingEvents($clearingEvents)->build();
261  }
262 
263  $firstMatch = false;
264  //prepare the new one
265  if ($forClearingHistory) {
266  $previousClearingId = $clearingId;
267  } else {
268  $previousItemId = $itemId;
269  }
270  $clearingEvents = array();
271  $clearingDecisionBuilder = ClearingDecisionBuilder::create()
272  ->setClearingId($row['id'])
273  ->setUploadTreeId($itemId)
274  ->setPfileId($row['pfile_id'])
275  ->setUserName($row['user_name'])
276  ->setUserId($row['user_id'])
277  ->setType(intval($row['type_id']))
278  ->setScope(intval($row['scope']))
279  ->setTimeStamp($row['ts_added']);
280  }
281 
282  if ($licenseId !== null) {
283  if (!array_key_exists($eventId, $clearingEventCache)) {
284  if (!array_key_exists($licenseId, $this->licenseRefCache)) {
285  $this->licenseRefCache[$licenseId] = new LicenseRef($licenseId, $licenseShortName, $licenseName);
286  }
287  $licenseRef = $this->licenseRefCache[$licenseId];
288  $clearingEventCache[$eventId] = $this->buildClearingEvent($eventId, $eventUserId, $eventGroupId, $licenseRef, $licenseIsRemoved, $eventType, $reportInfo, $comment, $acknowledgement);
289  }
290  $clearingEvents[] = $clearingEventCache[$eventId];
291  }
292  }
293 
295  if (!$firstMatch) {
296  $clearingsWithLicensesArray[] = $clearingDecisionBuilder->setClearingEvents($clearingEvents)->build();
297  }
298  $this->dbManager->freeResult($result);
299 
300  return $clearingsWithLicensesArray;
301  }
307  public function getRelevantClearingDecision(ItemTreeBounds $itemTreeBounds, $groupId)
308  {
309  $clearingDecisions = $this->getFileClearings($itemTreeBounds, $groupId);
310  if (count($clearingDecisions) > 0) {
311  return $clearingDecisions[0];
312  }
313  return null;
314  }
315 
320  public function removeWipClearingDecision($uploadTreeId, $groupId)
321  {
322  $sql = "DELETE FROM clearing_decision WHERE uploadtree_fk=$1 AND group_fk=$2 AND decision_type=$3";
323  $this->dbManager->prepare($stmt = __METHOD__, $sql);
324  $this->dbManager->freeResult($this->dbManager->execute($stmt, array($uploadTreeId, $groupId, DecisionTypes::WIP)));
325  }
326 
334  public function createDecisionFromEvents($uploadTreeId, $userId, $groupId, $decType, $scope, $eventIds)
335  {
336  if ( ($scope == DecisionScopes::REPO) &&
337  !empty($this->getCandidateLicenseCountForCurrentDecisions($uploadTreeId))) {
338  throw new \Exception( _("Cannot add candidate license as global decision\n") );
339  }
340  $this->dbManager->begin();
341 
342  $this->removeWipClearingDecision($uploadTreeId, $groupId);
343 
344  $statementName = __METHOD__;
345  $this->dbManager->prepare($statementName,
346  "
347 INSERT INTO clearing_decision (
348  uploadtree_fk,
349  pfile_fk,
350  user_fk,
351  group_fk,
352  decision_type,
353  scope
354 ) VALUES (
355  $1,
356  (SELECT pfile_fk FROM uploadtree WHERE uploadtree_pk=$1),
357  $2,
358  $3,
359  $4,
360  $5) RETURNING clearing_decision_pk
361  ");
362  $res = $this->dbManager->execute($statementName,
363  array($uploadTreeId, $userId, $groupId, $decType, $scope));
364  $result = $this->dbManager->fetchArray($res);
365  $clearingDecisionId = $result['clearing_decision_pk'];
366  $this->dbManager->freeResult($res);
367 
368  $statementNameClearingDecisionEventInsert = __METHOD__ . ".insertClearingDecisionEvent";
369  $this->dbManager->prepare($statementNameClearingDecisionEventInsert,
370  "INSERT INTO clearing_decision_event (clearing_decision_fk, clearing_event_fk) VALUES($1, $2)"
371  );
372 
373  foreach ($eventIds as $eventId) {
374  $this->dbManager->freeResult($this->dbManager->execute($statementNameClearingDecisionEventInsert, array($clearingDecisionId, $eventId)));
375  }
376 
377  $this->dbManager->commit();
378  }
379 
385  public function getRelevantClearingEvents($itemTreeBounds, $groupId, $includeSubFolders=true)
386  {
387  $decision = $this->getFileClearingsFolder($itemTreeBounds, $groupId, $includeSubFolders, $onlyCurrent=true);
388  $events = array();
389  $date = 0;
390 
391  if (count($decision)) {
392  foreach ($decision[0]->getClearingEvents() as $event) {
393  $events[$event->getLicenseId()] = $event;
394  }
395  $date = $decision[0]->getTimeStamp();
396  }
397 
398  $stmt = __METHOD__;
399  $sql = 'SELECT rf_fk,rf_shortname,rf_fullname,clearing_event_pk,comment,type_fk,removed,reportinfo,acknowledgement, EXTRACT(EPOCH FROM date_added) AS ts_added
400  FROM clearing_event LEFT JOIN license_ref ON rf_fk=rf_pk
401  WHERE uploadtree_fk=$1 AND group_fk=$2 AND date_added>to_timestamp($3)
402  ORDER BY clearing_event_pk ASC';
403  $this->dbManager->prepare($stmt, $sql);
404  $res = $this->dbManager->execute($stmt,array($itemTreeBounds->getItemId(),$groupId,$date));
405 
406  while ($row = $this->dbManager->fetchArray($res)) {
407  $licenseRef = new LicenseRef($row['rf_fk'],$row['rf_shortname'],$row['rf_fullname']);
408  $events[$row['rf_fk']] = ClearingEventBuilder::create()
409  ->setEventId($row['clearing_event_pk'])
410  ->setComment($row['comment'])
411  ->setTimeStamp($row['ts_added'])
412  ->setEventType($row['type_fk'])
413  ->setLicenseRef($licenseRef)
414  ->setRemoved($this->dbManager->booleanFromDb($row['removed']))
415  ->setReportinfo($row['reportinfo'])
416  ->setAcknowledgement($row['acknowledgement'])
417  ->setUploadTreeId($itemTreeBounds->getItemId())
418  ->build();
419  }
420  $this->dbManager->freeResult($res);
421  return $events;
422  }
423 
432  public function updateClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $what, $changeTo)
433  {
434  $this->dbManager->begin();
435 
436  $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";
437  $statementName = __METHOD__ . 'getOld';
438  $params = array($uploadTreeId, $licenseId, $groupId);
439  $row = $this->dbManager->getSingleRow($statementGetOldata, $params, $statementName);
440 
441  if (!$row) { //The license was not added as user decision yet -> we promote it here
442  $type = ClearingEventTypes::USER;
443  $row['type_fk'] = $type;
444  $row['comment'] = "";
445  $row['reportinfo'] = "";
446  $row['acknowledgement'] = "";
447  }
448 
449  if ($what == 'reportinfo') {
450  $reportInfo = $changeTo;
451  $comment = $row['comment'];
452  $acknowledgement = $row['acknowledgement'];
453  } elseif ($what == 'comment') {
454  $reportInfo = $row['reportinfo'];
455  $comment = $changeTo;
456  $acknowledgement = $row['acknowledgement'];
457  } else {
458  $reportInfo = $row['reportinfo'];
459  $comment = $row['comment'];
460  $acknowledgement = $changeTo;
461  }
462  $this->insertClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, false, $row['type_fk'], $reportInfo, $comment, $acknowledgement);
463 
464  $this->dbManager->commit();
465 
466  }
467 
468  public function copyEventIdTo($eventId, $itemId, $userId, $groupId)
469  {
470  $stmt = __METHOD__;
471  $this->dbManager->prepare($stmt,
472  "INSERT INTO clearing_event(uploadtree_fk, user_fk, group_fk, type_fk, rf_fk, removed, reportinfo, comment, acknowledgement)
473  SELECT $2, $3, $4, type_fk, rf_fk, removed, reportinfo, comment, acknowledgement FROM clearing_event WHERE clearing_event_pk = $1"
474  );
475 
476  $this->dbManager->freeResult($this->dbManager->execute($stmt, array($eventId, $itemId, $userId, $groupId)));
477  }
478 
491  public function insertClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $isRemoved, $type = ClearingEventTypes::USER, $reportInfo = '', $comment = '', $acknowledgement = '', $jobId=0)
492  {
493  $insertIsRemoved = $this->dbManager->booleanToDb($isRemoved);
494 
495  $stmt = __METHOD__;
496  $params = array($uploadTreeId, $userId, $groupId, $type, $licenseId, $insertIsRemoved, $reportInfo, $comment, $acknowledgement);
497  $columns = "uploadtree_fk, user_fk, group_fk, type_fk, rf_fk, removed, reportinfo, comment, acknowledgement";
498  $values = "$1,$2,$3,$4,$5,$6,$7,$8,$9";
499 
500  if ($jobId > 0) {
501  $stmt.= ".jobId";
502  $params[] = $jobId;
503  $columns .= ", job_fk";
504  $values .= ",$".count($params);
505  } else {
506  $this->markDecisionAsWip($uploadTreeId, $userId, $groupId);
507  }
508 
509  $this->dbManager->prepare($stmt, "INSERT INTO clearing_event ($columns) VALUES($values) RETURNING clearing_event_pk");
510  $res = $this->dbManager->execute($stmt, $params);
511 
512  $row = $this->dbManager->fetchArray($res);
513  $this->dbManager->freeResult($res);
514 
515  return intval($row['clearing_event_pk']);
516  }
517 
522  public function getEventIdsOfJob($jobId)
523  {
524  $statementName = __METHOD__;
525  $this->dbManager->prepare(
526  $statementName,
527  "SELECT uploadtree_fk, clearing_event_pk, rf_fk FROM clearing_event WHERE job_fk = $1"
528  );
529 
530  $res = $this->dbManager->execute($statementName, array($jobId));
531 
532  $events = array();
533  while ($row = $this->dbManager->fetchArray($res)) {
534  $itemId = intval($row['uploadtree_fk']);
535  $eventId = intval($row['clearing_event_pk']);
536  $licenseId = intval($row['rf_fk']);
537 
538  $events[$itemId][$licenseId] = $eventId;
539  }
540  $this->dbManager->freeResult($res);
541 
542  return $events;
543  }
544 
556  protected function buildClearingEvent($eventId, $userId, $groupId, $licenseRef, $licenseIsRemoved, $type, $reportInfo, $comment, $acknowledgement)
557  {
558  $removed = $this->dbManager->booleanFromDb($licenseIsRemoved);
559 
560  return ClearingEventBuilder::create()
561  ->setEventId($eventId)
562  ->setUserId($userId)
563  ->setGroupId($groupId)
564  ->setEventType($type)
565  ->setLicenseRef($licenseRef)
566  ->setRemoved($removed)
567  ->setReportInfo($reportInfo)
568  ->setAcknowledgement($acknowledgement)
569  ->setComment($comment)
570  ->build();
571  }
572 
578  public function markDecisionAsWip($uploadTreeId, $userId, $groupId)
579  {
580  $statementName = __METHOD__;
581 
582  $this->dbManager->prepare($statementName,
583  "INSERT INTO clearing_decision (uploadtree_fk,pfile_fk,user_fk,group_fk,decision_type,scope) VALUES (
584  $1, (SELECT pfile_fk FROM uploadtree WHERE uploadtree_pk=$1), $2, $3, $4, $5)");
585  $res = $this->dbManager->execute($statementName,
586  array($uploadTreeId, $userId, $groupId, DecisionTypes::WIP, DecisionScopes::ITEM));
587  $this->dbManager->freeResult($res);
588  }
589 
590  public function isDecisionWip($uploadTreeId, $groupId)
591  {
592  $sql = "SELECT decision_type FROM clearing_decision WHERE uploadtree_fk=$1 AND group_fk = $2 ORDER BY date_added DESC LIMIT 1";
593  $latestDec = $this->dbManager->getSingleRow($sql,
594  array($uploadTreeId, $groupId), $sqlLog = __METHOD__);
595  if ($latestDec === false) {
596  return false;
597  }
598  return ($latestDec['decision_type'] == DecisionTypes::WIP);
599  }
600 
601  public function isDecisionTBD($uploadTreeId, $groupId)
602  {
603  $sql = "SELECT decision_type FROM clearing_decision WHERE uploadtree_fk=$1 AND group_fk = $2 ORDER BY date_added DESC LIMIT 1";
604  $latestDec = $this->dbManager->getSingleRow($sql,
605  array($uploadTreeId, $groupId), $sqlLog = __METHOD__);
606  if ($latestDec === false) {
607  return false;
608  }
609  return ($latestDec['decision_type'] == DecisionTypes::TO_BE_DISCUSSED);
610  }
611 
612  public function isDecisionDNU($uploadTreeId, $groupId)
613  {
614  $sql = "SELECT decision_type FROM clearing_decision
615  WHERE uploadtree_fk=$1 AND group_fk = $2
616  ORDER BY clearing_decision_pk DESC LIMIT 1";
617  $latestDec = $this->dbManager->getSingleRow($sql,
618  array($uploadTreeId, $groupId), $sqlLog = __METHOD__);
619  if ($latestDec === false) {
620  return false;
621  }
622  return ($latestDec['decision_type'] == DecisionTypes::DO_NOT_USE);
623  }
624 
631  public function getBulkHistory(ItemTreeBounds $itemTreeBound, $groupId, $onlyTried = true)
632  {
633  $uploadTreeTableName = $itemTreeBound->getUploadTreeTableName();
634  $itemId = $itemTreeBound->getItemId();
635  $uploadId = $itemTreeBound->getUploadId();
636  $left = $itemTreeBound->getLeft();
637 
638  $params = array($uploadId, $itemId, $left, $groupId);
639  $stmt = __METHOD__ . "." . $uploadTreeTableName;
640 
641  $triedExpr = "$3 between ut2.lft and ut2.rgt";
642  $triedFilter = "";
643  if ($onlyTried) {
644  $triedFilter = "and " . $triedExpr;
645  $stmt .= ".tried";
646  }
647 
648  $sql = "WITH alltried AS (
649  SELECT lr.lrb_pk, ce.clearing_event_pk ce_pk, lr.rf_text, ce.uploadtree_fk,
650  $triedExpr AS tried
651  FROM license_ref_bulk lr
652  LEFT JOIN highlight_bulk h ON lrb_fk = lrb_pk
653  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = h.clearing_event_fk
654  LEFT JOIN $uploadTreeTableName ut ON ut.uploadtree_pk = ce.uploadtree_fk
655  INNER JOIN $uploadTreeTableName ut2 ON ut2.uploadtree_pk = lr.uploadtree_fk
656  WHERE ut2.upload_fk = $1 AND lr.group_fk = $4
657  $triedFilter
658  ORDER BY lr.lrb_pk
659  ), aggregated_tried AS (
660  SELECT DISTINCT ON(lrb_pk) lrb_pk, ce_pk, rf_text AS text, tried, matched
661  FROM (
662  SELECT DISTINCT ON(lrb_pk) lrb_pk, ce_pk, rf_text, tried, true AS matched FROM alltried WHERE uploadtree_fk = $2
663  UNION ALL
664  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
665  ) AS result ORDER BY lrb_pk, matched DESC)
666  SELECT lrb_pk, text, rf_shortname, removing, tried, ce_pk, matched
667  FROM aggregated_tried
668  INNER JOIN license_set_bulk lsb ON lsb.lrb_fk = lrb_pk
669  INNER JOIN license_ref lrf ON lsb.rf_fk = lrf.rf_pk
670  ORDER BY lrb_pk";
671 
672  $this->dbManager->prepare($stmt, $sql);
673  $res = $this->dbManager->execute($stmt, $params);
674 
675  $bulks = array();
676  while ($row = $this->dbManager->fetchArray($res)) {
677  $bulkRun = $row['lrb_pk'];
678  if (!array_key_exists($bulkRun, $bulks)) {
679  $bulks[$bulkRun] = array(
680  "bulkId" => $row['lrb_pk'],
681  "id" => $row['ce_pk'],
682  "text" => $row['text'],
683  "matched" => $this->dbManager->booleanFromDb($row['matched']),
684  "tried" => $this->dbManager->booleanFromDb($row['tried']),
685  "removedLicenses" => array(),
686  "addedLicenses" => array());
687  }
688  $key = $this->dbManager->booleanFromDb($row['removing']) ? 'removedLicenses' : 'addedLicenses';
689  $bulks[$bulkRun][$key][] = $row['rf_shortname'];
690  }
691 
692  $this->dbManager->freeResult($res);
693  return $bulks;
694  }
695 
696 
697  public function getBulkMatches($bulkId, $groupId)
698  {
699  $stmt = __METHOD__;
700  $sql = "SELECT uploadtree_fk AS itemid
701  FROM clearing_event ce
702  INNER JOIN highlight_bulk h
703  ON ce.clearing_event_pk = h.clearing_event_fk
704  WHERE lrb_fk = $1 AND group_fk = $2";
705 
706  $this->dbManager->prepare($stmt, $sql);
707  $res = $this->dbManager->execute($stmt, array($bulkId, $groupId));
708 
709  $result = $this->dbManager->fetchAll($res);
710  $this->dbManager->freeResult($res);
711  return $result;
712  }
713 
719  function getClearedLicenseIdAndMultiplicities(ItemTreeBounds $itemTreeBounds, $groupId)
720  {
721  $statementName = __METHOD__;
722 
723  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
724  $condition = "ut.lft BETWEEN $1 AND $2";
725 
726  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent=true, $statementName, $params, $condition);
727  $params[] = DecisionTypes::IRRELEVANT;
728  $sql = "$decisionsCte
729  SELECT
730  COUNT(DISTINCT itemid) AS count,
731  lr.rf_shortname AS shortname,
732  rf_pk
733  FROM decision
734  LEFT JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
735  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
736  LEFT JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
737  WHERE (NOT ce.removed OR clearing_event_pk IS NULL) AND type_id!=$".count($params)."
738  GROUP BY shortname,rf_pk";
739 
740  $this->dbManager->prepare($statementName, $sql);
741  $res = $this->dbManager->execute($statementName, $params);
742  $multiplicity = array();
743  while ($row = $this->dbManager->fetchArray($res)) {
744  $shortname= empty($row['rf_pk']) ? LicenseDao::NO_LICENSE_FOUND : $row['shortname'];
745  $multiplicity[$shortname] = $row;
746  }
747  $this->dbManager->freeResult($res);
748 
749  return $multiplicity;
750  }
751 
757  public function markDirectoryAsDecisionType(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
758  {
759  if ($decisionMark == "doNotUse") {
760  $decisionMark = DecisionTypes::DO_NOT_USE;
761  } else {
762  $decisionMark = DecisionTypes::IRRELEVANT;
763  }
764  $this->markDirectoryAsDecisionTypeIfScannerDetected($itemTreeBounds, $groupId, $userId, false, $decisionMark);
765  $this->markDirectoryAsDecisionTypeIfUserEdited($itemTreeBounds, $groupId, $userId, false, $decisionMark);
766  }
767 
773  public function deleteDecisionTypeFromDirectory(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
774  {
775  if ($decisionMark == "deleteDoNotUse") {
776  $decisionMark = DecisionTypes::DO_NOT_USE;
777  } else {
778  $decisionMark = DecisionTypes::IRRELEVANT;
779  }
780  $this->markDirectoryAsDecisionTypeIfScannerDetected($itemTreeBounds, $groupId, $userId, true, $decisionMark);
781  $this->markDirectoryAsDecisionTypeIfUserEdited($itemTreeBounds, $groupId, $userId, true, $decisionMark);
782  }
783 
789  protected function markDirectoryAsDecisionTypeIfScannerDetected(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $removeDecision=false, $decisionMark=DecisionTypes::IRRELEVANT)
790  {
791  $statementName = __METHOD__ ;
792  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
793  $params[] = $groupId;
794  $a = count($params);
795  $options = array(UploadTreeProxy::OPT_SKIP_THESE=>'noLicense',
796  UploadTreeProxy::OPT_ITEM_FILTER=>' AND (lft BETWEEN $1 AND $2)',
797  UploadTreeProxy::OPT_GROUP_ID=>'$'.$a.'');
798  $uploadTreeProxy = new UploadTreeProxy($itemTreeBounds->getUploadId(), $options, $itemTreeBounds->getUploadTreeTableName());
799  if (!$removeDecision) {
800  $params[] = $userId;
801  $params[] = $decisionMark;
802  $params[] = DecisionScopes::ITEM;
803  $sql = $uploadTreeProxy->asCte()
804  .' INSERT INTO clearing_decision (uploadtree_fk,pfile_fk,user_fk,group_fk,decision_type,scope)
805  SELECT uploadtree_pk itemid,pfile_fk pfile_id, $'.($a+1).', $'.$a.', $'.($a+2).', $'.($a+3).'
806  FROM UploadTreeView WHERE NOT EXISTS (
807  SELECT uploadtree_fk FROM clearing_decision
808  WHERE decision_type=$'.($a+2).' AND uploadtree_fk=UploadTreeView.uploadtree_pk)';
809  } else {
810  $params[] = $decisionMark;
811  $sql = $uploadTreeProxy->asCte()
812  .' DELETE FROM clearing_decision WHERE clearing_decision_pk IN (
813  SELECT clearing_decision_pk
814  FROM clearing_decision cd INNER JOIN (
815  SELECT MAX(date_added) AS date_added, uploadtree_fk
816  FROM clearing_decision WHERE uploadtree_fk IN (
817  SELECT uploadtree_pk FROM UploadTreeView) GROUP BY uploadtree_fk) cd2 ON cd.uploadtree_fk = cd2.uploadtree_fk
818  AND cd.date_added = cd2.date_added AND decision_type = $'.($a+1).')';
819  }
820  $this->dbManager->prepare($statementName, $sql);
821  $res = $this->dbManager->execute($statementName,$params);
822  $this->dbManager->freeResult($res);
823  }
824 
830  protected function markDirectoryAsDecisionTypeIfUserEdited(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $removeDecision=false, $decisionMark=DecisionTypes::IRRELEVANT)
831  {
832  $statementName = __METHOD__ ;
833  $params = array($itemTreeBounds->getLeft(), $itemTreeBounds->getRight());
834  $condition = "ut.lft BETWEEN $1 AND $2";
835  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent=true, $statementName, $params, $condition);
836  if (!$removeDecision) {
837  $params[] = $userId;
838  $a = count($params);
839  $params[] = $groupId;
840  $params[] = $decisionMark;
841  $params[] = DecisionScopes::ITEM;
842  $this->dbManager->prepare($statementName, $decisionsCte
843  .' INSERT INTO clearing_decision (uploadtree_fk,pfile_fk,user_fk,group_fk,decision_type,scope)
844  SELECT itemid,pfile_id, $'.$a.', $'.($a+1).', $'.($a+2).', $'.($a+3).'
845  FROM allDecs ad WHERE type_id != $'.($a+2));
846  } else {
847  $params[] = $decisionMark;
848  $a = count($params);
849  $this->dbManager->prepare($statementName, $decisionsCte
850  .' DELETE FROM clearing_decision WHERE decision_type = $'.$a.'
851  AND clearing_decision_pk IN (
852  SELECT id FROM allDecs WHERE type_id = $'.$a.')');
853  }
854  $res = $this->dbManager->execute($statementName,$params);
855  $this->dbManager->freeResult($res);
856  }
857 
863  public function getMainLicenseIds($uploadId, $groupId)
864  {
865  $stmt = __METHOD__;
866  $sql = "SELECT rf_fk FROM upload_clearing_license WHERE upload_fk=$1 AND group_fk=$2";
867  $this->dbManager->prepare($stmt, $sql);
868  $res = $this->dbManager->execute($stmt,array($uploadId,$groupId));
869  $ids = array();
870  while ($row = $this->dbManager->fetchArray($res)) {
871  $ids[$row['rf_fk']] = $row['rf_fk'];
872  }
873  $this->dbManager->freeResult($res);
874  return $ids;
875  }
876 
882  public function makeMainLicense($uploadId, $groupId, $licenseId)
883  {
884  $this->dbManager->insertTableRow('upload_clearing_license',
885  array('upload_fk'=>$uploadId,'group_fk'=>$groupId,'rf_fk'=>$licenseId));
886  }
887 
893  public function removeMainLicense($uploadId, $groupId, $licenseId)
894  {
895  $this->dbManager->getSingleRow('DELETE FROM upload_clearing_license WHERE upload_fk=$1 AND group_fk=$2 AND rf_fk=$3',
896  array($uploadId,$groupId,$licenseId));
897  }
898 
905  function getFilesForDecisionTypeFolderLevel(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $decisionMark="")
906  {
907  if (!empty($decisionMark)) {
908  $decisionMark = DecisionTypes::DO_NOT_USE;
909  } else {
910  $decisionMark = DecisionTypes::IRRELEVANT;
911  }
912  $statementName = __METHOD__;
913  $params = array();
914  $decisionsCte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, $onlyCurrent, $statementName, $params);
915  $params[] = $decisionMark;
916  $sql = "$decisionsCte
917  SELECT
918  itemid as uploadtree_pk,
919  lr.rf_shortname AS shortname,
920  comment
921  FROM decision
922  LEFT JOIN clearing_decision_event cde ON cde.clearing_decision_fk = decision.id
923  LEFT JOIN clearing_event ce ON ce.clearing_event_pk = cde.clearing_event_fk
924  LEFT JOIN license_ref lr ON lr.rf_pk = ce.rf_fk
925  WHERE type_id=$".count($params);
926  $this->dbManager->prepare($statementName, $sql);
927  $res = $this->dbManager->execute($statementName, $params);
928  $irrelevantFiles = $this->dbManager->fetchAll($res);
929  $this->dbManager->freeResult($res);
930  return $irrelevantFiles;
931  }
932 
938  public function getPreviousBulkIds($uploadId, $groupId, $userId, $onlyCount=0)
939  {
940  $stmt = __METHOD__;
941  $bulkIds = array();
942  $sql = "SELECT jq_args FROM upload_reuse, jobqueue, job
943  WHERE upload_fk=$1 AND group_fk=$2
944  AND EXISTS(SELECT * FROM group_user_member gum WHERE gum.group_fk=upload_reuse.group_fk AND gum.user_fk=$3)
945  AND jq_type=$4 AND jq_job_fk=job_pk
946  AND job_upload_fk=reused_upload_fk AND job_group_fk=reused_group_fk";
947  $this->dbManager->prepare($stmt, $sql);
948  $res = $this->dbManager->execute($stmt,array($uploadId, $groupId, $userId,'monkbulk'));
949  while ($row= $this->dbManager->fetchArray($res)) {
950  $bulkIds = array_merge($bulkIds,explode("\n", $row['jq_args']));
951  }
952  $this->dbManager->freeResult($res);
953  if (empty($onlyCount)) {
954  return array_unique($bulkIds);
955  } else {
956  return count(array_unique($bulkIds));
957  }
958  }
959 
967  public function getClearingDecisionsCount($uploadId, $groupId)
968  {
969  $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId);
970  $statementName = "";
971  $params = array();
972 
973  $cte = $this->getRelevantDecisionsCte($itemTreeBounds, $groupId, true,
974  $statementName, $params);
975 
976  $statementName = __METHOD__ . $statementName;
977  $sql = "$cte SELECT COUNT(*) AS cnt FROM decision WHERE type_id <> ".DecisionTypes::TO_BE_DISCUSSED;
978 
979  $clearedCounter = $this->dbManager->getSingleRow($sql, $params,
980  $statementName);
981  return $clearedCounter['cnt'];
982  }
983 
991  public function getTotalDecisionCount($uploadId, $groupId)
992  {
993  $uploadTreeTable = $this->uploadDao->getUploadtreeTableName($uploadId);
994  $scanJobProxy = new ScanJobProxy($GLOBALS['container']->get('dao.agent'), $uploadId);
995  $scanJobProxy->createAgentStatus(array_keys(AgentRef::AGENT_LIST));
996  $latestAgentIds = $scanJobProxy->getLatestSuccessfulAgentIds();
997  $agentIds = "{" . implode(",", $latestAgentIds) . "}";
998 
999  $globalScope = DecisionScopes::REPO;
1000  $params = array($groupId, $uploadId, $agentIds);
1001  $statement = __METHOD__ . "." . $uploadTreeTable;
1002  $sql = "
1003 WITH allDecs AS (
1004  SELECT DISTINCT ON (ut.uploadtree_pk) * FROM $uploadTreeTable AS ut
1005  LEFT JOIN license_file AS lf
1006  ON lf.pfile_fk = ut.pfile_fk
1007  AND lf.agent_fk = ANY($3::int[])
1008  AND lf.rf_fk NOT IN (SELECT rf_pk FROM license_ref
1009  WHERE rf_shortname = ANY(VALUES('No_license_found'),('Void'))
1010  )
1011  AND lf.rf_fk IS NOT NULL
1012  LEFT JOIN clearing_decision AS cd ON
1013  (ut.uploadtree_pk = cd.uploadtree_fk)
1014  OR (ut.pfile_fk = cd.pfile_fk AND cd.scope = $globalScope)
1015  AND cd.group_fk = $1
1016  WHERE ut.upload_fk = $2 AND (
1017  CASE
1018  WHEN lf.fl_pk IS NULL AND cd.clearing_decision_pk IS NULL
1019  THEN FALSE
1020  ELSE TRUE
1021  END
1022  )
1023 )
1024 SELECT count(*) AS cnt
1025 FROM (SELECT DISTINCT uploadtree_pk FROM allDecs) AS no_license_uploadtree;";
1026  $foundCounter = $this->dbManager->getSingleRow($sql, $params, $statement);
1027  return $foundCounter['cnt'];
1028  }
1029 
1034  public function getCandidateLicenseCountForCurrentDecisions($uploadTreeId, $uploadId=0)
1035  {
1036  if (!empty($uploadId)) {
1037  $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId, $uploadTreeTableName);
1038  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
1039  $params[] = $itemTreeBounds->getLeft();
1040  $params[] = $itemTreeBounds->getRight();
1041  $condition = "UT.lft BETWEEN $1 AND $2";
1042  $uploadtreeStatement = " uploadtree_fk IN (SELECT uploadtree_pk FROM $uploadTreeTableName UT WHERE $condition)";
1043  } else {
1044  $params = array($uploadTreeId);
1045  $uploadtreeStatement = " uploadtree_fk = $1";
1046  }
1047 
1048  $sql = "WITH latestEvents AS (
1049  SELECT rf_fk, date_added, removed FROM (
1050  SELECT rf_fk, date_added, removed, row_number()
1051  OVER (PARTITION BY rf_fk ORDER BY date_added DESC) AS ROWNUM
1052  FROM clearing_event WHERE $uploadtreeStatement) SORTABLE
1053  WHERE ROWNUM = 1 ORDER BY rf_fk)
1054  SELECT count(*) FROM license_candidate WHERE license_candidate.rf_pk IN
1055  (SELECT rf_fk FROM latestEvents WHERE removed=false);";
1056  $countCandidate = $this->dbManager->getSingleRow($sql,
1057  $params, $sqlLog = __METHOD__);
1058 
1059  return $countCandidate['count'];
1060  }
1061 
1066  public function marklocalDecisionsAsGlobal($uploadId)
1067  {
1068  $statementName = __METHOD__ . $uploadId;
1069 
1070  $sql = "WITH latestDecisions AS (
1071  SELECT clearing_decision_pk FROM (
1072  SELECT clearing_decision_pk, uploadtree_fk, date_added, row_number()
1073  OVER (PARTITION BY uploadtree_fk ORDER BY date_added DESC) AS ROWNUM
1074  FROM clearing_decision WHERE uploadtree_fk IN
1075  (SELECT uploadtree_pk FROM uploadtree WHERE upload_fk = $1)) SORTABLE
1076  WHERE ROWNUM = $2 ORDER BY uploadtree_fk)
1077  UPDATE clearing_decision SET scope = $2 WHERE clearing_decision_pk IN (
1078  SELECT clearing_decision_pk FROM latestDecisions) RETURNING clearing_decision_pk";
1079 
1080  $countUpdated = $this->dbManager->getSingleRow($sql,
1081  array($uploadId, DecisionScopes::REPO), $statementName);
1082 
1083  return count($countUpdated);
1084  }
1085 }
getFileClearingsFolder(ItemTreeBounds $itemTreeBounds, $groupId, $includeSubFolders=true, $onlyCurrent=true)
markDirectoryAsDecisionTypeIfUserEdited(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $removeDecision=false, $decisionMark=DecisionTypes::IRRELEVANT)
getCandidateLicenseCountForCurrentDecisions($uploadTreeId, $uploadId=0)
getTotalDecisionCount($uploadId, $groupId)
getRelevantClearingDecision(ItemTreeBounds $itemTreeBounds, $groupId)
getMainLicenseIds($uploadId, $groupId)
getClearedLicenses(ItemTreeBounds $itemTreeBounds, $groupId)
removeWipClearingDecision($uploadTreeId, $groupId)
deleteDecisionTypeFromDirectory(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
getFileClearings(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $forClearingHistory=false)
insertClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $isRemoved, $type=ClearingEventTypes::USER, $reportInfo= '', $comment= '', $acknowledgement= '', $jobId=0)
buildClearingEvent($eventId, $userId, $groupId, $licenseRef, $licenseIsRemoved, $type, $reportInfo, $comment, $acknowledgement)
getRelevantClearingEvents($itemTreeBounds, $groupId, $includeSubFolders=true)
updateClearingEvent($uploadTreeId, $userId, $groupId, $licenseId, $what, $changeTo)
makeMainLicense($uploadId, $groupId, $licenseId)
getPreviousBulkIds($uploadId, $groupId, $userId, $onlyCount=0)
markDirectoryAsDecisionType(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $decisionMark)
getFilesForDecisionTypeFolderLevel(ItemTreeBounds $itemTreeBounds, $groupId, $onlyCurrent=true, $decisionMark="")
__construct(DbManager $dbManager, UploadDao $uploadDao)
Definition: ClearingDao.php:52
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:28
getDecisionsFromCte($decisionsCte, $statementName, $params, $forClearingHistory=false)
getBulkHistory(ItemTreeBounds $itemTreeBound, $groupId, $onlyTried=true)
markDecisionAsWip($uploadTreeId, $userId, $groupId)
getClearedLicenseIdAndMultiplicities(ItemTreeBounds $itemTreeBounds, $groupId)
getClearingDecisionsCount($uploadId, $groupId)
createDecisionFromEvents($uploadTreeId, $userId, $groupId, $decType, $scope, $eventIds)
markDirectoryAsDecisionTypeIfScannerDetected(ItemTreeBounds $itemTreeBounds, $groupId, $userId, $removeDecision=false, $decisionMark=DecisionTypes::IRRELEVANT)
removeMainLicense($uploadId, $groupId, $licenseId)