Skip to content

Commit c45ab55

Browse files
committed
CTP-1685 add unfreeze function to lifecycle block
1 parent b4a5c5d commit c45ab55

13 files changed

+377
-46
lines changed

block_lifecycle.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ public function get_content() {
7373
$html .= $renderer->fetch_clc_content($courseid);
7474
if (manager::is_course_frozen($courseid)) {
7575
$html .= $renderer->fetch_course_read_only_notification();
76+
77+
// Check if user has the capability to unfreeze the course.
78+
if (has_capability("block/lifecycle:unfreezecourse", $context)) {
79+
$html .= $renderer->fetch_unfreeze_button_html($context);
80+
}
7681
}
7782
$html .= $renderer->fetch_course_dates($courseid);
7883
}

classes/manager.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,26 @@ public static function get_weeks_delay_in_seconds() {
346346
return $enddateextend;
347347
}
348348

349+
/**
350+
* Unfreeze course context.
351+
*
352+
* @param int $courseid Course id.
353+
* @return void
354+
* @throws \coding_exception
355+
* @throws \moodle_exception
356+
*/
357+
public static function unfreeze_course(int $courseid): void {
358+
// Check user's permission.
359+
if (!has_capability('block/lifecycle:unfreezecourse', context_course::instance($courseid))) {
360+
throw new \moodle_exception('error:unfreeze_course', 'block_lifecycle');
361+
}
362+
$context = context_course::instance($courseid);
363+
if ($context->is_locked()) {
364+
// Unlock the course context.
365+
$context->set_locked(false);
366+
}
367+
}
368+
349369
/**
350370
* Get the furthest date among LSA end date and course end date, plus weeks delay.
351371
*

db/access.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,12 @@
5757
'manager' => CAP_ALLOW,
5858
],
5959
],
60+
'block/lifecycle:unfreezecourse' => [
61+
'captype' => 'read',
62+
'contextlevel' => CONTEXT_COURSE,
63+
'archetypes' => [
64+
'editingteacher' => CAP_ALLOW,
65+
'manager' => CAP_ALLOW,
66+
],
67+
],
6068
];

lang/en/block_lifecycle.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,33 @@
2323
* @author Alex Yeung <k.yeung@ucl.ac.uk>
2424
*/
2525

26-
$string['pluginname'] = 'Lifecycle';
2726
$string['button:editsettings'] = 'Edit automatic Read-Only settings';
2827
$string['button:toggleautoreadonly'] = 'Disable Automatic Read-Only';
29-
$string['error:dateformat'] = 'Date must be in format YYYY-MM-DD';
28+
$string['confirm:unfreeze_button'] = '
29+
<p>{$a->contextname} is currently frozen. Unfreezing it will allow users to make changes. Are you sure you wish to continue?</p>
30+
<p class="red">Warning: it will be read-only again tomorrow unless you disable "Automatic Read-Only" in the block.</p>';
3031
$string['error:cannotgetscheduledfreezedate'] = 'Could not get the automatically suggested date.';
31-
$string['error:updatepreferencessuccess'] = 'Auto read only settings updated successfully.';
32+
$string['error:dateformat'] = 'Date must be in format YYYY-MM-DD';
33+
$string['error:unfreeze_course'] = 'You do not have permission to enable editing.';
3234
$string['error:updatepreferencesfailed'] = 'Failed to update read only settings.';
35+
$string['error:updatepreferencessuccess'] = 'Auto read only settings updated successfully.';
3336
$string['generalsettings'] = 'General Settings';
34-
$string['help:togglefreezing'] = 'Disable Automatic Read-Only';
35-
$string['help:togglefreezing_help'] = 'Disable Automatic Read-Only.';
3637
$string['help:delayfreezedate'] = 'override Read-Only date';
3738
$string['help:delayfreezedate_help'] = 'The date for a Read-Only override must be post the automatically suggested date, earlier dates may not be used.';
39+
$string['help:togglefreezing'] = 'Disable Automatic Read-Only';
40+
$string['help:togglefreezing_help'] = 'Disable Automatic Read-Only.';
3841
$string['label:readonlydate'] = 'This course will be made automatically Read Only on: ';
3942
$string['label:readonlydateinput'] = 'Overrides Read-Only date:';
43+
$string['label:unfreezebutton'] = 'Enable editing';
4044
$string['lifecycle:addinstance'] = 'Add lifecycle block';
45+
$string['lifecycle:coursereadonly'] = 'This Course is Read Only';
4146
$string['lifecycle:enddate'] = 'This course\'s end date: {$a}';
4247
$string['lifecycle:myaddinstance'] = 'Add my lifecycle block';
4348
$string['lifecycle:overridecontextfreeze'] = 'Override default course context freezing settings';
4449
$string['lifecycle:startdate'] = 'This course\'s start date: {$a}';
45-
$string['lifecycle:coursereadonly'] = 'This Course is Read Only';
50+
$string['lifecycle:unfreezecourse'] = 'Unfreeze course';
4651
$string['lifecycle:view'] = 'View lifecycle block';
52+
$string['pluginname'] = 'Lifecycle';
4753
$string['privacy:metadata'] = 'The Lifecycle block does not store personal data';
4854
$string['settings:academicyearstartdate'] = 'Academic year start date';
4955
$string['settings:academicyearstartdate:desc'] = 'This field is used to calculate the current academic year period and in MM-DD format';

