5 * Copyright 1999-2000, Tim Perdue/Sourceforge
6 * Copyright 2002, Tim Perdue/GForge, LLC
7 * Copyright 2009, Roland Mas
8 * Copyright (C) 2011 Alain Peyrat - Alcatel-Lucent
9 * Copyright 2013, Franck Villaume - TrivialDev
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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', '#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+');
34 * Gets a Forum object from its id
36 * @param int the Forum id
37 * @return object the Forum object
39 function &forum_get_object($forum_id) {
40 $res = db_query_params('SELECT group_id FROM forum_group_list WHERE group_forum_id=$1',
42 if (!$res || db_numrows($res) < 1) {
46 $data = db_fetch_array($res);
47 $Group = group_get_object($data["group_id"]);
48 $f = new Forum($Group, $forum_id);
50 $f->fetchData($forum_id);
55 function forum_get_groupid ($forum_id) {
56 $res = db_query_params('SELECT group_id FROM forum_group_list WHERE group_forum_id=$1',
58 if (!$res || db_numrows($res) < 1) {
61 $arr = db_fetch_array($res);
62 return $arr['group_id'];
65 class Forum extends Error {
68 * Associative array of data from db.
70 * @var array $data_array.
79 var $Group; //group object
82 * An array of 'types' for this forum - nested, flat, ultimate, etc.
84 * @var array view_types.
91 * @param object The Group object to which this forum is associated.
92 * @param int The group_forum_id.
93 * @param array The associative array of data.
94 * @return boolean success.
96 function Forum(&$Group, $group_forum_id=false, $arr=false, $is_news=false) {
98 if (!$Group || !is_object($Group)) {
99 $this->setError(_('Forums: No Valid Group Object'));
102 if ($Group->isError()) {
103 $this->setError('Forums: '.$Group->getErrorMessage());
106 if (!$is_news && $group_forum_id) {
108 // Is this a news posting (or a real forum)?
110 $res = db_query_params('SELECT forum_id FROM news_bytes
112 array($group_forum_id));
113 $is_news = $res && db_numrows($res) >= 1;
115 if (!$is_news && !$Group->usesForum()) {
116 $this->setError(sprintf(_('%s does not use the Forum tool'),
117 $Group->getPublicName()));
120 $this->Group =& $Group;
122 if ($group_forum_id) {
123 if (!$arr || !is_array($arr)) {
124 if (!$this->fetchData($group_forum_id)) {
128 $this->data_array =& $arr;
129 if ($this->data_array['group_id'] != $this->Group->getID()) {
130 $this->setError(_('Group_id in db result does not match Group Object'));
131 $this->data_array = null;
136 // Make sure they can even access this object
139 !forge_check_perm ('forum', $this->getID(), 'read')) {
140 $this->setPermissionDeniedError();
141 $this->data_array = null;
145 $this->view_types[] = 'ultimate';
146 $this->view_types[] = 'flat';
147 $this->view_types[] = 'nested';
148 $this->view_types[] = 'threaded';
149 $this->is_news = $is_news;
154 * create - use this function to create a new entry in the database.
156 * @param string The name of the forum.
157 * @param string The description of the forum.
158 * @param int Pass (1) if it should be public (0) for private.
159 * @param string The email address to send all new posts to.
160 * @param int Pass (1) if a welcome message should be created (0) for no welcome message.
161 * @param int Pass (1) if we should allow non-logged-in users to post (0) for mandatory login.
162 * @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
163 * @return boolean success.
165 function create($forum_name,$description,$is_public=1,$send_all_posts_to='',$create_default_message=1,$allow_anonymous=1,$moderation_level=0) {
166 if (!$this->is_news && strlen($forum_name) < 3) {
167 $this->setError(_('Forum Name Must Be At Least 3 Characters'));
170 if (!$this->is_news && strlen($description) < 10) {
171 $this->setError(_('Forum Description Must Be At Least 10 Characters'));
174 if (!preg_match('/^([_\.0-9a-z-])*$/i',$forum_name)) {
175 $this->setError(_('Illegal Characters in Forum Name'));
178 if ($send_all_posts_to) {
179 $send_all_posts_to = str_replace(';', ',', $send_all_posts_to);
180 $invalid_mails = validate_emails($send_all_posts_to);
181 if (count($invalid_mails) > 0) {
182 $this->setInvalidEmailError($send_all_posts_to);
187 $project_name = $this->Group->getUnixName();
188 $result_list_samename = db_query_params('SELECT 1 FROM mail_group_list WHERE list_name=$1 AND group_id=$2',
190 array($project_name.'-'.strtolower($forum_name),
191 $this->Group->getID()));
193 if (db_numrows($result_list_samename) > 0){
194 $this->setError(_('Mailing List Exists with same name'));
199 // This is a hack to allow non-site-wide-admins to post
200 // news. The news/submit.php checks for proper permissions.
201 // This needs to be revisited.
203 if ($this->Group->getID() == forge_get_config('news_group')) {
204 // Future check will be added.
207 // Current permissions check.
209 if (!forge_check_perm ('forum_admin', $this->Group->getID())) {
210 $this->setPermissionDeniedError();
216 $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)',
217 array($this->Group->getID(),
218 strtolower($forum_name),
220 htmlspecialchars($description),
225 $this->setError(_('Error Adding Forum:').' '.db_error());
229 $this->group_forum_id=db_insertid($result,'forum_group_list','group_forum_id');
230 $this->fetchData($this->group_forum_id);
232 if ($create_default_message) {
233 $fm=new ForumMessage($this);
234 // Use the system side default language
235 setup_gettext_from_sys_lang();
236 $string = sprintf(_('Welcome to %1$s'), $forum_name);
237 // and switch back to the user preference
238 setup_gettext_from_context();
239 if (!$fm->create($string, $string)) {
240 $this->setError($fm->getErrorMessage());
245 $this->Group->normalizeAllRoles () ;
251 * fetchData - re-fetch the data for this forum from the database.
253 * @param int The forum_id.
254 * @return boolean success.
256 function fetchData($group_forum_id) {
257 $res=db_query_params('SELECT * FROM forum_group_list_vw WHERE group_forum_id=$1 AND group_id=$2',
258 array($group_forum_id, $this->Group->getID()));
259 if (!$res || db_numrows($res) < 1) {
260 $this->setError(_('Invalid forum group identifier'));
263 $this->data_array = db_fetch_array($res);
264 db_free_result($res);
269 * getGroup - get the Group object this ArtifactType is associated with.
271 * @return object The Group object.
273 function &getGroup() {
278 * getID - The id of this forum.
280 * @return int The group_forum_id #.
283 return $this->data_array['group_forum_id'];
287 * getNextThreadID - The next thread_id for a new top in this forum.
289 * @return int The next thread_id #.
291 function getNextThreadID() {
292 $result = db_query_params('SELECT nextval($1)',
293 array('forum_thread_seq'));
294 if (!$result || db_numrows($result) < 1) {
298 return db_result($result, 0, 0);
302 * getUnixName - returns the name used by email gateway
304 * @return string unix name
306 function getUnixName() {
307 return $this->Group->getUnixName().'-'.$this->getName();
311 * getSavedDate - The unix time when the person last hit "save my place".
313 * @return int The unix time.
315 function getSavedDate() {
316 if (isset($this->save_date)) {
317 return $this->save_date;
319 if (session_loggedin()) {
320 $result = db_query_params('SELECT save_date FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
323 if ($result && db_numrows($result) > 0) {
324 $this->save_date=db_result($result, 0, 'save_date');
325 return $this->save_date;
327 //highlight new messages from the past week only
328 $this->save_date=(time()-604800);
329 return $this->save_date;
332 //highlight new messages from the past week only
333 $this->save_date=(time()-604800);
334 return $this->save_date;
340 * allowAnonymous - does this forum allow non-logged in users to post.
342 * @return boolean allow_anonymous.
344 function allowAnonymous() {
345 return $this->data_array['allow_anonymous'];
349 * isPublic - Is this forum open to the general public.
351 * @return boolean is_public.
353 function isPublic() {
354 return $this->data_array['is_public'];
358 * getName - get the name of this forum.
360 * @return string The name of this forum.
363 return $this->data_array['forum_name'];
367 * getSendAllPostsTo - an optional email address to send all forum posts to.
369 * @return string The email address.
371 function getSendAllPostsTo() {
372 return $this->data_array['send_all_posts_to'];
376 * getDescription - the description of this forum.
378 * @return string The description.
380 function getDescription() {
381 return $this->data_array['description'];
385 * getModerationLevel - the moderation level of the forum
387 * @return int The moderation level.
389 function getModerationLevel() {
390 return $this->data_array['moderation_level'];
394 * getMessageCount - the total number of messages in this forum.
396 * @return int The count.
398 function getMessageCount() {
399 return $this->data_array['total'];
403 * getThreadCount - the total number of threads in this forum.
405 * @return int The count.
407 function getThreadCount() {
408 return $this->data_array['threads'];
412 * getMostRecentDate - the most recent date of a post to this board.
414 * @return int The most recent date.
416 function getMostRecentDate() {
417 return $this->data_array['recent'];
421 * getMonitoringIDs - return an array of user_id's for those monitoring this forum.
423 * @return array The array of user_id's.
425 function getMonitoringIDs() {
426 $result = db_query_params('SELECT user_id FROM forum_monitored_forums WHERE forum_id=$1',
427 array($this->getID()));
428 return util_result_column_to_array($result);
432 * getReturnEmailAddress() - return the return email address for notification emails
434 * @return string return email address
436 function getReturnEmailAddress() {
438 if(forge_get_config('use_gateways')) {
439 $address = $this->getUnixName();
441 $address = 'noreply';
444 if(forge_get_config('use_gateways') && forge_get_config('forum_return_domain')) {
445 $address .= forge_get_config('forum_return_domain');
447 $address .= forge_get_config('web_host');
453 * setMonitor - Add the current user to the list of people monitoring the forum.
455 * @param int user id of the user which will be set to monitor this forum. Defaults to 0, meaning the current logged in user will be used.
456 * @return boolean success.
458 function setMonitor($u = -1) {
460 if (!session_loggedin()) {
461 $this->setError(_('You can only monitor if you are logged in'));
466 $result = db_query_params('SELECT * FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
469 if (!$result || db_numrows($result) < 1) {
471 User is not already monitoring thread, so
472 insert a row so monitoring can begin
474 $result = db_query_params('INSERT INTO forum_monitored_forums (forum_id,user_id) VALUES ($1,$2)',
475 array($this->getID(),
479 $this->setError(_('Unable To Add Monitor').' : '.db_error());
488 * stopMonitor - Remove the current user from the list of people monitoring the forum.
490 * @return boolean success.
492 function stopMonitor($u = -1) {
494 if (!session_loggedin()) {
495 $this->setError(_('You can only monitor if you are logged in'));
500 return db_query_params('DELETE FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
506 * isMonitoring - See if the current user is in the list of people monitoring the forum.
508 * @return boolean is_monitoring.
510 function isMonitoring() {
511 if (!session_loggedin()) {
514 $result = db_query_params('SELECT count(*) AS count FROM forum_monitored_forums WHERE user_id=$1 AND forum_id=$2',
517 $row_count = db_fetch_array($result);
518 return $result && $row_count['count'] > 0;
522 * savePlace - set a unix time into the database for this user, so future messages can be highlighted.
524 * @return boolean success.
526 function savePlace() {
527 if (!session_loggedin()) {
528 $this->setError(_('You Can Only Save Your Place If You Are Logged In'));
531 $result = db_query_params('SELECT * FROM forum_saved_place WHERE user_id=$1 AND forum_id=$2',
535 if (!$result || db_numrows($result) < 1) {
537 User is not already monitoring thread, so
538 insert a row so monitoring can begin
540 $result = db_query_params('INSERT INTO forum_saved_place (forum_id,user_id,save_date) VALUES ($1,$2,$3)',
541 array($this->getID(),
546 $this->setError(_('Forum::savePlace()').': '.db_error());
551 $result = db_query_params('UPDATE forum_saved_place SET save_date=$1 WHERE user_id=$2 AND forum_id=$3',
557 $this->setError('Forum::savePlace() '.db_error());
565 * update - use this function to update an entry in the database.
567 * @param string The name of the forum.
568 * @param string The description of the forum.
569 * @param int if it should be public (0) for private.
570 * @param int if we should allow non-logged-in users to post (0) for mandatory login.
571 * @param string The email address to send all new posts to.
572 * @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
573 * @return boolean success.
575 function update($forum_name, $description, $allow_anonymous, $is_public, $send_all_posts_to = '', $moderation_level = 0) {
576 if (strlen($forum_name) < 3) {
577 $this->setError(_('Forum Name Must Be At Least 3 Characters'));
580 if (strlen($description) < 10) {
581 $this->setError(_('Forum Description Must Be At Least 10 Characters'));
584 if (!preg_match('/^([_\.0-9a-z-])*$/i',$forum_name)) {
585 $this->setError(_('Illegal Characters in Forum Name'));
588 if ($send_all_posts_to) {
589 $send_all_posts_to = str_replace(';', ',', $send_all_posts_to);
590 $invalid_mails = validate_emails($send_all_posts_to);
591 if (count($invalid_mails) > 0) {
592 $this->setInvalidEmailError($send_all_posts_to);
597 if (!forge_check_perm('forum_admin', $this->Group->getID())) {
598 $this->setPermissionDeniedError();
602 $project_name = $this->Group->getUnixName();
603 $result_list_samename = db_query_params('SELECT 1 FROM mail_group_list WHERE list_name=$1 AND group_id=$2',
605 array($project_name.'-'.strtolower($forum_name),
606 $this->Group->getID()));
608 if (db_numrows($result_list_samename) > 0){
609 $this->setError(_('Mailing List Exists with same name'));
613 $res = db_query_params('UPDATE forum_group_list SET
616 send_all_posts_to=$3,
621 AND group_forum_id=$8',
622 array(strtolower($forum_name),
623 htmlspecialchars($description),
628 $this->Group->getID(),
631 if (!$res || db_affected_rows($res) < 1) {
632 $this->setError(_('Error On Update:').': '.db_error());
639 * delete - delete this forum and all its related data.
641 * @param bool I'm Sure.
642 * @param bool I'm REALLY sure.
643 * @return bool true/false;
645 function delete($sure, $really_sure) {
646 if (!$sure || !$really_sure) {
647 $this->setMissingParamsError(_('Please tick all checkboxes.'));
650 if (!forge_check_perm ('forum_admin', $this->Group->getID())) {
651 $this->setPermissionDeniedError();
655 $result = db_query_params('DELETE FROM forum_agg_msg_count WHERE group_forum_id=$1',
656 array($this->getID()));
658 $this->setError(_('Error Deleting Forum:').' '.db_error());
663 $result = db_query_params('DELETE FROM forum_monitored_forums WHERE forum_id=$1',
664 array($this->getID()));
666 $this->setError(_('Error Deleting Forum:').' '.db_error());
671 $result = db_query_params('DELETE FROM forum_saved_place WHERE forum_id=$1',
672 array($this->getID()));
674 $this->setError(_('Error Deleting Forum:').' '.db_error());
679 $result = db_query_params('DELETE FROM forum_attachment WHERE msg_id IN (SELECT msg_id from forum where group_forum_id=$1)',
680 array($this->getID()));
682 $this->setError(_('Error Deleting Forum:').' '.db_error());
687 $result = db_query_params('DELETE FROM forum WHERE group_forum_id=$1',
688 array($this->getID()));
690 $this->setError(_('Error Deleting Forum:').' '.db_error());
695 $result = db_query_params('DELETE FROM forum_group_list WHERE group_forum_id=$1',
696 array($this->getID()));
698 $this->setError(_('Error Deleting Forum:').' '.db_error());
705 $this->Group->normalizeAllRoles();
714 // c-file-style: "bsd"