5 * Copyright 1999-2000, Tim Perdue/Sourceforge
6 * Copyright 2002, Tim Perdue/GForge, LLC
7 * Copyright 2009, Roland Mas
9 * This file is part of FusionForge.
11 * FusionForge is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published
13 * by the Free Software Foundation; either version 2 of the License,
14 * or (at your option) any later version.
16 * FusionForge is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with FusionForge; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 require_once $gfcommon.'include/Error.class.php';
28 require_once $gfcommon.'forum/ForumMessage.class.php';
29 // This string is used when sending the notification mail for identifying the
31 define('FORUM_MAIL_MARKER', '#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+');
33 class Forum extends Error {
36 * Associative array of data from db.
38 * @var array $data_array.
47 var $Group; //group object
50 * An array of 'types' for this forum - nested, flat, ultimate, etc.
52 * @var array view_types.
56 var $current_user_perm;
61 * @param object The Group object to which this forum is associated.
62 * @param int The group_forum_id.
63 * @param array The associative array of data.
64 * @return boolean success.
66 function Forum(&$Group, $group_forum_id=false, $arr=false) {
68 if (!$Group || !is_object($Group)) {
69 $this->setError(sprintf(_('%1$s:: No Valid Group Object'), "Forum"));
72 if ($Group->isError()) {
73 $this->setError('Forum:: '.$Group->getErrorMessage());
76 $this->Group =& $Group;
78 if ($group_forum_id) {
79 if (!$arr || !is_array($arr)) {
80 if (!$this->fetchData($group_forum_id)) {
84 $this->data_array =& $arr;
85 if ($this->data_array['group_id'] != $this->Group->getID()) {
86 $this->setError(_('Group_id in db result does not match Group Object'));
87 $this->data_array = null;
92 // Make sure they can even access this object
94 if (!$this->userCanView()) {
95 $this->setPermissionDeniedError();
96 $this->data_array = null;
100 $this->view_types[]='ultimate';
101 $this->view_types[]='flat';
102 $this->view_types[]='nested';
103 $this->view_types[]='threaded';
108 * create - use this function to create a new entry in the database.
110 * @param string The name of the forum.
111 * @param string The description of the forum.
112 * @param int Pass (1) if it should be public (0) for private.
113 * @param string The email address to send all new posts to.
114 * @param int Pass (1) if a welcome message should be created (0) for no welcome message.
115 * @param int Pass (1) if we should allow non-logged-in users to post (0) for mandatory login.
116 * @param int Pass (0) if the messages that are posted in the forum should go to moderation before available. 0-> no moderation 1-> moderation for anonymous and non-project members 2-> moderation for everyone
117 * @return boolean success.
119 function create($forum_name,$description,$is_public=1,$send_all_posts_to='',$create_default_message=1,$allow_anonymous=1,$moderation_level=0) {
120 if (strlen($forum_name) < 3) {
121 $this->setError(_('Forum Name Must Be At Least 3 Characters'));
124 if (strlen($description) < 10) {
125 $this->setError(_('Forum Description Must Be At Least 10 Characters'));
128 if (!preg_match('/^([_\.0-9a-z-])*$/i',$forum_name)) {
129 $this->setError(_('Illegal Characters in Forum Name'));
132 if ($send_all_posts_to) {
133 $send_all_posts_to = str_replace(';', ',', $send_all_posts_to);
134 $invalid_mails = validate_emails($send_all_posts_to);
135 if (count($invalid_mails) > 0) {
136 $this->setInvalidEmailError();
141 $project_name = $this->Group->getUnixName();
142 $result_list_samename = db_query_params ('SELECT 1 FROM mail_group_list WHERE list_name=$1 AND group_id=$2',
144 array ($project_name.'-'.strtolower($forum_name),
145 $this->Group->getID())) ;
147 if (db_numrows($result_list_samename) > 0){
148 $this->setError(_('Mailing List Exists with same name'));
153 // This is a hack to allow non-site-wide-admins to post
154 // news. The news/submit.php checks for proper permissions.
155 // This needs to be revisited.
156 global $sys_news_group;
157 if ($this->Group->getID() == $sys_news_group) {
158 // Future check will be added.
161 // Current permissions check.
163 $perm =& $this->Group->getPermission( session_get_user() );
165 if (!$perm || !is_object($perm) || !$perm->isForumAdmin()) {
166 $this->setPermissionDeniedError();
172 $result = db_query_params('INSERT INTO forum_group_list (group_id,forum_name,is_public,description,send_all_posts_to,allow_anonymous,moderation_level) VALUES ($1,$2,$3,$4,$5,$6,$7)',
173 array ($this->Group->getID(),
174 strtolower($forum_name),
176 htmlspecialchars($description),
179 $moderation_level)) ;
182 $this->setError(_('Error Adding Forum').db_error());
185 $this->group_forum_id=db_insertid($result,'forum_group_list','group_forum_id');
186 $this->fetchData($this->group_forum_id);
188 if ($create_default_message) {
189 $fm=new ForumMessage($this);
190 // Use the system side default language
191 setup_gettext_from_sys_lang ();
192 $string=sprintf(_('Welcome to %1$s'), $forum_name);
193 // and switch back to the user preference
194 setup_gettext_from_context();
195 if (!$fm->create($string, $string)) {
196 $this->setError($fm->getErrorMessage());
202 $this->Group->normalizeAllRoles () ;
208 * fetchData - re-fetch the data for this forum from the database.
210 * @param int The forum_id.
211 * @return boolean success.
213 function fetchData($group_forum_id) {
214 global $sys_database_type;
216 $res = db_query_params ('SELECT * FROM forum_group_list_vw WHERE group_forum_id=$1',
217 array ($group_forum_id)) ;
218 if (!$res || db_numrows($res) < 1) {
219 $this->setError(_('Invalid forum group identifier'));
222 $this->data_array =& db_fetch_array($res);
223 db_free_result($res);
228 * getGroup - get the Group object this ArtifactType is associated with.
230 * @return object The Group object.
232 function &getGroup() {
237 * getID - The id of this forum.
239 * @return int The group_forum_id #.
242 return $this->data_array['group_forum_id'];
246 * getNextThreadID - The next thread_id for a new top in this forum.
248 * @return int The next thread_id #.
250 function getNextThreadID() {
251 $result = db_query_params ('SELECT nextval($1)',
252 array ('forum_thread_seq')) ;
253 if (!$result || db_numrows($result) < 1) {
257 return db_result($result,0,0);
261 * getUnixName - returns the name used by email gateway
263 * @return string unix name
265 function getUnixName() {
266 return $this->Group->getUnixName().'-'.$this->getName();
270 * getSavedDate - The unix time when the person last hit "save my place".
272 * @return int The unix time.
274 function getSavedDate() {
275 if (@$this->save_date) {
276 return $this->save_date;
278 if (session_loggedin()) {
279 $result = db_query_params ('SELECT save_date FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
282 if ($result && db_numrows($result) > 0) {
283 $this->save_date=db_result($result,0,'save_date');
284 return $this->save_date;
286 //highlight new messages from the past week only
287 $this->save_date=(time()-604800);
288 return $this->save_date;
291 //highlight new messages from the past week only
292 $this->save_date=(time()-604800);
293 return $this->save_date;
299 * allowAnonymous - does this forum allow non-logged in users to post.
301 * @return boolean allow_anonymous.
303 function allowAnonymous() {
304 return $this->data_array['allow_anonymous'];
308 * isPublic - Is this forum open to the general public.
310 * @return boolean is_public.
312 function isPublic() {
313 return $this->data_array['is_public'];
317 * getName - get the name of this forum.
319 * @return string The name of this forum.
322 return $this->data_array['forum_name'];
326 * getSendAllPostsTo - an optional email address to send all forum posts to.
328 * @return string The email address.
330 function getSendAllPostsTo() {
331 return $this->data_array['send_all_posts_to'];
335 * getDescription - the description of this forum.
337 * @return string The description.
339 function getDescription() {
340 return $this->data_array['description'];
344 * getModerationLevel - the moderation level of the forum
346 * @return int The moderation level.
348 function getModerationLevel() {
349 return $this->data_array['moderation_level'];
353 * getMessageCount - the total number of messages in this forum.
355 * @return int The count.
357 function getMessageCount() {
358 return $this->data_array['total'];
362 * getThreadCount - the total number of threads in this forum.
364 * @return int The count.
366 function getThreadCount() {
367 return $this->data_array['threads'];
371 * getMostRecentDate - the most recent date of a post to this board.
373 * @return int The most recent date.
375 function getMostRecentDate() {
376 return $this->data_array['recent'];
380 * getMonitoringIDs - return an array of user_id's for those monitoring this forum.
382 * @return array The array of user_id's.
384 function getMonitoringIDs() {
385 $result = db_query_params ('SELECT user_id FROM forum_monitored_forums WHERE forum_id=$1',
386 array ($this->getID())) ;
387 return util_result_column_to_array($result);
391 * getForumAdminIDs - return an array of user_id's for those users which are forum admins.
393 * @return array The array of user_id's.
395 function getForumAdminIDs() {
396 $result = db_query_params ('SELECT user_group.user_id FROM user_group, role_setting
397 WHERE role_setting.section_name=$1
398 AND role_setting.ref_id=$2
399 AND role_setting.value::integer > 1
400 AND user_group.role_id = role_setting.role_id',
403 return util_result_column_to_array($result);
407 * getReturnEmailAddress() - return the return email address for notification emails
409 * @return string return email address
411 function getReturnEmailAddress() {
412 global $sys_use_gateways;
414 if($sys_use_gateways) {
415 $address .= $this->getUnixName();
417 $address .= 'noreply';
420 if($sys_use_gateways && isset($GLOBALS['sys_forum_return_domain'])) {
421 $address .= $GLOBALS['sys_forum_return_domain'];
423 $address .= forge_get_config('web_host');
429 * setMonitor - Add the current user to the list of people monitoring the forum.
431 * @return boolean success.
433 function setMonitor ($u = -1) {
435 if (!session_loggedin()) {
436 $this->setError(_('You can only monitor if you are logged in'));
441 $result = db_query_params ('SELECT * FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
444 if (!$result || db_numrows($result) < 1) {
446 User is not already monitoring thread, so
447 insert a row so monitoring can begin
449 $sql="INSERT INTO forum_monitored_forums (forum_id,user_id)
450 VALUES ('".$this->getID()."','$u')";
452 $result = db_query_params ('INSERT INTO forum_monitored_forums (forum_id,user_id) VALUES ($1,$2)',
453 array ($this->getID(),
457 $this->setError(_('Unable To Add Monitor').' : '.db_error());
466 * stopMonitor - Remove the current user from the list of people monitoring the forum.
468 * @return boolean success.
470 function stopMonitor ($u = -1) {
472 if (!session_loggedin()) {
473 $this->setError(_('You can only monitor if you are logged in'));
478 return db_query_params ('DELETE FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
484 * isMonitoring - See if the current user is in the list of people monitoring the forum.
486 * @return boolean is_monitoring.
488 function isMonitoring() {
489 if (!session_loggedin()) {
492 $result = db_query_params ('SELECT count(*) AS count FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
495 $row_count = db_fetch_array($result);
496 return $result && $row_count['count'] > 0;
500 * savePlace - set a unix time into the database for this user, so future messages can be highlighted.
502 * @return boolean success.
504 function savePlace() {
505 if (!session_loggedin()) {
506 $this->setError(_('You Can Only Save Your Place If You Are Logged In'));
509 $result = db_query_params ('SELECT * FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
513 if (!$result || db_numrows($result) < 1) {
515 User is not already monitoring thread, so
516 insert a row so monitoring can begin
518 $result = db_query_params ('INSERT INTO forum_saved_place (forum_id,user_id,save_date) VALUES ($1,$2,$3)',
519 array ($this->getID(),
524 $this->setError(_('Forum::savePlace()').': '.db_error());
529 $result = db_query_params ('UPDATE forum_saved_place SET save_date=$1 WHERE user_id=$2 AND forum_id=$3',
535 $this->setError('Forum::savePlace() '.db_error());
543 * update - use this function to update an entry in the database.
545 * @param string The name of the forum.
546 * @param string The description of the forum.
547 * @param int if it should be public (0) for private.
548 * @param int if we should allow non-logged-in users to post (0) for mandatory login.
549 * @param string The email address to send all new posts to.
550 * @param int if the messages that are posted in the forum should go to moderation before available. 0-> no moderation 1-> moderation for anonymous and non-project members 2-> moderation for everyone
551 * @return boolean success.
553 function update($forum_name,$description,$allow_anonymous,$is_public,$send_all_posts_to='',$moderation_level=0) {
554 if (strlen($forum_name) < 3) {
555 $this->setError(_('Forum Name Must Be At Least 3 Characters'));
558 if (strlen($description) < 10) {
559 $this->setError(_('Forum Description Must Be At Least 10 Characters'));
562 if (!preg_match('/^([_\.0-9a-z-])*$/i',$forum_name)) {
563 $this->setError(_('Illegal Characters in Forum Name'));
566 if ($send_all_posts_to) {
567 $send_all_posts_to = str_replace(';', ',', $send_all_posts_to);
568 $invalid_mails = validate_emails($send_all_posts_to);
569 if (count($invalid_mails) > 0) {
570 $this->setInvalidEmailError();
575 if (!$this->userIsAdmin()) {
576 $this->setPermissionDeniedError();
580 $res = db_query_params ('UPDATE forum_group_list SET
583 send_all_posts_to=$3,
588 AND group_forum_id=$8',
589 array (strtolower($forum_name),
590 htmlspecialchars($description),
595 $this->Group->getID(),
598 if (!$res || db_affected_rows($res) < 1) {
599 $this->setError(_('Error On Update:').': '.db_error());
606 * delete - delete this forum and all its related data.
608 * @param bool I'm Sure.
609 * @param bool I'm REALLY sure.
610 * @return bool true/false;
612 function delete($sure, $really_sure) {
613 if (!$sure || !$really_sure) {
614 $this->setMissingParamsError();
617 if (!$this->userIsAdmin()) {
618 $this->setPermissionDeniedError();
622 db_query_params ('DELETE FROM forum_agg_msg_count WHERE group_forum_id=$1',
623 array ($this->getID())) ;
624 //echo '1'.db_error();
625 db_query_params ('DELETE FROM forum_monitored_forums WHERE forum_id=$1',
626 array ($this->getID())) ;
627 //echo '2'.db_error();
628 db_query_params ('DELETE FROM forum_saved_place WHERE forum_id=$1',
629 array ($this->getID())) ;
630 //echo '3'.db_error();
631 db_query_params ('DELETE FROM forum_attachment WHERE msg_id IN (SELECT msg_id from forum where group_forum_id=$1)',
632 array ($this->getID())) ;
633 db_query_params ('DELETE FROM forum WHERE group_forum_id=$1',
634 array ($this->getID())) ;
635 //echo '4'.db_error();
636 db_query_params ('DELETE FROM forum_group_list WHERE group_forum_id=$1',
637 array ($this->getID())) ;
638 //echo '5'.db_error();
639 //delete forum's role setting
640 db_query_params ('DELETE FROM role_setting WHERE section_name=$1 AND ref_id=$2',
646 $this->Group->normalizeAllRoles () ;
653 USER PERMISSION FUNCTIONS
658 * userCanView - determine if the user can view this forum.
660 * @return boolean user_can_view.
662 function userCanView() {
663 if ($this->isPublic()) {
666 if (!session_loggedin()) {
670 // You must have a role in the project if this forum is not public
672 if ($this->userIsAdmin() || $this->getCurrentUserPerm() >= 0) {
682 * userIsModLvl1 - see if the user goes into the moderated level 1 category
684 * @return boolean user_is_mod_lvl1
686 function userIsModLvl1() {
687 if (!session_loggedin()) {
688 if ( ($this->isPublic() && $this->allowAnonymous()) ) {
689 return true;//public forum, anonymous allowed, user not logged in
692 $perm =& $this->Group->getPermission( session_get_user() );
693 if ( (!$perm->isMember() )) {
694 //the user isn't a member of the project
702 * userIsModLvl2 - see if the user goes into the moderated level 2 category
704 * @return boolean user_is_mod_lvl1
706 function userIsModLvl2() {
707 if ( $this->userIsAdmin() ) {
715 * userCanPost - see if the logged-in user's perms are >= 1 or Group ForumAdmin.
717 * @return boolean user_can_post.
719 function userCanPost() {
720 if (($this->isPublic() && $this->allowAnonymous()) || $this->userIsAdmin()) {
722 } elseif ($this->isPublic() && session_loggedin()) {
725 if (!session_loggedin()) {
728 if ($this->getCurrentUserPerm() >= 1) {
738 * userIsAdmin - see if the logged-in user's perms are >= 2 or Group ForumAdmin.
740 * @return boolean user_is_admin.
742 function userIsAdmin() {
743 if (!session_loggedin()) {
746 $perm =& $this->Group->getPermission( session_get_user() );
748 if (($this->getCurrentUserPerm() >= 2) || ($perm->isForumAdmin())) {
757 * getCurrentUserPerm - get the logged-in user's perms from his role.
759 * @return int perm level for the logged-in user.
761 function getCurrentUserPerm() {
762 if (!session_loggedin()) {
765 if (!isset($this->current_user_perm)) {
766 $res = db_query_params ('SELECT role_setting.value::integer
767 FROM role_setting, user_group
768 WHERE role_setting.ref_id=$1
769 AND user_group.role_id=role_setting.role_id
770 AND user_group.user_id=$2
771 AND role_setting.section_name=$3',
772 array ($this->getID(),
775 $this->current_user_perm=db_result($res,0,0);
777 // Return no access if no access rights defined.
778 if (!$this->current_user_perm)
779 $this->current_user_perm=-1;
781 return $this->current_user_perm;
790 // c-file-style: "bsd"