$discussion = new backup_nested_element('discussion', array('id'), array(
'name', 'firstpost', 'userid', 'groupid',
'assessed', 'timemodified', 'usermodified', 'timestart',
- 'timeend'));
+ 'timeend', 'pinned'));
$posts = new backup_nested_element('posts');
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+/**
+ * The mod_forum discussion pinned event.
+ *
+ * @package mod_forum
+ * @copyright 2014 Charles Fulton <fultonc@lafayette.edu>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_forum\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_forum discussion pinned event.
+ *
+ * @package mod_forum
+ * @copyright 2014 Charles Fulton <fultonc@lafayette.edu>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class discussion_pinned extends \core\event\base {
+ /**
+ * Init method.
+ *
+ * @return void
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ $this->data['edulevel'] = self::LEVEL_OTHER;
+ $this->data['objecttable'] = 'forum_discussions';
+ }
+
+ /**
+ * Returns description of what happened.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return "The user {$this->userid} has pinned the discussion {$this->objectid} in the forum {$this->other['forumid']}";
+ }
+
+ /**
+ * Return localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventdiscussionpinned', 'mod_forum');
+ }
+
+ /**
+ * Get URL related to the action
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/mod/forum/discuss.php', array('d' => $this->objectid));
+ }
+
+ /**
+ * Return the legacy event log data.
+ *
+ * @return array|null
+ */
+ protected function get_legacy_logdata() {
+ // The legacy log table expects a relative path to /mod/forum/.
+ $logurl = substr($this->get_url()->out_as_local_url(), strlen('/mod/forum/'));
+ return array($this->courseid, 'forum', 'pin discussion', $logurl, $this->objectid, $this->contextinstanceid);
+ }
+
+ /**
+ * Custom validation.
+ *
+ * @throws \coding_exception
+ * @return void
+ */
+ protected function validate_data() {
+ parent::validate_data();
+ if (!isset($this->other['forumid'])) {
+ throw new \coding_exception('forumid must be set in $other.');
+ }
+ if ($this->contextlevel != CONTEXT_MODULE) {
+ throw new \coding_exception('Context passed must be module context.');
+ }
+ if (!isset($this->objectid)) {
+ throw new \coding_exception('objectid must be set to the discussionid.');
+ }
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+/**
+ * The mod_forum discussion unpinned event.
+ *
+ * @package mod_forum
+ * @copyright 2014 Charles Fulton <fultonc@lafayette.edu>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_forum\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_forum discussion unpinned event.
+ *
+ * @package mod_forum
+ * @copyright 2014 Charles Fulton <fultonc@lafayette.edu>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class discussion_unpinned extends \core\event\base {
+ /**
+ * Init method.
+ *
+ * @return void
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ $this->data['edulevel'] = self::LEVEL_OTHER;
+ $this->data['objecttable'] = 'forum_discussions';
+ }
+
+ /**
+ * Returns description of what happened.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return "The user {$this->userid} has unpinned the discussion {$this->objectid} in the forum {$this->other['forumid']}";
+ }
+
+ /**
+ * Return localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventdiscussionunpinned', 'mod_forum');
+ }
+
+ /**
+ * Get URL related to the action
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/mod/forum/discuss.php', array('d' => $this->objectid));
+ }
+
+ /**
+ * Return the legacy event log data.
+ *
+ * @return array|null
+ */
+ protected function get_legacy_logdata() {
+ // The legacy log table expects a relative path to /mod/forum/.
+ $logurl = substr($this->get_url()->out_as_local_url(), strlen('/mod/forum/'));
+ return array($this->courseid, 'forum', 'unpin discussion', $logurl, $this->objectid, $this->contextinstanceid);
+ }
+
+ /**
+ * Custom validation.
+ *
+ * @throws \coding_exception
+ * @return void
+ */
+ protected function validate_data() {
+ parent::validate_data();
+ if (!isset($this->other['forumid'])) {
+ throw new \coding_exception('forumid must be set in $other.');
+ }
+ if ($this->contextlevel != CONTEXT_MODULE) {
+ throw new \coding_exception('Context passed must be module context.');
+ }
+ if (!isset($this->objectid)) {
+ throw new \coding_exception('objectid must be set to the discussionid.');
+ }
+ }
+}
)
),
+ 'mod/forum:pindiscussions' => array(
+
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => array(
+ 'teacher' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW
+ )
+ ),
+
'mod/forum:editanypost' => array(
'riskbitmask' => RISK_SPAM,
<FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timestart" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timeend" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+ <FIELD NAME="pinned" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
array('module'=>'forum', 'action'=>'view forum', 'mtable'=>'forum', 'field'=>'name'),
array('module'=>'forum', 'action'=>'subscribe', 'mtable'=>'forum', 'field'=>'name'),
array('module'=>'forum', 'action'=>'unsubscribe', 'mtable'=>'forum', 'field'=>'name'),
+ array('module'=>'forum', 'action'=>'pin discussion', 'mtable'=>'forum_discussions', 'field'=>'name'),
+ array('module'=>'forum', 'action'=>'unpin discussion', 'mtable'=>'forum_discussions', 'field'=>'name'),
);
\ No newline at end of file
// Moodle v2.8.0 release upgrade line.
// Put any upgrade step following this.
+ if ($oldversion < 2014112400) {
+
+ // Add support for pinned discussions.
+ $table = new xmldb_table('forum_discussions');
+ $field = new xmldb_field('pinned', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'timeend');
+
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Forum savepoint reached.
+ upgrade_mod_savepoint(true, 2014112400, 'forum');
+ }
// Moodle v2.9.0 release upgrade line.
// Put any upgrade step following this.
$move = optional_param('move', 0, PARAM_INT); // If set, moves this discussion to another forum
$mark = optional_param('mark', '', PARAM_ALPHA); // Used for tracking read posts if user initiated.
$postid = optional_param('postid', 0, PARAM_INT); // Used for tracking read posts if user initiated.
+$pin = optional_param('pin', -1, PARAM_INT); // If set, pin or unpin this discussion.
$url = new moodle_url('/mod/forum/discuss.php', array('d'=>$d));
if ($parent !== 0) {
redirect($return.'&move=-1&sesskey='.sesskey());
}
+// Pin or unpin discussion if requested.
+if ($pin !== -1 && confirm_sesskey()) {
+ require_capability('mod/forum:pindiscussions', $modcontext);
+
+ $params = array('context' => $modcontext, 'objectid' => $discussion->id, 'other' => array('forumid' => $forum->id));
+
+ switch ($pin) {
+ case FORUM_DISCUSSION_PINNED:
+ $DB->set_field('forum_discussions', 'pinned', $pin, array('id' => $discussion->id));
+ $event = \mod_forum\event\discussion_pinned::create($params);
+ $event->add_record_snapshot('forum_discussions', $discussion);
+ $event->trigger();
+ break;
+ case FORUM_DISCUSSION_UNPINNED:
+ $DB->set_field('forum_discussions', 'pinned', $pin, array('id' => $discussion->id));
+ $event = \mod_forum\event\discussion_unpinned::create($params);
+ $event->add_record_snapshot('forum_discussions', $discussion);
+ $event->trigger();
+ break;
+ default:
+ echo $OUTPUT->notfication("Invalid value when attempting to pin/unpin discussion");
+ break;
+ }
+
+ redirect(new moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id)));
+}
+
// Trigger discussion viewed event.
forum_discussion_view($modcontext, $forum, $discussion);
}
echo "</div>";
}
+
+if (has_capability('mod/forum:pindiscussions', $modcontext)) {
+ if ($discussion->pinned == FORUM_DISCUSSION_PINNED) {
+ $pinlink = FORUM_DISCUSSION_UNPINNED;
+ $pintext = get_string('discussionunpin', 'forum');
+ } else {
+ $pinlink = FORUM_DISCUSSION_PINNED;
+ $pintext = get_string('discussionpin', 'forum');
+ }
+ $button = new single_button(new moodle_url('discuss.php', array('pin' => $pinlink, 'd' => $discussion->id)), $pintext, 'post');
+ echo html_writer::tag('div', $OUTPUT->render($button), array('class' => 'discussioncontrol pindiscussion'));
+}
+
echo '<div class="clearfloat"> </div>';
echo "</div>";
$string['discussionname'] = 'Discussion name';
$string['discussionnownotsubscribed'] = '{$a->name} will NOT be notified of new posts in \'{$a->discussion}\' of \'{$a->forum}\'';
$string['discussionnowsubscribed'] = '{$a->name} will be notified of new posts in \'{$a->discussion}\' of \'{$a->forum}\'';
+$string['discussionpin'] = 'Pin';
+$string['discussionpinned'] = 'Pinned: {$a}';
$string['discussionsubscribestop'] = 'I don\'t want to be notified of new posts in this discussion';
$string['discussionsubscribestart'] = 'Send me notifications of new posts in this discussion';
$string['discussionsubscription'] = 'Discussion subscription';
$string['discussionsstartedby'] = 'Discussions started by {$a}';
$string['discussionsstartedbyrecent'] = 'Discussions recently started by {$a}';
$string['discussionsstartedbyuserincourse'] = 'Discussions started by {$a->fullname} in {$a->coursename}';
+$string['discussionunpin'] = 'Unpin';
$string['discussthistopic'] = 'Discuss this topic';
$string['displayend'] = 'Display end';
$string['displayend_help'] = 'This setting specifies whether a forum post should be hidden after a certain date. Note that administrators can always view forum posts.';
$string['eventdiscussionviewed'] = 'Discussion viewed';
$string['eventdiscussionsubscriptioncreated'] = 'Discussion subscription created';
$string['eventdiscussionsubscriptiondeleted'] = 'Discussion subscription deleted';
+$string['eventdiscussionpinned'] = 'Discussion pinned';
+$string['eventdiscussionunpinned'] = 'Discussion unpinned';
$string['eventuserreportviewed'] = 'User report viewed';
$string['eventpostcreated'] = 'Post created';
$string['eventpostdeleted'] = 'Post deleted';
$string['forumintro'] = 'Description';
$string['forum:managesubscriptions'] = 'Manage subscriptions';
$string['forum:movediscussions'] = 'Move discussions';
+$string['forum:pindiscussions'] = 'Pin discussions';
$string['forum:postwithoutthrottling'] = 'Exempt from post threshold';
$string['forumname'] = 'Forum name';
$string['forumposts'] = 'Forum posts';
*/
define('FORUM_POSTS_ALL_USER_GROUPS', -2);
+define('FORUM_DISCUSSION_PINNED', 1);
+define('FORUM_DISCUSSION_UNPINNED', 0);
+
/// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
/**
}
$allnames = get_all_user_name_fields(true, 'u');
- $sql = "SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend, $allnames,
+ $sql = "SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend, d.pinned, $allnames,
u.email, u.picture, u.imagealt $umfields
FROM {forum_discussions} d
JOIN {forum_posts} p ON p.discussion = d.id
$umtable
WHERE d.forum = ? AND p.parent = 0
$timelimit $groupselect
- ORDER BY $forumsort";
+ ORDER BY pinned DESC, $forumsort";
return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
}
* by the user, it simply uses it as a reference to find the neighbours. On the other hand,
* the returned neighbours are checked and are accessible to the current user.
*
+ * This function ignores whether a discussion is pinned.
+ *
* @param object $cm The CM record.
* @param object $discussion The discussion record.
* @param object $forum The forum instance record.
echo "\n\n";
echo '<tr class="discussion r'.$rowcount.$timedoutsidewindow.'">';
- // Topic
- echo '<td class="topic starter">';
+ $topicclass = 'topic starter';
+ if (FORUM_DISCUSSION_PINNED == $post->pinned) {
+ $topicclass .= ' pinned';
+ }
+ echo '<td class="'.$topicclass.'">';
$canalwaysseetimedpost = $USER->id == $post->userid || $canviewhiddentimedposts;
if ($timeddiscussion && $canalwaysseetimedpost) {
} else {
$ownpost=false;
}
- // Use discussion name instead of subject of first post
+ // Use discussion name instead of subject of first post.
$discussion->subject = $discussion->name;
+ if (FORUM_DISCUSSION_PINNED == $discussion->pinned) {
+ $discussion->subject = get_string('discussionpinned', 'forum', $discussion->subject);
+ }
switch ($displayformat) {
case 'header':
}
$discussion->timestart = $fromform->timestart;
$discussion->timeend = $fromform->timeend;
+ $discussion->pinned = FORUM_DISCUSSION_UNPINNED;
$allowedgroups = array();
$groupstopostto = array();
#page-mod-forum-discuss .discussioncontrol.displaymode {text-align:center;}
#page-mod-forum-discuss .discussioncontrol.movediscussion {float:right;width:auto;text-align:right;padding-right:10px;}
#page-mod-forum-discuss .discussioncontrol.movediscussion .movediscussionoption {}
+#page-mod-forum-discuss .discussioncontrol.pindiscussion {float:right;width:auto;text-align:right;padding-right:10px;}
/** Styles for view.php **/
#page-mod-forum-view .forumaddnew {margin-bottom: 20px;}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2015111601; // The current module version (Date: YYYYMMDDXX)
+$plugin->version = 2015112300; // The current module version (Date: YYYYMMDDXX)
$plugin->requires = 2015111000; // Requires this Moodle version
$plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)