FOSSology  4.4.0
Open Source License Compliance by Open Source Software
AjaxExplorer.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2008-2015 Hewlett-Packard Development Company, L.P.
4  SPDX-FileCopyrightText: © 2014-2017, 2020 Siemens AG
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 namespace Fossology\UI\Ajax;
10 
11 use ClearingView;
26 use Symfony\Component\HttpFoundation\JsonResponse;
27 use Symfony\Component\HttpFoundation\Request;
28 use Symfony\Component\HttpFoundation\Response;
30 
37 {
38  const NAME = "ajax_explorer";
39 
40  private $uploadtree_tablename = "";
42  private $uploadDao;
44  private $licenseDao;
46  private $clearingDao;
48  private $agentDao;
50  private $clearingFilter;
52  private $licenseProjector;
54  private $filesThatShouldStillBeCleared;
56  private $filesToBeCleared;
64  protected $agentNames = AgentRef::AGENT_LIST;
68 
69  public function __construct()
70  {
71  parent::__construct(self::NAME, array(
72  self::TITLE => _("Ajax: License Browser"),
73  self::DEPENDENCIES => array("license"),
74  self::PERMISSION => Auth::PERM_READ,
75  self::REQUIRES_LOGIN => false
76  ));
77 
78  $this->uploadDao = $this->getObject('dao.upload');
79  $this->licenseDao = $this->getObject('dao.license');
80  $this->clearingDao = $this->getObject('dao.clearing');
81  $this->agentDao = $this->getObject('dao.agent');
82  $this->clearingFilter = $this->getObject('businessrules.clearing_decision_filter');
83  $this->filesThatShouldStillBeCleared = [];
84  $this->filesToBeCleared = [];
85  $this->alreadyClearedUploadTreeView = NULL;
86  $this->noLicenseUploadTreeView = NULL;
87  $this->cacheClearedCounter = [];
88  }
89 
90  public function __destruct()
91  {
92  // Destruct the proxy views before exiting
93  if ($this->alreadyClearedUploadTreeView !== NULL) {
94  $this->alreadyClearedUploadTreeView->unmaterialize();
95  }
96  if ($this->noLicenseUploadTreeView !== NULL) {
97  $this->noLicenseUploadTreeView->unmaterialize();
98  }
99  }
100 
105  public function handle(Request $request)
106  {
107  $upload = intval($request->get("upload"));
108  $groupId = Auth::getGroupId();
109  if (!$this->uploadDao->isAccessible($upload, $groupId)) {
110  throw new \Exception("Permission Denied");
111  }
112 
113  $item = intval($request->get("item"));
114  $this->uploadtree_tablename = $this->uploadDao->getUploadtreeTableName($upload);
115  $itemTreeBounds = $this->uploadDao->getItemTreeBounds($item, $this->uploadtree_tablename);
116  $left = $itemTreeBounds->getLeft();
117  if (empty($left)) {
118  throw new \Exception("Job unpack/adj2nest hasn't completed.");
119  }
120 
121  $scannerAgents = array_keys($this->agentNames);
122  $scanJobProxy = new ScanJobProxy($this->agentDao, $upload);
123  $scanJobProxy->createAgentStatus($scannerAgents);
124  $selectedAgentId = intval($request->get('agentId'));
125  $tag_pk = intval($request->get('tag'));
126 
127  $UniqueTagArray = array();
128  $this->licenseProjector = new LicenseMap($this->getObject('db.manager'),$groupId,LicenseMap::CONCLUSION,true);
129  $vars = $this->createFileListing($tag_pk, $itemTreeBounds, $UniqueTagArray, $selectedAgentId, $groupId, $scanJobProxy, $request);
130 
131  return new JsonResponse(array(
132  'sEcho' => intval($request->get('sEcho')),
133  'aaData' => $vars['fileData'],
134  'iTotalRecords' => intval($request->get('totalRecords')),
135  'iTotalDisplayRecords' => $vars['iTotalDisplayRecords']
136  ) );
137  }
138 
139 
150  private function createFileListing($tagId, ItemTreeBounds $itemTreeBounds, &$UniqueTagArray, $selectedAgentId, $groupId, $scanJobProxy, $request)
151  {
152  if (!empty($selectedAgentId)) {
153  $agentName = $this->agentDao->getAgentName($selectedAgentId);
154  $selectedScanners = array($agentName=>$selectedAgentId);
155  } else {
156  $selectedScanners = $scanJobProxy->getLatestSuccessfulAgentIds();
157  }
158 
160  $uploadId = $itemTreeBounds->getUploadId();
161  $isFlat = $request->get('flatten') !== null;
162 
163  if ($isFlat) {
164  $options = array(UploadTreeProxy::OPT_RANGE => $itemTreeBounds);
165  } else {
166  $options = array(UploadTreeProxy::OPT_REALPARENT => $itemTreeBounds->getItemId());
167  }
168 
169  $searchMap = array();
170  foreach (explode(' ',$request->get('sSearch')) as $pair) {
171  $a = explode(':',$pair);
172  if (count($a) == 1) {
173  $searchMap['head'] = $pair;
174  } else {
175  $searchMap[$a[0]] = $a[1];
176  }
177  }
178 
179  if (array_key_exists('ext', $searchMap) && strlen($searchMap['ext'])>=1) {
180  $options[UploadTreeProxy::OPT_EXT] = $searchMap['ext'];
181  }
182  if (array_key_exists('head', $searchMap) && strlen($searchMap['head'])>=1) {
183  $options[UploadTreeProxy::OPT_HEAD] = $searchMap['head'];
184  }
185  if (($rfId=$request->get('scanFilter'))>0) {
186  $options[UploadTreeProxy::OPT_AGENT_SET] = $selectedScanners;
187  $options[UploadTreeProxy::OPT_SCAN_REF] = $rfId;
188  }
189  if (($rfId=$request->get('conFilter'))>0) {
190  $options[UploadTreeProxy::OPT_GROUP_ID] = Auth::getGroupId();
191  $options[UploadTreeProxy::OPT_CONCLUDE_REF] = $rfId;
192  }
193  $openFilter = $request->get('openCBoxFilter');
194  if ($openFilter=='true' || $openFilter=='checked') {
195  $options[UploadTreeProxy::OPT_AGENT_SET] = $selectedScanners;
196  $options[UploadTreeProxy::OPT_GROUP_ID] = Auth::getGroupId();
197  $options[UploadTreeProxy::OPT_SKIP_ALREADY_CLEARED] = true;
198  }
199 
200  $descendantView = new UploadTreeProxy($uploadId, $options, $itemTreeBounds->getUploadTreeTableName(), 'uberItems');
201 
202  $vars['iTotalDisplayRecords'] = $descendantView->count();
203 
204  $columnNamesInDatabase = array($isFlat?'ufile_name':'lft');
205  $defaultOrder = array(array(0, "asc"));
206 
207  $orderString = $this->getObject('utils.data_tables_utility')->getSortingString($request->get('fromRest') ? $request->request->all(): $request->query->all(), $columnNamesInDatabase, $defaultOrder);
208 
209  $offset = $request->get('iDisplayStart');
210  $limit = $request->get('iDisplayLength');
211  if ($offset) {
212  $orderString .= " OFFSET $offset";
213  }
214  if ($limit) {
215  $orderString .= " LIMIT $limit";
216  }
217 
218  /* Get ALL the items under this Uploadtree_pk */
219  $sql = $descendantView->getDbViewQuery()." $orderString";
220  $dbManager = $this->getObject('db.manager');
221 
222  $dbManager->prepare($stmt=__METHOD__.$orderString,$sql);
223  $res = $dbManager->execute($stmt,$descendantView->getParams());
224  $descendants = $dbManager->fetchAll($res);
225  $dbManager->freeResult($res);
226 
227  /* Filter out Children that don't have tag */
228  if (!empty($tagId)) {
229  TagFilter($descendants, $tagId, $itemTreeBounds->getUploadTreeTableName());
230  }
231  if (empty($descendants)) {
232  $vars['fileData'] = array();
233  return $vars;
234  }
235 
236  if ($isFlat) {
237  $firstChild = reset($descendants);
238  $lastChild = end($descendants);
239  $nameRange = array($firstChild['ufile_name'],$lastChild['ufile_name']);
240  } else {
241  $nameRange = array();
242  }
243 
244  $allDecisions = $this->clearingDao->getFileClearingsFolder($itemTreeBounds, $groupId, $isFlat);
245  $editedMappedLicenses = $this->clearingFilter->filterCurrentClearingDecisions($allDecisions);
246 
247  $pfileLicenses = $this->updateTheFindingsAndDecisions($selectedScanners,
248  $isFlat, $groupId, $editedMappedLicenses, $itemTreeBounds, $nameRange);
249 
250  $baseUri = Traceback_uri().'?mod=license'.Traceback_parm_keep(array('upload','folder','show'));
251 
252  $tableData = array();
253  global $Plugins;
254  $ModLicView = &$Plugins[plugin_find_id("view-license")];
255  $latestSuccessfulAgentIds = $scanJobProxy->getLatestSuccessfulAgentIds();
256  foreach ($descendants as $child) {
257  if (empty($child)) {
258  continue;
259  }
260  $tableData[] = $this->createFileDataRow($child, $uploadId, $selectedAgentId, $pfileLicenses, $groupId, $editedMappedLicenses, $baseUri, $ModLicView, $UniqueTagArray, $isFlat, $latestSuccessfulAgentIds, $request);
261  }
262 
263  $vars['fileData'] = $tableData;
264  return $vars;
265  }
266 
267 
283  private function createFileDataRow($child, $uploadId, $selectedAgentId, $pfileLicenses, $groupId, $editedMappedLicenses, $uri, $ModLicView, &$UniqueTagArray, $isFlat, $latestSuccessfulAgentIds, $request)
284  {
285  $fileDetails = array(
286  "fileName" => "", "id" => "", "uploadId" => $uploadId, "agentId" => "", "isContainer" => false,
287  );
288 
289  $fileId = $child['pfile_fk'];
290  $childUploadTreeId = $child['uploadtree_pk'];
291  $linkUri = '';
292  if (!empty($fileId) && !empty($ModLicView)) {
293  $linkUri = Traceback_uri();
294  $linkUri .= "?mod=view-license&upload=$uploadId&item=$childUploadTreeId";
295  $fileDetails["id"] = intval($childUploadTreeId);
296  $fileDetails["uploadId"] = $uploadId;
297  if ($selectedAgentId) {
298  $linkUri .= "&agentId=$selectedAgentId";
299  $fileDetails["agentId"] = $selectedAgentId;
300  }
301  }
302 
303  /* Determine link for containers */
304  $isContainer = Iscontainer($child['ufile_mode']);
305  if ($isContainer && !$isFlat) {
306  $fatChild = $this->uploadDao->getFatItemArray($child['uploadtree_pk'], $uploadId, $this->uploadtree_tablename);
307  $uploadtree_pk = $fatChild['item_id'];
308  $childUploadTreeId = $uploadtree_pk;
309  $upload = $this->uploadDao->getUploadEntry($uploadtree_pk, $this->uploadtree_tablename);
310  $fileId = $upload['pfile_fk'];
311  $parent = $upload['realparent'];
312  $parentItemTreeBound = $this->uploadDao->getItemTreeBounds($parent, $this->uploadtree_tablename);
313 
314  $pfileLicenses = array_replace($pfileLicenses,
315  $this->updateTheFindingsAndDecisions($latestSuccessfulAgentIds, $isFlat,
316  $groupId, $editedMappedLicenses, $parentItemTreeBound));
317 
318  $linkUri = "$uri&item=" . $uploadtree_pk;
319  $fileDetails["id"] = intval($uploadtree_pk);
320  if ($selectedAgentId) {
321  $linkUri .= "&agentId=$selectedAgentId";
322  $fileDetails["agentId"] = $selectedAgentId;
323  }
324  $child['ufile_name'] = $fatChild['ufile_name'];
325  if (!Iscontainer($fatChild['ufile_mode'])) {
326  $isContainer = false;
327  }
328  } else if ($isContainer) {
329  $uploadtree_pk = Isartifact($child['ufile_mode']) ? DirGetNonArtifact($childUploadTreeId, $this->uploadtree_tablename) : $childUploadTreeId;
330  $linkUri = "$uri&item=" . $uploadtree_pk;
331  $fileDetails["id"] = intval($uploadtree_pk);
332  $fileDetails["isContainer"] = true;
333  if ($selectedAgentId) {
334  $linkUri .= "&agentId=$selectedAgentId";
335  $fileDetails["agentId"] = $selectedAgentId;
336  }
337  }
338 
339  /* Populate the output ($VF) - file list */
340  /* id of each element is its uploadtree_pk */
341  $fileName = $child['ufile_name'];
342  if ($isContainer) {
343  $fileDetails["fileName"] = $fileName;
344  $fileName = "<a href='$linkUri'><span style='color: darkblue'> <b>$fileName</b> </span></a>";
345  } else if (!empty($linkUri)) {
346  $fileDetails["fileName"] = $fileName;
347  $fileName = "<a href='$linkUri'>$fileName</a>";
348  }
349  /* show licenses under file name */
350  $childItemTreeBounds =
351  new ItemTreeBounds($childUploadTreeId, $this->uploadtree_tablename, $child['upload_fk'], $child['lft'], $child['rgt']);
352  $totalFilesCount = $this->uploadDao->countPlainFiles($childItemTreeBounds);
353  $licenseEntriesRest = array();
354  if ($isContainer) {
355  $fileDetails["isContainer"] = true;
356  $agentFilter = $selectedAgentId ? array($selectedAgentId) : $latestSuccessfulAgentIds;
357  $licenseEntries = $this->licenseDao->getLicenseShortnamesContained($childItemTreeBounds, $agentFilter, array());
358  $editedLicenses = $this->clearingDao->getClearedLicenses($childItemTreeBounds, $groupId);
359 
360  if ($request->get('fromRest')) {
361  foreach ($licenseEntries as $shortName) {
362  $licenseEntriesRest[] = array(
363  "id" => $this->licenseDao->getLicenseByShortName($shortName, $groupId)->getId(),
364  "name" => $shortName,
365  "agents" => []
366  );
367  }
368  }
369  } else {
370  $licenseEntries = array();
371  if (array_key_exists($fileId, $pfileLicenses)) {
372  foreach ($pfileLicenses[$fileId] as $shortName => $rfInfo) {
373  $agentEntries = array();
374  $agentEntriesRest = array();
375  foreach ($rfInfo as $agent => $match) {
376  $agentName = $this->agentNames[$agent];
377  $agentEntry = "<a href='?mod=view-license&upload=$child[upload_fk]&item=$childUploadTreeId&format=text&agentId=$match[agent_id]&licenseId=$match[license_id]#highlight'>" . $agentName . "</a>";
378 
379  if ($match['match_percentage'] > 0) {
380  $agentEntry .= ": $match[match_percentage]%";
381  }
382  $agentEntries[] = $agentEntry;
383  $agentEntriesRest[] = array(
384  "name" => $agentName,
385  "id" => intval($match['agent_id']),
386  "matchPercentage" => intval($match['match_percentage']),
387  );
388  }
389  $licenseEntriesRest[] = array(
390  "id" => $this->licenseDao->getLicenseByShortName($shortName, $groupId)->getId(),
391  "name" => $shortName,
392  "agents" => $agentEntriesRest,
393  );
394  $licenseEntries[] = $shortName . " [" . implode("][", $agentEntries) . "]";
395  }
396  }
397 
398  /* @var $decision ClearingDecision */
399  if (false !== ($decision = $this->clearingFilter->getDecisionOf($editedMappedLicenses,$childUploadTreeId, $fileId))) {
400  $editedLicenses = $decision->getPositiveLicenses();
401  } else {
402  $editedLicenses = array();
403  }
404  }
405  $concludedLicensesRest = array();
406  $concludedLicenses = array();
408  foreach ($editedLicenses as $licenseRef) {
409  $projectedId = $this->licenseProjector->getProjectedId($licenseRef->getId());
410  $projectedName = $this->licenseProjector->getProjectedShortname($licenseRef->getId(),$licenseRef->getShortName());
411  $concludedLicenses[$projectedId] = $projectedName;
412  $concludedLicensesRest[] = array('id' => $projectedId, 'name' => $projectedName);
413  }
414 
415  $editedLicenseList = implode(', ', $concludedLicenses);
416  $licenseList = implode(', ', $licenseEntries);
417 
418  $fileListLinks = FileListLinks($uploadId, $childUploadTreeId, 0, $fileId, true, $UniqueTagArray, $this->uploadtree_tablename, !$isFlat);
419 
420  $getTextEditUser = _("Edit");
421  $fileListLinks .= "[<a href='#' onclick='openUserModal($childUploadTreeId)' >$getTextEditUser</a>]";
422 
423  if ($isContainer) {
424  $getTextEditBulk = _("Bulk");
425  $fileListLinks .= "[<a href='#' data-toggle='modal' data-target='#bulkModal' onclick='openBulkModal($childUploadTreeId)' >$getTextEditBulk</a>]";
426  }
427  $fileListLinks .= "<input type='checkbox' class='selectedForIrrelevant' class='info-bullet view-license-rc-size' value='".$childUploadTreeId."'>";
428  $filesThatShouldStillBeCleared = array_key_exists($childItemTreeBounds->getItemId()
429  , $this->filesThatShouldStillBeCleared) ? $this->filesThatShouldStillBeCleared[$childItemTreeBounds->getItemId()] : 0;
430 
431  $filesToBeCleared = array_key_exists($childItemTreeBounds->getItemId()
432  , $this->filesToBeCleared) ? $this->filesToBeCleared[$childItemTreeBounds->getItemId()] : 0;
433 
434  $filesCleared = $filesToBeCleared - $filesThatShouldStillBeCleared;
435 
436  $img = ($filesCleared == $filesToBeCleared) ? 'green' : 'red';
437 
438  // override green/red flag with grey flag in case of no_license_found scanner finding
439  if (!empty($licenseList) && empty($editedLicenseList)) {
440  $img = (
441  (strpos($licenseList, LicenseDao::NO_LICENSE_FOUND) !== false)
442  &&
443  (count(explode(",", $licenseList)) == 1)
444  ) ? 'grey' : $img;
445  }
446 
447  // override green/red flag with yellow flag in case of single file with decision type "To Be Discussed"
448  $isDecisionTBD = $this->clearingDao->isDecisionCheck($childUploadTreeId, $groupId, DecisionTypes::TO_BE_DISCUSSED);
449  $img = $isDecisionTBD ? 'yellow' : $img;
450 
451  // override green/red flag with greenRed flag in case of single file with decision type "Do Not Use" or "Non functional"
452  $isDecisionDNU = $this->clearingDao->isDecisionCheck($childUploadTreeId, $groupId, DecisionTypes::DO_NOT_USE);
453  $isDecisionNonFunctional = $this->clearingDao->isDecisionCheck($childUploadTreeId, $groupId, DecisionTypes::NON_FUNCTIONAL);
454 
455  $img = ($isDecisionDNU || $isDecisionNonFunctional) ? 'redGreen' : $img;
456 
457  return $request->get('fromRest') ? array(
458  "fileDetails" => $fileDetails,
459  "licenseList" => $licenseEntriesRest,
460  "editedLicenseList" => $concludedLicensesRest,
461  "clearingStatus" => $img,
462  "clearingProgress" => array(
463  "filesCleared" => intval($filesCleared),
464  "filesToBeCleared" => intval($filesToBeCleared),
465  "totalFilesCount" => intval($totalFilesCount)
466  ),
467  ) : array($fileName, $licenseList, $editedLicenseList, $img, "$filesCleared / $filesToBeCleared / $totalFilesCount", $fileListLinks);
468  }
469 
482  private function updateTheFindingsAndDecisions($agentIds, $isFlat, $groupId,
483  &$editedMappedLicenses, $itemTreeBounds, $nameRange = array())
484  {
488  $pfileLicenses = [];
489  foreach ($agentIds as $agentName => $agentId) {
490  $licensePerPfile = $this->licenseDao->getLicenseIdPerPfileForAgentId(
491  $itemTreeBounds, $agentId, $isFlat, $nameRange);
492  foreach ($licensePerPfile as $pfile => $licenseRow) {
493  foreach ($licenseRow as $licId => $row) {
494  $lic = $this->licenseProjector->getProjectedShortname($licId);
495  $pfileLicenses[$pfile][$lic][$agentName] = $row;
496  }
497  }
498  }
499 
500  if ($this->alreadyClearedUploadTreeView === NULL) {
501  // Initialize the proxy view only once for the complete table
502  $this->alreadyClearedUploadTreeView = new UploadTreeProxy(
503  $itemTreeBounds->getUploadId(),
504  $options = array(
505  UploadTreeProxy::OPT_SKIP_THESE => UploadTreeProxy::OPT_SKIP_ALREADY_CLEARED,
506  UploadTreeProxy::OPT_ITEM_FILTER => "AND (lft BETWEEN " .
507  $itemTreeBounds->getLeft() . " AND " . $itemTreeBounds->getRight() . ")",
508  UploadTreeProxy::OPT_GROUP_ID => $groupId
509  ), $itemTreeBounds->getUploadTreeTableName(),
510  $viewName = 'already_cleared_uploadtree' . $itemTreeBounds->getUploadId());
511 
512  $this->alreadyClearedUploadTreeView->materialize();
513  }
514 
515  if ($this->noLicenseUploadTreeView === NULL) {
516  // Initialize the proxy view only once for the complete table
517  $this->noLicenseUploadTreeView = new UploadTreeProxy(
518  $itemTreeBounds->getUploadId(),
519  $options = array(
520  UploadTreeProxy::OPT_SKIP_THESE => "noLicense",
521  UploadTreeProxy::OPT_ITEM_FILTER => "AND (lft BETWEEN " .
522  $itemTreeBounds->getLeft() . " AND " . $itemTreeBounds->getRight() . ")",
523  UploadTreeProxy::OPT_GROUP_ID => $groupId
524  ), $itemTreeBounds->getUploadTreeTableName(),
525  $viewName = 'no_license_uploadtree' . $itemTreeBounds->getUploadId());
526  $this->noLicenseUploadTreeView->materialize();
527  }
528 
529  $this->updateFilesToBeCleared($isFlat, $itemTreeBounds);
530  $allDecisions = $this->clearingDao->getFileClearingsFolder($itemTreeBounds,
531  $groupId, $isFlat);
532  $editedMappedLicenses = array_replace($editedMappedLicenses,
533  $this->clearingFilter->filterCurrentClearingDecisions($allDecisions));
534  return $pfileLicenses;
535  }
536 
543  private function updateFilesToBeCleared($isFlat, $itemTreeBounds)
544  {
545  $itemId = $itemTreeBounds->getItemId();
546  if (in_array($itemId, $this->cacheClearedCounter)) {
547  // Already calculated, no need to recount
548  return;
549  }
550  $this->cacheClearedCounter[] = $itemId;
551  if (! $isFlat) {
552  $this->filesThatShouldStillBeCleared = array_replace(
553  $this->filesThatShouldStillBeCleared,
554  $this->alreadyClearedUploadTreeView->countMaskedNonArtifactChildren(
555  $itemId));
556  $this->filesToBeCleared = array_replace($this->filesToBeCleared,
557  $this->noLicenseUploadTreeView->countMaskedNonArtifactChildren(
558  $itemId));
559  } else {
560  $this->filesThatShouldStillBeCleared = array_replace(
561  $this->filesThatShouldStillBeCleared,
562  $this->alreadyClearedUploadTreeView->getNonArtifactDescendants(
563  $itemTreeBounds));
564  $this->filesToBeCleared = array_replace($this->filesToBeCleared,
565  $this->noLicenseUploadTreeView->getNonArtifactDescendants($itemTreeBounds));
566  }
567  }
568 }
569 
570 register_plugin(new AjaxExplorer());
char * uploadtree_tablename
upload.uploadtree_tablename
Definition: adj2nest.c:100
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
static getGroupId()
Get the current user's group id.
Definition: Auth.php:80
Various utility functions to filter ClearingDecision.
Wrapper class for license map.
Definition: LicenseMap.php:19
updateTheFindingsAndDecisions($agentIds, $isFlat, $groupId, &$editedMappedLicenses, $itemTreeBounds, $nameRange=array())
Fetch the license findings and decisions.
updateFilesToBeCleared($isFlat, $itemTreeBounds)
createFileListing($tagId, ItemTreeBounds $itemTreeBounds, &$UniqueTagArray, $selectedAgentId, $groupId, $scanJobProxy, $request)
Isartifact($mode)
Definition: common-dir.php:29
DirGetNonArtifact($UploadtreePk, $uploadtree_tablename='uploadtree')
Given an artifact directory (uploadtree_pk), return the first non-artifact directory (uploadtree_pk).
Definition: common-dir.php:158
Iscontainer($mode)
Definition: common-dir.php:38
FileListLinks($upload_fk, $uploadtree_pk, $napk, $pfile_pk, $Recurse=True, &$UniqueTagArray=array(), $uploadtree_tablename="uploadtree", $wantTags=true)
Get list of links: [View][Info][Download]
Traceback_uri()
Get the URI without query to this location.
Definition: common-parm.php:97
Traceback_parm_keep($List)
Create a new URI, keeping only these items.
TagFilter(&$UploadtreeRows, $tag_pk, $uploadtree_tablename)
Given a list of uploadtree recs, remove recs that do not have $tag_pk.