3 * FusionForge document manager
5 * Copyright 2000, Quentin Cregan/Sourceforge
6 * Copyright 2002-2003, Tim Perdue/GForge, LLC
7 * Copyright 2009, Roland Mas
8 * Copyright 2010-2011, Franck Villaume - Capgemini
9 * http://fusionforge.org
11 * This file is part of FusionForge.
13 * FusionForge is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published
15 * by the Free Software Foundation; either version 2 of the License,
16 * or (at your option) any later version.
18 * FusionForge is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with FusionForge; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 require_once $gfcommon.'include/Error.class.php';
30 require_once $gfcommon.'docman/Parsedata.class.php';
32 class Document extends Error {
35 * Associative array of data from db.
37 * @var array $data_array.
49 * The Search engine path.
51 * @var string $engine_path
58 * @param object The Group object to which this document is associated.
59 * @param int The docid.
60 * @param array The associative array of data.
61 * @return boolean success.
63 function Document(&$Group, $docid = false, $arr = false, $engine = '') {
65 if (!$Group || !is_object($Group)) {
66 $this->setNotValidGroupObjectError();
69 if ($Group->isError()) {
70 $this->setError('Document:: '. $Group->getErrorMessage());
73 $this->Group =& $Group;
76 if (!$arr || !is_array($arr)) {
77 if (!$this->fetchData($docid)) {
81 $this->data_array =& $arr;
82 if ($this->data_array['group_id'] != $this->Group->getID()) {
83 $this->setError('Document:: '. _('Group_id in db result does not match Group Object'));
84 $this->data_array = null;
88 if (!$this->isPublic()) {
89 $perm =& $this->Group->getPermission();
91 if (!$perm || !is_object($perm) || !$perm->isMember()) {
92 $this->setPermissionDeniedError();
93 $this->data_array = null;
98 $this->engine_path = $engine;
103 * create - use this function to create a new entry in the database.
105 * @param string The filename of this document. Can be a URL.
106 * @param string The filetype of this document. If filename is URL, this should be 'URL';
107 * @param string The contents of this document.
108 * @param int The doc_group id of the doc_groups table.
109 * @param string The title of this document.
110 * @param string The description of this document.
111 * @return boolean success.
113 function create($filename, $filetype, $data, $doc_group, $title, $description) {
114 if (strlen($title) < 5) {
115 $this->setError(_('Title Must Be At Least 5 Characters'));
118 if (strlen($description) < 10) {
119 $this->setError(_('Document Description Must Be At Least 10 Characters'));
123 $user_id = ((session_loggedin()) ? user_getid() : 100);
125 $doc_initstatus = '3';
126 // If Editor - uploaded Documents are ACTIVE
127 if (session_loggedin()) {
128 $perm =& $this->Group->getPermission();
129 if ($perm && is_object($perm) && $perm->isDocEditor()) {
130 $doc_initstatus = '1';
134 $result = db_query_params('SELECT filename, doc_group from docdata_vw
138 array($filename, $doc_group, $doc_initstatus));
140 if (!$result || db_numrows($result) > 0) {
141 $this->setError(_('Document already published in this directory'));
145 // If $filetype is "text/plain", $body convert UTF-8 encoding.
146 if (strcasecmp($filetype,"text/plain") === 0 &&
147 function_exists('mb_convert_encoding') &&
148 function_exists('mb_detect_encoding')) {
149 $data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
153 // key words for in-document search
154 if ($this->Group->useDocmanSearch()) {
155 $kw = new Parsedata($this->engine_path);
156 $kwords = $kw->get_parse_data($data1, htmlspecialchars($title), htmlspecialchars($description), $filetype);
161 $filesize = strlen($data);
164 $result = db_query_params('INSERT INTO doc_data (group_id,title,description,createdate,doc_group,
165 stateid,filename,filetype,filesize,data_words,created_by)
166 VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)',
167 array($this->Group->getId(),
168 htmlspecialchars($title),
169 htmlspecialchars($description),
179 $this->setError(_('Error Adding Document:').' '.db_error().$result);
184 $docid = db_insertid($result,'doc_data','docid');
186 switch ($this->Group->getStorageAPI()) {
188 $result = db_query_params('UPDATE doc_data set data = $1 where docid = $2',
189 array(base64_encode($data),$docid));
191 $this->setError(_('Error Adding Document:').' '.db_error().$result);
198 $this->setError(_('Error Adding Document: No Storage API'));
204 if (!$this->fetchData($docid)) {
208 $this->sendNotice(true);
214 * fetchData() - re-fetch the data for this document from the database.
216 * @param int The document id.
217 * @return boolean success
219 function fetchData($docid) {
220 $res = db_query_params('SELECT * FROM docdata_vw WHERE docid=$1 AND group_id=$2',
221 array($docid, $this->Group->getID()));
222 if (!$res || db_numrows($res) < 1) {
223 $this->setError(_('Document:: Invalid docid'));
226 $this->data_array = db_fetch_array($res);
227 db_free_result($res);
232 * getGroup - get the Group object this Document is associated with.
234 * @return Object The Group object.
236 function &getGroup() {
241 * getID - get this docid.
243 * @return int The docid.
246 return $this->data_array['docid'];
250 * getName - get the name of this document.
252 * @return string The name of this document.
255 return $this->data_array['title'];
259 * getDescription - the description of this document.
261 * @return string The description.
263 function getDescription() {
264 return $this->data_array['description'];
268 * isURL - whether this document is a URL and not a local file.
270 * @return boolean is_url.
273 return ($this->data_array['filetype'] == 'URL');
277 * isText - whether this document is a text document and not a binary one.
279 * @return boolean is_text.
282 $doctype = $this->data_array['filetype'];
283 if (preg_match('|^text/|i', $doctype)) { // text plain, text html, text x-patch, etc
290 * isHtml - whether this document is a html document.
292 * @return boolean is_html.
295 $doctype = $this->data_array['filetype'];
296 if (preg_match('/html/i',$doctype)) {
303 * isPublic - whether this document is available to the general public.
305 * @return boolean is_public.
307 function isPublic() {
308 return (($this->data_array['stateid'] == 1) ? true : false);
312 * getStateID - get this stateid.
314 * @return int The stateid.
316 function getStateID() {
317 return $this->data_array['stateid'];
321 * getStateName - the statename of this document.
323 * @return string The statename.
325 function getStateName() {
326 return $this->data_array['state_name'];
330 * getDocGroupID - get this doc_group_id.
332 * @return int The doc_group_id.
334 function getDocGroupID() {
335 return $this->data_array['doc_group'];
339 * getDocGroupName - the doc_group_name of this document.
341 * @return string The docgroupname.
343 function getDocGroupName() {
344 return $this->data_array['group_name'];
348 * getCreatorID - get this creator's user_id.
350 * @return int The user_id.
352 function getCreatorID() {
353 return $this->data_array['created_by'];
357 * getCreatorUserName - the unix name of the person who created this document.
359 * @return string The unix name of the creator.
361 function getCreatorUserName() {
362 return $this->data_array['user_name'];
366 * getCreatorRealName - the real name of the person who created this document.
368 * @return string The real name of the creator.
370 function getCreatorRealName() {
371 return $this->data_array['realname'];
375 * getCreatorEmail - the email of the person who created this document.
377 * @return string The email of the creator.
379 function getCreatorEmail() {
380 return $this->data_array['email'];
384 * getFileName - the filename of this document.
386 * @return string The filename.
388 function getFileName() {
389 return $this->data_array['filename'];
393 * getFileType - the filetype of this document.
395 * @return string The filetype.
397 function getFileType() {
398 return $this->data_array['filetype'];
402 * getFileData - the filedata of this document.
404 * @return string The filedata.
406 function getFileData() {
408 // Because this could be a large string, we only fetch if we actually need it
410 $res = db_query_params('SELECT data FROM doc_data WHERE docid=$1', array($this->getID()));
411 return base64_decode(db_result($res, 0, 'data'));
415 * getFileSize - Return the size of the document
417 * @return int The file size
419 function getFileSize() {
420 return $this->data_array['filesize'];
424 * getUpdated - get the time this document was updated.
426 * @return int The epoch date this document was updated.
428 function getUpdated() {
429 return $this->data_array['updatedate'];
433 * getCreated - get the time this document was created.
435 * @return int The epoch date this document was created.
437 function getCreated() {
438 return $this->data_array['createdate'];
442 * getLocked - get the lock status of this document.
444 * @return int The lock status of this document.
446 function getLocked() {
447 return $this->data_array['locked'];
451 * getLockdate - get the lock time of this document.
453 * @return int The lock time of this document.
455 function getLockdate() {
456 return $this->data_array['lockdate'];
460 * getLockedBy - get the user id who set lock on this document.
462 * @return int The user id who set lock on this document.
464 function getLockedBy() {
465 return $this->data_array['locked_by'];
469 * getReservedBy - get the owner of the reversed status of this document.
471 * @return int The owner of the reversed status of this document.
473 function getReservedBy() {
474 return $this->data_array['reserved_by'];
478 * getReserved - get the reversed status of this document.
480 * @return int The reversed status of this document.
482 function getReserved() {
483 return $this->data_array['reserved'];
487 * getMonitoredUserEmailAddress - get the email addresses of users who monitor this file
489 * @return string The list of emails comma separated
491 function getMonitoredUserEmailAddress() {
492 $result = db_query_params('select users.email from users,docdata_monitored_docman where users.user_id = docdata_monitored_docman.user_id and docdata_monitored_docman.doc_id = $1', array ($this->getID()));
493 if (!$result || db_numrows($result) < 1) {
499 while ($arr = db_fetch_array($result)) {
503 $values .= $comma.$arr['email'];
511 * isMonitoredBy - get the monitored status of this document for a specific user id.
514 * @return boolean true if monitored by this user
516 function isMonitoredBy($userid = 'ALL') {
517 if ( $userid == 'ALL' ) {
520 $condition = 'user_id='.$userid.' AND';
522 $result = db_query_params('SELECT * FROM docdata_monitored_docman WHERE '.$condition.' doc_id=$1',
523 array($this->getID()));
525 if (!$result || db_numrows($result) < 1)
532 * removeMonitoredBy - remove this document for a specific user id for monitoring.
535 * @return boolean true if success
537 function removeMonitoredBy($userid) {
538 $result = db_query_params('DELETE FROM docdata_monitored_docman WHERE doc_id=$1 AND user_id=$2',
539 array($this->getID(), $userid));
542 $this->setError(_('Unable To Remove Monitor').' : '.db_error());
549 * addMonitoredBy - add this document for a specific user id for monitoring.
552 * @return boolean true if success
554 function addMonitoredBy($userid) {
555 $result = db_query_params('SELECT * FROM docdata_monitored_docman WHERE user_id=$1 AND doc_id=$2',
556 array($userid, $this->getID()));
558 if (!$result || db_numrows($result) < 1) {
559 $result = db_query_params('INSERT INTO docdata_monitored_docman (doc_id,user_id) VALUES ($1,$2)',
560 array($this->getID(), $userid));
563 $this->setError(_('Unable To Add Monitor').' : '.db_error());
571 * setState - set the stateid of the document.
573 * @param int The state id of the doc_states table.
574 * @return boolean success.
576 function setState($stateid) {
577 $res = db_query_params('UPDATE doc_data SET
582 $this->Group->getID(),
585 if (!$res || db_affected_rows($res) < 1) {
586 $this->setOnUpdateError(db_error());
589 $this->sendNotice(false);
594 * setLock - set the locking status of the document
596 * @param int The status of the lock
597 * @param int The userid who set the lock
598 * @param time the epoch time
599 * @return boolean success
601 function setLock($stateLock, $userid = NULL, $thistime = 0) {
602 $res = db_query_params('UPDATE doc_data SET
611 $this->Group->getID(),
614 if (!$res || db_affected_rows($res) < 1) {
615 $this->setOnUpdateError(_('Document lock failed').' '.db_error());
618 $this->data_array['locked'] = $stateLock;
619 $this->data_array['locked_by'] = $userid;
620 $this->data_array['lockdate'] = $thistime;
625 * setReservedBy - set the reserved status of the document and the owner
627 * @param int The status of the reserved
628 * @param int The ID of the owner : by default : noone
629 * @return boolean success
631 function setReservedBy($statusReserved, $idReserver = NULL) {
632 $res = db_query_params('UPDATE doc_data SET
637 array($statusReserved,
639 $this->Group->getID(),
642 if (!$res || db_affected_rows($res) < 1) {
643 $this->setOnUpdateError(_('Document reservation failed').' '.db_error());
646 $this->sendNotice(false);
651 * getFileTypeImage - return the file image for icon
653 * @return string the file image name
656 function getFileTypeImage() {
657 switch ($this->getFileType()) {
662 case "image/vnd.microsoft.icon":
663 case "image/svg+xml": {
664 $image = 'docman/file_type_image.png';
667 case "application/pdf": {
668 $image = 'docman/file_type_pdf.png';
673 $image = 'docman/file_type_html.png';
678 case "application/xml":
680 $image = 'docman/file_type_plain.png';
683 case "application/msword":
684 case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
685 case "application/vnd.oasis.opendocument.text": {
686 $image = 'docman/file_type_writer.png';
689 case "application/vnd.ms-excel":
690 case "application/vnd.oasis.opendocument.spreadsheet":
691 case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
692 $image = 'docman/file_type_spreadsheet.png';
695 case "application/vnd.oasis.opendocument.presentation":
696 case "application/vnd.ms-powerpoint":
697 case "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
698 $image = 'docman/file_type_presentation.png';
701 case "application/zip":
702 case "application/x-tar":
703 case "application/x-rpm":
704 case "application/x-rar-compressed":
705 case "application/x-bzip2":
706 case "application/x-gzip":
707 case "application/x-lzip":
708 case "application/x-compress":
709 case "application/x-7z-compressed":
710 case "application/x-gtar":
711 case "application/x-stuffitx":
712 case "application/x-lzx":
713 case "application/x-lzh":
714 case "application/x-gca-compressed":
715 case "application/x-apple-diskimage":
716 case "application/x-dgc-compressed":
717 case "application/x-dar":
718 case "application/x-cfs-compressed":
719 case "application/vnd.ms-cab-compressed":
720 case "application/x-alz-compressed":
721 case "application/x-astrotite-afa":
722 case "application/x-ace-compressed":
723 case "application/x-cpio":
724 case "application/x-shar":
725 case "application/x-xz": {
726 $image = 'docman/file_type_archive.png';
730 $image = 'docman/file_type_unknown.png';
737 * update - use this function to update an existing entry in the database.
739 * @param string The filename of this document. Can be a URL.
740 * @param string The filetype of this document. If filename is URL, this should be 'URL';
741 * @param string The contents of this document.
742 * @param int The doc_group id of the doc_groups table.
743 * @param string The title of this document.
744 * @param string The description of this document.
745 * @param int The state id of the doc_states table.
746 * @return boolean success.
748 function update($filename, $filetype, $data, $doc_group, $title, $description, $stateid) {
751 $perm =& $this->Group->getPermission();
752 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
753 $this->setPermissionDeniedError();
757 if ($this->getLockedBy() != $LUSER->getID()) {
758 $this->setPermissionDeniedError();
762 if (strlen($title) < 5) {
763 $this->setError(_('Title Must Be At Least 5 Characters'));
767 if (strlen($description) < 10) {
768 $this->setError(_('Document Description Must Be At Least 10 Characters'));
773 $result = db_query_params('SELECT filename, doc_group FROM docdata_vw WHERE filename = $1 and doc_group = $2 and stateid = $3',
774 array($filename, $doc_group, $stateid));
775 if (!$result || db_numrows($result) > 0) {
776 $this->setError(_('Document already published in this directory'));
781 $res = db_query_params('UPDATE doc_data SET
793 array(htmlspecialchars($title),
794 htmlspecialchars($description),
802 $this->Group->getID(),
806 if (!$res || db_affected_rows($res) < 1) {
807 $this->setOnUpdateError(db_error());
814 // key words for in-document search
815 if ($this->Group->useDocmanSearch()) {
816 $kw = new Parsedata($this->engine_path);
817 $kwords = $kw->get_parse_data($data1, htmlspecialchars($title), htmlspecialchars($description), $filetype);
822 $res = db_query_params('UPDATE doc_data SET filesize=$1, data_words=$2 WHERE group_id=$3 AND docid=$4',
825 $this->Group->getID(),
829 if (!$res || db_affected_rows($res) < 1) {
830 $this->setOnUpdateError(db_error());
834 switch ($this->Group->getStorageAPI()) {
836 $res = db_query_params('UPDATE doc_data SET data = $1 where group_id = $2 and docid = $3',
837 array(base64_encode($data),
838 $this->Group->getID(),
842 if (!$res || db_affected_rows($res) < 1) {
843 $this->setOnUpdateError(db_error());
849 $this->setOnUpdateError(_('No Storage API'));
855 $this->sendNotice(false);
860 * sendNotice - Notifies of document submissions
862 * @param boolean true = new document (default value)
864 function sendNotice ($new=true) {
865 $BCC = $this->Group->getDocEmailAddress();
866 if ($this->isMonitoredBy('ALL')) {
867 $BCC .= $this->getMonitoredUserEmailAddress();
869 if (strlen($BCC) > 0) {
871 $status = _('New document');
873 $status = _('Updated document');
875 $subject = '['.$this->Group->getPublicName().'] '.$status.' - '.$this->getName();
876 $body = _('Project:').' '.$this->Group->getPublicName()."\n";
877 $body .= _('Directory:').' '.$this->getDocGroupName()."\n";
878 $body .= _('Document title:').' '.$this->getName()."\n";
879 $body .= _('Document description:').' '.util_unconvert_htmlspecialchars($this->getDescription())."\n";
880 $body .= _('Submitter:').' '.$this->getCreatorRealName()." (".$this->getCreatorUserName().") \n";
881 $body .= "\n\n-------------------------------------------------------\n".
882 _('For more info, visit:').
883 "\n\n" . util_make_url('/docman/?group_id='.$this->Group->getID().'&view=listfile&dirid='.$this->getDocGroupID());
885 util_send_message('', $subject, $body, '', $BCC);
892 * delete - Delete this file
894 * @return boolean success
897 $perm =& $this->Group->getPermission();
898 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
899 $this->setPermissionDeniedError();
903 $result = db_query_params('DELETE FROM doc_data WHERE docid=$1',
904 array($this->getID()));
906 $this->setError(_('Error Deleting Document:').' '.db_error());
911 switch ($this->Group->getStorageAPI()) {
916 $this->setError(_('Error Deleting Document: No Storage API'));
922 // we should be able to send a notice that this doc has been deleted .... but we need to rewrite sendNotice
923 //$this->sendNotice(false);
930 // c-file-style: "bsd"