Skip to content

Commit

Permalink
Basic form for creating and editing questions #520123
Browse files Browse the repository at this point in the history
  • Loading branch information
mkassaei committed May 30, 2024
1 parent ebd4b1c commit 0b6a70f
Show file tree
Hide file tree
Showing 18 changed files with 2,225 additions and 0 deletions.
118 changes: 118 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: Moodle plugin CI
on: [push, pull_request]

jobs:
test:
runs-on: 'ubuntu-latest'
strategy:
fail-fast: false
matrix:
include:
- php: '8.3'
moodle-branch: 'master'
database: 'pgsql'
- php: '8.3'
moodle-branch: 'MOODLE_404_STABLE'
database: 'pgsql'
- php: '8.2'
moodle-branch: 'MOODLE_403_STABLE'
database: 'mariadb'

services:
postgres:
image: postgres:13
env:
POSTGRES_USER: 'postgres'
POSTGRES_HOST_AUTH_METHOD: 'trust'
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 3
ports:
- 5432:5432

mariadb:
image: mariadb:10
env:
MYSQL_USER: 'root'
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
MYSQL_CHARACTER_SET_SERVER: "utf8mb4"
MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci"
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3

steps:
- name: Checkout
uses: actions/checkout@v3
with:
path: plugin

- name: Setup PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.extensions }}
ini-values: max_input_vars=5000
coverage: none

- name: Initialise moodle-plugin-ci
run: |
composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4
echo $(cd ci/bin; pwd) >> $GITHUB_PATH
echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
sudo locale-gen en_AU.UTF-8
echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV
- name: Install moodle-plugin-ci
run: |
moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1
env:
DB: ${{ matrix.database }}
MOODLE_BRANCH: ${{ matrix.moodle-branch }}

- name: PHP Lint
if: ${{ always() }}
run: moodle-plugin-ci phplint

- name: PHP Copy/Paste Detector
continue-on-error: true # This step will show errors but will not fail.
if: ${{ always() }}
run: moodle-plugin-ci phpcpd

- name: PHP Mess Detector
if: ${{ always() }}
run: moodle-plugin-ci phpmd

- name: Moodle Code Checker
if: ${{ always() }}
run: moodle-plugin-ci phpcs --max-warnings 0

- name: Moodle PHPDoc Checker
continue-on-error: true # This step will show errors but will not fail.
if: ${{ always() }}
run: moodle-plugin-ci phpdoc

- name: Validating
if: ${{ always() }}
run: moodle-plugin-ci validate

- name: Check upgrade savepoints
if: ${{ always() }}
run: moodle-plugin-ci savepoints

- name: Mustache Lint
if: ${{ always() }}
run: moodle-plugin-ci mustache

- name: Grunt
run: moodle-plugin-ci grunt --max-lint-warnings 0

- name: PHPUnit tests
if: ${{ always() }}
run: moodle-plugin-ci phpunit --fail-on-warning

- name: Behat features
if: ${{ always() }}
run: moodle-plugin-ci behat --profile chrome
141 changes: 141 additions & 0 deletions classes/line.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php
// 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 <http://www.gnu.org/licenses/>.

namespace qtype_drawlines;

/**
* Represents a line objet of drawlines question.
*
* @package qtype_drawlines
* @copyright 2024 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class line {
/** @var int Number of lines to start with. */
const LINE_NUMBER_START = 1;

/** @var int Number of lines to add. */
const LINE_NUMBER_ADD = 2;

/** @var string linesegment (Line segment ---). */
const TYPE_LINE_SEGMENT ='linesegment';

/** @var string linesinglearrow (Single arrow -→). */
const TYPE_LINE_SINGLE_ARROW ='linesinglearrow';

/** @var string linedoublearrows (Double arrows ←--→). */
const TYPE_LINE_DOUBLE_ARROW ='linedoublearrows';

/** @var string lineinfinite (Infinite line --o--o--). */
const TYPE_LINE_INFINITE ='lineinfinite';


/** @var string lineinfinite (Infinite line --o--o--). */
const VALIDATE_ZONE_COORDINATES = "/([0-9]+),([0-9]+);([0-9]+)/";

/** @var int The line id. */
public $id;

/** @var int The id of the question. */
public $questionid;

/** @var int The line number. */
public $number;

/** @var string The line type. */
public $type;

/** @var string The label shows at the start of the line. */
public $labelstart;

/** @var string The label shows in the middle of the line. */
public $labelmiddle;

/** @var string The label shows at the end of the line. */
public $labelend;

/** @var string The line start zone position in 'xcenter,ycenter;radius' format.*/
public $zonestart;

/** @var string The line end zone position in 'xcenter,ycenter;radius' format.*/
public $zoneend;

/**
* Construct the line object.
*
* @param int $id
* @param int $questionid
* @param int $number
* @param string $type
* @param string $labelstart
* @param string $labelmiddle
* @param string $labelend
* @param string $zonestart
* @param string $zoneend
*/
public function __construct(int $id, int $questionid, int $number, string $type,
string $labelstart, string $labelmiddle, string $labelend,
string $zonestart, string $zoneend) {

$this->id = $id;
$this->questionid = $questionid;
$this->number = $number;
$this->type = $type;
$this->labelstart = $labelstart;
$this->labelmiddle = $labelmiddle;
$this->labelend = $labelend;
$this->zonestart = $zonestart;
$this->zoneend = $zoneend;
}

