3 * FusionForge Documentation 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 * Copyright (C) 2011-2012 Alain Peyrat - Alcatel-Lucent
10 * Copyright 2011-2017,2021-2022, Franck Villaume - TrivialDev
11 * http://fusionforge.org
13 * This file is part of FusionForge. FusionForge is free software;
14 * you can redistribute it and/or modify it under the terms of the
15 * GNU General Public License as published by the Free Software
16 * Foundation; either version 2 of the Licence, or (at your option)
19 * FusionForge is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 require_once $gfcommon.'include/FFObject.class.php';
30 require_once $gfcommon.'docman/Parsedata.class.php';
31 require_once $gfcommon.'docman/DocumentManager.class.php';
32 require_once $gfcommon.'docman/DocumentGroup.class.php';
33 require_once $gfcommon.'docman/DocumentStorage.class.php';
34 require_once $gfcommon.'docman/DocumentVersion.class.php';
35 require_once $gfcommon.'include/MonitorElement.class.php';
36 require_once $gfcommon.'include/utils_crossref.php';
37 require_once $gfcommon.'docman/include/constants.php';
39 $DOCUMENT_OBJ = array();
42 * document_get_object() - Get document object by document ID.
43 * document_get_object is useful so you can pool document objects/save database queries
44 * You should always use this instead of instantiating the object directly
46 * @param int $doc_id The ID of the document - required
47 * @param int|bool $group_id Group ID of the project - required
48 * @param int|bool $res The result set handle ("SELECT * FROM docdata_vw WHERE docid=$1")
49 * @return Document a document object or false on failure
51 function &document_get_object($doc_id, $group_id = false, $res = false) {
53 if (!isset($DOCUMENT_OBJ["_".$doc_id."_"])) {
55 //the db result handle was passed in
56 } elseif ($group_id) {
57 $res = db_query_params('SELECT * FROM docdata_vw WHERE docid = $1 and group_id = $2',
58 array($doc_id, $group_id));
60 $res = db_query_params('SELECT * FROM docdata_vw WHERE docid = $1',
63 if (!$res || db_numrows($res) < 1) {
64 $DOCUMENT_OBJ["_".$doc_id."_"] = false;
66 $arr = db_fetch_array($res);
67 $DOCUMENT_OBJ["_".$doc_id."_"] = new Document(group_get_object($arr['group_id']), $doc_id, $arr);
70 return $DOCUMENT_OBJ["_".$doc_id."_"];
73 class Document extends FFObject {
76 * Associative array of data from db.
78 * @var array $data_array.
94 function __construct(&$Group, $docid = false, $arr = false) {
95 parent::__construct($docid, get_class());
96 if (!$Group || !is_object($Group)) {
97 $this->setError(_('Invalid Project'));
100 if ($Group->isError()) {
101 $this->setError(_('Document')._(': ').$Group->getErrorMessage());
104 $this->Group =& $Group;
107 if (!$arr || !is_array($arr)) {
108 if (!$this->fetchData($docid)) {
112 $this->data_array =& $arr;
113 if ($this->data_array['group_id'] != $this->Group->getID()) {
114 $this->setError(_('Document')._(': ')._('group_id in db result does not match Group Object'));
115 $this->data_array = null;
119 if (!$this->isPublic()) {
120 $perm =& $this->Group->getPermission();
122 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
123 $this->setPermissionDeniedError();
124 $this->data_array = null;
131 * create - use this function to create a new entry in the database.
133 * @param string $filename The filename of this document. Can be a URL.
134 * @param string $filetype The filetype of this document. If filename is URL, this should be 'URL';
135 * @param string $data The absolute path file itself.
136 * @param int $doc_group The doc_group id of the doc_groups table.
137 * @param string $title The title of this document.
138 * @param string $description The description of this document.
139 * @param int $stateid The state id of the document. At creation, cannot be deleted status.
140 * @param string $vcomment The comment of the new created version
141 * @param array $importData Array of data to change creator, time of creation, bypass permission check and do not send notification like:
142 * array('user' => 127, 'time' => 1234556789, 'nopermcheck' => 1, 'nonotice' => 1)
143 * @return bool success.
145 function create($filename, $filetype, $data, $doc_group, $title, $description, $stateid = 0, $vcomment = '', $importData = array()) {
146 if (strlen($title) < DOCMAN_TITLE_MIN_SIZE) {
147 $this->setError(sprintf(_('Title Must Be At Least %d Characters'), DOCMAN_TITLE_MIN_SIZE));
150 if (strlen($description) < DOCMAN_DESCRIPTION_MIN_SIZE) {
151 $this->setError(sprintf(_('Document Description Must Be At Least %d Characters'), DOCMAN_DESCRIPTION_MIN_SIZE));
155 if (strlen($title) > DOCMAN_TITLE_MAX_SIZE) {
156 $this->setError(sprintf(_('Title Must Be Max %d Characters'), DOCMAN_TITLE_MAX_SIZE));
160 if (strlen($description) > DOCMAN_DESCRIPTION_MAX_SIZE) {
161 $this->setError(sprintf(_('Document Description Must Be Max %d Characters'), DOCMAN_DESCRIPTION_MAX_SIZE));
165 if (strlen($description) > DOCMAN_COMMENT_MAX_SIZE) {
166 $this->setError(sprintf(_('Document Comment Must Be Max %d Characters'), DOCMAN_COMMENT_MAX_SIZE));
170 if (isset($importData['user'])) {
171 $user_id = $importData['user'];
173 $user_id = ((session_loggedin()) ? user_getid() : DOCMAN_INFAMOUS_USER_ID);
176 $perm =& $this->Group->getPermission();
177 if (isset($importData['nopermcheck']) && $importData['nopermcheck']) {
178 $doc_initstatus = $stateid;
180 $doc_initstatus = '3';
181 if ($perm && is_object($perm) && $perm->isDocEditor()) {
182 if ($stateid && $stateid != 2) {
183 $doc_initstatus = $stateid;
185 $doc_initstatus = '1';
190 $dg = documentgroup_get_object($doc_group, $this->Group->getID());
191 if ($dg->hasDocument($filename)) {
192 $this->setError(_('Document already published in this folder').' '.$dg->getPath());
196 $result = db_query_params('SELECT title FROM docdata_vw where title = $1 AND doc_group = $2',
197 array($title, $doc_group));
198 if (!$result || db_numrows($result) > 0) {
199 $this->setError(_('Document already published in this folder').' '.$dg->getPath());
203 // If $filetype is "text/plain", $body convert UTF-8 encoding.
204 if (strcasecmp($filetype, "text/plain") === 0 &&
205 function_exists('mb_convert_encoding') &&
206 function_exists('mb_detect_encoding')) {
207 $data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
210 $filesize = filesize($data);
211 if (!$filesize) { $filesize = 0; }
213 // key words for in-document search
214 if ($this->Group->useDocmanSearch() && $filesize) {
215 $kw = new Parsedata();
216 $kwords = $kw->get_parse_data($data, $filetype);
222 $createtimestamp = (isset($importData['time']))? $importData['time'] : time();
223 $result = db_query_params('INSERT INTO doc_data (group_id, createdate, doc_group, stateid)
224 VALUES ($1, $2, $3, $4)',
225 array($this->Group->getID(), $createtimestamp, $doc_group, $doc_initstatus));
227 $docid = db_insertid($result, 'doc_data', 'docid');
228 if (!$result || !$docid) {
229 $this->setError(_('Error Adding Document')._(': ').db_error().$result);
234 $dv = new DocumentVersion($this);
235 $idversion = $dv->create($docid, $title, $description, $user_id, $filetype, $filename, $filesize, $kwords, $createtimestamp, 1, 1, $vcomment);
237 $this->setError($dv->getErrorMessage());
243 if (is_file($data)) {
244 if (!DocumentStorage::instance()->store($idversion, $data)) {
245 DocumentStorage::instance()->rollback();
247 $this->setError(DocumentStorage::instance()->getErrorMessage());
251 $this->setError(_('Error Adding Document')._(': ')._('Not a file').' '.$filename);
257 if (!$this->fetchData($docid)) {
259 DocumentStorage::instance()->rollback();
265 if ($perm->isDocEditor() || (isset($importData['nopermcheck']) && $importData['nopermcheck'])) {
266 $localDg = documentgroup_get_object($doc_group, $this->Group->getID());
267 if (!$localDg->update($localDg->getName(), $localDg->getParentID(), 1, $localDg->getState(), $createtimestamp)) {
268 $this->setError(_('Error updating document group')._(': ').$localDg->getErrorMessage());
270 DocumentStorage::instance()->rollback();
276 if (!isset($importData['nonotice'])) {
277 $this->sendNotice(true);
278 $this->sendApprovalNotice();
282 DocumentStorage::instance()->commit();
288 * fetchData() - re-fetch the data for this document from the database.
290 * @param int $docid The document id.
291 * @return bool success
293 function fetchData($docid) {
294 $res = db_query_params('SELECT * FROM docdata_vw WHERE docid=$1 AND group_id=$2',
295 array($docid, $this->Group->getID()));
296 if (!$res || db_numrows($res) < 1) {
297 $this->setError(_('Document: Invalid docid'));
300 $this->data_array = db_fetch_array($res);
301 db_free_result($res);
306 * getGroup - get the Group object this Document is associated with.
308 * @return Object The Group object.
310 function &getGroup() {
315 * getID - get this docid.
317 * @return int The docid.
320 return $this->data_array['docid'];
324 * getName - get the name of this document.
326 * @return string The name of this document.
329 return $this->data_array['title'];
333 * getDescription - the description of this document.
335 * @return string The description.
337 function getDescription() {
339 $result = util_gen_cross_ref($this->data_array['description'], $this->Group->getID());
340 if (forge_get_config('docman_parser_type') == 'markdown') {
341 require_once $gfcommon.'include/Markdown.include.php';
342 $result = FF_Markdown($result);
344 $result = nl2br($result);
350 * isURL - whether this document is a URL and not a local file.
352 * @return bool is_url.
355 return ($this->data_array['filetype'] == 'URL');
359 * isText - whether this document is a text document and not a binary one.
361 * @return bool is_text.
364 $doctype = $this->data_array['filetype'];
365 if (preg_match('|^text/|i', $doctype)) { // text plain, text html, text x-patch, etc
372 * isHtml - whether this document is a html document.
374 * @return bool is_html.
377 $doctype = $this->data_array['filetype'];
378 if (preg_match('/html/i',$doctype)) {
385 * isPublic - whether this document is available to the general public.
387 * @return bool is_public.
389 function isPublic() {
390 return (($this->data_array['stateid'] == 1) ? true : false);
394 * getStateID - get this stateid.
396 * @return int The stateid.
398 function getStateID() {
399 return $this->data_array['stateid'];
404 if ($this->getStateID() == 2) {
405 $view = 'listtrashfile';
411 * getStateName - the statename of this document.
413 * @return string The statename.
415 function getStateName() {
416 return $this->data_array['state_name'];
420 * getDocGroupID - get this doc_group_id.
422 * @return int The doc_group_id.
424 function getDocGroupID() {
425 return $this->data_array['doc_group'];
429 * getDocGroupName - the doc_group_name of this document.
431 * @return string The docgroupname.
433 function getDocGroupName() {
434 return $this->data_array['group_name'];
438 * getCreatorID - get this creator's user_id.
440 * @return int The user_id.
442 function getCreatorID() {
443 return $this->data_array['created_by'];
447 * getCreatorUserName - the unix name of the person who created this document.
449 * @return string The unix name of the creator.
451 function getCreatorUserName() {
452 return $this->data_array['user_name'];
456 * getCreatorRealName - the real name of the person who created this document.
458 * @return string The real name of the creator.
460 function getCreatorRealName() {
461 return $this->data_array['realname'];
465 * getCreatorEmail - the email of the person who created this document.
467 * @return string The email of the creator.
469 function getCreatorEmail() {
470 return $this->data_array['email'];
474 * getFileName - the filename of this document.
476 * @return string The filename.
478 function getFileName() {
479 return $this->data_array['filename'];
483 * getFileType - the filetype of this document.
485 * @return string The filetype.
487 function getFileType() {
488 return $this->data_array['filetype'];
492 * getFileData - the filedata of this document.
494 * @param bool $download update the download flag or not. default is true
495 * @return string The filedata.
497 function getFileData($download = true) {
501 return file_get_contents($this->getFilePath());
505 * getFilePath - the filepath of this document.
507 * @return string The file where the file is stored.
509 function getFilePath() {
510 return DocumentStorage::instance()->get($this->getSerialIDVersion());
513 function getSerialIDVersion() {
514 return $this->data_array['serial_id'];
517 function getVersion() {
518 return $this->data_array['version'];
522 * getFileSize - Return the size of the document
524 * @return int The file size
526 function getFileSize() {
527 return $this->data_array['filesize'];
531 * getUpdated - get the time this document was updated.
533 * @return int The epoch date this document was updated.
535 function getUpdated() {
536 return $this->data_array['updatedate'];
540 * getDownload - get the number of views of this document.
542 * @return int the number of views
544 function getDownload() {
545 return $this->data_array['download'];
549 * getCreated - get the time this document was created.
551 * @return int The epoch date this document was created.
553 function getCreated() {
554 return $this->data_array['createdate'];
558 * getLocked - get the lock status of this document.
560 * @return int The lock status of this document.
562 function getLocked() {
563 return $this->data_array['locked'];
567 * getLockdate - get the lock time of this document.
569 * @return int The lock time of this document.
571 function getLockdate() {
572 return $this->data_array['lockdate'];
576 * getLockedBy - get the user id who set lock on this document.
578 * @return int The user id who set lock on this document.
580 function getLockedBy() {
581 return $this->data_array['locked_by'];
585 * getReservedBy - get the owner of the reserved status of this document.
587 * @return int The owner of the reserved status of this document.
589 function getReservedBy() {
590 return $this->data_array['reserved_by'];
594 * getReserved - get the reserved status of this document.
596 * @return int The reserved status of this document.
598 function getReserved() {
599 return $this->data_array['reserved'];
603 * getMonitoredUserEmailAddress - get the email addresses of users who monitor this file
605 * @return string The list of emails comma separated
607 function getMonitoredUserEmailAddress() {
608 $MonitorElementObject = new MonitorElement('docdata');
609 return $MonitorElementObject->getAllEmailsInCommatSeparated($this->getID());
613 * getMonitorIds - get user ids monitoring this Document.
615 * @return array of user ids monitoring this Document.
617 function getMonitorIds() {
618 $MonitorElementObject = new MonitorElement('docdata');
619 return $MonitorElementObject->getMonitorUsersIdsInArray($this->getID());
623 * isMonitoredBy - get the monitored status of this document for a specific user id.
625 * @param string $userid
626 * @return bool true if monitored by this user
628 function isMonitoredBy($userid = 'ALL') {
629 $MonitorElementObject = new MonitorElement('docdata');
630 if ( $userid == 'ALL' ) {
631 return $MonitorElementObject->isMonitoredByAny($this->getID());
633 return $MonitorElementObject->isMonitoredByUserId($this->getID(), $userid);
638 * removeMonitoredBy - remove this document for a specific user id for monitoring.
640 * @param int $userid User ID
641 * @return bool true if success
643 function removeMonitoredBy($userid) {
644 $MonitorElementObject = new MonitorElement('docdata');
645 if (!$MonitorElementObject->disableMonitoringByUserId($this->getID(), $userid)) {
646 $this->setError($MonitorElementObject->getErrorMessage());
653 * addMonitoredBy - add this document for a specific user id for monitoring.
655 * @param int $userid User ID
656 * @return bool true if success
658 function addMonitoredBy($userid) {
659 $MonitorElementObject = new MonitorElement('docdata');
660 if (!$MonitorElementObject->enableMonitoringByUserId($this->getID(), $userid)) {
661 $this->setError($MonitorElementObject->getErrorMessage());
668 * clearMonitor - remove all entries of monitoring for this document.
670 * @return bool true if success.
672 function clearMonitor() {
673 $MonitorElementObject = new MonitorElement('docdata');
674 if (!$MonitorElementObject->clearMonitor($this->getID())) {
675 $this->setError($MonitorElementObject->getErrorMessage());
682 * setState - set the stateid of the document.
684 * @param int $stateid The state id of the doc_states table.
685 * @return bool success or not.
687 function setState($stateid) {
688 return $this->setValueinDB(array('stateid'), array($stateid));
693 * setDocGroupID - set the doc_group of the document.
695 * @param int $newdocgroupid The group_id of this document.
696 * @return bool success or not.
698 function setDocGroupID($newdocgroupid) {
699 return $this->setValueinDB(array('doc_group'), array($newdocgroupid));
703 * setLock - set the locking status of the document.
705 * @param int $stateLock the status to be set
706 * @param string $userid the lock owner
707 * @param int $thistime the epoch time
708 * @return bool success or not.
710 function setLock($stateLock, $userid = NULL, $thistime = 0) {
711 $colArr = array('locked', 'locked_by', 'lockdate');
712 $valArr = array($stateLock, $userid, $thistime);
713 if (!$this->setValueinDB($colArr, $valArr)) {
714 $this->setOnUpdateError(_('Document lock failed').' '.db_error());
717 $this->data_array['locked'] = $stateLock;
718 $this->data_array['locked_by'] = $userid;
719 $this->data_array['lockdate'] = $thistime;
724 * setReservedBy - set the reserved status of the document and the owner
726 * @param int $statusReserved The status of the reserved
727 * @param int $idReserver The ID of the owner : by default : noone
728 * @return bool success
730 function setReservedBy($statusReserved, $idReserver = NULL) {
731 $colArr = array('reserved', 'reserved_by');
732 $valArr = array($statusReserved, $idReserver);
733 if (!$this->setValueinDB($colArr, $valArr)) {
734 $this->setOnUpdateError(_('Document reservation failed').' '.db_error());
737 $this->sendNotice(false);
742 * getFileTypeImage - return the file image for icon
744 * @return string the file image name
747 function getFileTypeImage() {
748 switch ($this->getFileType()) {
753 case "image/vnd.microsoft.icon":
754 case "image/svg+xml": {
755 $image = 'docman/file_type_image.png';
759 case "audio/x-vorbis+ogg":
761 case "audio/x-ms-wma":
762 case "audio/vnd.rn-realaudio": {
763 $image = "docman/file_type_sound.png";
766 case "application/pdf": {
767 $image = 'docman/file_type_pdf.png';
772 $image = 'docman/file_type_html.png';
777 case "application/xml":
780 case "text/x-shellscript": {
781 $image = 'ic/file-txt.png';
784 case "application/msword":
785 case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
786 case "application/vnd.oasis.opendocument.text": {
787 $image = 'docman/file_type_writer.png';
790 case "application/vnd.ms-excel":
791 case "application/vnd.oasis.opendocument.spreadsheet":
792 case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
793 $image = 'docman/file_type_spreadsheet.png';
796 case "application/vnd.oasis.opendocument.presentation":
797 case "application/vnd.ms-powerpoint":
798 case "application/vnd.ms-office":
799 case "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
800 $image = 'docman/file_type_presentation.png';
803 case "application/zip":
804 case "application/x-tar":
805 case "application/x-rpm":
806 case "application/x-rar-compressed":
807 case "application/x-bzip2":
808 case "application/x-gzip":
809 case "application/x-lzip":
810 case "application/x-compress":
811 case "application/x-7z-compressed":
812 case "application/x-gtar":
813 case "application/x-stuffitx":
814 case "application/x-lzx":
815 case "application/x-lzh":
816 case "application/x-gca-compressed":
817 case "application/x-apple-diskimage":
818 case "application/x-dgc-compressed":
819 case "application/x-dar":
820 case "application/x-cfs-compressed":
821 case "application/vnd.ms-cab-compressed":
822 case "application/x-alz-compressed":
823 case "application/x-astrotite-afa":
824 case "application/x-ace-compressed":
825 case "application/x-cpio":
826 case "application/x-shar":
827 case "application/x-xz": {
828 $image = 'ic/file_type_archive.png';
832 $image = 'docman/file_type_unknown.png';
839 * update - use this function to update an existing entry in the database.
841 * @param string $filename The filename of this document. Can be a URL.
842 * @param string $filetype The filetype of this document. If filename is URL, this should be 'URL';
843 * @param string $data The contents of this document.
844 * @param int $doc_group The doc_group id of the doc_groups table.
845 * @param string $title The title of this document.
846 * @param string $description The description of this document.
847 * @param int $stateid The state id of the doc_states table.
848 * @param int $version The version to update. Default is 1.
849 * @param int $current_version Is the current version? default is 1.
850 * @param int $new_version To create a new version? default is 0. == No.
851 * @param array $importData Array of data to change creator, time of creation, bypass permission check and do not send notification like:
852 * array('user' => 127, 'time' => 1234556789, 'nopermcheck' => 1, 'nonotice' => 1)
853 * @param string $vcomment The comment of this version
854 * @return bool success.
856 function update($filename, $filetype, $data, $doc_group, $title, $description, $stateid, $version = 1, $current_version = 1, $new_version = 0, $importData = array(), $vcomment = '') {
858 $perm =& $this->Group->getPermission();
859 if (!isset($importData['nopermcheck'])) {
860 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
861 $this->setPermissionDeniedError();
866 if (isset($importData['user'])) {
867 $user = user_get_object($importData['user']);
869 $user = session_get_user();
871 if (!isset($importData['nopermcheck'])) {
872 if ($this->getLocked() && ($this->getLockedBy() != $user->getID())) {
873 $this->setPermissionDeniedError();
878 if (strlen($title) < DOCMAN_TITLE_MIN_SIZE) {
879 $this->setError(sprintf(_('Title Must Be At Least %d Characters'), DOCMAN_TITLE_MIN_SIZE));
883 if (strlen($description) < DOCMAN_DESCRIPTION_MIN_SIZE) {
884 $this->setError(sprintf(_('Document Description Must Be At Least %d Characters'), DOCMAN_DESCRIPTION_MIN_SIZE));
888 if (strlen($title) > DOCMAN_TITLE_MAX_SIZE) {
889 $this->setError(sprintf(_('Title Must Be Max %d Characters'), DOCMAN_TITLE_MAX_SIZE));
893 if (strlen($description) > DOCMAN_DESCRIPTION_MAX_SIZE) {
894 $this->setError(sprintf(_('Document Description Must Be Max %d Characters'), DOCMAN_DESCRIPTION_MAX_SIZE));
898 if (strlen($description) > DOCMAN_COMMENT_MAX_SIZE) {
899 $this->setError(sprintf(_('Document Comment Must Be Max %d Characters'), DOCMAN_COMMENT_MAX_SIZE));
904 $updatetimestamp = ((isset($importData['time'])) ? $importData['time'] : time());
905 $colArr = array('stateid', 'doc_group', 'updatedate', 'locked', 'locked_by');
906 $valArr = array($stateid, $doc_group, $updatetimestamp, 0, NULL);
907 if (!$this->setValueinDB($colArr, $valArr)) {
912 $localDg = new DocumentGroup($this->Group, $doc_group);
913 if (!$localDg->update($localDg->getName(), $localDg->getParentID(), 1, $localDg->getState(), $updatetimestamp)) {
914 $this->setOnUpdateError(_('Error updating document group')._(': ').$localDg->getErrorMessage());
919 $dv = new DocumentVersion($this);
921 $dv = documentversion_get_object($version, $this->getID(), $this->Group->getID());
924 $this->setOnUpdateError(_('Error getting document version'));
929 if (filesize($data)) {
930 $filesize = filesize($data);
931 // key words for in-document search
932 if ($this->Group->useDocmanSearch()) {
933 $kw = new Parsedata();
934 $kwords = $kw->get_parse_data($data, $filetype);
937 $filesize = $dv->getFileSize();
938 if ($filesize == null) {
944 if ($dv->isError()) {
945 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
949 //new version to create. We overwrite the param.
950 $version = $dv->getMaxVersionID();
952 $version_kwords = '';
953 if (isset($kwords)) {
954 $version_kwords = $kwords;
956 $serial_id = $dv->create($this->getID(), $title, $description, $user->getID(), $filetype, $filename, $filesize, $version_kwords, $updatetimestamp, $version, $current_version, $vcomment);
958 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
963 if ($dv->isError() || !$dv->update($version, $title, $description, $filetype, $filename, $filesize, $updatetimestamp, $current_version, $vcomment)) {
964 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
969 if (isset($kwords) && !$dv->updateDataWords($version, $kwords)) {
970 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
975 if (filesize($data)) {
977 if (!DocumentStorage::instance()->store($serial_id, $data)) {
978 DocumentStorage::instance()->rollback();
980 $this->setError(DocumentStorage::instance()->getErrorMessage());
983 DocumentStorage::instance()->commit();
985 DocumentStorage::instance()->delete($dv->getID())->commit();
986 DocumentStorage::instance()->store($dv->getID(), $data);
991 $this->fetchData($this->getID());
992 $this->sendNotice(false);
997 * sendNotice - Notifies of document submissions
999 * @param bool true = new document (default value)
1002 function sendNotice($new = true) {
1003 $BCC = $this->Group->getDocEmailAddress();
1004 if ($this->isMonitoredBy('ALL')) {
1005 $BCC .= $this->getMonitoredUserEmailAddress();
1007 $dg = documentgroup_get_object($this->getDocGroupID(), $this->Group->getID());
1008 if ($dg->isMonitoredBy('ALL')) {
1009 $BCC .= $dg->getMonitoredUserEmailAddress();
1011 if (strlen($BCC) > 0) {
1012 $session = session_get_user();
1014 $status = _('New Document');
1016 $status = _('Updated document').' '._('by').' ' . $session->getRealName();
1018 $subject = '['.$this->Group->getPublicName().'] '.$status.' - '.$this->getName();
1019 $body = _('Project')._(': ').$this->Group->getPublicName()."\n";
1020 $body .= _('Folder')._(': ').$this->getDocGroupName()."\n";
1021 $body .= _('Document Title')._(': ').$this->getName()."\n";
1022 $body .= _('Document description')._(': ').util_unconvert_htmlspecialchars($this->getDescription())."\n";
1023 $body .= _('Submitter')._(': ').$this->getCreatorRealName()." (".$this->getCreatorUserName().") \n";
1024 $body .= "\n\n-------------------------------------------------------\n".
1025 _('For more info, visit:').
1026 "\n\n" . util_make_url($this->getPermalink());
1028 $BCCarray = explode(',',$BCC);
1029 foreach ($BCCarray as $dest_email) {
1030 util_send_message($dest_email, $subject, $body, 'noreply@'.forge_get_config('web_host'), '', _('Docman'));
1037 * sendApprovalNotice - send email to project admin for pending documents.
1039 * @return bool success.
1041 function sendApprovalNotice() {
1042 if ($this->getStateID() != 3) {
1045 $doc_name = $this->getName();
1046 $desc = util_unconvert_htmlspecialchars($this->getDescription());
1047 $group_id = $this->Group->getID();
1048 $name = $this->getCreatorRealName()." (".$this->getCreatorUserName().")";
1051 $subject="[" . forge_get_config('forge_name') ."] ".util_unconvert_htmlspecialchars($doc_name);
1052 $body = "\n"._('A new document has been uploaded and waiting to be approved by you')._(': ').
1053 "\n".util_make_url($this->getPermalink()).
1054 "\n"._('by').(': ').$name."\n";
1056 $sanitizer = new TextSanitizer();
1058 if (strstr($text,'<br/>') || strstr($text,'<br />')) {
1059 $text = preg_replace('/[\n\r]/', '', $text);
1061 $text = $sanitizer->convertNeededTagsForEmail($text);
1062 $text = preg_replace('/\[.+\](.+)\[\/.+\]/','$1',$text);
1063 $text = $sanitizer->convertExtendedCharsForEmail($text);
1066 $extra_headers = "Return-Path: <noreply@".forge_get_config('web_host').">\n";
1067 $extra_headers .= "Errors-To: <noreply@".forge_get_config('web_host').">\n";
1068 $extra_headers .= "Sender: <noreply@".forge_get_config('web_host').">";
1070 $groupUsers = $this->Group->getUsers();
1071 $rbacEngine = RBACEngine::getInstance();
1072 foreach ($groupUsers as $groupUser) {
1073 if ($rbacEngine->isActionAllowedForUser($groupUser, 'docman', $group_id, 'approve')) {
1074 $bcc .= $groupUser->getEmail().',';
1077 if (strlen($bcc) > 0) {
1078 util_send_message('', $subject, $body, "noreply@".forge_get_config('web_host'),
1079 $bcc, 'Docman', $extra_headers);
1085 * delete - Delete this file
1087 * @return bool success
1090 $perm =& $this->Group->getPermission();
1091 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
1092 $this->setPermissionDeniedError();
1097 $dvf = new DocumentVersionFactory($this);
1098 $serialids = $dvf->getSerialIDs();
1099 $result = db_query_params('DELETE FROM doc_data WHERE docid=$1',
1100 array($this->getID()));
1102 $this->setError(_('Error Deleting Document')._(': ').db_error());
1107 if (!$this->removeAllAssociations()) {
1108 // error message already set by FFObject class.
1114 foreach ($serialids as $serialid) {
1115 DocumentStorage::instance()->delete($serialid)->commit();
1118 /** we should be able to send a notice that this doc has been deleted .... but we need to rewrite sendNotice
1119 * $this->sendNotice(false);
1120 * @TODO delete monitoring this file */
1125 * trash - move this file to trash
1127 * @return bool success or not.
1130 if (!$this->getLocked() || ((time() - $this->getLockdate()) > 600)) {
1131 $this->setState('2');
1132 $dm = new DocumentManager($this->Group);
1133 $this->setDocGroupID($dm->getTrashID());
1135 $this->setReservedBy(0);
1136 $this->sendNotice(false);
1137 $this->clearMonitor();
1145 * downloadUp - insert download stats
1148 function downloadUp() {
1149 if (session_loggedin()) {
1151 $us = $LUSER->getID();
1156 $ip = getStringFromServer('REMOTE_ADDR');
1157 db_query_params("INSERT INTO docman_dlstats_doc (ip_address, docid, month, day, user_id) VALUES ($1, $2, $3, $4, $5)", array($ip, $this->getID(), date('Ym'), date('d'), $us));
1161 * setValueinDB - private function to update columns in db
1163 * @param array $colArr the columns to update in array form array('col1', col2')
1164 * @param array $valArr the values to store in array form array('val1', 'val2')
1165 * @return bool success or not
1167 private function setValueinDB($colArr, $valArr) {
1168 if ((count($colArr) != count($valArr)) || !count($colArr) || !count($valArr)) {
1169 $this->setOnUpdateError(_('wrong parameters'));
1173 $qpa = db_construct_qpa(false, 'UPDATE doc_data SET ');
1174 for ($i = 0; $i < count($colArr); $i++) {
1175 switch ($colArr[$i]) {
1185 $qpa = db_construct_qpa($qpa, ',');
1187 $qpa = db_construct_qpa($qpa, $colArr[$i]);
1188 $qpa = db_construct_qpa($qpa, '=$1 ', array($valArr[$i]));
1192 $this->setOnUpdateError(_('wrong column name'));
1197 $qpa = db_construct_qpa($qpa, ' WHERE group_id=$1
1199 array($this->Group->getID(),
1201 $res = db_query_qpa($qpa);
1202 if (!$res || db_affected_rows($res) < 1) {
1203 $this->setOnUpdateError(db_error());
1206 $localDg = documentgroup_get_object($this->getDocGroupID(), $this->Group->getID());
1207 if (!$localDg->update($localDg->getName(), $localDg->getParentID(), 1, $localDg->getState())) {
1208 $this->setError(_('Error updating document group')._(': ').$localDg->getErrorMessage());
1211 for ($i = 0; $i < count($colArr); $i++) {
1212 switch ($colArr[$i]) {
1221 $this->data_array[$colArr[$i]] = $valArr[$i];
1225 $this->sendNotice(false);
1229 function getPermalink() {
1230 return '/docman/d_follow.php/'.$this->getID();
1233 function hasValidatedReview() {
1234 $dv = documentversion_get_object($this->getVersion(), $this->getID(), $this->Group->getID());
1235 return $dv->hasValidatedReview();
1241 // c-file-style: "bsd"