Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/moodle-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Moodle Plugin CI

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-22.04

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

strategy:
fail-fast: false
matrix:
include:
- moodle-branch: 'MOODLE_405_STABLE'
php: '8.1'
database: 'mariadb'
extensions: 'mbstring, intl, xml, soap, zip, gd, opcache, sodium'
- moodle-branch: 'MOODLE_405_STABLE'
php: '8.3'
database: 'mariadb'
extensions: 'mbstring, intl, xml, soap, zip, gd, opcache, sodium'
- moodle-branch: 'MOODLE_501_STABLE'
php: '8.2'
database: 'mariadb'
extensions: 'mbstring, intl, xml, soap, zip, gd, opcache, sodium'
- moodle-branch: 'MOODLE_501_STABLE'
php: '8.4'
database: 'mariadb'
extensions: 'mbstring, intl, xml, soap, zip, gd, opcache, sodium'

steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
path: plugin

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

- name: Initialise moodle-plugin-ci
run: |
composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4
echo $(cd ci/bin; pwd) >> $GITHUB_PATH
echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
sudo locale-gen en_AU.UTF-8
echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV

- name: Install moodle-plugin-ci
run: |
moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1
env:
DB: ${{ matrix.database }}
MOODLE_BRANCH: ${{ matrix.moodle-branch }}

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

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

- name: Moodle PHPDoc Checker
if: ${{ !cancelled() }}
run: moodle-plugin-ci phpdoc --max-warnings 0

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

- name: PHPUnit tests
if: ${{ !cancelled() }}
run: moodle-plugin-ci phpunit

- name: Mark cancelled jobs as failed
if: ${{ cancelled() }}
run: exit 1
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions .idea/brcli.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions .idea/php.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Please type the commands below to know how to use this plugin:
`sudo -u www-data /usr/bin/php admin/tool/brcli/restore.php --help`

## Release notes
* v1.3 - additional options for backupping (neglect users, log, histories etc.) added
* v1.2 - the description of the plugin was improved.
* v1.1 - it is mandatory to inform the destination folder.
* v1.0 - the restore feature is available.
Expand Down
148 changes: 116 additions & 32 deletions backup.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,72 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* admin tool brcli
* Backup & restore command line interface
* @package admin
* @subpackage tool
* @author Paulo Júnior <pauloa.junior@ufla.br> based on /admin/cli/backup.php
* Backup courses of a category via CLI.
*
* @package tool_brcli
* @copyright 2019 Paulo Júnior
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', 1);

require(__DIR__.'/../../../config.php');
require_once($CFG->libdir.'/clilib.php');
define('CLI_SCRIPT', true);

require(__DIR__ . '/../../../config.php');
require_once($CFG->libdir . '/clilib.php');
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');

// Now get cli options.
list($options, $unrecognized) = cli_get_params(array(
'categoryid' => false,
'destination' => '',
'help' => false,
), array('h' => 'help'));
/**
* Safely set a backup plan setting if it exists.
*
* Moodle versions and backup modes may expose different settings,
* so we set only when present.
*
* @param backup_plan $plan The backup plan instance.
* @param string $settingname The name of the setting to set.
* @param mixed $value The value to assign.
* @return void
*/
function tool_brcli_backup_set_if_exists(backup_plan $plan, string $settingname, $value): void {
try {
$setting = $plan->get_setting($settingname);
$setting->set_value($value);
} catch (\Exception $e) {
// Setting does not exist in this Moodle version or mode.
$e; // Prevent unused variable warning.
}
}

// Now get CLI options.
[$options, $unrecognized] = cli_get_params(
[
'categoryid' => false,
'destination' => '',
'preset' => 'full',
'users' => null,
'questionbank' => null,
'calendarevents' => null,
'competencies' => null,
'histories' => null,
'logs' => null,
'help' => false,
],
[
'h' => 'help',
]
);

if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
Expand All @@ -35,54 +83,90 @@
cli_error(get_string('noadminaccount', 'tool_brcli'));
}

// Do we need to store backup somewhere else?
$dir = rtrim($options['destination'], '/');
// Normalise and validate destination.
$dir = rtrim($options['destination'], "/\\");
if (empty($dir) || !file_exists($dir) || !is_dir($dir) || !is_writable($dir)) {
cli_error(get_string('directoryerror', 'tool_brcli'));
}

// Check that the category exists.
if ($DB->count_records('course_categories', array('id'=>$options['categoryid'])) == 0) {
if ($DB->count_records('course_categories', ['id' => $options['categoryid']]) == 0) {
cli_error(get_string('nocategory', 'tool_brcli'));
}
}

$courses = $DB->get_records('course', array('category'=>$options['categoryid']));
$amount_of_courses = count($courses);
$categoryid = (int) $options['categoryid'];
$courses = $DB->get_records('course', ['category' => $categoryid]);
$amountofcourses = count($courses);

$index = 1;

foreach ($courses as $cs) {
$bc = new backup_controller(backup::TYPE_1COURSE, $cs->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);

mtrace(get_string('performingbck', 'tool_brcli', $index . '/' . $amount_of_courses));
$bc = new backup_controller(
backup::TYPE_1COURSE,
$cs->id,
backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES,
backup::MODE_GENERAL,
$admin->id
);

mtrace(get_string('performingbck', 'tool_brcli', $index . '/' . $amountofcourses));

// Apply preset and overrides.
$plan = $bc->get_plan();
$overrides = [];
foreach (['users', 'questionbank', 'calendarevents', 'competencies', 'histories', 'logs'] as $name) {
if ($options[$name] !== null) {
$overrides[$name] = (int) $options[$name];
}
}

try {
$settings = \tool_brcli\local\preset::build_settings((string) $options['preset'], $overrides);
} catch (\InvalidArgumentException $e) {
$bc->destroy();
cli_error(get_string('invalidpreset', 'tool_brcli', $options['preset']));
}

foreach ($settings as $name => $value) {
tool_brcli_backup_set_if_exists($plan, $name, $value);
}

// Set the default filename.
$format = $bc->get_format();
$type = $bc->get_type();
$id = $bc->get_id();
$users = $bc->get_plan()->get_setting('users')->get_value();
$anonymised = $bc->get_plan()->get_setting('anonymize')->get_value();
$users = 1;
$anonymised = 0;
try {
$users = (int) $plan->get_setting('users')->get_value();
$anonymised = (int) $plan->get_setting('anonymize')->get_value();
} catch (\Exception $e) {
// Settings may not exist; use defaults.
$e; // Prevent unused variable warning.
}
$filename = backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised);
$bc->get_plan()->get_setting('filename')->set_value($filename);
tool_brcli_backup_set_if_exists($plan, 'filename', $filename);

// Execution.
$bc->finish_ui();
$bc->execute_plan();
$results = $bc->get_results();
$file = $results['backup_destination']; // May be empty if file already moved to target location.
$file = $results['backup_destination'] ?? null;

// Do we need to store backup somewhere else?
// Store backup to the destination directory if needed.
if ($file) {
if ($file->copy_content_to($dir.'/'.$filename)) {
$target = $dir . '/' . $filename;
if ($file->copy_content_to($target)) {
$file->delete();
} else {
mtrace(get_string('directoryerror', 'tool_brcli'));
}
}
$bc->destroy();
$index = $index + 1;
$index++;
}

mtrace(get_string('operationdone', 'tool_brcli'));

exit(0);
exit(0);
Loading