FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
FolderDao.php
1 <?php
2 /*
3 Copyright (C) 2014-2015, Siemens AG
4 Authors: Andreas Würl, Steffen Weber
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 
20 namespace Fossology\Lib\Dao;
21 
26 use Monolog\Logger;
27 
28 class FolderDao
29 {
30  const FOLDER_KEY = "folder";
31  const DEPTH_KEY = "depth";
32  const REUSE_KEY = 'reuse';
33  const TOP_LEVEL = 1;
34 
35  const MODE_FOLDER = 1;
36  const MODE_UPLOAD = 2;
37  const MODE_ITEM = 4;
38 
40  private $dbManager;
42  private $userDao;
44  private $uploadDao;
46  private $logger;
47 
48  public function __construct(DbManager $dbManager, UserDao $userDao, UploadDao $uploadDao)
49  {
50  $this->dbManager = $dbManager;
51  $this->logger = new Logger(self::class);
52  $this->uploadDao = $uploadDao;
53  $this->userDao = $userDao;
54  }
55 
59  public function hasTopLevelFolder()
60  {
61  $folderInfo = $this->dbManager->getSingleRow("SELECT count(*) cnt FROM folder WHERE folder_pk=$1", array(self::TOP_LEVEL), __METHOD__);
62  $hasFolder = $folderInfo['cnt'] > 0;
63  return $hasFolder;
64  }
65 
66  public function insertFolder($folderName, $folderDescription, $parentFolderId = self::TOP_LEVEL)
67  {
68 
69  $statementName = __METHOD__;
70 
71  $this->dbManager->prepare($statementName,
72  "INSERT INTO folder (folder_name, folder_desc) VALUES ($1, $2) returning folder_pk");
73  $res = $this->dbManager->execute($statementName, array($folderName, $folderDescription));
74  $folderRow = $this->dbManager->fetchArray($res);
75  $folderId = $folderRow["folder_pk"];
76  $this->dbManager->freeResult($res);
77  $this->insertFolderContents($parentFolderId, self::MODE_FOLDER, $folderId);
78 
79  return $folderId;
80  }
81 
82  public function getFolderId($folderName, $parentFolderId = self::TOP_LEVEL)
83  {
84  $statementName = __METHOD__;
85  $this->dbManager->prepare($statementName,
86  "SELECT folder_pk FROM folder, foldercontents fc"
87  ." WHERE LOWER(folder_name)=LOWER($1) AND fc.parent_fk=$2 AND fc.foldercontents_mode=$3 AND folder_pk=child_id");
88  $res = $this->dbManager->execute($statementName, array( $folderName, $parentFolderId, self::MODE_FOLDER));
89  $rows= $this->dbManager->fetchAll($res);
90 
91  $rootFolder = !empty($rows) ? intval($rows[0]['folder_pk']) : null;
92  $this->dbManager->freeResult($res);
93 
94  return $rootFolder;
95  }
96 
97  public function insertFolderContents($parentId, $foldercontentsMode, $childId)
98  {
99  $statementName = __METHOD__;
100  $this->dbManager->prepare($statementName,
101  "INSERT INTO foldercontents (parent_fk, foldercontents_mode, child_id) VALUES ($1, $2, $3)");
102  $res = $this->dbManager->execute($statementName, array($parentId, $foldercontentsMode, $childId));
103  $this->dbManager->freeResult($res);
104  }
105 
106  protected function fixFolderSequence()
107  {
108  $statementName = __METHOD__;
109  $this->dbManager->prepare($statementName,
110  "SELECT setval('folder_folder_pk_seq', (SELECT max(folder_pk) + 1 FROM folder LIMIT 1))");
111  $res = $this->dbManager->execute($statementName);
112  $this->dbManager->freeResult($res);
113  }
114 
119  public function getRootFolder($userId)
120  {
121  $statementName = __METHOD__;
122  $this->dbManager->prepare($statementName,
123  "SELECT f.* FROM folder f INNER JOIN users u ON f.folder_pk = u.root_folder_fk WHERE u.user_pk = $1");
124  $res = $this->dbManager->execute($statementName, array($userId));
125  $row = $this->dbManager->fetchArray($res);
126  $rootFolder = $row ? new Folder(intval($row['folder_pk']), $row['folder_name'], $row['folder_desc'], intval($row['folder_perm'])) : null;
127  $this->dbManager->freeResult($res);
128  return $rootFolder;
129  }
130 
131  public function getFolderTreeCte($parentId = null)
132  {
133  $parentCondition = $parentId ? 'folder_pk=$1' : 'folder_pk=' . self::TOP_LEVEL;
134 
135  return "WITH RECURSIVE folder_tree(folder_pk, parent_fk, folder_name, folder_desc, folder_perm, id_path, name_path, depth, cycle_detected) AS (
136  SELECT
137  f.folder_pk, fc.parent_fk, f.folder_name, f.folder_desc, f.folder_perm,
138  ARRAY [f.folder_pk] AS id_path,
139  ARRAY [f.folder_name] AS name_path,
140  0 AS depth,
141  FALSE AS cycle_detected
142  FROM folder f LEFT JOIN foldercontents fc ON fc.foldercontents_mode=" . self::MODE_FOLDER . " AND f.folder_pk=fc.child_id
143  WHERE $parentCondition
144  UNION ALL
145  SELECT
146  f.folder_pk, fc.parent_fk, f.folder_name, f.folder_desc, f.folder_perm,
147  id_path || f.folder_pk,
148  name_path || f.folder_name,
149  array_length(id_path, 1),
150  f.folder_pk = ANY (id_path)
151  FROM folder f, foldercontents fc, folder_tree ft
152  WHERE f.folder_pk=fc.child_id AND foldercontents_mode=" . self::MODE_FOLDER . " AND fc.parent_fk = ft.folder_pk AND NOT cycle_detected
153 )";
154  }
155 
156  public function getFolderStructure($parentId = null)
157  {
158  $statementName = __METHOD__ . ($parentId ? '.relativeToParent' : '');
159  $parameters = $parentId ? array($parentId) : array();
160  $this->dbManager->prepare($statementName, $this->getFolderTreeCte($parentId)
161  . " SELECT folder_pk, parent_fk, folder_name, folder_desc, folder_perm, depth FROM folder_tree ORDER BY name_path");
162  $res = $this->dbManager->execute($statementName, $parameters);
163 
164  $userGroupMap = $this->userDao->getUserGroupMap(Auth::getUserId());
165 
166  $results = array();
167  while ($row = $this->dbManager->fetchArray($res)) {
168  $countUploads = $this->countFolderUploads(intval($row['folder_pk']), $userGroupMap);
169 
170  $results[] = array(
171  self::FOLDER_KEY => new Folder(
172  intval($row['folder_pk']), $row['folder_name'], $row['folder_desc'], intval($row['folder_perm'])),
173  self::DEPTH_KEY => $row['depth'],
174  self::REUSE_KEY => $countUploads
175  );
176  }
177  $this->dbManager->freeResult($res);
178  return $results;
179  }
180 
186  public function countFolderUploads($parentId, $userGroupMap)
187  {
188  $trustGroupIds = array_keys($userGroupMap);
189  $statementName = __METHOD__;
190  $trustedGroups = '{' . implode(',', $trustGroupIds) . '}';
191  $parameters = array($parentId, $trustedGroups);
192 
193  $this->dbManager->prepare($statementName, "
194 SELECT group_fk group_id,count(*) FROM foldercontents fc
195  INNER JOIN upload u ON u.upload_pk = fc.child_id
196  INNER JOIN upload_clearing uc ON u.upload_pk=uc.upload_fk AND uc.group_fk=ANY($2)
197 WHERE fc.parent_fk = $1 AND fc.foldercontents_mode = " . self::MODE_UPLOAD . " AND (u.upload_mode = 100 OR u.upload_mode = 104)
198 GROUP BY group_fk
199 ");
200  $res = $this->dbManager->execute($statementName, $parameters);
201  $results = array();
202  while ($row = $this->dbManager->fetchArray($res)) {
203  $row['group_name'] = $userGroupMap[$row['group_id']];
204  $results[$row['group_name']] = $row;
205  }
206  $this->dbManager->freeResult($res);
207  return $results;
208  }
209 
210  public function getAllFolderIds()
211  {
212  $statementName = __METHOD__;
213  $this->dbManager->prepare($statementName, "SELECT DISTINCT folder_pk FROM folder");
214  $res = $this->dbManager->execute($statementName);
215  $results = $this->dbManager->fetchAll($res);
216  $this->dbManager->freeResult($res);
217 
218  $allIds = array();
219  for ($i=0; $i < sizeof($results); $i++) {
220  array_push($allIds, intval($results[$i]['folder_pk']));
221  }
222 
223  return $allIds;
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
234  INNER JOIN upload_clearing uc ON u.upload_pk=uc.upload_fk AND uc.group_fk=$2
235 WHERE fc.parent_fk = $1 AND fc.foldercontents_mode = " . self::MODE_UPLOAD . " AND (u.upload_mode = 100 OR u.upload_mode = 104);");
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  protected 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  }
388  }
389 
390  public function removeContentById($uploadpk, $folderId)
391  {
392  $sql = "DELETE FROM foldercontents WHERE child_id=$1 AND parent_fk=$2 AND foldercontents_mode=$3";
393  $this->dbManager->getSingleRow($sql,array($uploadpk, $folderId,2),__METHOD__);
394  }
395 
396  public function getFolderChildFolders($folderId)
397  {
398  $results = array();
399  $stmtFolder = __METHOD__;
400  $sqlFolder = "SELECT foldercontents_pk,foldercontents_mode, folder_name FROM foldercontents,folder "
401  . "WHERE foldercontents.parent_fk=$1 AND foldercontents.child_id=folder.folder_pk"
402  . " AND foldercontents_mode=" . self::MODE_FOLDER;
403  $this->dbManager->prepare($stmtFolder, $sqlFolder);
404  $res = $this->dbManager->execute($stmtFolder, array($folderId));
405  while ($row = $this->dbManager->fetchArray($res)) {
406  $results[$row['foldercontents_pk']] = $row;
407  }
408  $this->dbManager->freeResult($res);
409  return $results;
410  }
411 
416  public function getFolder($folderId)
417  {
418  $folderRow = $this->dbManager->getSingleRow('SELECT * FROM folder WHERE folder_pk = $1', array($folderId));
419  if (!$folderRow) {
420  return null;
421  }
422  return new Folder($folderRow['folder_pk'], $folderRow['folder_name'], $folderRow['folder_desc'], $folderRow['folder_perm']);
423  }
424 
430  public function isFolderAccessible($folderId, $userId = null)
431  {
432  $allUserFolders = array();
433  if ($userId == null) {
434  $userId = Auth::getUserId();
435  }
436  $rootFolder = $this->getRootFolder($userId)->getId();
437  GetFolderArray($rootFolder, $allUserFolders);
438  if (in_array($folderId, array_keys($allUserFolders))) {
439  return true;
440  }
441  return false;
442  }
443 
449  public function getFolderContentsId($childId)
450  {
451  $folderContentsRow = $this->dbManager->getSingleRow(
452  'SELECT foldercontents_pk FROM foldercontents '.
453  'WHERE child_id = $1', [$childId]);
454  if (!$folderContentsRow) {
455  return null;
456  }
457  return intval($folderContentsRow['foldercontents_pk']);
458  }
459 
465  public function getFolderParentId($folderPk)
466  {
467  $sql = "SELECT parent_fk FROM foldercontents " .
468  "WHERE foldercontents_mode = " . self::MODE_FOLDER .
469  " AND child_id = $1;";
470  $statement = __METHOD__ . ".getParentId";
471  $row = $this->dbManager->getSingleRow($sql, [$folderPk], $statement);
472  return (empty($row)) ? null : $row['parent_fk'];
473  }
474 }
static getUserId()
Get the current user&#39;s id.
Definition: Auth.php:69
isFolderAccessible($folderId, $userId=null)
Definition: FolderDao.php:430
GetFolderArray($RootFolder, &$FolderArray)
Get an array of all the folders from a $RootFolder on down.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:28
countFolderUploads($parentId, $userGroupMap)
Definition: FolderDao.php:186
static getGroupId()
Get the current user&#39;s group id.
Definition: Auth.php:78
getFolderUploads($parentId, $trustGroupId=null)
Definition: FolderDao.php:247