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 // set the permission for the role's group
189 $roles_group = $this->Group->getRolesId();
190 for ($i=0; $i<sizeof($roles_group); $i++) {
191 $role_setting_res = db_query_params ('INSERT INTO role_setting (role_id,section_name,ref_id,value) VALUES ($1,$2,$3,$4)',
192 array ($roles_group[$i],
194 $this->group_forum_id,
196 if (!$role_setting_res) {
198 $this->setError('Error: Role setting for forum id ' . $this->group_forum_id . ' for groud id ' . $this->Group->getID() . ' ' .db_error());
203 if ($create_default_message) {
204 $fm=new ForumMessage($this);
205 // Use the system side default language
206 setup_gettext_from_sys_lang ();
207 $string=sprintf(_('Welcome to %1$s'), $forum_name);
208 // and switch back to the user preference
209 setup_gettext_from_context();
210 if (!$fm->create($string, $string)) {
211 $this->setError($fm->getErrorMessage());
220 * fetchData - re-fetch the data for this forum from the database.
222 * @param int The forum_id.
223 * @return boolean success.
225 function fetchData($group_forum_id) {
226 global $sys_database_type;
228 if ($sys_database_type == "mysql") {
231 (SELECT count(*) AS `count`
233 SELECT DISTINCT group_forum_id, thread_id FROM forum
235 WHERE tmp.group_forum_id = fgl.group_forum_id
237 FROM forum_group_list_vw AS fgl
238 WHERE group_forum_id='$group_forum_id'";
239 $res = db_query_mysql ($sql);
241 $res = db_query_params ('SELECT * FROM forum_group_list_vw WHERE group_forum_id=$1',
242 array ($group_forum_id)) ;
244 if (!$res || db_numrows($res) < 1) {
245 $this->setError(_('Invalid forum group identifier'));
248 $this->data_array =& db_fetch_array($res);
249 db_free_result($res);
254 * getGroup - get the Group object this ArtifactType is associated with.
256 * @return object The Group object.
258 function &getGroup() {
263 * getID - The id of this forum.
265 * @return int The group_forum_id #.
268 return $this->data_array['group_forum_id'];
272 * getNextThreadID - The next thread_id for a new top in this forum.
274 * @return int The next thread_id #.
276 function getNextThreadID() {
277 $result = db_query_params ('SELECT nextval($1)',
278 array ('forum_thread_seq')) ;
279 if (!$result || db_numrows($result) < 1) {
283 return db_result($result,0,0);
287 * getUnixName - returns the name used by email gateway
289 * @return string unix name
291 function getUnixName() {
292 return $this->Group->getUnixName().'-'.$this->getName();
296 * getSavedDate - The unix time when the person last hit "save my place".
298 * @return int The unix time.
300 function getSavedDate() {
301 if (@$this->save_date) {
302 return $this->save_date;
304 if (session_loggedin()) {
305 $result = db_query_params ('SELECT save_date FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
308 if ($result && db_numrows($result) > 0) {
309 $this->save_date=db_result($result,0,'save_date');
310 return $this->save_date;
312 //highlight new messages from the past week only
313 $this->save_date=(time()-604800);
314 return $this->save_date;
317 //highlight new messages from the past week only
318 $this->save_date=(time()-604800);
319 return $this->save_date;
325 * allowAnonymous - does this forum allow non-logged in users to post.
327 * @return boolean allow_anonymous.
329 function allowAnonymous() {
330 return $this->data_array['allow_anonymous'];
334 * isPublic - Is this forum open to the general public.
336 * @return boolean is_public.
338 function isPublic() {
339 return $this->data_array['is_public'];
343 * getName - get the name of this forum.
345 * @return string The name of this forum.
348 return $this->data_array['forum_name'];
352 * getSendAllPostsTo - an optional email address to send all forum posts to.
354 * @return string The email address.
356 function getSendAllPostsTo() {
357 return $this->data_array['send_all_posts_to'];
361 * getDescription - the description of this forum.
363 * @return string The description.
365 function getDescription() {
366 return $this->data_array['description'];
370 * getModerationLevel - the moderation level of the forum
372 * @return int The moderation level.
374 function getModerationLevel() {
375 return $this->data_array['moderation_level'];
379 * getMessageCount - the total number of messages in this forum.
381 * @return int The count.
383 function getMessageCount() {
384 return $this->data_array['total'];
388 * getThreadCount - the total number of threads in this forum.
390 * @return int The count.
392 function getThreadCount() {
393 return $this->data_array['threads'];
397 * getMostRecentDate - the most recent date of a post to this board.
399 * @return int The most recent date.
401 function getMostRecentDate() {
402 return $this->data_array['recent'];
406 * getMonitoringIDs - return an array of user_id's for those monitoring this forum.
408 * @return array The array of user_id's.
410 function getMonitoringIDs() {
411 $result = db_query_params ('SELECT user_id FROM forum_monitored_forums WHERE forum_id=$1',
412 array ($this->getID())) ;
413 return util_result_column_to_array($result);
417 * getForumAdminIDs - return an array of user_id's for those users which are forum admins.
419 * @return array The array of user_id's.
421 function getForumAdminIDs() {
422 $result = db_query_params ('SELECT user_group.user_id FROM user_group, role_setting
423 WHERE role_setting.section_name=$1
424 AND role_setting.ref_id=$2
425 AND role_setting.value::integer > 1
426 AND user_group.role_id = role_setting.role_id',
429 return util_result_column_to_array($result);
433 * getReturnEmailAddress() - return the return email address for notification emails
435 * @return string return email address
437 function getReturnEmailAddress() {
438 global $sys_default_domain, $sys_use_gateways;
440 if($sys_use_gateways) {
441 $address .= $this->getUnixName();
443 $address .= 'noreply';
446 if($sys_use_gateways && isset($GLOBALS['sys_forum_return_domain'])) {
447 $address .= $GLOBALS['sys_forum_return_domain'];
449 $address .= $sys_default_domain;
455 * setMonitor - Add the current user to the list of people monitoring the forum.
457 * @return boolean success.
459 function setMonitor ($u = -1) {
461 if (!session_loggedin()) {
462 $this->setError(_('You can only monitor if you are logged in'));
467 $result = db_query_params ('SELECT * FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
470 if (!$result || db_numrows($result) < 1) {
472 User is not already monitoring thread, so
473 insert a row so monitoring can begin
475 $sql="INSERT INTO forum_monitored_forums (forum_id,user_id)
476 VALUES ('".$this->getID()."','$u')";
478 $result = db_query_params ('INSERT INTO forum_monitored_forums (forum_id,user_id) VALUES ($1,$2)',
479 array ($this->getID(),
483 $this->setError(_('Unable To Add Monitor').' : '.db_error());
492 * stopMonitor - Remove the current user from the list of people monitoring the forum.
494 * @return boolean success.
496 function stopMonitor ($u = -1) {
498 if (!session_loggedin()) {
499 $this->setError(_('You can only monitor if you are logged in'));
504 return db_query_params ('DELETE FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
510 * isMonitoring - See if the current user is in the list of people monitoring the forum.
512 * @return boolean is_monitoring.
514 function isMonitoring() {
515 if (!session_loggedin()) {
518 $result = db_query_params ('SELECT count(*) AS count FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
521 $row_count = db_fetch_array($result);
522 return $result && $row_count['count'] > 0;
526 * savePlace - set a unix time into the database for this user, so future messages can be highlighted.
528 * @return boolean success.
530 function savePlace() {
531 if (!session_loggedin()) {
532 $this->setError(_('You Can Only Save Your Place If You Are Logged In'));
535 $result = db_query_params ('SELECT * FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
539 if (!$result || db_numrows($result) < 1) {
541 User is not already monitoring thread, so
542 insert a row so monitoring can begin
544 $result = db_query_params ('INSERT INTO forum_saved_place (forum_id,user_id,save_date) VALUES ($1,$2,$3)',
545 array ($this->getID(),
550 $this->setError(_('Forum::savePlace()').': '.db_error());
555 $result = db_query_params ('UPDATE forum_saved_place SET save_date=$1 WHERE user_id=$2 AND forum_id=$3',
561 $this->setError('Forum::savePlace() '.db_error());
569 * update - use this function to update an entry in the database.
571 * @param string The name of the forum.
572 * @param string The description of the forum.
573 * @param int if it should be public (0) for private.
574 * @param int if we should allow non-logged-in users to post (0) for mandatory login.
575 * @param string The email address to send all new posts to.
576 * @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
577 * @return boolean success.
579 function update($forum_name,$description,$allow_anonymous,$is_public,$send_all_posts_to='',$moderation_level=0) {
580 if (strlen($forum_name) < 3) {
581 $this->setError(_('Forum Name Must Be At Least 3 Characters'));
584 if (strlen($description) < 10) {
585 $this->setError(_('Forum Description Must Be At Least 10 Characters'));
588 if (!preg_match('/^([_\.0-9a-z-])*$/i',$forum_name)) {
589 $this->setError(_('Illegal Characters in Forum Name'));
592 if ($send_all_posts_to) {
593 $send_all_posts_to = str_replace(';', ',', $send_all_posts_to);
594 $invalid_mails = validate_emails($send_all_posts_to);
595 if (count($invalid_mails) > 0) {
596 $this->setInvalidEmailError();
601 if (!$this->userIsAdmin()) {
602 $this->setPermissionDeniedError();
606 $res = db_query_params ('UPDATE forum_group_list SET
609 send_all_posts_to=$3,
614 AND group_forum_id=$8',
615 array (strtolower($forum_name),
616 htmlspecialchars($description),
621 $this->Group->getID(),
624 if (!$res || db_affected_rows($res) < 1) {
625 $this->setError(_('Error On Update:').': '.db_error());
632 * delete - delete this forum and all its related data.
634 * @param bool I'm Sure.
635 * @param bool I'm REALLY sure.
636 * @return bool true/false;
638 function delete($sure, $really_sure) {
639 if (!$sure || !$really_sure) {
640 $this->setMissingParamsError();
643 if (!$this->userIsAdmin()) {
644 $this->setPermissionDeniedError();
648 db_query_params ('DELETE FROM forum_agg_msg_count WHERE group_forum_id=$1',
649 array ($this->getID())) ;
650 //echo '1'.db_error();
651 db_query_params ('DELETE FROM forum_monitored_forums WHERE forum_id=$1',
652 array ($this->getID())) ;
653 //echo '2'.db_error();
654 db_query_params ('DELETE FROM forum_saved_place WHERE forum_id=$1',
655 array ($this->getID())) ;
656 //echo '3'.db_error();
657 db_query_params ('DELETE FROM forum_attachment WHERE msg_id IN (SELECT msg_id from forum where group_forum_id=$1)',
658 array ($this->getID())) ;
659 db_query_params ('DELETE FROM forum WHERE group_forum_id=$1',
660 array ($this->getID())) ;
661 //echo '4'.db_error();
662 db_query_params ('DELETE FROM forum_group_list WHERE group_forum_id=$1',
663 array ($this->getID())) ;
664 //echo '5'.db_error();
665 //delete forum's role setting
666 db_query_params ('DELETE FROM role_setting WHERE section_name=$1 AND ref_id=$2',
675 USER PERMISSION FUNCTIONS
680 * userCanView - determine if the user can view this forum.
682 * @return boolean user_can_view.
684 function userCanView() {
685 if ($this->isPublic()) {
688 if (!session_loggedin()) {
692 // You must have a role in the project if this forum is not public
694 if ($this->userIsAdmin() || $this->getCurrentUserPerm() >= 0) {
704 * userIsModLvl1 - see if the user goes into the moderated level 1 category
706 * @return boolean user_is_mod_lvl1
708 function userIsModLvl1() {
709 if (!session_loggedin()) {
710 if ( ($this->isPublic() && $this->allowAnonymous()) ) {
711 return true;//public forum, anonymous allowed, user not logged in
714 $perm =& $this->Group->getPermission( session_get_user() );
715 if ( (!$perm->isMember() )) {
716 //the user isn't a member of the project
724 * userIsModLvl2 - see if the user goes into the moderated level 2 category
726 * @return boolean user_is_mod_lvl1
728 function userIsModLvl2() {
729 if ( $this->userIsAdmin() ) {
737 * userCanPost - see if the logged-in user's perms are >= 1 or Group ForumAdmin.
739 * @return boolean user_can_post.
741 function userCanPost() {
742 if (($this->isPublic() && $this->allowAnonymous()) || $this->userIsAdmin()) {
744 } elseif ($this->isPublic() && session_loggedin()) {
747 if (!session_loggedin()) {
750 if ($this->getCurrentUserPerm() >= 1) {
760 * userIsAdmin - see if the logged-in user's perms are >= 2 or Group ForumAdmin.
762 * @return boolean user_is_admin.
764 function userIsAdmin() {
765 if (!session_loggedin()) {
768 $perm =& $this->Group->getPermission( session_get_user() );
770 if (($this->getCurrentUserPerm() >= 2) || ($perm->isForumAdmin())) {
779 * getCurrentUserPerm - get the logged-in user's perms from his role.
781 * @return int perm level for the logged-in user.
783 function getCurrentUserPerm() {
784 if (!session_loggedin()) {
787 if (!isset($this->current_user_perm)) {
788 $res = db_query_params ('SELECT role_setting.value::integer
789 FROM role_setting, user_group
790 WHERE role_setting.ref_id=$1
791 AND user_group.role_id=role_setting.role_id
792 AND user_group.user_id=$2
793 AND role_setting.section_name=$3',
794 array ($this->getID(),
797 $this->current_user_perm=db_result($res,0,0);
799 // Return no access if no access rights defined.
800 if (!$this->current_user_perm)
801 $this->current_user_perm=-1;
803 return $this->current_user_perm;
812 // c-file-style: "bsd"