FOSSology  4.7.1
Open Source License Compliance by Open Source Software
ui-clearing-view.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2017 Siemens AG
4  Author: Daniele Fognini, Johannes Najjar
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
30 use Monolog\Logger;
31 use Symfony\Component\HttpFoundation\RedirectResponse;
32 use Symfony\Component\HttpFoundation\Response;
33 
34 define("TITLE_CLEARINGVIEW", _("Change concluded License "));
35 
36 class ClearingView extends FO_Plugin
37 {
39  private $uploadDao;
41  private $licenseDao;
43  private $clearingDao;
45  private $agentsDao;
47  private $logger;
49  private $highlightDao;
51  private $highlightProcessor;
53  private $highlightRenderer;
55  private $clearingDecisionEventProcessor;
57  private $clearingDecisionFilter;
59  private $invalidParm = false;
61  private $decisionTypes;
63  private $searchChunkSize = 1048576;
65  private $searchBlockSize = 81920;
66 
67  function __construct()
68  {
69  $this->Name = "view-license";
70  $this->Title = TITLE_CLEARINGVIEW;
71  $this->DBaccess = PLUGIN_DB_WRITE;
72  $this->Dependency = array("view");
73  $this->LoginFlag = 0;
74  $this->NoMenu = 0;
75  parent::__construct();
76 
77  global $container;
78  $this->licenseDao = $container->get('dao.license');
79  $this->uploadDao = $container->get('dao.upload');
80  $this->clearingDao = $container->get('dao.clearing');
81  $this->agentsDao = $container->get('dao.agent');
82  $this->logger = $container->get("logger");
83  $this->highlightDao = $container->get("dao.highlight");
84  $this->highlightRenderer = $container->get("view.highlight_renderer");
85  $this->highlightProcessor = $container->get("view.highlight_processor");
86 
87  $this->decisionTypes = $container->get('decision.types');
88 
89  $this->clearingDecisionEventProcessor = $container->get(
90  'businessrules.clearing_decision_processor');
91  $this->clearingDecisionFilter = $container->get(
92  'businessrules.clearing_decision_filter');
93  }
94 
95 
105  public function getSelectedHighlighting(ItemTreeBounds $itemTreeBounds, $licenseId, $selectedAgentId, $highlightId, $clearingId, $uploadId)
106  {
107  $unmaskAgents = $selectedAgentId;
108  if (empty($selectedAgentId)) {
109  $scanJobProxy = new ScanJobProxy($this->agentsDao,$uploadId);
110  $scanJobProxy->createAgentStatus(array_keys(AgentRef::AGENT_LIST));
111  $unmaskAgents = $scanJobProxy->getLatestSuccessfulAgentIds();
112  }
113  $highlightEntries = $this->highlightDao->getHighlightEntries($itemTreeBounds,
114  $licenseId, $unmaskAgents, $highlightId, $clearingId);
115  $groupId = Auth::getGroupId();
116  if (($selectedAgentId > 0) || ($clearingId > 0)) {
117  $this->highlightProcessor->addReferenceTexts($highlightEntries, $groupId);
118  } else {
119  $this->highlightProcessor->flattenHighlights($highlightEntries, array("K", "K "));
120  }
121  return $highlightEntries;
122  }
123 
124  public function execute()
125  {
126  $openOutput = $this->OutputOpen();
127  if ($openOutput instanceof RedirectResponse) {
128  $response = $openOutput;
129  } else {
130  $response = $this->getResponse();
131  }
132  $response->prepare($this->getRequest());
133  $response->send();
134  }
135 
136  function OutputOpen()
137  {
138  if ($this->State != PLUGIN_STATE_READY) {
139  return (0);
140  }
141  $uploadId = GetParm("upload", PARM_INTEGER);
142  if (empty($uploadId)) {
143  return;
144  }
145 
146  $uploadTreeId = GetParm("item", PARM_INTEGER);
147  if (empty($uploadTreeId)) {
148  $parent = $this->uploadDao->getUploadParent($uploadId);
149  if (!isset($parent)) {
150  $this->invalidParm = true;
151  return;
152  }
153 
154  $item = $this->uploadDao->getNextItem($uploadId, $parent);
155  if ($item === UploadDao::NOT_FOUND) {
156  $this->invalidParm = true;
157  return;
158  }
159  $uploadTreeId = $item->getId();
160  return new RedirectResponse(Traceback_uri() . '?mod=' . $this->Name
161  . Traceback_parm_keep(array("upload", "show")) . "&item=$uploadTreeId");
162  }
163 
164  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
165  $uploadEntry = $this->uploadDao->getUploadEntry($uploadTreeId, $uploadTreeTableName);
166  if (Isdir($uploadEntry['ufile_mode']) || Iscontainer($uploadEntry['ufile_mode'])) {
167  $parent = $this->uploadDao->getUploadParent($uploadId);
168  if (!isset($parent)) {
169  $this->invalidParm = true;
170  return;
171  }
172 
173  $item = $this->uploadDao->getNextItem($uploadId, $parent);
174  if ($item === UploadDao::NOT_FOUND) {
175  $this->invalidParm = true;
176  return;
177  }
178  $uploadTreeId = $item->getId();
179  return new RedirectResponse(Traceback_uri() . '?mod=' . $this->Name
180  . Traceback_parm_keep(array("upload", "show")) . "&item=$uploadTreeId");
181  }
182 
183  return parent::OutputOpen();
184  }
185 
186 
190  function Output()
191  {
192  if ($this->invalidParm) {
193  $this->vars['content'] = 'This upload contains no files!<br><a href="'
194  . Traceback_uri() . '?mod=browse">Go back to browse view</a>';
195  return $this->render("include/base.html.twig");
196  }
197 
198  $uploadId = GetParm("upload", PARM_INTEGER);
199  if (empty($uploadId)) {
200  return new Response("", Response::HTTP_BAD_REQUEST);
201  }
202  $uploadTreeId = GetParm("item", PARM_INTEGER);
203  if (empty($uploadTreeId)) {
204  return new Response("", Response::HTTP_BAD_REQUEST);
205  }
206 
207  $userId = Auth::getUserId();
208  $groupId = Auth::getGroupId();
209 
210  $lastItem = GetParm("lastItem", PARM_INTEGER);
211 
212  if (!empty($lastItem)) {
213  $currentUploadtreeId = $lastItem;
214  if ($lastItem == $uploadTreeId) {
215  $currentUploadtreeId = $uploadTreeId;
216  }
217  $this->updateLastItem($userId, $groupId, $lastItem, $currentUploadtreeId);
218  }
219 
220  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
221  $itemTreeBounds = $this->uploadDao->getItemTreeBounds($uploadTreeId, $uploadTreeTableName);
222 
223  $this->vars['micromenu'] = Dir2Browse('license', $uploadTreeId, NULL,
224  $showBox = 0, "View", -1, '', '', $uploadTreeTableName);
225 
226  global $Plugins;
228  $view = &$Plugins[plugin_find_id("view")];
229 
230  $licenseId = GetParm("licenseId", PARM_INTEGER);
231  $selectedAgentId = GetParm("agentId", PARM_INTEGER);
232  $highlightId = GetParm("highlightId", PARM_INTEGER);
233  $clearingId = GetParm("clearingId", PARM_INTEGER);
234 
235  $searchQuery = GetParm("search", PARM_STRING);
236  $this->vars['searchQuery'] = $searchQuery;
237  $this->vars['searchMatches'] = [];
238  $this->vars['currentPage'] = GetParm("page", PARM_INTEGER) ?: 0;
239 
240  if ($clearingId !== null) {
241  $highlightId = -1;
242  } else if ($highlightId !== null) {
243  $clearingId = -1;
244  }
245 
246  $baseUri = Traceback_uri();
247  $this->vars['baseuri'] = $baseUri;
248  $this->vars['uri'] = $baseUri . "?mod=" . $this->Name . Traceback_parm_keep(array('upload', 'folder'));
249  $this->vars['bulkHistoryHighlightUri'] = $this->vars['uri'];
250  $this->vars['optionName'] = "skipFile";
251  $this->vars['formName'] = "uiClearingForm";
252  $this->vars['ajaxAction'] = "setNextPrev";
253  $highlights = $this->getSelectedHighlighting($itemTreeBounds, $licenseId,
254  $selectedAgentId, $highlightId, $clearingId, $uploadId);
255  if (empty($searchQuery)) {
256  $request = $this->getRequest();
257  if ($request) {
258  $searchQuery = $request->query->get('search', '');
259  }
260  }
261  if (!empty($searchQuery)) {
262  $searchQuery = trim($searchQuery);
263  if (strlen($searchQuery) < 3) {
264  $this->vars['searchMatches'] = [];
265  } else {
266  $item = GetParm("item", PARM_INTEGER);
267  $filePath = RepPathItem($item);
268 
269  if ($filePath && file_exists($filePath)) {
270  $this->vars['searchMatches'] = $this->getSearchMatches($filePath, $searchQuery, $this->searchBlockSize);
271  } else {
272  $this->vars['searchMatches'] = [];
273  }
274  }
275  }
276 
277  $isSingleFile = !$itemTreeBounds->containsFiles();
278  $hasWritePermission = $this->uploadDao->isEditable($uploadId, $groupId);
279 
280  $clearingDecisions = null;
281  if ($isSingleFile || $hasWritePermission) {
282  $clearingDecisions = $this->clearingDao->getFileClearings($itemTreeBounds, $groupId, false);
283  }
284 
285  if ($isSingleFile && $hasWritePermission) {
286  $this->vars['bulkUri'] = Traceback_uri() . "?mod=popup-license";
287  $licenseArray = $this->licenseDao->getLicenseArray($groupId);
288  list($addedResults, $removedResults) = $this->clearingDecisionEventProcessor->getCurrentClearings($itemTreeBounds, $groupId, LicenseMap::CONCLUSION);
289  if (count($addedResults)+count($removedResults)>0) {
290  array_unshift($licenseArray, array('id'=>0,'fullname'=>'','shortname'=>'------'));
291  }
293  foreach ($removedResults as $result) {
294  array_unshift($licenseArray, array( 'id'=>$result->getLicenseId() ,'fullname'=>$result->getLicenseFullName() ,'shortname'=>$result->getLicenseShortName()));
295  }
297  foreach ($addedResults as $result) {
298  array_unshift($licenseArray, array( 'id'=>$result->getLicenseId() ,'fullname'=>$result->getLicenseFullName() ,'shortname'=>$result->getLicenseShortName()));
299  }
300  $this->vars['licenseArray'] = $licenseArray;
301  } elseif ($isSingleFile) {
302  $this->vars['auditDenied'] = true;
303  }
304 
305  $selectedClearingType = false;
306  $selectedClearingScope = false;
307  if (!empty($clearingDecisions)) {
308  $selectedClearingType = $clearingDecisions[0]->getType();
309  $selectedClearingScope = $clearingDecisions[0]->getScope();
310  }
311  $bulkHistory = $this->clearingDao->getBulkHistory($itemTreeBounds, $groupId);
312  $hasKotobaFindings = $this->clearingDao->hasKotobaFindings($itemTreeBounds, $groupId);
313  $kotobaHistory = array();
314  if ($hasKotobaFindings) {
315  $kotobaHistory = $this->clearingDao->getKotobaHistory($itemTreeBounds, $groupId);
316  }
317 
318  $ModBack = GetParm("modback", PARM_STRING) ?: "license";
319  list($pageMenu, $textView) = $view->getView(NULL, $ModBack, 0, "", $highlights, false, true);
320 
321  $this->vars['uploadId'] = $uploadId;
322  $this->vars['itemId'] = $uploadTreeId;
323  $this->vars['pageMenu'] = $pageMenu;
324  $this->vars['textView'] = $textView;
325  $this->vars['legendData'] = $this->highlightRenderer->getLegendData($selectedAgentId || $clearingId);
326  $this->vars['clearingTypes'] = $this->decisionTypes->getMap();
327  $this->vars['selectedClearingType'] = $selectedClearingType;
328  $this->vars['selectedClearingScope'] = $selectedClearingScope;
329  $this->vars['tmpClearingType'] = $this->clearingDao->isDecisionCheck($uploadTreeId, $groupId, DecisionTypes::WIP);
330  $this->vars['bulkHistory'] = $bulkHistory;
331  $this->vars['hasKotobaFindings'] = $hasKotobaFindings;
332  $this->vars['kotobaHistory'] = $kotobaHistory;
333 
334  $noLicenseUploadTreeView = new UploadTreeProxy($uploadId,
335  array(UploadTreeProxy::OPT_SKIP_THESE => "noLicense",
336  UploadTreeProxy::OPT_GROUP_ID => $groupId),
337  $uploadTreeTableName,
338  'no_license_uploadtree' . $uploadId);
339  $filesOfInterest = $noLicenseUploadTreeView->count();
340 
341  $nonClearedUploadTreeView = new UploadTreeProxy($uploadId,
342  array(UploadTreeProxy::OPT_SKIP_THESE => "alreadyCleared",
343  UploadTreeProxy::OPT_GROUP_ID => $groupId),
344  $uploadTreeTableName,
345  'already_cleared_uploadtree' . $uploadId);
346  $filesToBeCleared = $nonClearedUploadTreeView->count();
347 
348  $filesAlreadyCleared = $filesOfInterest - $filesToBeCleared;
349  $this->vars['message'] = _("Cleared").": $filesAlreadyCleared/$filesOfInterest";
350  if ($filesOfInterest == 0) {
351  $percentage = 100;
352  } else {
353  $percentage = ($filesAlreadyCleared / $filesOfInterest) * 100;
354  $percentage = ($percentage > 11) ? $percentage : 11;
355  }
356  $this->vars['progressBar'] = "width:".$percentage."%";
357 
358  return $this->render("ui-clearing-view.html.twig");
359  }
360 
361  /*
362  * \brief Customize submenus.
363  */
364  function RegisterMenus()
365  {
366  $menuText="Licenses";
367  $menuPosition = 58;
368  $uri = $this->Name . Traceback_parm_keep(array("upload", "item", "show"));
369  $tooltipText = _("Set the concluded licenses for this upload");
370  $this->microMenu->insert(array(MicroMenu::VIEW, MicroMenu::VIEW_META), $menuText, $menuPosition, $this->Name, $uri, $tooltipText );
371 
372  if (GetParm("mod", PARM_STRING) != $this->Name) {
373  menu_insert("Browse-Pfile::$menuText", 0, $this->Name, $tooltipText);
374  }
375  return 0;
376  }
377 
385  public function updateLastItem($userId, $groupId, $lastItem, $currentUploadtreeId)
386  {
387  $type = GetParm("clearingTypes", PARM_INTEGER);
388  $global = GetParm("globalDecision", PARM_STRING) === "on" ? 1 : 0;
389  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($lastItem);
390  $itemBounds = $this->uploadDao->getItemTreeBounds($lastItem, $uploadTreeTableName);
391  if ($global) {
392  $isDecisionWip = $this->clearingDao->isDecisionCheck($currentUploadtreeId, $groupId, DecisionTypes::WIP);
393  $hasChangedClearingType = $this->clearingDao->isDecisionCheck($currentUploadtreeId, $groupId, '');
394  if ($isDecisionWip) {
395  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
396  } else if (empty($hasChangedClearingType['scope'])
397  || ($hasChangedClearingType['decision_type'] != $type)
398  ) {
399  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
400  } else {
401  return;
402  }
403  } else {
404  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
405  }
406  }
407 
414  private function getSearchMatches($filePath, $searchQuery, $blockSize = 81920)
415  {
416  $handle = fopen($filePath, "rb");
417  if (!$handle) {
418  return [];
419  }
420 
421  $searchMatches = [];
422  $searchLen = strlen($searchQuery);
423  $currentFilePos = 0;
424  $overlapBuffer = '';
425 
426  $pattern = '/' . preg_quote($searchQuery, '/') . '/i';
427 
428  while (!feof($handle)) {
429  $chunk = fread($handle, $this->searchChunkSize);
430  $haystack = $overlapBuffer . $chunk;
431 
432  if (preg_match_all($pattern, $haystack, $matches, PREG_OFFSET_CAPTURE)) {
433  foreach ($matches[0] as $match) {
434  $posInHaystack = $match[1];
435  $absolutePos = $currentFilePos - strlen($overlapBuffer) + $posInHaystack;
436 
437  if (empty($searchMatches) || end($searchMatches)['position'] !== $absolutePos) {
438  $searchMatches[] = [
439  'position' => $absolutePos,
440  'page' => (int)floor($absolutePos / $blockSize)
441  ];
442  }
443  }
444  }
445 
446  $overlapBuffer = ($searchLen > 1) ? substr($haystack, -($searchLen - 1)) : '';
447  $currentFilePos += strlen($chunk);
448  }
449 
450  fclose($handle);
451  return $searchMatches;
452  }
453 }
454 
455 $NewPlugin = new ClearingView;
getSelectedHighlighting(ItemTreeBounds $itemTreeBounds, $licenseId, $selectedAgentId, $highlightId, $clearingId, $uploadId)
RegisterMenus()
While menus can be added to any time at or after the PostInitialize phase, this is the standard locat...
OutputOpen()
This function is called when user output is requested. This function is responsible for assigning hea...
getSearchMatches($filePath, $searchQuery, $blockSize=81920)
updateLastItem($userId, $groupId, $lastItem, $currentUploadtreeId)
__construct()
base constructor. Most plugins will just use this
This is the Plugin class. All plugins should:
Definition: FO_Plugin.php:57
Output()
This function is called when user output is requested. This function is responsible for content....
Definition: FO_Plugin.php:399
render($templateName, $vars=null)
Definition: FO_Plugin.php:434
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
Various utility functions to filter ClearingDecision.
Utility functions to process ClearingDecision.
Wrapper class for license map.
Definition: LicenseMap.php:19
Definition: state.hpp:16
Isdir($mode)
Definition: common-dir.php:20
Iscontainer($mode)
Definition: common-dir.php:38
Dir2Browse($Mod, $UploadtreePk, $LinkLast=NULL, $ShowBox=1, $ShowMicro=NULL, $Enumerate=-1, $PreText='', $PostText='', $uploadtree_tablename="uploadtree")
Get an html linked string of a file browse path.
Definition: common-dir.php:263
menu_insert($Path, $LastOrder=0, $URI=NULL, $Title=NULL, $Target=NULL, $HTML=NULL)
Given a Path, order level for the last item, and optional plugin name, insert the menu item.
Traceback_uri()
Get the URI without query to this location.
Definition: common-parm.php:97
const PARM_INTEGER
Definition: common-parm.php:14
const PARM_STRING
Definition: common-parm.php:18
GetParm($parameterName, $parameterType)
This function will retrieve the variables and check data types.
Definition: common-parm.php:46
Traceback_parm_keep($List)
Create a new URI, keeping only these items.
RepPathItem($Item, $Repo="files")
Given an uploadtree_pk, retrieve the pfile path.
Definition: common-repo.php:91
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:690
#define PLUGIN_DB_WRITE
Plugin requires write permission on DB.
Definition: libfossology.h:38