From 349b705d311c668e5209190151e5754b08e2d725 Mon Sep 17 00:00:00 2001 From: Adrian Greeve Date: Mon, 23 Oct 2017 08:04:09 +0800 Subject: [PATCH 1/4] MDL-60515 groups: Display group information on the participants page. --- group/classes/output/group_details.php | 93 +++++++++++++++++++++++ group/classes/output/renderer.php | 11 +++ group/members.php | 31 +------- group/templates/group_details.mustache | 65 ++++++++++++++++ theme/boost/scss/moodle/user.scss | 4 + theme/bootstrapbase/less/moodle/user.less | 5 ++ theme/bootstrapbase/style/moodle.css | 3 + user/index.php | 6 ++ 8 files changed, 190 insertions(+), 28 deletions(-) create mode 100644 group/classes/output/group_details.php create mode 100644 group/templates/group_details.mustache diff --git a/group/classes/output/group_details.php b/group/classes/output/group_details.php new file mode 100644 index 00000000000..30c67b7cb77 --- /dev/null +++ b/group/classes/output/group_details.php @@ -0,0 +1,93 @@ +. + +/** + * Group details page. + * + * @package core_group + * @copyright 2017 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core_group\output; +defined('MOODLE_INTERNAL') || die(); + +use renderable; +use renderer_base; +use stdClass; +use templatable; +use context_course; +use moodle_url; + +/** + * Group details page class. + * + * @package core_group + * @copyright 2017 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class group_details implements renderable, templatable { + + /** @var stdClass $group An object with the group information. */ + protected $group; + + /** + * group_details constructor. + * + * @param int $groupid Group ID to show details of. + */ + public function __construct($groupid) { + $this->group = groups_get_group($groupid, '*', MUST_EXIST); + } + + /** + * Export the data. + * + * @param renderer_base $output + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + + if (!empty($this->group->description) || (!empty($this->group->picture) && empty($this->group->hidepicture))) { + $context = context_course::instance($this->group->courseid); + $description = file_rewrite_pluginfile_urls($this->group->description, + 'pluginfile.php', + $context->id, + 'group', + 'description', + $this->group->id); + + $descriptionformat = $this->group->descriptionformat ?? FORMAT_MOODLE; + $options = [ + 'overflowdiv' => true, + 'context' => $context + ]; + + $data = new stdClass(); + $data->picture = print_group_picture($this->group, $this->group->courseid, true, true, false); + $data->name = format_string($this->group->name, true, ['context' => $context]); + $data->description = format_text($description, $descriptionformat, $options); + + if (has_capability('moodle/course:managegroups', $context)) { + $url = new moodle_url('/group/group.php', ['id' => $this->group->id, 'courseid' => $this->group->courseid]); + $data->editurl = $url->out(false); + } + + return $data; + } else { + return; + } + } +} diff --git a/group/classes/output/renderer.php b/group/classes/output/renderer.php index 14443cf7891..c3285fa9697 100644 --- a/group/classes/output/renderer.php +++ b/group/classes/output/renderer.php @@ -47,4 +47,15 @@ class renderer extends plugin_renderer_base { $data = $page->export_for_template($this); return parent::render_from_template('core_group/index', $data); } + + /** + * Defer to template. + * + * @param group_details $page Group details page object. + * @return string HTML to render the group details. + */ + public function group_details(group_details $page) { + $data = $page->export_for_template($this); + return parent::render_from_template('core_group/group_details', $data); + } } diff --git a/group/members.php b/group/members.php index 3f4e352b152..f089e3275b0 100644 --- a/group/members.php +++ b/group/members.php @@ -102,36 +102,11 @@ echo $OUTPUT->heading(get_string('adduserstogroup', 'group').": $groupname", 3); // Store the rows we want to display in the group info. $groupinforow = array(); -// Check if there is a picture to display. -if (!empty($group->picture)) { - $picturecell = new html_table_cell(); - $picturecell->attributes['class'] = 'left side picture'; - $picturecell->text = print_group_picture($group, $course->id, true, true, false); - $groupinforow[] = $picturecell; -} - // Check if there is a description to display. -$group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id); if (!empty($group->description)) { - if (!isset($group->descriptionformat)) { - $group->descriptionformat = FORMAT_MOODLE; - } - - $options = new stdClass; - $options->overflowdiv = true; - - $contentcell = new html_table_cell(); - $contentcell->attributes['class'] = 'content'; - $contentcell->text = format_text($group->description, $group->descriptionformat, $options); - $groupinforow[] = $contentcell; -} - -// Check if we have something to show. -if (!empty($groupinforow)) { - $groupinfotable = new html_table(); - $groupinfotable->attributes['class'] = 'groupinfobox'; - $groupinfotable->data[] = new html_table_row($groupinforow); - echo html_writer::table($groupinfotable); + $grouprenderer = $PAGE->get_renderer('core_group'); + $groupdetailpage = new \core_group\output\group_details($groupid); + echo $grouprenderer->group_details($groupdetailpage); } /// Print the editing form diff --git a/group/templates/group_details.mustache b/group/templates/group_details.mustache new file mode 100644 index 00000000000..05ac40595fc --- /dev/null +++ b/group/templates/group_details.mustache @@ -0,0 +1,65 @@ +{{! + 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 . +}} +{{! + @template core_group/group_details + + Template for the Groups page. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Context variables required for this template: + * name string Group Name + * picture string Group image HTML + * description string Group description + * edit string edit link to edit the group + + Example context (json): + { + "name": "Group Name", + "picture": "", + "description": "This is the description for Group Name", + "editurl": "" + } +}} +{{#name}} +
+
+ {{#picture}} +
{{{picture}}}
+ {{/picture}} +
+
+
+
+

{{name}}

+ {{#editurl}} + {{#pix}}t/edit, core, {{#str}}editgroupprofile{{/str}}{{/pix}} + {{/editurl}} +
+
+
+
{{{description}}}
+
+
+
+
+
+{{/name}} diff --git a/theme/boost/scss/moodle/user.scss b/theme/boost/scss/moodle/user.scss index aa7f3a6edfc..3561900bcfb 100644 --- a/theme/boost/scss/moodle/user.scss +++ b/theme/boost/scss/moodle/user.scss @@ -200,6 +200,10 @@ font-weight: bold; } +.group-image { + min-width: 93px; +} + .groupinfobox { @extend .card; } diff --git a/theme/bootstrapbase/less/moodle/user.less b/theme/bootstrapbase/less/moodle/user.less index 265d53e81dc..4e7ee1fe8f0 100644 --- a/theme/bootstrapbase/less/moodle/user.less +++ b/theme/bootstrapbase/less/moodle/user.less @@ -202,6 +202,11 @@ width: 100px; vertical-align: top; } + +.group-image { + min-width: 60px; +} + .course-participation #showall { text-align: center; margin: 10px 0; diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index 378907054a6..dc577b35c78 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -9895,6 +9895,9 @@ body.path-question-type .mform fieldset.hidden { width: 100px; vertical-align: top; } +.group-image { + min-width: 60px; +} .course-participation #showall { text-align: center; margin: 10px 0; diff --git a/user/index.php b/user/index.php index ef2de01dac6..e458477d31c 100644 --- a/user/index.php +++ b/user/index.php @@ -196,6 +196,12 @@ if ($groupid !== false) { } } +if ($groupid && ($course->groupmode != SEPARATEGROUPS || $canaccessallgroups)) { + $grouprenderer = $PAGE->get_renderer('core_group'); + $groupdetailpage = new \core_group\output\group_details($groupid); + echo $grouprenderer->group_details($groupdetailpage); +} + // Manage enrolments. $manager = new course_enrolment_manager($PAGE, $course); $enrolbuttons = $manager->get_manual_enrol_buttons(); From c550fd0e1180130f57b5bbecb634cb129aa5ee5a Mon Sep 17 00:00:00 2001 From: Adrian Greeve Date: Mon, 30 Oct 2017 11:00:36 +0800 Subject: [PATCH 2/4] MDL-60515 groups: Update to weblib group function. Added a new function to get the url for the group picture. --- group/classes/output/group_details.php | 2 +- group/templates/group_details.mustache | 14 +++--- lib/weblib.php | 60 ++++++++++++++++++-------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/group/classes/output/group_details.php b/group/classes/output/group_details.php index 30c67b7cb77..11d4a62e078 100644 --- a/group/classes/output/group_details.php +++ b/group/classes/output/group_details.php @@ -76,8 +76,8 @@ class group_details implements renderable, templatable { ]; $data = new stdClass(); - $data->picture = print_group_picture($this->group, $this->group->courseid, true, true, false); $data->name = format_string($this->group->name, true, ['context' => $context]); + $data->pictureurl = get_group_picture_url($this->group, $this->group->courseid, true); $data->description = format_text($description, $descriptionformat, $options); if (has_capability('moodle/course:managegroups', $context)) { diff --git a/group/templates/group_details.mustache b/group/templates/group_details.mustache index 05ac40595fc..d05e1d23775 100644 --- a/group/templates/group_details.mustache +++ b/group/templates/group_details.mustache @@ -27,25 +27,25 @@ Context variables required for this template: * name string Group Name - * picture string Group image HTML + * pictureurl string Group image url * description string Group description * edit string edit link to edit the group Example context (json): { "name": "Group Name", - "picture": "", + "pictureurl": "https://raw.githubusercontent.com/moodle/moodle/master/pix/g/f1.png", "description": "This is the description for Group Name", - "editurl": "" + "editurl": "http://www.moodle.org" } }} {{#name}}
- {{#picture}} -
{{{picture}}}
- {{/picture}} -
+ {{#pictureurl}} +
{{{pictureurl}}}
+ {{/pictureurl}} +
diff --git a/lib/weblib.php b/lib/weblib.php index e8e2e95de39..471608023db 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -2423,23 +2423,56 @@ function print_group_picture($group, $courseid, $large=false, $return=false, $li } } + $pictureurl = get_group_picture_url($group, $courseid, $large); + + // If there is no picture, do nothing. + if (!isset($pictureurl)) { + return; + } + + $context = context_course::instance($courseid); + + $groupname = s($group->name); + $pictureimage = html_writer::img($pictureurl, $groupname, ['title' => $groupname]); + + $output = ''; + if ($link or has_capability('moodle/site:accessallgroups', $context)) { + $linkurl = new moodle_url('/user/index.php', ['id' => $courseid, 'group' => $group->id]); + $output .= html_writer::link($linkurl, $pictureimage); + } else { + $output .= $pictureimage; + } + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Return the url to the group picture. + * + * @param stdClass $group A group object. + * @param int $courseid The course ID for the group. + * @param bool $large A large or small group picture? Default is small. + * @return moodle_url Returns the url for the group picture. + */ +function get_group_picture_url($group, $courseid, $large = false) { + global $CFG; + $context = context_course::instance($courseid); // If there is no picture, do nothing. if (!$group->picture) { - return ''; + return; } // If picture is hidden, only show to those with course:managegroups. if ($group->hidepicture and !has_capability('moodle/course:managegroups', $context)) { - return ''; + return; } - if ($link or has_capability('moodle/site:accessallgroups', $context)) { - $output = ''; - } else { - $output = ''; - } if ($large) { $file = 'f1'; } else { @@ -2448,18 +2481,7 @@ function print_group_picture($group, $courseid, $large=false, $return=false, $li $grouppictureurl = moodle_url::make_pluginfile_url($context->id, 'group', 'icon', $group->id, '/', $file); $grouppictureurl->param('rev', $group->picture); - $output .= ''.s(get_string('group').' '.$group->name).''; - - if ($link or has_capability('moodle/site:accessallgroups', $context)) { - $output .= ''; - } - - if ($return) { - return $output; - } else { - echo $output; - } + return $grouppictureurl; } From 6b839f3222bbb7a139b4dbcd76c21929e4f54e83 Mon Sep 17 00:00:00 2001 From: Adrian Greeve Date: Mon, 30 Oct 2017 11:09:33 +0800 Subject: [PATCH 3/4] MDL-60515 groups: Group details template change. The group details template has been changed to be simpler and is styled a bit nicer. --- group/templates/group_details.mustache | 30 +++++++---------------- theme/boost/scss/moodle/user.scss | 14 ++++++++++- theme/bootstrapbase/less/moodle/user.less | 18 ++++++++++++-- theme/bootstrapbase/style/moodle.css | 13 +++++++++- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/group/templates/group_details.mustache b/group/templates/group_details.mustache index d05e1d23775..bd6408ff469 100644 --- a/group/templates/group_details.mustache +++ b/group/templates/group_details.mustache @@ -40,26 +40,14 @@ } }} {{#name}} -
-
- {{#pictureurl}} -
{{{pictureurl}}}
- {{/pictureurl}} -
-
-
-
-

{{name}}

- {{#editurl}} - {{#pix}}t/edit, core, {{#str}}editgroupprofile{{/str}}{{/pix}} - {{/editurl}} -
-
-
-
{{{description}}}
-
-
-
-
+
+ {{#pictureurl}} +
{{{name}}}
+ {{/pictureurl}} + {{#editurl}} + + {{/editurl}} +

{{{name}}}

+
{{{description}}}
{{/name}} diff --git a/theme/boost/scss/moodle/user.scss b/theme/boost/scss/moodle/user.scss index 3561900bcfb..c4674a8c9d7 100644 --- a/theme/boost/scss/moodle/user.scss +++ b/theme/boost/scss/moodle/user.scss @@ -200,8 +200,20 @@ font-weight: bold; } +.group-edit { + position: absolute; + right: 0; + margin-right: 0.6em; +} + .group-image { - min-width: 93px; + display: block; + float: left; + margin-right: 1em; + + .grouppicture { + border-radius: 50%; + } } .groupinfobox { diff --git a/theme/bootstrapbase/less/moodle/user.less b/theme/bootstrapbase/less/moodle/user.less index 4e7ee1fe8f0..2df2277b1b6 100644 --- a/theme/bootstrapbase/less/moodle/user.less +++ b/theme/bootstrapbase/less/moodle/user.less @@ -195,8 +195,14 @@ font-weight: bold; } .groupinfobox { - .well + .well; + position: relative; + + h3 { + margin-top: 0px; + } } + .groupinfobox .left { padding: 10px; width: 100px; @@ -204,7 +210,15 @@ } .group-image { - min-width: 60px; + display: block; + float: left; + margin-right: 1em; +} + +.group-edit { + position: absolute; + right: 0; + margin-right: 0.6em; } .course-participation #showall { diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index dc577b35c78..cee6fe33835 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -9885,18 +9885,29 @@ body.path-question-type .mform fieldset.hidden { -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); border-color: #e3e3e3; + position: relative; } .groupinfobox blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } +.groupinfobox h3 { + margin-top: 0px; +} .groupinfobox .left { padding: 10px; width: 100px; vertical-align: top; } .group-image { - min-width: 60px; + display: block; + float: left; + margin-right: 1em; +} +.group-edit { + position: absolute; + right: 0; + margin-right: 0.6em; } .course-participation #showall { text-align: center; From ab2095fb0f05a5b50c195c7c38014e0e6698bc33 Mon Sep 17 00:00:00 2001 From: Adrian Greeve Date: Mon, 30 Oct 2017 16:17:55 +0800 Subject: [PATCH 4/4] MDL-60515 groups: Behat test for viewing the group description. --- group/tests/behat/group_description.feature | 104 +++++++++++++++++++ lib/behat/classes/partial_named_selector.php | 4 + 2 files changed, 108 insertions(+) create mode 100644 group/tests/behat/group_description.feature diff --git a/group/tests/behat/group_description.feature b/group/tests/behat/group_description.feature new file mode 100644 index 00000000000..015cb260fc3 --- /dev/null +++ b/group/tests/behat/group_description.feature @@ -0,0 +1,104 @@ +@core @core_group +Feature: The description of a group can be viewed by students and teachers + In order to view the description of a group + As a teacher + I need to create groups and add descriptions to them. + + Background: + Given the following "courses" exist: + | fullname | shortname | format | + | Course 1 | C1 | topics | + And 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 "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + + @javascript + Scenario: A student can see the group description when visible groups are set. Teachers can see group details. + Given I log in as "teacher1" + And I am on "Course 1" course homepage + And I navigate to "Edit settings" in current page administration + And I set the following fields to these values: + | Group mode | Visible groups | + And I press "Save and display" + And I navigate to "Users > Groups" in current page administration + And I press "Create group" + And I set the following fields to these values: + | Group name | Group A | + | Group description | Description for Group A | + And I press "Save changes" + And I press "Create group" + And I set the following fields to these values: + | Group name | Group B | + And I press "Save changes" + And I add "Student 1 (student1@example.com)" user to "Group A" group members + And I add "Student 2 (student2@example.com)" user to "Group B" group members + And I am on "Course 1" course homepage + And I navigate to course participants + And I open the autocomplete suggestions list + And I click on "Group: Group A" item in the autocomplete list + And I should see "Description for Group A" + And ".groupinfobox" "css_element" should exist + And I should see "Description for Group A" + And I click on "Group: Group A" "autocomplete_selection" + And I open the autocomplete suggestions list + And I click on "Group: Group B" item in the autocomplete list + And ".groupinfobox" "css_element" should not exist + And I log out + When I log in as "student1" + And I am on "Course 1" course homepage + And I navigate to course participants + Then I should see "Description for Group A" + And I log out + And I log in as "student2" + And I am on "Course 1" course homepage + And I navigate to course participants + And ".groupinfobox" "css_element" should not exist + + @javascript + Scenario: A student can not see the group description when separate groups are set. Teachers can see group details. + Given I log in as "teacher1" + And I am on "Course 1" course homepage + And I navigate to "Edit settings" in current page administration + And I set the following fields to these values: + | Group mode | Separate groups | + And I press "Save and display" + And I navigate to "Users > Groups" in current page administration + And I press "Create group" + And I set the following fields to these values: + | Group name | Group A | + | Group description | Description for Group A | + And I press "Save changes" + And I press "Create group" + And I set the following fields to these values: + | Group name | Group B | + And I press "Save changes" + And I add "Student 1 (student1@example.com)" user to "Group A" group members + And I add "Student 2 (student2@example.com)" user to "Group B" group members + And I am on "Course 1" course homepage + And I navigate to course participants + And I open the autocomplete suggestions list + And I click on "Group: Group A" item in the autocomplete list + And I should see "Description for Group A" + And ".groupinfobox" "css_element" should exist + And I click on "Group: Group A" "autocomplete_selection" + And I open the autocomplete suggestions list + And I click on "Group: Group B" item in the autocomplete list + And ".groupinfobox" "css_element" should not exist + And I log out + When I log in as "student1" + And I am on "Course 1" course homepage + And I navigate to course participants + Then I should not see "Description for Group A" + And ".groupinfobox" "css_element" should not exist + And I log out + And I log in as "student2" + And I am on "Course 1" course homepage + And I navigate to course participants + And ".groupinfobox" "css_element" should not exist \ No newline at end of file diff --git a/lib/behat/classes/partial_named_selector.php b/lib/behat/classes/partial_named_selector.php index a0599fbca11..1faa0db4c80 100644 --- a/lib/behat/classes/partial_named_selector.php +++ b/lib/behat/classes/partial_named_selector.php @@ -109,6 +109,7 @@ class behat_partial_named_selector extends \Behat\Mink\Selector\PartialNamedSele 'text' => 'text', 'xpath_element' => 'xpath_element', 'form_row' => 'form_row', + 'autocomplete_selection' => 'autocomplete_selection', ); /** @@ -178,6 +179,9 @@ XPATH XPATH , 'message_area_action' => << <<