71 use Symfony\Component\Process\Process;
73 include_once(__DIR__ .
"/version.php");
81 const RULES_NOMOS_IN_MONK = 0x1;
82 const RULES_NOMOS_MONK_NINKA = 0x2;
83 const RULES_WIP_SCANNER_UPDATES = 0x8;
84 const RULES_OJO_NO_CONTRADICTION = 0x10;
85 const RULES_COPYRIGHT_FALSE_POSITIVE = 0x20;
86 const RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER = 0x40;
87 const RULES_LICENSE_TYPE_CONCLUSION = 0x80;
88 const RULES_KOTOBA_NO_CONTRADICTION = 0x100;
89 const RULES_RESO_NO_CONTRADICTION = 0x200;
90 const RULES_ALL = self::RULES_NOMOS_IN_MONK | self::RULES_NOMOS_MONK_NINKA |
91 self::RULES_WIP_SCANNER_UPDATES |
92 self::RULES_OJO_NO_CONTRADICTION | self::RULES_RESO_NO_CONTRADICTION |
93 self::RULES_LICENSE_TYPE_CONCLUSION | self::RULES_KOTOBA_NO_CONTRADICTION;
157 parent::__construct(AGENT_DECIDER_NAME, AGENT_DECIDER_VERSION, AGENT_DECIDER_REV);
159 $this->uploadDao = $this->container->get(
'dao.upload');
160 $this->clearingDao = $this->container->get(
'dao.clearing');
161 $this->highlightDao = $this->container->get(
'dao.highlight');
162 $this->showJobsDao = $this->container->get(
'dao.show_jobs');
163 $this->decisionTypes = $this->container->get(
'decision.types');
164 $this->clearingDecisionProcessor = $this->container->get(
'businessrules.clearing_decision_processor');
165 $this->agentLicenseEventProcessor = $this->container->get(
'businessrules.agent_license_event_processor');
166 $this->copyrightDao = $this->container->get(
'dao.copyright');
167 $this->compatibilityDao = $this->container->get(
'dao.compatibility');
168 $this->licenseDao = $this->container->get(
'dao.license');
170 $this->agentSpecifOptions =
"r:t:";
180 $this->activeRules = array_key_exists(
'r',
$args) ? intval(
$args[
'r']) : self::RULES_ALL;
181 $this->licenseType = array_key_exists(
't',
$args) ?
183 $this->licenseMap =
new LicenseMap($this->
dbManager, $this->groupId, $this->licenseMapUsage);
185 if (array_key_exists(
"r",
$args) && (($this->activeRules&self::RULES_COPYRIGHT_FALSE_POSITIVE)== self::RULES_COPYRIGHT_FALSE_POSITIVE)) {
188 if (array_key_exists(
"r",
$args) && (($this->activeRules&self::RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER)== self::RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER)) {
191 $parentBounds = $this->uploadDao->getParentItemBounds($uploadId);
192 foreach ($this->uploadDao->getContainedItems($parentBounds) as $item) {
210 $itemTreeBounds = $item->getItemTreeBounds();
212 $unMappedMatches = $this->agentLicenseEventProcessor->getLatestScannerDetectedMatches($itemTreeBounds);
215 $lastDecision = $this->clearingDao->getRelevantClearingDecision($itemTreeBounds, $this->groupId);
217 if (
null!==$lastDecision && $lastDecision->getType()==DecisionTypes::IRRELEVANT) {
221 $currentEvents = $this->clearingDao->getRelevantClearingEvents($itemTreeBounds, $this->groupId);
224 if (
null !== $lastDecision && $projectedScannerMatches
225 && ($this->activeRules & self::RULES_WIP_SCANNER_UPDATES) == self::RULES_WIP_SCANNER_UPDATES) {
226 $licensesFromDecision = array();
227 foreach ($lastDecision->getClearingLicenses() as $clearingLicense) {
228 $licenseIdFromEvent = $this->licenseMap->getProjectedId($clearingLicense->getLicenseId());
229 $licensesFromDecision[$licenseIdFromEvent] = $licenseIdFromEvent;
234 if (
null !== $lastDecision && $markAsWip) {
235 $this->clearingDao->markDecisionAsWip($item->getId(), $this->userId, $this->groupId);
242 if (
null === $lastDecision && count($currentEvents) > 0
243 && ($this->activeRules & self::RULES_KOTOBA_NO_CONTRADICTION) == self::RULES_KOTOBA_NO_CONTRADICTION) {
249 if (
null!==$lastDecision || 0<count($currentEvents)) {
253 $haveDecided =
false;
255 if (!$haveDecided && ($this->activeRules&self::RULES_OJO_NO_CONTRADICTION) == self::RULES_OJO_NO_CONTRADICTION) {
259 if (!$haveDecided && ($this->activeRules&self::RULES_RESO_NO_CONTRADICTION) == self::RULES_RESO_NO_CONTRADICTION) {
263 if (!$haveDecided && ($this->activeRules&self::RULES_NOMOS_IN_MONK) == self::RULES_NOMOS_IN_MONK) {
267 if (!$haveDecided && ($this->activeRules&self::RULES_NOMOS_MONK_NINKA)== self::RULES_NOMOS_MONK_NINKA) {
271 if (!$haveDecided && ($this->activeRules &
272 self::RULES_LICENSE_TYPE_CONCLUSION) ==
273 self::RULES_LICENSE_TYPE_CONCLUSION) {
275 $projectedScannerMatches);
278 if (!$haveDecided && $markAsWip) {
279 $this->clearingDao->markDecisionAsWip($item->getId(), $this->userId, $this->groupId);
282 return ($haveDecided||$markAsWip ? 1 : 0);
293 foreach (array_keys($projectedScannerMatches) as $projectedLicenseId) {
294 if (!array_key_exists($projectedLicenseId, $licensesFromDecision)) {
311 $licenseMatchExists = count($matches) > 0;
312 foreach ($matches as $licenseMatches) {
316 if ($licenseMatchExists) {
318 $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
319 $itemTreeBounds, $this->userId, $this->groupId,
320 DecisionTypes::IDENTIFIED,
false);
321 }
catch (\Exception $e) {
322 echo
"Can not auto decide as file '" .
323 $itemTreeBounds->
getItemId() .
"' contains candidate license.\n";
326 return $licenseMatchExists;
341 $accountedLicenses = array();
342 foreach ($currentEvents as $event) {
343 if ($event->getEventType() != ClearingEventTypes::KOTOBA) {
346 $projectedId = $this->licenseMap->getProjectedId($event->getLicenseId());
347 $accountedLicenses[$projectedId] =
true;
350 foreach (array_keys($projectedScannerMatches) as $projectedLicenseId) {
351 if (!array_key_exists($projectedLicenseId, $accountedLicenses)) {
357 $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
358 $itemTreeBounds, $this->userId, $this->groupId,
359 DecisionTypes::IDENTIFIED,
false);
360 }
catch (\Exception $e) {
361 echo
"Can not auto decide as file '" .
362 $itemTreeBounds->
getItemId() .
"' contains candidate license.\n";
378 $licenseMatchExists = count($matches) > 0;
379 foreach ($matches as $licenseMatches) {
383 if ($licenseMatchExists) {
385 $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
386 $itemTreeBounds, $this->userId, $this->groupId,
387 DecisionTypes::IDENTIFIED,
false);
388 }
catch (\Exception $e) {
389 echo
"Can not auto decide as file '" .
390 $itemTreeBounds->
getItemId() .
"' contains candidate license.\n";
393 return $licenseMatchExists;
406 $canDecide = (count($matches)>0);
408 foreach ($matches as $licenseMatches) {
416 $this->clearingDecisionProcessor->makeDecisionFromLastEvents($itemTreeBounds, $this->userId, $this->groupId, DecisionTypes::IDENTIFIED, $global=
true);
431 $canDecide = (count($matches)>0);
433 foreach ($matches as $licenseMatches) {
441 $this->clearingDecisionProcessor->makeDecisionFromLastEvents($itemTreeBounds, $this->userId, $this->groupId, DecisionTypes::IDENTIFIED, $global=
true);
464 $this->clearingDecisionProcessor
465 ->makeDecisionFromLastEvents($itemTreeBounds, $this->userId,
466 $this->groupId, DecisionTypes::IDENTIFIED, DecisionScopes::ITEM, [],
true);
480 foreach ($matches as $licenseId => $licenseMatches) {
481 $projectedId = $this->licenseMap->getProjectedId($licenseId);
483 foreach ($licenseMatches as $agent => $agentMatches) {
484 $haveId = array_key_exists($projectedId, $remapped);
485 $haveAgent = $haveId && array_key_exists($agent, $remapped[$projectedId]);
487 $remapped[$projectedId][$agent] = array_merge($remapped[$projectedId][$agent], $agentMatches);
489 $remapped[$projectedId][$agent] = $agentMatches;
504 return ($big[0] >= 0) && ($small[0] >= $big[0]) && ($small[1] <= $big[1]);
514 if (!array_key_exists(
"nomos", $licenseMatches)) {
517 if (!array_key_exists(
"monk", $licenseMatches)) {
521 foreach ($licenseMatches[
"nomos"] as $licenseMatch) {
522 $matchId = $licenseMatch->getLicenseFileId();
523 $nomosRegion = $this->highlightDao->getHighlightRegion($matchId);
526 foreach ($licenseMatches[
"monk"] as $monkLicenseMatch) {
527 $monkRegion = $this->highlightDao->getHighlightRegion($monkLicenseMatch->getLicenseFileId());
548 $scanners = array(
'nomos',
'monk',
'ninka');
550 foreach ($scanners as $scanner) {
551 if (!array_key_exists($scanner, $licenseMatches)) {
554 foreach ($licenseMatches[$scanner] as $licenseMatch) {
555 $licId = $licenseMatch->getLicenseId();
556 $vote[$licId][$scanner] =
true;
560 foreach ($vote as $licId=>$voters) {
561 if (count($voters) != 3) {
576 if (array_key_exists($scanner, $licenseMatches) ===
true) {
579 return $match->getLicenseId();
580 }, $licenseMatches[$scanner]);
593 if (count($findingsByOjo) == 0) {
599 if (count($findingsByOtherScanner) == 0) {
603 foreach ($findingsByOtherScanner as $findingsByScanner) {
604 if (in_array($findingsByScanner, $findingsByOjo) ===
false) {
620 if (count($findingsByReso) == 0) {
626 if (count($findingsByOtherScanner) == 0) {
630 foreach ($findingsByOtherScanner as $findingsByScanner) {
631 if (in_array($findingsByScanner, $findingsByReso) ===
false) {
648 if (empty($uploadId)) {
652 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
653 $scanJobProxy =
new ScanJobProxy($GLOBALS[
'container']->
get(
'dao.agent'), $uploadId);
654 $scanJobProxy->createAgentStatus(array(
$agentName));
655 $selectedScanners = $scanJobProxy->getLatestSuccessfulAgentIds();
656 if (!array_key_exists(
$agentName, $selectedScanners)) {
659 $latestXpAgentId = $selectedScanners[
$agentName];
660 $extrawhere =
' agent_fk='.$latestXpAgentId;
661 $allCopyrights = $this->copyrightDao->getScannerEntries(
'copyright',
662 $uploadTreeTableName, $uploadId,
null, $extrawhere);
664 if (empty($allCopyrights)) {
665 echo
"No copyrights found for upload $uploadId. Skipping false positive deactivation.\n";
669 $copyrightJSON = json_encode($allCopyrights);
670 $tmpFile = tmpfile();
671 $tmpFilePath = stream_get_meta_data($tmpFile)[
'uri'];
672 fwrite($tmpFile, $copyrightJSON);
674 if (empty($deactivatedCopyrightData)) {
678 $deactivatedCopyrights = json_decode($deactivatedCopyrightData,
true);
679 foreach ($deactivatedCopyrights as $deactivatedCopyright) {
680 $item = $deactivatedCopyright[
'uploadtree_pk'];
681 $itemTreeBounds = $this->uploadDao->getItemTreeBounds($item, $uploadTreeTableName);
682 $hash = $deactivatedCopyright[
'hash'];
683 $content = $deactivatedCopyright[
'content'];
684 $cpTable =
'copyright';
685 if ($deactivatedCopyright[
'is_copyright'] ==
"t") {
687 if (array_key_exists(
'decluttered_content', $deactivatedCopyright) &&
688 !empty($deactivatedCopyright[
'decluttered_content'])) {
689 $content = $deactivatedCopyright[
'decluttered_content'];
698 $this->copyrightDao->updateTable($itemTreeBounds, $hash, $content, $this->userId, $cpTable, $action);
711 $clutter_flag): string
713 $script =
"copyrightDeactivationClutterRemovalScript.py";
714 $args = [
"python3", __DIR__ .
"/$script",
"--file", $tmpFilePath];
716 $args[] =
"--clutter";
722 $process =
new Process(
$args);
723 $process->setTimeout(
null);
730 if ($sleepTime < $maxSleepTime) {
733 }
while ($process->isRunning());
735 echo $process->getErrorOutput();
737 return $process->getOutput();
748 $licenseTypes = array_map(
'trim', explode(
',',
749 $SysConf[
'SYSCONFIG'][
'LicenseTypes']));
766 foreach ($licenseMatches as $agentMatch) {
767 foreach ($agentMatch as $agentLicenseMatches) {
768 foreach ($agentLicenseMatches as $licenseMatch) {
769 $shortnames[$licenseMatch->getLicenseId()] = $licenseMatch
770 ->getLicenseRef()->getShortName();
774 foreach ($shortnames as $shortname) {
776 if (! $this->compatibilityDao->getCompatibilityForFile($itemTreeBounds,
795 foreach ($licenseMatches as $agentMatch) {
796 foreach ($agentMatch as $agentLicenseMatches) {
797 foreach ($agentLicenseMatches as $licenseMatch) {
798 if (!array_key_exists($licenseMatch->getLicenseId(), $licenseTypes)) {
799 $licenseTypes[$licenseMatch->getLicenseId()] = $this->licenseDao
800 ->getLicenseType($licenseMatch->getLicenseId());
805 if (! in_array($this->licenseType, $licenseTypes)) {
808 if (! empty(array_diff($licenseTypes, [$this->licenseType]))) {
Agent to decide license findings in an upload.
$agentLicenseEventProcessor
existsUnhandledMatch($projectedScannerMatches, $licensesFromDecision)
Check if matches contains unhandled match.
areOtherScannerFindingsAndRESOAgreed($licenseMatches)
Check if the finding by only contains one single license and that no other scanner (nomos) has produc...
$clearingDecisionProcessor
autodecideIfResoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk, OJO and Reso findings.
processItem(Item $item)
Given an item, check with the $activeRules and apply rules to it.
areOtherScannerFindingsAndOJOAgreed($licenseMatches)
Check if the finding by only contains one single license and that no other scanner (nomos) has produc...
callCopyrightDeactivationClutterRemovalScript($tmpFilePath, $clutter_flag)
autodecideNomosMatchesInsideMonk(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches by nomos which are in monk findings.
noLicenseConflict($itemTreeBounds, $licenseMatches)
Check if findings by all agents are same or not.
autodecideNomosMonkNinka(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk and ninka findings.
processUploadId($uploadId)
Given an upload ID, process the items in it.
getLicenseType($licenseType)
allLicenseInType($licenseMatches)
Check if findings by all agents are same or not.
autodecideLicenseType(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches where there is no license conflict.
getLicenseIdsOfMatchesForScanner($scanner, $licenseMatches)
extracts the matches corresponding to a scanner from a $licenseMatches structure
isRegionIncluded($small, $big)
Check if the small highlight region is inside big one.
autodecideIfOjoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk and OJO findings.
areNomosMatchesInsideAMonkMatch($licenseMatches)
Check if matches by nomos are inside monk findings.
getCopyrightsToDisableFalsePositivesClutter($uploadId, $clutter_flag)
remapByProjectedId($matches)
Given a set of matches, remap according to project id instead of license id.
areNomosMonkNinkaAgreed($licenseMatches)
Check if findings by all agents are same or not.
autodecideIfKotobaMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $projectedScannerMatches, $currentEvents)
Auto-conclude when kotoba events cover all scanner findings.
Structure of an Agent with all required parameters.
heartbeat($newProcessed)
Send hear beat to the scheduler.
Handle events related to license findings.
Utility functions to process ClearingDecision.
Wrapper class for license map.
Exception when an agent's stage is invalid.
fo_dbManager * dbManager
fo_dbManager object
Namespace for decider agent.