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['kotobaHistoryHighlightUri'] = $this->vars['uri'];
251  $this->vars['optionName'] = "skipFile";
252  $this->vars['formName'] = "uiClearingForm";
253  $this->vars['ajaxAction'] = "setNextPrev";
254  $highlights = $this->getSelectedHighlighting($itemTreeBounds, $licenseId,
255  $selectedAgentId, $highlightId, $clearingId, $uploadId);
256  if (empty($searchQuery)) {
257  $request = $this->getRequest();
258  if ($request) {
259  $searchQuery = $request->query->get('search', '');
260  }
261  }
262  if (!empty($searchQuery)) {
263  $searchQuery = trim($searchQuery);
264  if (strlen($searchQuery) < 3) {
265  $this->vars['searchMatches'] = [];
266  } else {
267  $item = GetParm("item", PARM_INTEGER);
268  $filePath = RepPathItem($item);
269 
270  if ($filePath && file_exists($filePath)) {
271  $this->vars['searchMatches'] = $this->getSearchMatches($filePath, $searchQuery, $this->searchBlockSize);
272  } else {
273  $this->vars['searchMatches'] = [];
274  }
275  }
276  }
277 
278  $isSingleFile = !$itemTreeBounds->containsFiles();
279  $hasWritePermission = $this->uploadDao->isEditable($uploadId, $groupId);
280 
281  $clearingDecisions = null;
282  if ($isSingleFile || $hasWritePermission) {
283  $clearingDecisions = $this->clearingDao->getFileClearings($itemTreeBounds, $groupId, false);
284  }
285 
286  if ($isSingleFile && $hasWritePermission) {
287  $this->vars['bulkUri'] = Traceback_uri() . "?mod=popup-license";
288  $licenseArray = $this->licenseDao->getLicenseArray($groupId);
289  list($addedResults, $removedResults) = $this->clearingDecisionEventProcessor->getCurrentClearings($itemTreeBounds, $groupId, LicenseMap::CONCLUSION);
290  if (count($addedResults)+count($removedResults)>0) {
291  array_unshift($licenseArray, array('id'=>0,'fullname'=>'','shortname'=>'------'));
292  }
294  foreach ($removedResults as $result) {
295  array_unshift($licenseArray, array( 'id'=>$result->getLicenseId() ,'fullname'=>$result->getLicenseFullName() ,'shortname'=>$result->getLicenseShortName()));
296  }
298  foreach ($addedResults as $result) {
299  array_unshift($licenseArray, array( 'id'=>$result->getLicenseId() ,'fullname'=>$result->getLicenseFullName() ,'shortname'=>$result->getLicenseShortName()));
300  }
301  $this->vars['licenseArray'] = $licenseArray;
302  } elseif ($isSingleFile) {
303  $this->vars['auditDenied'] = true;
304  }
305 
306  $selectedClearingType = false;
307  $selectedClearingScope = false;
308  if (!empty($clearingDecisions)) {
309  $selectedClearingType = $clearingDecisions[0]->getType();
310  $selectedClearingScope = $clearingDecisions[0]->getScope();
311  }
312  $bulkHistory = $this->clearingDao->getBulkHistory($itemTreeBounds, $groupId);
313  $hasKotobaFindings = $this->clearingDao->hasKotobaFindings($itemTreeBounds, $groupId);
314  $kotobaHistory = array();
315  if ($hasKotobaFindings) {
316  $kotobaHistory = $this->clearingDao->getKotobaHistory($itemTreeBounds, $groupId);
317  }
318 
319  $ModBack = GetParm("modback", PARM_STRING) ?: "license";
320  list($pageMenu, $textView) = $view->getView(NULL, $ModBack, 0, "", $highlights, false, true);
321 
322  $this->vars['uploadId'] = $uploadId;
323  $this->vars['itemId'] = $uploadTreeId;
324  $this->vars['pageMenu'] = $pageMenu;
325  $this->vars['textView'] = $textView;
326  $this->vars['legendData'] = $this->highlightRenderer->getLegendData($selectedAgentId || $clearingId);
327  $this->vars['clearingTypes'] = $this->decisionTypes->getMap();
328  $this->vars['selectedClearingType'] = $selectedClearingType;
329  $this->vars['selectedClearingScope'] = $selectedClearingScope;
330  $this->vars['tmpClearingType'] = $this->clearingDao->isDecisionCheck($uploadTreeId, $groupId, DecisionTypes::WIP);
331  $this->vars['bulkHistory'] = $bulkHistory;
332  $this->vars['hasKotobaFindings'] = $hasKotobaFindings;
333  $this->vars['kotobaHistory'] = $kotobaHistory;
334  $this->vars['isAdmin'] = Auth::isAdmin();
335 
336  $noLicenseUploadTreeView = new UploadTreeProxy($uploadId,
337  array(UploadTreeProxy::OPT_SKIP_THESE => "noLicense",
338  UploadTreeProxy::OPT_GROUP_ID => $groupId),
339  $uploadTreeTableName,
340  'no_license_uploadtree' . $uploadId);
341  $filesOfInterest = $noLicenseUploadTreeView->count();
342 
343  $nonClearedUploadTreeView = new UploadTreeProxy($uploadId,
344  array(UploadTreeProxy::OPT_SKIP_THESE => "alreadyCleared",
345  UploadTreeProxy::OPT_GROUP_ID => $groupId),
346  $uploadTreeTableName,
347  'already_cleared_uploadtree' . $uploadId);
348  $filesToBeCleared = $nonClearedUploadTreeView->count();
349 
350  $filesAlreadyCleared = $filesOfInterest - $filesToBeCleared;
351  $this->vars['message'] = _("Cleared").": $filesAlreadyCleared/$filesOfInterest";
352  if ($filesOfInterest == 0) {
353  $percentage = 100;
354  } else {
355  $percentage = ($filesAlreadyCleared / $filesOfInterest) * 100;
356  $percentage = ($percentage > 11) ? $percentage : 11;
357  }
358  $this->vars['progressBar'] = "width:".$percentage."%";
359 
360  return $this->render("ui-clearing-view.html.twig");
361  }
362 
363  /*
364  * \brief Customize submenus.
365  */
366  function RegisterMenus()
367  {
368  $menuText="Licenses";
369  $menuPosition = 58;
370  $uri = $this->Name . Traceback_parm_keep(array("upload", "item", "show"));
371  $tooltipText = _("Set the concluded licenses for this upload");
372  $this->microMenu->insert(array(MicroMenu::VIEW, MicroMenu::VIEW_META), $menuText, $menuPosition, $this->Name, $uri, $tooltipText );
373 
374  if (GetParm("mod", PARM_STRING) != $this->Name) {
375  menu_insert("Browse-Pfile::$menuText", 0, $this->Name, $tooltipText);
376  }
377  return 0;
378  }
379 
387  public function updateLastItem($userId, $groupId, $lastItem, $currentUploadtreeId)
388  {
389  $type = GetParm("clearingTypes", PARM_INTEGER);
390  $global = GetParm("globalDecision", PARM_STRING) === "on" ? 1 : 0;
391  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($lastItem);
392  $itemBounds = $this->uploadDao->getItemTreeBounds($lastItem, $uploadTreeTableName);
393  if ($global) {
394  $isDecisionWip = $this->clearingDao->isDecisionCheck($currentUploadtreeId, $groupId, DecisionTypes::WIP);
395  $hasChangedClearingType = $this->clearingDao->isDecisionCheck($currentUploadtreeId, $groupId, '');
396  if ($isDecisionWip) {
397  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
398  } else if (empty($hasChangedClearingType['scope'])
399  || ($hasChangedClearingType['decision_type'] != $type)
400  ) {
401  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
402  } else {
403  return;
404  }
405  } else {
406  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
407  }
408  }
409 
416  private function getSearchMatches($filePath, $searchQuery, $blockSize = 81920)
417  {
418  $handle = fopen($filePath, "rb");
419  if (!$handle) {
420  return [];
421  }
422 
423  $searchMatches = [];
424  $searchLen = strlen($searchQuery);
425  $currentFilePos = 0;
426  $overlapBuffer = '';
427 
428  $pattern = '/' . preg_quote($searchQuery, '/') . '/i';
429 
430  while (!feof($handle)) {
431  $chunk = fread($handle, $this->searchChunkSize);
432  $haystack = $overlapBuffer . $chunk;
433 
434  if (preg_match_all($pattern, $haystack, $matches, PREG_OFFSET_CAPTURE)) {
435  foreach ($matches[0] as $match) {
436  $posInHaystack = $match[1];
437  $absolutePos = $currentFilePos - strlen($overlapBuffer) + $posInHaystack;
438 
439  if (empty($searchMatches) || end($searchMatches)['position'] !== $absolutePos) {
440  $searchMatches[] = [
441  'position' => $absolutePos,
442  'page' => (int)floor($absolutePos / $blockSize)
443  ];
444  }
445  }
446  }
447 
448  $overlapBuffer = ($searchLen > 1) ? substr($haystack, -($searchLen - 1)) : '';
449  $currentFilePos += strlen($chunk);
450  }
451 
452  fclose($handle);
453  return $searchMatches;
454  }
455 }
456 
457 $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