├── .github └── workflows │ ├── moodle-ci.yml │ └── moodle-release.yml ├── README.md ├── amd ├── build │ ├── radiobuttondeselect.min.js │ └── radiobuttondeselect.min.js.map └── src │ └── radiobuttondeselect.js ├── backup └── moodle2 │ ├── backup_ratingallocate_activity_stepslib.php │ ├── backup_ratingallocate_activity_task.class.php │ ├── backup_restore_helper.php │ ├── restore_ratingallocate_activity_stepslib.php │ └── restore_ratingallocate_activity_task.class.php ├── classes ├── algorithm_status.php ├── allocations_table.php ├── choice_importer.php ├── completion │ └── custom_completion.php ├── dates.php ├── event │ ├── all_ratings_deleted.php │ ├── allocation_published.php │ ├── allocation_statistics_viewed.php │ ├── allocation_table_viewed.php │ ├── distribution_triggered.php │ ├── index_viewed.php │ ├── manual_allocation_saved.php │ ├── rating_deleted.php │ ├── rating_saved.php │ ├── rating_viewed.php │ ├── ratingallocate_viewed.php │ └── ratings_and_allocation_table_viewed.php ├── privacy │ └── provider.php ├── ratingallocate_observer.php ├── ratings_and_allocations_table.php └── task │ ├── cron_task.php │ ├── distribute_unallocated_task.php │ └── send_distribution_notification.php ├── db ├── access.php ├── db_structure.php ├── events.php ├── install.php ├── install.xml ├── log.php ├── messages.php ├── tasks.php ├── uninstall.php └── upgrade.php ├── form_manual_allocation.php ├── form_modify_choice.php ├── form_upload_choices.php ├── grade.php ├── index.php ├── lang └── en │ └── ratingallocate.php ├── lib.php ├── locallib.php ├── mod_form.php ├── pix ├── checkbox-selected.svg ├── checkbox.svg ├── icon.png ├── icon.svg └── monologo.svg ├── renderable.php ├── renderer.php ├── settings.php ├── solver ├── edmonds-karp.php ├── export_lp_solve.php ├── ford-fulkerson-koegel.php └── solver-template.php ├── strategy ├── strategy01_yes_no.php ├── strategy02_yes_maybe_no.php ├── strategy03_lickert.php ├── strategy04_points.php ├── strategy05_order.php ├── strategy06_tickyes.php ├── strategy_template.php └── strategy_template_options.php ├── styles.css ├── tests ├── backup_restore_test.php ├── behat │ ├── allocation_status.feature │ ├── behat_mod_ratingallocate.php │ ├── completion_condition_allocation.feature │ ├── completion_condition_vote.feature │ ├── completion_manual.feature │ ├── defaultratings.feature │ ├── manual_allocation.feature │ ├── mod_form.feature │ ├── ratings.feature │ ├── select_strategy.feature │ ├── validate_rating.feature │ └── visibile_calendar_events.feature ├── cron_test.php ├── generator │ └── lib.php ├── locallib_test.php ├── mod_generator_test.php ├── mod_ratingallocate_allocate_unrated_test.php ├── mod_ratingallocate_choice_groups_test.php ├── mod_ratingallocate_choice_importer_test.php ├── mod_ratingallocate_notification_test.php ├── mod_ratingallocate_privacy_provider_test.php ├── mod_ratingallocate_processor_test.php ├── mod_ratingallocate_solver_test.php ├── mod_ratingallocate_status_test.php └── mod_ratingallocate_strategy_test.php ├── version.php └── view.php /.github/workflows/moodle-ci.yml: -------------------------------------------------------------------------------- 1 | name: Moodle Plugin CI 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | static: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | php: ['8.3'] 12 | moodle-branch: ['MOODLE_405_STABLE'] 13 | database: ['pgsql'] 14 | 15 | steps: 16 | - name: Start PostgreSQL 17 | run: docker run -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:14 18 | 19 | - name: Check out repository code 20 | uses: actions/checkout@v4 21 | with: 22 | path: plugin 23 | 24 | - name: Setup PHP ${{ matrix.php }} 25 | uses: shivammathur/setup-php@v2 26 | with: 27 | php-version: ${{ matrix.php }} 28 | ini-values: max_input_vars=5000 29 | coverage: none 30 | 31 | - name: Initialise moodle-plugin-ci 32 | run: | 33 | composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 34 | echo $(cd ci/bin; pwd) >> $GITHUB_PATH 35 | echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH 36 | sudo locale-gen en_AU.UTF-8 37 | echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV 38 | 39 | - name: Install moodle-plugin-ci 40 | run: | 41 | moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 --no-init 42 | env: 43 | DB: ${{ matrix.database }} 44 | MOODLE_BRANCH: ${{ matrix.moodle-branch }} 45 | 46 | - name: PHP Lint 47 | if: ${{ always() }} 48 | run: moodle-plugin-ci phplint 49 | 50 | - name: PHP Mess Detector 51 | if: ${{ always() }} 52 | run: moodle-plugin-ci phpmd 53 | 54 | - name: Moodle Code Checker 55 | if: ${{ always() }} 56 | run: moodle-plugin-ci codechecker 57 | 58 | - name: Moodle PHPDoc Checker 59 | if: ${{ always() }} 60 | run: moodle-plugin-ci phpdoc 61 | continue-on-error: true 62 | 63 | - name: Validating 64 | if: ${{ always() }} 65 | run: moodle-plugin-ci validate 66 | 67 | - name: Check upgrade savepoints 68 | if: ${{ always() }} 69 | run: moodle-plugin-ci savepoints 70 | 71 | - name: Mustache Lint 72 | if: ${{ always() }} 73 | run: moodle-plugin-ci mustache 74 | 75 | - name: Grunt 76 | if: ${{ always() }} 77 | run: moodle-plugin-ci grunt 78 | 79 | test: 80 | runs-on: ubuntu-latest 81 | needs: static 82 | 83 | strategy: 84 | fail-fast: false 85 | matrix: 86 | php: ['8.0', '8.1', '8.2', '8.3'] 87 | moodle-branch: [ 88 | 'MOODLE_401_STABLE', 89 | 'MOODLE_402_STABLE', 90 | 'MOODLE_403_STABLE', 91 | 'MOODLE_404_STABLE', 92 | 'MOODLE_405_STABLE' 93 | ] 94 | database: ['mariadb', 'pgsql'] 95 | exclude: 96 | - php: '8.0' 97 | moodle-branch: 'MOODLE_404_STABLE' 98 | - php: '8.0' 99 | moodle-branch: 'MOODLE_405_STABLE' 100 | - php: '8.2' 101 | moodle-branch: 'MOODLE_401_STABLE' 102 | - php: '8.3' 103 | moodle-branch: 'MOODLE_401_STABLE' 104 | - php: '8.3' 105 | moodle-branch: 'MOODLE_402_STABLE' 106 | - php: '8.3' 107 | moodle-branch: 'MOODLE_403_STABLE' 108 | include: 109 | - php: '7.4' 110 | moodle-branch: 'MOODLE_401_STABLE' 111 | database: 'pgsql' 112 | - php: '7.4' 113 | moodle-branch: 'MOODLE_401_STABLE' 114 | database: 'mariadb' 115 | 116 | steps: 117 | - name: Start MariaDB 118 | if: matrix.database == 'mariadb' 119 | run: docker run -p 3306:3306 -e MYSQL_USER=root -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mariadb:10 120 | 121 | - name: Start PostgreSQL 122 | if: matrix.database == 'pgsql' 123 | run: docker run -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:14 124 | 125 | - name: Check out repository code 126 | uses: actions/checkout@v4 127 | with: 128 | path: plugin 129 | 130 | - name: Setup PHP ${{ matrix.php }} 131 | uses: shivammathur/setup-php@v2 132 | with: 133 | php-version: ${{ matrix.php }} 134 | ini-values: max_input_vars=5000 135 | coverage: none 136 | 137 | - name: Initialise moodle-plugin-ci 138 | run: | 139 | composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 140 | echo $(cd ci/bin; pwd) >> $GITHUB_PATH 141 | echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH 142 | sudo locale-gen en_AU.UTF-8 143 | echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV 144 | 145 | - name: Install moodle-plugin-ci 146 | run: | 147 | moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 148 | env: 149 | DB: ${{ matrix.database }} 150 | MOODLE_BRANCH: ${{ matrix.moodle-branch }} 151 | 152 | - name: PHPUnit tests 153 | if: ${{ always() }} 154 | run: moodle-plugin-ci phpunit 155 | 156 | - name: Behat features 157 | if: ${{ always() }} 158 | run: moodle-plugin-ci behat --profile chrome --auto-rerun 0 159 | 160 | # This step allows to upload Behat faildump (screenshots) as workflow artifact, 161 | # so it can be downloaded and inspected. You do not need this step if you 162 | # are not running Behat test. Artifact will be retained for 7 days. 163 | - name: Upload Behat Faildump 164 | if: ${{ failure() && steps.behat.outcome == 'failure' }} 165 | uses: actions/upload-artifact@v4 166 | with: 167 | name: Behat Faildump (${{ join(matrix.*, ', ') }}) 168 | path: ${{ github.workspace }}/moodledata/behat_dump 169 | retention-days: 7 170 | if-no-files-found: ignore 171 | -------------------------------------------------------------------------------- /.github/workflows/moodle-release.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Whenever a new tag starting with "v" is pushed, add the tagged version 3 | # to the Moodle Plugins directory at https://moodle.org/plugins 4 | # 5 | # revision: 2021070201 6 | # Changed to be released on Github release with the release notes. 7 | # 8 | name: Releasing in the Plugins directory 9 | 10 | on: 11 | release: 12 | types: [ published ] 13 | 14 | defaults: 15 | run: 16 | shell: bash 17 | 18 | jobs: 19 | release-at-moodle-org: 20 | runs-on: ubuntu-latest 21 | env: 22 | PLUGIN: mod_ratingallocate 23 | CURL: curl -s 24 | ENDPOINT: https://moodle.org/webservice/rest/server.php 25 | TOKEN: ${{ secrets.MOODLE_ORG_TOKEN }} 26 | FUNCTION: local_plugins_add_version 27 | 28 | steps: 29 | - name: Call the service function 30 | id: add-version 31 | run: | 32 | TAGNAME="${{ github.event.release.tag_name }}" 33 | BODY="${{ github.event.release.body }}" 34 | ZIPURL="${{ github.event.release.zipball_url }}" 35 | RESPONSE=$(${CURL} ${ENDPOINT} --data-urlencode "wstoken=${TOKEN}" \ 36 | --data-urlencode "wsfunction=${FUNCTION}" \ 37 | --data-urlencode "moodlewsrestformat=json" \ 38 | --data-urlencode "frankenstyle=${PLUGIN}" \ 39 | --data-urlencode "zipurl=${ZIPURL}" \ 40 | --data-urlencode "vcssystem=git" \ 41 | --data-urlencode "vcsrepositoryurl=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" \ 42 | --data-urlencode "vcstag=${TAGNAME}" \ 43 | --data-urlencode "changelogurl=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commits/${TAGNAME}" \ 44 | --data-urlencode "altdownloadurl=${ZIPURL}" \ 45 | --data-urlencode "releasenotes=${BODY}" \ 46 | --data-urlencode "releasenotesformat=4") 47 | echo "response=${RESPONSE}" >> $GITHUB_OUTPUT 48 | - name: Evaluate the response 49 | id: evaluate-response 50 | env: 51 | RESPONSE: ${{ steps.add-version.outputs.response }} 52 | run: | 53 | jq <<< ${RESPONSE} 54 | jq --exit-status ".id" <<< ${RESPONSE} > /dev/null 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | moodle-mod_ratingallocate 2 | ============================ 3 | [![codecov](https://codecov.io/gh/learnweb/moodle-mod_ratingallocate/branch/master/graph/badge.svg)](https://codecov.io/gh/learnweb/moodle-mod_ratingallocate) 4 | 5 | Module which lets you add an activity to courses, in which users can rate choices. You may then distribute the users fairly to the choices by maximising overall 'hapiness' in terms 6 | of ratings. 7 | This may be an alternative to the choice activity or other first-come-first-served plugins. 8 | 9 | This plugin is based on previous work by Stefan Koegel and Alexander Bias, University of Ulm. 10 | 11 | Installation 12 | ============ 13 | This is an activity plugin and should go into ``mod/ratingallocate``. 14 | Obtain this plugin from https://moodle.org/plugins/view/mod_ratingallocate. 15 | 16 | Usage 17 | ============ 18 | 19 | Add an activity instance. Set mandatory parameters. These are timespan, in which users can give ratings, and the strategy, 20 | which form will be presented to the users to rate. 21 | Next you can add choices, which the users will have to rate later on. 22 | After the rating period has finished, you can allocate the users automatically or manually. Upon publishing the results, users will be able to see which choice they have been 23 | allocated to. 24 | For more information please visit the [moodle wiki](https://docs.moodle.org/31/en/Ratingallocate). 25 | 26 | Moodle version 27 | ====================== 28 | The plugin is continously tested with all moodle versions, which are security supported by the moodle headquarter. 29 | Therefore, Travis uses the most current release to build a test instance and run the behat and unit tests on them. 30 | In addition to all stable branches the version is also tested against the master branch to support early adopters. 31 | 32 | Algorithm 33 | ========= 34 | This module uses a modified Edmonds-karp algorithm to solve the minimum-cost flow problem. Augmenting paths are found using Bellman-Ford, but the user ratings are multiplied with 35 | -1 first. 36 | 37 | Worst-Case complexity is O(m^2n^2) with m,n being number of edges (#users+#choices+#ratings_users_gave) and nodes (2+#users+#choices) in the graph. 38 | Distributing 500 users to 21 choices takes around 11sec. 39 | 40 | Changelog 41 | ========= 42 | The changes for every release are listed here: https://github.com/learnweb/moodle-mod_ratingallocate/wiki/Changelog. 43 | -------------------------------------------------------------------------------- /amd/build/radiobuttondeselect.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class manages the deselection of radiobuttons, which is necessary for deleting allocations 3 | * 4 | * @module mod_ratingallocate/radiobuttondeselect 5 | * @copyright 2017 Tobias Reischmann 6 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 7 | */ 8 | define("mod_ratingallocate/radiobuttondeselect",["jquery"],(function($){return{init:function(){$(".ratingallocate_checkbox_label:checked").on("click",this.deselect(this)),$(".ratingallocate_checkbox_label:not(:checked)").on("click",this.callrefresh(this))},deselect:function(that){return function(event){event.target.checked&&(event.target.checked=!1),that.refresh(that)}},refresh:function(that){$(".ratingallocate_checkbox_label").off("click"),$(".ratingallocate_checkbox_label:checked").on("click",that.deselect(that)),$(".ratingallocate_checkbox_label:not(:checked)").on("click",that.callrefresh(that))},callrefresh:function(that){return function(){that.refresh(that)}}}})); 9 | 10 | //# sourceMappingURL=radiobuttondeselect.min.js.map -------------------------------------------------------------------------------- /amd/build/radiobuttondeselect.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"radiobuttondeselect.min.js","sources":["../src/radiobuttondeselect.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This class manages the deselection of radiobuttons, which is necessary for deleting allocations\n *\n * @module mod_ratingallocate/radiobuttondeselect\n * @copyright 2017 Tobias Reischmann\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery'], function ($) {\n\n /**\n * @alias module:mod_ratingallocate/radiobuttondeselect\n */\n var t = {\n\n /**\n * Create the click events for deselecting radiobuttons.\n */\n init: function () {\n $('.ratingallocate_checkbox_label:checked').on('click', this.deselect(this));\n $('.ratingallocate_checkbox_label:not(:checked)').on('click', this.callrefresh(this));\n },\n\n deselect: function (that) {\n return function (event) {\n if (event.target.checked) {\n event.target.checked = false;\n }\n that.refresh(that);\n };\n },\n\n refresh: function (that) {\n $('.ratingallocate_checkbox_label').off('click');\n $('.ratingallocate_checkbox_label:checked').on('click', that.deselect(that));\n $('.ratingallocate_checkbox_label:not(:checked)').on('click', that.callrefresh(that));\n },\n\n callrefresh: function (that) {\n return function () {\n that.refresh(that);\n };\n }\n };\n\n return t;\n});\n"],"names":["define","$","init","on","this","deselect","callrefresh","that","event","target","checked","refresh","off"],"mappings":";;;;;;;AAsBAA,gDAAO,CAAC,WAAW,SAAUC,SAKjB,CAKJC,KAAM,WACFD,EAAE,0CAA0CE,GAAG,QAASC,KAAKC,SAASD,OACtEH,EAAE,gDAAgDE,GAAG,QAASC,KAAKE,YAAYF,QAGnFC,SAAU,SAAUE,aACT,SAAUC,OACTA,MAAMC,OAAOC,UACbF,MAAMC,OAAOC,SAAU,GAE3BH,KAAKI,QAAQJ,QAIrBI,QAAS,SAAUJ,MACfN,EAAE,kCAAkCW,IAAI,SACxCX,EAAE,0CAA0CE,GAAG,QAASI,KAAKF,SAASE,OACtEN,EAAE,gDAAgDE,GAAG,QAASI,KAAKD,YAAYC,QAGnFD,YAAa,SAAUC,aACZ,WACHA,KAAKI,QAAQJ"} -------------------------------------------------------------------------------- /amd/src/radiobuttondeselect.js: -------------------------------------------------------------------------------- 1 | // This file is part of Moodle - http://moodle.org/ 2 | // 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 . 15 | 16 | /** 17 | * This class manages the deselection of radiobuttons, which is necessary for deleting allocations 18 | * 19 | * @module mod_ratingallocate/radiobuttondeselect 20 | * @copyright 2017 Tobias Reischmann 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | define(['jquery'], function ($) { 24 | 25 | /** 26 | * @alias module:mod_ratingallocate/radiobuttondeselect 27 | */ 28 | var t = { 29 | 30 | /** 31 | * Create the click events for deselecting radiobuttons. 32 | */ 33 | init: function () { 34 | $('.ratingallocate_checkbox_label:checked').on('click', this.deselect(this)); 35 | $('.ratingallocate_checkbox_label:not(:checked)').on('click', this.callrefresh(this)); 36 | }, 37 | 38 | deselect: function (that) { 39 | return function (event) { 40 | if (event.target.checked) { 41 | event.target.checked = false; 42 | } 43 | that.refresh(that); 44 | }; 45 | }, 46 | 47 | refresh: function (that) { 48 | $('.ratingallocate_checkbox_label').off('click'); 49 | $('.ratingallocate_checkbox_label:checked').on('click', that.deselect(that)); 50 | $('.ratingallocate_checkbox_label:not(:checked)').on('click', that.callrefresh(that)); 51 | }, 52 | 53 | callrefresh: function (that) { 54 | return function () { 55 | that.refresh(that); 56 | }; 57 | } 58 | }; 59 | 60 | return t; 61 | }); 62 | -------------------------------------------------------------------------------- /backup/moodle2/backup_ratingallocate_activity_task.class.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | defined('MOODLE_INTERNAL') || die(); 18 | 19 | require_once($CFG->dirroot . '/mod/ratingallocate/backup/moodle2/backup_ratingallocate_activity_stepslib.php'); 20 | 21 | /** 22 | * Ratingallocate backup task that provides all the settings and steps to perform one 23 | * complete backup of the activity. 24 | * 25 | * @package mod_ratingallocate 26 | * @copyright 2014 C. Usener 27 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 | */ 29 | class backup_ratingallocate_activity_task extends backup_activity_task { 30 | 31 | /** 32 | * Define (add) particular settings this activity can have 33 | */ 34 | protected function define_my_settings() { 35 | // No particular settings for this activity. 36 | } 37 | 38 | /** 39 | * Define (add) particular steps this activity can have 40 | */ 41 | protected function define_my_steps() { 42 | // Ratingallocate only has one structure step. 43 | $this->add_step(new backup_ratingallocate_activity_structure_step('ratingallocate_structure', 'ratingallocate.xml')); 44 | } 45 | 46 | /** 47 | * Code the transformations to perform in the activity in 48 | * order to get transportable (encoded) links 49 | */ 50 | public static function encode_content_links($content) { 51 | return $content; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /backup/moodle2/backup_restore_helper.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Backup restore helper. 19 | * 20 | * @package mod_ratingallocate 21 | * @subpackage backup-moodle2 22 | * @copyright 2014 C. Usener 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | /** 27 | * Get fields for tableclass 28 | * 29 | * @param $class 30 | * @return array 31 | * @throws ReflectionException 32 | */ 33 | function get_fields_for_tableclass($class) { 34 | $class = new ReflectionClass($class); 35 | $constants = $class->getConstants(); 36 | $keystoremove = ['ID', 'TABLE']; 37 | foreach ($constants as $key => $value) { 38 | if (count(array_intersect([$key], $keystoremove)) > 0) { 39 | unset($constants[$key]); 40 | } 41 | } 42 | return array_values($constants); 43 | } 44 | 45 | /** 46 | * Get tablename for tableclass. 47 | * 48 | * @param $class 49 | * @return mixed 50 | * @throws ReflectionException 51 | */ 52 | function get_tablename_for_tableclass($class) { 53 | $class = new ReflectionClass($class); 54 | $constants = $class->getConstants(); 55 | return $constants['TABLE']; 56 | } 57 | 58 | /** 59 | * Get id for tableclass. 60 | * 61 | * @param $class 62 | * @return array 63 | * @throws ReflectionException 64 | */ 65 | function get_id_for_tableclass($class) { 66 | $class = new ReflectionClass($class); 67 | $constants = $class->getConstants(); 68 | return [$constants['ID']]; 69 | } 70 | -------------------------------------------------------------------------------- /backup/moodle2/restore_ratingallocate_activity_task.class.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | defined('MOODLE_INTERNAL') || die(); 18 | 19 | /** 20 | * Ratingallocate restore task that provides all the settings and steps to perform one 21 | * complete restore of the activity. 22 | * 23 | * @package moodlecore 24 | * @subpackage backup-moodle2 25 | * @copyright 2014 C. Usener 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | require_once($CFG->dirroot . '/mod/ratingallocate/backup/moodle2/restore_ratingallocate_activity_stepslib.php'); 29 | 30 | /** 31 | * Restore ratingallocate activity class 32 | * 33 | * @package mod_ratingallocate 34 | * @copyright 214 C. Usener 35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 | */ 37 | class restore_ratingallocate_activity_task extends restore_activity_task { 38 | 39 | /** 40 | * Define (add) particular settings this activity can have 41 | */ 42 | protected function define_my_settings() { 43 | // No particular settings for this activity. 44 | } 45 | 46 | /** 47 | * Define (add) particular steps this activity can have 48 | */ 49 | protected function define_my_steps() { 50 | // Ratingallocate only has one structure step. 51 | $this->add_step(new restore_ratingallocate_activity_structure_step('ratingallocate_structure', 'ratingallocate.xml')); 52 | } 53 | 54 | /** 55 | * Define the contents in the activity that must be 56 | * processed by the link decoder 57 | */ 58 | public static function define_decode_contents() { 59 | $contents = []; 60 | 61 | return $contents; 62 | } 63 | 64 | /** 65 | * Define the decoding rules for links belonging 66 | * to the activity to be executed by the link decoder 67 | */ 68 | public static function define_decode_rules() { 69 | $rules = []; 70 | 71 | return $rules; 72 | } 73 | 74 | /** 75 | * Define the restore log rules that will be applied 76 | * by the {@link restore_logs_processor} when restoring 77 | * ratingallocate logs. 78 | * It must return one array 79 | * of {@link restore_log_rule} objects 80 | */ 81 | public static function define_restore_log_rules() { 82 | $rules = []; 83 | 84 | return $rules; 85 | } 86 | 87 | /** 88 | * Define the restore log rules that will be applied 89 | * by the {@link restore_logs_processor} when restoring 90 | * course logs. 91 | * It must return one array 92 | * of {@link restore_log_rule} objects 93 | * 94 | * Note this rules are applied when restoring course logs 95 | * by the restore final task, but are defined here at 96 | * activity level. All them are rules not linked to any module instance (cmid = 0) 97 | */ 98 | public static function define_restore_log_rules_for_course() { 99 | $rules = []; 100 | return $rules; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /classes/algorithm_status.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_ratingallocate; 18 | /** 19 | * The different status a ratingallocate object can be in according to its algorithm run. 20 | * 21 | * @package mod_ratingallocate 22 | * @copyright 2015 Tobias Reischmann 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | class algorithm_status { 26 | /** 27 | * Algorithm did not finish correctly. 28 | */ 29 | const FAILURE = -1; 30 | /** 31 | * Default status for new instances. 32 | */ 33 | const NOTSTARTED = 0; 34 | /** 35 | * Algorithm is currently running. 36 | */ 37 | const RUNNING = 1; 38 | /** 39 | * Algorithm finished correctly. 40 | */ 41 | const FINISHED = 2; 42 | } 43 | -------------------------------------------------------------------------------- /classes/completion/custom_completion.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | declare(strict_types=1); 18 | 19 | namespace mod_ratingallocate\completion; 20 | 21 | use context_module; 22 | use core_completion\activity_custom_completion; 23 | 24 | /** 25 | * Activity custom completion subclass for the ratingallocate activity. 26 | * 27 | * Class for defining the custom completion rules of ratingallocate and fetching the completion statuses 28 | * of the custom completion rules for a given ratingallocate instance and a user. 29 | * 30 | * @package mod_ratingallocate 31 | * @copyright Irina Hoppe Uni Münster 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | */ 34 | class custom_completion extends activity_custom_completion { 35 | 36 | /** 37 | * Fetches the completion state for a given completion rule. 38 | * 39 | * @param string $rule The completion rule. 40 | * @return int The completion state. 41 | * @throws \moodle_exception 42 | */ 43 | public function get_state(string $rule): int { 44 | global $DB; 45 | $status = false; 46 | $this->validate_rule($rule); 47 | 48 | $userid = $this->userid; 49 | $instance = $this->cm->instance; 50 | 51 | if (!$DB->get_record('ratingallocate', ['id' => $instance])) { 52 | throw new \moodle_exception('Unable to find ratingallocate instance with id ' . $instance); 53 | } 54 | 55 | if ($rule == 'completionvote') { 56 | $sql = "SELECT * FROM {ratingallocate_ratings} r INNER JOIN {ratingallocate_choices} c on r.choiceid=c.id " . 57 | "WHERE r.userid= :userid AND c.ratingallocateid= :ratingallocateid AND c.active=1"; 58 | $votesofuser = $DB->get_records_sql($sql, ['userid' => $userid, 'ratingallocateid' => $instance]); 59 | $status = count($votesofuser) > 0; 60 | } else if ($rule == 'completionallocation') { 61 | $sql = "SELECT * FROM {ratingallocate_allocations} a INNER JOIN {ratingallocate_choices} c 62 | ON a.choiceid = c.id WHERE userid= :userid AND a.ratingallocateid= :ratingallocateid AND c.active=1"; 63 | $allocationsofuser = $DB->get_records_sql($sql, ['userid' => $userid, 'ratingallocateid' => $instance]); 64 | $status = count($allocationsofuser) > 0; 65 | } 66 | 67 | return $status ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE; 68 | } 69 | 70 | /** 71 | * Fetch the list of custom completion rules that this module defines. 72 | * 73 | * @return array 74 | */ 75 | public static function get_defined_custom_rules(): array { 76 | return [ 77 | 'completionvote', 78 | 'completionallocation', 79 | ]; 80 | } 81 | 82 | /** 83 | * Returns an associative array of the descriptions of custom completion rules. 84 | * 85 | * @return array 86 | */ 87 | public function get_custom_rule_descriptions(): array { 88 | return [ 89 | 'completionvote' => get_string('completionvote_desc', RATINGALLOCATE_MOD_NAME), 90 | 'completionallocation' => get_string('completionallocation_desc', RATINGALLOCATE_MOD_NAME), 91 | ]; 92 | } 93 | 94 | /** 95 | * Returns an array of all completion rules, in the order they should be displayed to users. 96 | * 97 | * @return array 98 | */ 99 | public function get_sort_order(): array { 100 | return [ 101 | 'completionview', 102 | 'completionvote', 103 | 'completionallocation', 104 | ]; 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /classes/dates.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains the class for fetching the important dates in mod_ratingallocate for a given module instance and a user. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2022 University of Vienna 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | declare(strict_types=1); 26 | 27 | namespace mod_ratingallocate; 28 | 29 | use core\activity_dates; 30 | 31 | /** 32 | * Class for fetching the important dates in mod_ratingallocate for a given module instance and a user. 33 | * 34 | * @copyright 2022 Jakob Mischke 35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 | */ 37 | class dates extends activity_dates { 38 | /** 39 | * Returns a list of important dates in mod_ratingallocate 40 | * 41 | * @return array 42 | */ 43 | protected function get_dates(): array { 44 | global $DB; 45 | 46 | $timeopen = $this->cm->customdata['accesstimestart'] ?? null; 47 | $timeclose = $this->cm->customdata['accesstimestop'] ?? null; 48 | 49 | $now = time(); 50 | $dates = []; 51 | 52 | if ($timeopen) { 53 | $openlabelid = $timeopen > $now ? 'activitydate:opens' : 'activitydate:opened'; 54 | $dates[] = [ 55 | 'label' => get_string($openlabelid, 'core_course'), 56 | 'timestamp' => (int) $timeopen, 57 | ]; 58 | } 59 | 60 | if ($timeclose) { 61 | $closelabelid = $timeclose > $now ? 'activitydate:closes' : 'activitydate:closed'; 62 | $dates[] = [ 63 | 'label' => get_string($closelabelid, 'core_course'), 64 | 'timestamp' => (int) $timeclose, 65 | ]; 66 | } 67 | 68 | return $dates; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /classes/event/all_ratings_deleted.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate rating_deleted event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2020 Robin Tschudi 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | namespace mod_ratingallocate\event; 25 | 26 | /** 27 | * The mod_ratingallocate rating_deleted event class. 28 | * 29 | * @copyright 2020 Robin Tschudi 30 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 | **/ 32 | class all_ratings_deleted extends \core\event\base { 33 | 34 | /** 35 | * Create simple all_ratings_deleted event. 36 | * @param $modulecontext 37 | * @param $ratingallocateid 38 | * @return \core\event\base 39 | * @throws \coding_exception 40 | */ 41 | public static function create_simple($modulecontext, $ratingallocateid) { 42 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 43 | } 44 | 45 | /** 46 | * Initialize data. 47 | * @return void 48 | */ 49 | protected function init() { 50 | $this->data['crud'] = 'd'; 51 | $this->data['edulevel'] = self::LEVEL_TEACHING; 52 | $this->data['objecttable'] = 'ratingallocate_ratings'; 53 | } 54 | 55 | /** 56 | * Get event name. 57 | * @return \lang_string|string 58 | * @throws \coding_exception 59 | */ 60 | public static function get_name() { 61 | return get_string('log_all_ratings_deleted', 'mod_ratingallocate'); 62 | } 63 | 64 | /** 65 | * Get event description. 66 | * @return \lang_string|string|null 67 | * @throws \coding_exception 68 | */ 69 | public function get_description() { 70 | return get_string('log_all_ratings_deleted_description', 'mod_ratingallocate', 71 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 72 | } 73 | 74 | /** 75 | * Get event url. 76 | * @return \moodle_url 77 | * @throws \moodle_exception 78 | */ 79 | public function get_url() { 80 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 81 | } 82 | 83 | /** 84 | * Get event mapping. 85 | * @return string[] 86 | */ 87 | public static function get_objectid_mapping() { 88 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 89 | } 90 | 91 | /** 92 | * No other mappings available. 93 | * @return false 94 | */ 95 | public static function get_other_mapping() { 96 | return false; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /classes/event/allocation_published.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate allocation_published event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate allocation_published event class. 29 | * 30 | * @property-read array $other { 31 | * Extra information about event. 32 | * 33 | * - array allocations: published allocations 34 | * } 35 | * 36 | * @since Moodle 2.7 37 | * @copyright 2014 Tobias Reischmann 38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 | **/ 40 | class allocation_published extends \core\event\base { 41 | 42 | /** 43 | * Create simple allocation_published event. 44 | * @param $modulecontext 45 | * @param $ratingallocateid 46 | * @return \core\event\base 47 | * @throws \coding_exception 48 | */ 49 | public static function create_simple($modulecontext, $ratingallocateid) { 50 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 51 | } 52 | 53 | /** 54 | * Initialize data. 55 | * @return void 56 | */ 57 | protected function init() { 58 | $this->data['crud'] = 'r'; 59 | $this->data['edulevel'] = self::LEVEL_TEACHING; 60 | $this->data['objecttable'] = 'ratingallocate'; 61 | } 62 | 63 | /** 64 | * Get event name. 65 | * @return \lang_string|string 66 | * @throws \coding_exception 67 | */ 68 | public static function get_name() { 69 | return get_string('log_allocation_published', 'mod_ratingallocate'); 70 | } 71 | 72 | /** 73 | * Get event description. 74 | * @return \lang_string|string|null 75 | * @throws \coding_exception 76 | */ 77 | public function get_description() { 78 | return get_string('log_allocation_published_description', 'mod_ratingallocate', 79 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 80 | } 81 | 82 | /** 83 | * Get event url. 84 | * @return \moodle_url 85 | * @throws \moodle_exception 86 | */ 87 | public function get_url() { 88 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 89 | } 90 | 91 | /** 92 | * Get event mapping. 93 | * @return string[] 94 | */ 95 | public static function get_objectid_mapping() { 96 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 97 | } 98 | 99 | /** 100 | * No other mappings available. 101 | * @return false 102 | */ 103 | public static function get_other_mapping() { 104 | return false; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /classes/event/allocation_statistics_viewed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate allocation_statistics_viewed event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate allocation_statistics_viewed event class. 29 | * 30 | * @since Moodle 2.7 31 | * @copyright 2015 Tobias Reischmann 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | **/ 34 | class allocation_statistics_viewed extends \core\event\base { 35 | 36 | /** 37 | * Create simple allocation_statistics_viewed event. 38 | * @param $modulecontext 39 | * @param $ratingallocateid 40 | * @return \core\event\base 41 | * @throws \coding_exception 42 | */ 43 | public static function create_simple($modulecontext, $ratingallocateid) { 44 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 45 | } 46 | 47 | /** 48 | * Initialize data. 49 | * @return void 50 | */ 51 | protected function init() { 52 | $this->data['crud'] = 'r'; 53 | $this->data['edulevel'] = self::LEVEL_TEACHING; 54 | $this->data['objecttable'] = 'ratingallocate'; 55 | } 56 | 57 | /** 58 | * Get event name. 59 | * @return \lang_string|string 60 | * @throws \coding_exception 61 | */ 62 | public static function get_name() { 63 | return get_string('log_allocation_statistics_viewed', 'mod_ratingallocate'); 64 | } 65 | 66 | /** 67 | * Get event description. 68 | * @return \lang_string|string|null 69 | * @throws \coding_exception 70 | */ 71 | public function get_description() { 72 | return get_string('log_allocation_statistics_viewed_description', 'mod_ratingallocate', 73 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 74 | } 75 | 76 | /** 77 | * Get event url. 78 | * @return \moodle_url 79 | * @throws \moodle_exception 80 | */ 81 | public function get_url() { 82 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 83 | } 84 | 85 | /** 86 | * Get event mapping. 87 | * @return string[] 88 | */ 89 | public static function get_objectid_mapping() { 90 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 91 | } 92 | 93 | /** 94 | * No other mappings available. 95 | * @return false 96 | */ 97 | public static function get_other_mapping() { 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /classes/event/allocation_table_viewed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate allocation_table_viewed event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate allocation_table_viewed event class. 29 | * 30 | * @since Moodle 2.7 31 | * @copyright 2014 Tobias Reischmann 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | **/ 34 | class allocation_table_viewed extends \core\event\base { 35 | 36 | /** 37 | * Create simple allocation_table_viewed event. 38 | * @param $modulecontext 39 | * @param $ratingallocateid 40 | * @return \core\event\base 41 | * @throws \coding_exception 42 | */ 43 | public static function create_simple($modulecontext, $ratingallocateid) { 44 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 45 | } 46 | 47 | /** 48 | * Initialize data. 49 | * @return void 50 | */ 51 | protected function init() { 52 | $this->data['crud'] = 'r'; 53 | $this->data['edulevel'] = self::LEVEL_TEACHING; 54 | $this->data['objecttable'] = 'ratingallocate'; 55 | } 56 | 57 | /** 58 | * Get event name. 59 | * @return \lang_string|string 60 | * @throws \coding_exception 61 | */ 62 | public static function get_name() { 63 | return get_string('log_allocation_table_viewed', 'mod_ratingallocate'); 64 | } 65 | 66 | /** 67 | * Get event description. 68 | * @return \lang_string|string|null 69 | * @throws \coding_exception 70 | */ 71 | public function get_description() { 72 | return get_string('log_allocation_table_viewed_description', 'mod_ratingallocate', 73 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 74 | } 75 | 76 | /** 77 | * Get event url. 78 | * @return \moodle_url 79 | * @throws \moodle_exception 80 | */ 81 | public function get_url() { 82 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 83 | } 84 | 85 | /** 86 | * Get event mapping. 87 | * @return string[] 88 | */ 89 | public static function get_objectid_mapping() { 90 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 91 | } 92 | 93 | /** 94 | * No other mappings available. 95 | * @return false 96 | */ 97 | public static function get_other_mapping() { 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /classes/event/distribution_triggered.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate distribution_triggered event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate distribution_triggered event class. 29 | * 30 | * @property-read array $other { 31 | * Extra information about event. 32 | * 33 | * - array allocations: created allocations 34 | * - double time_needed: time needed to finish the distribution 35 | * } 36 | * 37 | * @since Moodle 2.7 38 | * @copyright 2014 Tobias Reischmann 39 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 | **/ 41 | class distribution_triggered extends \core\event\base { 42 | 43 | /** 44 | * Create simple distribution_triggered event. 45 | * @param $modulecontext 46 | * @param $ratingallocateid 47 | * @param $timeneeded 48 | * @return \core\event\base 49 | * @throws \coding_exception 50 | */ 51 | public static function create_simple($modulecontext, $ratingallocateid, $timeneeded) { 52 | $timeneededjsonvalid = json_decode(json_encode($timeneeded), true); 53 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid, 54 | 'other' => ['time_needed' => $timeneededjsonvalid]]); 55 | } 56 | 57 | /** 58 | * Initialize data. 59 | * @return void 60 | */ 61 | protected function init() { 62 | $this->data['crud'] = 'u'; 63 | $this->data['edulevel'] = self::LEVEL_TEACHING; 64 | $this->data['objecttable'] = 'ratingallocate_ratings'; 65 | } 66 | 67 | /** 68 | * Get event name. 69 | * @return \lang_string|string 70 | * @throws \coding_exception 71 | */ 72 | public static function get_name() { 73 | return get_string('log_distribution_triggered', 'mod_ratingallocate'); 74 | } 75 | 76 | /** 77 | * Get event description. 78 | * @return \lang_string|string|null 79 | * @throws \coding_exception 80 | */ 81 | public function get_description() { 82 | return get_string('log_distribution_triggered_description', 'mod_ratingallocate', 83 | ['userid' => $this->userid, 84 | 'ratingallocateid' => $this->objectid, 85 | 'time_needed' => $this->other['time_needed']]); 86 | } 87 | 88 | /** 89 | * Get event url. 90 | * @return \moodle_url 91 | * @throws \moodle_exception 92 | */ 93 | public function get_url() { 94 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 95 | } 96 | 97 | /** 98 | * Get event mapping. 99 | * @return string[] 100 | */ 101 | public static function get_objectid_mapping() { 102 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 103 | } 104 | 105 | /** 106 | * No other mappings available. 107 | * @return false 108 | */ 109 | public static function get_other_mapping() { 110 | return false; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /classes/event/index_viewed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate index_viewed event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2017 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate index_viewed event class. 29 | * 30 | * @copyright 2017 Tobias Reischmann 31 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 | **/ 33 | class index_viewed extends \core\event\base { 34 | 35 | /** 36 | * Create simple index_viewed event. 37 | * @param $coursecontext 38 | * @return \core\event\base 39 | * @throws \coding_exception 40 | */ 41 | public static function create_simple($coursecontext) { 42 | return self::create(['context' => $coursecontext]); 43 | } 44 | 45 | /** 46 | * Initialize data. 47 | * @return void 48 | */ 49 | protected function init() { 50 | $this->data['crud'] = 'r'; 51 | $this->data['edulevel'] = self::LEVEL_OTHER; 52 | } 53 | 54 | /** 55 | * Get event name. 56 | * @return \lang_string|string 57 | * @throws \coding_exception 58 | */ 59 | public static function get_name() { 60 | return get_string('log_index_viewed', 'mod_ratingallocate'); 61 | } 62 | 63 | /** 64 | * Get event description. 65 | * @return \lang_string|string|null 66 | * @throws \coding_exception 67 | */ 68 | public function get_description() { 69 | return get_string('log_index_viewed_description', 'mod_ratingallocate', ['userid' => $this->userid]); 70 | } 71 | 72 | /** 73 | * Get event url. 74 | * @return \moodle_url 75 | * @throws \moodle_exception 76 | */ 77 | public function get_url() { 78 | return new \moodle_url('/mod/ratingallocate/index.php', ['id' => $this->courseid]); 79 | } 80 | 81 | /** 82 | * Get event mapping. 83 | * @return array 84 | */ 85 | public static function get_objectid_mapping() { 86 | return []; 87 | } 88 | 89 | /** 90 | * No other mappings available. 91 | * @return false 92 | */ 93 | public static function get_other_mapping() { 94 | return false; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /classes/event/manual_allocation_saved.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate manual_allocation_saved event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate manual_allocation_saved event class. 29 | * 30 | * @property-read array $other { 31 | * Extra information about event. 32 | * 33 | * - array allocations: changes of allocations 34 | * } 35 | * 36 | * @since Moodle 2.7 37 | * @copyright 2014 Tobias Reischmann 38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 | **/ 40 | class manual_allocation_saved extends \core\event\base { 41 | 42 | /** 43 | * Create simple manual_allocation_saved event. 44 | * @param $modulecontext 45 | * @param $ratingallocateid 46 | * @return \core\event\base 47 | * @throws \coding_exception 48 | */ 49 | public static function create_simple($modulecontext, $ratingallocateid) { 50 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 51 | } 52 | 53 | /** 54 | * Initialize data. 55 | * @return void 56 | */ 57 | protected function init() { 58 | $this->data['crud'] = 'u'; 59 | $this->data['edulevel'] = self::LEVEL_TEACHING; 60 | $this->data['objecttable'] = 'ratingallocate_ratings'; 61 | } 62 | 63 | /** 64 | * Get event name. 65 | * @return \lang_string|string 66 | * @throws \coding_exception 67 | */ 68 | public static function get_name() { 69 | return get_string('log_manual_allocation_saved', 'mod_ratingallocate'); 70 | } 71 | 72 | /** 73 | * Get event description. 74 | * @return \lang_string|string|null 75 | * @throws \coding_exception 76 | */ 77 | public function get_description() { 78 | return get_string('log_manual_allocation_saved_description', 'mod_ratingallocate', 79 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 80 | } 81 | 82 | /** 83 | * Get event url. 84 | * @return \moodle_url 85 | * @throws \moodle_exception 86 | */ 87 | public function get_url() { 88 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 89 | } 90 | 91 | /** 92 | * Get event mapping. 93 | * @return string[] 94 | */ 95 | public static function get_objectid_mapping() { 96 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 97 | } 98 | 99 | /** 100 | * No other mappings available. 101 | * @return false 102 | */ 103 | public static function get_other_mapping() { 104 | return false; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /classes/event/rating_deleted.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate rating_deleted event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2017 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate rating_deleted event class. 29 | * 30 | * @copyright 2017 Tobias Reischmann 31 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 | **/ 33 | class rating_deleted extends \core\event\base { 34 | 35 | /** 36 | * Create simple rating_deleted event. 37 | * @param $modulecontext 38 | * @param $ratingallocateid 39 | * @return \core\event\base 40 | * @throws \coding_exception 41 | */ 42 | public static function create_simple($modulecontext, $ratingallocateid) { 43 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 44 | } 45 | 46 | /** 47 | * Initialize data. 48 | * @return void 49 | */ 50 | protected function init() { 51 | $this->data['crud'] = 'd'; 52 | $this->data['edulevel'] = self::LEVEL_PARTICIPATING; 53 | $this->data['objecttable'] = 'ratingallocate_ratings'; 54 | } 55 | 56 | /** 57 | * Get event name. 58 | * @return \lang_string|string 59 | * @throws \coding_exception 60 | */ 61 | public static function get_name() { 62 | return get_string('log_rating_deleted', 'mod_ratingallocate'); 63 | } 64 | 65 | /** 66 | * Get event description. 67 | * @return \lang_string|string|null 68 | * @throws \coding_exception 69 | */ 70 | public function get_description() { 71 | return get_string('log_rating_deleted_description', 'mod_ratingallocate', 72 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 73 | } 74 | 75 | /** 76 | * Get event url. 77 | * @return \moodle_url 78 | * @throws \moodle_exception 79 | */ 80 | public function get_url() { 81 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 82 | } 83 | 84 | /** 85 | * Get event mapping. 86 | * @return string[] 87 | */ 88 | public static function get_objectid_mapping() { 89 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 90 | } 91 | 92 | /** 93 | * No other mappings available. 94 | * @return false 95 | */ 96 | public static function get_other_mapping() { 97 | return false; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /classes/event/rating_saved.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate rating_saved event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate rating_saved event class. 29 | * 30 | * @property-read array $other { 31 | * Extra information about event. 32 | * 33 | * - array rating: new values of rating 34 | * } 35 | * 36 | * @since Moodle 2.7 37 | * @copyright 2014 Tobias Reischmann 38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 | **/ 40 | class rating_saved extends \core\event\base { 41 | 42 | /** 43 | * Create simple rating_saved event. 44 | * @param $modulecontext 45 | * @param $ratingallocateid 46 | * @param $rating 47 | * @return \core\event\base 48 | * @throws \coding_exception 49 | */ 50 | public static function create_simple($modulecontext, $ratingallocateid, $rating) { 51 | // The values of other need to be encoded since the base checks for equality 52 | // of a decoded encoded other instance with the original 53 | // this is not given for nested arrays. 54 | $ratingjsonvalid = json_decode(json_encode($rating), true); 55 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid, 56 | 'other' => ['ratings' => $ratingjsonvalid]]); 57 | } 58 | 59 | /** 60 | * Initialize data. 61 | * @return void 62 | */ 63 | protected function init() { 64 | $this->data['crud'] = 'u'; 65 | $this->data['edulevel'] = self::LEVEL_PARTICIPATING; 66 | $this->data['objecttable'] = 'ratingallocate_ratings'; 67 | } 68 | 69 | /** 70 | * Get event name. 71 | * @return \lang_string|string 72 | * @throws \coding_exception 73 | */ 74 | public static function get_name() { 75 | return get_string('log_rating_saved', 'mod_ratingallocate'); 76 | } 77 | 78 | /** 79 | * Get event description. 80 | * @return \lang_string|string|null 81 | * @throws \coding_exception 82 | */ 83 | public function get_description() { 84 | return get_string('log_rating_saved_description', 'mod_ratingallocate', 85 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 86 | } 87 | 88 | /** 89 | * Get event url. 90 | * @return \moodle_url 91 | * @throws \moodle_exception 92 | */ 93 | public function get_url() { 94 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 95 | } 96 | 97 | /** 98 | * Get event mapping. 99 | * @return string[] 100 | */ 101 | public static function get_objectid_mapping() { 102 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 103 | } 104 | 105 | /** 106 | * No other mappings available. 107 | * @return false 108 | */ 109 | public static function get_other_mapping() { 110 | return false; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /classes/event/rating_viewed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate rating_viewed event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate rating_viewed event class. 29 | * 30 | * @since Moodle 2.7 31 | * @copyright 2014 Tobias Reischmann 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | **/ 34 | class rating_viewed extends \core\event\base { 35 | 36 | /** 37 | * Create simple rating_viewed event. 38 | * @param $modulecontext 39 | * @param $ratingallocateid 40 | * @return \core\event\base 41 | * @throws \coding_exception 42 | */ 43 | public static function create_simple($modulecontext, $ratingallocateid) { 44 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 45 | } 46 | 47 | /** 48 | * Initialize data. 49 | * @return void 50 | */ 51 | protected function init() { 52 | $this->data['crud'] = 'r'; 53 | $this->data['edulevel'] = self::LEVEL_PARTICIPATING; 54 | $this->data['objecttable'] = 'ratingallocate'; 55 | } 56 | 57 | /** 58 | * Get event name. 59 | * @return \lang_string|string 60 | * @throws \coding_exception 61 | */ 62 | public static function get_name() { 63 | return get_string('log_rating_viewed', 'mod_ratingallocate'); 64 | } 65 | 66 | /** 67 | * Get event description. 68 | * @return \lang_string|string|null 69 | * @throws \coding_exception 70 | */ 71 | public function get_description() { 72 | return get_string('log_rating_viewed_description', 'mod_ratingallocate', 73 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 74 | } 75 | 76 | /** 77 | * Get event url. 78 | * @return \moodle_url 79 | * @throws \moodle_exception 80 | */ 81 | public function get_url() { 82 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 83 | } 84 | 85 | /** 86 | * Get event mapping. 87 | * @return string[] 88 | */ 89 | public static function get_objectid_mapping() { 90 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 91 | } 92 | 93 | /** 94 | * No other mappings available. 95 | * @return false 96 | */ 97 | public static function get_other_mapping() { 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /classes/event/ratingallocate_viewed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate ratingallocate_viewed event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | /** 28 | * The mod_ratingallocate ratingallocate_viewed event class. 29 | * 30 | * @since Moodle 2.7 31 | * @copyright 2014 Tobias Reischmann 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | **/ 34 | class ratingallocate_viewed extends \core\event\base { 35 | 36 | /** 37 | * Create simple ratingallocate_viewed event. 38 | * @param $modulecontext 39 | * @param $ratingallocateid 40 | * @return \core\event\base 41 | * @throws \coding_exception 42 | */ 43 | public static function create_simple($modulecontext, $ratingallocateid) { 44 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 45 | } 46 | 47 | /** 48 | * Initialize data. 49 | * @return void 50 | */ 51 | protected function init() { 52 | $this->data['crud'] = 'r'; 53 | $this->data['edulevel'] = self::LEVEL_TEACHING; 54 | $this->data['objecttable'] = 'ratingallocate'; 55 | } 56 | 57 | /** 58 | * Get event name. 59 | * @return \lang_string|string 60 | * @throws \coding_exception 61 | */ 62 | public static function get_name() { 63 | return get_string('log_ratingallocate_viewed', 'mod_ratingallocate'); 64 | } 65 | 66 | /** 67 | * Get event description. 68 | * @return \lang_string|string|null 69 | * @throws \coding_exception 70 | */ 71 | public function get_description() { 72 | return get_string('log_ratingallocate_viewed_description', 'mod_ratingallocate', 73 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 74 | } 75 | 76 | /** 77 | * Get event url. 78 | * @return \moodle_url 79 | * @throws \moodle_exception 80 | */ 81 | public function get_url() { 82 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 83 | } 84 | 85 | /** 86 | * Get event mapping. 87 | * @return string[] 88 | */ 89 | public static function get_objectid_mapping() { 90 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 91 | } 92 | 93 | /** 94 | * No other mappings available. 95 | * @return false 96 | */ 97 | public static function get_other_mapping() { 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /classes/event/ratings_and_allocation_table_viewed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * The mod_ratingallocate ratings_and_allocation_table_viewed event. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\event; 26 | 27 | 28 | /** 29 | * The mod_ratingallocate ratings_and_allocation_table_viewed event class. 30 | * 31 | * @since Moodle 2.7 32 | * @copyright 2014 Tobias Reischmann 33 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 | **/ 35 | class ratings_and_allocation_table_viewed extends \core\event\base { 36 | 37 | /** 38 | * Create simple ratings_and_allocation_table_viewed event. 39 | * @param $modulecontext 40 | * @param $ratingallocateid 41 | * @return \core\event\base 42 | * @throws \coding_exception 43 | */ 44 | public static function create_simple($modulecontext, $ratingallocateid) { 45 | return self::create(['context' => $modulecontext, 'objectid' => $ratingallocateid]); 46 | } 47 | 48 | /** 49 | * Initialize data. 50 | * @return void 51 | */ 52 | protected function init() { 53 | $this->data['crud'] = 'r'; 54 | $this->data['edulevel'] = self::LEVEL_TEACHING; 55 | $this->data['objecttable'] = 'ratingallocate'; 56 | } 57 | 58 | /** 59 | * Get event name. 60 | * @return \lang_string|string 61 | * @throws \coding_exception 62 | */ 63 | public static function get_name() { 64 | return get_string('log_ratings_and_allocation_table_viewed', 'mod_ratingallocate'); 65 | } 66 | 67 | /** 68 | * Get event description. 69 | * @return \lang_string|string|null 70 | * @throws \coding_exception 71 | */ 72 | public function get_description() { 73 | return get_string('log_ratings_and_allocation_table_viewed_description', 'mod_ratingallocate', 74 | ['userid' => $this->userid, 'ratingallocateid' => $this->objectid]); 75 | } 76 | 77 | /** 78 | * Get event url. 79 | * @return \moodle_url 80 | * @throws \moodle_exception 81 | */ 82 | public function get_url() { 83 | return new \moodle_url('/mod/ratingallocate/view.php', ['m' => $this->objectid]); 84 | } 85 | 86 | /** 87 | * Get event mapping. 88 | * @return string[] 89 | */ 90 | public static function get_objectid_mapping() { 91 | return ['db' => 'ratingallocate', 'restore' => 'ratingallocate']; 92 | } 93 | 94 | /** 95 | * No other mappings available. 96 | * @return false 97 | */ 98 | public static function get_other_mapping() { 99 | return false; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /classes/ratingallocate_observer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Event observer for ratingallocate. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2023 I Hoppe 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate; 26 | use coding_exception; 27 | use dml_exception; 28 | 29 | /** 30 | * Ratingallocate observer. 31 | * 32 | * @package mod_ratingallocate 33 | */ 34 | class ratingallocate_observer { 35 | 36 | /** 37 | * Triggered if group_deleted event is triggered. 38 | * 39 | * @param \core\event\group_deleted $event 40 | * @return void 41 | * @throws coding_exception 42 | * @throws dml_exception 43 | */ 44 | public static function ch_gengroups_delete(\core\event\group_deleted $event) { 45 | global $DB; 46 | 47 | $eventdata = $event->get_record_snapshot('groups', $event->objectid); 48 | if ($DB->record_exists( 49 | 'ratingallocate_ch_gengroups', 50 | ['groupid' => $eventdata->id])) { 51 | 52 | // Delete the group from ratingallocate_ch_gengroups table. 53 | $DB->delete_records( 54 | 'ratingallocate_ch_gengroups', 55 | ['groupid' => $eventdata->id] 56 | ); 57 | } 58 | 59 | } 60 | 61 | /** 62 | * Triggered if grouping_deleted event is triggered. 63 | * 64 | * @param \core\event\grouping_deleted $event 65 | * @return void 66 | * @throws coding_exception 67 | * @throws dml_exception 68 | */ 69 | public static function ra_groupings_delete(\core\event\grouping_deleted $event) { 70 | global $DB; 71 | 72 | $eventdata = $event->get_record_snapshot('groupings', $event->objectid); 73 | if ($DB->record_exists( 74 | 'ratingallocate_groupings', 75 | ['groupingid' => $eventdata->id])) { 76 | 77 | // Delete the grouping from the ratingallocate_groupings table. 78 | $DB->delete_records( 79 | 'ratingallocate_groupings', 80 | ['groupingid' => $eventdata->id] 81 | ); 82 | 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /classes/task/cron_task.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_ratingallocate\task; 18 | 19 | use mod_ratingallocate\db as this_db; 20 | 21 | defined('MOODLE_INTERNAL') || die(); 22 | 23 | require_once(__DIR__ . '/../../locallib.php'); 24 | 25 | /** 26 | * A scheduled task for ratingallocate cron. 27 | * 28 | * @package mod_ratingallocate 29 | * @copyright 2015 Tobias Reischmann 30 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 | */ 32 | class cron_task extends \core\task\scheduled_task { 33 | 34 | /** 35 | * Get a descriptive name for this task (shown to admins). 36 | * 37 | * @return string 38 | */ 39 | public function get_name() { 40 | return get_string('crontask', 'mod_ratingallocate'); 41 | } 42 | 43 | /** 44 | * Run forum cron. 45 | */ 46 | public function execute() { 47 | global $DB, $CFG; 48 | 49 | $currenttime = time(); 50 | $statement = 'SELECT R.* FROM {ratingallocate} R 51 | LEFT JOIN {ratingallocate_allocations} A 52 | ON R.' . this_db\ratingallocate::ID . '=A.' . this_db\ratingallocate_allocations::RATINGALLOCATEID . ' 53 | WHERE A.' . this_db\ratingallocate_allocations::ID . ' IS NULL AND R.' . this_db\ratingallocate::ACCESSTIMESTOP . '<' . 54 | $currenttime; 55 | $records = $DB->get_records_sql($statement); 56 | $course = null; 57 | foreach ($records as $record) { 58 | $cm = get_coursemodule_from_instance(this_db\ratingallocate::TABLE, $record->{this_db\ratingallocate::ID}); 59 | // Fetch the data for the course, if is has changed. 60 | if (!$course || $course->id != $record->{this_db\ratingallocate::COURSE}) { 61 | $course = $DB->get_record('course', ['id' => $record->{this_db\ratingallocate::COURSE}], '*', MUST_EXIST); 62 | } 63 | // Create ratingallocate instance from record. 64 | $ratingallocate = new \ratingallocate($record, $course, $cm, \context_module::instance($cm->id)); 65 | $currenttime = time(); 66 | $timetoterminate = $CFG->ratingallocate_algorithm_timeout + $ratingallocate->ratingallocate->algorithmstarttime; 67 | 68 | // If last execution exeeds timeout limit assume failure of algorithm run. 69 | if ($ratingallocate->ratingallocate->algorithmstarttime && 70 | $currenttime >= $timetoterminate && 71 | $ratingallocate->get_algorithm_status() === \mod_ratingallocate\algorithm_status::RUNNING) { 72 | $ratingallocate->set_algorithm_failed(); 73 | return true; 74 | } 75 | 76 | // Only start the algorithm, if it should be run by the cron and hasn't been started somehow, yet. 77 | if ($ratingallocate->ratingallocate->runalgorithmbycron === "1" && 78 | $ratingallocate->get_algorithm_status() === \mod_ratingallocate\algorithm_status::NOTSTARTED) { 79 | // Clear eventually scheduled distribution of unallocated users. 80 | $ratingallocate->clear_distribute_unallocated_tasks(); 81 | // Run allocation. 82 | $ratingallocate->distrubute_choices(); 83 | } 84 | } 85 | return true; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /classes/task/distribute_unallocated_task.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Task for distributing unallocated users in the background. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2023 ISB Bayern 22 | * @author Philipp Memmel 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | namespace mod_ratingallocate\task; 27 | 28 | use context_module; 29 | use core\task\adhoc_task; 30 | use moodle_exception; 31 | use ratingallocate; 32 | 33 | /** 34 | * Task for distributing unallocated users in the background. 35 | * 36 | * @copyright 2023 ISB Bayern 37 | * @author Philipp Memmel 38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 | */ 40 | class distribute_unallocated_task extends adhoc_task { 41 | 42 | /** 43 | * Executes the distribution of unallocated users. 44 | * 45 | * @throws moodle_exception 46 | */ 47 | public function execute(): void { 48 | global $CFG, $DB; 49 | // Make sure to include the global definitions of constants defined in locallib. 50 | require_once($CFG->dirroot . '/mod/ratingallocate/locallib.php'); 51 | 52 | $data = $this->get_custom_data(); 53 | if (empty($data->distributionalgorithm) || 54 | !in_array($data->distributionalgorithm, [ACTION_DISTRIBUTE_UNALLOCATED_EQUALLY, ACTION_DISTRIBUTE_UNALLOCATED_FILL])) { 55 | mtrace('No distribution algorithm has been specified, exiting.'); 56 | return; 57 | } 58 | if (empty($data->courseid)) { 59 | mtrace('No course ID has been found, exiting.'); 60 | return; 61 | } 62 | if (empty($data->cmid)) { 63 | mtrace('No course module ID has been found, exiting.'); 64 | return; 65 | } 66 | 67 | $modinfo = get_fast_modinfo($data->courseid); 68 | $cm = $modinfo->get_cm($data->cmid); 69 | $course = $modinfo->get_course(); 70 | $ratingallocatedb = $DB->get_record('ratingallocate', ['id' => $cm->instance]); 71 | if (empty($ratingallocatedb)) { 72 | mtrace('Could not find database record of ratingallocate instance for course module id ' . $cm->id 73 | . '. Nothing to do.'); 74 | return; 75 | } 76 | $context = context_module::instance($cm->id); 77 | $ratingallocate = new ratingallocate($ratingallocatedb, $course, $cm, $context); 78 | 79 | mtrace('Distributing unallocated users for ratingallocate with course module id ' . $cm->id); 80 | $ratingallocate->distribute_users_without_choice($data->distributionalgorithm); 81 | mtrace('Distribution of unallocated users for ratingallocate instance with course module id ' . $cm->id . ' done.'); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /classes/task/send_distribution_notification.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Send distibution notification. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 M Schulze 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace mod_ratingallocate\task; 26 | 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | require_once(dirname(__FILE__) . '/../../db/db_structure.php'); 30 | 31 | use mod_ratingallocate\db as this_db; 32 | 33 | /** 34 | * Send distribution notification 35 | * 36 | * @package mod_ratingallocate 37 | */ 38 | class send_distribution_notification extends \core\task\adhoc_task { 39 | 40 | /** 41 | * Gets executed by the task runner. Will lookup the ratingallocation object and command it 42 | * to notify users. 43 | * @return void 44 | * @throws \coding_exception 45 | * @throws \dml_exception 46 | * @throws \moodle_exception 47 | */ 48 | public function execute() { 49 | global $CFG, $DB; 50 | 51 | require_once($CFG->dirroot . '/mod/ratingallocate/locallib.php'); 52 | 53 | $site = get_site(); 54 | // Parse customdata passed. 55 | $customdata = $this->get_custom_data(); 56 | $ratingallocateid = $customdata->ratingallocateid; 57 | 58 | // Get instance of ratingallocate. 59 | $ratingallocate = 60 | $DB->get_record(this_db\ratingallocate::TABLE, [this_db\ratingallocate::ID => $ratingallocateid], '*', 61 | MUST_EXIST); 62 | 63 | $courseid = $ratingallocate->course; 64 | $course = get_course($courseid); 65 | $cm = get_coursemodule_from_instance('ratingallocate', $ratingallocate->id, $courseid); 66 | $context = \context_module::instance($cm->id); 67 | 68 | $ratingallocateobj = new \ratingallocate($ratingallocate, $course, $cm, $context); 69 | 70 | $ratingallocateobj->notify_users_distribution(); 71 | 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /db/access.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Capability definitions for the ratingallocate module 19 | * 20 | * The capabilities are loaded into the database table when the module is 21 | * installed or updated. Whenever the capability definitions are updated, 22 | * the module version number should be bumped up. 23 | * 24 | * The system has four possible values for a capability: 25 | * CAP_ALLOW, CAP_PREVENT, CAP_PROHIBIT, and inherit (not set). 26 | * 27 | * It is important that capability names are unique. The naming convention 28 | * for capabilities that are specific to modules and blocks is as follows: 29 | * [mod/block]/: 30 | * 31 | * component_name should be the same as the directory name of the mod or block. 32 | * 33 | * Core moodle capabilities are defined thus: 34 | * moodle/: 35 | * 36 | * Examples: mod/forum:viewpost 37 | * block/recent_activity:view 38 | * moodle/site:deleteuser 39 | * 40 | * The variable name for the capability definitions array is $capabilities 41 | * 42 | * @package mod_ratingallocate 43 | * @copyright 2014 M Schulze 44 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 | */ 46 | defined('MOODLE_INTERNAL') || die(); 47 | 48 | $capabilities = [ 49 | 50 | 'mod/ratingallocate:addinstance' => [ 51 | 'riskbitmask' => RISK_XSS | RISK_PERSONAL, 52 | 'contextlevel' => CONTEXT_COURSE, 53 | 'captype' => 'write', 54 | 'archetypes' => [ 55 | 'editingteacher' => CAP_ALLOW, 56 | 'manager' => CAP_ALLOW, 57 | ], 58 | 'clonepermissionsfrom' => 'moodle/course:manageactivities', 59 | ], 60 | 'mod/ratingallocate:view' => [ 61 | 'captype' => 'read', 62 | 'contextlevel' => CONTEXT_MODULE, 63 | 'legacy' => [ 64 | 'guest' => CAP_ALLOW, 65 | 'student' => CAP_ALLOW, 66 | 'teacher' => CAP_ALLOW, 67 | 'editingteacher' => CAP_ALLOW, 68 | 'manager' => CAP_ALLOW, 69 | ], 70 | ], 71 | 'mod/ratingallocate:give_rating' => [ 72 | 'contextlevel' => CONTEXT_MODULE, 73 | 'captype' => 'write', 74 | 'archetypes' => [ 75 | 'student' => CAP_ALLOW, 76 | ], 77 | ], 78 | 'mod/ratingallocate:start_distribution' => [ 79 | 'contextlevel' => CONTEXT_MODULE, 80 | 'riskbitmask' => RISK_PERSONAL, 81 | 'captype' => 'write', 82 | 'archetypes' => [ 83 | 'editingteacher' => CAP_ALLOW, 84 | 'manager' => CAP_ALLOW, 85 | ], 86 | ], 87 | 'mod/ratingallocate:modify_choices' => [ 88 | 'contextlevel' => CONTEXT_MODULE, 89 | 'captype' => 'write', 90 | 'archetypes' => [ 91 | 'editingteacher' => CAP_ALLOW, 92 | 'manager' => CAP_ALLOW, 93 | ], 94 | ], 95 | 'mod/ratingallocate:export_ratings' => [ 96 | 'contextlevel' => CONTEXT_MODULE, 97 | 'riskbitmask' => RISK_PERSONAL, 98 | 'captype' => 'read', 99 | 'archetypes' => [ 100 | 'editingteacher' => CAP_ALLOW, 101 | 'manager' => CAP_ALLOW, 102 | ], 103 | ], 104 | 'mod/ratingallocate:distribute_unallocated' => [ 105 | 'contextlevel' => CONTEXT_MODULE, 106 | 'riskbitmask' => RISK_PERSONAL, 107 | 'captype' => 'write', 108 | 'archetypes' => [ 109 | 'editingteacher' => CAP_ALLOW, 110 | 'manager' => CAP_ALLOW, 111 | ], 112 | ], 113 | ]; 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /db/db_structure.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Database structure of the table needed by the ratingallocate module 19 | * Grants easier acces to database fields 20 | * 21 | * @package mod_ratingallocate 22 | * @copyright 2014 T Reischmann, M Schulze 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | namespace mod_ratingallocate\db; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | /** 31 | * Ratingallocate. 32 | * 33 | * @package mod_ratingallocate 34 | */ 35 | class ratingallocate { 36 | /** 37 | * The ratingallocate table. 38 | */ 39 | const TABLE = 'ratingallocate'; 40 | /** 41 | * Ratingallocateid. 42 | */ 43 | const ID = 'id'; 44 | /** 45 | * The course. 46 | */ 47 | const COURSE = 'course'; 48 | /** 49 | * Name of the instance. 50 | */ 51 | const NAME = 'name'; 52 | /** 53 | * Intro. 54 | */ 55 | const INTRO = 'intro'; 56 | /** 57 | * The introformat. 58 | */ 59 | const INTROFORMAT = 'introformat'; 60 | /** 61 | * When the instance was created. 62 | */ 63 | const TIMECREATED = 'timecreated'; 64 | /** 65 | * Time it was modified. 66 | */ 67 | const TIMEMODIFIED = 'timemodified'; 68 | /** 69 | * Beginning voting. 70 | */ 71 | const ACCESSTIMESTART = 'accesstimestart'; 72 | /** 73 | * End of voting. 74 | */ 75 | const ACCESSTIMESTOP = 'accesstimestop'; 76 | /** 77 | * Setting. 78 | */ 79 | const SETTING = 'setting'; 80 | /** 81 | * The strategy used. 82 | */ 83 | const STRATEGY = 'strategy'; 84 | /** 85 | * Date to publish allocation. 86 | */ 87 | const PUBLISHDATE = 'publishdate'; 88 | /** 89 | * Wether its published. 90 | */ 91 | const PUBLISHED = 'published'; 92 | /** 93 | * Send notification to users. 94 | */ 95 | const NOTIFICATIONSEND = 'notificationsend'; 96 | /** 97 | * Strat time of algorithm. 98 | */ 99 | const ALGORITHMSTARTTIME = 'algorithmstarttime'; 100 | /** 101 | * Wether algorithm is run by cron task. 102 | */ 103 | const RUNALGORITHMBYCRON = 'runalgorithmbycron'; 104 | /** 105 | * Status of the most recent algorithm run. 106 | */ 107 | const ALGORITHMSTATUS = 'algorithmstatus'; 108 | } 109 | 110 | /** 111 | * Ratingallocate choices. 112 | * 113 | * @package mod_ratingallocate 114 | */ 115 | class ratingallocate_choices { 116 | /** 117 | * Table. 118 | */ 119 | const TABLE = 'ratingallocate_choices'; 120 | /** 121 | * ID. 122 | */ 123 | const ID = 'id'; 124 | /** 125 | * Ratingallocateid. 126 | */ 127 | const RATINGALLOCATEID = 'ratingallocateid'; 128 | /** 129 | * Title of choice. 130 | */ 131 | const TITLE = 'title'; 132 | /** 133 | * Explanation. 134 | */ 135 | const EXPLANATION = 'explanation'; 136 | /** 137 | * Max number of users. 138 | */ 139 | const MAXSIZE = 'maxsize'; 140 | /** 141 | * If its active. 142 | */ 143 | const ACTIVE = 'active'; 144 | /** 145 | * Restrict visibility by groups. 146 | */ 147 | const USEGROUPS = 'usegroups'; 148 | } 149 | 150 | /** 151 | * Ratingallocate group choices. 152 | * 153 | * @package mod_ratingallocate 154 | */ 155 | class ratingallocate_group_choices { 156 | /** 157 | * Table. 158 | */ 159 | const TABLE = 'ratingallocate_group_choices'; 160 | /** 161 | * Id. 162 | */ 163 | const ID = 'id'; 164 | /** 165 | * Choiceid. 166 | */ 167 | const CHOICEID = 'choiceid'; 168 | /** 169 | * Groupid. 170 | */ 171 | const GROUPID = 'groupid'; 172 | } 173 | 174 | /** 175 | * Ratingallocate generated groups of choices 176 | * 177 | * @package mod_ratingallocate 178 | */ 179 | class ratingallocate_ch_gengroups { 180 | /** 181 | * Table. 182 | */ 183 | const TABLE = 'ratingallocate_ch_gengroups'; 184 | /** 185 | * Id. 186 | */ 187 | const ID = 'id'; 188 | /** 189 | * Groupid. 190 | */ 191 | const GROUPID = 'groupid'; 192 | /** 193 | * Choiceid. 194 | */ 195 | const CHOICEID = 'choiceid'; 196 | } 197 | 198 | /** 199 | * Ratingallocate groupings 200 | * 201 | * @package mod_ratingallocate 202 | */ 203 | class ratingallocate_groupings { 204 | /** 205 | * Table. 206 | */ 207 | const TABLE = 'ratingallocate_groupings'; 208 | /** 209 | * Id. 210 | */ 211 | const ID = 'id'; 212 | /** 213 | * Ratingallocateid. 214 | */ 215 | const RATINGALLOCATEID = 'ratingallocateid'; 216 | /** 217 | * Groupingid. 218 | */ 219 | const GROUPINGID = 'groupingid'; 220 | } 221 | 222 | /** 223 | * Ratingallocate ratings 224 | * 225 | * @package mod_ratingallocate 226 | */ 227 | class ratingallocate_ratings { 228 | /** 229 | * Table. 230 | */ 231 | const TABLE = 'ratingallocate_ratings'; 232 | /** 233 | * Id. 234 | */ 235 | const ID = 'id'; 236 | /** 237 | * The choiceid. 238 | */ 239 | const CHOICEID = 'choiceid'; 240 | /** 241 | * The userid. 242 | */ 243 | const USERID = 'userid'; 244 | /** 245 | * How the user rated the choice. 246 | */ 247 | const RATING = 'rating'; 248 | } 249 | 250 | /** 251 | * Ratingallocate allocations. 252 | * 253 | * @package mod_ratingallocate 254 | */ 255 | class ratingallocate_allocations { 256 | /** 257 | * Table. 258 | */ 259 | const TABLE = 'ratingallocate_allocations'; 260 | /** 261 | * Id. 262 | */ 263 | const ID = 'id'; 264 | /** 265 | * Userid. 266 | */ 267 | const USERID = 'userid'; 268 | /** 269 | * Id of ratingallocate instance. 270 | */ 271 | const RATINGALLOCATEID = 'ratingallocateid'; 272 | /** 273 | * Choiceid. 274 | */ 275 | const CHOICEID = 'choiceid'; 276 | } 277 | -------------------------------------------------------------------------------- /db/events.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of ratingallocate event observers. 19 | * 20 | * The observers defined in this file are notified when respective events are triggered. 21 | * 22 | * @package mod_ratingallocate 23 | * @category event 24 | * @copyright 2023 I Hoppe 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | * 27 | */ 28 | 29 | defined('MOODLE_INTERNAL') || die(); 30 | 31 | 32 | $handlers = []; 33 | 34 | // List of observers for group_deleted and grouping_deleted. 35 | 36 | $observers = [ 37 | [ 38 | 'eventname' => '\core\event\group_deleted', 39 | 'callback' => 'mod_ratingallocate\ratingallocate_observer::ch_gengroups_delete', 40 | ], 41 | [ 42 | 'eventname' => '\core\event\grouping_deleted', 43 | 'callback' => 'mod_ratingallocate\ratingallocate_observer::ra_groupings_delete', 44 | ], 45 | ]; 46 | -------------------------------------------------------------------------------- /db/install.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file replaces the legacy STATEMENTS section in db/install.xml, 19 | * lib.php/modulename_install() post installation hook and partially defaults.php 20 | * 21 | * @package mod_ratingallocate 22 | * @copyright 2014 M Schulze 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | /** 27 | * Post installation procedure 28 | * 29 | * @see upgrade_plugins_modules() 30 | */ 31 | function xmldb_ratingallocate_install() { 32 | } 33 | 34 | /** 35 | * Post installation recovery procedure 36 | * 37 | * @see upgrade_plugins_modules() 38 | */ 39 | function xmldb_ratingallocate_install_recovery() { 40 | } 41 | -------------------------------------------------------------------------------- /db/log.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of log events 19 | * 20 | * NOTE: this is an example how to insert log event during installation/update. 21 | * It is not really essential to know about it, but these logs were created as example 22 | * in the previous 1.9 NEWMODULE. 23 | * 24 | * @package mod_ratingallocate 25 | * @copyright 2014 M Schulze 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | global $DB; 31 | 32 | $logs = [ 33 | ['module' => 'ratingallocate', 'action' => 'add', 'mtable' => 'ratingallocate', 'field' => 'name'], 34 | ['module' => 'ratingallocate', 'action' => 'update', 'mtable' => 'ratingallocate', 'field' => 'name'], 35 | ['module' => 'ratingallocate', 'action' => 'view', 'mtable' => 'ratingallocate', 'field' => 'name'], 36 | ['module' => 'ratingallocate', 'action' => 'view all', 'mtable' => 'ratingallocate', 'field' => 'name'], 37 | ]; 38 | -------------------------------------------------------------------------------- /db/messages.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of Ratingallocate messages. 19 | * 20 | * @package mod_ratingallocate 21 | * @category message 22 | * @copyright 2018 Tobias Reischmann 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $messageproviders = [ 29 | // Notify student about published allocation. 30 | 'allocation' => [ 31 | 'capability' => 'mod/ratingallocate:give_rating', 32 | ], 33 | ]; 34 | -------------------------------------------------------------------------------- /db/tasks.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of Ratingallocate scheduled tasks. 19 | * 20 | * @package mod_ratingallocate 21 | * @category task 22 | * @copyright 2015 Tobias Reischmann 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $tasks = [ 29 | [ 30 | 'classname' => 'mod_ratingallocate\task\cron_task', 31 | 'blocking' => 0, 32 | 'minute' => '*', 33 | 'hour' => '*', 34 | 'day' => '*', 35 | 'month' => '*', 36 | 'dayofweek' => '*', 37 | 'faildelay' => 1, 38 | ], 39 | ]; 40 | -------------------------------------------------------------------------------- /db/uninstall.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Db uninstall. 19 | * 20 | * @see uninstall_plugin() 21 | * 22 | * @package mod_ratingallocate 23 | * @copyright 2014 M Schulze 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | 27 | /** 28 | * Uninstall. 29 | * 30 | * @package mod_ratingallocate 31 | */ 32 | function xmldb_ratingallocate_uninstall() { 33 | return true; 34 | } 35 | -------------------------------------------------------------------------------- /form_upload_choices.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Bulk upload one or more choices for the ratingallocate instance via CSV file. 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2021 Catalyst IT 22 | * @author David Thompson 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | defined('MOODLE_INTERNAL') || die(); 26 | global $CFG; 27 | require_once($CFG->dirroot . '/course/moodleform_mod.php'); 28 | require_once(dirname(__FILE__) . '/locallib.php'); 29 | 30 | /** 31 | * A form to upload multiple choices 32 | */ 33 | class upload_choices_form extends moodleform { 34 | 35 | /** @var $ratingallocate ratingallocate */ 36 | private $ratingallocate; 37 | 38 | /** 39 | * Constructor 40 | * @param string $url 41 | * @param ratingallocate $ratingallocate 42 | */ 43 | public function __construct($url, ratingallocate $ratingallocate) { 44 | $this->ratingallocate = $ratingallocate; 45 | parent::__construct($url); 46 | } 47 | 48 | /** 49 | * Defines forms elements 50 | */ 51 | public function definition() { 52 | $mform = $this->_form; 53 | 54 | $requiredfields = \mod_ratingallocate\choice_importer::print_fields(); 55 | $elementname = 'description'; 56 | $mform->addElement('static', $elementname, get_string('upload_choices_required_fields', 'ratingallocate'), 57 | get_string('upload_choices_fields_desc', 'ratingallocate', $requiredfields)); 58 | 59 | $elementname = 'uploadfile'; 60 | $mform->addElement('filepicker', $elementname, get_string('csvupload', 'ratingallocate'), null, 61 | ['accepted_types' => 'text/csv'] 62 | ); 63 | $mform->addRule($elementname, get_string('err_required', 'form') , 'required', null, 'server'); 64 | 65 | $elementname = 'testimport'; 66 | $mform->addElement('advcheckbox', $elementname, get_string('csvupload_test_upload', 'ratingallocate'), 67 | null, null, [0, 1]); 68 | $mform->addHelpButton($elementname, 'csvupload_test_upload', 'ratingallocate'); 69 | 70 | $this->add_buttons(); 71 | } 72 | 73 | /** 74 | * Add button group. 75 | * @return void 76 | * @throws coding_exception 77 | */ 78 | public function add_buttons() { 79 | $mform =& $this->_form; 80 | 81 | $buttonarray = []; 82 | $buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('csvupload', 'ratingallocate')); 83 | $buttonarray[] = &$mform->createElement('cancel'); 84 | $mform->addGroup($buttonarray, 'buttonar', '', [' '], false); 85 | $mform->closeHeaderBefore('buttonar'); 86 | } 87 | 88 | 89 | /** 90 | * Returns the forms HTML code. 91 | * So we don't have to call display(). 92 | */ 93 | public function to_html() { 94 | $o = ''; 95 | $o .= $this->_form->getValidationScript(); 96 | $o .= $this->_form->toHtml(); 97 | return $o; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /grade.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Redirect the user to the appropriate submission related page 19 | * 20 | * @package mod_ratingallocate 21 | * @category grade 22 | * @copyright 2014 C Usener 23 | * @copyright based on code by M Schulze copyright (C) 2014 M Schulze 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | 27 | require_once(__DIR__ . "/../../config.php"); 28 | require_login(); 29 | 30 | $id = required_param('id', PARAM_INT); // Course module ID. 31 | $itemnumber = optional_param('itemnumber', 0, 32 | PARAM_INT); // Item number, may be != 0 for activities that allow more than one grade per user. 33 | $userid = optional_param('userid', 0, PARAM_INT); // Graded user ID (optional). 34 | 35 | // In the simplest case just redirect to the view page. 36 | redirect('view.php?id=' . $id); 37 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This is a one-line short description of the file 19 | * 20 | * You can have a rather longer description of the file as well, 21 | * if you like, and it can span multiple lines. 22 | * 23 | * @package mod_ratingallocate 24 | * @copyright 2014 M Schulze, C Usener 25 | * @copyright based on code by Stefan Koegel copyright (C) 2013 Stefan Koegel 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | 29 | require_once(dirname(dirname(dirname(__FILE__))) . '/config.php'); 30 | require_once(dirname(__FILE__) . '/lib.php'); 31 | require_once(dirname(__FILE__) . '/locallib.php'); 32 | 33 | $id = required_param('id', PARAM_INT); // Courseid. 34 | 35 | $course = get_course($id); 36 | 37 | require_course_login($course); 38 | 39 | $coursecontext = context_course::instance($course->id); 40 | 41 | $PAGE->set_pagelayout('incourse'); 42 | $PAGE->set_url('/mod/ratingallocate/index.php', ['id' => $id]); 43 | $PAGE->set_title(format_string($course->fullname)); 44 | $PAGE->set_heading(format_string($course->fullname)); 45 | $PAGE->set_context($coursecontext); 46 | 47 | echo $OUTPUT->header(); 48 | echo $OUTPUT->heading(get_string('modulenameplural', RATINGALLOCATE_MOD_NAME), 2); 49 | 50 | require_capability('mod/ratingallocate:view', $coursecontext); 51 | 52 | $event = \mod_ratingallocate\event\index_viewed::create_simple( 53 | context_course::instance($course->id)); 54 | $event->trigger(); 55 | 56 | if (!$ratingallocates = get_all_instances_in_course('ratingallocate', $course, $USER->id)) { 57 | notice(get_string('noratingallocates', RATINGALLOCATE_MOD_NAME), 58 | new moodle_url('/course/view.php', ['id' => $course->id])); 59 | } 60 | 61 | $table = new html_table(); 62 | $table->head = [ 63 | get_string('name'), 64 | get_string('rating_begintime', 'mod_ratingallocate'), 65 | get_string('rating_endtime', 'mod_ratingallocate'), 66 | get_string('is_published', 'mod_ratingallocate')]; 67 | $table->align = ['left', 'left', 'left', 'left']; 68 | 69 | foreach ($ratingallocates as $ratingallocate) { 70 | $ratingallocateinstance = $DB->get_record('ratingallocate', ['id' => $ratingallocate->id]); 71 | if (!$ratingallocate->visible) { 72 | $link = html_writer::link( 73 | new moodle_url('/mod/ratingallocate/view.php', ['id' => $ratingallocate->coursemodule]), 74 | format_string($ratingallocate->name, true), 75 | ['class' => 'dimmed']); 76 | } else { 77 | $link = html_writer::link( 78 | new moodle_url('/mod/ratingallocate/view.php', ['id' => $ratingallocate->coursemodule]), 79 | format_string($ratingallocate->name, true)); 80 | } 81 | $table->data[] = [$link, userdate($ratingallocateinstance->accesstimestart), 82 | userdate($ratingallocateinstance->accesstimestop), 83 | $ratingallocateinstance->published == 0 ? get_string('no') : get_string('yes')]; 84 | 85 | } 86 | 87 | echo html_writer::table($table); 88 | echo $OUTPUT->footer(); 89 | -------------------------------------------------------------------------------- /pix/checkbox-selected.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 16 | 18 | image/svg+xml 19 | 21 | 22 | 23 | 24 | 25 | 27 | 31 | 35 | 39 | 43 | 44 | -------------------------------------------------------------------------------- /pix/checkbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 16 | 18 | image/svg+xml 19 | 21 | 22 | 23 | 24 | 25 | 27 | 31 | 35 | 39 | 43 | 44 | -------------------------------------------------------------------------------- /pix/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learnweb/moodle-mod_ratingallocate/3798407ec44256f717ac72ec1a4dedf92e6a00e9/pix/icon.png -------------------------------------------------------------------------------- /pix/monologo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /renderable.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains the definition for the renderable classes for the ratingallocate module 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 C Usener, T Reischmann 22 | * @copyright based on code by M Schulze copyright (C) 2014 M Schulze 23 | * 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | * 26 | */ 27 | defined('MOODLE_INTERNAL') || die(); 28 | 29 | /** 30 | * Renderable header 31 | * @package mod_ratingallocate 32 | */ 33 | class ratingallocate_header implements renderable { 34 | /** @var ratingallocate_db_wrapper the ratingallocate class */ 35 | public $ratingallocate = null; 36 | /** @var mixed context|null the context record */ 37 | public $context = null; 38 | /** @var bool $showintro - show or hide the intro */ 39 | public $showintro = false; 40 | /** @var int coursemoduleid - The course module id */ 41 | public $coursemoduleid = 0; 42 | 43 | /** 44 | * Construct. 45 | * 46 | * @param ratingallocate_db_wrapper $ratingallocate 47 | * @param $context 48 | * @param $showintro 49 | * @param $coursemoduleid 50 | */ 51 | public function __construct(ratingallocate_db_wrapper $ratingallocate, $context, $showintro, $coursemoduleid) { 52 | $this->ratingallocate = $ratingallocate; 53 | $this->context = $context; 54 | $this->showintro = $showintro; 55 | $this->coursemoduleid = $coursemoduleid; 56 | } 57 | } 58 | 59 | /** 60 | * Choice status 61 | * 62 | * @package mod_ratingallocate 63 | */ 64 | class ratingallocate_choice_status implements renderable { 65 | 66 | /** @var $accesstimestop */ 67 | public $accesstimestop; 68 | /** @var $accesstimestart */ 69 | public $accesstimestart; 70 | /** @var $ispublished */ 71 | public $ispublished; 72 | /** @var $publishdate */ 73 | public $publishdate; 74 | /** @var $availablechoices */ 75 | public $availablechoices; 76 | /** @var $necessarychoices */ 77 | public $necessarychoices; 78 | /** @var $ownchoices */ 79 | public $ownchoices; 80 | /** @var $allocations */ 81 | public $allocations; 82 | /** @var $strategy */ 83 | public $strategy; 84 | /** @var bool show_distribution_info specifies if the info regarding the distribution should be displayed. * */ 85 | public $showdistributioninfo; 86 | /** @var bool show_user_info specifies if the current ratings of the user shoulld be renderer. * */ 87 | public $showuserinfo; 88 | /** @var $algorithmstarttime */ 89 | public $algorithmstarttime; 90 | /** @var $algorithmstatus */ 91 | public $algorithmstatus; 92 | } 93 | -------------------------------------------------------------------------------- /settings.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Admin settings for mod_ratingallocate 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2015 Tobias Reischmann 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | defined('MOODLE_INTERNAL') || die; 25 | 26 | if ($ADMIN->fulltree) { 27 | $settings->add(new admin_setting_configtext('ratingallocate_algorithm_timeout', 28 | get_string('algorithmtimeout', 'ratingallocate'), 29 | get_string('configalgorithmtimeout', 'ratingallocate'), 600, PARAM_INT)); 30 | 31 | $settings->add(new admin_setting_configmulticheckbox('ratingallocate_download_userfields', 32 | new lang_string('downloaduserfields', 'ratingallocate'), 33 | new lang_string('configdownloaduserfields', 'ratingallocate'), 34 | [ 35 | 'id' => 1, 36 | 'username' => 1, 37 | 'department' => 0, 38 | 'institution' => 0, 39 | 'email' => 1, 40 | ], 41 | [ 42 | 'id' => new lang_string('userid', 'ratingallocate'), 43 | 'username' => new lang_string('username'), 44 | 'idnumber' => new lang_string('idnumber'), 45 | 'department' => new lang_string('department'), 46 | 'institution' => new lang_string('institution'), 47 | 'email' => new lang_string('email'), 48 | ])); 49 | 50 | $settings->add(new admin_setting_configcheckbox('ratingallocate_algorithm_force_background_execution', 51 | new lang_string('algorithmforcebackground', 'ratingallocate'), 52 | new lang_string('configalgorithmforcebackground', 'ratingallocate'), 0)); 53 | } 54 | -------------------------------------------------------------------------------- /solver/edmonds-karp.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * 19 | * Contains the algorithm for the distribution 20 | * 21 | * @package mod_ratingallocate 22 | * @subpackage mod_ratingallocate 23 | * @copyright 2014 M Schulze 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | require_once(dirname(__FILE__) . '/../locallib.php'); 29 | require_once(dirname(__FILE__) . '/solver-template.php'); 30 | 31 | /** 32 | * Solver edmonds-karp. 33 | * 34 | * @package mod_ratingallocate 35 | */ 36 | class solver_edmonds_karp extends distributor { 37 | 38 | /** 39 | * Return name. 40 | * 41 | * @return string 42 | */ 43 | public function get_name() { 44 | return 'edmonds_karp'; 45 | } 46 | 47 | /** 48 | * Compute distribution. 49 | * 50 | * @param $choicerecords 51 | * @param $ratings 52 | * @param $usercount 53 | * @return an|array 54 | * @throws moodle_exception 55 | */ 56 | public function compute_distribution($choicerecords, $ratings, $usercount) { 57 | $choicedata = []; 58 | foreach ($choicerecords as $record) { 59 | $choicedata[$record->id] = $record; 60 | } 61 | 62 | $choicecount = count($choicedata); 63 | // Index of source and sink in the graph. 64 | $source = 0; 65 | $sink = $choicecount + $usercount + 1; 66 | 67 | list($fromuserid, $touserid, $fromchoiceid, $tochoiceid) = $this->setup_id_conversions($usercount, $ratings); 68 | 69 | $this->setup_graph($choicecount, $usercount, $fromuserid, $fromchoiceid, $ratings, $choicedata, $source, $sink, -1); 70 | 71 | // Now that the datastructure is complete, we can start the algorithm 72 | // This is an adaptation of the Ford-Fulkerson algorithm 73 | // with Bellman-Ford as search function (see: Edmonds-Karp in Introduction to Algorithms) 74 | // http://stackoverflow.com/questions/6681075/while-loop-in-php-with-assignment-operator 75 | // Look for an augmenting path (a shortest path from the source to the sink). 76 | while ($path = $this->find_shortest_path_bellf($source, $sink)) { // If the function returns null, the while will stop. 77 | // Reverse the augmentin path, thereby distributing a user into a group. 78 | $this->augment_flow($path); 79 | unset($path); // Clear up old path. 80 | } 81 | return $this->extract_allocation($touserid, $tochoiceid); 82 | } 83 | 84 | /** 85 | * Bellman-Ford acc. to Cormen 86 | * 87 | * @param $from index of starting node 88 | * @param $to index of end node 89 | * @return array with the of the nodes in the path 90 | */ 91 | private function find_shortest_path_bellf($from, $to) { 92 | // Table of distances known so far. 93 | $dists = []; 94 | // Table of predecessors (used to reconstruct the shortest path later). 95 | $preds = []; 96 | 97 | // Number of nodes in the graph. 98 | $count = $this->graph['count']; 99 | 100 | // Step 1: initialize graph. 101 | for ($i = 0; $i < $count; $i++) { // For each vertex v in vertices. 102 | if ($i == $from) {// If v is source then weight[v] := 0. 103 | $dists[$i] = 0; 104 | } else {// Else set weight[v] to infinity. 105 | $dists[$i] = INF; 106 | } 107 | $preds[$i] = null; // Set predecessor[v] to null. 108 | } 109 | 110 | // Step 2: relax edges repeatedly. 111 | for ($i = 0; $i < $count; $i++) { // For i from 1 to size(vertices)-1:. 112 | $updatedsomething = false; 113 | foreach ($this->graph as $key => $edges) { // For each edge (u, v) with weight w in edges:. 114 | if (is_array($edges)) { 115 | foreach ($edges as $key2 => $edge) { 116 | if ($dists[$edge->from] + $edge->weight < $dists[$edge->to]) { // If weight[u] + w < weight[v]:. 117 | $dists[$edge->to] = $dists[$edge->from] + $edge->weight; // Set weight[v] := weight[u] + w. 118 | $preds[$edge->to] = $edge->from; // Set predecessor[v] := u. 119 | $updatedsomething = true; 120 | } 121 | } 122 | } 123 | } 124 | if (!$updatedsomething) { 125 | break; // Leave. 126 | } 127 | } 128 | 129 | // If there is no path to $to, return null. 130 | if (is_null($preds[$to])) { 131 | return null; 132 | } 133 | 134 | // Cleanup dists to save some space. 135 | unset($dists); 136 | 137 | // Use the preds table to reconstruct the shortest path. 138 | $path = []; 139 | $p = $to; 140 | while ($p != $from) { 141 | $path[] = $p; 142 | $p = $preds[$p]; 143 | } 144 | $path[] = $from; 145 | return $path; 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /solver/ford-fulkerson-koegel.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Internal library of functions for module groupdistribution. 19 | * 20 | * Contains the algorithm for the group distribution 21 | * 22 | * @package mod_ratingallocate 23 | * @subpackage mod_ratingallocate originally mod_groupdistribution 24 | * @copyright 2014 M Schulze 25 | * @copyright based on code by Stefan Koegel copyright (C) 2013 Stefan Koegel 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | require_once(dirname(__FILE__) . '/../locallib.php'); 31 | require_once(dirname(__FILE__) . '/solver-template.php'); 32 | 33 | /** 34 | * Solver Ford-fulkerson. 35 | * 36 | * @package mod_ratingallocate 37 | */ 38 | class solver_ford_fulkerson extends distributor { 39 | 40 | /** 41 | * Starts the distribution algorithm. 42 | * Uses the users' ratings and a minimum-cost maximum-flow algorithm 43 | * to distribute the users fairly into the groups. 44 | * (see http://en.wikipedia.org/wiki/Minimum-cost_flow_problem) 45 | * After the algorithm is done, users are removed from their current 46 | * groups (see clear_all_groups_in_course()) and redistributed 47 | * according to the computed distriution. 48 | * 49 | */ 50 | public function compute_distribution($choicerecords, $ratings, $usercount) { 51 | $groupdata = []; 52 | foreach ($choicerecords as $record) { 53 | $groupdata[$record->id] = $record; 54 | } 55 | 56 | $groupcount = count($groupdata); 57 | // Index of source and sink in the graph. 58 | $source = 0; 59 | $sink = $groupcount + $usercount + 1; 60 | list($fromuserid, $touserid, $fromgroupid, $togroupid) = $this->setup_id_conversions($usercount, $ratings); 61 | 62 | $this->setup_graph($groupcount, $usercount, $fromuserid, $fromgroupid, $ratings, $groupdata, $source, $sink); 63 | 64 | // Now that the datastructure is complete, we can start the algorithm 65 | // This is an adaptation of the Ford-Fulkerson algorithm 66 | // (http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm). 67 | for ($i = 1; $i <= $usercount; $i++) { 68 | // Look for an augmenting path (a shortest path from the source to the sink). 69 | $path = $this->find_shortest_path_bellmanf_koegel($source, $sink); 70 | // If there is no such path, it is impossible to fit any more users into groups. 71 | if (is_null($path)) { 72 | // Stop the algorithm. 73 | continue; 74 | } 75 | // Reverse the augmenting path, thereby distributing a user into a group. 76 | $this->augment_flow($path); 77 | } 78 | 79 | return $this->extract_allocation($touserid, $togroupid); 80 | } 81 | 82 | /** 83 | * Uses a modified Bellman-Ford algorithm to find a shortest path 84 | * from $from to $to in $graph. We can't use Dijkstra here, because 85 | * the graph contains edges with negative weight. 86 | * 87 | * @param $from index of starting node 88 | * @param $to index of end node 89 | * @return array with the of the nodes in the path 90 | * @throws moodle_exception 91 | */ 92 | public function find_shortest_path_bellmanf_koegel($from, $to) { 93 | 94 | // Table of distances known so far. 95 | $dists = []; 96 | // Table of predecessors (used to reconstruct the shortest path later). 97 | $preds = []; 98 | // Stack of the edges we need to test next. 99 | $edges = $this->graph[$from]; 100 | // Number of nodes in the graph. 101 | $count = $this->graph['count']; 102 | 103 | // To prevent the algorithm from getting stuck in a loop with 104 | // with negative weight, we stop it after $count ^ 3 iterations. 105 | $counter = 0; 106 | $limit = $count * $count * $count; 107 | 108 | // Initialize dists and preds. 109 | for ($i = 0; $i < $count; $i++) { 110 | if ($i == $from) { 111 | $dists[$i] = 0; 112 | } else { 113 | $dists[$i] = -INF; 114 | } 115 | $preds[$i] = null; 116 | } 117 | 118 | while (!empty($edges) && $counter < $limit) { 119 | $counter++; 120 | 121 | /* @var e edge */ 122 | $e = array_pop($edges); 123 | 124 | $f = $e->from; 125 | $t = $e->to; 126 | $dist = $e->weight + $dists[$f]; 127 | 128 | // If this edge improves a distance update the tables and the edges stack. 129 | if ($dist > $dists[$t]) { 130 | $dists[$t] = $dist; 131 | $preds[$t] = $f; 132 | foreach ($this->graph[$t] as $newedge) { 133 | $edges[] = $newedge; 134 | } 135 | } 136 | } 137 | 138 | // A valid groupdistribution graph can't contain a negative edge. 139 | if ($counter == $limit) { 140 | throw new \moodle_exception('negative_cycle', 'ratingallocate'); 141 | } 142 | 143 | // If there is no path to $to, return null. 144 | if (is_null($preds[$to])) { 145 | return null; 146 | } 147 | 148 | // Use the preds table to reconstruct the shortest path. 149 | $path = []; 150 | $p = $to; 151 | while ($p != $from) { 152 | $path[] = $p; 153 | $p = $preds[$p]; 154 | } 155 | $path[] = $from; 156 | 157 | return $path; 158 | } 159 | 160 | /** 161 | * Return name. 162 | * 163 | * @return string 164 | */ 165 | public function get_name() { 166 | return "ford-fulkerson Koegel2014"; 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /strategy/strategy01_yes_no.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Internal library of functions for module ratingallocate 19 | * 20 | * All the ratingallocate specific functions, needed to implement the module 21 | * logic, should go here. Never include this file from your lib.php! 22 | * 23 | * @package mod_ratingallocate 24 | * @copyright 2014 T Reischmann, C Usener 25 | * @copyright based on code by M Schulze copyright (C) 2014 M Schulze 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | 29 | namespace mod_ratingallocate\strategy_yesno; 30 | 31 | defined('MOODLE_INTERNAL') || die(); 32 | require_once($CFG->libdir . '/formslib.php'); 33 | require_once(dirname(__FILE__) . '/../locallib.php'); 34 | require_once(dirname(__FILE__) . '/strategy_template_options.php'); 35 | 36 | /** 37 | * Strategy 38 | * 39 | * @package mod_ratingallocate 40 | */ 41 | class strategy extends \strategytemplate_options { 42 | 43 | /** 44 | * Strategyid. 45 | */ 46 | const STRATEGYID = 'strategy_yesno'; 47 | /** 48 | * Maximum to deny. 49 | */ 50 | const MAXCROSSOUT = 'maxcrossout'; 51 | 52 | /** 53 | * Get strategy id. 54 | * @return string 55 | */ 56 | public function get_strategyid() { 57 | return self::STRATEGYID; 58 | } 59 | 60 | /** 61 | * Get static settingfields. 62 | * @return array|array[] 63 | * @throws \coding_exception 64 | */ 65 | public function get_static_settingfields() { 66 | $output = [ 67 | self::MAXCROSSOUT => [ 68 | 'int', 69 | get_string(self::STRATEGYID . '_setting_crossout', RATINGALLOCATE_MOD_NAME), 70 | $this->get_settings_value(self::MAXCROSSOUT), 71 | null, 72 | ], 73 | ]; 74 | foreach (array_keys($this->get_choiceoptions()) as $id) { 75 | $output[$id] = [ 76 | 'text', 77 | get_string('strategy_settings_label', RATINGALLOCATE_MOD_NAME, $this->get_settings_default_value($id)), 78 | null, 79 | $this->get_settings_default_value($id), 80 | ]; 81 | } 82 | $output += $this->get_default_strategy_option(); 83 | return $output; 84 | } 85 | 86 | /** 87 | * Get dynamic settingfields. 88 | * @return array 89 | */ 90 | public function get_dynamic_settingfields() { 91 | return []; 92 | } 93 | 94 | /** 95 | * Get choice options. 96 | * @return array 97 | */ 98 | public function get_choiceoptions() { 99 | $options = [ 100 | 0 => $this->get_settings_value(0), 101 | 1 => $this->get_settings_value(1), 102 | ]; 103 | return $options; 104 | } 105 | 106 | /** 107 | * Get default settings. 108 | * @return array 109 | * @throws \coding_exception 110 | */ 111 | public function get_default_settings() { 112 | return [ 113 | self::MAXCROSSOUT => 3, 114 | 0 => get_string(self::STRATEGYID . '_rating_crossout', RATINGALLOCATE_MOD_NAME), 115 | 1 => get_string(self::STRATEGYID . '_rating_choose', RATINGALLOCATE_MOD_NAME), 116 | 'default' => 1, 117 | ]; 118 | } 119 | 120 | /** 121 | * Get validation information. 122 | * @return array[] 123 | */ 124 | protected function getvalidationinfo() { 125 | return [self::MAXCROSSOUT => [true, 0]]; 126 | } 127 | } 128 | 129 | // Register with the strategymanager. 130 | \strategymanager::add_strategy(strategy::STRATEGYID); 131 | 132 | /** 133 | * View form 134 | * 135 | * @package mod_ratingallocate 136 | */ 137 | class mod_ratingallocate_view_form extends \ratingallocate_options_strategyform { 138 | // Already specified by parent class. 139 | 140 | /** 141 | * Create new strategy. 142 | * @param $strategyoptions 143 | * @return strategy 144 | */ 145 | protected function construct_strategy($strategyoptions) { 146 | return new strategy($strategyoptions); 147 | } 148 | 149 | /** 150 | * Get choice options. 151 | * @return mixed 152 | */ 153 | public function get_choiceoptions() { 154 | return $this->get_strategy()->get_choiceoptions(); 155 | } 156 | 157 | /** 158 | * Get maximal amount how many times a user is allowed to rate a choice with "NO". 159 | * @return mixed|\the|null 160 | */ 161 | protected function get_max_amount_of_nos() { 162 | return $this->get_strategysetting(strategy::MAXCROSSOUT); 163 | } 164 | 165 | /** 166 | * Get string identifier of max_nos. 167 | * @return string 168 | */ 169 | protected function get_max_nos_string_identyfier() { 170 | return strategy::STRATEGYID . '_max_no'; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /strategy/strategy02_yes_maybe_no.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Internal library of functions for module ratingallocate 19 | * 20 | * All the ratingallocate specific functions, needed to implement the module 21 | * logic, should go here. Never include this file from your lib.php! 22 | * 23 | * @package mod_ratingallocate 24 | * @copyright 2014 T Reischmann, C Usener 25 | * @copyright based on code by M Schulze copyright (C) 2014 M Schulze 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | 29 | // Namespace is mandatory! 30 | namespace mod_ratingallocate\strategy_yesmaybeno; 31 | 32 | defined('MOODLE_INTERNAL') || die(); 33 | require_once($CFG->libdir . '/formslib.php'); 34 | require_once(dirname(__FILE__) . '/../locallib.php'); 35 | require_once(dirname(__FILE__) . '/strategy_template_options.php'); 36 | 37 | /** 38 | * Strategy. 39 | * 40 | * @package mod_ratingallocate 41 | */ 42 | class strategy extends \strategytemplate_options { 43 | 44 | /** 45 | * Strategyid. 46 | */ 47 | const STRATEGYID = 'strategy_yesmaybeno'; 48 | /** 49 | * Maximal votes for no. 50 | */ 51 | const MAXNO = 'maxno'; 52 | 53 | /** 54 | * Get strategy id. 55 | * @return string 56 | */ 57 | public function get_strategyid() { 58 | return self::STRATEGYID; 59 | } 60 | 61 | /** 62 | * Get static settingfields of strategy. 63 | * @return array|array[] 64 | * @throws \coding_exception 65 | */ 66 | public function get_static_settingfields() { 67 | $output = [ 68 | self::MAXNO => [// Maximum count of 'No'. 69 | 'int', 70 | get_string(self::STRATEGYID . '_setting_maxno', RATINGALLOCATE_MOD_NAME), 71 | $this->get_settings_value(self::MAXNO), 72 | null, 73 | ], 74 | ]; 75 | foreach (array_keys($this->get_choiceoptions()) as $id) { 76 | $output[$id] = [ 77 | 'text', 78 | get_string('strategy_settings_label', RATINGALLOCATE_MOD_NAME, $this->get_settings_default_value($id)), 79 | null, 80 | $this->get_settings_default_value($id), 81 | ]; 82 | } 83 | $output += $this->get_default_strategy_option(); 84 | return $output; 85 | } 86 | 87 | /** 88 | * Get dynamic settingfields. 89 | * 90 | * @return array 91 | */ 92 | public function get_dynamic_settingfields() { 93 | return []; 94 | } 95 | 96 | /** 97 | * Get choiceoptions. 98 | * 99 | * @return array 100 | */ 101 | public function get_choiceoptions() { 102 | $options = [ 103 | 0 => $this->get_settings_value(0), 104 | 3 => $this->get_settings_value(3), 105 | 5 => $this->get_settings_value(5), 106 | ]; 107 | return $options; 108 | } 109 | 110 | /** 111 | * Get default settings. 112 | * 113 | * @return array 114 | * @throws \coding_exception 115 | */ 116 | public function get_default_settings() { 117 | return [ 118 | self::MAXNO => 3, 119 | 0 => get_string(self::STRATEGYID . '_rating_no', RATINGALLOCATE_MOD_NAME), 120 | 3 => get_string(self::STRATEGYID . '_rating_maybe', RATINGALLOCATE_MOD_NAME), 121 | 5 => get_string(self::STRATEGYID . '_rating_yes', RATINGALLOCATE_MOD_NAME), 122 | 'default' => 3, 123 | ]; 124 | } 125 | 126 | /** 127 | * Get validation info. 128 | * 129 | * @return array[] 130 | */ 131 | protected function getvalidationinfo() { 132 | return [self::MAXNO => [true, 0]]; 133 | } 134 | } 135 | 136 | // Register with the strategymanager. 137 | \strategymanager::add_strategy(strategy::STRATEGYID); 138 | 139 | /** 140 | * View form. 141 | * 142 | * @package mod_ratingallocate 143 | */ 144 | class mod_ratingallocate_view_form extends \ratingallocate_options_strategyform { 145 | // Already specified by parent class. 146 | 147 | /** 148 | * Create new strategy. 149 | * @param $strategyoptions 150 | * @return strategy 151 | */ 152 | protected function construct_strategy($strategyoptions) { 153 | return new strategy($strategyoptions); 154 | } 155 | 156 | /** 157 | * Get all choice options. 158 | * @return mixed 159 | */ 160 | public function get_choiceoptions() { 161 | return $this->get_strategy()->get_choiceoptions(); 162 | } 163 | 164 | /** 165 | * Get maximal amount how many times a user is allowed to rate a choice with "NO". 166 | * @return \the|null 167 | */ 168 | protected function get_max_amount_of_nos() { 169 | return $this->get_strategysetting(strategy::MAXNO); 170 | } 171 | 172 | /** 173 | * Get string identifier of max_nos. 174 | * @return string 175 | */ 176 | protected function get_max_nos_string_identyfier() { 177 | return strategy::STRATEGYID . '_max_no'; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /strategy/strategy03_lickert.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Internal library of functions for module ratingallocate 19 | * 20 | * All the ratingallocate specific functions, needed to implement the module 21 | * logic, should go here. Never include this file from your lib.php! 22 | * 23 | * @package mod_ratingallocate 24 | * @copyright 2014 M Schulze 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | // Namespace is mandatory! 29 | namespace mod_ratingallocate\strategy_lickert; 30 | 31 | defined('MOODLE_INTERNAL') || die(); 32 | require_once($CFG->libdir . '/formslib.php'); 33 | require_once(dirname(__FILE__) . '/../locallib.php'); 34 | require_once(dirname(__FILE__) . '/strategy_template_options.php'); 35 | 36 | /** 37 | * Strategy 38 | * 39 | * @package mod_ratingallocate 40 | */ 41 | class strategy extends \strategytemplate_options { 42 | 43 | /** 44 | * Strategyid. 45 | */ 46 | const STRATEGYID = 'strategy_lickert'; 47 | /** 48 | * Max NO. 49 | */ 50 | const MAXNO = 'maxno'; 51 | /** 52 | * Countlickert. 53 | */ 54 | const COUNTLICKERT = 'countlickert'; 55 | /** @var mixed $maxlickert */ 56 | private $maxlickert; 57 | 58 | /** 59 | * Constructor. 60 | * @param array|null $strategysettings 61 | * @throws \coding_exception 62 | */ 63 | public function __construct(?array $strategysettings = null) { 64 | parent::__construct($strategysettings); 65 | if (isset($strategysettings) && array_key_exists(self::COUNTLICKERT, $strategysettings)) { 66 | $this->maxlickert = $strategysettings[self::COUNTLICKERT]; 67 | } else { 68 | $this->maxlickert = $this->get_default_settings()[self::COUNTLICKERT]; 69 | } 70 | } 71 | 72 | /** 73 | * Get strategy id. 74 | * @return string 75 | */ 76 | public function get_strategyid() { 77 | return self::STRATEGYID; 78 | } 79 | 80 | /** 81 | * Get static settingfields of strategy. 82 | * @return array[] 83 | * @throws \coding_exception 84 | */ 85 | public function get_static_settingfields() { 86 | return [ 87 | self::MAXNO => [// Maximum count of 'No'. 88 | 'int', 89 | get_string(self::STRATEGYID . '_setting_maxno', RATINGALLOCATE_MOD_NAME), 90 | $this->get_settings_value(self::MAXNO), 91 | null, 92 | ], 93 | self::COUNTLICKERT => [// How many fields there are. 94 | 'int', 95 | get_string(self::STRATEGYID . '_setting_maxlickert', RATINGALLOCATE_MOD_NAME), 96 | $this->get_settings_value(self::COUNTLICKERT), 97 | null, 98 | ], 99 | ]; 100 | } 101 | 102 | /** 103 | * Get dynamic settingfields of strategy. 104 | * @return array|array[] 105 | * @throws \coding_exception 106 | */ 107 | public function get_dynamic_settingfields() { 108 | $output = []; 109 | foreach (array_keys($this->get_choiceoptions()) as $id) { 110 | $output[$id] = [ 111 | 'text', 112 | get_string('strategy_settings_label', RATINGALLOCATE_MOD_NAME, $this->get_settings_default_value($id)), 113 | null, 114 | $this->get_settings_default_value($id), 115 | ]; 116 | } 117 | $output += $this->get_default_strategy_option(); 118 | return $output; 119 | } 120 | 121 | /** 122 | * Get choiceoptions. 123 | * 124 | * @return array 125 | */ 126 | public function get_choiceoptions() { 127 | $options = []; 128 | for ($i = 0; $i <= $this->maxlickert; $i++) { 129 | $options[$i] = $this->get_settings_value($i); 130 | } 131 | return $options; 132 | } 133 | 134 | /** 135 | * Get default settings. 136 | * 137 | * @return array 138 | * @throws \coding_exception 139 | */ 140 | public function get_default_settings() { 141 | $defaults = [ 142 | self::MAXNO => 3, 143 | self::COUNTLICKERT => 4, 144 | 0 => get_string(self::STRATEGYID . '_rating_exclude', RATINGALLOCATE_MOD_NAME, "0"), 145 | 'default' => $this->maxlickert, 146 | ]; 147 | 148 | for ($i = 1; $i <= $this->maxlickert; $i++) { 149 | if ($i == $this->maxlickert) { 150 | $defaults[$i] = get_string(self::STRATEGYID . '_rating_biggestwish', RATINGALLOCATE_MOD_NAME, "$i"); 151 | } else { 152 | $defaults[$i] = $i; 153 | } 154 | } 155 | return $defaults; 156 | } 157 | 158 | /** 159 | * Get validation info. 160 | * 161 | * @return array[] 162 | */ 163 | protected function getvalidationinfo() { 164 | return [self::MAXNO => [true, 0], 165 | self::COUNTLICKERT => [true, 2], 166 | ]; 167 | } 168 | } 169 | 170 | // Register with the strategymanager. 171 | \strategymanager::add_strategy(strategy::STRATEGYID); 172 | 173 | /** 174 | * View form. 175 | * 176 | * @package mod_ratingallocate 177 | */ 178 | class mod_ratingallocate_view_form extends \ratingallocate_options_strategyform { 179 | // Already specified by parent class. 180 | 181 | /**Get maximal amount how many times a user is allowed to rate a choice with "NO". 182 | * Create new strategy. 183 | * @param $strategyoptions 184 | * @return strategy 185 | * @throws \coding_exception 186 | */ 187 | protected function construct_strategy($strategyoptions) { 188 | return new strategy($strategyoptions); 189 | } 190 | 191 | /** 192 | * Get choice options. 193 | * @return mixed 194 | */ 195 | public function get_choiceoptions() { 196 | $params = $this->get_strategysetting(strategy::COUNTLICKERT); 197 | return $this->get_strategy()->get_choiceoptions($params); 198 | } 199 | 200 | /** 201 | * 202 | * @return \the|null 203 | */ 204 | protected function get_max_amount_of_nos() { 205 | return $this->get_strategysetting(strategy::MAXNO); 206 | } 207 | 208 | /** 209 | * Get string identifier of max_nos. 210 | * @return string 211 | */ 212 | protected function get_max_nos_string_identyfier() { 213 | return strategy::STRATEGYID . '_max_no'; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .path-mod-ratingallocate ul.horizontal.choices { 2 | margin: 0; 3 | } 4 | 5 | .path-mod-ratingallocate .horizontal.choices .option { 6 | padding-right: 20px; 7 | display: inline-block; 8 | white-space: normal; 9 | } 10 | 11 | .ratingallocate_ratings_table tr.ratingallocate_summary, 12 | .ratingallocate_ratings_table span.ratingallocate_member { 13 | font-weight: bold; 14 | } 15 | 16 | .ratingallocate_ratings_table span.ratingallocate_member { 17 | display: flex; 18 | align-items: center; 19 | } 20 | 21 | /* Indicate selected choice in non-writeable tables */ 22 | .ratingallocate_ratings_table span.ratingallocate_member::before { 23 | content: url('[[pix:i/checked]]'); 24 | display: inline-block; 25 | width: 1em; 26 | height: 1em; 27 | margin-right: 5px; 28 | } 29 | 30 | .ratingallocate_ratings_table span input[type=radio] ~ label { 31 | display: flex; 32 | align-items: center; 33 | margin-bottom: 0; 34 | } 35 | 36 | /* Show a tickmark for a selected choice */ 37 | .ratingallocate_ratings_table span input[type=radio]:checked ~ label { 38 | /* necessary for containing absolute position values */ 39 | position: relative; 40 | } 41 | 42 | .ratingallocate_ratings_table span input[type=radio]:checked ~ label::before { 43 | content: url('[[pix:i/checked]]'); 44 | position: absolute; 45 | top: 1px; 46 | left: 2px; 47 | width: 12px; 48 | height: 12px; 49 | } 50 | 51 | /* Special highlight for values that were checked *initially* */ 52 | .ratingallocate_ratings_table span input[type=radio][checked] ~ label > span.ratingallocate_checkbox { 53 | background: url('[[pix:ratingallocate|checkbox-selected]]'); 54 | background-size: 13px 13px; 55 | } 56 | 57 | .ratingallocate_ratings_table span input[type=radio][checked] ~ label { 58 | font-weight: bold; 59 | } 60 | 61 | /* Checkbox/radio replacement */ 62 | .ratingallocate_ratings_table span input[type=radio] ~ label > span.ratingallocate_checkbox { 63 | display: inline-flex; 64 | height: 13px; 65 | width: 13px; 66 | margin-right: 5px; 67 | vertical-align: text-top; 68 | background: url('[[pix:ratingallocate|checkbox]]'); 69 | background-size: 13px 13px; 70 | } 71 | 72 | .ratingallocate_ratings_table span input[type=radio] { 73 | display: none; 74 | } 75 | 76 | .ratingallocate_ratings_box { 77 | overflow: auto; /* Scrolling tables */ 78 | } 79 | 80 | .path-mod-ratingallocate .mod-ratingallocate-choice-maxno { 81 | text-align: right; 82 | } 83 | 84 | .ratingallocate_distribute_unallocated { 85 | margin: 1em 1em 0 0; 86 | } 87 | 88 | .ratingallocate_ratings_table { 89 | border-collapse: separate; 90 | border-spacing: 0; 91 | } 92 | 93 | .ratingallocate_ratings_table thead th:first-child, 94 | .ratingallocate_ratings_table tbody td:first-child { 95 | position: sticky; 96 | left: 0; 97 | min-width: 10rem; 98 | max-width: 10rem; 99 | } 100 | 101 | .ratingallocate_ratings_table.includegroups tbody td:nth-child(2), 102 | .ratingallocate_ratings_table.includegroups thead th:nth-child(2) { 103 | position: sticky; 104 | left: 10rem; 105 | border-right: 2px solid #dee2e6; 106 | } 107 | 108 | .ratingallocate_ratings_table:not(.includegroups) tbody td:first-child, 109 | .ratingallocate_ratings_table:not(.includegroups) thead th:first-child { 110 | border-right: 2px solid #dee2e6; 111 | } 112 | 113 | .ratingallocate_ratings_table thead th:first-child, 114 | .ratingallocate_ratings_table.includegroups thead th:nth-child(2) { 115 | z-index: 3; 116 | } 117 | 118 | .ratingallocate_ratings_table .groupsinchoiceheadings { 119 | font-size: xx-small; 120 | } 121 | 122 | .ratingallocate_ratings_table tr.ratingallocate_summary td { 123 | position: sticky; 124 | bottom: 0; 125 | background-color: #fff; 126 | } 127 | 128 | .ratingallocate_ratings_table thead th { 129 | background-color: #fff; 130 | position: sticky; 131 | top: 0; 132 | z-index: 2; 133 | } 134 | 135 | .ratingallocate_ratings_table tbody td:first-child, 136 | .ratingallocate_ratings_table.includegroups tbody td:nth-child(2) { 137 | background-color: #fff; 138 | z-index: 1; 139 | font-weight: bold; 140 | } 141 | 142 | .ratingallocate_ratings_table_container .no-overflow { 143 | overflow: unset; 144 | } 145 | 146 | .ratingallocate_front_page_table_1 { 147 | margin: auto; 148 | width: 40%; 149 | } 150 | 151 | .ratingallocate_front_page_table_23 { 152 | margin: auto; 153 | width: 30%; 154 | padding-left: 50px; 155 | padding-right: 50px; 156 | } 157 | 158 | .ratingallocate_front_page_buttons { 159 | margin: auto; 160 | } 161 | -------------------------------------------------------------------------------- /tests/behat/allocation_status.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @javascript 2 | Feature: Students should get status information according to their rating and their allocation. 3 | 4 | Background: 5 | Given the following "courses" exist: 6 | | fullname | shortname | category | groupmode | 7 | | Course 1 | C1 | 0 | 1 | 8 | And the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Theo | Teacher | teacher1@example.com | 11 | | student1 | Steve | Student | student1@example.com | 12 | | student2 | Sophie | Student | student2@example.com | 13 | | student3 | Steffanie | Student | student3@example.com | 14 | And the following "course enrolments" exist: 15 | | user | course | role | 16 | | teacher1 | C1 | editingteacher | 17 | | student1 | C1 | student | 18 | | student2 | C1 | student | 19 | | student3 | C1 | student | 20 | And the following "activities" exist: 21 | | activity | course | idnumber | name | accesstimestart | 22 | | ratingallocate | C1 | ra1 | My Fair Allocation | ##yesterday## | 23 | And I log in as "teacher1" 24 | And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page 25 | And I add a new choice with the values: 26 | | title | My only choice | 27 | | Description (optional) | Test | 28 | | maxsize | 1 | 29 | And I log out 30 | And I log in as "student1" 31 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 32 | And I press "Edit Rating" 33 | And I press "Save changes" 34 | And I log out 35 | And I log in as "student2" 36 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 37 | And I press "Edit Rating" 38 | And I click on "Deny" "radio" 39 | And I press "Save changes" 40 | And I log out 41 | And I log in as "teacher1" 42 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 43 | And I set the following fields to these values: 44 | | Rating begins at | ##2 days ago## | 45 | | Rating ends at | ##yesterday## | 46 | And I press "id_submitbutton" 47 | And I run the scheduled task "mod_ratingallocate\task\cron_task" 48 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 49 | And I press "Publish Allocation" 50 | And I log out 51 | 52 | @javascript 53 | Scenario: As a user, who rated and was allocated, I should see my allocated choice. 54 | When I log in as "student1" 55 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 56 | Then I should see "My only choice" in the "//*[contains(@class, 'allocation')]" "xpath_element" 57 | And I should see "My only choice" in the "//*[contains(@class, 'alert-success')]" "xpath_element" 58 | 59 | @javascript 60 | Scenario: As a user, who rated and was not allocated, I should see a warning. 61 | When I log in as "student2" 62 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 63 | Then I should see "You were not allocated to any choice!" in the "//*[contains(@class, 'allocation')]" "xpath_element" 64 | And I should see "You could not be allocated to any choice." in the "//*[contains(@class, 'alert-danger')]" "xpath_element" 65 | 66 | @javascript 67 | Scenario: As a user, who did not rate, I should not see my allocated choice 68 | When I log in as "student3" 69 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 70 | Then I should not see "Your Allocation" 71 | And I should see "The rating is over." in the "//*[contains(@class, 'alert-info')]" "xpath_element" 72 | -------------------------------------------------------------------------------- /tests/behat/completion_condition_allocation.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @core_completion 2 | Feature: Set a ratingallocate activity marked as completed when a user has been allocated 3 | In order to ensure a student has been allocated 4 | As a teacher 5 | I need to set the ratingallocate to complete when the student has an allocation 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | student1 | Student | 1 | student1@example.com | 11 | | student2 | Student | 2 | student2@example.com | 12 | | teacher1 | Teacher | 1 | teacher1@example.com | 13 | And the following "courses" exist: 14 | | fullname | shortname | category | enablecompletion | 15 | | Course 1 | C1 | 0 | 1 | 16 | And the following "course enrolments" exist: 17 | | user | course | role | 18 | | teacher1 | C1 | editingteacher | 19 | | student1 | C1 | student | 20 | | student2 | C1 | student | 21 | And the following "activities" exist: 22 | | activity | course | idnumber | name | completion | completionallocation | accesstimestart | accesstimestop | 23 | | ratingallocate | C1 | ra1 | My Fair Allocation | 2 | 1 | ##2 days ago## | ##yesterday## | 24 | And the following choices exist: 25 | | title | explanation | maxsize | ratingallocate | 26 | | C1 | Test | 1 | My Fair Allocation | 27 | | C2 | Test | 0 | My Fair Allocation | 28 | And the following ratings exist: 29 | | choice | user | rating | 30 | | C1 | student1 | 1 | 31 | | C1 | student2 | 0 | 32 | | C2 | student1 | 0 | 33 | | C2 | student2 | 0 | 34 | And I log in as "teacher1" 35 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 36 | And I run the scheduled task "mod_ratingallocate\task\cron_task" 37 | And I press "Publish Allocation" 38 | And I wait "1" seconds 39 | And I run the scheduled task "core\task\completion_regular_task" 40 | And I wait "1" seconds 41 | And I log out 42 | 43 | @javascript 44 | Scenario: User completes ratingallocate only if they have been allocated 45 | When I log in as "teacher1" 46 | And I am on "Course 1" course homepage 47 | Then "Student 1" user has completed "My Fair Allocation" activity 48 | And "Student 2" user has not completed "My Fair Allocation" activity 49 | -------------------------------------------------------------------------------- /tests/behat/completion_condition_vote.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @core_completion 2 | Feature: Set a ratingallocate activity marked as completed when a user submits a vote 3 | In order to ensure a student has voted in the activity 4 | As a teacher 5 | I need to set the ratingallocate to complete when the student has voted 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | student1 | Student | 1 | student1@example.com | 11 | | student2 | Student | 2 | student2@example.com | 12 | | teacher1 | Teacher | 1 | teacher1@example.com | 13 | And the following "courses" exist: 14 | | fullname | shortname | category | enablecompletion | 15 | | Course 1 | C1 | 0 | 1 | 16 | And the following "course enrolments" exist: 17 | | user | course | role | 18 | | teacher1 | C1 | editingteacher | 19 | | student1 | C1 | student | 20 | | student2 | C1 | student | 21 | And the following "activities" exist: 22 | | activity | course | idnumber | name | completion | completionvote | 23 | | ratingallocate | C1 | ra1 | My Fair Allocation | 2 | 1 | 24 | And I log in as "teacher1" 25 | And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page 26 | And I add a new choice with the values: 27 | | title | My first choice | 28 | | Description (optional) | Test 1 | 29 | | maxsize | 2 | 30 | 31 | @javascript 32 | Scenario: User completes ratingallocate only if they voted 33 | When I log in as "student1" 34 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 35 | And I press "Edit Rating" 36 | And I press "Save changes" 37 | And I log out 38 | And I log in as "teacher1" 39 | And I am on "Course 1" course homepage 40 | And I navigate to "Reports" in current page administration 41 | And I click on "Activity completion" "link" 42 | Then "Completed" "icon" should exist in the "Student 1" "table_row" 43 | And "Completed" "icon" should not exist in the "Student 2" "table_row" 44 | -------------------------------------------------------------------------------- /tests/behat/completion_manual.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @core_completion 2 | Feature: Manually mark a ratingallocate activity as completed 3 | In order to meet manual ratingallocate completion requirements 4 | As a student 5 | I need to be able to view and modify my ratingallocate manual completion status 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | student1 | Student | 1 | student1@example.com | 11 | | teacher1 | Teacher | 1 | teacher1@example.com | 12 | And the following "courses" exist: 13 | | fullname | shortname | category | enablecompletion | 14 | | Course 1 | C1 | 0 | 1 | 15 | And the following "course enrolments" exist: 16 | | user | course | role | 17 | | teacher1 | C1 | editingteacher | 18 | | student1 | C1 | student | 19 | And the following "activities" exist: 20 | | activity | course | idnumber | name | completion | 21 | | ratingallocate | C1 | ra1 | My Fair Allocation | 1 | 22 | And I log in as "teacher1" 23 | And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page 24 | And I add a new choice with the values: 25 | | title | My first choice | 26 | | Description (optional) | Test 1 | 27 | | maxsize | 2 | 28 | 29 | @javascript 30 | Scenario: Use manual completion as teacher 31 | When I log in as "teacher1" 32 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 33 | Then the manual completion button for "My Fair Allocation" should be disabled 34 | 35 | @javascript 36 | Scenario: Use manual completion student view 37 | When I log in as "student1" 38 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 39 | Then the manual completion button of "My Fair Allocation" is displayed as "Mark as done" 40 | And I toggle the manual completion state of "My Fair Allocation" 41 | And the manual completion button of "My Fair Allocation" is displayed as "Done" 42 | -------------------------------------------------------------------------------- /tests/behat/defaultratings.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @javascript 2 | Feature: When a student starts a rating the default values of all choices 3 | are set according to the instance settings. 4 | 5 | Background: 6 | Given the following "courses" exist: 7 | | fullname | shortname | category | groupmode | 8 | | Course 1 | C1 | 0 | 1 | 9 | And the following "users" exist: 10 | | username | firstname | lastname | email | 11 | | teacher1 | Teacher | 1 | teacher1@example.com | 12 | | student1 | Student | 1 | student1@example.com | 13 | And the following "course enrolments" exist: 14 | | user | course | role | 15 | | teacher1 | C1 | editingteacher | 16 | | student1 | C1 | student | 17 | And the following "activities" exist: 18 | | activity | course | idnumber | name | 19 | | ratingallocate | C1 | ra1 | My Fair Allocation | 20 | And I log in as "teacher1" 21 | And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page 22 | And I add a new choice with the values: 23 | | title | My first choice | 24 | | Description (optional) | Test 1 | 25 | | maxsize | 2 | 26 | And I add a new choice with the values: 27 | | title | My second choice | 28 | | Description (optional) | Test 1 | 29 | | maxsize | 2 | 30 | 31 | @javascript 32 | Scenario: The default rating is the max rating 33 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 34 | And I select "strategy_lickert" from the "strategy" singleselect 35 | And I press "id_submitbutton" 36 | And I log out 37 | When I log in as "student1" 38 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 39 | And I press "Edit Rating" 40 | Then I should see the following rating form: 41 | | My first choice | 4 | 42 | | My second choice | 4 | 43 | 44 | @javascript 45 | Scenario: The default rating should be changeable to a medium rating 46 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 47 | And I select "strategy_lickert" from the "strategy" singleselect 48 | And I select "3" from the "strategyopt[strategy_lickert][default]" singleselect 49 | And I press "id_submitbutton" 50 | And I log out 51 | When I log in as "student1" 52 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 53 | And I press "Edit Rating" 54 | Then I should see the following rating form: 55 | | My first choice | 3 | 56 | | My second choice | 3 | 57 | 58 | @javascript 59 | Scenario: The default rating should be changeable to the lowest rating 60 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 61 | And I select "strategy_lickert" from the "strategy" singleselect 62 | And I select "0" from the "strategyopt[strategy_lickert][default]" singleselect 63 | And I press "id_submitbutton" 64 | And I log out 65 | When I log in as "student1" 66 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 67 | And I press "Edit Rating" 68 | Then I should see the following rating form: 69 | | My first choice | 0 | 70 | | My second choice | 0 | 71 | 72 | @javascript 73 | Scenario: The default rating is the max rating 74 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 75 | And I select "strategy_lickert" from the "strategy" singleselect 76 | And I press "id_submitbutton" 77 | And I log out 78 | When I log in as "student1" 79 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 80 | And I press "Edit Rating" 81 | And I set the rating form to the following values: 82 | | My first choice | 2 | 83 | | My second choice | 3 | 84 | And I press "Save changes" 85 | And I press "Edit Rating" 86 | Then I should see the following rating form: 87 | | My first choice | 2 | 88 | | My second choice | 3 | 89 | -------------------------------------------------------------------------------- /tests/behat/manual_allocation.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate 2 | Feature: Teachers should be able to alter the allocations manually. 3 | 4 | Background: 5 | Given the following "courses" exist: 6 | | fullname | shortname | category | groupmode | 7 | | Course 1 | C1 | 0 | 1 | 8 | And the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Theo | Teacher | teacher1@example.com | 11 | | student1 | Steve | Student | student1@example.com | 12 | | student2 | Sophie | Student | student2@example.com | 13 | | student3 | Stefanie | Student | student3@example.com | 14 | And the following "course enrolments" exist: 15 | | user | course | role | 16 | | teacher1 | C1 | editingteacher | 17 | | student1 | C1 | student | 18 | | student2 | C1 | student | 19 | | student3 | C1 | student | 20 | And the following "activities" exist: 21 | | activity | course | idnumber | name | accesstimestart | accesstimestop | 22 | | ratingallocate | C1 | ra1 | My Fair Allocation | ##yesterday## | ##yesterday## | 23 | And the following choices exist: 24 | | title | explanation | maxsize | ratingallocate | 25 | | C1 | Test | 1 | My Fair Allocation | 26 | | C2 | Test | 1 | My Fair Allocation | 27 | And the following ratings exist: 28 | | choice | user | rating | 29 | | C1 | student1 | 1 | 30 | | C1 | student2 | 0 | 31 | | C2 | student1 | 0 | 32 | | C2 | student2 | 1 | 33 | And I run the scheduled task "mod_ratingallocate\task\cron_task" 34 | 35 | Scenario: As a teacher, I want to allocate a so far not allocated user. 36 | And I log in as "teacher1" 37 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 38 | And I press "Manual Allocation Form" 39 | Then I should see "Steve" assigned to "C1" 40 | And I should see "Steve" not assigned to "C2" 41 | And I should see "Sophie" not assigned to "C1" 42 | And I should see "Sophie" assigned to "C2" 43 | And I should not see "Stefanie" 44 | When I assign "Steve" to choice "C2" 45 | And I press "Save and Continue" 46 | Then I should see "Steve" not assigned to "C1" 47 | And I should see "Steve" assigned to "C2" 48 | And I should see "Sophie" not assigned to "C1" 49 | And I should see "Sophie" assigned to "C2" 50 | When I assign "Sophie" to choice "C1" 51 | And I press "Save and Continue" 52 | Then I should see "Steve" not assigned to "C1" 53 | And I should see "Steve" assigned to "C2" 54 | And I should see "Sophie" assigned to "C1" 55 | And I should see "Sophie" not assigned to "C2" 56 | -------------------------------------------------------------------------------- /tests/behat/mod_form.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @javascript 2 | Feature: Creating a new rating allocation, where new choices need to 3 | be added and if necessary deleted prior to submission. 4 | 5 | Background: 6 | Given the following "courses" exist: 7 | | fullname | shortname | category | groupmode | 8 | | Course 1 | C1 | 0 | 1 | 9 | And the following "users" exist: 10 | | username | firstname | lastname | email | 11 | | teacher1 | Teacher | 1 | teacher1@example.com | 12 | | student1 | Student | 1 | student1@example.com | 13 | And the following "course enrolments" exist: 14 | | user | course | role | 15 | | teacher1 | C1 | editingteacher | 16 | | student1 | C1 | student | 17 | And I log in as "teacher1" 18 | And I am on "Course 1" course homepage with editing mode on 19 | And I add a ratingallocate to course "Course 1" section "0" and I fill the form with: 20 | | id_name | My Fair Allocation | 21 | And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page 22 | And I add a new choice with the values: 23 | | title | My first choice | 24 | | Description (optional) | Test 1 | 25 | | maxsize | 2 | 26 | And I add a new choice with the values: 27 | | title | My second choice | 28 | | Description (optional) | Test 2 | 29 | | maxsize | 2 | 30 | And I add a new choice with the values: 31 | | title | My third choice | 32 | | Description (optional) | Test 3 | 33 | | maxsize | 2 | 34 | And the default editor is set to "textarea" 35 | 36 | Scenario: Create a new rating alloation and add an additonal new choice. 37 | Given I add a new choice with the values: 38 | | title | My fourth choice | 39 | | Description (optional) | Test 4 | 40 | | maxsize | 2 | 41 | Then I should see the choice with the title "My first choice" 42 | And I should see the choice with the title "My second choice" 43 | And I should see the choice with the title "My third choice" 44 | And I should see the choice with the title "My fourth choice" 45 | 46 | Scenario: Create a new rating alloation and add two additonal new choices using the add next button. 47 | Given I add new choices with the values: 48 | | title | Description (optional) | maxsize | 49 | | My fourth choice | Test 4 | 2 | 50 | | My fifth choice | Test 5 | 2 | 51 | Then I should see the choice with the title "My first choice" 52 | And I should see the choice with the title "My second choice" 53 | And I should see the choice with the title "My third choice" 54 | And I should see the choice with the title "My fourth choice" 55 | And I should see the choice with the title "My fifth choice" 56 | 57 | Scenario: Create a new rating alloation and add two additonal new choices, but delete two old and one new. 58 | When I add new choices with the values: 59 | | title | Description (optional) | maxsize | 60 | | My fourth choice | Test 4 | 2 | 61 | | My fifth choice | Test 5 | 2 | 62 | And I delete the choice with the title "My first choice" 63 | And I delete the choice with the title "My second choice" 64 | And I delete the choice with the title "My fifth choice" 65 | 66 | Then I should not see the choice with the title "My first choice" 67 | And I should not see the choice with the title "My second choice" 68 | And I should see the choice with the title "My third choice" 69 | And I should see the choice with the title "My fourth choice" 70 | And I should not see the choice with the title "My fifth choice" 71 | 72 | Scenario: Create a new rating alloation and add an additonal new active choice. 73 | When I add a new choice with the values: 74 | | title | My fourth choice | 75 | | Description (optional) | Test 4 | 76 | | maxsize | 1337 | 77 | | active | true | 78 | And I should see the choice with the title "My fourth choice" 79 | And the choice with name "My fourth choice" should have explanation being equal to "Test 4" 80 | And the choice with name "My fourth choice" should have maxsize being equal to 1337 81 | And the choice with name "My fourth choice" should be active 82 | 83 | Scenario: Create a new rating alloation and add an additonal new inactive choice. 84 | When I add a new choice with the values: 85 | | title | My fourth choice | 86 | | Description (optional) | Test 4 | 87 | | maxsize | 1337 | 88 | | active | false | 89 | And I should see the choice with the title "My fourth choice" 90 | And the choice with name "My fourth choice" should have explanation being equal to "Test 4" 91 | And the choice with name "My fourth choice" should have maxsize being equal to 1337 92 | And the choice with name "My fourth choice" should not be active 93 | 94 | Scenario: Create a new rating alloation and add an additonal new inactive choice. Change the the choice to active. 95 | When I add a new choice with the values: 96 | | title | My fourth choice | 97 | | Description (optional) | This is my discription | 98 | | maxsize | 1231243 | 99 | | active | false | 100 | Then I set the choice with the title "My fourth choice" to active 101 | And I should see "My fourth choice" 102 | And the choice with name "My fourth choice" should be active 103 | 104 | Scenario: Create a new rating alloation and add an additonal new active choice. Change the the choice to inactive. 105 | When I add a new choice with the values: 106 | | title | My fourth choice | 107 | | Description (optional) | This is my discription | 108 | | maxsize | 1231243 | 109 | | active | true | 110 | Then I set the choice with the title "My fourth choice" to inactive 111 | And I should see "My fourth choice" 112 | And the choice with name "My fourth choice" should not be active 113 | 114 | Scenario: Create a new rating alloation and check the field runalgorithmbycron. It should be saved as true. 115 | When I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 116 | And I set the field "runalgorithmbycron" to "1" 117 | And I press "id_submitbutton" 118 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 119 | Then the field "runalgorithmbycron" matches value "1" 120 | 121 | Scenario: Create a new rating alloation and uncheck the field runalgorithmbycron. It should be saved as false. 122 | When I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 123 | And I set the field "runalgorithmbycron" to "" 124 | And I press "id_submitbutton" 125 | And I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 126 | Then the field "runalgorithmbycron" matches value "" 127 | 128 | Scenario: Create a new rating alloation and assume the default for the field runalgorithmbycron is true. 129 | When I am on the "My Fair Allocation" "mod_ratingallocate > Edit" page 130 | Then the field "runalgorithmbycron" matches value "1" 131 | -------------------------------------------------------------------------------- /tests/behat/ratings.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @javascript 2 | Feature: When a student rates a rating should be saved and it should be possible to delete it again. 3 | 4 | Background: 5 | Given the following "courses" exist: 6 | | fullname | shortname | category | groupmode | 7 | | Course 1 | C1 | 0 | 1 | 8 | And the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | student1 | Student | 1 | student1@example.com | 11 | And the following "course enrolments" exist: 12 | | user | course | role | 13 | | student1 | C1 | student | 14 | And the following "activities" exist: 15 | | activity | course | idnumber | name | 16 | | ratingallocate | C1 | ra1 | My Fair Allocation | 17 | And the following choices exist: 18 | | title | maxsize | ratingallocate | 19 | | My first choice | 2 | My Fair Allocation | 20 | | My second choice | 2 | My Fair Allocation | 21 | | My third choice | 2 | My Fair Allocation | 22 | 23 | @javascript 24 | Scenario: The user can create a rating 25 | When I log in as "student1" 26 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 27 | And I press "Edit Rating" 28 | And I press "Save changes" 29 | Then the user "student1" should have ratings 30 | 31 | @javascript 32 | Scenario: The user can delete a rating 33 | When I log in as "student1" 34 | And I am on the "My Fair Allocation" "mod_ratingallocate > View" page 35 | And I press "Edit Rating" 36 | And I press "Save changes" 37 | Then the user "student1" should have ratings 38 | When I press "Delete Rating" 39 | Then the user "student1" should not have ratings 40 | -------------------------------------------------------------------------------- /tests/behat/select_strategy.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @javascript 2 | Feature: When a teacher selects a strategy the appropriate options are displayed 3 | 4 | Background: 5 | Given the following "courses" exist: 6 | | fullname | shortname | category | groupmode | 7 | | Course 1 | CO1 | 0 | 1 | 8 | And the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Teacher | 1 | teacher1@example.com | 11 | And the following "course enrolments" exist: 12 | | user | course | role | 13 | | teacher1 | CO1 | editingteacher | 14 | And I log in as "teacher1" 15 | And I am on "Course 1" course homepage with editing mode on 16 | And I add a ratingallocate to course "Course 1" section "1" 17 | 18 | @javascript 19 | Scenario: The correct options are displayed for the default strategy (Yes-No) 20 | Then the field "Rating strategy" matches value "Accept-Deny" 21 | And I should see "Maximum number of choices the user can rate with \"Deny\"" 22 | And I should see "Designation for \"Deny\"" 23 | 24 | @javascript 25 | Scenario: Selecting "Likert Scale" strategy should show the correct options. 26 | When I select "strategy_lickert" from the "strategy" singleselect 27 | Then I should see "Maximum number of choices the user can rate with 0" 28 | And I should see "Highest number on the likert scale" 29 | And I should see "Designation for \"0 - Exclude\"" 30 | And I should not see "Maximum number of choices the user can rate with \"Deny\"" 31 | And I should not see "Designation for \"Deny\"" 32 | 33 | @javascript 34 | Scenario: Selecting "Give Points" then "Yes-No" shows only the correct options. 35 | When I select "strategy_points" from the "strategy" singleselect 36 | And I should see "Maximum number of choices to which the user can give 0 points" 37 | And I should see "Total number of points the user can assign" 38 | And I select "strategy_yesno" from the "strategy" singleselect 39 | Then I should see "Maximum number of choices the user can rate with \"Deny\"" 40 | And I should see "Designation for \"Deny\"" 41 | And I should not see "Maximum number of choices to which the user can give 0 points" 42 | And I should not see "Total number of points the user can assign" 43 | -------------------------------------------------------------------------------- /tests/behat/validate_rating.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate @javascript 2 | Feature: When a student attempts to rate choices it should be validated prior to changing. 3 | 4 | Background: 5 | Given the following "courses" exist: 6 | | fullname | shortname | category | groupmode | 7 | | Course 1 | C1 | 0 | 1 | 8 | And the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Teacher | 1 | teacher1@example.com | 11 | | student1 | Student | 1 | student1@example.com | 12 | And the following "course enrolments" exist: 13 | | user | course | role | 14 | | teacher1 | C1 | editingteacher | 15 | | student1 | C1 | student | 16 | And I log in as "teacher1" 17 | And I am on "Course 1" course homepage with editing mode on 18 | And I add a ratingallocate to course "Course 1" section "1" and I fill the form with: 19 | | id_name | Validated Rating | 20 | | strategy | strategy_points | 21 | | Rating begins at | ##2 days ago## | 22 | | strategyopt[strategy_points][maxzero] | 2 | 23 | And I am on the "Validated Rating" "mod_ratingallocate > Choices" page 24 | And I add a new choice with the values: 25 | | title | My first choice | 26 | | Description (optional) | Test 1 | 27 | | maxsize | 2 | 28 | And I add a new choice with the values: 29 | | title | My second choice | 30 | | Description (optional) | Test 2 | 31 | | maxsize | 2 | 32 | And I add a new choice with the values: 33 | | title | My third choice | 34 | | Description (optional) | Test 3 | 35 | | maxsize | 2 | 36 | And I add a new choice with the values: 37 | | title | My fourth choice | 38 | | Description (optional) | Test 4 | 39 | | maxsize | 2 | 40 | And I log out 41 | 42 | Scenario: The user cannot enter values less than 0. 43 | When I log in as "student1" 44 | And I am on the "Validated Rating" "mod_ratingallocate > View" page 45 | And I press "Edit Rating" 46 | And I rate choices with the following points: 47 | | My first choice | -1 | 48 | | My second choice | 1 | 49 | | My third choice | 1 | 50 | | My fourth choice | 99 | 51 | And I press "Save changes" 52 | Then I should see "The points that you assign to a choice must be between 0 and 100." 53 | 54 | Scenario: The values entered by the user must sum up to the (default) maximum. 55 | When I log in as "student1" 56 | And I am on the "Validated Rating" "mod_ratingallocate > View" page 57 | And I press "Edit Rating" 58 | And I rate choices with the following points: 59 | | My first choice | 1 | 60 | | My second choice | 2 | 61 | | My third choice | 3 | 62 | | My fourth choice | 4 | 63 | And I press "Save changes" 64 | Then I should see "Incorrect total number of points. The sum of all points has to be 100." 65 | 66 | Scenario: The user may not rate more than a (default) number of choices with 0. 67 | When I log in as "student1" 68 | And I am on the "Validated Rating" "mod_ratingallocate > View" page 69 | And I press "Edit Rating" 70 | And I rate choices with the following points: 71 | | My first choice | 0 | 72 | | My second choice | 0 | 73 | | My third choice | 0 | 74 | | My fourth choice | 100 | 75 | And I press "Save changes" 76 | Then I should see "You may give 0 points to at most 2 choice(s)." 77 | -------------------------------------------------------------------------------- /tests/behat/visibile_calendar_events.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_ratingallocate 2 | Feature: Students should only see the ratingallocate calendar events if they are able to rate. 3 | 4 | Background: 5 | Given the following "courses" exist: 6 | | fullname | shortname | category | groupmode | 7 | | Course 1 | C1 | 0 | 1 | 8 | And the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Theo | Teacher | teacher1@example.com | 11 | | student1 | Steve | Student | student1@example.com | 12 | | student2 | Sophie | Student | student2@example.com | 13 | And the following "course enrolments" exist: 14 | | user | course | role | 15 | | teacher1 | C1 | editingteacher | 16 | | student1 | C1 | student | 17 | | student2 | C1 | student | 18 | And the following "groups" exist: 19 | | name | course | idnumber | 20 | | group1 | C1 | G1 | 21 | | group2 | C1 | G2 | 22 | And the following "group members" exist: 23 | | user | group | 24 | | student1 | G1 | 25 | | student2 | G1 | 26 | And the following "activities" exist: 27 | | activity | course | idnumber | name | accesstimestart | accesstimestop | accesstype | 28 | | ratingallocate | C1 | ra1 | My Fair Allocation | ##1 May 2023## | ##2 May 2023## | group1 | 29 | 30 | @javascript 31 | Scenario: As a user that is able to rate, I should see the event 32 | Given I log in as "student1" 33 | And I view the calendar for "5" "2023" 34 | Then I should see "My Fair Allocation opens" 35 | And I should see "My Fair Allocation closes" 36 | 37 | Scenario: As a user that is not able to rate, I should not see the event 38 | Given I log in as "student2" 39 | And I view the calendar for "5" "2023" 40 | Then I should not see "My Fair Allocation begins" 41 | And I should not see "My Fair Allocation ends" 42 | -------------------------------------------------------------------------------- /tests/mod_generator_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_ratingallocate; 18 | defined('MOODLE_INTERNAL') || die(); 19 | 20 | global $CFG; 21 | require_once(dirname(__FILE__) . '/../locallib.php'); 22 | 23 | /** 24 | * mod_ratingallocate generator tests 25 | * 26 | * @package mod_ratingallocate 27 | * @category test 28 | * @group mod_ratingallocate 29 | * @copyright usener 30 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 | * @covers \mod_ratingallocate_generator 32 | */ 33 | final class mod_generator_test extends \advanced_testcase { 34 | 35 | public function test_create_instance(): void { 36 | 37 | global $DB, $USER; 38 | \core_php_time_limit::raise(); 39 | $this->resetAfterTest(); 40 | $this->setAdminUser(); 41 | 42 | $course = $this->getDataGenerator()->create_course(); 43 | 44 | // There should not be any module for that course first. 45 | $this->assertFalse( 46 | $DB->record_exists('ratingallocate', ['course' => $course->id, 47 | ])); 48 | $records = $DB->get_records('ratingallocate_choices', [], 'id'); 49 | $this->assertEquals(0, count($records)); 50 | 51 | // Create activity. 52 | $mod = \mod_ratingallocate_generator::create_instance_with_choices($this, 53 | ['course' => $course]); 54 | $records = $DB->get_records('ratingallocate', ['course' => $course->id, 55 | ], 'id'); 56 | $this->assertEquals(1, count($records)); 57 | $this->assertTrue(array_key_exists($mod->id, $records)); 58 | $expectedvaluesdb = [ 59 | 'id' => $mod->id, 60 | 'course' => $course->id, 61 | 'name' => 'Rating Allocation', 62 | 'intro' => 'Test ratingallocate 1', 63 | 'introformat' => '0', 64 | 'timecreated' => reset($records)->{'timecreated'}, 65 | 'timemodified' => '0', 66 | 'accesstimestart' => reset($records)->{'accesstimestart'}, 67 | 'accesstimestop' => reset($records)->{'accesstimestop'}, 68 | 'setting' => '{"strategy_yesno":{"maxcrossout":"1"}}', 69 | 'strategy' => 'strategy_yesno', 70 | 'publishdate' => reset($records)->{'publishdate'}, 71 | 'published' => '0', 72 | 'notificationsend' => '0', 73 | 'algorithmstarttime' => null, 74 | 'algorithmstatus' => '0', 75 | 'runalgorithmbycron' => '1', 76 | 'completionvote' => '0', 77 | 'completionallocation' => '0', 78 | ]; 79 | 80 | $this->assertEquals(json_decode(json_encode($expectedvaluesdb, false)), reset($records)); 81 | // Must have two choices. 82 | $records = $DB->get_records('ratingallocate_choices', 83 | ['ratingallocateid' => $mod->id, 84 | ], 'title'); 85 | $this->assertEquals(2, count($records)); 86 | $choiceids = array_keys($records); 87 | $expectedchoices = [ 88 | $choiceids[0] => (object) [ 89 | 'title' => 'Choice 1', 90 | 'id' => $choiceids[0], 91 | 'ratingallocateid' => $mod->id, 92 | 'explanation' => 'Some explanatory text for choice 1', 93 | 'maxsize' => '10', 94 | 'usegroups' => '0', 95 | 'active' => '1', 96 | ], 97 | $choiceids[1] => (object) [ 98 | 'title' => 'Choice 2', 99 | 'id' => $choiceids[1], 100 | 'ratingallocateid' => $mod->id, 101 | 'explanation' => 'Some explanatory text for choice 2', 102 | 'maxsize' => '5', 103 | 'usegroups' => '0', 104 | 'active' => '0', 105 | ], 106 | ]; 107 | $this->assertEquals($expectedchoices, $records); 108 | 109 | // Create an other mod_ratingallocate within the course. 110 | $params = ['course' => $course->id, 'name' => 'Another mod_ratingallocate', 111 | ]; 112 | $mod = \mod_ratingallocate_generator::create_instance_with_choices($this, $params); 113 | $records = $DB->get_records('ratingallocate', ['course' => $course->id, 114 | ], 'id'); 115 | // Are there 2 modules within the course? 116 | $this->assertEquals(2, count($records)); 117 | // Is the name correct? 118 | $this->assertEquals('Another mod_ratingallocate', $records[$mod->id]->name); 119 | 120 | $records = $DB->get_records('ratingallocate_choices', [], 'id'); 121 | $this->assertEquals(4, count($records)); 122 | 123 | // Other tables. 124 | $records = $DB->get_records('ratingallocate_ratings', [], 'id'); 125 | $this->assertEquals(0, count($records)); 126 | $records = $DB->get_records('ratingallocate_allocations', [], 'id'); 127 | $this->assertEquals(0, count($records)); 128 | } 129 | 130 | public function test_mod_ratingallocate_generated_module(): void { 131 | $choicedata = \mod_ratingallocate_generator::get_default_choice_data(); 132 | foreach ($choicedata as $id => $choice) { 133 | $choice['maxsize'] = 10; 134 | $choice['active'] = true; 135 | $choicedata[$id] = $choice; 136 | } 137 | $moduledata = \mod_ratingallocate_generator::get_default_values(); 138 | $moduledata['num_students'] = 22; 139 | $testmodule = new \mod_ratingallocate_generated_module($this, $moduledata, $choicedata); 140 | $this->assertCount($moduledata['num_students'], $testmodule->students); 141 | $this->assertCount(20, $testmodule->allocations); 142 | 143 | $ratingallocate = \mod_ratingallocate_generator::get_ratingallocate_for_user( 144 | $this, $testmodule->moddb, $testmodule->teacher); 145 | foreach ($ratingallocate->get_choices_with_allocationcount() as $choice) { 146 | $this->assertEquals(10, $choice->{'usercount'}); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /tests/mod_ratingallocate_notification_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_ratingallocate; 18 | defined('MOODLE_INTERNAL') || die(); 19 | require_once(__DIR__ . '/../locallib.php'); 20 | 21 | /** 22 | * Tests the notifications when allocations are published. 23 | * 24 | * @package mod_ratingallocate 25 | * @category test 26 | * @group mod_ratingallocate 27 | * @copyright 2018 T Reischmann 28 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 | */ 30 | final class mod_ratingallocate_notification_test extends \advanced_testcase { 31 | 32 | /** 33 | * Choice 1. 34 | */ 35 | const CHOICE1 = 'Choice 1'; 36 | /** 37 | * Choice 2. 38 | */ 39 | const CHOICE2 = 'Choice 2'; 40 | 41 | /** 42 | * Tests if publishing the allocation send messages with the right content to the right users. 43 | * 44 | * @covers ::send_distribution_notification() 45 | */ 46 | public function test_allocation_notification(): void { 47 | $course = $this->getDataGenerator()->create_course(); 48 | $students = []; 49 | for ($i = 1; $i <= 4; $i++) { 50 | $students[$i] = \mod_ratingallocate_generator::create_user_and_enrol($this, $course); 51 | } 52 | $choices = [ 53 | [ 54 | 'title' => self::CHOICE1, 55 | 'maxsize' => '1', 56 | 'active' => '1', 57 | ], 58 | [ 59 | 'title' => self::CHOICE2, 60 | 'maxsize' => '1', 61 | 'active' => '1', 62 | ], 63 | ]; 64 | $ratings = [ 65 | $students[1]->id => [ 66 | [ 67 | 'choice' => self::CHOICE1, 68 | 'rating' => 1, 69 | ], 70 | [ 71 | 'choice' => self::CHOICE2, 72 | 'rating' => 0, 73 | ], 74 | ], 75 | $students[2]->id => [ 76 | [ 77 | 'choice' => self::CHOICE1, 78 | 'rating' => 0, 79 | ], 80 | [ 81 | 'choice' => self::CHOICE2, 82 | 'rating' => 1, 83 | ], 84 | ], 85 | $students[3]->id => [ 86 | [ 87 | 'choice' => self::CHOICE1, 88 | 'rating' => 0, 89 | ], 90 | [ 91 | 'choice' => self::CHOICE2, 92 | 'rating' => 0, 93 | ], 94 | ], 95 | ]; 96 | 97 | $ratingallocate = \mod_ratingallocate_generator::get_closed_ratingallocate_for_teacher($this, $choices, 98 | $course, $ratings); 99 | $allocations = $ratingallocate->get_allocations(); 100 | $this->assertArrayHasKey($students[1]->id, $allocations); 101 | $this->assertArrayHasKey($students[2]->id, $allocations); 102 | $this->assertCount(2, $allocations); 103 | $choices = $ratingallocate->get_choices(); 104 | $this->assertEquals(self::CHOICE1, $choices[$allocations[$students[1]->id]->choiceid]->title); 105 | $this->assertEquals(self::CHOICE2, $choices[$allocations[$students[2]->id]->choiceid]->title); 106 | 107 | $this->preventResetByRollback(); 108 | $messagesink = $this->redirectMessages(); 109 | 110 | // Create a notification task. 111 | $task = new \mod_ratingallocate\task\send_distribution_notification(); 112 | 113 | // Add custom data. 114 | $task->set_component('mod_ratingallocate'); 115 | $task->set_custom_data([ 116 | 'ratingallocateid' => $ratingallocate->ratingallocate->id, 117 | ]); 118 | 119 | $this->setAdminUser(); 120 | $task->execute(); 121 | 122 | $messages = $messagesink->get_messages(); 123 | $this->assertEquals(3, count($messages)); 124 | $this->assert_message_contains($messages, $students[1]->id, self::CHOICE1); 125 | $this->assert_message_contains($messages, $students[2]->id, self::CHOICE2); 126 | $this->assert_message_contains($messages, $students[3]->id, 'could not'); 127 | $this->assert_no_message_for_user($messages, $students[4]->id); 128 | } 129 | 130 | /** 131 | * Asserts that a message for a user exists and that it contains a certain search string 132 | * @param $messages \stdClass[] received messages 133 | * @param $userid int id of the user 134 | * @param $needle string search string 135 | */ 136 | private function assert_message_contains($messages, $userid, $needle) { 137 | $messageexists = false; 138 | foreach ($messages as $message) { 139 | if ($message->useridto == $userid) { 140 | $messageexists = true; 141 | $this->assertStringContainsString($needle, $message->fullmessage); 142 | } 143 | } 144 | $this->assertTrue($messageexists, 'Message for userid ' . $userid . 'could not be found.'); 145 | } 146 | 147 | /** 148 | * Asserts that there is no message for a certain user. 149 | * @param $messages \stdClass[] received messages 150 | * @param $userid int id of the user 151 | * @param $needle string search string 152 | */ 153 | private function assert_no_message_for_user($messages, $userid) { 154 | $messageexists = false; 155 | foreach ($messages as $message) { 156 | if ($message->useridto == $userid) { 157 | $messageexists = true; 158 | } 159 | } 160 | $this->assertFalse($messageexists, 'There is a message for userid ' . $userid . '.'); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /tests/mod_ratingallocate_status_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_ratingallocate; 18 | 19 | use PHP_CodeSniffer\Generators\Generator; 20 | use PhpOffice\PhpSpreadsheet\Worksheet\Iterator; 21 | 22 | defined('MOODLE_INTERNAL') || die(); 23 | 24 | require_once(__DIR__ . '/generator/lib.php'); 25 | require_once(__DIR__ . '/../locallib.php'); 26 | 27 | /** 28 | * Tests the method get_status() 29 | * 30 | * @package mod_ratingallocate 31 | * @category test 32 | * @group mod_ratingallocate 33 | * @copyright reischmann 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | final class mod_ratingallocate_status_test extends \advanced_testcase { 37 | 38 | public function setUp(): void { 39 | global $PAGE; 40 | parent::setUp(); 41 | $PAGE->set_url('/'); 42 | $this->resetAfterTest(); 43 | } 44 | 45 | /** 46 | * Provider 47 | * 48 | * @return array 49 | */ 50 | public static function ratingallocate_provider(): array { 51 | return [ 52 | 'Rating phase is not started.' => [ 53 | 3, 6, false, false, \ratingallocate::DISTRIBUTION_STATUS_TOO_EARLY], 54 | 'Rating phase is not started, but some allocations exist.' => [ 55 | 3, 6, false, true, \ratingallocate::DISTRIBUTION_STATUS_TOO_EARLY], 56 | 'Rating phase is not started, but allocation is published.' => [ 57 | 3, 6, true, false, \ratingallocate::DISTRIBUTION_STATUS_TOO_EARLY], 58 | 'Rating phase is not started, but allocations exist and are published.' => [ 59 | 3, 6, true, true, \ratingallocate::DISTRIBUTION_STATUS_TOO_EARLY], 60 | 'The rating phase is running' => [ 61 | -1, 6, false, false, \ratingallocate::DISTRIBUTION_STATUS_RATING_IN_PROGRESS], 62 | 'The rating phase is running, but allocations exist.' => [ 63 | -1, 6, false, true, \ratingallocate::DISTRIBUTION_STATUS_RATING_IN_PROGRESS], 64 | 'The rating phase is running, but allocation is published.' => [ 65 | -1, 6, true, false, \ratingallocate::DISTRIBUTION_STATUS_RATING_IN_PROGRESS], 66 | 'The rating phase is running, but allocations exist and are published.' => [ 67 | -1, 6, true, true, \ratingallocate::DISTRIBUTION_STATUS_RATING_IN_PROGRESS], 68 | 'The rating phase is running.' => [ 69 | -7, -6, false, false, \ratingallocate::DISTRIBUTION_STATUS_READY], 70 | 'The rating phase is running and some allocations exist.' => [ 71 | -7, -6, false, true, \ratingallocate::DISTRIBUTION_STATUS_READY_ALLOC_STARTED], 72 | 'The rating phase is running and allocation is published.' => [ 73 | -7, -6, true, false, \ratingallocate::DISTRIBUTION_STATUS_PUBLISHED], 74 | 'The rating phase is running and allocations exist and are published.' => [ 75 | -7, -6, true, true, \ratingallocate::DISTRIBUTION_STATUS_PUBLISHED], 76 | ]; 77 | } 78 | 79 | /** 80 | * Tests under different conditions if the returned status object is correct. 81 | * @dataProvider ratingallocate_provider 82 | * @covers ::get_status() 83 | */ 84 | public function test_get_status($addtostart, $addtostop, $published, $hasallocations, $expected): void { 85 | $record = [ 86 | 'name' => 'Rating Allocation', 87 | 'accesstimestart' => time() + ($addtostart * 24 * 60 * 60), 88 | 'accesstimestop' => time() + ($addtostop * 24 * 60 * 60), 89 | 'strategyopt' => ['strategy_yesno' => ['maxcrossout' => '1']], 90 | 'strategy' => 'strategy_yesno']; 91 | if ($hasallocations) { 92 | $genmod = new \mod_ratingallocate_generated_module($this, $record); 93 | $moddb = $genmod->moddb; 94 | } else { 95 | $course = $this->getDataGenerator()->create_course(); 96 | $record['course'] = $course; 97 | $moddb = $this->getDataGenerator()->create_module(RATINGALLOCATE_MOD_NAME, $record); 98 | } 99 | 100 | $ratingallocate = \mod_ratingallocate_generator::get_ratingallocate($moddb); 101 | $ratingallocate->ratingallocate->published = $published; 102 | 103 | $status = $ratingallocate->get_status(); 104 | $this->assertEquals($expected, $status); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Defines the version of ratingallocate 19 | * 20 | * @package mod_ratingallocate 21 | * @copyright 2014 T Reischmann, C Usener 22 | * @copyright based on code by M Schulze copyright (C) 2014 M Schulze 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $plugin->version = 2025021900; // The current module version (Date: YYYYMMDDXX). 29 | $plugin->requires = 2022112800; // Requires Moodle 4.1 and higher. 30 | $plugin->maturity = MATURITY_STABLE; 31 | $plugin->release = 'v4.5-r1'; 32 | $plugin->component = 'mod_ratingallocate'; // To check on upgrade, that module sits in correct place. 33 | -------------------------------------------------------------------------------- /view.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Prints a particular instance of ratingallocate 19 | * 20 | * You can have a rather longer description of the file as well, 21 | * if you like, and it can span multiple lines. 22 | * 23 | * @package mod_ratingallocate 24 | * @copyright 2014 T Reischmann, C Usener 25 | * @copyright based on code by M Schulze copyright (C) 2014 M Schulze 26 | * @copyright based on code by Stefan Koegel copyright (C) 2013 Stefan Koegel 27 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 | */ 29 | 30 | require_once(dirname(dirname(dirname(__FILE__))) . '/config.php'); 31 | require_once(dirname(__FILE__) . '/locallib.php'); 32 | 33 | require_once(dirname(__FILE__) . '/solver/ford-fulkerson-koegel.php'); 34 | 35 | $id = optional_param('id', 0, PARAM_INT); // Course_module ID, or. 36 | $n = optional_param('m', 0, PARAM_INT); // Ratingallocate instance ID - it should be named as the first character of the module. 37 | 38 | if ($id) { 39 | $cm = get_coursemodule_from_id('ratingallocate', $id, 0, false, MUST_EXIST); 40 | $course = get_course($cm->course); 41 | $ratingallocate = $DB->get_record('ratingallocate', ['id' => $cm->instance], '*', MUST_EXIST); 42 | } else if ($n) { 43 | $ratingallocate = $DB->get_record('ratingallocate', ['id' => $n], '*', MUST_EXIST); 44 | $course = get_course($ratingallocate->course); 45 | $cm = get_coursemodule_from_instance('ratingallocate', $ratingallocate->id, $course->id, false, MUST_EXIST); 46 | } else { 47 | throw new \moodle_exception('no_id_or_m_error', RATINGALLOCATE_MOD_NAME); 48 | } 49 | 50 | require_login($course, true, $cm); 51 | $context = context_module::instance($cm->id); 52 | $PAGE->set_title($cm->name); 53 | $PAGE->set_context($context); 54 | $PAGE->set_url('/mod/ratingallocate/view.php', ['id' => $cm->id]); 55 | 56 | require_capability('mod/ratingallocate:view', $context); 57 | 58 | $ratingallocateobj = new ratingallocate($ratingallocate, $course, $cm, $context); 59 | echo $ratingallocateobj->handle_view(); 60 | --------------------------------------------------------------------------------