├── .gitattributes
├── pix
└── monologo.svg
├── README.md
├── templates
├── notready.mustache
├── waitscreen.mustache
├── questionleaderboard_player.mustache
├── preparation.mustache
├── donescreen_player.mustache
├── questionresult_player.mustache
├── joinscreen.mustache
├── question.mustache
├── donescreen.mustache
├── questionleaderboard_gamemaster.mustache
├── lobby.mustache
├── questionresult_gamemaster.mustache
├── question_player.mustache
└── question_gamemaster.mustache
├── version.php
├── styles.css
├── lang
└── en
│ └── kahoodle.php
├── classes
├── event
│ ├── course_module_instance_list_viewed.php
│ └── course_module_viewed.php
├── constants.php
├── output
│ └── renderer.php
├── game.php
└── api.php
├── tests
├── generator
│ └── lib.php
├── behat
│ └── basic_actions.feature
└── lib_test.php
├── backup
└── moodle2
│ ├── backup_kahoodle_stepslib.php
│ ├── restore_kahoodle_stepslib.php
│ ├── backup_kahoodle_activity_task.class.php
│ └── restore_kahoodle_activity_task.class.php
├── mod_form.php
├── view.php
├── db
├── access.php
├── install.xml
└── upgrade.php
├── index.php
├── amd
├── build
│ ├── game.min.js
│ └── game.min.js.map
└── src
│ └── game.js
├── .github
└── workflows
│ └── gha.yml
└── lib.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | amd/build/** -diff
2 |
3 |
--------------------------------------------------------------------------------
/pix/monologo.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kahoodle - real-time quiz game for Moodle using web sockets
2 |
3 | This plugin was originally developed during DevCamp in MoodlemootDACH 2025 by:
4 | Marina Glancy, Jan Britz, Immanuel Pasanec, Vasco Grossmann, Lars Dreier, Kathleen Aermes and Monika Weber.
5 |
6 | We use [tool_realtime](https://github.com/marinaglancy/moodle-tool_realtime) with an additional subplugin for bi-directional websockets.
7 |
8 | We demoed it during the DevCamp and had 70 people playing it at the same time.
9 |
10 | This plugin is still in early development and not ready for production use.
11 |
12 | If you are a UI designer and want to help us, please contact Marina Glancy.
13 |
--------------------------------------------------------------------------------
/templates/notready.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/notready
19 |
20 | TODO describe template notready
21 |
22 | Example context (json):
23 | {
24 | }
25 | }}
26 |
Activity is not available
27 |
--------------------------------------------------------------------------------
/templates/waitscreen.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/waitscreen
19 |
20 | TODO describe template waitscreen
21 |
22 | Example context (json):
23 | {
24 | }
25 | }}
26 |
Please look at the screen
--------------------------------------------------------------------------------
/templates/questionleaderboard_player.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/questionleaderboard_player
19 |
20 | TODO describe template questionleaderboard_player
21 |
22 | Example context (json):
23 | {
24 | "score": 1050
25 | }
26 | }}
27 |
Here you will see your score after this question
28 |
Your total score is {{score}}
29 |
--------------------------------------------------------------------------------
/templates/preparation.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/preparation
19 |
20 | TODO describe template preparation
21 |
22 | Example context (json):
23 | {
24 | }
25 | }}
26 |
Activity is in preparation state. You can allow users to join the game.
27 |
28 |
--------------------------------------------------------------------------------
/templates/donescreen_player.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/donescreen_player
19 |
20 | TODO describe template donescreen_player
21 |
22 | Example context (json):
23 | {
24 | "player": {
25 | "playerid": 10,
26 | "name": "Max Mustermann",
27 | "points": 100
28 | }
29 | }
30 | }}
31 | {{#player}}
32 |
The game is finished! Your score is {{points}} points
33 | {{/player}}
34 |
--------------------------------------------------------------------------------
/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Version information for Kahoodle
19 | *
20 | * @package mod_kahoodle
21 | * @copyright Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | $plugin->component = 'mod_kahoodle';
28 | $plugin->release = '1.0';
29 | $plugin->version = 2025090208;
30 | $plugin->requires = 2024100700;
31 | $plugin->supported = [405, 500];
32 | $plugin->maturity = MATURITY_STABLE;
33 | $plugin->dependencies = [
34 | 'tool_realtime' => ANY_VERSION,
35 | ];
36 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --option-color-1: #F98012;
3 | --option-color-1-hover: #dc6700;
4 |
5 | --option-color-2: #9ABB50;
6 | --option-color-2-hover: #708a38;
7 |
8 | --option-color-3: #69E0FF;
9 | --option-color-3-hover: #4ea4bd;
10 |
11 | --option-color-4: #FFE84F;
12 | --option-color-4-hover: #cab83f;
13 | }
14 |
15 | .mod_kahoodle_option:nth-of-type(1) {
16 | background-color: var(--option-color-1);
17 | }
18 |
19 | .mod_kahoodle_option:nth-child(2) {
20 | background-color: var(--option-color-2);
21 | }
22 |
23 | .mod_kahoodle_option:nth-child(3) {
24 | background-color: var(--option-color-3);
25 | }
26 |
27 | .mod_kahoodle_option:nth-child(4) {
28 | background-color: var(--option-color-4);
29 | }
30 |
31 | /* Hover states */
32 | .mod_kahoodle_option[data-action="answer"]:nth-child(1):hover:not([disabled]) {
33 | background-color: var(--option-color-1-hover);
34 | }
35 |
36 | .mod_kahoodle_option[data-action="answer"]:nth-child(2):hover:not([disabled]) {
37 | background-color: var(--option-color-2-hover);
38 | }
39 |
40 | .mod_kahoodle_option[data-action="answer"]:nth-child(3):hover:not([disabled]) {
41 | background-color: var(--option-color-3-hover);
42 | }
43 |
44 | [data-action="answer"]:nth-child(4):hover:not([disabled]) {
45 | background-color: var(--option-color-4-hover);
46 | }
--------------------------------------------------------------------------------
/templates/questionresult_player.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/questionresult_player
19 |
20 | TODO describe template questionresult_player
21 |
22 | Example context (json):
23 | {
24 | }
25 | }}
26 |
27 |
28 |
29 |
You get {{points}} points!
30 | {{#options}}
31 | {{#iscorrect}}
32 |
The correct answer is:
33 |
{{text}}
34 | {{/iscorrect}}
35 | {{/options}}
36 |
37 |
--------------------------------------------------------------------------------
/templates/joinscreen.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/joinscreen
19 |
20 | TODO describe template joinscreen
21 |
22 | Example context (json):
23 | {
24 | "url": "/",
25 | "sesskey": "abc123"
26 | }
27 | }}
28 |
38 |
--------------------------------------------------------------------------------
/lang/en/kahoodle.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * English language pack for Kahoodle
19 | *
20 | * @package mod_kahoodle
21 | * @category string
22 | * @copyright Marina Glancy
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $string['kahoodle:addinstance'] = 'Add a new Kahoodle';
29 | $string['kahoodle:answer'] = 'Answer Kahoodle';
30 | $string['kahoodle:transition'] = 'Transition Kahoodle';
31 | $string['kahoodle:view'] = 'View Kahoodle';
32 | $string['modulename'] = 'Kahoodle';
33 | $string['modulenameplural'] = 'Kahoodles';
34 | $string['pluginadministration'] = 'Kahoodle administration';
35 | $string['pluginname'] = 'Kahoodle';
36 |
--------------------------------------------------------------------------------
/templates/question.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/question
19 |
20 | TODO describe template question
21 |
22 | Example context (json):
23 | {
24 | "title": "Question",
25 | "source": "https://example.com/image.png",
26 | "answers": [
27 | {"text": "Answer 1", "id": 1 },
28 | {"text": "Answer 2", "id": 2 },
29 | {"text": "Answer 3", "id": 3 }
30 | ]
31 | }
32 | }}
33 |
34 | {{#source}}
35 |
36 | {{/source}}
37 |
{{{title}}}
38 |
39 | {{#answers}}
40 |
41 |
44 |
45 | {{/answers}}
46 |
47 |
48 |
--------------------------------------------------------------------------------
/templates/donescreen.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/donescreen
19 |
20 | TODO describe template donescreen
21 |
22 | Example context (json):
23 | {
24 | "players": [
25 | {
26 | "playerid": 10,
27 | "name": "Max Mustermann",
28 | "points": 100,
29 | "color": "text-primary"
30 | }
31 | ]
32 | }
33 | }}
34 |
46 |
--------------------------------------------------------------------------------
/classes/event/course_module_instance_list_viewed.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace mod_kahoodle\event;
18 |
19 | /**
20 | * Event course_module_instance_list_viewed
21 | *
22 | * @package mod_kahoodle
23 | * @copyright Marina Glancy
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 | class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
27 |
28 | /**
29 | * Create the event from course record.
30 | *
31 | * @param \stdClass $course
32 | * @return course_module_instance_list_viewed
33 | */
34 | public static function create_from_course(\stdClass $course) {
35 | $params = [
36 | 'context' => \context_course::instance($course->id),
37 | ];
38 | /** @var course_module_instance_list_viewed $event */
39 | $event = static::create($params);
40 | $event->add_record_snapshot('course', $course);
41 | return $event;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/templates/questionleaderboard_gamemaster.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/questionleaderboard_gamemaster
19 |
20 | TODO describe template questionleaderboard_gamemaster
21 |
22 | Example context (json):
23 | {
24 | "players": [
25 | {
26 | "playerid": 10,
27 | "name": "Max Mustermann",
28 | "points": 100
29 | }
30 | ]
31 | }
32 | }}
33 |
44 |
45 |
--------------------------------------------------------------------------------
/templates/lobby.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/lobby
19 |
20 | TODO describe template lobby
21 |
22 | Example context (json):
23 | {
24 | "title": "Lobby",
25 | "players": [
26 | {"name": "Player 1"},
27 | {"name": "Player 2"},
28 | {"name": "Player 3"}
29 | ]
30 | }
31 | }}
32 |
33 |
34 |
35 |
{{{title}}}
36 |
Waiting for players to join...
37 |
38 |
39 | {{#players}}
40 |
41 |
42 | {{{name}}}
43 |
44 | {{/players}}
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/templates/questionresult_gamemaster.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/questionresult_gamemaster
19 |
20 | TODO describe template questionresult_gamemaster
21 |
22 | Example context (json):
23 | {
24 | "uniqid": "uniqueid123",
25 | "chartdata": "\"\""
26 | }
27 | }}
28 |
29 |
30 |
31 |
32 |
33 | {{#js}}
34 | require([
35 | 'jquery',
36 | 'core/chart_builder',
37 | 'core/chart_output_chartjs',
38 | ], function($, Builder, Output) {
39 | var data = {{{chartdata}}},
40 | uniqid = "{{uniqid}}",
41 | chartArea = $('#chart-area-' + uniqid),
42 | chartImage = chartArea.find('.chart-image');
43 | Builder.make(data).then(function(ChartInst) {
44 | return new Output(chartImage, ChartInst);
45 | }).catch(function(error) {
46 | window.console.error('Error creating chart:', error);
47 | });
48 | });
49 | {{/js}}
50 |
51 |
52 |
--------------------------------------------------------------------------------
/templates/question_player.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/question_player
19 |
20 | TODO describe template question_player
21 |
22 | Example context (json):
23 | {
24 | "isanswered": false,
25 | "questionid": 5,
26 | "options": [
27 | {"id": 1, "text": "3"},
28 | {"id": 2, "text": "4"},
29 | {"id": 3, "text": "5"},
30 | {"id": 4, "text": "22"}
31 | ]
32 | }
33 | }}
34 |
35 |
36 |
37 | {{#options}}
38 |
45 | {{/options}}
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/classes/constants.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace mod_kahoodle;
18 |
19 | /**
20 | * Constants for the kahoodle module
21 | *
22 | * @package mod_kahoodle
23 | * @copyright Marina Glancy
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 | class constants {
27 | /** @var string game state: game did not start yet, teacher is editing, players are not allowed to join */
28 | public const STATE_PREPARATION = 'PREPARATION';
29 | /** @var string game state: waiting for players to join (aka lobby) */
30 | public const STATE_WAITING = 'WAITING';
31 | /** @var string game state: game is in progress */
32 | public const STATE_INPROGRESS = 'INPROGRESS';
33 | /** @var string game state: game is finished */
34 | public const STATE_DONE = 'DONE';
35 |
36 | /** @var string question state: waiting for answers to the current question */
37 | public const QSTATE_ASKING = 'ASKING';
38 | /** @var string question state: showing results for the current question */
39 | public const QSTATE_RESULTS = 'RESULTS';
40 | /** @var string question state: showing leaderboard for the current question */
41 | public const QSTATE_LEADERBOARD = 'LEADERBOARD';
42 | }
43 |
--------------------------------------------------------------------------------
/tests/generator/lib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Data generator class
19 | *
20 | * @package mod_kahoodle
21 | * @category test
22 | * @copyright Marina Glancy
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 | class mod_kahoodle_generator extends testing_module_generator {
26 |
27 | /**
28 | * Creates an instance of the module for testing purposes.
29 | *
30 | * Module type will be taken from the class name.
31 | *
32 | * @param array|stdClass $record data for module being generated. Requires 'course' key
33 | * (an id or the full object). Also can have any fields from add module form.
34 | * @param null|array $options general options for course module, can be merged into $record
35 | * @return stdClass record from module-defined table with additional field
36 | * cmid (corresponding id in course_modules table)
37 | */
38 | public function create_instance($record = null, ?array $options = null) {
39 | $record = (object)(array)$record;
40 | // TODO add default values for plugin-specific fields here.
41 | $instance = parent::create_instance($record, (array)$options);
42 |
43 | return $instance;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/classes/event/course_module_viewed.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace mod_kahoodle\event;
18 |
19 | /**
20 | * Event course_module_viewed
21 | *
22 | * @package mod_kahoodle
23 | * @copyright Marina Glancy
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 | class course_module_viewed extends \core\event\course_module_viewed {
27 |
28 | /**
29 | * Init method.
30 | */
31 | protected function init() {
32 | parent::init();
33 | $this->data['objecttable'] = 'kahoodle';
34 | }
35 |
36 | /**
37 | * Creates an instance of event
38 | *
39 | * @param \stdClass $record
40 | * @param \cm_info|\stdClass $cm
41 | * @param \stdClass $course
42 | * @return course_module_viewed
43 | */
44 | public static function create_from_record($record, $cm, $course) {
45 | /** @var course_module_viewed $event */
46 | $event = self::create([
47 | 'objectid' => $record->id,
48 | 'context' => \context_module::instance($cm->id),
49 | ]);
50 | $event->add_record_snapshot('course_modules', $cm);
51 | $event->add_record_snapshot('course', $course);
52 | $event->add_record_snapshot('kahoodle', $record);
53 | return $event;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/backup/moodle2/backup_kahoodle_stepslib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides all the settings and steps to perform one complete backup of the activity
19 | *
20 | * @package mod_kahoodle
21 | * @copyright Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 | class backup_kahoodle_activity_structure_step extends backup_activity_structure_step {
25 |
26 | /**
27 | * Backup structure
28 | */
29 | protected function define_structure() {
30 |
31 | // To know if we are including userinfo.
32 | $userinfo = $this->get_setting_value('userinfo');
33 |
34 | // TODO: add all additional fields from the kahoodle table.
35 | $kahoodle = new backup_nested_element('kahoodle', ['id'],
36 | ['name', 'intro', 'introformat', 'timemodified']);
37 |
38 | // Define sources.
39 | $kahoodle->set_source_table('kahoodle', ['id' => backup::VAR_ACTIVITYID]);
40 |
41 | // Define id annotations.
42 | // TODO: add all additional id annotations.
43 |
44 | // Define file annotations.
45 | // TODO: add all additional file annotations.
46 | $kahoodle->annotate_files('mod_kahoodle', 'intro', null);
47 |
48 | // Return the root element (kahoodle), wrapped into standard activity structure.
49 | return $this->prepare_activity_structure($kahoodle);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/mod_form.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | defined('MOODLE_INTERNAL') || die();
18 |
19 | require_once($CFG->dirroot . '/course/moodleform_mod.php');
20 |
21 | /**
22 | * Form for adding and editing Kahoodle instances
23 | *
24 | * @package mod_kahoodle
25 | * @copyright Marina Glancy
26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 | */
28 | class mod_kahoodle_mod_form extends moodleform_mod {
29 |
30 | /**
31 | * Defines forms elements
32 | */
33 | public function definition() {
34 | global $CFG;
35 |
36 | $mform = $this->_form;
37 |
38 | // General fieldset.
39 | $mform->addElement('header', 'general', get_string('general', 'form'));
40 |
41 | $mform->addElement('text', 'name', get_string('name'), ['size' => '64']);
42 | $mform->setType('name', empty($CFG->formatstringstriptags) ? PARAM_CLEANHTML : PARAM_TEXT);
43 | $mform->addRule('name', null, 'required', null, 'client');
44 | $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
45 |
46 | if (!empty($this->_features->introeditor)) {
47 | // Description element that is usually added to the General fieldset.
48 | $this->standard_intro_elements();
49 | }
50 |
51 | // Other standard elements that are displayed in their own fieldsets.
52 | $this->standard_grading_coursemodule_elements();
53 | $this->standard_coursemodule_elements();
54 |
55 | $this->add_action_buttons();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/templates/question_gamemaster.mustache:
--------------------------------------------------------------------------------
1 | {{!
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 .
16 | }}
17 | {{!
18 | @template mod_kahoodle/question_gamemaster
19 |
20 | TODO describe template question_gamemaster
21 |
22 | Example context (json):
23 | {
24 | "image": "https://raw.githubusercontent.com/moodle/moodle/MOODLE_405_STABLE/mod/feedback/pix/monologo.svg",
25 | "question": "What is 2 + 2?",
26 | "options": [
27 | {"id": 1, "text": "3"},
28 | {"id": 2, "text": "4"},
29 | {"id": 3, "text": "5"},
30 | {"id": 4, "text": "22"}
31 | ]
32 | }
33 | }}
34 |
35 | {{#image}}
36 |
37 |
38 |
39 |
40 |
41 | {{/image}}
42 |
43 |
44 |
45 |
{{{question}}}
46 |
47 |
48 |
49 |
50 |
51 | {{#options}}
52 |
53 |
{{{text}}}
54 |
55 | {{/options}}
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/view.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * View Kahoodle instance
19 | *
20 | * @package mod_kahoodle
21 | * @copyright Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | require(__DIR__.'/../../config.php');
26 | require_once(__DIR__.'/lib.php');
27 |
28 | // Course module id.
29 | $id = optional_param('id', 0, PARAM_INT);
30 |
31 | // Activity instance id.
32 | $k = optional_param('k', 0, PARAM_INT);
33 |
34 | if ($id) {
35 | $cm = get_coursemodule_from_id('kahoodle', $id, 0, false, MUST_EXIST);
36 | $course = $DB->get_record('course', ['id' => $cm->course], '*', MUST_EXIST);
37 | $moduleinstance = $DB->get_record('kahoodle', ['id' => $cm->instance], '*', MUST_EXIST);
38 | } else {
39 | $moduleinstance = $DB->get_record('kahoodle', ['id' => $k], '*', MUST_EXIST);
40 | $course = $DB->get_record('course', ['id' => $moduleinstance->course], '*', MUST_EXIST);
41 | $cm = get_coursemodule_from_instance('kahoodle', $moduleinstance->id, $course->id, false, MUST_EXIST);
42 | }
43 |
44 | require_login($course, true, $cm);
45 |
46 | \mod_kahoodle\event\course_module_viewed::create_from_record($moduleinstance, $cm, $course)->trigger();
47 |
48 | $api = new \mod_kahoodle\api($PAGE->cm, $PAGE->activityrecord);
49 | $api->process_simple_action();
50 |
51 | $PAGE->set_url('/mod/kahoodle/view.php', ['id' => $cm->id]);
52 | $PAGE->set_title(format_string($moduleinstance->name));
53 | $PAGE->set_heading(format_string($course->fullname));
54 |
55 | echo $OUTPUT->header();
56 |
57 | $renderer = $PAGE->get_renderer('mod_kahoodle');
58 | echo $renderer->game($api);
59 |
60 | echo $OUTPUT->footer();
61 |
--------------------------------------------------------------------------------
/backup/moodle2/restore_kahoodle_stepslib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Structure step to restore one Kahoodle activity
19 | *
20 | * @package mod_kahoodle
21 | * @copyright Marina Glancy
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 | class restore_kahoodle_activity_structure_step extends restore_activity_structure_step {
25 |
26 | /**
27 | * Structure step to restore one kahoodle activity
28 | *
29 | * @return array
30 | */
31 | protected function define_structure() {
32 |
33 | $paths = [];
34 | $paths[] = new restore_path_element('kahoodle', '/activity/kahoodle');
35 |
36 | // Return the paths wrapped into standard activity structure.
37 | return $this->prepare_activity_structure($paths);
38 | }
39 |
40 | /**
41 | * Process a kahoodle restore
42 | *
43 | * @param array $data
44 | * @return void
45 | */
46 | protected function process_kahoodle($data) {
47 | global $DB;
48 |
49 | $data = (object)$data;
50 | $oldid = $data->id;
51 | $data->course = $this->get_courseid();
52 |
53 | // Insert the kahoodle record.
54 | $newitemid = $DB->insert_record('kahoodle', $data);
55 | // Immediately after inserting "activity" record, call this.
56 | $this->apply_activity_instance($newitemid);
57 | }
58 |
59 | /**
60 | * Actions to be executed after the restore is completed
61 | */
62 | protected function after_execute() {
63 | // Add kahoodle related files, no need to match by itemname (just internally handled context).
64 | $this->add_related_files('mod_kahoodle', 'intro', null);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/db/access.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Capability definitions for Kahoodle
19 | *
20 | * Documentation: {@link https://moodledev.io/docs/apis/subsystems/access}
21 | *
22 | * @package mod_kahoodle
23 | * @category access
24 | * @copyright Marina Glancy
25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 | */
27 |
28 | defined('MOODLE_INTERNAL') || die();
29 |
30 | $capabilities = [
31 |
32 | 'mod/kahoodle:view' => [
33 | 'captype' => 'read',
34 | 'contextlevel' => CONTEXT_COURSE,
35 | 'archetypes' => [
36 | 'guest' => CAP_ALLOW,
37 | 'student' => CAP_ALLOW,
38 | 'teacher' => CAP_ALLOW,
39 | 'editingteacher' => CAP_ALLOW,
40 | 'manager' => CAP_ALLOW,
41 | 'frontpage' => CAP_ALLOW,
42 | ],
43 | ],
44 |
45 | 'mod/kahoodle:addinstance' => [
46 | 'captype' => 'write',
47 | 'riskbitmask' => RISK_XSS,
48 | 'contextlevel' => CONTEXT_COURSE,
49 | 'archetypes' => [
50 | 'editingteacher' => CAP_ALLOW,
51 | 'manager' => CAP_ALLOW,
52 | ],
53 | 'clonepermissionsfrom' => 'moodle/course:manageactivities',
54 | ],
55 |
56 | 'mod/kahoodle:transition' => [
57 | 'captype' => 'write',
58 | 'riskbitmask' => RISK_SPAM,
59 | 'contextlevel' => CONTEXT_MODULE,
60 | 'archetypes' => [
61 | 'teacher' => CAP_ALLOW,
62 | 'editingteacher' => CAP_ALLOW,
63 | ],
64 | ],
65 |
66 | 'mod/kahoodle:answer' => [
67 | 'captype' => 'read',
68 | 'contextlevel' => CONTEXT_MODULE,
69 | 'archetypes' => [
70 | 'student' => CAP_ALLOW,
71 | 'guest' => CAP_ALLOW,
72 | 'frontpage' => CAP_ALLOW,
73 | ],
74 | ],
75 | ];
76 |
--------------------------------------------------------------------------------
/backup/moodle2/backup_kahoodle_activity_task.class.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | defined('MOODLE_INTERNAL') || die();
18 |
19 | require_once($CFG->dirroot . '/mod/kahoodle/backup/moodle2/backup_kahoodle_stepslib.php');
20 |
21 | /**
22 | * Provides the steps to perform one complete backup of the Kahoodle instance
23 | *
24 | * @package mod_kahoodle
25 | * @copyright Marina Glancy
26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 | */
28 | class backup_kahoodle_activity_task extends backup_activity_task {
29 |
30 | /**
31 | * No specific settings for this activity
32 | */
33 | protected function define_my_settings() {
34 | }
35 |
36 | /**
37 | * Defines a backup step to store the instance data in the kahoodle.xml file
38 | */
39 | protected function define_my_steps() {
40 | $this->add_step(new backup_kahoodle_activity_structure_step('kahoodle_structure', 'kahoodle.xml'));
41 | }
42 |
43 | /**
44 | * Encodes URLs to the index.php and view.php scripts
45 | *
46 | * @param string $content some HTML text that eventually contains URLs to the activity instance scripts
47 | * @return string the content with the URLs encoded
48 | */
49 | public static function encode_content_links($content) {
50 | global $CFG;
51 |
52 | $base = preg_quote($CFG->wwwroot, "/");
53 |
54 | // Link to the list of kahoodles.
55 | $search = "/(".$base."\/mod\/kahoodle\/index.php\?id\=)([0-9]+)/";
56 | $content = preg_replace($search, '$@KAHOODLEINDEX*$2@$', $content);
57 |
58 | // Link to kahoodle view by moduleid.
59 | $search = "/(".$base."\/mod\/kahoodle\/view.php\?id\=)([0-9]+)/";
60 | $content = preg_replace($search, '$@KAHOODLEVIEWBYID*$2@$', $content);
61 |
62 | return $content;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/tests/behat/basic_actions.feature:
--------------------------------------------------------------------------------
1 | @mod @mod_kahoodle
2 | Feature: Basic operations with module Kahoodle
3 | In order to use Kahoodle in Moodle
4 | As a teacher and student
5 | I need to be able to modify and view Kahoodle
6 |
7 | Background:
8 | Given the following "users" exist:
9 | | username | firstname | lastname | email |
10 | | student1 | Sam | Student | student1@example.com |
11 | | teacher1 | Terry | Teacher | teacher1@example.com |
12 | And the following "courses" exist:
13 | | fullname | shortname | category |
14 | | Course 1 | C1 | 0 |
15 | And the following "course enrolments" exist:
16 | | user | course | role |
17 | | student1 | C1 | student |
18 | | teacher1 | C1 | editingteacher |
19 |
20 | @javascript
21 | Scenario: Viewing Kahoodle module and activities index page
22 | Given the following "activities" exist:
23 | | activity | name | course | intro | section |
24 | | kahoodle | Test module name | C1 | Test module description | 1 |
25 | When I log in as "teacher1"
26 | And I am on "Course 1" course homepage with editing mode on
27 | And I add the "Activities" block
28 | And I log out
29 | And I log in as "student1"
30 | And I am on "Course 1" course homepage
31 | And I click on "Test module name" "link" in the "region-main" "region"
32 | And I should see "Test module description"
33 | And I am on "Course 1" course homepage
34 | And I click on "Kahoodles" "link" in the "Activities" "block"
35 | And I should see "1" in the "Test module name" "table_row"
36 |
37 | @javascript
38 | Scenario: Creating and updating Kahoodle module
39 | When I log in as "teacher1"
40 | And I am on "Course 1" course homepage with editing mode on
41 | And I add a "Kahoodle" to section 1 using the activity chooser
42 | And I set the following fields to these values:
43 | | Name | Test module name |
44 | | Description | Test module description |
45 | | Display description on course page | 1 |
46 | And I press "Save and return to course"
47 | And I open "Test module name" actions menu
48 | And I click on "Edit settings" "link" in the "Test module name" activity
49 | And I set the field "Name" to "Test module new name"
50 | And I press "Save and return to course"
51 | And I should see "Test module new name"
52 | And I should not see "Test module name"
53 | And I should see "Test module description"
54 |
--------------------------------------------------------------------------------
/classes/output/renderer.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace mod_kahoodle\output;
18 |
19 | use context_module;
20 | use core\output\html_writer;
21 | use mod_kahoodle\api;
22 |
23 | /**
24 | * Renderer for Kahoodle
25 | *
26 | * @package mod_kahoodle
27 | * @copyright Marina Glancy
28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 | */
30 | class renderer extends \plugin_renderer_base {
31 | /**
32 | * Summary of render_game
33 | *
34 | * @param api $api
35 | * @return string
36 | */
37 | public function game(api $api) {
38 | $data = $api->get_game_state();
39 | $context = $api->get_context();
40 | $attrs = ['data-cmid' => $api->get_cm()->id, 'data-contextid' => $context->id];
41 | if ($api->can_transition()) {
42 | $channel = new \tool_realtime\channel($context, 'mod_kahoodle', 'gamemaster', 0);
43 | $channel->subscribe();
44 | } else if ($playerid = $api->get_player_id()) {
45 | $channel = new \tool_realtime\channel($context, 'mod_kahoodle', 'game', $playerid);
46 | $channel->subscribe();
47 | $channel2 = new \tool_realtime\channel($context, 'mod_kahoodle', 'game', 0);
48 | $channel2->subscribe();
49 | $attrs['playerid'] = $playerid;
50 | }
51 | $this->page->requires->js_call_amd('mod_kahoodle/game', 'init');
52 | $res = html_writer::start_div('', ['id' => 'mod_kahoodle_game'] + $attrs)
53 | . $this->render_from_template($data['template'], $data['data'])
54 | . html_writer::end_div();
55 |
56 | if ($api->can_transition()) {
57 | $reseturl = new \moodle_url("/mod/kahoodle/view.php",
58 | ['id' => $api->get_cm()->id, 'action' => 'reset', 'sesskey' => sesskey()]);
59 | $res .= "