Merge branch 'MDL-55982-master' of git://github.com/andrewnicols/moodle

This commit is contained in:
Eloy Lafuente (stronk7) 2016-09-21 03:04:36 +02:00
commit 6cc077e90f
12 changed files with 155 additions and 6 deletions

View File

@ -44,7 +44,7 @@ class backup_forum_activity_structure_step extends backup_activity_structure_ste
'maxbytes', 'maxattachments', 'forcesubscribe', 'trackingtype',
'rsstype', 'rssarticles', 'timemodified', 'warnafter',
'blockafter', 'blockperiod', 'completiondiscussions', 'completionreplies',
'completionposts', 'displaywordcount'));
'completionposts', 'displaywordcount', 'lockdiscussionafter'));
$discussions = new backup_nested_element('discussions');

View File

@ -366,5 +366,14 @@ $capabilities = array(
'manager' => CAP_ALLOW
)
),
'mod/forum:canoverridediscussionlock' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
);

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/forum/db" VERSION="20160113" COMMENT="XMLDB file for Moodle mod/forum"
<XMLDB PATH="mod/forum/db" VERSION="20160912" COMMENT="XMLDB file for Moodle mod/forum"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -30,6 +30,7 @@
<FIELD NAME="completionreplies" TYPE="int" LENGTH="9" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Nonzero if a certain number of replies are required to mark this forum complete for a user."/>
<FIELD NAME="completionposts" TYPE="int" LENGTH="9" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Nonzero if a certain number of posts or replies (total) are required to mark this forum complete for a user."/>
<FIELD NAME="displaywordcount" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="lockdiscussionafter" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

View File

@ -177,5 +177,20 @@ function xmldb_forum_upgrade($oldversion) {
// Moodle v3.1.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2016091200) {
// Define field lockdiscussionafter to be added to forum.
$table = new xmldb_table('forum');
$field = new xmldb_field('lockdiscussionafter', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'displaywordcount');
// Conditionally launch add field lockdiscussionafter.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Forum savepoint reached.
upgrade_mod_savepoint(true, 2016091200, 'forum');
}
return true;
}

View File

