Skip to content
This repository has been archived by the owner on Dec 14, 2024. It is now read-only.

Commit

Permalink
Add option USER_CREATE_ADLER_COURSE_CATEGORY
Browse files Browse the repository at this point in the history
- refactor setup php code into two files, a dedicated one to install plugins as doing it in the same php script causes problems with class autoloading
- add release set 3.1.0
- improve logging and documentation
- improve test/docker-compose.yml
  • Loading branch information
Glutamat42 committed Apr 5, 2024
1 parent 7c5b3d3 commit db67f78
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 132 deletions.
71 changes: 50 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
# Moodle Bitnami Image Extension - User Creation, PHP Environment Variables, and AdLer Setup

This project extends the bitnami/moodle image with the following features:

- Setting up AdLer (after the first start the Moodle part of AdLer is fully set up).
- Create user(s) on first start
- Create user(s) on first start
- Adding another environment variable to set a php.ini option.


## Dependencies
- Requires at least Plugin-Release-Set version 3.1.0


## Windows Users
This project works only under Linux.
Git on Windows (also WSL) breaks the line endings which is why it cannot be used there.
Also, editing on Windows can cause the project to stop working on Linux as well.
To use this project on Windows you have to disable the option core.autocrlf
(why the hell does this option exist and why is it enabled by default on Windows...).
To do this run the following command before the git clone `git config --global core.autocrlf false`.

This project works only under Linux.
Git on Windows (also WSL) breaks the line endings which is why it cannot be used there.
Also, editing on Windows can cause the project to stop working on Linux as well.
To use this project on Windows you have to disable the option core.autocrlf
(why the hell does this option exist and why is it enabled by default on Windows...).
To do this run the following command before the git clone `git config --global core.autocrlf false`.

**ATTENTION**: This affects all git repositories on this PC.

If you want to run this project with Windows without disabling autocrlf you can use an Docker-twostage approach.
I will not support this, but this is an approach you could use to implement it by yourself:

```
RUN apk add dos2unix
RUN cat setup.sh | dos2unix > setup.sh.tmp
Expand All @@ -26,31 +33,45 @@ RUN chmod +x setup.sh
```

## Environment variables

All variables from the bitnami/moodle image are supported. Additionally, the following environment variables can be set:

### PHP environment variables

| Variable | Description |
|-------------------------|-----------------------------------------------------------------------------------|
| `PHP_OUTPUT_BUFFERING` | Controls the output buffering behavior of PHP. Set it to adjust the buffering setting in the `php.ini` file. |
| Variable | required | Description |
|------------------------|----------|--------------------------------------------------------------------------------------------------------------|
| `PHP_OUTPUT_BUFFERING` | no | Controls the output buffering behavior of PHP. Set it to adjust the buffering setting in the `php.ini` file. |

### Moodle user creation variables

| Variable | Description |
|----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `USER_NAME` | Specifies the login name of a user to be created during the initial setup. Watch out that the default name of the admin user of bitnami/docker is "user" |
| `USER_PASSWORD` | Specifies the password for the user created during the initial setup. Passwords have to follow moodle password validation rules. Otherwise the setup script will break. |
| `USER_FIRST_NAME` | Specifies the first name of the user created during the initial setup. |
| `USER_LAST_NAME` | Specifies the last name of the user created during the initial setup. |
| `USER_EMAIL` | Specifies the email address of the user created during the initial setup. |
| `USER_ROLE` | Specifies the short name of a role to assign to the user created during the initial setup. |
| Variable | required | Description |
|-------------------------------------|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `USER_NAME` | no | Specifies the login name of a user to be created during the initial setup. Watch out that the default name of the admin user of bitnami/docker is "user" |
| `USER_PASSWORD` | if `USER_NAME` is specified | Specifies the password for the user created during the initial setup. Passwords have to follow moodle password validation rules. Otherwise the setup script will break. |
| `USER_FIRST_NAME` | no | Specifies the first name of the user created during the initial setup. |
| `USER_LAST_NAME` | no | Specifies the last name of the user created during the initial setup. |
| `USER_EMAIL` | no | Specifies the email address of the user created during the initial setup. |
| `USER_ROLE` | no | Specifies the short name of a page wide (system) role to assign to the user created during the initial setup. This is mostly useful for moodle administration accounts |
| `USER_CREATE_ADLER_COURSE_CATEGORY` | no | true \| false - If true a course category will be created for the user where has the role "adler_manager" |

### Other environment variables

| Variable | required | Description |
|--------------------------------|----------|--------------------------------------------------------------------------------------------------------|
| `DEVELOP_DONT_INSTALL_PLUGINS` | no | true \| false - If true the setup script will not install any plugins. This is useful for development. |

#### Examples

Example one user

