FOSSology  4.4.0
Open Source License Compliance by Open Source Software
FolderDao.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2015 Siemens AG
4  Authors: Andreas Würl, Steffen Weber
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 namespace Fossology\Lib\Dao;
10 
15 use Monolog\Logger;
16 
17 class FolderDao
18 {
19  const FOLDER_KEY = "folder";
20  const DEPTH_KEY = "depth";
21  const REUSE_KEY = 'reuse';
22  const TOP_LEVEL = 1;
23 
24  const MODE_FOLDER = 1;
25  const MODE_UPLOAD = 2;
26  const MODE_ITEM = 4;
27 
29  private $dbManager;
31  private $userDao;
33  private $uploadDao;
35  private $logger;
36 
37  public function __construct(DbManager $dbManager, UserDao $userDao, UploadDao $uploadDao)
38  {
39  $this->dbManager = $dbManager;
40  $this->logger = new Logger(self::class);
41  $this->uploadDao = $uploadDao;
42  $this->userDao = $userDao;
43  }
44 
48  public function hasTopLevelFolder()
49  {
50  $folderInfo = $this->dbManager->getSingleRow("SELECT count(*) cnt FROM folder WHERE folder_pk=$1", array(self::TOP_LEVEL), __METHOD__);
51  $hasFolder = $folderInfo['cnt'] > 0;
52  return $hasFolder;
53  }
54 
55  public function insertFolder($folderName, $folderDescription, $parentFolderId = self::TOP_LEVEL)
56  {
57 
58  $statementName = __METHOD__;
59 
60  $this->dbManager->prepare($statementName,
61  "INSERT INTO folder (folder_name, folder_desc) VALUES ($1, $2) returning folder_pk");
62  $res = $this->dbManager->execute($statementName, array($folderName, $folderDescription));
63  $folderRow = $this->dbManager->fetchArray($res);
64  $folderId = $folderRow["folder_pk"];
65  $this->dbManager->freeResult($res);
66  $this->insertFolderContents($parentFolderId, self::MODE_FOLDER, $folderId);
67 
68  return $folderId;
69  }
70 
71  public function getFolderId($folderName, $parentFolderId = self::TOP_LEVEL)
72  {
73  $statementName = __METHOD__;
74  $this->dbManager->prepare($statementName,
75  "SELECT folder_pk FROM folder, foldercontents fc"
76  ." WHERE LOWER(folder_name)=LOWER($1) AND fc.parent_fk=$2 AND fc.foldercontents_mode=$3 AND folder_pk=child_id");
77  $res = $this->dbManager->execute($statementName, array( $folderName, $parentFolderId, self::MODE_FOLDER));
78  $rows= $this->dbManager->fetchAll($res);
79 
80  $rootFolder = !empty($rows) ? intval($rows[0]['folder_pk']) : null;
81  $this->dbManager->freeResult($res);
82 
83  return $rootFolder;
84  }
85 
86  public function insertFolderContents($parentId, $foldercontentsMode, $childId)
87  {
88  $statementName = __METHOD__;
89  $this->dbManager->prepare($statementName,
90  "INSERT INTO foldercontents (parent_fk, foldercontents_mode, child_id) VALUES ($1, $2, $3)");
91  $res = $this->dbManager->execute($statementName, array($parentId, $foldercontentsMode, $childId));
92  $this->dbManager->freeResult($res);
93  }
94 
95  protected function fixFolderSequence()
96  {
97  $statementName = __METHOD__;
98  $this->dbManager->prepare($statementName,
99  "SELECT setval('folder_folder_pk_seq', (SELECT max(folder_pk) + 1 FROM folder LIMIT 1))");
100  $res = $this->dbManager->execute($statementName);
101  $this->dbManager->freeResult($res);
102  }
103 
108  public function getRootFolder($userId)
109  {
110  $statementName = __METHOD__;
111  $this->dbManager->prepare($statementName,
112  "SELECT f.* FROM folder f INNER JOIN users u ON f.folder_pk = u.root_folder_fk WHERE u.user_pk = $1");
113  $res = $this->dbManager->execute($statementName, array($userId));
114  $row = $this->dbManager->fetchArray($res);
115  $rootFolder = $row ? new Folder(intval($row['folder_pk']), $row['folder_name'], $row['folder_desc'], intval($row['folder_perm'])) : null;
116  $this->dbManager->freeResult($res);
117  return $rootFolder;
118  }
119 
124  public function getDefaultFolder($userId)
125  {
126  $statementName = __METHOD__;
127  $this->dbManager->prepare($statementName,
128  "SELECT f.* FROM folder f INNER JOIN users u ON f.folder_pk = u.default_folder_fk WHERE u.user_pk = $1");
129  $res = $this->dbManager->execute($statementName, array($userId));
130  $row = $this->dbManager->fetchArray($res);
131  $rootFolder = $row ? new Folder(intval($row['folder_pk']), $row['folder_name'], $row['folder_desc'], intval($row['folder_perm'])) : null;
132  $this->dbManager->freeResult($res);
133  return $rootFolder;
134  }
135 
136  public function getFolderTreeCte($parentId = null)
137  {
138  $parentCondition = $parentId ? 'folder_pk=$1' : 'folder_pk=' . self::TOP_LEVEL;
139 
140  return "WITH RECURSIVE folder_tree(folder_pk, parent_fk, folder_name, folder_desc, folder_perm, id_path, name_path, depth, cycle_detected) AS (
141  SELECT
142  f.folder_pk, fc.parent_fk, f.folder_name, f.folder_desc, f.folder_perm,
143  ARRAY [f.folder_pk] AS id_path,
144  ARRAY [f.folder_name] AS name_path,
145  0 AS depth,
146  FALSE AS cycle_detected
147  FROM folder f LEFT JOIN foldercontents fc ON fc.foldercontents_mode=" . self::MODE_FOLDER . " AND f.folder_pk=fc.child_id
148  WHERE $parentCondition
149  UNION ALL
150  SELECT
151  f.folder_pk, fc.parent_fk, f.folder_name, f.folder_desc, f.folder_perm,
152  id_path || f.folder_pk,
153  name_path || f.folder_name,
154  array_length(id_path, 1),
155  f.folder_pk = ANY (id_path)
156  FROM folder f, foldercontents fc, folder_tree ft
157  WHERE f.folder_pk=fc.child_id AND foldercontents_mode=" . self::MODE_FOLDER . " AND fc.parent_fk = ft.folder_pk AND NOT cycle_detected
158 )";
159  }
160 
161  public function getFolderStructure($parentId = null)
162  {
163  $statementName = __METHOD__ . ($parentId ? '.relativeToParent' : '');
164  $parameters = $parentId ? array($parentId) : array();
165  $this->dbManager->prepare($statementName, $this->getFolderTreeCte($parentId)
166  . " SELECT folder_pk, parent_fk, folder_name, folder_desc, folder_perm, depth FROM folder_tree ORDER BY name_path");
167  $res = $this->dbManager->execute($statementName, $parameters);
168 
169  $userGroupMap = $this->userDao->getUserGroupMap(Auth::getUserId());
170 
171  $results = array();
172  while ($row = $this->dbManager->fetchArray($res)) {
173  $countUploads = $this->countFolderUploads(intval($row['folder_pk']), $userGroupMap);
174 
175  $results[] = array(
176  self::FOLDER_KEY => new Folder(
177  intval($row['folder_pk']), $row['folder_name'], $row['folder_desc'], intval($row['folder_perm'])),
178  self::DEPTH_KEY => $row['depth'],
179  self::REUSE_KEY => $countUploads
180  );
181  }
182  $this->dbManager->freeResult($res);
183  return $results;
184  }
185 
191  public function countFolderUploads($parentId, $userGroupMap)
192  {
193  $trustGroupIds = array_keys($userGroupMap);
194  $statementName = __METHOD__;
195  $trustedGroups = '{' . implode(',', $trustGroupIds) . '}';
196  $parameters = array($parentId, $trustedGroups);
197 
198  $this->dbManager->prepare($statementName, "
199 SELECT group_fk group_id,count(*) FROM foldercontents fc
200  INNER JOIN upload u ON u.upload_pk = fc.child_id
201  INNER JOIN upload_clearing uc ON u.upload_pk=uc.upload_fk AND uc.group_fk=ANY($2)
202 WHERE fc.parent_fk = $1 AND fc.foldercontents_mode = " . self::MODE_UPLOAD . " AND (u.upload_mode = 100 OR u.upload_mode = 104)
203 GROUP BY group_fk
204 ");
205  $res = $this->dbManager->execute($statementName, $parameters);
206  $results = array();
207  while ($row = $this->dbManager->fetchArray($res)) {
208  $row['group_name'] = $userGroupMap[$row['group_id']];
209  $results[$row['group_name']] = $row;
210  }
211  $this->dbManager->freeResult($res);
212  return $results;
213  }
214 
215  public function getAllFolderIds()
216  {
217  $statementName = __METHOD__;
218  $this->dbManager->prepare($statementName, "SELECT DISTINCT folder_pk FROM folder");
219  $res = $this->dbManager->execute($statementName);
220  $results = $this->dbManager->fetchAll($res);
221  $this->dbManager->freeResult($res);
222 
223  $allIds = array();
224  for ($i=0; $i < sizeof($results); $i++) {
225  $allIds[] = intval($results[$i]['folder_pk']);
226  }
227 
228  return $allIds;
229  }
230 
231  public function getFolderChildUploads($parentId, $trustGroupId)
232  {
233  $statementName = __METHOD__;
234  $parameters = array($parentId, $trustGroupId);
235 
236  $this->dbManager->prepare($statementName, $sql = "
237 SELECT u.*,uc.*,fc.foldercontents_pk FROM foldercontents fc
238  INNER JOIN upload u ON u.upload_pk = fc.child_id
239  INNER JOIN upload_clearing uc ON u.upload_pk=uc.upload_fk AND uc.group_fk=$2
240 WHERE fc.parent_fk = $1 AND fc.foldercontents_mode = " . self::MODE_UPLOAD . " AND (u.upload_mode = 100 OR u.upload_mode = 104);");
241  $res = $this->dbManager->execute($statementName, $parameters);
242  $results = $this->dbManager->fetchAll($res);
243  $this->dbManager->freeResult($res);
244  return $results;
245  }
246 
252  public function getFolderUploads($parentId, $trustGroupId = null)
253  {
254  if (empty($trustGroupId)) {
255  $trustGroupId = Auth::getGroupId();
256  }
257  $results = array();
258  foreach ($this->getFolderChildUploads($parentId, $trustGroupId) as $row) {
259  $results[] = UploadProgress::createFromTable($row);
260  }
261  return $results;
262  }
263 
264  public function createFolder($folderName, $folderDescription, $parentId)
265  {
266  $folderId = $this->dbManager->insertTableRow("folder", array("folder_name" => $folderName, "user_fk" => Auth::getUserId(), "folder_desc" => $folderDescription), null, 'folder_pk');
267  $this->insertFolderContents($parentId, self::MODE_FOLDER, $folderId);
268  return $folderId;
269  }
270 
271 
272  public function ensureTopLevelFolder()
273  {
274  if (!$this->hasTopLevelFolder()) {
275  $this->dbManager->insertTableRow("folder", array("folder_pk" => self::TOP_LEVEL, "folder_name" => "Software Repository", "folder_desc" => "Top Folder"));
276  $this->insertFolderContents(1, 0, 0);
277  $this->fixFolderSequence();
278  }
279  }
280 
281  public function isWithoutReusableFolders($folderStructure)
282  {
283  foreach ($folderStructure as $folder) {
284  $posibilities = array_reduce($folder[self::REUSE_KEY], function($sum,$groupInfo)
285  {
286  return $sum+$groupInfo['count'];
287  }, 0);
288  if ($posibilities > 0) {
289  return false;
290  }
291  }
292  return true;
293  }
294 
295  protected function isInFolderTree($parentId, $folderId)
296  {
297  $cycle = $this->dbManager->getSingleRow(
298  $this->getFolderTreeCte($parentId) . " SELECT depth FROM folder_tree WHERE folder_pk=$2 LIMIT 1",
299  array($parentId, $folderId),
300  __METHOD__);
301  return !empty($cycle);
302  }
303 
304  public function getContent($folderContentId)
305  {
306  $content = $this->dbManager->getSingleRow('SELECT * FROM foldercontents WHERE foldercontents_pk=$1',
307  array($folderContentId),
308  __METHOD__ . '.getContent');
309  if (empty($content)) {
310  throw new \Exception('invalid FolderContentId');
311  }
312  return $content;
313  }
314 
315  protected function isContentMovable($content, $newParentId)
316  {
317  if ($content['parent_fk'] == $newParentId) {
318  return false;
319  }
320  $newParent = $this->dbManager->getSingleRow('SELECT * FROM folder WHERE folder_pk=$1',
321  array($newParentId),
322  __METHOD__ . '.getParent');
323  if (empty($newParent)) {
324  throw new \Exception('invalid parent folder');
325  }
326 
327  if ($content['foldercontents_mode'] == self::MODE_FOLDER) {
328  if ($this->isInFolderTree($content['child_id'], $newParentId)) {
329  throw new \Exception("action would cause a cycle");
330  }
331  } elseif ($content['foldercontents_mode'] == self::MODE_UPLOAD) {
332  $uploadId = $content['child_id'];
333  if (!$this->uploadDao->isEditable($uploadId, Auth::getGroupId())) {
334  throw new \Exception('permission to upload denied');
335  }
336  }
337 
338  return true;
339  }
340 
341  public function moveContent($folderContentId, $newParentId)
342  {
343  $content = $this->getContent($folderContentId);
344  if (!$this->isContentMovable($content, $newParentId)) {
345  return;
346  }
347 
348  $this->dbManager->getSingleRow('UPDATE foldercontents SET parent_fk=$2 WHERE foldercontents_pk=$1',
349  array($folderContentId, $newParentId), __METHOD__ . '.updateFolderParent');
350  }
351 
352  public function copyContent($folderContentId, $newParentId)
353  {
354  $content = $this->getContent($folderContentId);
355  if (!$this->isContentMovable($content, $newParentId)) {
356  return;
357  }
358 
359  $this->insertFolderContents($newParentId, $content['foldercontents_mode'], $content['child_id']);
360  }
361 
362  public function getRemovableContents($folderId)
363  {
364  $sqlChildren = "SELECT child_id,foldercontents_mode
365  FROM foldercontents GROUP BY child_id,foldercontents_mode
366  HAVING count(*)>1 AND bool_or(parent_fk=$1)";
367  $sql = "SELECT fc.* FROM foldercontents fc,($sqlChildren) chi "
368  . "WHERE fc.child_id=chi.child_id AND fc.foldercontents_mode=chi.foldercontents_mode and fc.parent_fk=$1";
369  $this->dbManager->prepare($stmt = __METHOD__, $sql);
370  $res = $this->dbManager->execute($stmt, array($folderId));
371  $contents = array();
372  while ($row = $this->dbManager->fetchArray($res)) {
373  $contents[] = $row['foldercontents_pk'];
374  }
375  $this->dbManager->freeResult($res);
376  return $contents;
377  }
378 
379  public function isRemovableContent($childId, $mode)
380  {
381  $sql = "SELECT count(parent_fk) FROM foldercontents WHERE child_id=$1 AND foldercontents_mode=$2";
382  $parentCounter = $this->dbManager->getSingleRow($sql, array($childId, $mode), __METHOD__);
383  return $parentCounter['count'] > 1;
384  }
385 
386  public function removeContent($folderContentId)
387  {
388  $content = $this->getContent($folderContentId);
389  if ($this->isRemovableContent($content['child_id'], $content['foldercontents_mode'])) {
390  $sql = "DELETE FROM foldercontents WHERE foldercontents_pk=$1";
391  $this->dbManager->getSingleRow($sql, array($folderContentId), __METHOD__);
392  return true;
393  }
394  return false;
395  }
396 
397  public function removeContentById($uploadpk, $folderId)
398  {
399  $sql = "DELETE FROM foldercontents WHERE child_id=$1 AND parent_fk=$2 AND foldercontents_mode=$3";
400  $this->dbManager->getSingleRow($sql,array($uploadpk, $folderId,2),__METHOD__);
401  }
402 
403  public function getFolderChildFolders($folderId)
404  {
405  $results = array();
406  $stmtFolder = __METHOD__;
407  $sqlFolder = "SELECT foldercontents_pk,foldercontents_mode, folder_name FROM foldercontents JOIN folder"
408  . " ON foldercontents.child_id=folder.folder_pk WHERE foldercontents.parent_fk=$1"
409  . " AND foldercontents_mode=" . self::MODE_FOLDER;
410  $this->dbManager->prepare($stmtFolder, $sqlFolder);
411  $res = $this->dbManager->execute($stmtFolder, array($folderId));
412  while ($row = $this->dbManager->fetchArray($res)) {
413  $results[$row['foldercontents_pk']] = $row;
414  }
415  $this->dbManager->freeResult($res);
416  return $results;
417  }
418 
423  public function getFolder($folderId)
424  {
425  $folderRow = $this->dbManager->getSingleRow('SELECT * FROM folder WHERE folder_pk = $1', array($folderId));
426  if (!$folderRow) {
427  return null;
428  }
429  return new Folder($folderRow['folder_pk'], $folderRow['folder_name'], $folderRow['folder_desc'], $folderRow['folder_perm']);
430  }
431 
437  public function isFolderAccessible($folderId, $userId = null)
438  {
439  $allUserFolders = array();
440  if ($userId == null) {
441  $userId = Auth::getUserId();
442  }
443  $rootFolder = $this->getRootFolder($userId)->getId();
444  GetFolderArray($rootFolder, $allUserFolders);
445  if (in_array($folderId, array_keys($allUserFolders))) {
446  return true;
447  }
448  return false;
449  }
450 
457  public function getFolderContentsId($childId, $mode)
458  {
459  $folderContentsRow = $this->dbManager->getSingleRow(
460  'SELECT foldercontents_pk FROM foldercontents '.
461  'WHERE child_id = $1 AND foldercontents_mode = $2', [$childId, $mode]);
462  if (!$folderContentsRow) {
463  return null;
464  }
465  return intval($folderContentsRow['foldercontents_pk']);
466  }
467 
473  public function getFolderParentId($folderPk)
474  {
475  $sql = "SELECT parent_fk FROM foldercontents " .
476  "WHERE foldercontents_mode = " . self::MODE_FOLDER .
477  " AND child_id = $1;";
478  $statement = __METHOD__ . ".getParentId";
479  $row = $this->dbManager->getSingleRow($sql, [$folderPk], $statement);
480  return (empty($row)) ? null : $row['parent_fk'];
481  }
482 }
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
static getUserId()
Get the current user's id.
Definition: Auth.php:68
static getGroupId()
Get the current user's group id.
Definition: Auth.php:80
isFolderAccessible($folderId, $userId=null)
Definition: FolderDao.php:437
getFolderUploads($parentId, $trustGroupId=null)
Definition: FolderDao.php:252
getFolderContentsId($childId, $mode)
Definition: FolderDao.php:457
countFolderUploads($parentId, $userGroupMap)
Definition: FolderDao.php:191
GetFolderArray($RootFolder, &$FolderArray)
Get an array of all the folders from a $RootFolder on down.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16