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, 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;
132 * create - use this function to create a new entry in the database.
134 * @param string $filename The filename of this document. Can be a URL.
135 * @param string $filetype The filetype of this document. If filename is URL, this should be 'URL';
136 * @param string $data The absolute path file itself.
137 * @param int $doc_group The doc_group id of the doc_groups table.
138 * @param string $title The title of this document.
139 * @param string $description The description of this document.
140 * @param int $stateid The state id of the document. At creation, cannot be deleted status.
141 * @param string $vcomment The comment of the new created version
142 * @param array $importData Array of data to change creator, time of creation, bypass permission check and do not send notification like:
143 * array('user' => 127, 'time' => 1234556789, 'nopermcheck' => 1, 'nonotice' => 1)
144 * @return bool success.
146 function create($filename, $filetype, $data, $doc_group, $title, $description, $stateid = 0, $vcomment = '', $importData = array()) {
147 if (strlen($title) < DOCMAN__TITLE_MIN_SIZE) {
148 $this->setError(sprintf(_('Title Must Be At Least %d Characters'), DOCMAN__TITLE_MIN_SIZE));
151 if (strlen($description) < DOCMAN__DESCRIPTION_MIN_SIZE) {
152 $this->setError(sprintf(_('Document Description Must Be At Least %d Characters'), DOCMAN__DESCRIPTION_MIN_SIZE));
156 if (strlen($title) > DOCMAN__TITLE_MAX_SIZE) {
157 $this->setError(sprintf(_('Title Must Be Max %d Characters'), DOCMAN__TITLE_MAX_SIZE));
161 if (strlen($description) > DOCMAN__DESCRIPTION_MAX_SIZE) {
162 $this->setError(sprintf(_('Document Description Must Be Max %d Characters'), DOCMAN__DESCRIPTION_MAX_SIZE));
166 if (strlen($description) > DOCMAN__COMMENT_MAX_SIZE) {
167 $this->setError(sprintf(_('Document Comment Must Be Max %d Characters'), DOCMAN__COMMENT_MAX_SIZE));
171 if (isset($importData['user'])) {
172 $user_id = $importData['user'];
174 $user_id = ((session_loggedin()) ? user_getid() : DOCMAN__INFAMOUS_USER_ID);
177 $perm =& $this->Group->getPermission();
178 if (isset($importData['nopermcheck']) && $importData['nopermcheck']) {
179 $doc_initstatus = $stateid;
181 $doc_initstatus = '3';
182 if ($perm && is_object($perm) && $perm->isDocEditor()) {
183 if ($stateid && $stateid != 2) {
184 $doc_initstatus = $stateid;
186 $doc_initstatus = '1';
191 $dg = documentgroup_get_object($doc_group, $this->Group->getID());
192 if ($dg->hasDocument($filename)) {
193 $this->setError(_('Document already published in this folder').' '.$dg->getPath());
197 $result = db_query_params('SELECT title FROM docdata_vw where title = $1 AND doc_group = $2',
198 array($title, $doc_group));
199 if (!$result || db_numrows($result) > 0) {
200 $this->setError(_('Document already published in this folder').' '.$dg->getPath());
204 // If $filetype is "text/plain", $body convert UTF-8 encoding.
205 if (strcasecmp($filetype, "text/plain") === 0 &&
206 function_exists('mb_convert_encoding') &&
207 function_exists('mb_detect_encoding')) {
208 $data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
211 $filesize = filesize($data);
212 if (!$filesize) { $filesize = 0; }
214 // key words for in-document search
215 if ($this->Group->useDocmanSearch() && $filesize) {
216 $kw = new Parsedata();
217 $kwords = $kw->get_parse_data($data, $filetype);
223 $createtimestamp = (isset($importData['time']))? $importData['time'] : time();
224 $result = db_query_params('INSERT INTO doc_data (group_id, createdate, doc_group, stateid)
225 VALUES ($1, $2, $3, $4)',
226 array($this->Group->getID(), $createtimestamp, $doc_group, $doc_initstatus));
228 $docid = db_insertid($result, 'doc_data', 'docid');
229 if (!$result || !$docid) {
230 $this->setError(_('Error Adding Document')._(': ').db_error().$result);
235 $dv = new DocumentVersion($this);
236 $idversion = $dv->create($docid, $title, $description, $user_id, $filetype, $filename, $filesize, $kwords, $createtimestamp, 1, 1, $vcomment);
238 $this->setError($dv->getErrorMessage());
244 if (is_file($data)) {
245 if (!DocumentStorage::instance()->store($idversion, $data)) {
246 DocumentStorage::instance()->rollback();
248 $this->setError(DocumentStorage::instance()->getErrorMessage());
252 $this->setError(_('Error Adding Document')._(': ')._('Not a file').' '.$filename);
258 if (!$this->fetchData($docid)) {
260 DocumentStorage::instance()->rollback();
266 if ($perm->isDocEditor() || (isset($importData['nopermcheck']) && $importData['nopermcheck'])) {
267 $localDg = documentgroup_get_object($doc_group, $this->Group->getID());
268 if (!$localDg->update($localDg->getName(), $localDg->getParentID(), 1, $localDg->getState(), $createtimestamp)) {
269 $this->setError(_('Error updating document group')._(': ').$localDg->getErrorMessage());
271 DocumentStorage::instance()->rollback();
277 if (!isset($importData['nonotice'])) {
278 $this->sendNotice(true);
279 $this->sendApprovalNotice();
283 DocumentStorage::instance()->commit();
289 * fetchData() - re-fetch the data for this document from the database.
291 * @param int $docid The document id.
292 * @return bool success
294 function fetchData($docid) {
295 $res = db_query_params('SELECT * FROM docdata_vw WHERE docid=$1 AND group_id=$2',
296 array($docid, $this->Group->getID()));
297 if (!$res || db_numrows($res) < 1) {
298 $this->setError(_('Document: Invalid docid'));
301 $this->data_array = db_fetch_array($res);
302 db_free_result($res);
307 * getGroup - get the Group object this Document is associated with.
309 * @return Object The Group object.
311 function &getGroup() {
316 * getID - get this docid.
318 * @return int The docid.
321 return $this->data_array['docid'];
325 * getName - get the name of this document.
327 * @return string The name of this document.
330 return $this->data_array['title'];
334 * getDescription - the description of this document.
336 * @return string The description.
338 function getDescription() {
339 $result = util_gen_cross_ref($this->data_array['description'], $this->Group->getID());
340 $result = nl2br($result);
345 * isURL - whether this document is a URL and not a local file.
347 * @return bool is_url.
350 return ($this->data_array['filetype'] == 'URL');
354 * isText - whether this document is a text document and not a binary one.
356 * @return bool is_text.
359 $doctype = $this->data_array['filetype'];
360 if (preg_match('|^text/|i', $doctype)) { // text plain, text html, text x-patch, etc
367 * isHtml - whether this document is a html document.
369 * @return bool is_html.
372 $doctype = $this->data_array['filetype'];
373 if (preg_match('/html/i',$doctype)) {
380 * isPublic - whether this document is available to the general public.
382 * @return bool is_public.
384 function isPublic() {
385 return (($this->data_array['stateid'] == 1) ? true : false);
389 * getStateID - get this stateid.
391 * @return int The stateid.
393 function getStateID() {
394 return $this->data_array['stateid'];
399 if ($this->getStateID() == 2) {
400 $view = 'listtrashfile';
406 * getStateName - the statename of this document.
408 * @return string The statename.
410 function getStateName() {
411 return $this->data_array['state_name'];
415 * getDocGroupID - get this doc_group_id.
417 * @return int The doc_group_id.
419 function getDocGroupID() {
420 return $this->data_array['doc_group'];
424 * getDocGroupName - the doc_group_name of this document.
426 * @return string The docgroupname.
428 function getDocGroupName() {
429 return $this->data_array['group_name'];
433 * getCreatorID - get this creator's user_id.
435 * @return int The user_id.
437 function getCreatorID() {
438 return $this->data_array['created_by'];
442 * getCreatorUserName - the unix name of the person who created this document.
444 * @return string The unix name of the creator.
446 function getCreatorUserName() {
447 return $this->data_array['user_name'];
451 * getCreatorRealName - the real name of the person who created this document.
453 * @return string The real name of the creator.
455 function getCreatorRealName() {
456 return $this->data_array['realname'];
460 * getCreatorEmail - the email of the person who created this document.
462 * @return string The email of the creator.
464 function getCreatorEmail() {
465 return $this->data_array['email'];
469 * getFileName - the filename of this document.
471 * @return string The filename.
473 function getFileName() {
474 return $this->data_array['filename'];
478 * getFileType - the filetype of this document.
480 * @return string The filetype.
482 function getFileType() {
483 return $this->data_array['filetype'];
487 * getFileData - the filedata of this document.
489 * @param bool $download update the download flag or not. default is true
490 * @return string The filedata.
492 function getFileData($download = true) {
496 return file_get_contents($this->getFilePath());
500 * getFilePath - the filepath of this document.
502 * @return string The file where the file is stored.
504 function getFilePath() {
505 return DocumentStorage::instance()->get($this->getSerialIDVersion());
508 function getSerialIDVersion() {
509 return $this->data_array['serial_id'];
512 function getVersion() {
513 return $this->data_array['version'];
517 * getFileSize - Return the size of the document
519 * @return int The file size
521 function getFileSize() {
522 return $this->data_array['filesize'];
526 * getUpdated - get the time this document was updated.
528 * @return int The epoch date this document was updated.
530 function getUpdated() {
531 return $this->data_array['updatedate'];
535 * getDownload - get the number of views of this document.
537 * @return int the number of views
539 function getDownload() {
540 return $this->data_array['download'];
544 * getCreated - get the time this document was created.
546 * @return int The epoch date this document was created.
548 function getCreated() {
549 return $this->data_array['createdate'];
553 * getLocked - get the lock status of this document.
555 * @return int The lock status of this document.
557 function getLocked() {
558 return $this->data_array['locked'];
562 * getLockdate - get the lock time of this document.
564 * @return int The lock time of this document.
566 function getLockdate() {
567 return $this->data_array['lockdate'];
571 * getLockedBy - get the user id who set lock on this document.
573 * @return int The user id who set lock on this document.
575 function getLockedBy() {
576 return $this->data_array['locked_by'];
580 * getReservedBy - get the owner of the reserved status of this document.
582 * @return int The owner of the reserved status of this document.
584 function getReservedBy() {
585 return $this->data_array['reserved_by'];
589 * getReserved - get the reserved status of this document.
591 * @return int The reserved status of this document.
593 function getReserved() {
594 return $this->data_array['reserved'];
598 * getMonitoredUserEmailAddress - get the email addresses of users who monitor this file
600 * @return string The list of emails comma separated
602 function getMonitoredUserEmailAddress() {
603 $MonitorElementObject = new MonitorElement('docdata');
604 return $MonitorElementObject->getAllEmailsInCommatSeparated($this->getID());
608 * getMonitorIds - get user ids monitoring this Document.
610 * @return array of user ids monitoring this Artifact.
612 function getMonitorIds() {
613 $MonitorElementObject = new MonitorElement('docdata');
614 return $MonitorElementObject->getMonitorUsersIdsInArray($this->getID());
618 * isMonitoredBy - get the monitored status of this document for a specific user id.
620 * @param string $userid
621 * @return bool true if monitored by this user
623 function isMonitoredBy($userid = 'ALL') {
624 $MonitorElementObject = new MonitorElement('docdata');
625 if ( $userid == 'ALL' ) {
626 return $MonitorElementObject->isMonitoredByAny($this->getID());
628 return $MonitorElementObject->isMonitoredByUserId($this->getID(), $userid);
633 * removeMonitoredBy - remove this document for a specific user id for monitoring.
635 * @param int $userid User ID
636 * @return bool true if success
638 function removeMonitoredBy($userid) {
639 $MonitorElementObject = new MonitorElement('docdata');
640 if (!$MonitorElementObject->disableMonitoringByUserId($this->getID(), $userid)) {
641 $this->setError($MonitorElementObject->getErrorMessage());
648 * addMonitoredBy - add this document for a specific user id for monitoring.
650 * @param int $userid User ID
651 * @return bool true if success
653 function addMonitoredBy($userid) {
654 $MonitorElementObject = new MonitorElement('docdata');
655 if (!$MonitorElementObject->enableMonitoringByUserId($this->getID(), $userid)) {
656 $this->setError($MonitorElementObject->getErrorMessage());
663 * clearMonitor - remove all entries of monitoring for this document.
665 * @return bool true if success.
667 function clearMonitor() {
668 $MonitorElementObject = new MonitorElement('docdata');
669 if (!$MonitorElementObject->clearMonitor($this->getID())) {
670 $this->setError($MonitorElementObject->getErrorMessage());
677 * setState - set the stateid of the document.
679 * @param int $stateid The state id of the doc_states table.
680 * @return bool success or not.
682 function setState($stateid) {
683 return $this->setValueinDB(array('stateid'), array($stateid));
688 * setDocGroupID - set the doc_group of the document.
690 * @param int $newdocgroupid The group_id of this document.
691 * @return bool success or not.
693 function setDocGroupID($newdocgroupid) {
694 return $this->setValueinDB(array('doc_group'), array($newdocgroupid));
698 * setLock - set the locking status of the document.
700 * @param int $stateLock the status to be set
701 * @param string $userid the lock owner
702 * @param int $thistime the epoch time
703 * @return bool success or not.
705 function setLock($stateLock, $userid = NULL, $thistime = 0) {
706 $colArr = array('locked', 'locked_by', 'lockdate');
707 $valArr = array($stateLock, $userid, $thistime);
708 if (!$this->setValueinDB($colArr, $valArr)) {
709 $this->setOnUpdateError(_('Document lock failed').' '.db_error());
712 $this->data_array['locked'] = $stateLock;
713 $this->data_array['locked_by'] = $userid;
714 $this->data_array['lockdate'] = $thistime;
719 * setReservedBy - set the reserved status of the document and the owner
721 * @param int $statusReserved The status of the reserved
722 * @param int $idReserver The ID of the owner : by default : noone
723 * @return bool success
725 function setReservedBy($statusReserved, $idReserver = NULL) {
726 $colArr = array('reserved', 'reserved_by');
727 $valArr = array($statusReserved, $idReserver);
728 if (!$this->setValueinDB($colArr, $valArr)) {
729 $this->setOnUpdateError(_('Document reservation failed').' '.db_error());
732 $this->sendNotice(false);
737 * getFileTypeImage - return the file image for icon
739 * @return string the file image name
742 function getFileTypeImage() {
743 switch ($this->getFileType()) {
748 case "image/vnd.microsoft.icon":
749 case "image/svg+xml": {
750 $image = 'docman/file_type_image.png';
754 case "audio/x-vorbis+ogg":
756 case "audio/x-ms-wma":
757 case "audio/vnd.rn-realaudio": {
758 $image = "docman/file_type_sound.png";
761 case "application/pdf": {
762 $image = 'docman/file_type_pdf.png';
767 $image = 'docman/file_type_html.png';
772 case "application/xml":
775 case "text/x-shellscript": {
776 $image = 'ic/file-txt.png';
779 case "application/msword":
780 case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
781 case "application/vnd.oasis.opendocument.text": {
782 $image = 'docman/file_type_writer.png';
785 case "application/vnd.ms-excel":
786 case "application/vnd.oasis.opendocument.spreadsheet":
787 case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
788 $image = 'docman/file_type_spreadsheet.png';
791 case "application/vnd.oasis.opendocument.presentation":
792 case "application/vnd.ms-powerpoint":
793 case "application/vnd.ms-office":
794 case "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
795 $image = 'docman/file_type_presentation.png';
798 case "application/zip":
799 case "application/x-tar":
800 case "application/x-rpm":
801 case "application/x-rar-compressed":
802 case "application/x-bzip2":
803 case "application/x-gzip":
804 case "application/x-lzip":
805 case "application/x-compress":
806 case "application/x-7z-compressed":
807 case "application/x-gtar":
808 case "application/x-stuffitx":
809 case "application/x-lzx":
810 case "application/x-lzh":
811 case "application/x-gca-compressed":
812 case "application/x-apple-diskimage":
813 case "application/x-dgc-compressed":
814 case "application/x-dar":
815 case "application/x-cfs-compressed":
816 case "application/vnd.ms-cab-compressed":
817 case "application/x-alz-compressed":
818 case "application/x-astrotite-afa":
819 case "application/x-ace-compressed":
820 case "application/x-cpio":
821 case "application/x-shar":
822 case "application/x-xz": {
823 $image = 'ic/file_type_archive.png';
827 $image = 'docman/file_type_unknown.png';
834 * update - use this function to update an existing entry in the database.
836 * @param string $filename The filename of this document. Can be a URL.
837 * @param string $filetype The filetype of this document. If filename is URL, this should be 'URL';
838 * @param string $data The contents of this document.
839 * @param int $doc_group The doc_group id of the doc_groups table.
840 * @param string $title The title of this document.
841 * @param string $description The description of this document.
842 * @param int $stateid The state id of the doc_states table.
843 * @param int $version The version to update. Default is 1.
844 * @param int $current_version Is the current version? default is 1.
845 * @param int $new_version To create a new version? default is 0. == No.
846 * @param array $importData Array of data to change creator, time of creation, bypass permission check and do not send notification like:
847 * array('user' => 127, 'time' => 1234556789, 'nopermcheck' => 1, 'nonotice' => 1)
848 * @param string $vcomment The comment of this version
849 * @return bool success.
851 function update($filename, $filetype, $data, $doc_group, $title, $description, $stateid, $version = 1, $current_version = 1, $new_version = 0, $importData = array(), $vcomment = '') {
853 $perm =& $this->Group->getPermission();
854 if (!isset($importData['nopermcheck'])) {
855 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
856 $this->setPermissionDeniedError();
861 if (isset($importData['user'])) {
862 $user = user_get_object($importData['user']);
864 $user = session_get_user();
866 if (!isset($importData['nopermcheck'])) {
867 if ($this->getLocked() && ($this->getLockedBy() != $user->getID())) {
868 $this->setPermissionDeniedError();
873 if (strlen($title) < DOCMAN__TITLE_MIN_SIZE) {
874 $this->setError(sprintf(_('Title Must Be At Least %d Characters'), DOCMAN__TITLE_MIN_SIZE));
878 if (strlen($description) < DOCMAN__DESCRIPTION_MIN_SIZE) {
879 $this->setError(sprintf(_('Document Description Must Be At Least %d Characters'), DOCMAN__DESCRIPTION_MIN_SIZE));
883 if (strlen($title) > DOCMAN__TITLE_MAX_SIZE) {
884 $this->setError(sprintf(_('Title Must Be Max %d Characters'), DOCMAN__TITLE_MAX_SIZE));
888 if (strlen($description) > DOCMAN__DESCRIPTION_MAX_SIZE) {
889 $this->setError(sprintf(_('Document Description Must Be Max %d Characters'), DOCMAN__DESCRIPTION_MAX_SIZE));
893 if (strlen($description) > DOCMAN__COMMENT_MAX_SIZE) {
894 $this->setError(sprintf(_('Document Comment Must Be Max %d Characters'), DOCMAN__COMMENT_MAX_SIZE));
899 $updatetimestamp = ((isset($importData['time'])) ? $importData['time'] : time());
900 $colArr = array('stateid', 'doc_group', 'updatedate', 'locked', 'locked_by');
901 $valArr = array($stateid, $doc_group, $updatetimestamp, 0, NULL);
902 if (!$this->setValueinDB($colArr, $valArr)) {
907 $localDg = new DocumentGroup($this->Group, $doc_group);
908 if (!$localDg->update($localDg->getName(), $localDg->getParentID(), 1, $localDg->getState(), $updatetimestamp)) {
909 $this->setOnUpdateError(_('Error updating document group')._(': ').$localDg->getErrorMessage());
914 $dv = new DocumentVersion($this);
916 $dv = documentversion_get_object($version, $this->getID(), $this->Group->getID());
919 $this->setOnUpdateError(_('Error getting document version'));
924 if (filesize($data)) {
925 $filesize = filesize($data);
926 // key words for in-document search
927 if ($this->Group->useDocmanSearch()) {
928 $kw = new Parsedata();
929 $kwords = $kw->get_parse_data($data, $filetype);
932 $filesize = $dv->getFileSize();
933 if ($filesize == null) {
939 if ($dv->isError()) {
940 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
944 //new version to create. We overwrite the param.
945 $version = $dv->getMaxVersionID();
947 $version_kwords = '';
948 if (isset($kwords)) {
949 $version_kwords = $kwords;
951 $serial_id = $dv->create($this->getID(), $title, $description, $user->getID(), $filetype, $filename, $filesize, $version_kwords, $updatetimestamp, $version, $current_version, $vcomment);
953 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
958 if ($dv->isError() || !$dv->update($version, $title, $description, $filetype, $filename, $filesize, $updatetimestamp, $current_version, $vcomment)) {
959 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
964 if (isset($kwords)) {
965 if(!$dv->updateDataWords($version, $kwords)) {
966 $this->setOnUpdateError(_('Error updating document version')._(': ').$dv->getErrorMessage());
972 if (filesize($data)) {
974 if (!DocumentStorage::instance()->store($serial_id, $data)) {
975 DocumentStorage::instance()->rollback();
977 $this->setError(DocumentStorage::instance()->getErrorMessage());
980 DocumentStorage::instance()->commit();
982 DocumentStorage::instance()->delete($dv->getID())->commit();
983 DocumentStorage::instance()->store($dv->getID(), $data);
988 $this->fetchData($this->getID());
989 $this->sendNotice(false);
994 * sendNotice - Notifies of document submissions
996 * @param bool true = new document (default value)
999 function sendNotice($new = true) {
1000 $BCC = $this->Group->getDocEmailAddress();
1001 if ($this->isMonitoredBy('ALL')) {
1002 $BCC .= $this->getMonitoredUserEmailAddress();
1004 $dg = documentgroup_get_object($this->getDocGroupID(), $this->Group->getID());
1005 if ($dg->isMonitoredBy('ALL')) {
1006 $BCC .= $dg->getMonitoredUserEmailAddress();
1008 if (strlen($BCC) > 0) {
1009 $session = session_get_user();
1011 $status = _('New Document');
1013 $status = _('Updated document').' '._('by').' ' . $session->getRealName();
1015 $subject = '['.$this->Group->getPublicName().'] '.$status.' - '.$this->getName();
1016 $body = _('Project')._(': ').$this->Group->getPublicName()."\n";
1017 $body .= _('Folder')._(': ').$this->getDocGroupName()."\n";
1018 $body .= _('Document Title')._(': ').$this->getName()."\n";
1019 $body .= _('Document description')._(': ').util_unconvert_htmlspecialchars($this->getDescription())."\n";
1020 $body .= _('Submitter')._(': ').$this->getCreatorRealName()." (".$this->getCreatorUserName().") \n";
1021 $body .= "\n\n-------------------------------------------------------\n".
1022 _('For more info, visit:').
1023 "\n\n" . util_make_url($this->getPermalink());
1025 $BCCarray = explode(',',$BCC);
1026 foreach ($BCCarray as $dest_email) {
1027 util_send_message($dest_email, $subject, $body, 'noreply@'.forge_get_config('web_host'), '', _('Docman'));
1034 * sendApprovalNotice - send email to project admin for pending documents.
1036 * @return bool success.
1038 function sendApprovalNotice() {
1039 if ($this->getStateID() != 3)
1042 $doc_name = $this->getName();
1043 $desc = util_unconvert_htmlspecialchars($this->getDescription());
1044 $group_id = $this->Group->getID();
1045 $name = $this->getCreatorRealName()." (".$this->getCreatorUserName().")";
1048 $subject="[" . forge_get_config('forge_name') ."] ".util_unconvert_htmlspecialchars($doc_name);
1049 $body = "\n"._('A new document has been uploaded and waiting to be approved by you')._(': ').
1050 "\n".util_make_url($this->getPermalink()).
1051 "\n"._('by').(': ').$name."\n";
1053 $sanitizer = new TextSanitizer();
1055 if (strstr($text,'<br/>') || strstr($text,'<br />')) {
1056 $text = preg_replace('/[\n\r]/', '', $text);
1058 $text = $sanitizer->convertNeededTagsForEmail($text);
1059 $text = preg_replace('/\[.+\](.+)\[\/.+\]/','$1',$text);
1060 $text = $sanitizer->convertExtendedCharsForEmail($text);
1063 $extra_headers = "Return-Path: <noreply@".forge_get_config('web_host').">\n";
1064 $extra_headers .= "Errors-To: <noreply@".forge_get_config('web_host').">\n";
1065 $extra_headers .= "Sender: <noreply@".forge_get_config('web_host').">";
1067 $groupUsers = $this->Group->getUsers();
1068 $rbacEngine = RBACEngine::getInstance();
1069 foreach ($groupUsers as $groupUser) {
1070 if ($rbacEngine->isActionAllowedForUser($groupUser, 'docman', $group_id, 'approve')) {
1071 $bcc .= $groupUser->getEmail().',';
1074 if (strlen($bcc) > 0) {
1075 util_send_message('', $subject, $body, "noreply@".forge_get_config('web_host'),
1076 $bcc, 'Docman', $extra_headers);
1082 * delete - Delete this file
1084 * @return bool success
1087 $perm =& $this->Group->getPermission();
1088 if (!$perm || !is_object($perm) || !$perm->isDocEditor()) {
1089 $this->setPermissionDeniedError();
1094 $dvf = new DocumentVersionFactory($this);
1095 $serialids = $dvf->getSerialIDs();
1096 $result = db_query_params('DELETE FROM doc_data WHERE docid=$1',
1097 array($this->getID()));
1099 $this->setError(_('Error Deleting Document')._(': ').db_error());
1104 if (!$this->removeAllAssociations()) {
1105 // error message already set by FFObject class.
1111 foreach ($serialids as $serialid) {
1112 DocumentStorage::instance()->delete($serialid)->commit();
1115 /** we should be able to send a notice that this doc has been deleted .... but we need to rewrite sendNotice
1116 * $this->sendNotice(false);
1117 * @TODO delete monitoring this file */
1122 * trash - move this file to trash
1124 * @return bool success or not.
1127 if (!$this->getLocked() || ((time() - $this->getLockdate()) > 600)) {
1128 $this->setState('2');
1129 $dm = new DocumentManager($this->Group);
1130 $this->setDocGroupID($dm->getTrashID());
1132 $this->setReservedBy(0);
1133 $this->sendNotice(false);
1134 $this->clearMonitor();
1142 * downloadUp - insert download stats
1145 function downloadUp() {
1146 if (session_loggedin()) {
1148 $us = $LUSER->getID();
1153 $ip = getStringFromServer('REMOTE_ADDR');
1154 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));
1158 * setValueinDB - private function to update columns in db
1160 * @param array $colArr the columns to update in array form array('col1', col2')
1161 * @param array $valArr the values to store in array form array('val1', 'val2')
1162 * @return bool success or not
1164 private function setValueinDB($colArr, $valArr) {
1165 if ((count($colArr) != count($valArr)) || !count($colArr) || !count($valArr)) {
1166 $this->setOnUpdateError(_('wrong parameters'));
1170 $qpa = db_construct_qpa(false, 'UPDATE doc_data SET ');
1171 for ($i = 0; $i < count($colArr); $i++) {
1172 switch ($colArr[$i]) {
1182 $qpa = db_construct_qpa($qpa, ',');
1184 $qpa = db_construct_qpa($qpa, $colArr[$i]);
1185 $qpa = db_construct_qpa($qpa, '=$1 ', array($valArr[$i]));
1189 $this->setOnUpdateError(_('wrong column name'));
1194 $qpa = db_construct_qpa($qpa, ' WHERE group_id=$1
1196 array($this->Group->getID(),
1198 $res = db_query_qpa($qpa);
1199 if (!$res || db_affected_rows($res) < 1) {
1200 $this->setOnUpdateError(db_error());
1203 $localDg = documentgroup_get_object($this->getDocGroupID(), $this->Group->getID());
1204 if (!$localDg->update($localDg->getName(), $localDg->getParentID(), 1, $localDg->getState())) {
1205 $this->setError(_('Error updating document group')._(': ').$localDg->getErrorMessage());
1208 for ($i = 0; $i < count($colArr); $i++) {
1209 switch ($colArr[$i]) {
1218 $this->data_array[$colArr[$i]] = $valArr[$i];
1222 $this->sendNotice(false);
1226 function getPermalink() {
1227 return '/docman/d_follow.php/'.$this->getID();
1230 function hasValidatedReview() {
1231 $dv = documentversion_get_object($this->getVersion(), $this->getID(), $this->Group->getID());
1232 return $dv->hasValidatedReview();
1238 // c-file-style: "bsd"