renderer.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use block_lifecycle\manager;
18+
use core\context\course;
1819

1920
/**
2021
* Class block_lifecycle_renderer
@@ -151,4 +152,22 @@ public function fetch_course_read_only_notification(): string {
151152

152153
return $content;
153154
}
155+
156+
/**
157+
* Return the html for the unfreeze button.
158+
*
159+
* @param context_course $context
160+
* @return string
161+
* @throws coding_exception|moodle_exception
162+
*/
163+
public function fetch_unfreeze_button_html(context_course $context): string {
164+
$url = new moodle_url('/blocks/lifecycle/unfreeze.php', ['id' => $context->instanceid]);
165+
return $this->output->render_from_template(
166+
'block_lifecycle/unfreeze_button',
167+
[
168+
'url' => $url->out(false),
169+
'coursename' => $context->get_context_name(),
170+
]
171+
);
172+
}
154173
}

templates/unfreeze_button.mustache

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{{!
2+
This file is part the Local Analytics plugin for Moodle
3+
Moodle is free software: you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation, either version 3 of the License, or
6+
(at your option) any later version.
7+
8+
Moodle is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
13+
You should have received a copy of the GNU General Public License
14+
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
15+
}}
16+
{{!
17+
@template block_lifecycle/unfreeze_button
18+
19+
Template for displaying the unfreeze button to unfreeze a frozen course.
20+
21+
Classes required for JS:
22+
* none
23+
24+
Data attributes required for JS:
25+
* none
26+
27+
Context variables required for this template:
28+
* url - string The URL to the unfreeze page.
29+
* coursefullname - string The full name of the course.
30+
31+
Example context (json):
32+
{
33+
"url": "http://test.m44.local/blocks/lifecycle/unfreeze.php?id=5",
34+
"coursename": "Test Course 1"
35+
}
36+
}}
37+
<button type="button"
38+
class="btn btn-primary w-100"
39+
data-confirmation="modal"
40+
data-confirmation-title-str='["label:unfreezebutton", "block_lifecycle"]'
41+
data-confirmation-content-str='["confirm:unfreeze_button", "block_lifecycle", {"contextname": "{{coursename}}"}]'
42+
data-confirmation-yes-button-str='["confirm"]'
43+
data-confirmation-destination="{{url}}"
44+
>
45+
{{#str}} label:unfreezebutton, block_lifecycle {{/str}}
46+
<span class="sr-only"> for course {{coursename}}</span>
47+
</button>

tests/behat/behat_lifecycle.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
use Behat\Gherkin\Node\TableNode;
18+
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
19+
20+
/**
21+
* Defines the behat steps for the block_lifecycle plugin.
22+
*
23+
* @package block_lifecycle
24+
* @copyright 2024 onwards University College London {@link https://www.ucl.ac.uk/}
25+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26+
* @author Alex Yeung <k.yeung@ucl.ac.uk>
27+
*/
28+
class behat_lifecycle extends behat_base {
29+
/**
30+
* Create custom field.
31+
*
32+
* @param TableNode $table
33+
* @throws \dml_exception
34+
*
35+
* @Given /^the following custom field exists for lifecycle block:$/
36+
*/
37+
public function the_following_custom_field_exists_for_lifecycle_block(TableNode $table): void {
38+
global $DB;
39+
40+
$data = $table->getRowsHash();
41+
42+
// Create a new custom field category if it doesn't exist.
43+
$category = $DB->get_record(
44+
'customfield_category',
45+
['name' => $data['category'],
46+
'component' => 'core_course',
47+
'area' => 'course']);
48+
49+
if (!$category) {
50+
$category = (object)[
51+
'name' => $data['category'],
52+
'component' => 'core_course',
53+
'area' => 'course',
54+
'sortorder' => 1,
55+
'timecreated' => time(),
56+
'timemodified' => time(),
57+
];
58+
$category->id = $DB->insert_record(
59+
'customfield_category',
60+
$category
61+
);
62+
}
63+
64+
// Check if the field already exists.
65+
$fieldexists = $DB->record_exists('customfield_field', ['shortname' => $data['shortname'], 'categoryid' => $category->id]);
66+
67+
// Create the custom field if not exists.
68+
if (!$fieldexists) {
69+
$field = (object)[
70+
'shortname' => $data['shortname'],
71+
'name' => $data['name'],
72+
'type' => $data['type'],
73+
'categoryid' => $category->id,
74+
'sortorder' => 0,
75+
'configdata' => json_encode([
76+
"required" => 0,
77+
"uniquevalues" => 0,
78+
"maxlength" => 4,
79+
"defaultvalue" => "",
80+
"ispassword" => 0,
81+
"displaysize" => 4,
82+
"locked" => 1,
83+
"visibility" => 0,
84+
]),
85+
'timecreated' => time(),
86+
'timemodified' => time(),
87+
];
88+
$DB->insert_record('customfield_field', $field);
89+
}
90+
}
91+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@block @block_lifecycle
2+
3+
Feature: Unfreeze a frozen course
4+
As a teacher with the appropriate permission
5+
I can click on the "Enable editing" button in the lifecycle block to unfreeze a frozen course
6+
7+
Background:
8+
Given the following "users" exist:
9+
| username | firstname | lastname | idnumber | email |
10+
| teacher1 | Teacher1 | Test | tea1 | teacher1@example.com |
11+
And the following custom field exists for lifecycle block:
12+
| category | CLC |
13+
| shortname | course_year |
14+
| name | Course Year |
15+
| type | text |
16+
And the following "courses" exist:
17+
| fullname | shortname | format | customfield_course_year | startdate | enddate |
18+
| Course 1 | C1 | topics | ##now##%Y## | ## 2 days ago ## | ## yesterday ## |
19+
And the following "course enrolments" exist:
20+
| user | course | role |
21+
| teacher1 | C1 | editingteacher |
22+
And the following "blocks" exist:
23+
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
24+
| lifecycle | Course | C1 | course-view-* | side-pre |
25+
And the "C1" "Course" is context frozen
26+
27+
@javascript
28+
Scenario: Unfreeze a frozen course
29+
Given I am on the "C1" course page logged in as teacher1
30+
And edit mode should not be available on the current page
31+
And I should see "Enable editing" in the "Lifecycle" "block"
32+
And I click on "Enable editing" "text"
33+
And I press "Confirm"
34+
Then edit mode should be available on the current page

tests/freezecontext_test.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2828
* @author Alex Yeung <k.yeung@ucl.ac.uk>
2929
*/
30-
class freezecontext_test extends \advanced_testcase {
30+
final class freezecontext_test extends \advanced_testcase {
3131
protected function setUp(): void {
3232
parent::setUp();
3333
$this->resetAfterTest();

0 commit comments

Comments
 (0)