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.
49 * @internal param \The $object Group object to which this document is associated.
51 function __construct(&$Group) {
52 parent::__construct();
53 if (!$Group || !is_object($Group)) {
54 $this->setError(_('Invalid Project'));
57 if ($Group->isError()) {
58 $this->setError('DocumentManager: '. $Group->getErrorMessage());
61 $this->Group =& $Group;
65 * getGroup - get the Group object this Document is associated with.
67 * @return Object The Group object.
69 function &getGroup() {
74 * getTrashID - the trash doc_group id for this DocumentManager.
76 * @return integer The trash doc_group id.
78 function getTrashID() {
79 if (isset($this->data_array['trashid']))
80 return $this->data_array['trashid'];
82 $res = db_query_params('SELECT doc_group from doc_groups
86 array('.trash', $this->Group->getID(), '2'));
87 if (db_numrows($res) == 1) {
88 $arr = db_fetch_array($res);
89 $this->data_array['trashid'] = $arr['doc_group'];
90 return $this->data_array['trashid'];
92 $dg = new DocumentGroup($this->Group);
93 $dg->create('.trash');
100 * cleanTrash - delete all items in trash for this DocumentManager
102 * @return boolean true on success
104 function cleanTrash() {
105 $trashId = $this->getTrashID();
106 if ($trashId !== -1) {
108 $result = db_query_params('select docid FROM doc_data WHERE stateid=$1 and group_id=$2', array('2', $this->Group->getID()));
109 $emptyFile = db_query_params('DELETE FROM doc_data WHERE stateid=$1 and group_id=$2', array('2', $this->Group->getID()));
114 $emptyDir = db_query_params('DELETE FROM doc_groups WHERE stateid=$1 and group_id=$2 and groupname !=$3', array('2', $this->Group->getID(), '.trash'));
119 while ($arr = db_fetch_array($result)) {
120 DocumentStorage::instance()->delete($arr['docid'])->commit();
129 * isTrashEmpty - check if the trash is empty
130 * @return boolean success or not
132 function isTrashEmpty() {
133 if ($this->Group->usesPlugin('projects-hierarchy')) {
134 $projectsHierarchy = plugin_get_object('projects-hierarchy');
135 $projectIDsArray = $projectsHierarchy->getFamily($this->Group->getID(), 'child', true, 'validated');
139 if (isset($projectIDsArray) && is_array($projectIDsArray)) {
140 foreach ($projectIDsArray as $projectID) {
141 $groupObject = group_get_object($projectID);
142 if ($groupObject->usesDocman() && $projectsHierarchy->getDocmanStatus($groupObject->getID())
143 && forge_check_perm('docman', $groupObject->getID(), 'approve')) {
144 $groupIdArr[] = $projectID;
148 $groupIdArr[] = $this->Group->getID();
150 $res = db_query_params('select ( select count(*) from doc_groups where group_id = ANY ($1) and stateid = 2 and groupname !=$2 )
151 + ( select count(*) from docdata_vw where group_id = ANY ($3) and stateid = 2 ) as c',
152 array(db_int_array_to_any_clause($groupIdArr), '.trash', db_int_array_to_any_clause($groupIdArr)));
157 return (db_result($res, 0, 'c') == 0);
161 * getHTMLTree - display recursively the content of the doc_group. Only doc_groups within doc_groups.
163 * @param int $selecteddir the selected directory
164 * @param string $linkmenu the type of link in the menu
165 * @param int $docGroupId the doc_group to start: default 0
167 function getHTMLTree($selecteddir, $linkmenu, $docGroupId = 0) {
168 global $g; // the master group of all the groups .... anyway. Needed to support projects-hierarchy plugin
169 $dg = new DocumentGroup($this->Group);
171 case 'listtrashfile': {
173 $doc_group_stateid = array(2);
178 $doc_group_stateid = array(1);
179 if (forge_check_perm('docman', $this->Group->getID(), 'approve')) {
180 $doc_group_stateid = array(1, 3, 4, 5);
185 $subGroupIdArr = $dg->getSubgroup($docGroupId, $doc_group_stateid);
186 if (sizeof($subGroupIdArr)) {
187 foreach ($subGroupIdArr as $subGroupIdValue) {
188 $localDg = documentgroup_get_object($subGroupIdValue, $this->Group->getID());
189 $liclass = 'docman_li_treecontent';
190 if ($selecteddir == $localDg->getID()) {
191 $liclass = 'docman_li_treecontent_selected';
193 // support projects-hierarchy plugin
194 if ($this->Group->getID() != $g->getID()) {
195 $link = '/docman/?group_id='.$g->getID().'&view='.$linkmenu.'&dirid='.$localDg->getID().'&childgroup_id='.$this->Group->getID();
197 $link = '/docman/?group_id='.$this->Group->getID().'&view='.$linkmenu.'&dirid='.$localDg->getID();
200 $nbDocs = $localDg->getNumberOfDocuments($stateId);
201 if ($stateId == 1 && forge_check_perm('docman', $this->Group->getID(), 'approve')) {
202 $nbDocsPending = $localDg->getNumberOfDocuments(3);
203 $nbDocsHidden = $localDg->getNumberOfDocuments(4);
204 $nbDocsPrivate = $localDg->getNumberOfDocuments(5);
207 if ($stateId == 2 && forge_check_perm('docman', $this->Group->getID(), 'approve')) {
208 $nbDocsTrashed = $localDg->getNumberOfDocuments(2);
211 if ($nbDocs && (!isset($nbDocsPending) || $nbDocsPending == 0) && (!isset($nbDocsHidden) || $nbDocsHidden == 0) && (!isset($nbDocsPrivate) || $nbDocsPrivate) && (!isset($nbDocsTrashed) || $nbDocsTrashed)) {
212 $nbDocsLabel = html_e('span', array('title' => _('Number of documents in this folder')), '('.$nbDocs.')', false);
214 if (isset($nbDocsPending) && isset($nbDocsHidden) && isset($nbDocsPrivate)) {
215 $nbDocsLabel = html_e('span', array('title' => _('Number of documents in this folder per status. active/pending/hidden/private')), '('.$nbDocs.'/'.$nbDocsPending.'/'.$nbDocsHidden.'/'.$nbDocsPrivate.')', false);
217 if (isset($nbDocsTrashed)) {
218 $nbDocsLabel = html_e('span', array('title' => _('Number of deleted documents in this folder')), '('.$nbDocsTrashed.')', false);
220 if ($localDg->getName() != '.trash') {
222 if ($localDg->getCreated_by()) {
223 $user = user_get_object($localDg->getCreated_by());
224 $lititle .= _('Created by')._(': ').$user->getRealName();
226 if ($localDg->getLastModifyDate()) {
230 $lititle .= _('Last Modified')._(': ').relative_date($localDg->getLastModifyDate());
232 $linkname = $localDg->getName();
233 if ($localDg->getState() == 5) {
234 $linkname .= ' '._('(private)');
236 //use   + inline to support Chrome browser correctly
237 echo html_ao('li', array('id' => 'leaf-'.$subGroupIdValue, 'class' => $liclass)).' '.util_make_link($link, $localDg->getName(), array('title'=>$lititle, 'style' => 'display: inline')).$nbDocsLabel;
239 echo html_ao('li', array('id' => 'leaf-'.$subGroupIdValue, 'class' => $liclass)).' '.util_make_link($link, $localDg->getName(), array('style' => 'display: inline')).$nbDocsLabel;
241 if ($dg->getSubgroup($subGroupIdValue, $doc_group_stateid)) {
242 echo html_ao('ul', array('class' => 'simpleTreeMenu'));
243 $this->getHTMLTree($selecteddir, $linkmenu, $subGroupIdValue);
244 echo html_ac(html_ap() - 1);
246 echo html_ac(html_ap() -1);
252 * getTree - retrieve the tree structure into an organized array
254 * @param int $docGroupId the doc_group to start: default 0
256 function getTree($docGroupId = 0) {
257 $dg = new DocumentGroup($this->Group);
258 $stateid = array(1, 2, 3, 4, 5);
259 $tree = $dg->getSubgroup($docGroupId, $stateid);
261 foreach ($tree as $key => $value) {
262 $tree[$key] = (array)documentgroup_get_object($value, $this->Group->getID());
263 unset($tree[$key]['Group']);
264 $tree[$key]['subdocgroups'] = $this->getTree($value);
265 $df = new DocumentFactory($this->Group);
266 $df->setDocGroupID($value);
267 $df->setStateID($stateid);
268 $df->setOrder(array('docid'));
269 $tree[$key]['files'] = (array)$df->getDocumentsWithVersions();
276 * getSettings - return the configuration flags of the docman
279 function getSettings() {
280 $settingsArr = array();
281 $settingsArr['new_doc_address'] = $this->Group->data_array['new_doc_address'];
282 $settingsArr['send_all_docs'] = $this->Group->data_array['send_all_docs'];
283 $settingsArr['use_docman_search'] = $this->Group->data_array['use_docman_search'];
284 $settingsArr['force_docman_reindex'] = $this->Group->data_array['force_docman_reindex'];
285 $settingsArr['use_webdav'] = $this->Group->data_array['use_webdav'];
286 $settingsArr['use_docman_create_online'] = $this->Group->data_array['use_docman_create_online'];
287 $settingsArr['use_docman_review'] = forge_get_config('use_docman_review');
292 * getStatusNameList - get all status for documents
294 * @param string $format format of the return values. json returns : { name: id, }. Default is DB object.
295 * @param string $removedval skipped status id
296 * @return resource|string
298 function getStatusNameList($format = '', $removedval = '') {
299 if (!empty($removedval)) {
300 $stateQuery = db_query_params('select * from doc_states where stateid not in ($1) order by stateid', array($removedval));
302 $stateQuery = db_query_params('select * from doc_states order by stateid', array());
307 while ($stateArr = db_fetch_array($stateQuery)) {
308 $returnString .= util_html_secure($stateArr['name']).': \''.$stateArr['stateid'].'\',';
310 $returnString .= '}';
311 return $returnString;
320 * getDocGroupList - Returns as a string used in javascript the list of available folders
322 * @param array $nested_groups
323 * @param string $format must be json which is wrong, this function does not return any json object
324 * @param bool $allow_none allow the "None" which is the "/"
325 * @param int $selected_id the selected folder id
326 * @param array $dont_display folders id to not display
329 function getDocGroupList($nested_groups, $format = '', $allow_none = true, $selected_id = 0, $dont_display = array()) {
331 $text_array = array();
332 $this->buildArrays($nested_groups, $id_array, $text_array, $dont_display);
333 $rows = count($id_array);
337 for ($i = 0; $i < $rows; $i++) {
338 $returnString .= '['.$id_array[$i].',\''.util_html_secure(addslashes($text_array[$i])).'\'],';
340 $returnString .= ']';
344 return $returnString;
348 * showSelectNestedGroups - Display the tree of document groups inside a <select> tag
350 * @param array $group_arr Array of groups.
351 * @param string $select_name The name that will be assigned to the input
352 * @param bool $allow_none Allow selection of "None"
353 * @param int $selected_id The ID of the group that should be selected by default (if any)
354 * @param array $dont_display Array of IDs of groups that should not be displayed
355 * @param bool $display_files Display filename instead of directory name only.
356 * @return string html select box code
358 function showSelectNestedGroups($group_arr, $select_name, $allow_none = true, $selected_id = 0, $dont_display = array(), $display_files = false) {
359 // Build arrays for calling html_build_select_box_from_arrays()
361 $text_array = array();
364 // First option to be displayed
366 $text_array[] = _('None');
369 // Recursively build the document group tree
370 $this->buildArrays($group_arr, $id_array, $text_array, $dont_display, 0, 0, $display_files);
372 return html_build_select_box_from_arrays($id_array, $text_array, $select_name, $selected_id, false);
376 * buildArrays - Build the arrays to call html_build_select_box_from_arrays()
378 * @param array $group_arr Array of groups.
379 * @param array $id_array Reference to the array of ids that will be build
380 * @param array $text_array Reference to the array of group names
381 * @param array $dont_display Array of IDs of groups that should not be displayed
382 * @param int $parent The ID of the parent whose childs are being showed (0 for root groups)
383 * @param int $level The current level
384 * @param bool $display_files Set filename instead of directory name.
386 function buildArrays($group_arr, &$id_array, &$text_array, &$dont_display, $parent = 0, $level = 0, $display_files = false) {
387 if (!is_array($group_arr) || !array_key_exists("$parent", $group_arr)) return;
389 $child_count = count($group_arr["$parent"]);
390 for ($i = 0; $i < $child_count; $i++) {
391 $doc_group =& $group_arr["$parent"][$i];
393 // Should we display this element?
394 if (in_array($doc_group->getID(), $dont_display)) continue;
396 $margin = str_repeat("--", $level);
398 if (!$display_files) {
399 $id_array[] = $doc_group->getID();
400 $text_array[] = $margin.$doc_group->getName();
402 $df = new DocumentFactory($doc_group->getGroup());
403 $df->setDocGroupID($doc_group->getID());
404 if (forge_check_perm('docman', $this->getGroup()->getID(), 'approve')) {
407 $df->setStateID(array(1, 4, 5));
408 $df->setDocGroupState($stateIdDg);
409 $docs = $df->getDocuments();
410 if (is_array($docs)) {
411 foreach ($docs as $doc) {
412 if (!$doc->isURL()) {
413 $id_array[] = $doc->getID();
414 $text_array[] = $margin.$doc_group->getName().'/'.$doc->getFileName();
419 // Show childs (if any)
420 $this->buildArrays($group_arr, $id_array, $text_array, $dont_display, $doc_group->getID(), $level+1, $display_files);
425 * getActivity - return the number of searched actions per sections between two dates
427 * @param array $sections Sections to search for activity
428 * @param int $begin the start date time format time()
429 * @param int $end the end date time format time()
430 * @return array number per section of activities found between begin and end values
432 function getActivity($sections, $begin, $end) {
434 for ($i = 0; $i < count($sections); $i++) {
435 $results[$sections[$i]] = 0;
437 if (count($sections) >= 1 && $i != count($sections) -1) {
440 $qpa = db_construct_qpa(false, 'SELECT count(*) FROM activity_vw WHERE activity_date BETWEEN $1 AND $2
441 AND group_id = $3 AND section = $4 ',
444 $this->getGroup()->getID(),
447 $qpa = db_construct_qpa($qpa, ' UNION ALL ', array());
450 $res = db_query_qpa($qpa);
452 while ($arr = db_fetch_array($res)) {
453 $results[$sections[$j]] = $arr['0'];