Merge branch 'MDL-86995-main' of https://github.com/sh-csg/moodle
This commit is contained in:
@@ -38,13 +38,35 @@ class backup_forum_activity_structure_step extends backup_activity_structure_ste
|
||||
|
||||
// Define each element separated
|
||||
|
||||
$forum = new backup_nested_element('forum', array('id'), array(
|
||||
'type', 'name', 'intro', 'introformat', 'duedate', 'cutoffdate',
|
||||
'assessed', 'assesstimestart', 'assesstimefinish', 'scale',
|
||||
'maxbytes', 'maxattachments', 'forcesubscribe', 'trackingtype',
|
||||
'rsstype', 'rssarticles', 'timemodified', 'warnafter',
|
||||
'blockafter', 'blockperiod', 'completiondiscussions', 'completionreplies',
|
||||
'completionposts', 'displaywordcount', 'lockdiscussionafter', 'grade_forum'));
|
||||
$forum = new backup_nested_element('forum', ['id'], [
|
||||
'type',
|
||||
'name',
|
||||
'intro',
|
||||
'introformat',
|
||||
'duedate',
|
||||
'cutoffdate',
|
||||
'assessed',
|
||||
'assesstimestart',
|
||||
'assesstimefinish',
|
||||
'scale',
|
||||
'maxbytes',
|
||||
'maxattachments',
|
||||
'forcesubscribe',
|
||||
'trackingtype',
|
||||
'rsstype',
|
||||
'rssarticles',
|
||||
'timemodified',
|
||||
'warnafter',
|
||||
'blockafter',
|
||||
'blockperiod',
|
||||
'completiondiscussions',
|
||||
'completionreplies',
|
||||
'completionposts',
|
||||
'displaywordcount',
|
||||
'lockdiscussionafter',
|
||||
'grade_forum',
|
||||
'showimmediately',
|
||||
]);
|
||||
|
||||
$discussions = new backup_nested_element('discussions');
|
||||
|
||||
|
||||
@@ -73,7 +73,8 @@ class forum {
|
||||
'displaywordcount' => $forum->should_display_word_count(),
|
||||
'lockdiscussionafter' => $forum->get_lock_discussions_after(),
|
||||
'duedate' => $forum->get_due_date(),
|
||||
'cutoffdate' => $forum->get_cutoff_date()
|
||||
'cutoffdate' => $forum->get_cutoff_date(),
|
||||
'showimmediately' => $forum->get_showimmediately(),
|
||||
];
|
||||
}, $forums);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ class forum {
|
||||
private $duedate;
|
||||
/** @var int $cutoffdate Timestamp after which forum posts will no longer be accepted */
|
||||
private $cutoffdate;
|
||||
/** @var bool $showimmediately Whether to show replies in a qanda forum immediately */
|
||||
private bool $showimmediately;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -144,6 +146,7 @@ class forum {
|
||||
* @param int $lockdiscussionafter Timestamp after which discussions should be locked
|
||||
* @param int $duedate Timestamp that represents the due date for forum posts
|
||||
* @param int $cutoffdate Timestamp after which forum posts will no longer be accepted
|
||||
* @param bool $showimmediately Whether to show replies in a qanda forum immediately
|
||||
*/
|
||||
public function __construct(
|
||||
context $context,
|
||||
@@ -178,7 +181,8 @@ class forum {
|
||||
bool $displaywordcount,
|
||||
int $lockdiscussionafter,
|
||||
int $duedate,
|
||||
int $cutoffdate
|
||||
int $cutoffdate,
|
||||
bool $showimmediately
|
||||
) {
|
||||
$this->context = $context;
|
||||
$this->coursemodule = $coursemodule;
|
||||
@@ -213,6 +217,7 @@ class forum {
|
||||
$this->lockdiscussionafter = $lockdiscussionafter;
|
||||
$this->duedate = $duedate;
|
||||
$this->cutoffdate = $cutoffdate;
|
||||
$this->showimmediately = $showimmediately;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,4 +674,13 @@ class forum {
|
||||
|
||||
return $this->is_discussion_time_locked($discussion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of showimmediately
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_showimmediately(): bool {
|
||||
return $this->showimmediately;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ class entity {
|
||||
$record->displaywordcount,
|
||||
$record->lockdiscussionafter,
|
||||
$record->duedate,
|
||||
$record->cutoffdate
|
||||
$record->cutoffdate,
|
||||
$record->showimmediately
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/forum/db" VERSION="20250414" COMMENT="XMLDB file for Moodle mod/forum"
|
||||
<XMLDB PATH="mod/forum/db" VERSION="20251105" COMMENT="XMLDB file for Moodle mod/forum"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@@ -35,6 +35,7 @@
|
||||
<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"/>
|
||||
<FIELD NAME="showimmediately" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
||||
@@ -69,5 +69,19 @@ function xmldb_forum_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v5.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2025110500) {
|
||||
// Define field showimmediately to be added to forum.
|
||||
$table = new xmldb_table('forum');
|
||||
$field = new xmldb_field('showimmediately', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'lockdiscussionafter');
|
||||
|
||||
// Conditionally launch add field showimmediately.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Forum savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2025110500, 'forum');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class mod_forum_external extends external_api {
|
||||
// Also, the return type declaration is wrong, but I am not changing it now because I don't want ot break things.
|
||||
return new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
[
|
||||
'id' => new external_value(PARAM_INT, 'Forum id'),
|
||||
'course' => new external_value(PARAM_INT, 'Course id'),
|
||||
'type' => new external_value(PARAM_TEXT, 'The forum type'),
|
||||
@@ -176,7 +176,13 @@ class mod_forum_external extends external_api {
|
||||
'istracked' => new external_value(PARAM_BOOL, 'If the user is tracking the forum', VALUE_OPTIONAL),
|
||||
'unreadpostscount' => new external_value(PARAM_INT, 'The number of unread posts for tracked forums',
|
||||
VALUE_OPTIONAL),
|
||||
), 'forum'
|
||||
'showimmediately' => new external_value(
|
||||
PARAM_BOOL,
|
||||
'Whether to show replies immediately in a Q&A forum',
|
||||
VALUE_OPTIONAL
|
||||
),
|
||||
],
|
||||
'forum'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -370,6 +370,8 @@ $string['indicator:socialbreadth_help'] = 'This indicator is based on the social
|
||||
$string['indicator:socialbreadthdef'] = 'Forum social';
|
||||
$string['indicator:socialbreadthdef_help'] = 'The participant has reached this percentage of the social engagement offered by the Forum activities during this analysis interval (Levels = No participation, Participant alone, Participant with others)';
|
||||
$string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth';
|
||||
$string['showimmediately'] = 'Show other replies immediately after posting';
|
||||
$string['showimmediately_help'] = 'This will show the replies of other participants before reaching the maximum editing time ({$a} minutes). Participants could still change their post during this time.';
|
||||
$string['starredonly'] = 'Search starred discussions only';
|
||||
$string['indexoutoftotal'] = '{$a->index} out of {$a->total}';
|
||||
$string['inforum'] = 'in {$a}';
|
||||
|
||||
@@ -580,7 +580,7 @@ function forum_print_recent_activity($course, $viewfullnames, $timestart) {
|
||||
f.scale, f.grade_forum, f.maxbytes, f.maxattachments, f.forcesubscribe,
|
||||
f.trackingtype, f.rsstype, f.rssarticles, f.timemodified, f.warnafter, f.blockafter,
|
||||
f.blockperiod, f.completiondiscussions, f.completionreplies, f.completionposts,
|
||||
f.displaywordcount, f.lockdiscussionafter, f.grade_forum_notify,
|
||||
f.displaywordcount, f.lockdiscussionafter, f.grade_forum_notify, f.showimmediately,
|
||||
d.name AS discussionname, d.firstpost, d.userid AS discussionstarter,
|
||||
d.assessed AS discussionassessed, d.timemodified, d.usermodified, d.forum, d.groupid,
|
||||
d.timestart, d.timeend, d.pinned, d.timelocked,
|
||||
@@ -672,7 +672,8 @@ function forum_print_recent_activity($course, $viewfullnames, $timestart) {
|
||||
'completionposts' => $post->completionposts,
|
||||
'displaywordcount' => $post->displaywordcount,
|
||||
'lockdiscussionafter' => $post->lockdiscussionafter,
|
||||
'grade_forum_notify' => $post->grade_forum_notify
|
||||
'grade_forum_notify' => $post->grade_forum_notify,
|
||||
'showimmediately' => $post->showimmediately,
|
||||
];
|
||||
// Build the forum entity from the factory.
|
||||
$forumentity = $entityfactory->get_forum_from_stdclass($forumrecord, $context, $coursemodule, $course);
|
||||
@@ -3901,7 +3902,7 @@ function forum_user_can_see_post($forum, $discussion, $post, $user = null, $cm =
|
||||
return true;
|
||||
}
|
||||
$userfirstpost = forum_get_user_posted_time($discussion->id, $user->id);
|
||||
return (($userfirstpost !== false && (time() - $userfirstpost >= $CFG->maxeditingtime)));
|
||||
return ($userfirstpost !== false && (time() - $userfirstpost >= $CFG->maxeditingtime || $forum->showimmediately));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ class mod_forum_mod_form extends moodleform_mod {
|
||||
$mform->addHelpButton('type', 'forumtype', 'forum');
|
||||
$mform->setDefault('type', 'general');
|
||||
|
||||
$mform->addElement('advcheckbox', 'showimmediately', get_string('showimmediately', 'forum'));
|
||||
$mform->addHelpButton('showimmediately', 'showimmediately', 'forum', '', false, $CFG->maxeditingtime / 60);
|
||||
$mform->setDefault('showimmediately', 0);
|
||||
$mform->hideIf('showimmediately', 'type', 'neq', 'qanda');
|
||||
|
||||
$mform->addElement('header', 'availability', get_string('availability', 'forum'));
|
||||
|
||||
$name = get_string('duedate', 'forum');
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
@mod @mod_forum
|
||||
Feature: QandA forum discussion type
|
||||
In order to let students first see other replies to a post after replying themselves
|
||||
As a teacher
|
||||
I need to create a forum of qand a type
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | type | course | idnumber | showimmediately |
|
||||
| forum | Q and A forum | Q and A forum description | qanda | C1 | forum | 0 |
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| forum | name | subject | message | user |
|
||||
| forum | Discussion 1 | Discussion 1 | Discussion contents 1, first message | student1 |
|
||||
| forum | Discussion 2 | Discussion 2 | Discussion contents 2, first message | teacher1 |
|
||||
And the following "mod_forum > posts" exist:
|
||||
| parentsubject | subject | message | user |
|
||||
| Discussion 1 | Reply 1 to discussion 1 | Discussion contents 1, second message | student2 |
|
||||
| Discussion 2 | Reply 1 to discussion 2 | Discussion contents 2, second message | student2 |
|
||||
|
||||
Scenario: Students can see all replies to own discussions
|
||||
When I am on the "Q and A forum" "forum activity" page logged in as student1
|
||||
And I follow "Discussion 1"
|
||||
Then I should see "Reply 1 to discussion 1"
|
||||
|
||||
Scenario: Teachers can see all replies
|
||||
When I am on the "Q and A forum" "forum activity" page logged in as teacher1
|
||||
And I follow "Discussion 1"
|
||||
Then I should see "Reply 1 to discussion 1"
|
||||
|
||||
Scenario: Students can't see replies to discussions from other users they didn't reply to yet
|
||||
When I am on the "Q and A forum" "forum activity" page logged in as student1
|
||||
And I follow "Discussion 2"
|
||||
Then I should not see "Reply 1 to discussion 2"
|
||||
|
||||
Scenario: Students can't see replies to discussions from other users when they have replied but they are within the maximum editing time
|
||||
Given the following "mod_forum > posts" exist:
|
||||
| parentsubject | subject | message | user |
|
||||
| Discussion 2 | Reply 2 to discussion 1 | Discussion contents 2, third message | student1 |
|
||||
When I am on the "Q and A forum" "forum activity" page logged in as student1
|
||||
And I follow "Discussion 2"
|
||||
Then I should not see "Reply 1 to discussion 2"
|
||||
|
||||
Scenario: Students can see replies to discussions from other users when they have replied and they can't edit the post anymore
|
||||
Given the following "mod_forum > posts" exist:
|
||||
| parentsubject | subject | message | user | created |
|
||||
| Discussion 2 | Reply 2 to discussion 2 | Discussion contents 2, third message | student1 | ##now +1 second## |
|
||||
And the following config values are set as admin:
|
||||
| maxeditingtime | 1 |
|
||||
And I wait "2" seconds
|
||||
When I am on the "Q and A forum" "forum activity" page logged in as student1
|
||||
And I follow "Discussion 2"
|
||||
Then I should see "Reply 1 to discussion 2"
|
||||
|
||||
Scenario: Students can see replies to discussions from other users when they have replied regardless of editing time when showimmediately option is set
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | type | course | idnumber | showimmediately |
|
||||
| forum | Q and A forum showimmediately | Q and A forum description | qanda | C1 | forum2 | 1 |
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| forum | name | subject | message | user |
|
||||
| forum2 | Discussion 3 | Discussion 3 | Discussion contents 3, first message | teacher1 |
|
||||
And the following "mod_forum > posts" exist:
|
||||
| parentsubject | subject | message | user |
|
||||
| Discussion 3 | Reply 1 to discussion 3 | Discussion contents 3, second message | student2 |
|
||||
| Discussion 3 | Reply 2 to discussion 3 | Discussion contents 3, second message | student1 |
|
||||
When I am on the "Q and A forum showimmediately" "forum activity" page logged in as student1
|
||||
And I follow "Discussion 3"
|
||||
Then I should see "Reply 1 to discussion 3"
|
||||
@@ -91,6 +91,7 @@ final class entities_forum_test extends \advanced_testcase {
|
||||
$duedate = 0;
|
||||
$cutoffdate = 0;
|
||||
$sendnotification = false;
|
||||
$showimmediately = false;
|
||||
$forum = new forum_entity(
|
||||
$context,
|
||||
$coursemodule,
|
||||
@@ -124,7 +125,8 @@ final class entities_forum_test extends \advanced_testcase {
|
||||
$displaywordcount,
|
||||
$lockdiscussionafter,
|
||||
$duedate,
|
||||
$cutoffdate
|
||||
$cutoffdate,
|
||||
$showimmediately
|
||||
);
|
||||
|
||||
$this->assertEquals($context, $forum->get_context());
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2025100600; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2025110500; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2025092600; // Requires this Moodle version.
|
||||
$plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
Reference in New Issue
Block a user