/**
* Return an assosiative array of line types as key => value,
* where key is stored name in the database and Value is the displayed name in question form.
*
* @return array
*/
public static function get_line_types(): array {
return [
self::TYPE_LINE_SEGMENT => get_string(self::TYPE_LINE_SEGMENT, 'qtype_drawlines'),
self::TYPE_LINE_SINGLE_ARROW => get_string(self::TYPE_LINE_SINGLE_ARROW , 'qtype_drawlines'),
self::TYPE_LINE_DOUBLE_ARROW => get_string(self::TYPE_LINE_DOUBLE_ARROW, 'qtype_drawlines'),
self::TYPE_LINE_INFINITE => get_string(self::TYPE_LINE_INFINITE, 'qtype_drawlines'),
];
}

/**
* Validate the zone coordinates for Start or End zone of a line.
* The correct format is x,y;r where x,y are the coordinates of the centre of a circle and r is the radius.
*
* @param string $zone
* @return bool
*/
public static function is_zone_coordinates_valid(string $zone): bool {
preg_match_all(self::VALIDATE_ZONE_COORDINATES, $zone, $matches);
// If the zone is empty return fale
if (trim($zone) === '') {
return false;
}
// if there is no match return false.
foreach ($matches as $i => $match) {
if (empty($matches[$i])) {
return false;
}
}
// Match found.
return true;
}
}
81 changes: 81 additions & 0 deletions classes/privacy/provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
// 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 <http://www.gnu.org/licenses/>.

/**
* Privacy Subsystem implementation for qtype_drawlines.
*
* @package qtype_drawlines
* @copyright 2024 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace qtype_drawlines\privacy;

use core_privacy\local\metadata\collection;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;

/**
* Privacy Subsystem for qtype_drawlines implementing user_preference_provider.
*
* @copyright 2024 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
// This component has data.
// We need to return default options that have been set a user preferences.
\core_privacy\local\metadata\provider,
\core_privacy\local\request\user_preference_provider
{

/**
* Returns meta data about this system.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection) : collection {
$collection->add_user_preference('qtype_drawlines_defaultmark', 'privacy:preference:defaultmark');
$collection->add_user_preference('qtype_drawlines_penalty', 'privacy:preference:penalty');
$collection->add_user_preference('qtype_drawlines_grademethod', 'privacy:preference:grademethod');
return $collection;
}

/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$preference = get_user_preferences('qtype_drawlines_defaultmark', null, $userid);
if (null !== $preference) {
$desc = get_string('privacy:preference:defaultmark', 'qtype_drawlines');
writer::export_user_preference('qtype_drawlines', 'defaultmark', $preference, $desc);
}

$preference = get_user_preferences('qtype_drawlines_penalty', null, $userid);
if (null !== $preference) {
$desc = get_string('privacy:preference:penalty', 'qtype_drawlines');
writer::export_user_preference('qtype_drawlines', 'penalty', transform::percentage($preference), $desc);
}

$preference = get_user_preferences('qtype_oumatrix_grademethod', null, $userid);
if (null !== $preference) {
$desc = get_string('privacy:preference:grademethod', 'qtype_drawlines');
writer::export_user_preference('qtype_drawlines', 'grademethod', transform::yesno($preference), $desc);
}
}
}
46 changes: 46 additions & 0 deletions db/install.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="question/type/drawlines/db" VERSION="2024041600" COMMENT="XMLDB file for Moodle question/type/drawlines."
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd">
<TABLES>
<TABLE NAME="qtype_drawlines_options" COMMENT="Defines options for drawlines questions">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="grademethod" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="partial" SEQUENCE="false" COMMENT="Whether grading is partial or all-or-nothing"/>
<FIELD NAME="correctfeedback" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any correct response."/>
<FIELD NAME="correctfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="partiallycorrectfeedback" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any partially correct response."/>
<FIELD NAME="partiallycorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="incorrectfeedback" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any incorrect response."/>
<FIELD NAME="incorrectfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="shownumcorrect" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="showmisplaced" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="questionid" TYPE="foreign" FIELDS="questionid" REFTABLE="question" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="qtype_drawlines_lines" COMMENT="Settings for the line object in qtype_drawlines_lines table.">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="number" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="line number, lines are numbered sequentially 1, 2, 3, ... in a given question"/>
<FIELD NAME="type" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Whether the line is a 'line segment', 'single arrow', double arrow' or 'infinite line'"/>
<FIELD NAME="labelstart" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The line label is displayed at the start of the line."/>
<FIELD NAME="labelmiddle" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The line label is displayed on the middle of the line."/>
<FIELD NAME="labelend" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The line label is displayed at the end of the line."/>
<FIELD NAME="zonestart" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Coordinates within a circle in 'xcenter,ycenter;radius' format."/>
<FIELD NAME="zoneend" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Coordinates within a circle in 'xcenter,ycenter;radius' format."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="questionid" TYPE="foreign" FIELDS="questionid" REFTABLE="question" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="questionid-number" UNIQUE="true" FIELDS="questionid, number" COMMENT="Unique index for a line within a question."/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
Loading

0 comments on commit 0b6a70f

Please sign in to comment.