FOSSology  4.6.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 folder_pk FROM folder");
219  $res = $this->dbManager->execute($statementName);
220  $results = $this->dbManager->fetchAll($res);
221  $this->dbManager->freeResult($res);
222 
223  return array_map('intval', array_column($results, 'folder_pk'));
224  }
225 
226  public function getFolderChildUploads($parentId, $trustGroupId)
227  {
228  $statementName = __METHOD__;
229  $parameters = array($parentId, $trustGroupId);
230 
231  $this->dbManager->prepare($statementName, $sql = "
232 SELECT u.*, uc.*, fc.foldercontents_pk FROM foldercontents fc
233  INNER JOIN upload u ON u.upload_pk = fc.child_id AND u.upload_mode IN (100, 104)
234  INNER JOIN upload_clearing uc ON uc.upload_fk = u.upload_pk AND uc.group_fk = $2
235 WHERE fc.parent_fk = $1 AND fc.foldercontents_mode = " . self::MODE_UPLOAD . ";");
236  $res = $this->dbManager->execute($statementName, $parameters);
237  $results = $this->dbManager->fetchAll($res);
238  $this->dbManager->freeResult($res);
239  return $results;
240  }
241 
247  public function getFolderUploads($parentId, $trustGroupId = null)
248  {
249  if (empty($trustGroupId)) {
250  $trustGroupId = Auth::getGroupId();
251  }
252  $results = array();
253  foreach ($this->getFolderChildUploads($parentId, $trustGroupId) as $row) {
254  $results[] = UploadProgress::createFromTable($row);
255  }
256  return $results;
257  }
258 
259  public function createFolder($folderName, $folderDescription, $parentId)
260  {
261  $folderId = $this->dbManager->insertTableRow("folder", array("folder_name" => $folderName, "user_fk" => Auth::getUserId(), "folder_desc" => $folderDescription), null, 'folder_pk');
262  $this->insertFolderContents($parentId, self::MODE_FOLDER, $folderId);
263  return $folderId;
264  }
265 
266 
267  public function ensureTopLevelFolder()
268  {
269  if (!$this->hasTopLevelFolder()) {
270  $this->dbManager->insertTableRow("folder", array("folder_pk" => self::TOP_LEVEL, "folder_name" => "Software Repository", "folder_desc" => "Top Folder"));
271  $this->insertFolderContents(1, 0, 0);
272  $this->fixFolderSequence();
273  }
274  }
275 
276  public function isWithoutReusableFolders($folderStructure)
277  {
278  foreach ($folderStructure as $folder) {
279  $posibilities = array_reduce($folder[self::REUSE_KEY], function($sum,$groupInfo)
280  {
281  return $sum+$groupInfo['count'];
282  }, 0);
283  if ($posibilities > 0) {
284  return false;
285  }
286  }
287  return true;
288  }
289 
290  protected function isInFolderTree($parentId, $folderId)
291  {
292  $cycle = $this->dbManager->getSingleRow(
293  $this->getFolderTreeCte($parentId) . " SELECT depth FROM folder_tree WHERE folder_pk=$2 LIMIT 1",
294  array($parentId, $folderId),
295  __METHOD__);
296  return !empty($cycle);
297  }
298 
299  public function getContent($folderContentId)
300  {
301  $content = $this->dbManager->getSingleRow('SELECT * FROM foldercontents WHERE foldercontents_pk=$1',
302  array($folderContentId),
303  __METHOD__ . '.getContent');
304  if (empty($content)) {
305  throw new \Exception('invalid FolderContentId');
306  }
307  return $content;
308  }
309 
310  protected function isContentMovable($content, $newParentId)
311  {
312  if ($content['parent_fk'] == $newParentId) {
313  return false;
314  }
315  $newParent = $this->dbManager->getSingleRow('SELECT * FROM folder WHERE folder_pk=$1',
316  array($newParentId),
317  __METHOD__ . '.getParent');
318  if (empty($newParent)) {
319  throw new \Exception('invalid parent folder');
320  }
321 
322  if ($content['foldercontents_mode'] == self::MODE_FOLDER) {
323  if ($this->isInFolderTree($content['child_id'], $newParentId)) {
324  throw new \Exception("action would cause a cycle");
325  }
326  } elseif ($content['foldercontents_mode'] == self::MODE_UPLOAD) {
327  $uploadId = $content['child_id'];
328  if (!$this->uploadDao->isEditable($uploadId, Auth::getGroupId())) {
329  throw new \Exception('permission to upload denied');
330  }
331  }
332 
333  return true;
334  }
335 
336  public function moveContent($folderContentId, $newParentId)
337  {
338  $content = $this->getContent($folderContentId);
339  if (!$this->isContentMovable($content, $newParentId)) {
340  return;
341  }
342 
343  $this->dbManager->getSingleRow('UPDATE foldercontents SET parent_fk=$2 WHERE foldercontents_pk=$1',
344  array($folderContentId, $newParentId), __METHOD__ . '.updateFolderParent');
345  }
346 
347  public function copyContent($folderContentId, $newParentId)
348  {
349  $content = $this->getContent($folderContentId);
350  if (!$this->isContentMovable($content, $newParentId)) {
351  return;
352  }
353 
354  $this->insertFolderContents($newParentId, $content['foldercontents_mode'], $content['child_id']);
355  }
356 
357  public function getRemovableContents($folderId)
358  {
359  $sqlChildren = "SELECT child_id,foldercontents_mode
360  FROM foldercontents GROUP BY child_id,foldercontents_mode
361  HAVING count(*)>1 AND bool_or(parent_fk=$1)";
362  $sql = "SELECT fc.* FROM foldercontents fc,($sqlChildren) chi "
363  . "WHERE fc.child_id=chi.child_id AND fc.foldercontents_mode=chi.foldercontents_mode and fc.parent_fk=$1";
364  $this->dbManager->prepare($stmt = __METHOD__, $sql);
365  $res = $this->dbManager->execute($stmt, array($folderId));
366  $contents = array();
367  while ($row = $this->dbManager->fetchArray($res)) {
368  $contents[] = $row['foldercontents_pk'];
369  }
370  $this->dbManager->freeResult($res);
371  return $contents;
372  }
373 
374  public function isRemovableContent($childId, $mode)
375  {
376  $sql = "SELECT count(parent_fk) FROM foldercontents WHERE child_id=$1 AND foldercontents_mode=$2";
377  $parentCounter = $this->dbManager->getSingleRow($sql, array($childId, $mode), __METHOD__);
378  return $parentCounter['count'] > 1;
379  }
380 
381  public function removeContent($folderContentId)
382  {
383  $content = $this->getContent($folderContentId);
384  if ($this->isRemovableContent($content['child_id'], $content['foldercontents_mode'])) {
385  $sql = "DELETE FROM foldercontents WHERE foldercontents_pk=$1";
386  $this->dbManager->getSingleRow($sql, array($folderContentId), __METHOD__);
387  return true;
388  }
389  return false;
390  }
391 
392  public function removeContentById($uploadpk, $folderId)
393  {
394  $sql = "DELETE FROM foldercontents WHERE child_id=$1 AND parent_fk=$2 AND foldercontents_mode=$3";
395  $this->dbManager->getSingleRow($sql,array($uploadpk, $folderId,2),__METHOD__);
396  }
397 
398  public function getFolderChildFolders($folderId)
399  {
400  $results = array();
401  $stmtFolder = __METHOD__;
402  $sqlFolder = "SELECT foldercontents_pk,foldercontents_mode, folder_name FROM foldercontents JOIN folder"
403  . " ON foldercontents.child_id=folder.folder_pk WHERE foldercontents.parent_fk=$1"
404  . " AND foldercontents_mode=" . self::MODE_FOLDER;
405  $this->dbManager->prepare($stmtFolder, $sqlFolder);
406  $res = $this->dbManager->execute($stmtFolder, array($folderId));
407  while ($row = $this->dbManager->fetchArray($res)) {
408  $results[$row['foldercontents_pk']] = $row;
409  }
410  $this->dbManager->freeResult($res);
411  return $results;
412  }
413 
418  public function getFolder($folderId)
419  {
420  $folderRow = $this->dbManager->getSingleRow('SELECT * FROM folder WHERE folder_pk = $1', array($folderId));
421  if (!$folderRow) {
422  return null;
423  }
424  return new Folder($folderRow['folder_pk'], $folderRow['folder_name'], $folderRow['folder_desc'], $folderRow['folder_perm']);
425  }
426 
432  public function isFolderAccessible($folderId, $userId = null)
433  {
434  if ($userId == null) {
435  $userId = Auth::getUserId();
436  }
437  $rootFolder = $this->getRootFolder($userId)->getId();
438  return $this->isInFolderTree($rootFolder, $folderId);
439  }
440 
447  public function getFolderContentsId($childId, $mode)
448  {
449  $folderContentsRow = $this->dbManager->getSingleRow(
450  'SELECT foldercontents_pk FROM foldercontents '.
451  'WHERE child_id = $1 AND foldercontents_mode = $2', [$childId, $mode]);
452  if (!$folderContentsRow) {
453  return null;
454  }
455  return intval($folderContentsRow['foldercontents_pk']);
456  }
457 
463  public function getFolderParentId($folderPk)
464  {
465  $sql = "SELECT parent_fk FROM foldercontents " .
466  "WHERE foldercontents_mode = " . self::MODE_FOLDER .
467  " AND child_id = $1;";
468  $statement = __METHOD__ . ".getParentId";
469  $row = $this->dbManager->getSingleRow($sql, [$folderPk], $statement);
470  return (empty($row)) ? null : $row['parent_fk'];
471  }
472 }
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:432
getFolderUploads($parentId, $trustGroupId=null)
Definition: FolderDao.php:247
getFolderContentsId($childId, $mode)
Definition: FolderDao.php:447
countFolderUploads($parentId, $userGroupMap)
Definition: FolderDao.php:191
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16