diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml new file mode 100644 index 0000000..7b7e2d6 --- /dev/null +++ b/.github/workflows/moodle-ci.yml @@ -0,0 +1,205 @@ +name: Moodle Plugin CI + +on: [push, pull_request] + +jobs: + static: + runs-on: ubuntu-latest + + strategy: + matrix: + php: ['8.3'] + moodle-branch: ['MOODLE_404_STABLE'] + database: ['pgsql'] + + steps: + - name: Start PostgreSQL + run: docker run -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:14 + + - name: Check out repository code + uses: actions/checkout@v3 + with: + path: plugin + + - name: Setup PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-values: max_input_vars=5000 + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Composer cache + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + + - name: npm cache + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Initialise moodle-plugin-ci + run: | + composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci 4.5.4 + echo $(cd ci/bin; pwd) >> $GITHUB_PATH + echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH + sudo locale-gen en_AU.UTF-8 + echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV + + - name: Install mod plugin + run: moodle-plugin-ci add-plugin learnweb/moodle-mod_moodleoverflow + + - name: Install block plugin + run: moodle-plugin-ci add-plugin learnweb/moodle-block_townsquare + + - name: Install local plugin + run: moodle-plugin-ci add-plugin learnweb/moodle-local_townsquaresupport + + - name: Install moodle-plugin-ci + run: | + moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 --no-init + env: + DB: ${{ matrix.database }} + MOODLE_BRANCH: ${{ matrix.moodle-branch }} + + - name: PHP Lint + if: ${{ always() }} + run: moodle-plugin-ci phplint + + - name: PHP Copy/Paste Detector + if: ${{ always() }} + run: moodle-plugin-ci phpcpd + continue-on-error: true + + - name: PHP Mess Detector + if: ${{ always() }} + run: moodle-plugin-ci phpmd + + - name: Moodle Code Checker + if: ${{ always() }} + run: moodle-plugin-ci codechecker + + - name: Moodle PHPDoc Checker + if: ${{ always() }} + run: moodle-plugin-ci phpdoc + continue-on-error: true + + - name: Validating + if: ${{ always() }} + run: moodle-plugin-ci validate + + - name: Check upgrade savepoints + if: ${{ always() }} + run: moodle-plugin-ci savepoints + + - name: Mustache Lint + if: ${{ always() }} + run: moodle-plugin-ci mustache + continue-on-error: true + + - name: Grunt + if: ${{ always() }} + run: moodle-plugin-ci grunt + continue-on-error: true + + test: + runs-on: ubuntu-latest + needs: static + + strategy: + fail-fast: false + matrix: + php: ['8.0', '8.1', '8.2', '8.3'] + moodle-branch: ['MOODLE_401_STABLE', 'MOODLE_402_STABLE', 'MOODLE_403_STABLE', 'MOODLE_404_STABLE'] + database: ['mariadb', 'pgsql'] + exclude: + - php: '8.0' + moodle-branch: 'MOODLE_404_STABLE' + - php: '8.2' + moodle-branch: 'MOODLE_401_STABLE' + - php: '8.3' + moodle-branch: 'MOODLE_401_STABLE' + - php: '8.3' + moodle-branch: 'MOODLE_402_STABLE' + - php: '8.3' + moodle-branch: 'MOODLE_403_STABLE' + include: + - php: '7.4' + moodle-branch: 'MOODLE_401_STABLE' + database: 'pgsql' + - php: '7.4' + moodle-branch: 'MOODLE_401_STABLE' + database: 'mariadb' + + steps: + - name: Start MariaDB + if: matrix.database == 'mariadb' + run: docker run -p 3306:3306 -e MYSQL_USER=root -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mariadb:10 + + - name: Start PostgreSQL + if: matrix.database == 'pgsql' + run: docker run -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:14 + + - name: Check out repository code + uses: actions/checkout@v3 + with: + path: plugin + + - name: Setup PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-values: max_input_vars=5000 + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + - name: Composer cache + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + - name: npm cache + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Initialise moodle-plugin-ci + run: | + composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci 4.5.4 + echo $(cd ci/bin; pwd) >> $GITHUB_PATH + echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH + sudo locale-gen en_AU.UTF-8 + echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV + + - name: Install moodle-plugin-ci + run: | + moodle-plugin-ci add-plugin learnweb/moodle-local_townsquaresupport + moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 + env: + DB: ${{ matrix.database }} + MOODLE_BRANCH: ${{ matrix.moodle-branch }} + + - name: PHPUnit tests + if: ${{ always() }} + run: moodle-plugin-ci phpunit + + - name: Behat features + if: ${{ always() }} + run: moodle-plugin-ci behat --auto-rerun 0 diff --git a/.github/workflows/moodle-release.yml b/.github/workflows/moodle-release.yml new file mode 100644 index 0000000..e566b3a --- /dev/null +++ b/.github/workflows/moodle-release.yml @@ -0,0 +1,54 @@ +# +# Whenever a new tag starting with "v" is pushed, add the tagged version +# to the Moodle Plugins directory at https://moodle.org/plugins +# +# revision: 2021070201 +# Changed to be released on Github release with the release notes. +# +name: Releasing in the Plugins directory + +on: + release: + types: [published] + +defaults: + run: + shell: bash + +jobs: + release-at-moodle-org: + runs-on: ubuntu-latest + env: + PLUGIN: townsquareexpansion_moodleoverflow + CURL: curl -s + ENDPOINT: https://moodle.org/webservice/rest/server.php + TOKEN: ${{ secrets.MOODLE_ORG_TOKEN }} + FUNCTION: local_plugins_add_version + + steps: + - name: Call the service function + id: add-version + run: | + TAGNAME="${{ github.event.release.tag_name }}" + BODY="${{ github.event.release.body }}" + ZIPURL="${{ github.event.release.zipball_url }}" + RESPONSE=$(${CURL} ${ENDPOINT} --data-urlencode "wstoken=${TOKEN}" \ + --data-urlencode "wsfunction=${FUNCTION}" \ + --data-urlencode "moodlewsrestformat=json" \ + --data-urlencode "frankenstyle=${PLUGIN}" \ + --data-urlencode "zipurl=${ZIPURL}" \ + --data-urlencode "vcssystem=git" \ + --data-urlencode "vcsrepositoryurl=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" \ + --data-urlencode "vcstag=${TAGNAME}" \ + --data-urlencode "changelogurl=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commits/${TAGNAME}" \ + --data-urlencode "altdownloadurl=${ZIPURL}" \ + --data-urlencode "releasenotes=${BODY}" \ + --data-urlencode "releasenotesformat=4") + echo "response=${RESPONSE}" >> $GITHUB_OUTPUT + - name: Evaluate the response + id: evaluate-response + env: + RESPONSE: ${{ steps.add-version.outputs.response }} + run: | + jq <<< ${RESPONSE} + jq --exit-status ".id" <<< ${RESPONSE} > /dev/null diff --git a/classes/moodleoverflow.php b/classes/moodleoverflow.php index f7f4d9a..1d82f85 100644 --- a/classes/moodleoverflow.php +++ b/classes/moodleoverflow.php @@ -26,9 +26,11 @@ defined('MOODLE_INTERNAL') || die; use local_townsquaresupport\townsquaresupportinterface; +use mod_moodleoverflow\anonymous; +use moodle_url; global $CFG; -require_once($CFG->dirroot . '/blocks/townsquare/locallib.php'); +require_once($CFG->dirroot . '/blocks/townsquare/lib.php'); /** * Class that implements the townsquaresupportinterface with the function to get the events from the plugin. @@ -66,18 +68,35 @@ public static function get_events(): array { if ( (townsquare_filter_availability($event)) || ($event->eventtype == 'expectcompletionon' && townsquare_filter_activitycompletions($event))) { unset($moodleoverflowevents[$key]); - continue; } - // Add the name of the instance to the event. - if ($event->eventtype != 'post') { - $event->instancename = $DB->get_field($event->modulename, 'name', ['id' => $event->instance]); + if ($event->eventtype == 'post') { + // Add an anonymous attribute. + $event->anonymous = self::is_post_anonymous($event); + + // If the post is anonymous, make the author anonymous. + if ($event->anonymous) { + $event->postuserfirstname = 'anonymous'; + $event->postuserlastname = ''; + } + + // Add links. + $event->linktopost = new moodle_url('/mod/moodleoverflow/discussion.php', + ['d' => $event->postdiscussion], 'p' . $event->postid); + $event->linktoauthor = $event->anonymous ? new moodle_url('') : + new moodle_url('/user/view.php', ['id' => $event->postuserid]); } } - return $moodleoverflowevents; } + /** + * Builds the sql statement to get all moodleoverflow posts from the database. + * + * @param $courses + * @param $timestart + * @return array + */ private static function get_moodleoverflowposts_from_db($courses, $timestart): array { global $DB; // Prepare params for sql statement. @@ -102,7 +121,8 @@ private static function get_moodleoverflowposts_from_db($courses, $timestart): a posts.parent AS postparentid, posts.userid AS postuserid, posts.created AS timestart, - posts.message AS postmessage + posts.message AS content, + posts.messageformat AS postmessageformat FROM {moodleoverflow_posts} posts JOIN {moodleoverflow_discussions} discuss ON discuss.id = posts.discussion JOIN {moodleoverflow} module ON module.id = discuss.moodleoverflow @@ -118,19 +138,28 @@ private static function get_moodleoverflowposts_from_db($courses, $timestart): a return $DB->get_records_sql($sql, $params); } + /** + * Build the sql statement to get all other events related to moodleoverflow from the database. + * @param $courses + * @param $timestart + * @param $timeend + * @return array + */ private static function get_other_events_from_db($courses, $timestart, $timeend): array { global $DB; // Prepare params for sql statement. list($insqlcourses, $inparamscourses) = $DB->get_in_or_equal($courses, SQL_PARAMS_NAMED); $params = ['timestart' => $timestart, 'timeduration' => $timestart, - 'timeend' => $timeend, 'courses' => $courses] + $inparamscourses; + 'timeend' => $timeend, 'courses' => $courses, ] + $inparamscourses; // Set the sql statement. - $sql = "SELECT e.id, e.name, e.courseid, cm.id AS coursemoduleid, cm.availability AS availability, e.groupid, e.userid, - e.modulename, e.instance, e.eventtype, e.timestart, e.timemodified, e.visible + $sql = "SELECT e.id, e.name AS content, mo.name AS instancename, e.courseid, cm.id AS coursemoduleid, + cm.availability AS availability, e.groupid, e.userid, e.modulename, e.instance, e.eventtype, e.timestart, + e.timemodified, e.visible FROM {event} e JOIN {modules} m ON e.modulename = m.name JOIN {course_modules} cm ON (cm.course = e.courseid AND cm.module = m.id AND cm.instance = e.instance) + JOIN {moodleoverflow} mo ON mo.id = e.instance WHERE (e.timestart >= :timestart OR e.timestart+e.timeduration > :timeduration) AND e.timestart <= :timeend AND e.courseid $insqlcourses @@ -144,4 +173,17 @@ private static function get_other_events_from_db($courses, $timestart, $timeend) return $DB->get_records_sql($sql, $params); } + /** + * Helper function to check if a post is anonymous. Helps to reduce the cyclomatic complexity. + * @param $event + * @return bool + */ + private static function is_post_anonymous($event) { + if ($event->anonymoussetting == anonymous::EVERYTHING_ANONYMOUS) { + return true; + } else if ($event->anonymoussetting == anonymous::QUESTION_ANONYMOUS) { + return $event->postuserid == $event->discussionuserid; + } + return false; + } } diff --git a/lang/en/moodleoverflow.php b/lang/en/townsquareexpansion_moodleoverflow.php similarity index 95% rename from lang/en/moodleoverflow.php rename to lang/en/townsquareexpansion_moodleoverflow.php index fc8bfd9..4579b9f 100644 --- a/lang/en/moodleoverflow.php +++ b/lang/en/townsquareexpansion_moodleoverflow.php @@ -23,8 +23,8 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['pluginname'] = 'Townsquaresubplugin for mod_moodleoverflow'; -$string['pluginname'] = 'Moodleoverflow support for townsquare block'; +$string['pluginname_help'] = 'This subplugin allows the townsquare block to show posts and events from moodleoverflow.'; $string['pluginnameadding'] = "Adding a Moodleoverflow support subplugin"; $string['pluginnameediting'] = "Editing a Moodleoverflow support subplugin"; $string['pluginnamesummary'] = "This subplugin allows the townsquare block to show posts and events from moodleoverflow."; -$string['pluginname_help'] = 'This subplugin allows the townsquare block to show posts and events from moodleoverflow.'; +$string['plugintitle'] = 'Moodleoverflow support for townsquare block'; diff --git a/version.php b/version.php index 8759fe3..61aa435 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'townsquareexpansion_moodleoverflow'; -$plugin->dependencies = ['local_townsquaresupport' => ANY_VERSION]; +$plugin->dependencies = ['local_townsquaresupport' => ANY_VERSION, 'mod_moodleoverflow' => ANY_VERSION]; $plugin->release = '0.1.0'; $plugin->version = 2024050900; $plugin->requires = 2022041900;