FOSSology  4.6.0
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 
313  $ModBack = GetParm("modback", PARM_STRING) ?: "license";
314  list($pageMenu, $textView) = $view->getView(NULL, $ModBack, 0, "", $highlights, false, true);
315 
316  $this->vars['uploadId'] = $uploadId;
317  $this->vars['itemId'] = $uploadTreeId;
318  $this->vars['pageMenu'] = $pageMenu;
319  $this->vars['textView'] = $textView;
320  $this->vars['legendData'] = $this->highlightRenderer->getLegendData($selectedAgentId || $clearingId);
321  $this->vars['clearingTypes'] = $this->decisionTypes->getMap();
322  $this->vars['selectedClearingType'] = $selectedClearingType;
323  $this->vars['selectedClearingScope'] = $selectedClearingScope;
324  $this->vars['tmpClearingType'] = $this->clearingDao->isDecisionCheck($uploadTreeId, $groupId, DecisionTypes::WIP);
325  $this->vars['bulkHistory'] = $bulkHistory;
326 
327  $noLicenseUploadTreeView = new UploadTreeProxy($uploadId,
328  array(UploadTreeProxy::OPT_SKIP_THESE => "noLicense",
329  UploadTreeProxy::OPT_GROUP_ID => $groupId),
330  $uploadTreeTableName,
331  'no_license_uploadtree' . $uploadId);
332  $filesOfInterest = $noLicenseUploadTreeView->count();
333 
334  $nonClearedUploadTreeView = new UploadTreeProxy($uploadId,
335  array(UploadTreeProxy::OPT_SKIP_THESE => "alreadyCleared",
336  UploadTreeProxy::OPT_GROUP_ID => $groupId),
337  $uploadTreeTableName,
338  'already_cleared_uploadtree' . $uploadId);
339  $filesToBeCleared = $nonClearedUploadTreeView->count();
340 
341  $filesAlreadyCleared = $filesOfInterest - $filesToBeCleared;
342  $this->vars['message'] = _("Cleared").": $filesAlreadyCleared/$filesOfInterest";
343  if ($filesOfInterest == 0) {
344  $percentage = 100;
345  } else {
346  $percentage = ($filesAlreadyCleared / $filesOfInterest) * 100;
347  $percentage = ($percentage > 11) ? $percentage : 11;
348  }
349  $this->vars['progressBar'] = "width:".$percentage."%";
350 
351  return $this->render("ui-clearing-view.html.twig");
352  }
353 
354  /*
355  * \brief Customize submenus.
356  */
357  function RegisterMenus()
358  {
359  $menuText="Licenses";
360  $menuPosition = 58;
361  $uri = $this->Name . Traceback_parm_keep(array("upload", "item", "show"));
362  $tooltipText = _("Set the concluded licenses for this upload");
363  $this->microMenu->insert(array(MicroMenu::VIEW, MicroMenu::VIEW_META), $menuText, $menuPosition, $this->Name, $uri, $tooltipText );
364 
365  if (GetParm("mod", PARM_STRING) != $this->Name) {
366  menu_insert("Browse-Pfile::$menuText", 0, $this->Name, $tooltipText);
367  }
368  return 0;
369  }
370 
378  public function updateLastItem($userId, $groupId, $lastItem, $currentUploadtreeId)
379  {
380  $type = GetParm("clearingTypes", PARM_INTEGER);
381  $global = GetParm("globalDecision", PARM_STRING) === "on" ? 1 : 0;
382  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($lastItem);
383  $itemBounds = $this->uploadDao->getItemTreeBounds($lastItem, $uploadTreeTableName);
384  if ($global) {
385  $isDecisionWip = $this->clearingDao->isDecisionCheck($currentUploadtreeId, $groupId, DecisionTypes::WIP);
386  $hasChangedClearingType = $this->clearingDao->isDecisionCheck($currentUploadtreeId, $groupId, '');
387  if ($isDecisionWip) {
388  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
389  } else if (empty($hasChangedClearingType['scope'])
390  || ($hasChangedClearingType['decision_type'] != $type)
391  ) {
392  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
393  } else {
394  return;
395  }
396  } else {
397  $this->clearingDecisionEventProcessor->makeDecisionFromLastEvents($itemBounds, $userId, $groupId, $type, $global);
398  }
399  }
400 
407  private function getSearchMatches($filePath, $searchQuery, $blockSize = 81920)
408  {
409  $handle = fopen($filePath, "rb");
410  if (!$handle) {
411  return [];
412  }
413 
414  $searchMatches = [];
415  $searchLen = strlen($searchQuery);
416  $currentFilePos = 0;
417  $overlapBuffer = '';
418 
419  $pattern = '/' . preg_quote($searchQuery, '/') . '/i';
420 
421  while (!feof($handle)) {
422  $chunk = fread($handle, $this->searchChunkSize);
423  $haystack = $overlapBuffer . $chunk;
424 
425  if (preg_match_all($pattern, $haystack, $matches, PREG_OFFSET_CAPTURE)) {
426  foreach ($matches[0] as $match) {
427  $posInHaystack = $match[1];
428  $absolutePos = $currentFilePos - strlen($overlapBuffer) + $posInHaystack;
429 
430  if (empty($searchMatches) || end($searchMatches)['position'] !== $absolutePos) {
431  $searchMatches[] = [
432  'position' => $absolutePos,
433  'page' => (int)floor($absolutePos / $blockSize)
434  ];
435  }
436  }
437  }
438 
439  $overlapBuffer = ($searchLen > 1) ? substr($haystack, -($searchLen - 1)) : '';
440  $currentFilePos += strlen($chunk);
441  }
442 
443  fclose($handle);
444  return $searchMatches;
445  }
446 }
447 
448 $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