3 * FusionForge Documentation Manager
5 * Copyright 2011-2014,2016-2017, Franck Villaume - TrivialDev
6 * Copyright (C) 2012 Alain Peyrat - Alcatel-Lucent
7 * Copyright 2013, French Ministry of National Education
8 * http://fusionforge.org
10 * This file is part of FusionForge. FusionForge is free software;
11 * you can redistribute it and/or modify it under the terms of the
12 * GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the Licence, or (at your option)
16 * FusionForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 require_once $gfcommon.'include/FFError.class.php';
27 require_once $gfcommon.'include/User.class.php';
28 require_once $gfcommon.'docman/DocumentGroup.class.php';
29 require_once $gfcommon.'docman/DocumentFactory.class.php';
31 class DocumentManager extends FFError {
34 * Associative array of data from db.
36 * @var array $data_array.
50 function __construct(&$Group) {
51 parent::__construct();
52 if (!$Group || !is_object($Group)) {
53 $this->setError(_('Invalid Project'));
56 if ($Group->isError()) {
57 $this->setError('DocumentManager: '. $Group->getErrorMessage());
60 $this->Group =& $Group;
64 * getGroup - get the Group object this Document is associated with.
66 * @return Object The Group object.
68 function &getGroup() {
73 * getTrashID - the trash doc_group id for this DocumentManager.
75 * @return integer The trash doc_group id.
77 function getTrashID() {
78 if (isset($this->data_array['trashid']))
79 return $this->data_array['trashid'];
81 $res = db_query_params('SELECT doc_group from doc_groups
85 array('.trash', $this->Group->getID(), '2'));
86 if (db_numrows($res) == 1) {
87 $arr = db_fetch_array($res);
88 $this->data_array['trashid'] = $arr['doc_group'];
89 return $this->data_array['trashid'];
91 $dg = new DocumentGroup($this->Group);
92 $dg->create('.trash');
99 * cleanTrash - delete all items in trash for this DocumentManager
101 * @return boolean true on success
103 function cleanTrash() {
104 $trashId = $this->getTrashID();
105 if ($trashId !== -1) {
107 $result = db_query_params('select docid FROM doc_data WHERE stateid=$1 and group_id=$2', array('2', $this->Group->getID()));
108 $emptyFile = db_query_params('DELETE FROM doc_data WHERE stateid=$1 and group_id=$2', array('2', $this->Group->getID()));
113 $emptyDir = db_query_params('DELETE FROM doc_groups WHERE stateid=$1 and group_id=$2 and groupname !=$3', array('2', $this->Group->getID(), '.trash'));
118 while ($arr = db_fetch_array($result)) {
119 DocumentStorage::instance()->delete($arr['docid'])->commit();
128 * isTrashEmpty - check if the trash is empty
129 * @return boolean success or not
131 function isTrashEmpty() {
132 if ($this->Group->usesPlugin('projects-hierarchy')) {
133 $projectsHierarchy = plugin_get_object('projects-hierarchy');
134 $projectIDsArray = $projectsHierarchy->getFamily($this->Group->getID(), 'child', true, 'validated');
138 if (isset($projectIDsArray) && is_array($projectIDsArray)) {
139 foreach ($projectIDsArray as $projectID) {
140 $groupObject = group_get_object($projectID);
141 if ($groupObject->usesDocman() && $projectsHierarchy->getDocmanStatus($groupObject->getID())
142 && forge_check_perm('docman', $groupObject->getID(), 'approve')) {
143 $groupIdArr[] = $projectID;
147 $groupIdArr[] = $this->Group->getID();
149 $res = db_query_params('select ( select count(*) from doc_groups where group_id = ANY ($1) and stateid = 2 and groupname !=$2 )
150 + ( select count(*) from docdata_vw where group_id = ANY ($3) and stateid = 2 ) as c',
151 array(db_int_array_to_any_clause($groupIdArr), '.trash', db_int_array_to_any_clause($groupIdArr)));
156 return (db_result($res, 0, 'c') == 0);
160 * getHTMLTree - display recursively the content of the doc_group. Only doc_groups within doc_groups.
162 * @param int $selecteddir the selected directory
163 * @param string $linkmenu the type of link in the menu
164 * @param int $docGroupId the doc_group to start: default 0
166 function getHTMLTree($selecteddir, $linkmenu, $docGroupId = 0) {
167 global $g; // the master group of all the groups .... anyway. Needed to support projects-hierarchy plugin
168 $dg = new DocumentGroup($this->Group);
170 case 'listtrashfile': {
172 $doc_group_stateid = array(2);
177 $doc_group_stateid = array(1);
178 if (forge_check_perm('docman', $this->Group->getID(), 'approve')) {
179 $doc_group_stateid = array(1, 3, 4, 5);
184 $subGroupIdArr = $dg->getSubgroup($docGroupId, $doc_group_stateid);
185 if (sizeof($subGroupIdArr)) {
186 foreach ($subGroupIdArr as $subGroupIdValue) {
187 $localDg = documentgroup_get_object($subGroupIdValue, $this->Group->getID());
188 $liclass = 'docman_li_treecontent';
189 if ($selecteddir == $localDg->getID()) {
190 $liclass = 'docman_li_treecontent_selected';
192 // support projects-hierarchy plugin
193 if ($this->Group->getID() != $g->getID()) {
194 $link = '/docman/?group_id='.$g->getID().'&view='.$linkmenu.'&dirid='.$localDg->getID().'&childgroup_id='.$this->Group->getID();
196 $link = '/docman/?group_id='.$this->Group->getID().'&view='.$linkmenu.'&dirid='.$localDg->getID();
199 $nbDocs = $localDg->getNumberOfDocuments($stateId);
200 if ($stateId == 1 && forge_check_perm('docman', $this->Group->getID(), 'approve')) {
201 $nbDocsPending = $localDg->getNumberOfDocuments(3);
202 $nbDocsHidden = $localDg->getNumberOfDocuments(4);
203 $nbDocsPrivate = $localDg->getNumberOfDocuments(5);
206 if ($stateId == 2 && forge_check_perm('docman', $this->Group->getID(), 'approve')) {
207 $nbDocsTrashed = $localDg->getNumberOfDocuments(2);
210 if ($nbDocs && (!isset($nbDocsPending) || $nbDocsPending == 0) && (!isset($nbDocsHidden) || $nbDocsHidden == 0) && (!isset($nbDocsPrivate) || $nbDocsPrivate) && (!isset($nbDocsTrashed) || $nbDocsTrashed)) {
211 $nbDocsLabel = html_e('span', array('title' => _('Number of documents in this folder')), '('.$nbDocs.')', false);
213 if (isset($nbDocsPending) && isset($nbDocsHidden) && isset($nbDocsPrivate)) {
214 $nbDocsLabel = html_e('span', array('title' => _('Number of documents in this folder per status. active/pending/hidden/private')), '('.$nbDocs.'/'.$nbDocsPending.'/'.$nbDocsHidden.'/'.$nbDocsPrivate.')', false);
216 if (isset($nbDocsTrashed)) {
217 $nbDocsLabel = html_e('span', array('title' => _('Number of deleted documents in this folder')), '('.$nbDocsTrashed.')', false);
219 if ($localDg->getName() != '.trash') {
221 if ($localDg->getCreated_by()) {
222 $user = user_get_object($localDg->getCreated_by());
223 $lititle .= _('Created by')._(': ').$user->getRealName();
225 if ($localDg->getLastModifyDate()) {
229 $lititle .= _('Last Modified')._(': ').relative_date($localDg->getLastModifyDate());
231 $linkname = $localDg->getName();
232 if ($localDg->getState() == 5) {
233 $linkname .= ' '._('(private)');
235 //use   + inline to support Chrome browser correctly
236 echo html_ao('li', array('id' => 'leaf-'.$subGroupIdValue, 'class' => $liclass)).' '.util_make_link($link, $localDg->getName(), array('title'=>$lititle, 'style' => 'display: inline')).$nbDocsLabel;
238 echo html_ao('li', array('id' => 'leaf-'.$subGroupIdValue, 'class' => $liclass)).' '.util_make_link($link, $localDg->getName(), array('style' => 'display: inline')).$nbDocsLabel;
240 if ($dg->getSubgroup($subGroupIdValue, $doc_group_stateid)) {
241 echo html_ao('ul', array('class' => 'simpleTreeMenu'));
242 $this->getHTMLTree($selecteddir, $linkmenu, $subGroupIdValue);
243 echo html_ac(html_ap() - 1);
245 echo html_ac(html_ap() -1);
251 * getTree - retrieve the tree structure into an organized array
253 * @param int $docGroupId the doc_group to start: default 0
255 function getTree($docGroupId = 0) {
256 $dg = new DocumentGroup($this->Group);
257 $stateid = array(1, 2, 3, 4, 5);
258 $tree = $dg->getSubgroup($docGroupId, $stateid);
260 foreach ($tree as $key => $value) {
261 $tree[$key] = (array)documentgroup_get_object($value, $this->Group->getID());
262 unset($tree[$key]['Group']);
263 $tree[$key]['subdocgroups'] = $this->getTree($value);
264 $df = new DocumentFactory($this->Group);
265 $df->setDocGroupID($value);
266 $df->setStateID($stateid);
267 $df->setOrder(array('docid'));
268 $tree[$key]['files'] = (array)$df->getDocumentsWithVersions();
275 * getSettings - return the configuration flags of the docman
278 function getSettings() {
279 $settingsArr = array();
280 $settingsArr['new_doc_address'] = $this->Group->data_array['new_doc_address'];
281 $settingsArr['send_all_docs'] = $this->Group->data_array['send_all_docs'];
282 $settingsArr['use_docman_search'] = $this->Group->data_array['use_docman_search'];
283 $settingsArr['force_docman_reindex'] = $this->Group->data_array['force_docman_reindex'];
284 $settingsArr['use_webdav'] = $this->Group->data_array['use_webdav'];
285 $settingsArr['use_docman_create_online'] = $this->Group->data_array['use_docman_create_online'];
286 $settingsArr['use_docman_review'] = forge_get_config('use_docman_review');
291 * getStatusNameList - get all status for documents
293 * @param string $format format of the return values. json returns : { name: id, }. Default is DB object.
294 * @param string $removedval skipped status id
295 * @return resource|string
297 function getStatusNameList($format = '', $removedval = '') {
298 if (!empty($removedval)) {
299 $stateQuery = db_query_params('select * from doc_states where stateid not in ($1) order by stateid', array($removedval));
301 $stateQuery = db_query_params('select * from doc_states order by stateid', array());
306 while ($stateArr = db_fetch_array($stateQuery)) {
307 $returnString .= util_html_secure($stateArr['name']).': \''.$stateArr['stateid'].'\',';
309 $returnString .= '}';
310 return $returnString;
319 * getDocGroupList - Returns as a string used in javascript the list of available folders
321 * @param array $nested_groups
322 * @param string $format must be json which is wrong, this function does not return any json object
323 * @param bool $allow_none allow the "None" which is the "/"
324 * @param int $selected_id the selected folder id
325 * @param array $dont_display folders id to not display
328 function getDocGroupList($nested_groups, $format = '', $allow_none = true, $selected_id = 0, $dont_display = array()) {
330 $text_array = array();
331 $this->buildArrays($nested_groups, $id_array, $text_array, $dont_display);
332 $rows = count($id_array);
336 for ($i = 0; $i < $rows; $i++) {
337 $returnString .= '['.$id_array[$i].',\''.util_html_secure(addslashes($text_array[$i])).'\'],';
339 $returnString .= ']';
343 return $returnString;
347 * showSelectNestedGroups - Display the tree of document groups inside a <select> tag
349 * @param array $group_arr Array of groups.
350 * @param string $select_name The name that will be assigned to the input
351 * @param bool $allow_none Allow selection of "None"
352 * @param int $selected_id The ID of the group that should be selected by default (if any)
353 * @param array $dont_display Array of IDs of groups that should not be displayed
354 * @param bool $display_files Display filename instead of directory name only.
355 * @return string html select box code
357 function showSelectNestedGroups($group_arr, $select_name, $allow_none = true, $selected_id = 0, $dont_display = array(), $display_files = false) {
358 // Build arrays for calling html_build_select_box_from_arrays()
360 $text_array = array();
363 // First option to be displayed
365 $text_array[] = _('None');
368 // Recursively build the document group tree
369 $this->buildArrays($group_arr, $id_array, $text_array, $dont_display, 0, 0, $display_files);
371 return html_build_select_box_from_arrays($id_array, $text_array, $select_name, $selected_id, false);
375 * buildArrays - Build the arrays to call html_build_select_box_from_arrays()
377 * @param array $group_arr Array of groups.
378 * @param array $id_array Reference to the array of ids that will be build
379 * @param array $text_array Reference to the array of group names
380 * @param array $dont_display Array of IDs of groups that should not be displayed
381 * @param int $parent The ID of the parent whose childs are being showed (0 for root groups)
382 * @param int $level The current level
383 * @param bool $display_files Set filename instead of directory name.
385 function buildArrays($group_arr, &$id_array, &$text_array, &$dont_display, $parent = 0, $level = 0, $display_files = false) {
386 if (!is_array($group_arr) || !array_key_exists("$parent", $group_arr)) return;
388 $child_count = count($group_arr["$parent"]);
389 for ($i = 0; $i < $child_count; $i++) {
390 $doc_group =& $group_arr["$parent"][$i];
392 // Should we display this element?
393 if (in_array($doc_group->getID(), $dont_display)) continue;
395 $margin = str_repeat("--", $level);
397 if (!$display_files) {
398 $id_array[] = $doc_group->getID();
399 $text_array[] = $margin.$doc_group->getName();
401 $df = new DocumentFactory($doc_group->getGroup());
402 $df->setDocGroupID($doc_group->getID());
403 if (forge_check_perm('docman', $this->getGroup()->getID(), 'approve')) {
406 $df->setStateID(array(1, 4, 5));
407 $df->setDocGroupState($stateIdDg);
408 $docs = $df->getDocuments();
409 if (is_array($docs)) {
410 foreach ($docs as $doc) {
411 if (!$doc->isURL()) {
412 $id_array[] = $doc->getID();
413 $text_array[] = $margin.$doc_group->getName().'/'.$doc->getFileName();
418 // Show childs (if any)
419 $this->buildArrays($group_arr, $id_array, $text_array, $dont_display, $doc_group->getID(), $level+1, $display_files);
424 * getActivity - return the number of searched actions per sections between two dates
426 * @param array $sections Sections to search for activity
427 * @param int $begin the start date time format time()
428 * @param int $end the end date time format time()
429 * @return array number per section of activities found between begin and end values
431 function getActivity($sections, $begin, $end) {
433 for ($i = 0; $i < count($sections); $i++) {
434 $results[$sections[$i]] = 0;
436 if (count($sections) >= 1 && $i != count($sections) -1) {
439 $qpa = db_construct_qpa(false, 'SELECT count(*) FROM activity_vw WHERE activity_date BETWEEN $1 AND $2
440 AND group_id = $3 AND section = $4 ',
443 $this->getGroup()->getID(),
446 $qpa = db_construct_qpa($qpa, ' UNION ALL ', array());
449 $res = db_query_qpa($qpa);
451 while ($arr = db_fetch_array($res)) {
452 $results[$sections[$j]] = $arr['0'];