@ -372,6 +372,10 @@ if (has_capability('mod/forum:pindiscussions', $modcontext)) {
echo "</div></div>";
if (forum_discussion_is_locked($forum, $discussion)) {
echo html_writer::div(get_string('discussionlocked', 'forum'), 'discussionlocked');
}
if (!empty($forum->blockafter) && !empty($forum->blockperiod)) {
$a = new stdClass();
$a->blockafter = $forum->blockafter;

View File

@ -112,7 +112,7 @@ class mod_forum_external extends external_api {
* @return external_single_structure
* @since Moodle 2.5
*/
public static function get_forums_by_courses_returns() {
public static function get_forums_by_courses_returns() {
return new external_multiple_structure(
new external_single_structure(
array(
@ -143,6 +143,7 @@ class mod_forum_external extends external_api {
'cmid' => new external_value(PARAM_INT, 'Course module id'),
'numdiscussions' => new external_value(PARAM_INT, 'Number of discussions in the forum', VALUE_OPTIONAL),
'cancreatediscussions' => new external_value(PARAM_BOOL, 'If the user can create discussions', VALUE_OPTIONAL),
'lockdiscussionafter' => new external_value(PARAM_INT, 'After what period a discussion is locked', VALUE_OPTIONAL),
), 'forum'
)
);
@ -499,6 +500,9 @@ class mod_forum_external extends external_api {
$discussion->id);
}
$discussion->locked = forum_discussion_is_locked($forum, $discussion);
$discussion->canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
$discussions[] = $discussion;
}
}
@ -549,7 +553,9 @@ class mod_forum_external extends external_api {
'usermodifiedpictureurl' => new external_value(PARAM_URL, 'Post modifier picture.'),
'numreplies' => new external_value(PARAM_TEXT, 'The number of replies in the discussion'),
'numunread' => new external_value(PARAM_INT, 'The number of unread discussions.'),
'pinned' => new external_value(PARAM_BOOL, 'Is the discussion pinned')
'pinned' => new external_value(PARAM_BOOL, 'Is the discussion pinned'),
'locked' => new external_value(PARAM_BOOL, 'Is the discussion locked'),
'canreply' => new external_value(PARAM_BOOL, 'Can the user reply to the discussion'),
), 'post'
)
),

View File

@ -133,6 +133,9 @@ $string['disallowsubscription'] = 'Subscription';
$string['disallowsubscription_help'] = 'This forum has been configured so that you cannot subscribe to discussions.';
$string['disallowsubscribeteacher'] = 'Subscriptions not allowed (except for teachers)';
$string['discussion'] = 'Discussion';
$string['discussionlocked'] = 'This discussion has been locked so you can no longer reply to it.';
$string['discussionlockingheader'] = 'Discussion locking';
$string['discussionlockingdisabled'] = 'Do not lock discussions';
$string['discussionmoved'] = 'This discussion has been moved to \'{$a}\'.';
$string['discussionmovedpost'] = 'This discussion has been moved to <a href="{$a->discusshref}">here</a> in the forum <a href="{$a->forumhref}">{$a->forumname}</a>';
$string['discussionname'] = 'Discussion name';
@ -216,6 +219,7 @@ $string['forum:addinstance'] = 'Add a new forum';
$string['forum:addnews'] = 'Add news';
$string['forum:addquestion'] = 'Add question';
$string['forum:allowforcesubscribe'] = 'Allow force subscribe';
$string['forum:canoverridediscussionlock'] = 'Reply to locked discussions';
$string['forumauthorhidden'] = 'Author (hidden)';
$string['forumblockingalmosttoomanyposts'] = 'You are approaching the posting threshold. You have posted {$a->numposts} times in the last {$a->blockperiod} and the limit is {$a->blockafter} posts.';
$string['forumbodyhidden'] = 'This post cannot be viewed by you, probably because you have not posted in the discussion, the maximum editing time hasn\'t passed yet, the discussion has not started or the discussion has expired.';
@ -275,6 +279,10 @@ $string['invalidparentpostid'] = 'Parent post ID was incorrect';
$string['invalidpostid'] = 'Invalid post ID - {$a}';
$string['lastpost'] = 'Last post';
$string['learningforums'] = 'Learning forums';
$string['lockdiscussionafter'] = 'Lock discussions after period of inactivity';
$string['lockdiscussionafter_help'] = 'Discussions may be automatically locked after a specified time has elapsed since the last reply.
Users with the capability to reply to locked discussions can unlock a discussion by replying to it.';
$string['longpost'] = 'Long post';
$string['mailnow'] = 'Send forum post notifications with no editing-time delay';
$string['manydiscussions'] = 'Discussions per page';

View File

@ -5043,6 +5043,13 @@ function forum_user_can_post($forum, $discussion, $user=NULL, $cm=NULL, $course=
$context = context_module::instance($cm->id);
}
// Check whether the discussion is locked.
if (forum_discussion_is_locked($forum, $discussion)) {
if (!has_capability('mod/forum:canoverridediscussionlock', $context)) {
return false;
}
}
// normal users with temporary guest access can not post, suspended users can not post either
if (!is_viewing($context, $user->id) and !is_enrolled($context, $user->id, '', true)) {
return false;
@ -8013,3 +8020,27 @@ function mod_forum_inplace_editable($itemtype, $itemid, $newvalue) {
return $renderer->render_digest_options($forum, $newvalue);
}
}
/**
* Determine whether the specified discussion is time-locked.
*
* @param stdClass $forum The forum that the discussion belongs to
* @param stdClass $discussion The discussion to test
* @return bool
*/
function forum_discussion_is_locked($forum, $discussion) {
if (empty($forum->lockdiscussionafter)) {
return false;
}
if ($forum->type === 'single') {
// It does not make sense to lock a single discussion forum.
return false;
}
if (($discussion->timemodified + $forum->lockdiscussionafter) < time()) {
return true;
}
return false;
}

View File

@ -147,6 +147,22 @@ class mod_forum_mod_form extends moodleform_mod {
}
}
$mform->addElement('header', 'discussionlocking', get_string('discussionlockingheader', 'forum'));
$options = [
0 => get_string('discussionlockingdisabled', 'forum'),
1 * DAYSECS => get_string('numday', 'core', 1),
1 * WEEKSECS => get_string('numweek', 'core', 1),
2 * WEEKSECS => get_string('numweeks', 'core', 2),
30 * DAYSECS => get_string('nummonth', 'core', 1),
60 * DAYSECS => get_string('nummonths', 'core', 2),
90 * DAYSECS => get_string('nummonths', 'core', 3),
180 * DAYSECS => get_string('nummonths', 'core', 6),
1 * YEARSECS => get_string('numyear', 'core', 1),
];
$mform->addElement('select', 'lockdiscussionafter', get_string('lockdiscussionafter', 'forum'), $options);
$mform->addHelpButton('lockdiscussionafter', 'lockdiscussionafter', 'forum');
$mform->disabledIf('lockdiscussionafter', 'type', 'eq', 'single');
//-------------------------------------------------------------------------------
$mform->addElement('header', 'blockafterheader', get_string('blockafter', 'forum'));
$options = array();