```
USER_NAME=john_doe
USER_PASSWORD=Pass1234
USER_FIRST_NAME=John
```

Example three users

```
USER_NAME=user1,user2,user3
USER_PASSWORD=Secret123,Secret123,Pass1234
Expand All @@ -61,9 +82,11 @@ USER_ROLE=false,manager,false
```

## Sample docker-compose.yml

see [tests/docker-compose.yml](tests/docker-compose.yml)

## Updating moodle

> [!IMPORTANT]
> The moodle release is NOT updated automatically in any way! \
> Incrementing MOODLE_VERSION build arg will not result in an update of moodle.
Expand All @@ -72,8 +95,8 @@ Moodle updates have to be done manually (Plugins are not affected by this issue)
Follow the [Bitnami Moodle Upgrade Guide](https://docs.bitnami.com/aws/apps/moodle/administration/upgrade/).
Sadly it is not easy to automate that process as moodle itself does not provide a way to automatically update moodle.

It might be within the realm of possibility to provide AdLer images with moodle and Plugins preinstalled,
but with this approach all additional plugins would be deleted after every update (potentially breaking moodle).
It might be within the realm of possibility to provide AdLer images with moodle and Plugins preinstalled,
but with this approach all additional plugins would be deleted after every update (potentially breaking moodle).

A possible approach to mitigate this issue might be placing an overlay volume on top of the whole moodle directory of this
moodle image. But it is unknown whether this would work and what potential issues might arise from this.
Expand All @@ -85,4 +108,10 @@ When building the Docker image for this project, you can customize the following
- `MOODLE_VERSION`: Specifies the version of Moodle to be used in the image. The default value is `latest`.
- `PLUGIN_VERSION`: Specifies the version of the Moodle plugin to be included in the image. The default value is `main`.

These arguments allow you to control the versions of Moodle and the plugin that are used during the image build process. You can adjust these values according to your specific requirements and preferences.
These arguments allow you to control the versions of Moodle and the plugin that are used during the image build process. You can adjust these values according to your specific
requirements and preferences.

## Troubleshooting

**Moodle setup fails with "The configuration file config.php alreaady exists. ...":** \
This typically indicates the setup script already failed during a previous run. Have a look on the logs of the first execution.
2 changes: 1 addition & 1 deletion opt/adler/entrypoint_adler.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# inject adler update
if ! grep "/opt/adler/setup.sh" /opt/bitnami/scripts/moodle/entrypoint.sh > /dev/null ; then
echo "inject adler update"
sed -i '/^exec "$@".*/i /opt/adler/setup.sh' /opt/bitnami/scripts/moodle/entrypoint.sh
sed -i '/^exec "$@".*/i echo "starting adler setup script" && /opt/adler/setup.sh' /opt/bitnami/scripts/moodle/entrypoint.sh
fi


Expand Down
3 changes: 3 additions & 0 deletions opt/adler/moodle/adler_setup/dependencies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

$MINIMUM_PLUGIN_RELEASE_SET = "3.1.0";
123 changes: 123 additions & 0 deletions opt/adler/moodle/adler_setup/install_plugins.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
# requirements
# - curl
# - unzip

define('CLI_SCRIPT', true);

$config_php_path = __DIR__ . '/../config.php';


require_once($config_php_path);
require_once('dependencies.php');

global $CFG, $DB;

require_once($CFG->libdir . "/clilib.php");
require_once("lib.php");


## cli opts
$help = "Command line tool to uninstall plugins.
Options:
-h --help Print this help.
--plugin_version Version of AdLer plugins to install. main or exact release name. Defaults to main.
--develop_dont_install_plugins DEVELOP OPTION: Skip plugin installation
";

list($options, $unrecognised) = cli_get_params([
'help' => false,
'plugin_version' => 'main',
'develop_dont_install_plugins' => false,
], []);

if ($unrecognised) {
$unrecognised = implode(PHP_EOL . ' ', $unrecognised);
cli_error('unknown option(s):' . $unrecognised);
}


if ($options['help']) {
cli_writeln($help);
exit(0);
}

# cast boolean cli opts
$options['develop_dont_install_plugins'] = $options['develop_dont_install_plugins'] == "true";
## end cli opts
cli_writeln('CLI options: ' . json_encode($options));


// validate plugin version
if (version_compare($options['plugin_version'], $MINIMUM_PLUGIN_RELEASE_SET, '<') && $options['plugin_version'] !== 'main') {
cli_error("Plugin version is too low. Minimum required version is $MINIMUM_PLUGIN_RELEASE_SET");
}


function get_plugin_config() {
$url = __DIR__ . '/plugin-releases.json';
// $url = 'https://raw.githubusercontent.com/Glutamat42/moodle-docker/main/plugin-releases.json';
$file_content = file_get_contents($url);
return json_decode($file_content, true);
}


if ($options['develop_dont_install_plugins']) {
cli_writeln("skipping plugin installation");
} else {
cli_writeln("installing plugins");

$plugin_release_info = get_plugin_config();

$plugins = [];
if (isset($plugin_release_info['common_versions'][$options['plugin_version']])) {
foreach ($plugin_release_info['common_versions'][$options['plugin_version']] as $plugin) {
$path = $CFG->dirroot . $plugin['path'];

if (preg_match('/^[0-9]+(\.[0-9]+){0,2}(-rc(\.[0-9]+)?)?$/', $plugin['version'])) {
// plugin is a release
$info = get_updated_release_info(
$plugin['git_project'],
$plugin['version'],
core_plugin_manager::instance()->get_plugin_info($plugin['name'])->release
);

if ($info === false) {
cli_writeln("No update available for {$plugin['name']} {$plugin['version']}");
continue;
} else if ($info !== null && property_exists($info, 'tag_name')) {
// checking for one of the keys is sufficient
$url = $info->zip_url;
} else {
cli_error("Failed to get release info for {$plugin['name']} {$plugin['version']}");
}
} else {
// plugin is a branch
$url = "https://github.com/" . $plugin['git_project'] . "/archive/refs/heads/" . $plugin['version'] . ".zip";
}

/** @noinspection PhpUndefinedVariableInspection */
$plugins[] = [
"path" => $path,
"url" => $url
];
}
} else {
cli_error("plugin version not found");
}

cli_writeln("plugins to install: " . json_encode($plugins));
foreach ($plugins as $plugin) {
update_plugin($plugin);
}
}

// upgrade moodle installation
cli_writeln("Upgrading moodle installation...");
$cmd = "php {$CFG->dirroot}/admin/cli/upgrade.php --non-interactive --allow-unstable";
cli_writeln("Executing: $cmd");
exec($cmd, $blub, $result_code);
if ($result_code != 0) {
cli_error('command execution failed');
}
32 changes: 28 additions & 4 deletions opt/adler/moodle/adler_setup/lib.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php

global $CFG;
require_once($CFG->dirroot . '/user/profile/lib.php');
require_once($CFG->dirroot . '/user/lib.php');


use core_plugin_manager;
use \core\event\user_created;
use local_adler\plugin_interface;
use core\event\user_created;


/** Get Infos (incl download urls) of release to update to. Will return false if nothing to update
Expand Down Expand Up @@ -139,6 +139,19 @@ function create_users($options) {
$users_data['last_name'] = $options['user_last_name'] ? explode(',', $options['user_last_name']) : array_fill(0, count($users_data['name']), "false");
$users_data['email'] = $options['user_email'] ? explode(',', $options['user_email']) : array_fill(0, count($users_data['name']), "false");
$users_data['role'] = $options['user_role'] ? explode(',', $options['user_role']) : array_fill(0, count($users_data['name']), "false");
$users_data['create_adler_course_category'] = $options['user_create_adler_course_category'] ? explode(',', $options['user_create_adler_course_category']) : array_fill(0, count($users_data['name']), "false");

// trim all values
foreach (array_keys($users_data) as $key) {
$users_data[$key] = array_map('trim', $users_data[$key]);
}

// in case any value is empty, set to false
foreach (array_keys($users_data) as $key) {
$users_data[$key] = array_map(function ($value) {
return empty($value) ? "false" : $value;
}, $users_data[$key]);
}

// validation
foreach (array_keys($users_data) as $key) {
Expand All @@ -147,11 +160,22 @@ function create_users($options) {


for ($i = 0; $i < count($users_data['name']); $i++) {
// for optional fields, fill with default values if not set
$first_name = $users_data['first_name'][$i] != "false" ? $users_data['first_name'][$i] : $users_data['name'][$i];
$last_name = $users_data['last_name'][$i] != "false" ? $users_data['last_name'][$i] : $users_data['name'][$i];
$role = $users_data['role'][$i] == "false" ? false : $users_data['role'][$i];
$email = $users_data['email'][$i] != "false" ?: $users_data['name'][$i] . '@example.example';

create_one_user($users_data['name'][$i], $users_data['password'][$i], $first_name, $last_name, $email, $role);
$user = create_one_user($users_data['name'][$i], $users_data['password'][$i], $first_name, $last_name, $email, $role);

if ($users_data['create_adler_course_category'][$i] == "true") {
cli_writeln("creating course category with upload permission for user " . $user->username);
create_default_course_category_for_user($user->username);
}
}
}

function create_default_course_category_for_user($username) {
// use local_adler cli script
plugin_interface::create_category_user_can_create_courses_in($username, 'adler_manager');
}
Loading

0 comments on commit db67f78

Please sign in to comment.