Commit 415c8143 authored by Cecilia Vela Gurovic's avatar Cecilia Vela Gurovic

Bug 1803912: Moderate forum posts and replies

behatnotneeded

Change-Id: Ic40f573044b16a96272413d6b7742d369982a8a2
parent ca308ba5
......@@ -75,7 +75,7 @@ class PluginBlocktypeRecentForumPosts extends MaharaCoreBlocktype {
$foruminfo = get_records_sql_array('
SELECT
p.id, p.subject, p.body, p.poster, p.topic, t.forum, pt.subject AS topicname,
p.id, p.subject, p.body, p.poster, p.topic, pt.approved, t.forum, pt.subject AS topicname,
u.firstname, u.lastname, u.username, u.preferredname, u.email, u.profileicon, u.admin, u.staff, u.deleted, u.urlid
FROM
{interaction_forum_post} p
......@@ -88,6 +88,7 @@ class PluginBlocktypeRecentForumPosts extends MaharaCoreBlocktype {
AND i.deleted = 0
AND t.deleted = 0
AND p.deleted = 0
AND pt.approved = 1
ORDER BY
p.ctime DESC',
array($group->id), 0, $limit
......
......@@ -41,6 +41,7 @@
<FIELD NAME="deleted" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" />
<FIELD NAME="sent" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" />
<FIELD NAME="path" TYPE="char" LENGTH="2048" NOTNULL="false" />
<FIELD NAME="approved" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
......
......@@ -160,5 +160,14 @@ function xmldb_interaction_forum_upgrade($oldversion=0) {
}
}
if ($oldversion < 2018121900) {
$table = new XMLDBTable('interaction_forum_post');
$field = new XMLDBField('approved');
$field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
if (!field_exists($table, $field)) {
add_field($table, $field);
}
}
return true;
}
......@@ -52,7 +52,7 @@ if (!$parentid) {
}
$parent = get_record_sql(
'SELECT p.subject, p.body, p.topic, p.parent, p.poster, p.deleted, ' . db_format_tsfield('p.ctime', 'ctime') . ', m.user AS moderator, t.id AS topic, t.forum, t.closed AS topicclosed, p2.subject AS topicsubject, f.group AS "group", f.title AS forumtitle, g.name AS groupname, COUNT(p3.id)
'SELECT p.subject, p.body, p.topic, p.parent, p.poster, p.approved, p.deleted, ' . db_format_tsfield('p.ctime', 'ctime') . ', m.user AS moderator, t.id AS topic, t.forum, t.closed AS topicclosed, p2.subject AS topicsubject, f.group AS "group", f.title AS forumtitle, g.name AS groupname, COUNT(p3.id)
FROM {interaction_forum_post} p
INNER JOIN {interaction_forum_topic} t ON (p.topic = t.id AND t.deleted != 1)
INNER JOIN {interaction_forum_post} p2 ON (p2.topic = t.id AND p2.parent IS NULL)
......@@ -67,7 +67,7 @@ $parent = get_record_sql(
INNER JOIN {interaction_forum_topic} t2 ON (t2.deleted != 1 AND p3.topic = t2.id)
INNER JOIN {interaction_instance} f2 ON (t2.forum = f2.id AND f2.deleted != 1 AND f2.group = f.group)
WHERE p.id = ?
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15',
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16',
array(0, $parentid)
);
......@@ -240,6 +240,24 @@ function get_groupid_from_postid($postid) {
return $groupid;
}
function reply_needs_approval($topicid) {
$needsapproval = get_field_sql("SELECT c.value FROM {interaction_forum_instance_config} c
INNER JOIN {interaction_forum_topic} t
ON t.forum = c.forum WHERE field = 'moderateposts' AND t.id = ?", array($topicid));
return ($needsapproval == 'replies' || $needsapproval == 'postsandreplies');
}
function is_logged_user_moderator($topicid) {
global $USER;
return (count_records_sql(
'SELECT COUNT(*)
FROM {interaction_forum_moderator} m
INNER JOIN {interaction_instance} f ON (m.forum = f.id AND f.deleted != 1)
INNER JOIN {interaction_forum_topic} t ON (t.forum = f.id)
WHERE t.id = ? AND m.user = ?',
array($topicid, $USER->get('id'))) != 0 );
}
function editpost_submit(Pieform $form, $values) {
global $USER, $SESSION, $parent;
require_once('embeddedimage.php');
......@@ -318,6 +336,11 @@ function addpost_submit(Pieform $form, $values) {
'body' => $values['body'],
'ctime' => db_format_timestamp(time())
);
if (reply_needs_approval($values['topic']) && !is_logged_user_moderator($values['topic']) && !$USER->get('admin')) {
$post->approved = 0;
}
$sendnow = isset($values['sendnow']) && $values['sendnow'] ? 1 : 0;
// See if the same content has been submitted in the last 5 seconds. If so, don't add this post.
$oldpost = get_record_select('interaction_forum_post', 'topic = ? AND poster = ? AND parent = ? AND subject = ? AND body = ? AND ctime > ?',
......@@ -331,6 +354,20 @@ function addpost_submit(Pieform $form, $values) {
$postrec->path = get_field('interaction_forum_post', 'path', 'id', $parentid) . '/' . sprintf('%010d', $postrec->id);
update_record('interaction_forum_post', $postrec);
if (isset($post->approved) && $post->approved == 0) {
$forumid = get_field('interaction_forum_topic', 'forum', 'id', $values['topic']);
// Trigger activity.
$data = new stdClass();
$data->topicid = $values['topic'];
$data->forumid = $forumid;
$data->postbody = $values['body'];
$data->poster = $USER->get('id');
$data->postedtime = time();
$data->reason = '';
$data->event = POST_NEEDS_APPROVAL;
activity_occurred('postmoderation', $data, 'interaction', 'forum');
}
// Rewrite the post id into links in the body
$groupid = get_groupid_from_postid($postid);
$newbody = EmbeddedImage::prepare_embedded_images($post->body, 'post', $postid, $groupid);
......
......@@ -241,8 +241,16 @@ function edittopic_validate(Pieform $form, $values) {
}
}
function post_needs_approval($topicid) {
$needsapproval = get_field_sql("SELECT c.value FROM {interaction_forum_instance_config} c
INNER JOIN {interaction_forum_topic} t
ON t.forum = c.forum WHERE field = 'moderateposts' AND t.id = ?", array($topicid));
return ($needsapproval == 'posts' || $needsapproval == 'postsandreplies');
}
function addtopic_submit(Pieform $form, $values) {
global $USER, $SESSION;
global $USER, $SESSION, $moderator;
$forumid = param_integer('forum');
$groupid = get_field('interaction_instance', '"group"', 'id', $forumid);
......@@ -263,6 +271,11 @@ function addtopic_submit(Pieform $form, $values) {
'body' => $values['body'],
'ctime' => db_format_timestamp(time())
);
if (post_needs_approval($topicid) && !$moderator && ! $USER->get('admin')) {
$post->approved = 0;
}
$postid = insert_record('interaction_forum_post', $post, 'id', true);
set_field('interaction_forum_post', 'path', sprintf('%010d', $postid), 'id', $postid);
// Rewrite the post id into links in the body
......@@ -313,6 +326,20 @@ function addtopic_submit(Pieform $form, $values) {
PluginInteractionForum::interaction_forum_new_post(array($postid));
}
if (isset($post->approved) && $post->approved == 0) {
$forumid = get_field('interaction_forum_topic', 'forum', 'id', $topicid);
// Trigger activity.
$data = new stdClass();
$data->topicid = $topicid;
$data->forumid = $forumid;
$data->postbody = $values['body'];
$data->poster = $USER->get('id');
$data->postedtime = time();
$data->reason = '';
$data->event = POST_NEEDS_APPROVAL;
activity_occurred('postmoderation', $data, 'interaction', 'forum');
}
$result = array(
'error' => false,
'message' => get_string('addtopicsuccess', 'interaction.forum'),
......
......@@ -19,10 +19,12 @@ $string['allowunsubscribe'] = 'Allow users to unsubscribe';
$string['allowunsubscribedescription'] = 'Choose whether users are allowed to unsubscribe from forums and topics';
$string['autosubscribeusers'] = 'Automatically subscribe users';
$string['autosubscribeusersdescription'] = 'Choose whether group users will automatically be subscribed to this forum';
$string['awaitingapproval'] = 'Awaiting approval';
$string['Body'] = 'Message';
$string['cantaddposttoforum'] = 'You are not allowed to post in this forum';
$string['cantaddposttotopic'] = 'You are not allowed to post in this topic';
$string['cantaddtopic'] = 'You are not allowed to add topics to this forum';
$string['cantapproveposts'] = 'You are not allowed approve posts on this forum';
$string['cantdeletepost'] = 'You are not allowed to delete posts in this forum';
$string['cantdeletethispost'] = 'You are not allowed to delete this post';
$string['cantdeletetopic'] = 'You are not allowed to delete topics in this forum';
......@@ -139,6 +141,9 @@ $string['noforumpostsyet'] = 'There are no posts in this group yet';
$string['noforums'] = 'There are no forums in this group';
$string['notopics'] = 'There are no topics in this forum';
$string['notifyadministrator'] = 'Notify administrator';
$string['notifyauthor'] = 'Notify author';
$string['rejectpost'] = 'Reject post';
$string['reasonempty'] = ' Reason field cannot be empty';
$string['objectionablepostdeletedsubject'] = 'Objectionable post in forum topic "%s" was deleted by %s.';
$string['objectionablepostdeletedbody'] = '%s has looked at post by %s previously reported as objectionable and deleted it.
......@@ -154,7 +159,9 @@ $string['Order'] = 'Order';
$string['orderdescription'] = 'Choose at which position this forum shall appear in the list of forums';
$string['Post'] = 'Post';
$string['postaftertimeout'] = 'You have submitted your change after the timeout of %s minutes. Your change has not been applied.';
$string['postapprovesuccessful'] = 'Post approved';
$string['postbyuserwasdeleted'] = 'A post by %s was deleted';
$string['postnotapprovederror'] = 'There was an error while trying to mark the post as approved';
$string['postsbyuserweredeleted'] = '%s posts by %s were deleted';
$string['postdelay'] = 'Post delay';
$string['postdelaydescription'] = 'The minimum time (in minutes) that must pass before a new post can be mailed out to forum subscribers. The author of a post may make edits during this time.';
......@@ -207,6 +214,7 @@ $string['topicunsubscribesuccess'] = 'Topics unsubscribed successfully';
$string['topicupdatefailed'] = 'Topics update failed';
$string['typenewpost'] = 'New forum post';
$string['typereportpost'] = 'Objectionable content in forum';
$string['typepostmoderation'] = 'Forum moderation';
$string['Unsticky'] = 'Unsticky';
$string['Unsubscribe'] = 'Unsubscribe';
$string['unsubscribefromforum'] = 'Unsubscribe from forum';
......@@ -237,6 +245,10 @@ $string['maxindentdescription'] = 'Set the maximum indentation level for a topic
$string['closetopics'] = 'Close new topics';
$string['closetopicsdescription1'] = 'Close all new topics by default. Only moderators and group administrators can reply to closed topics.';
$string['approvalofposts'] = 'Approval of posts';
$string['moderatenewposts'] = 'Moderate new posts';
$string['moderatenewpostsdescription'] = 'New posts need to be approved by a group moderator or administrator.';
$string['activetopicsdescription'] = 'Recently updated topics in your groups.';
$string['timeleftnotice1'] = 'You have <span class="num">%s</span> minutes left to finish editing.';
......@@ -277,3 +289,72 @@ To see the post, follow this link:
%s
To see the reporter\'s profile, follow this link:
%s';
$string['postsandreplies'] = 'Posts and replies';
$string['postneedapprovalsubject'] = 'New post needs moderation in forum "%s"';
$string['postneedapprovalbody'] = '%s has posted in forum "%s" and is awaiting for moderation.
The post content is:
%s';
$string['postneedapprovalhtml'] = '<div style="padding: 0.5em 0; border-bottom: 1px solid #999;">A new post by "%s" in forum "%s" needs moderation
<div style="padding: 0.5em 0; border-bottom: 1px solid #999;">The post content is:
<br>%s</div>
<div style="margin: 1em 0;">%s</div>
<div style="font-size: smaller; border-top: 1px solid #999;">
<p>Posted by: <a href="%s">%s</a></p>
</div>';
$string['postneedapprovaltext'] = 'A new post by "%s" in forum "%s" needs moderation
%s
------------------------------------------------------------------------
The post content is:
%s
------------------------------------------------------------------------
To go to the forum post follow this link:
%s';
$string['rejectedpostsubject'] = 'Forum post rejected on forum "%s"';
$string['rejectedpostbody'] = '%s has looked at post by %s waiting for approval and deleted it.
Rejection reason:
%s
The post content was:
%s';
$string['rejectedposthtml'] = '<div style="padding: 0.5em 0; border-bottom: 1px solid #999;">Forum post rejected on forum "%s"
<br>%s</div>
<div style="margin: 1em 0;">%s</div>
<div style="padding: 0.5em 0; border-bottom: 1px solid #999;">The rejected post content is:
<br>%s</div>
<div style="margin: 1em 0;">%s</div>
<div style="font-size: smaller; border-top: 1px solid #999;">
<p>Rejection relates to: <a href="%s">%s</a></p>
<p>Rejected by: <a href="%s">%s</a></p>
</div>';
$string['rejectedposttext'] = 'Forum post rejected on forum "%s" by "%s"
%s
------------------------------------------------------------------------
%s
------------------------------------------------------------------------
The rejected post content is:
%s
------------------------------------------------------------------------
%s
-----------------------------------------------------------------------
The post has been deleted, to go to the forum follow this link:
%s
To see the reporter\'s profile, follow this link:
%s';
$string['rejectpostsuccess'] = 'The post has been removed';
$string['replies'] = 'Replies';
......@@ -16,6 +16,8 @@ define('REPORT_OBJECTIONABLE', 1);
define('MAKE_NOT_OBJECTIONABLE', 2);
define('DELETE_OBJECTIONABLE_POST', 3);
define('DELETE_OBJECTIONABLE_TOPIC', 4);
define('POST_NEEDS_APPROVAL', 5);
define('POST_REJECTED', 6);
class PluginInteractionForum extends PluginInteraction {
......@@ -28,6 +30,7 @@ class PluginInteractionForum extends PluginInteraction {
$createtopicusers = isset($instanceconfig['createtopicusers']) ? $instanceconfig['createtopicusers']->value : null;
$closetopics = !empty($instanceconfig['closetopics']);
$allowunsubscribe = isset($instanceconfig['allowunsubscribe']) ? $instanceconfig['allowunsubscribe']->value : null;
$moderateposts = (empty($instanceconfig['moderateposts']) ? 'none' : $instanceconfig['moderateposts']->value);
$indentmode = isset($instanceconfig['indentmode']) ? $instanceconfig['indentmode']->value : null;
$maxindent = isset($instanceconfig['maxindent']) ? $instanceconfig['maxindent']->value : null;
......@@ -114,7 +117,16 @@ class PluginInteractionForum extends PluginInteraction {
'description' => get_string('closetopicsdescription1', 'interaction.forum'),
'defaultvalue' => !empty($closetopics),
);
$fieldsetelements['moderateposts'] = array(
'type' => 'select',
'title' => get_string('moderatenewposts', 'interaction.forum'),
'options' => array('none' => get_string('none'),
'posts' => get_string('posts'),
'replies' => get_string('replies', 'interaction.forum'),
'postsandreplies' => get_string('postsandreplies', 'interaction.forum')),
'description' => get_string('moderatenewpostsdescription', 'interaction.forum'),
'defaultvalue' => empty($moderateposts) ? 'none' : $moderateposts,
);
$form = array(
'indentmode' => array(
......@@ -330,6 +342,20 @@ EOF;
}
}
// Moderate new posts
delete_records_sql(
"DELETE FROM {interaction_forum_instance_config}
WHERE field = 'moderateposts' AND forum = ?",
array($instance->get('id'))
);
if (!empty($values['moderateposts'])) {
insert_record('interaction_forum_instance_config', (object)array(
'forum' => $instance->get('id'),
'field' => 'moderateposts',
'value' => $values['moderateposts'],
));
}
//Indent mode
delete_records_sql(
"DELETE FROM {interaction_forum_instance_config}
......@@ -387,6 +413,13 @@ EOF;
'allownonemethod' => 1,
'defaultmethod' => 'email',
),
(object)array(
'name' => 'postmoderation',
'admin' => 0,
'delay' => 0,
'allownonemethod' => 1,
'defaultmethod' => 'email',
),
);
}
......@@ -568,9 +601,9 @@ EOF;
$postswhere = 'ctime < ?';
$delay = null;
}
$posts = get_column_sql('SELECT id FROM {interaction_forum_post} WHERE sent = 0 AND deleted = 0 AND ' . $postswhere, $values);
$posts = get_column_sql('SELECT id FROM {interaction_forum_post} WHERE sent = 0 AND deleted = 0 AND approved = 1 AND ' . $postswhere, $values);
if ($posts) {
set_field_select('interaction_forum_post', 'sent', 1, 'deleted = 0 AND sent = 0 AND ' . $postswhere, $values);
set_field_select('interaction_forum_post', 'sent', 1, 'deleted = 0 AND sent = 0 AND approved = 1 AND ' . $postswhere, $values);
foreach ($posts as $postid) {
activity_occurred('newpost', array('postid' => $postid), 'interaction', 'forum', $delay);
}
......@@ -1339,6 +1372,157 @@ class ActivityTypeInteractionForumReportPost extends ActivityTypePlugin {
}
}
class ActivityTypeInteractionForumPostmoderation extends ActivityTypePlugin {
protected $topicid;
protected $forumid;
protected $forumtitle;
protected $postbody;
protected $postedtime;
protected $poster;
protected $reason;
protected $event;
protected $url;
protected $temp;
public function __construct($data, $cron = false) {
parent::__construct($data, $cron);
global $USER;
$this->forumtitle = get_field('interaction_instance','title', 'id', $this->forumid);
$this->url = 'interaction/forum/view.php?id=' . $this->forumid;
if ($this->event === POST_REJECTED) {
// only notify the author of the post
$this->users = activity_get_users($this->get_id(), array($this->poster));
$this->temp = new stdClass();
$this->temp->rejecter = $USER->get('id');
$this->temp->rejectedtime = time();
$this->strings = (object) array(
'subject' => (object) array(
'key' => 'rejectedpostsubject',
'section' => 'interaction.forum',
'args' => array($this->forumtitle),
),
'message' => (object) array(
'key' => 'rejectedpostbody',
'section' => 'interaction.forum',
'args' => array(display_default_name($this->temp->rejecter),
display_default_name($this->poster),
$this->reason,
trim(html2text($this->postbody))
),
),
);
}
else if ($this->event === POST_NEEDS_APPROVAL) {
$groupid = get_field('interaction_instance', 'group', 'id', $this->forumid);
// Get forum moderators and admins.
$forumadminsandmoderators = activity_get_users(
$this->get_id(),
array_merge(get_forum_moderators($this->forumid),
group_get_admin_ids($groupid)));
// Populate users to notify list and get rid of duplicates.
foreach ($forumadminsandmoderators as $user) {
if (!isset($this->users[$user->id])) {
$this->users[$user->id] = $user;
}
}
$this->strings = (object) array(
'subject' => (object) array(
'key' => 'postneedapprovalsubject',
'section' => 'interaction.forum',
'args' => array($this->forumtitle),
),
'message' => (object) array(
'key' => 'postneedapprovalbody',
'section' => 'interaction.forum',
'args' => array(display_default_name($this->poster),
$this->forumtitle,
trim(html2text($this->postbody))
),
),
);
}
else {
throw new SystemException();
}
}
public function get_emailmessage($user) {
if ($this->event === POST_REJECTED) {
$rejecterurl = profile_url($this->temp->rejecter);
$rejectedtime = strftime(get_string_from_language($user->lang, 'strftimedaydatetime'), $this->temp->rejectedtime);
$postedtime = strftime(get_string_from_language($user->lang, 'strftimedaydatetime'), $this->postedtime);
$return = get_string_from_language(
$user->lang, 'rejectedposttext', 'interaction.forum',
$this->forumtitle, display_default_name($this->temp->rejecter), $rejectedtime,
$this->reason, clean_html($this->postbody),
$postedtime, get_config('wwwroot') . $this->url, $rejecterurl
);
}
else if ($this->event === POST_NEEDS_APPROVAL) {
$postedtime = strftime(get_string_from_language($user->lang, 'strftimedaydatetime'), $this->postedtime);
$return = get_string_from_language(
$user->lang, 'postneedapprovaltext', 'interaction.forum',
display_default_name($this->poster), $this->forumtitle, $postedtime,
clean_html($this->postbody), get_config('wwwroot') . $this->url
);
}
else {
throw new SystemException();
}
return $return;
}
public function get_htmlmessage($user) {
if ($this->event === POST_REJECTED) {
$rejectername = hsc(display_default_name($this->temp->rejecter));
$rejecterurl = profile_url($this->temp->rejecter);
$rejectedtime = strftime(get_string_from_language($user->lang, 'strftimedaydatetime'), $this->temp->rejectedtime);
$postedtime = strftime(get_string_from_language($user->lang, 'strftimedaydatetime'), $this->postedtime);
$return = get_string_from_language(
$user->lang, 'rejectedposthtml', 'interaction.forum',
hsc($this->forumtitle), $rejectername, $rejectedtime,
$this->reason, clean_html($this->postbody),
$postedtime, get_config('wwwroot') . $this->url, $rejecterurl, $rejectername
);
}
else if ($this->event === POST_NEEDS_APPROVAL) {
$postedtime = strftime(get_string_from_language($user->lang, 'strftimedaydatetime'), $this->postedtime);
$return = get_string_from_language(
$user->lang, 'postneedapprovalhtml', 'interaction.forum',
display_default_name($this->poster), hsc($this->forumtitle),
clean_html($this->postbody), $postedtime,
get_config('wwwroot') . $this->url, display_default_name($this->poster)
);
}
else {
throw new SystemException();
}
return $return;
}
public function get_plugintype(){
return 'interaction';
}
public function get_pluginname(){
return 'forum';
}
public function get_required_parameters() {
return array('topicid', 'forumid', 'postbody',
'postedtime', 'poster', 'reason', 'event');
}
}
// constants for forum membership types
define('INTERACTION_FORUM_ADMIN', 1);
define('INTERACTION_FORUM_MOD', 2);
......
<?php
/**
*
* @package mahara
* @subpackage interaction-forum
* @author Lancaster University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('MENUITEM', 'engage/mygroups');
define('MENUITEM_SUBPAGE', 'forums');
define('SECTION_PLUGINTYPE', 'interaction');
define('SECTION_PLUGINNAME', 'forum');
define('SECTION_PAGE', 'reportpost');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
safe_require('interaction' ,'forum');
require_once('group.php');
require_once(get_config('docroot') . 'interaction/lib.php');
define('SUBSECTIONHEADING', get_string('nameplural', 'interaction.forum'));
$postid = param_integer('id');
$post = get_record_sql(
'SELECT p.subject, p.body, p.topic, p.parent, p.poster, ' . db_format_tsfield('p.ctime', 'ctime') . ',
m.user AS moderator, t.forum, p2.subject AS topicsubject, f.group, f.title AS forumtitle, g.name AS groupname
FROM {interaction_forum_post} p
INNER JOIN {interaction_forum_topic} t ON (p.topic = t.id AND t.deleted != 1)
INNER JOIN {interaction_forum_post} p2 ON (p2.topic = t.id AND p2.parent IS NULL)
INNER JOIN {interaction_instance} f ON (t.forum = f.id AND f.deleted != 1)
INNER JOIN {group} g ON (g.id = f.group AND g.deleted = ?)
LEFT JOIN (
SELECT m.forum, m.user
FROM {interaction_forum_moderator} m
INNER JOIN {usr} u ON (m.user = u.id AND u.deleted = 0)
) m ON (m.forum = f.id AND m.user = p.poster)
WHERE p.id = ?
AND p.deleted != 1',
array(0, $postid)
);
if (!$post) {
throw new NotFoundException(get_string('cantfindpost', 'interaction.forum', $postid));
}
$attachments = array();
// Check if the post has any attachments
if ($postattachments = get_records_sql_array("
SELECT a.*, aff.size, aff.fileid, pa.post
FROM {artefact} a
JOIN {interaction_forum_post_attachment} pa ON pa.attachment = a.id
LEFT JOIN {artefact_file_files} aff ON aff.artefact = a.id
WHERE pa.post = ?", array($postid))) {
safe_require('artefact', 'file');
foreach ($postattachments as $file) {
$file->icon = call_static_method(generate_artefact_class_name($file->artefacttype), 'get_icon', array('id' => $file->id, 'post' => $postid));
}
}
$post->attachments = $postattachments;
$membership = user_can_access_forum((int)$post->forum);
$moderator = (bool)($membership & INTERACTION_FORUM_MOD);
if (!$membership && !get_field('group', 'public', 'id', $post->group)) {
throw new GroupAccessDeniedException(get_string('cantviewtopic', 'interaction.forum'));