View File

@ -491,7 +491,9 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
'usermodifiedpictureurl' => '',
'numreplies' => 3,
'numunread' => 0,
'pinned' => FORUM_DISCUSSION_UNPINNED
'pinned' => FORUM_DISCUSSION_UNPINNED,
'locked' => false,
'canreply' => false,
);
// Call the external function passing forum id.

View File

@ -3203,4 +3203,61 @@ class mod_forum_lib_testcase extends advanced_testcase {
],
];
}
/**
* Test the forum_discussion_is_locked function.
*
* @dataProvider forum_discussion_is_locked_provider
* @param stdClass $forum
* @param stdClass $discussion
* @param bool $expect
*/
public function test_forum_discussion_is_locked($forum, $discussion, $expect) {
$this->assertEquals($expect, forum_discussion_is_locked($forum, $discussion));
}
/**
* Dataprovider for forum_discussion_is_locked tests.
*
* @return array
*/
public function forum_discussion_is_locked_provider() {
return [
'Unlocked: lockdiscussionafter is unset' => [
(object) [],
(object) [],
false
],
'Unlocked: lockdiscussionafter is false' => [
(object) ['lockdiscussionafter' => false],
(object) [],
false
],
'Unlocked: lockdiscussionafter is null' => [
(object) ['lockdiscussionafter' => null],
(object) [],
false
],
'Unlocked: lockdiscussionafter is set; forum is of type single; post is recent' => [
(object) ['lockdiscussionafter' => DAYSECS, 'type' => 'single'],
(object) ['timemodified' => time()],
false
],
'Unlocked: lockdiscussionafter is set; forum is of type single; post is old' => [
(object) ['lockdiscussionafter' => MINSECS, 'type' => 'single'],
(object) ['timemodified' => time() - DAYSECS],
false
],
'Unlocked: lockdiscussionafter is set; forum is of type eachuser; post is recent' => [
(object) ['lockdiscussionafter' => DAYSECS, 'type' => 'eachuser'],
(object) ['timemodified' => time()],
false
],
'Locked: lockdiscussionafter is set; forum is of type eachuser; post is old' => [
(object) ['lockdiscussionafter' => MINSECS, 'type' => 'eachuser'],
(object) ['timemodified' => time() - DAYSECS],
true
],
];
}
}

View File

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016052300; // The current module version (Date: YYYYMMDDXX)
$plugin->version = 2016091201; // The current module version (Date: YYYYMMDDXX)
$plugin->requires = 2016051900; // Requires this Moodle version
$plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)