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 $invalid_mails = validate_emails($send_all_posts_to);
134 if (count($invalid_mails) > 0) {
135 $this->setInvalidEmailError();
140 $project_name = $this->Group->getUnixName();
141 $result_list_samename = db_query_params ('SELECT 1 FROM mail_group_list WHERE list_name=$1 AND group_id=$2',
143 array ($project_name.'-'.strtolower($forum_name),
144 $this->Group->getID())) ;
146 if (db_numrows($result_list_samename) > 0){
147 $this->setError(_('Mailing List Exists with same name'));
152 // This is a hack to allow non-site-wide-admins to post
153 // news. The news/submit.php checks for proper permissions.
154 // This needs to be revisited.
155 global $sys_news_group;
156 if ($this->Group->getID() == $sys_news_group) {
157 // Future check will be added.
160 // Current permissions check.
162 $perm =& $this->Group->getPermission( session_get_user() );
164 if (!$perm || !is_object($perm) || !$perm->isForumAdmin()) {
165 $this->setPermissionDeniedError();
171 $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)',
172 array ($this->Group->getID(),
173 strtolower($forum_name),
175 htmlspecialchars($description),
178 $moderation_level)) ;
181 $this->setError(_('Error Adding Forum').db_error());
184 $this->group_forum_id=db_insertid($result,'forum_group_list','group_forum_id');
185 $this->fetchData($this->group_forum_id);
187 // set the permission for the role's group
188 $roles_group = $this->Group->getRolesId();
189 for ($i=0; $i<sizeof($roles_group); $i++) {
190 $role_setting_res = db_query_params ('INSERT INTO role_setting (role_id,section_name,ref_id,value) VALUES ($1,$2,$3,$4)',
191 array ($roles_group[$i],
193 $this->group_forum_id,
195 if (!$role_setting_res) {
197 $this->setError('Error: Role setting for forum id ' . $this->group_forum_id . ' for groud id ' . $this->Group->getID() . ' ' .db_error());
202 if ($create_default_message) {
203 $fm=new ForumMessage($this);
204 // Use the system side default language
205 setup_gettext_from_sys_lang ();
206 $string=sprintf(_('Welcome to %1$s'), $forum_name);
207 // and switch back to the user preference
208 setup_gettext_from_context();
209 if (!$fm->create($string, $string)) {
210 $this->setError($fm->getErrorMessage());
219 * fetchData - re-fetch the data for this forum from the database.
221 * @param int The forum_id.
222 * @return boolean success.
224 function fetchData($group_forum_id) {
225 global $sys_database_type;
227 if ($sys_database_type == "mysql") {
230 (SELECT count(*) AS `count`
232 SELECT DISTINCT group_forum_id, thread_id FROM forum
234 WHERE tmp.group_forum_id = fgl.group_forum_id
236 FROM forum_group_list_vw AS fgl
237 WHERE group_forum_id='$group_forum_id'";
238 $res = db_query_mysql ($sql);
240 $res = db_query_params ('SELECT * FROM forum_group_list_vw WHERE group_forum_id=$1',
241 array ($group_forum_id)) ;
243 if (!$res || db_numrows($res) < 1) {
244 $this->setError(_('Invalid forum group identifier'));
247 $this->data_array =& db_fetch_array($res);
248 db_free_result($res);
253 * getGroup - get the Group object this ArtifactType is associated with.
255 * @return object The Group object.
257 function &getGroup() {
262 * getID - The id of this forum.
264 * @return int The group_forum_id #.
267 return $this->data_array['group_forum_id'];
271 * getNextThreadID - The next thread_id for a new top in this forum.
273 * @return int The next thread_id #.
275 function getNextThreadID() {
276 global $sys_database_type;
278 if ($sys_database_type == "mysql") {
279 $sql="call newval('forum_thread_seq', @res)";
280 $result=db_mquery($sql);
286 $result = db_query_mysql ($sql);
288 $result = db_query_params ('SELECT nextval($1)',
289 array ('forum_thread_seq')) ;
291 if (!$result || db_numrows($result) < 1) {
295 return db_result($result,0,0);
299 * getUnixName - returns the name used by email gateway
301 * @return string unix name
303 function getUnixName() {
304 return $this->Group->getUnixName().'-'.$this->getName();
308 * getSavedDate - The unix time when the person last hit "save my place".
310 * @return int The unix time.
312 function getSavedDate() {
313 if (@$this->save_date) {
314 return $this->save_date;
316 if (session_loggedin()) {
317 $result = db_query_params ('SELECT save_date FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
320 if ($result && db_numrows($result) > 0) {
321 $this->save_date=db_result($result,0,'save_date');
322 return $this->save_date;
324 //highlight new messages from the past week only
325 $this->save_date=(time()-604800);
326 return $this->save_date;
329 //highlight new messages from the past week only
330 $this->save_date=(time()-604800);
331 return $this->save_date;
337 * allowAnonymous - does this forum allow non-logged in users to post.
339 * @return boolean allow_anonymous.
341 function allowAnonymous() {
342 return $this->data_array['allow_anonymous'];
346 * isPublic - Is this forum open to the general public.
348 * @return boolean is_public.
350 function isPublic() {
351 return $this->data_array['is_public'];
355 * getName - get the name of this forum.
357 * @return string The name of this forum.
360 return $this->data_array['forum_name'];
364 * getSendAllPostsTo - an optional email address to send all forum posts to.
366 * @return string The email address.
368 function getSendAllPostsTo() {
369 return $this->data_array['send_all_posts_to'];
373 * getDescription - the description of this forum.
375 * @return string The description.
377 function getDescription() {
378 return $this->data_array['description'];
382 * getModerationLevel - the moderation level of the forum
384 * @return int The moderation level.
386 function getModerationLevel() {
387 return $this->data_array['moderation_level'];
391 * getMessageCount - the total number of messages in this forum.
393 * @return int The count.
395 function getMessageCount() {
396 return $this->data_array['total'];
400 * getThreadCount - the total number of threads in this forum.
402 * @return int The count.
404 function getThreadCount() {
405 return $this->data_array['threads'];
409 * getMostRecentDate - the most recent date of a post to this board.
411 * @return int The most recent date.
413 function getMostRecentDate() {
414 return $this->data_array['recent'];
418 * getMonitoringIDs - return an array of user_id's for those monitoring this forum.
420 * @return array The array of user_id's.
422 function getMonitoringIDs() {
423 $result = db_query_params ('SELECT user_id FROM forum_monitored_forums WHERE forum_id=$1',
424 array ($this->getID())) ;
425 return util_result_column_to_array($result);
429 * getForumAdminIDs - return an array of user_id's for those users which are forum admins.
431 * @return array The array of user_id's.
433 function getForumAdminIDs() {
434 $result = db_query_params ('SELECT user_group.user_id FROM user_group, role_setting
435 WHERE role_setting.section_name=$1
436 AND role_setting.ref_id=$2
437 AND role_setting.value::integer > 1
438 AND user_group.role_id = role_setting.role_id',
441 return util_result_column_to_array($result);
445 * getReturnEmailAddress() - return the return email address for notification emails
447 * @return string return email address
449 function getReturnEmailAddress() {
450 global $sys_default_domain, $sys_use_gateways;
452 if($sys_use_gateways) {
453 $address .= $this->getUnixName();
455 $address .= 'noreply';
458 if($sys_use_gateways && isset($GLOBALS['sys_forum_return_domain'])) {
459 $address .= $GLOBALS['sys_forum_return_domain'];
461 $address .= $sys_default_domain;
467 * setMonitor - Add the current user to the list of people monitoring the forum.
469 * @return boolean success.
471 function setMonitor ($u = -1) {
473 if (!session_loggedin()) {
474 $this->setError(_('You can only monitor if you are logged in'));
479 $result = db_query_params ('SELECT * FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
482 if (!$result || db_numrows($result) < 1) {
484 User is not already monitoring thread, so
485 insert a row so monitoring can begin
487 $sql="INSERT INTO forum_monitored_forums (forum_id,user_id)
488 VALUES ('".$this->getID()."','$u')";
490 $result = db_query_params ('INSERT INTO forum_monitored_forums (forum_id,user_id) VALUES ($1,$2)',
491 array ($this->getID(),
495 $this->setError(_('Unable To Add Monitor').' : '.db_error());
504 * stopMonitor - Remove the current user from the list of people monitoring the forum.
506 * @return boolean success.
508 function stopMonitor ($u = -1) {
510 if (!session_loggedin()) {
511 $this->setError(_('You can only monitor if you are logged in'));
516 return db_query_params ('DELETE FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
522 * isMonitoring - See if the current user is in the list of people monitoring the forum.
524 * @return boolean is_monitoring.
526 function isMonitoring() {
527 if (!session_loggedin()) {
530 $result = db_query_params ('SELECT count(*) AS count FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
533 $row_count = db_fetch_array($result);
534 return $result && $row_count['count'] > 0;
538 * savePlace - set a unix time into the database for this user, so future messages can be highlighted.
540 * @return boolean success.
542 function savePlace() {
543 if (!session_loggedin()) {
544 $this->setError(_('You Can Only Save Your Place If You Are Logged In'));
547 $result = db_query_params ('SELECT * FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
551 if (!$result || db_numrows($result) < 1) {
553 User is not already monitoring thread, so
554 insert a row so monitoring can begin
556 $result = db_query_params ('INSERT INTO forum_saved_place (forum_id,user_id,save_date) VALUES ($1,$2,$3)',
557 array ($this->getID(),
562 $this->setError(_('Forum::savePlace()').': '.db_error());
567 $result = db_query_params ('UPDATE forum_saved_place SET save_date=$1 WHERE user_id=$2 AND forum_id=$3',
573 $this->setError('Forum::savePlace() '.db_error());
581 * update - use this function to update an entry in the database.
583 * @param string The name of the forum.
584 * @param string The description of the forum.
585 * @param int if it should be public (0) for private.
586 * @param int if we should allow non-logged-in users to post (0) for mandatory login.
587 * @param string The email address to send all new posts to.
588 * @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
589 * @return boolean success.
591 function update($forum_name,$description,$allow_anonymous,$is_public,$send_all_posts_to='',$moderation_level=0) {
592 if (strlen($forum_name) < 3) {
593 $this->setError(_('Forum Name Must Be At Least 3 Characters'));
596 if (strlen($description) < 10) {
597 $this->setError(_('Forum Description Must Be At Least 10 Characters'));
600 if (!preg_match('/^([_\.0-9a-z-])*$/i',$forum_name)) {
601 $this->setError(_('Illegal Characters in Forum Name'));
604 if ($send_all_posts_to) {
605 $send_all_posts_to = str_replace(';', ',', $send_all_posts_to);
606 $invalid_mails = validate_emails($send_all_posts_to);
607 if (count($invalid_mails) > 0) {
608 $this->setInvalidEmailError();
613 if (!$this->userIsAdmin()) {
614 $this->setPermissionDeniedError();
618 $res = db_query_params ('UPDATE forum_group_list SET
621 send_all_posts_to=$3,
626 AND group_forum_id=$8',
627 array (strtolower($forum_name),
628 htmlspecialchars($description),
633 $this->Group->getID(),
636 if (!$res || db_affected_rows($res) < 1) {
637 $this->setError(_('Error On Update:').': '.db_error());
644 * delete - delete this forum and all its related data.
646 * @param bool I'm Sure.
647 * @param bool I'm REALLY sure.
648 * @return bool true/false;
650 function delete($sure, $really_sure) {
651 if (!$sure || !$really_sure) {
652 $this->setMissingParamsError();
655 if (!$this->userIsAdmin()) {
656 $this->setPermissionDeniedError();
660 db_query_params ('DELETE FROM forum_agg_msg_count WHERE group_forum_id=$1',
661 array ($this->getID())) ;
662 //echo '1'.db_error();
663 db_query_params ('DELETE FROM forum_monitored_forums WHERE forum_id=$1',
664 array ($this->getID())) ;
665 //echo '2'.db_error();
666 db_query_params ('DELETE FROM forum_saved_place WHERE forum_id=$1',
667 array ($this->getID())) ;
668 //echo '3'.db_error();
669 db_query_params ('DELETE FROM forum_attachment WHERE msg_id IN (SELECT msg_id from forum where group_forum_id=$1)',
670 array ($this->getID())) ;
671 db_query_params ('DELETE FROM forum WHERE group_forum_id=$1',
672 array ($this->getID())) ;
673 //echo '4'.db_error();
674 db_query_params ('DELETE FROM forum_group_list WHERE group_forum_id=$1',
675 array ($this->getID())) ;
676 //echo '5'.db_error();
677 //delete forum's role setting
678 db_query_params ('DELETE FROM role_setting WHERE section_name=$1 AND ref_id=$2',
687 USER PERMISSION FUNCTIONS
692 * userCanView - determine if the user can view this forum.
694 * @return boolean user_can_view.
696 function userCanView() {
697 if ($this->isPublic()) {
700 if (!session_loggedin()) {
704 // You must have a role in the project if this forum is not public
706 if ($this->userIsAdmin() || $this->getCurrentUserPerm() >= 0) {
716 * userIsModLvl1 - see if the user goes into the moderated level 1 category
718 * @return boolean user_is_mod_lvl1
720 function userIsModLvl1() {
721 if (!session_loggedin()) {
722 if ( ($this->isPublic() && $this->allowAnonymous()) ) {
723 return true;//public forum, anonymous allowed, user not logged in
726 $perm =& $this->Group->getPermission( session_get_user() );
727 if ( (!$perm->isMember() )) {
728 //the user isn't a member of the project
736 * userIsModLvl2 - see if the user goes into the moderated level 2 category
738 * @return boolean user_is_mod_lvl1
740 function userIsModLvl2() {
741 if ( $this->userIsAdmin() ) {
749 * userCanPost - see if the logged-in user's perms are >= 1 or Group ForumAdmin.
751 * @return boolean user_can_post.
753 function userCanPost() {
754 if (($this->isPublic() && $this->allowAnonymous()) || $this->userIsAdmin()) {
756 } elseif ($this->isPublic() && session_loggedin()) {
759 if (!session_loggedin()) {
762 if ($this->getCurrentUserPerm() >= 1) {
772 * userIsAdmin - see if the logged-in user's perms are >= 2 or Group ForumAdmin.
774 * @return boolean user_is_admin.
776 function userIsAdmin() {
777 if (!session_loggedin()) {
780 $perm =& $this->Group->getPermission( session_get_user() );
782 if (($this->getCurrentUserPerm() >= 2) || ($perm->isForumAdmin())) {
791 * getCurrentUserPerm - get the logged-in user's perms from his role.
793 * @return int perm level for the logged-in user.
795 function getCurrentUserPerm() {
796 if (!session_loggedin()) {
799 if (!isset($this->current_user_perm)) {
800 $res = db_query_params ('SELECT role_setting.value::integer
801 FROM role_setting, user_group
802 WHERE role_setting.ref_id=$1
803 AND user_group.role_id=role_setting.role_id
804 AND user_group.user_id=$2
805 AND role_setting.section_name=$3',
806 array ($this->getID(),
809 $this->current_user_perm=db_result($res,0,0);
811 // Return no access if no access rights defined.
812 if (!$this->current_user_perm)
813 $this->current_user_perm=-1;
815 return $this->current_user_perm;
824 // c-file-style: "bsd"