--get=
36 |
37 | Example:
38 | $ php mlangversion.php --value=3.10 --type=dir --get=branch
39 | ";
40 |
41 | [$options, $unrecognised] = cli_get_params([
42 | 'value' => '',
43 | 'type' => '',
44 | 'get' => '',
45 | 'help' => false,
46 | ], [
47 | 'h' => 'help',
48 | ]);
49 |
50 | if ($unrecognised) {
51 | $unrecognised = implode(PHP_EOL . ' ', $unrecognised);
52 | cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised));
53 | }
54 |
55 | if ($options['help']) {
56 | cli_writeln($usage);
57 | exit(2);
58 | }
59 |
60 | if (!in_array($options['type'], ['code', 'dir', 'branch'])) {
61 | cli_error('Invalid --type option value', 3);
62 | }
63 |
64 | if (!in_array($options['get'], ['code', 'dir', 'branch', 'label', 'translatable', 'current'])) {
65 | cli_error('Invalid --get option value', 3);
66 | }
67 |
68 | $methodname = 'by_' . $options['type'];
69 | $propertyname = $options['get'];
70 |
71 | cli_writeln(mlang_version::$methodname($options['value'])->$propertyname);
72 |
--------------------------------------------------------------------------------
/admin/newlanguage.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Register new language
20 | *
21 | * @package local-amos
22 | * @copyright 2010 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php');
27 | require_once(dirname(dirname(__FILE__)).'/mlanglib.php');
28 | require_once(dirname(__FILE__).'/newlanguage_form.php');
29 |
30 | require_login(SITEID, false);
31 | require_capability('local/amos:manage', context_system::instance());
32 |
33 | $cache = cache::make('local_amos', 'lists');
34 | $cache->delete('languages');
35 |
36 | $PAGE->set_pagelayout('standard');
37 | $PAGE->set_url('/local/amos/admin/newlanguage.php');
38 | $PAGE->set_title('AMOS ' . get_string('newlanguage', 'local_amos'));
39 | $PAGE->set_heading('AMOS ' . get_string('newlanguage', 'local_amos'));
40 |
41 | $form = new local_amos_newlanguage_form();
42 |
43 | if ($data = $form->get_data()) {
44 | $component = new mlang_component('langconfig', $data->langcode, mlang_version::oldest_version());
45 | $data->langname = mlang_string::fix_syntax($data->langname);
46 | $data->langnameint = mlang_string::fix_syntax($data->langnameint);
47 | $component->add_string(new mlang_string('thislanguage', $data->langname));
48 | $component->add_string(new mlang_string('thislanguageint', $data->langnameint));
49 | $stage = mlang_persistent_stage::instance_for_user($USER->id, sesskey());
50 | $stage->add($component);
51 | $stage->store();
52 | redirect(new moodle_url('/local/amos/stage.php'));
53 | }
54 |
55 | /// Output starts here
56 | echo $OUTPUT->header();
57 | $form->display();
58 | echo $OUTPUT->footer();
59 |
--------------------------------------------------------------------------------
/amd/build/stage.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../src/stage.js"],"names":["init","registerEventListeners","root","document","getElementById","addEventListener","e","target","getAttribute","preventDefault","item","closest","setAttribute"],"mappings":"sIA2BoB,QAAPA,CAAAA,IAAO,EAAM,CACtBC,CAAsB,EACzB,C,CAKD,GAAMA,CAAAA,CAAsB,CAAG,UAAM,CACjC,GAAIC,CAAAA,CAAI,CAAGC,QAAQ,CAACC,cAAT,CAAwB,kBAAxB,CAAX,CAEAF,CAAI,CAACG,gBAAL,CAAsB,OAAtB,CAA+B,SAAAC,CAAC,CAAI,CAChC,GAA4C,iBAAxC,EAAAA,CAAC,CAACC,MAAF,CAASC,YAAT,CAAsB,aAAtB,CAAJ,CAA+D,CAC3DF,CAAC,CAACG,cAAF,GACA,GAAIC,CAAAA,CAAI,CAAGJ,CAAC,CAACC,MAAF,CAASI,OAAT,CAAiB,iCAAjB,CAAX,CAEA,GAA0C,QAAtC,EAAAD,CAAI,CAACF,YAAL,CAAkB,eAAlB,CAAJ,CAAoD,CAChDE,CAAI,CAACE,YAAL,CAAkB,eAAlB,CAAmC,QAAnC,CACH,CAFD,IAEO,CACHF,CAAI,CAACE,YAAL,CAAkB,eAAlB,CAAmC,QAAnC,CACH,CACJ,CACJ,CAXD,CAYH,C","sourcesContent":["// This file is part of Moodle - https://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 * JS module for the AMOS stage.\n *\n * @module local_amos/stage\n * @package local_amos\n * @copyright 2020 David Mudrák \n * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * @function init\n */\nexport const init = () => {\n registerEventListeners();\n};\n\n/**\n * @function registerEventListeners\n */\nconst registerEventListeners = () => {\n let root = document.getElementById('amosstagestrings');\n\n root.addEventListener('click', e => {\n if (e.target.getAttribute('data-action') == 'toggle-diffmode') {\n e.preventDefault();\n let item = e.target.closest('[data-region=\"amosstageitem\"]');\n\n if (item.getAttribute('data-diffmode') == 'chunks') {\n item.setAttribute('data-diffmode', 'blocks');\n } else {\n item.setAttribute('data-diffmode', 'chunks');\n }\n }\n });\n};\n"],"file":"stage.min.js"}
--------------------------------------------------------------------------------
/scss/translator.scss:
--------------------------------------------------------------------------------
1 | // Strings translator.
2 | #page-local-amos-view #amostranslator {
3 |
4 | opacity: 1;
5 | transition: opacity 0.2s;
6 |
7 | &.loading {
8 | opacity: 0;
9 | }
10 |
11 | .amostranslatoritem {
12 |
13 | // Undo right margin on help icons.
14 | .amosinfo .icon {
15 | margin-right: 0;
16 | }
17 |
18 | .amosinfo {
19 | margin-bottom: 0.25rem;
20 | }
21 |
22 | .amosoriginal,
23 | .amostranslation {
24 | flex: 1 1 auto;
25 | min-height: 3rem;
26 | }
27 |
28 | .amosoriginal,
29 | .amostranslation,
30 | .amostranslationedit textarea {
31 | border: 1px solid rgb(204,204,204);
32 | border-radius: 4px;
33 | }
34 |
35 | .amosoriginal,
36 | .amostranslationview {
37 | padding: 10px;
38 | white-space: pre-wrap;
39 | word-wrap: break-word;
40 | }
41 |
42 | .amostranslationedit {
43 | padding: 4px;
44 | }
45 |
46 | .amostranslationedit textarea {
47 | padding: 5px;
48 | };
49 |
50 | .amostranslationview {
51 | cursor: text;
52 | }
53 |
54 | .amostranslationview,
55 | .amostranslationedit,
56 | .amostranslationedit textarea {
57 | height: 100%;
58 | width: 100%;
59 | }
60 |
61 | &.translatable .amostranslation {
62 | background-color: $amos-color-translatable;
63 | }
64 |
65 | &.translatable.missing .amostranslation {
66 | background-color: $amos-color-missing;
67 | }
68 |
69 | &.translatable.outdated .amostranslation {
70 | background-color: $amos-color-outdated;
71 | }
72 |
73 | &.translatable.staged .amostranslation {
74 | background-color: $amos-color-staged !important;
75 | }
76 |
77 | &.translatable.outdated .amostranslation {
78 | background-color: $amos-color-outdated;
79 | }
80 |
81 | &.nontranslatable .amostranslation {
82 | background-color: $amos-color-nontranslatable;
83 | font-style: italic;
84 | color: #545454;
85 | }
86 |
87 | &[data-mode="view"] .amostranslationedit {
88 | display: none !important;
89 | }
90 |
91 | &[data-mode="edit"] .amostranslationview {
92 | display: none !important;
93 | }
94 | }
95 |
96 | .amospaginator {
97 | .paginatoritem.current {
98 | font-weight: bold;
99 | background-color: #eee;
100 | }
101 | }
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/tests/privacy_provider_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides the {@link local_amos_privacy_provider_testcase} class.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2018 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | global $CFG;
29 |
30 | /**
31 | * Unit tests for the {@link \local_amos\privacy\provider} class.
32 | *
33 | * @copyright 2018 David Mudrák
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class local_amos_privacy_provider_testcase extends advanced_testcase {
37 |
38 | /**
39 | * Test {@link \local_amos\privacy\provider::get_users_in_context()} implementation.
40 | */
41 | public function test_get_users_in_context() {
42 | global $DB;
43 | $this->resetAfterTest();
44 |
45 | $context = context_system::instance();
46 |
47 | $userlist = new \core_privacy\local\request\userlist($context, 'local_amos');
48 |
49 | $u1 = $this->getDataGenerator()->create_user();
50 | $u2 = $this->getDataGenerator()->create_user();
51 | $u3 = $this->getDataGenerator()->create_user();
52 |
53 | $DB->insert_record('amos_commits', [
54 | 'source' => 'test',
55 | 'timecommitted' => time(),
56 | 'commitmsg' => 'Dummy commit',
57 | 'commithash' => sha1('foo bar'),
58 | 'userid' => $u1->id,
59 | 'userinfo' => 'Test User1 ',
60 | ]);
61 |
62 | $DB->insert_record('amos_translators', [
63 | 'userid' => $u2->id,
64 | 'lang' => 'cs',
65 | 'status' => 0,
66 | ]);
67 |
68 | \local_amos\privacy\provider::get_users_in_context($userlist);
69 |
70 | $expected = [$u1->id, $u2->id];
71 | $actual = $userlist->get_userids();
72 | $this->assertEqualsCanonicalizing($expected, $actual);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/admin/newlanguage_form.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * New language form
20 | *
21 | * @package local_amos
22 | * @copyright 2010 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | require_once($CFG->dirroot.'/lib/formslib.php');
29 |
30 | class local_amos_newlanguage_form extends moodleform {
31 |
32 | public function definition() {
33 | $mform = $this->_form;
34 |
35 | $mform->addElement('header', 'compulsory', 'New language');
36 |
37 | $mform->addElement('text', 'langcode', 'Language code', ['size' => 5]);
38 | $mform->setType('langcode', PARAM_SAFEDIR);
39 | $mform->addRule('langcode', get_string('err_required', 'form'), 'required', null, 'client');
40 |
41 | $mform->addElement('text', 'langname', 'Language name in the language itself');
42 | $mform->setType('langname', PARAM_RAW);
43 | $mform->addRule('langname', get_string('err_required', 'form'), 'required', null, 'client');
44 |
45 | $mform->addElement('text', 'langnameint', 'International language name in English');
46 | $mform->setType('langnameint', PARAM_RAW);
47 | $mform->addRule('langnameint', get_string('err_required', 'form'), 'required', null, 'client');
48 |
49 | $this->add_action_buttons(false, 'Register new language');
50 | }
51 |
52 | public function validation($data, $files) {
53 | global $CFG, $DB;
54 |
55 | $errors = parent::validation($data, $files);
56 |
57 | $tempcode = clean_param($data['langcode'], PARAM_SAFEDIR);
58 | $tempcode = strtolower($tempcode);
59 | if ($tempcode !== $data['langcode']) {
60 | $errors['langcode'] = 'Invalid language code format';
61 | }
62 |
63 | if ($DB->record_exists('amos_translations', ['lang' => $data['langcode']])) {
64 | $errors['langcode'] = 'Already exists';
65 | }
66 |
67 | return $errors;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/classes/contributor_selector.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * @package local_amos
19 | * @copyright 2014 David Mudrak
20 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21 | */
22 |
23 | defined('MOODLE_INTERNAL') || die();
24 |
25 | require_once($CFG->dirroot.'/user/selector/lib.php');
26 |
27 | class local_amos_contributor_selector extends user_selector_base {
28 |
29 | /**
30 | * Constructor.
31 | *
32 | * @param string $name
33 | * @param array $options
34 | */
35 | public function __construct($name, $options = array()) {
36 | $options['accesscontext'] = context_system::instance();
37 | $options['multiselect'] = false;
38 | $options['extrafields'] = array('email');
39 | parent::__construct($name, $options);
40 | }
41 |
42 | public function find_users($search) {
43 | global $DB;
44 |
45 | list($searchsql, $searchparams) = $this->search_sql($search, 'u');
46 | list($sortsql, $sortparams) = users_order_by_sql('u', $search, context_system::instance());
47 |
48 | $fields = "SELECT ".$this->required_fields_sql('u');
49 | $countfields = "SELECT COUNT(*)";
50 |
51 | $sql = " FROM {user} u
52 | WHERE ${searchsql}";
53 |
54 | $order = " ORDER BY ${sortsql}";
55 |
56 | if (!$this->is_validating()) {
57 | $foundcount = $DB->count_records_sql($countfields.$sql, array_merge($searchparams));
58 | if ($foundcount > $this->maxusersperpage) {
59 | return $this->too_many_results($search, $foundcount);
60 | }
61 | }
62 |
63 | $found = $DB->get_records_sql($fields.$sql.$order, array_merge($searchparams, $sortparams));
64 |
65 | if (empty($found)) {
66 | return array();
67 | }
68 |
69 | if ($search) {
70 | $groupname = get_string('potusersmatching', 'core_role', $search);
71 | } else {
72 | $groupname = get_string('potusers', 'core_role');
73 | }
74 |
75 | return array($groupname => $found);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/templates/translator_root.mustache:
--------------------------------------------------------------------------------
1 | {{!
2 | This file is part of Moodle - https://moodle.org/
3 |
4 | Moodle is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | Moodle is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with Moodle. If not, see .
16 | }}
17 | {{!
18 | @template local_amos/translator_root
19 |
20 | Render the content of the AMOS translator.
21 | }}
22 |
23 |
24 |
25 |
26 |
27 | - {{#str}} foundtotal, local_amos, {{found}} {{/str}}
28 | - {{#str}} foundmissing, local_amos, {{missing}} {{/str}}
29 | - {{#str}} foundmissingonthispage, local_amos, {{missingcurrentpage}} {{/str}}
30 | - {{#str}} permalink, local_amos {{/str}}
31 | - {{#str}} stagetoolopen, local_amos{{/str}}
32 |
33 |
34 |
35 | {{#paginator}}
36 | {{>local_amos/translator_paginator}}
37 | {{/paginator}}
38 |
39 |
40 |
41 |
42 | {{#strings}}
43 | {{>local_amos/translator_string}}
44 | {{/strings}}
45 |
46 |
47 |
48 |
49 |
50 | {{#found}}
51 | - {{#str}} up {{/str}}
52 | - {{#str}} stagetoolopen, local_amos{{/str}}
53 | {{/found}}
54 |
55 |
56 |
57 | {{#paginator}}
58 | {{>local_amos/translator_paginator}}
59 | {{/paginator}}
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/cli/enfix-export.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Exports strings from the en_fix language pack
20 | *
21 | * @package local_amos
22 | * @copyright 2013 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | define('CLI_SCRIPT', true);
27 |
28 | require(dirname(dirname(dirname(dirname(__FILE__)))) . '/config.php');
29 | require_once($CFG->libdir . '/clilib.php');
30 | require_once($CFG->dirroot . '/local/amos/cli/config.php');
31 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
32 |
33 | cli_error('TODO - this needs to be updated to use the new storage system.');
34 |
35 | // Get an information about existing strings in the en_fix
36 | $sql = "SELECT branch,lang,component,COUNT(stringid) AS numofstrings
37 | FROM {amos_repository}
38 | WHERE deleted=0
39 | AND lang='en_fix'
40 | GROUP BY branch,lang,component
41 | ORDER BY branch,lang,component";
42 | $rs = $DB->get_recordset_sql($sql);
43 | $tree = array(); // [branch][language][component] => numofstrings
44 | foreach ($rs as $record) {
45 | $tree[$record->branch][$record->lang][$record->component] = $record->numofstrings;
46 | }
47 | $rs->close();
48 |
49 | if (!defined('AMOS_EXPORT_ENFIX_DIR')) {
50 | cli_error('Target directory AMOS_EXPORT_ENFIX_DIR not defined!');
51 | }
52 |
53 | remove_dir(AMOS_EXPORT_ENFIX_DIR, true);
54 |
55 | foreach ($tree as $vercode => $languages) {
56 | $version = mlang_version::by_code($vercode);
57 | foreach ($languages as $langcode => $components) {
58 | if ($langcode !== 'en_fix') {
59 | throw new coding_exception('Unexpected language');
60 | }
61 | foreach ($components as $componentname => $unused) {
62 | $component = mlang_component::from_snapshot($componentname, $langcode, $version);
63 | if ($component->has_string()) {
64 | $file = AMOS_EXPORT_ENFIX_DIR.'/'.$version->dir.'/'.$component->name.'.php';
65 | if (!file_exists(dirname($file))) {
66 | mkdir(dirname($file), 0755, true);
67 | }
68 | echo "$file\n";
69 | $component->export_phpfile($file);
70 | }
71 | $component->clear();
72 | }
73 | }
74 | }
75 | echo "DONE\n";
76 |
--------------------------------------------------------------------------------
/classes/maintainer_selector.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * @package local_amos
19 | * @copyright 2014 David Mudrak
20 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21 | */
22 |
23 | defined('MOODLE_INTERNAL') || die();
24 |
25 | require_once($CFG->dirroot.'/user/selector/lib.php');
26 |
27 | class local_amos_maintainer_selector extends user_selector_base {
28 |
29 | /**
30 | * Constructor.
31 | *
32 | * @param string $name
33 | * @param array $options
34 | */
35 | public function __construct($name, $options = array()) {
36 | $options['accesscontext'] = context_system::instance();
37 | $options['multiselect'] = false;
38 | $options['extrafields'] = array('email');
39 | parent::__construct($name, $options);
40 | }
41 |
42 | public function find_users($search) {
43 | global $DB;
44 |
45 | $available = get_users_by_capability(context_system::instance(), 'local/amos:commit', 'u.id');
46 |
47 | list($permsql, $permparams) = $DB->get_in_or_equal(array_keys($available), SQL_PARAMS_NAMED, 'permparam');
48 | list($searchsql, $searchparams) = $this->search_sql($search, 'u');
49 | list($sortsql, $sortparams) = users_order_by_sql('u', $search, context_system::instance());
50 |
51 | $fields = "SELECT ".$this->required_fields_sql('u');
52 | $countfields = "SELECT COUNT(*)";
53 |
54 | $sql = " FROM {user} u
55 | WHERE u.id ${permsql} AND ${searchsql}";
56 |
57 | $order = " ORDER BY ${sortsql}";
58 |
59 | if (!$this->is_validating()) {
60 | $foundcount = $DB->count_records_sql($countfields.$sql, array_merge($permparams, $searchparams));
61 | if ($foundcount > $this->maxusersperpage) {
62 | return $this->too_many_results($search, $foundcount);
63 | }
64 | }
65 |
66 | $found = $DB->get_records_sql($fields.$sql.$order, array_merge($permparams, $searchparams, $sortparams));
67 |
68 | if (empty($found)) {
69 | return array();
70 | }
71 |
72 | if ($search) {
73 | $groupname = get_string('potusersmatching', 'core_role', $search);
74 | } else {
75 | $groupname = get_string('potusers', 'core_role');
76 | }
77 |
78 | return array($groupname => $found);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * AMOS home page
20 | *
21 | * @package local-amos
22 | * @copyright 2010 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
27 | require_once(dirname(__FILE__).'/locallib.php');
28 |
29 | require_login(SITEID, false);
30 |
31 | $PAGE->set_pagelayout('standard');
32 | $PAGE->set_url('/local/amos/index.php');
33 | $PAGE->set_title('AMOS');
34 | $PAGE->set_heading('AMOS');
35 |
36 | $output = $PAGE->get_renderer('local_amos');
37 |
38 | /// Output starts here
39 | echo $output->header();
40 |
41 | $amosroot = $PAGE->navigation->get('amos_root');
42 |
43 | echo html_writer::start_div('amostools');
44 |
45 | foreach ($amosroot->get_children_key_list() as $childkey) {
46 | $child = $amosroot->get($childkey);
47 | if (!($child->action instanceof moodle_url)) {
48 | continue;
49 | }
50 | echo html_writer::div(
51 | html_writer::link(
52 | $child->action,
53 | $child->text,
54 | array('class' => 'btn btn-primary btn-large')
55 | ),
56 | 'well amostool amostool-'.$child->key
57 | );
58 | }
59 |
60 | echo html_writer::end_div(); // .amostools
61 |
62 | echo $output->heading(get_string('privileges', 'local_amos'));
63 | $caps = array();
64 | if (has_capability('local/amos:manage', context_system::instance())) {
65 | $caps[] = get_string('amos:manage', 'local_amos');
66 | }
67 | if (has_capability('local/amos:stage', context_system::instance())) {
68 | $caps[] = get_string('amos:stage', 'local_amos');
69 | }
70 | if (has_capability('local/amos:commit', context_system::instance())) {
71 | $allowed = mlang_tools::list_allowed_languages();
72 | if (empty($allowed)) {
73 | $allowed = get_string('committablenone', 'local_amos');
74 | } elseif (!empty($allowed['X'])) {
75 | $allowed = get_string('committableall', 'local_amos');
76 | } else {
77 | $allowed = implode(', ', $allowed);
78 | }
79 | $caps[] = get_string('amos:commit', 'local_amos') . ' (' . $allowed . ')';
80 | }
81 | if (empty($caps)) {
82 | get_string('privilegesnone', 'local_amos');
83 | } else {
84 | $caps = '' . implode(" \n", $caps) . ' ';
85 | echo html_writer::tag('ul', $caps);
86 | }
87 |
88 | echo $output->footer();
89 |
--------------------------------------------------------------------------------
/tests/source_code_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link local_amos_source_code_testcase} class.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2019 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | global $CFG;
29 |
30 | /**
31 | * Test the implementation of {@link \local_amos\local\source_code} class.
32 | *
33 | * @copyright 2019 David Mudrák
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class local_amos_source_code_testcase extends advanced_testcase {
37 |
38 | /**
39 | * Test {@link \local_amos\local\source_code::parse_version_php()}.
40 | */
41 | public function test_get_version_php() {
42 | global $CFG;
43 |
44 | $amos = new \local_amos\local\source_code($CFG->dirroot.'/local/amos');
45 | $info = $amos->get_version_php();
46 |
47 | $this->assertEquals('local_amos', $info['component']);
48 | $this->assertArrayHasKey('version', $info);
49 | $this->assertArrayHasKey('release', $info);
50 | $this->assertArrayHasKey('requires', $info);
51 | $this->assertArrayHasKey('maturity', $info);
52 | }
53 |
54 | /**
55 | * Test {@link \local_amos\local\source_code::get_included_string_files()}.
56 | */
57 | public function test_get_included_string_files() {
58 |
59 | // Admin tool with the old subplugins.php file.
60 | $toolold = new \local_amos\local\source_code(__DIR__.'/fixtures/tool_old');
61 | $files = $toolold->get_included_string_files();
62 |
63 | $this->assertStringStartsWith('// Just a test file', $files['tool_old']['lang/en/tool_old.php']);
64 | $this->assertStringStartsWith('// Just a test file',
65 | $files['oldsubtype_subplug']['subtype/subplug/lang/en/oldsubtype_subplug.php']);
66 |
67 | // Activity module with the new subplugins.json file.
68 | $foonew = new \local_amos\local\source_code(__DIR__.'/fixtures/mod_new');
69 | $files = $foonew->get_included_string_files();
70 |
71 | $this->assertStringStartsWith('// Just a test file', $files['mod_new']['lang/en/new.php']);
72 | $this->assertStringStartsWith('// Just a test file',
73 | $files['newsubtype_subplug']['subtype/subplug/lang/en/newsubtype_subplug.php']);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/execute.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Executes the passed AMOScript and stages the result
20 | *
21 | * @package local
22 | * @subpackage amos
23 | * @copyright 2011 David Mudrak
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
28 | require_once(dirname(__FILE__).'/locallib.php');
29 | require_once(dirname(__FILE__).'/mlanglib.php');
30 | require_once(dirname(__FILE__).'/execute_form.php');
31 |
32 | require_login(SITEID, false);
33 | require_capability('local/amos:execute', context_system::instance());
34 | require_capability('local/amos:stage', context_system::instance());
35 |
36 | $PAGE->set_pagelayout('standard');
37 | $PAGE->set_url('/local/amos/execute.php');
38 | navigation_node::override_active_url(new moodle_url('/local/amos/stage.php'));
39 | $PAGE->set_title('AMOS ' . get_string('scriptexecute', 'local_amos'));
40 | $PAGE->set_heading('AMOS ' . get_string('scriptexecute', 'local_amos'));
41 |
42 | $executeform = new local_amos_execute_form(null, local_amos_execute_options());
43 |
44 | if ($data = $executeform->get_data()) {
45 | $version = mlang_version::by_code($data->version);
46 | $stage = mlang_persistent_stage::instance_for_user($USER->id, sesskey());
47 | $instructions = mlang_tools::extract_script_from_text($data->script);
48 | if (!empty($instructions)) {
49 | foreach ($instructions as $instruction) {
50 | $changes = mlang_tools::execute($instruction, $version);
51 | if ($changes instanceof mlang_stage) {
52 | foreach ($changes as $component) {
53 | $stage->add($component, true);
54 | }
55 | $changes->clear();
56 | } elseif ($changes < 0) {
57 | throw new moodle_exception('error_during_amoscript_execution', 'local_amos', '', null, $changes);
58 | }
59 | unset($changes);
60 | }
61 | }
62 | $stage->rebase();
63 | $stage->store();
64 |
65 | if (!isset($SESSION->local_amos)) {
66 | $SESSION->local_amos = new stdClass();
67 | }
68 | $SESSION->local_amos->presetcommitmessage = $data->script;
69 | }
70 |
71 | if (!isset($stage) or !$stage->has_component()) {
72 | notice(get_string('nothingtostage', 'local_amos'), new moodle_url('/local/amos/stage.php'));
73 | }
74 |
75 | redirect(new moodle_url('/local/amos/stage.php'));
76 |
--------------------------------------------------------------------------------
/classes/task/import_app_strings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides the {@link \local_amos\task\import_app_strings} class.
19 | *
20 | * @package local_amos
21 | * @category task
22 | * @copyright 2019 Pau Ferrer Ocaña
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace local_amos\task;
27 |
28 | defined('MOODLE_INTERNAL') || die();
29 |
30 | require_once($CFG->dirroot.'/local/amos/mlanglib.php');
31 |
32 | /**
33 | * Imports the strings used in the Moodle apps.
34 | *
35 | * @copyright 2019 Pau Ferrer Ocaña
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class import_app_strings extends \core\task\scheduled_task {
39 |
40 | /** @var \local_amos\local\git client to use */
41 | protected $git;
42 |
43 | /**
44 | * Return the task name.
45 | *
46 | * @return string
47 | */
48 | public function get_name() {
49 | return 'Import Moodle Apps strings';
50 | }
51 |
52 | /**
53 | * Execute the task.
54 | */
55 | public function execute() {
56 | global $DB;
57 |
58 | $langindexfile = get_config('local_amos', 'applangindexfile');
59 | mtrace('Loading langindex from '.$langindexfile);
60 | $file = file_get_contents($langindexfile);
61 | $strings = json_decode($file, true);
62 |
63 | $records = array();
64 | foreach ($strings as $key => $value) {
65 | if ($value != 'local_moodlemobileapp') {
66 | $record = new \StdClass();
67 | $record->appid = $key;
68 | $exp = explode('/', $value, 2);
69 | $record->component = $exp[0];
70 | if (count($exp) == 2) {
71 | $record->stringid = $exp[1];
72 | } else {
73 | $exp = explode('.', $key, 3);
74 |
75 | if (count($exp) == 3) {
76 | $record->stringid = $exp[2];
77 | } else {
78 | $record->stringid = $exp[1];
79 | }
80 | }
81 | $records[$key] = $record;
82 | }
83 | }
84 |
85 | if (count($records) > 0) {
86 | $DB->delete_records('amos_app_strings');
87 | $DB->insert_records('amos_app_strings', $records);
88 |
89 | mtrace(count($records) .' app strings inserted');
90 | }
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/classes/external/get_translator_data.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | namespace local_amos\external;
18 |
19 | defined('MOODLE_INTERNAL') || die();
20 |
21 | global $CFG;
22 | require_once($CFG->libdir . '/externallib.php');
23 |
24 | /**
25 | * Provide data for the AMOS translator based on the provided filter settings.
26 | *
27 | * @package local_amos
28 | * @category external
29 | * @copyright 2020 David Mudrák
30 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 | */
32 | class get_translator_data extends \external_api {
33 |
34 | /**
35 | * Describe the external function parameters.
36 | *
37 | * @return \external_function_parameters
38 | */
39 | public static function execute_parameters(): \external_function_parameters {
40 |
41 | return new \external_function_parameters([
42 | 'filterquery' => new \external_value(PARAM_RAW, 'Query string representing the filter form data.'),
43 | ]);
44 | }
45 |
46 | /**
47 | * Execute the external function.
48 | *
49 | * @param string $filterquery
50 | * @return array
51 | */
52 | public static function execute(string $filterquery): array {
53 | global $USER, $PAGE;
54 |
55 | $context = \context_system::instance();
56 | self::validate_context($context);
57 | require_capability('local/amos:stage', $context);
58 |
59 | ['filterquery' => $filterquery] = self::validate_parameters(self::execute_parameters(), compact('filterquery'));
60 |
61 | // Parse the query string and inject it as if it was part of HTTP POST request which is what the filter expects.
62 | parse_str($filterquery, $_POST);
63 |
64 | $filter = new \local_amos\output\filter(new \moodle_url('/local/amos/view.php'));
65 |
66 | // Make sure that $USER contains the sesskey property.
67 | sesskey();
68 | $translator = new \local_amos\output\translator($filter, $USER);
69 |
70 | return [
71 | 'json' => json_encode($translator->export_for_template($PAGE->get_renderer('local_amos'))),
72 | ];
73 | }
74 |
75 | /**
76 | * Describe the external function result value.
77 | *
78 | * @return \external_description
79 | */
80 | public static function execute_returns(): \external_description {
81 |
82 | return new \external_single_structure([
83 | 'json' => new \external_value(PARAM_RAW, 'JSON encoded template data'),
84 | ]);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/cli/backport.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * CLI utility to backport translations to older branches.
19 | *
20 | * @package local_amos
21 | * @copyright 2020 David Mudrák
22 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | define('CLI_SCRIPT', true);
26 |
27 | require(__DIR__ . '/../../../config.php');
28 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
29 | require_once($CFG->dirroot . '/local/amos/cli/utilslib.php');
30 | require_once($CFG->libdir.'/clilib.php');
31 |
32 | $usage = "Automatically backport translations to lower versions if they apply.
33 |
34 | A typical use case is when plugin English strings are registered on version X and translated. And then the X - 1 version
35 | is registered. Without backporting, that translations would exist since X only. But we want the translations of
36 | identical strings be backported from X to X -1 automatically.
37 |
38 | Backporting does not happen on 'en' and 'en_fix' languages.
39 |
40 | It is implicitly executed on committing in AMOS UI and whem importing English strings via external API. This script can
41 | be used to run it explicitly.
42 |
43 | Usage:
44 | php backport.php [--component=] [--languages=]
45 |
46 | Options:
47 | --component Backport translations for the given component only. Defaults to all known components.
48 | --languages Backport translations for the given languages only. Defaults to all languages.
49 | ";
50 |
51 | list($options, $unrecognised) = cli_get_params([
52 | 'component' => '',
53 | 'languages' => '',
54 | 'help' => false,
55 | ], [
56 | 'h' => 'help',
57 | ]);
58 |
59 | if ($options['help'] || !empty($unrecognised)) {
60 | cli_writeln($usage);
61 | exit(2);
62 | }
63 |
64 | $logger = new amos_cli_logger();
65 |
66 | $logger->log('backport', 'Loading list of components ...', amos_cli_logger::LEVEL_DEBUG);
67 |
68 | $components = array_keys(mlang_tools::list_components());
69 | $languages = [];
70 |
71 | if ($options['component']) {
72 | $components = array_intersect($components, [$options['component']]);
73 | }
74 |
75 | if ($options['languages']) {
76 | $languages = explode(',', $options['languages']);
77 | }
78 |
79 | $count = count($components);
80 | $i = 1;
81 |
82 | foreach ($components as $component) {
83 | $logger->log('backport', sprintf('%d%% %d/%d backporting %s translations ...',
84 | floor($i / $count * 100), $i, $count, $component));
85 | mlang_tools::backport_translations($component, $languages);
86 | $i++;
87 | }
88 |
89 | $logger->log('backport', 'Done!');
90 |
--------------------------------------------------------------------------------
/scss/stage.scss:
--------------------------------------------------------------------------------
1 | // Styles used at the stage page.
2 |
3 | .path-local-amos #amosstagewrapper {
4 |
5 | .stagetool {
6 | margin-bottom: 10px;
7 |
8 | &.simple {
9 | margin-bottom: 20px;
10 | }
11 |
12 | .stagetool-title {
13 | font-size: larger;
14 | background: url([[pix:core|t/expanded]]) no-repeat scroll 0 center;
15 | padding-left: 20px;
16 | cursor: pointer;
17 | color: $link-color;
18 | text-decoration: $link-decoration;
19 |
20 | &:hover {
21 | color: $link-hover-color;
22 | text-decoration: $link-hover-decoration;
23 | }
24 | }
25 |
26 | .collapsed .stagetool-title {
27 | background-image: url([[pix:core|t/collapsed]]);
28 | }
29 |
30 | .stagetool-content {
31 | padding-left: 1.3rem;
32 | }
33 |
34 | &.commit {
35 | label.checkbox {
36 | margin-bottom: 5px;
37 | }
38 | label.checkbox input[type="checkbox"] {
39 | margin-top: 4px; // Undo the dodgy hack from theme/bootstrapbase/less/moodle/forms.less
40 | margin-right: 0;
41 | }
42 | }
43 |
44 | &.stageactions {
45 | .btn {
46 | margin: 2px;
47 | }
48 | }
49 | }
50 |
51 | #amosstagestrings {
52 | margin-top: 2rem;
53 |
54 | .amosoriginal, .amostranslation {
55 | flex: 1 1 auto;
56 | min-height: 3rem;
57 | border: 1px solid rgb(204,204,204);
58 | border-radius: 4px;
59 | padding: 10px;
60 | white-space: pre-wrap;
61 | word-wrap: break-word;
62 | }
63 |
64 | .amosstageitem.uncommittable .amostranslation {
65 | background-color: $amos-color-nontranslatable;
66 | }
67 |
68 | .amosstageitem.committable .amostranslation {
69 | background-color: $amos-color-committable;
70 | }
71 |
72 | .amosstageitem.committable.nodiff .amostranslation {
73 | background-color: white;
74 | }
75 |
76 | .amosstageitem.diff[data-diffmode="chunks"] .amostranslation {
77 | .translation-new, .translation-current {
78 | display: none;
79 | }
80 | }
81 |
82 | .amosstageitem.diff[data-diffmode="blocks"] .amostranslation {
83 | .translation-diff {
84 | display: none;
85 | }
86 | }
87 |
88 | .amosstageitem.diff {
89 | &[data-diffmode="chunks"] .amostranslation del,
90 | &[data-diffmode="blocks"] .amostranslation .translation-current {
91 | color: #6b6b6b;
92 | text-decoration: line-through double;
93 | }
94 |
95 | &[data-diffmode="chunks"] .amostranslation ins,
96 | &[data-diffmode="blocks"] .amostranslation .translation-new {
97 | color: #008000;
98 | font-weight: bold;
99 | text-decoration: underline dotted;
100 | }
101 | }
102 |
103 | .amosstageitem:not([class~="diff"]) [data-action="toggle-diffmode"] {
104 | display: none;
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/tests/external_plugin_translation_stats_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides class {@see local_amos_external_plugin_translation_stats_testcase}.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2019 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | global $CFG;
29 |
30 | require_once($CFG->dirroot . '/webservice/tests/helpers.php');
31 |
32 | /**
33 | * Unit tests for AMOS external function 'plugin_translation_stats'.
34 | *
35 | * @copyright 2019 David Mudrák
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class local_amos_external_plugin_translation_stats_testcase extends externallib_advanced_testcase {
39 |
40 | /**
41 | * Test the behaviour of the plugin_translation_stats external function when unknown component is requested.
42 | */
43 | public function test_plugin_translation_stats_unknown_component() {
44 | $this->resetAfterTest(true);
45 |
46 | // No special capability needed.
47 | $user = self::getDataGenerator()->create_user();
48 | self::setUser($user);
49 |
50 | $this->expectException(invalid_parameter_exception::class);
51 |
52 | \local_amos\external\plugin_translation_stats::execute('muhehe');
53 | }
54 |
55 | /**
56 | * Test the behaviour of the plugin_translation_stats external function.
57 | */
58 | public function test_plugin_translation_stats() {
59 | global $CFG;
60 | require_once($CFG->dirroot.'/local/amos/mlanglib.php');
61 |
62 | $this->resetAfterTest(true);
63 |
64 | // No special capability needed.
65 | $user = self::getDataGenerator()->create_user();
66 | self::setUser($user);
67 |
68 | $stage = new mlang_stage();
69 | $component = new mlang_component('langconfig', 'en', mlang_version::by_branch('MOODLE_36_STABLE'));
70 | $component->add_string(new mlang_string('thislanguageint', 'English'));
71 | $stage->add($component);
72 | $component->clear();
73 | $stage->commit('Registering English language', ['source' => 'unittest']);
74 |
75 | $statsman = new local_amos_stats_manager();
76 | $statsman->update_stats('36', 'en', 'tool_foo', 9);
77 |
78 | $raw = \local_amos\external\plugin_translation_stats::execute('tool_foo');
79 | $clean = external_api::clean_returnvalue(\local_amos\external\plugin_translation_stats::execute_returns(), $raw);
80 |
81 | $this->assertEquals(1, count($clean['langnames']));
82 | $this->assertEquals(1, count($clean['branches']));
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/templates/stage.mustache:
--------------------------------------------------------------------------------
1 | {{!
2 | This file is part of Moodle - https://moodle.org/
3 |
4 | Moodle is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | Moodle is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with Moodle. If not, see .
16 | }}
17 | {{!
18 | @template local_amos/stage
19 |
20 | Render the AMOS Stage page.
21 |
22 | Classes required for JS:
23 | * none
24 |
25 | Data attributes required for JS:
26 | * none
27 |
28 | Example context (json):
29 | }}
30 |
31 |
32 | {{#strings}}
33 |
37 |
38 |
39 |
40 | {{displaysince}} | {{stringid}} | {{displaycomponent}}
41 |
42 | {{{displayoriginal}}}
43 |
44 |
45 |
46 |
47 |
48 | {{displaysince}} | {{displaylanguage}}
49 | {{#committable}}
50 |
51 | {{/committable}}
52 | | {{#str}} unstage, local_amos {{/str}}
53 | | {{#str}} edit {{/str}}
54 |
55 | +/-
60 |
61 |
62 | {{!--
63 | --}}{{{displaytranslationdiff}}}{{!--
64 | --}}{{{displaytranslationcurrent}}}{{!--
65 | --}}{{{displaytranslationnew}}}{{!--
66 | --}}
67 |
68 |
69 |
70 | {{/strings}}
71 |
72 |
73 | {{#js}}
74 | require(['local_amos/stage'], function(stagejs) {
75 | stagejs.init();
76 | });
77 | {{/js}}
78 |
79 |
--------------------------------------------------------------------------------
/db/services.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * AMOS external functions and web services are declared here.
19 | *
20 | * @package local_amos
21 | * @category webservice
22 | * @copyright 2012 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $functions = [
29 | 'local_amos_update_strings_file' => [
30 | 'classname' => '\local_amos\external\update_strings_file',
31 | 'methodname' => 'execute',
32 | 'description' => 'Imports strings from a string file.',
33 | 'type' => 'write',
34 | ],
35 | 'local_amos_plugin_translation_stats' => [
36 | 'classname' => '\local_amos\external\plugin_translation_stats',
37 | 'methodname' => 'execute',
38 | 'description' => 'Get translation statistics for the given component / plugin.',
39 | 'type' => 'read',
40 | ],
41 | 'local_amos_stage_translated_string' => [
42 | 'classname' => '\local_amos\external\stage_translated_string',
43 | 'methodname' => 'execute',
44 | 'description' => 'Add a string translation into a persistent AMOS stage.',
45 | 'capabilities' => 'local/amos:stage',
46 | 'type' => 'write',
47 | 'ajax' => true,
48 | ],
49 | 'local_amos_get_translator_data' => [
50 | 'classname' => '\local_amos\external\get_translator_data',
51 | 'methodname' => 'execute',
52 | 'description' => 'Return data for the translator based on the filter query.',
53 | 'capabilities' => 'local/amos:stage',
54 | 'type' => 'read',
55 | 'ajax' => true,
56 | ],
57 | 'local_amos_get_string_timeline' => [
58 | 'classname' => '\local_amos\external\get_string_timeline',
59 | 'methodname' => 'execute',
60 | 'description' => 'Return data for the string timeline modal info.',
61 | 'capabilities' => 'local/amos:stage',
62 | 'type' => 'read',
63 | 'ajax' => true,
64 | ],
65 | 'local_amos_make_translation_uptodate' => [
66 | 'classname' => '\local_amos\external\make_translation_uptodate',
67 | 'methodname' => 'execute',
68 | 'description' => 'Mark given translation as up-to-date against the given original.',
69 | 'capabilities' => 'local/amos:commit',
70 | 'type' => 'write',
71 | 'ajax' => true,
72 | ],
73 | ];
74 |
75 | $services = [
76 | 'AMOS integration with the Moodle Plugins directory' => [
77 | 'functions' => [
78 | 'local_amos_update_strings_file',
79 | 'local_amos_plugin_translation_stats',
80 | ],
81 | 'requiredcapability' => 'local/amos:importstrings',
82 | 'restrictedusers' => 1,
83 | 'enabled' => 1,
84 | ],
85 | ];
86 |
--------------------------------------------------------------------------------
/templates/downloadpage.mustache:
--------------------------------------------------------------------------------
1 | {{!
2 | This file is part of Moodle - https://moodle.org/
3 |
4 | Moodle is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | Moodle is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with Moodle. If not, see .
16 | }}
17 | {{!
18 | @template local_plugins/frontpage
19 |
20 | Template purpose and description.
21 |
22 | Classes required for JS:
23 | * none
24 |
25 | Data attributes required for JS:
26 | * none
27 |
28 | Context variables required for this template:
29 | * attributes Array of name / value pairs.
30 |
31 | Example context (json):
32 | {}
33 | }}
34 |
35 |
36 |
37 |
38 | Language
39 | Download
40 | Size
41 | Percentage of language strings translated
42 |
43 |
44 |
45 | {{#langpacks}}
46 | {{#haszip}}
47 |
48 |
49 | {{^parentlanguagecode}}
50 | {{langname}}
51 | {{/parentlanguagecode}}
52 | {{#parentlanguagecode}}
53 | {{langname}}
54 | {{/parentlanguagecode}}
55 |
56 |
57 |
58 | Download {{langcode}}.zip
59 |
60 |
61 |
62 | {{filesize}}
63 |
64 |
65 |
66 | {{^parentlanguagecode}}
67 |
68 |
69 |
70 | {{ratio}}% {{totalstrings}} / {{totalenglish}}
71 |
72 |
73 | {{/parentlanguagecode}}
74 | {{#parentlanguagecode}}
75 | {{totalstrings}} changes from the parent language '{{parentlanguagecode}}'
76 | {{/parentlanguagecode}}
77 |
78 |
79 | {{/haszip}}
80 | {{/langpacks}}
81 |
82 |
83 |
84 |
85 | Generated
86 |
87 |
--------------------------------------------------------------------------------
/db/access.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Capability definitions for AMOS local plugin
20 | *
21 | * @package local_amos
22 | * @copyright 2010 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | $capabilities = array(
29 |
30 | // Ability to set-up AMOS portal and assign translators of languages
31 | 'local/amos:manage' => array(
32 | 'captype' => 'write',
33 | 'contextlevel' => CONTEXT_SYSTEM,
34 | 'legacy' => array()
35 | ),
36 |
37 | // Ability to stage translations using the translation tool
38 | 'local/amos:stage' => array(
39 | 'captype' => 'write',
40 | 'contextlevel' => CONTEXT_SYSTEM,
41 | 'legacy' => array(
42 | 'user' => CAP_ALLOW,
43 | )
44 | ),
45 |
46 | // Ability to execute a given AMOScript and get the result in the stage
47 | 'local/amos:execute' => array(
48 | 'captype' => 'write',
49 | 'contextlevel' => CONTEXT_SYSTEM,
50 | 'legacy' => array()
51 | ),
52 |
53 | // Ability to commit the stage into AMOS repository
54 | 'local/amos:commit' => array(
55 | 'captype' => 'write',
56 | 'contextlevel' => CONTEXT_SYSTEM,
57 | 'legacy' => array()
58 | ),
59 |
60 | // Ability to stash a stage and to contribute
61 | 'local/amos:stash' => array(
62 | 'captype' => 'write',
63 | 'contextlevel' => CONTEXT_SYSTEM,
64 | 'legacy' => array(
65 | 'user' => CAP_ALLOW,
66 | )
67 | ),
68 |
69 | // Ability to import translated strings from uploaded file and stage them
70 | 'local/amos:importfile' => array(
71 | 'captype' => 'write',
72 | 'contextlevel' => CONTEXT_SYSTEM,
73 | 'legacy' => array(
74 | 'user' => CAP_ALLOW,
75 | )
76 | ),
77 |
78 | // Ability to import strings (including the English ones) directly into the repository
79 | // (this is intended mainly for the web service users)
80 | 'local/amos:importstrings' => array(
81 | 'captype' => 'write',
82 | 'contextlevel' => CONTEXT_SYSTEM,
83 | 'legacy' => array()
84 | ),
85 |
86 | // Ability to use Google Translate services
87 | 'local/amos:usegoogle' => array(
88 | 'captype' => 'read',
89 | 'contextlevel' => CONTEXT_SYSTEM,
90 | 'legacy' => array(
91 | 'user' => CAP_ALLOW,
92 | )
93 | ),
94 |
95 | // Ability to convert an existing contribution to a new contribution with
96 | // different language
97 | 'local/amos:changecontriblang' => array(
98 | 'captype' => 'write',
99 | 'contextlevel' => CONTEXT_SYSTEM,
100 | 'legacy' => array()
101 | ),
102 | );
103 |
--------------------------------------------------------------------------------
/cli/contrib-bulk.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * CLI script allowing to perform bulk operations over AMOS contributions.
19 | *
20 | * @package local_amos
21 | * @copyright 2020 David Mudrák
22 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | define('CLI_SCRIPT', true);
26 |
27 | require(__DIR__ . '/../../../config.php');
28 | require_once($CFG->libdir . '/clilib.php');
29 | require_once($CFG->dirroot . '/local/amos/locallib.php');
30 |
31 | $usage = "Perform bulk operations over AMOS contributed translations.
32 |
33 | Usage:
34 | # php contrib-bulk.php --user= --approve
35 |
36 | Options:
37 | --author= User ID of the contributor.
38 | --approve Approve all the pending contributions by the user.
39 |
40 | ";
41 |
42 | define('AMOS_BOT_USERID', 2);
43 |
44 | [$options, $unrecognised] = cli_get_params([
45 | 'help' => false,
46 | 'author' => null,
47 | 'approve' => false,
48 | ], [
49 | 'h' => 'help',
50 | 'e' => 'execute',
51 | ]);
52 |
53 | if ($unrecognised) {
54 | $unrecognised = implode(PHP_EOL . ' ', $unrecognised);
55 | cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised));
56 | }
57 |
58 | if ($options['help']) {
59 | cli_writeln($usage);
60 | exit(2);
61 | }
62 |
63 | if (empty($options['author'])) {
64 | cli_error('Missing mandatory argument: author', 2);
65 | }
66 |
67 | $sql = "SELECT c.id, c.lang, c.subject, c.stashid, c.status, c.timecreated,
68 | s.components, s.strings, " .
69 | user_picture::fields('a', null, 'authorid', 'author') . "
70 | FROM {amos_contributions} c
71 | JOIN {amos_stashes} s ON (c.stashid = s.id)
72 | JOIN {user} a ON c.authorid = a.id
73 | WHERE c.status < :rejected
74 | AND a.id = :authorid
75 | ORDER BY c.timemodified";
76 |
77 | $contributions = $DB->get_records_sql($sql, [
78 | 'rejected' => local_amos_contribution::STATE_REJECTED,
79 | 'authorid' => $options['author'],
80 | ]);
81 |
82 | $stage = new mlang_stage();
83 |
84 | foreach ($contributions as $contribution) {
85 | echo sprintf("#%d\t%s\t%s\t%d\n", $contribution->id, $contribution->subject, $contribution->components, $contribution->strings);
86 |
87 | if ($options['approve']) {
88 | $stash = mlang_stash::instance_from_id($contribution->stashid);
89 | $stash->apply($stage);
90 |
91 | $stage->commit('Bulk approval - contribution #' . $contribution->id, [
92 | 'source' => 'bot',
93 | 'userinfo' => 'AMOS-bot '
94 | ]);
95 |
96 | $update = [
97 | 'id' => $contribution->id,
98 | 'timemodified' => time(),
99 | 'assignee' => AMOS_BOT_USERID,
100 | 'status' => local_amos_contribution::STATE_ACCEPTED,
101 | ];
102 |
103 | $DB->update_record('amos_contributions', $update);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/scss/styles.scss:
--------------------------------------------------------------------------------
1 | @import "../../../theme/moodleorg/scss/pre.scss";
2 | @import "variables.scss";
3 | @import "filter.scss";
4 | @import "translator";
5 | @import "stage.scss";
6 | @import "credits.scss";
7 | @import "index.scss";
8 | @import "comment.scss";
9 |
10 | #page-local-amos-view {
11 | // Avoid content overlap with side blocks.
12 | #region-main {
13 | overflow-x: auto;
14 | }
15 |
16 | h2 {
17 | text-align: center;
18 | }
19 | }
20 |
21 | .path-local-amos .logrecord {
22 | border: 1px solid #ddd;
23 | padding: 0.5em;
24 | }
25 |
26 | .path-local-amos .contributionlist {
27 | margin: 1em auto;
28 | }
29 |
30 | .path-local-amos .contributionlist .userpicture {
31 | margin-right:5px;
32 | vertical-align: middle;
33 | }
34 |
35 | .path-local-amos .contributionlist .status0 .id,
36 | .path-local-amos .contributionlist .status0 .status,
37 | .path-local-amos .contributionwrapper .details .status0 td {
38 | background-color: #d2ebff;
39 | }
40 |
41 | .path-local-amos .contributionlist .status10 .id,
42 | .path-local-amos .contributionlist .status10 .status,
43 | .path-local-amos .contributionwrapper .details .status10 td,
44 | .path-local-amos .contribactions .singlebutton.review input[type="submit"] {
45 | background-color: #f3f2aa;
46 | }
47 |
48 | .path-local-amos .contributionlist .status20 .id,
49 | .path-local-amos .contributionlist .status20 .status,
50 | .path-local-amos .contributionwrapper .details .status20 td,
51 | .path-local-amos .contribactions .singlebutton.reject input[type="submit"] {
52 | background-color: #ffd3d9;
53 | }
54 |
55 | .path-local-amos .contributionlist .status30 .id,
56 | .path-local-amos .contributionlist .status30 .status,
57 | .path-local-amos .contributionwrapper .details .status30 td,
58 | .path-local-amos .contribactions .singlebutton.accept input[type="submit"] {
59 | background-color: #e7f1c3;
60 | }
61 |
62 | .path-local-amos .contributionwrapper .source {
63 | padding-left: 60px;
64 | position: relative;
65 | }
66 |
67 | .path-local-amos .contributionwrapper .source {
68 | margin-left: auto;
69 | margin-right: auto;
70 | }
71 |
72 | .path-local-amos .contributionwrapper .details {
73 | max-width: 100%;
74 | min-width: 300px;
75 | margin-top: 1em;
76 | margin-left: auto;
77 | margin-right: auto;
78 | }
79 |
80 | .path-local-amos .contributionwrapper .source h3,
81 | .path-local-amos .contributionwrapper .source div {
82 | margin: 0px 0px 0.3em;
83 | }
84 |
85 | .path-local-amos .contributionwrapper .source .timecreated {
86 | font-style: italic;
87 | }
88 |
89 | .path-local-amos .contributionwrapper .source .userpicture {
90 | position: absolute;
91 | top: 10px;
92 | left: 10px;
93 | }
94 |
95 | .path-local-amos .contributionwrapper .details .userpicture {
96 | margin-right:5px;
97 | vertical-align: middle;
98 | }
99 |
100 | .path-local-amos .contribactions {
101 | text-align: center;
102 | margin-bottom: 1em;
103 | }
104 |
105 | .path-local-amos .contribactions .singlebutton,
106 | .path-local-amos .contribactions .singlebutton form,
107 | .path-local-amos .contribactions .singlebutton form div {
108 | display: inline;
109 | }
110 |
111 | .path-local-amos .contribactions .singlebutton {
112 | margin: 0px 2px;
113 | }
114 |
115 | .path-local-amos .commentswrapper {
116 | width: 440px;
117 | margin-left: auto;
118 | margin-right: auto;
119 | padding: 10px;
120 | border: 1px solid #eee;
121 | background-color: white;
122 | }
123 |
124 | .path-local-amos .commentswrapper .comment-link {
125 | margin-bottom: 5px;
126 | }
127 |
128 | .path-local-amos .commentswrapper .comment-area {
129 | margin: 0px auto;
130 | }
131 |
--------------------------------------------------------------------------------
/tests/external_stage_translated_string_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Unit tests for external function {@see \local_amos\external\stage_translated_string}.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2020 David Mudrák
23 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 | class local_amos_external_stage_translated_string_testcase extends local_amos_testcase {
26 |
27 | /**
28 | * Test that permission check is performed.
29 | */
30 | public function test_execute_without_capability() {
31 | $this->resetAfterTest(true);
32 |
33 | $user = self::getDataGenerator()->create_user();
34 | self::setUser($user);
35 |
36 | $spammer = create_role('Spammer', 'spammer', 'Prohibits contributions to the site');
37 | assign_capability('local/amos:stage', CAP_PROHIBIT, $spammer, SYSCONTEXTID);
38 |
39 | role_assign($spammer, $user->id, SYSCONTEXTID);
40 | accesslib_clear_all_caches_for_unit_testing();
41 |
42 | $this->expectException(required_capability_exception::class);
43 | \local_amos\external\stage_translated_string::execute(sesskey(), 123, 'en_fix', 'Foo');
44 | }
45 |
46 | /**
47 | * Test basic behaviour of the method.
48 | */
49 | public function test_execute_basics() {
50 | global $DB, $USER;
51 | $this->resetAfterTest(true);
52 |
53 | self::setAdminUser();
54 |
55 | $this->register_language('en', 20);
56 | $this->register_language('cs', 20);
57 |
58 | $stage = new mlang_stage();
59 |
60 | $component = new mlang_component('foo_bar', 'en', mlang_version::by_code(39));
61 | $component->add_string(new mlang_string('foobar', 'Foo bar'));
62 | $stage->add($component);
63 | $component->clear();
64 |
65 | $stage->commit('First string', ['source' => 'unittest']);
66 |
67 | $foobarcomponent = mlang_component::from_snapshot('foo_bar', 'en', mlang_version::by_code(310), null, false, true);
68 | $foobarstring = $foobarcomponent->get_string('foobar');
69 |
70 | $stageid = sesskey();
71 | $originalid = $foobarstring->extra->id;
72 | $lang = 'cs';
73 | $text = 'Fů bár';
74 |
75 | $response = \local_amos\external\stage_translated_string::execute($stageid, $originalid, $lang, $text);
76 | $response = external_api::clean_returnvalue(\local_amos\external\stage_translated_string::execute_returns(), $response);
77 |
78 | $this->assertTrue(is_array($response));
79 | $this->assertSame('Fů bár', $response['translation']);
80 | $this->assertSame('Fů bár', $response['displaytranslation']);
81 | $this->assertSame('3.9+', $response['displaytranslationsince']);
82 | $this->assertFalse($response['nocleaning']);
83 | $this->assertSame([], $response['warnings']);
84 |
85 | $stage = mlang_persistent_stage::instance_for_user($USER->id, $USER->sesskey);
86 |
87 | $this->assertSame('Fů bár', $stage->get_component('foo_bar', 'cs', mlang_version::by_code(39))->get_string('foobar')->text);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/jobs/install-packs-publish:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Publish installer language packages at gitlab.
4 | # Merges newly generated installer strings into a local clone of moodle.git and pushes changes into a remote repository.
5 | # upstream: install-packs-make
6 |
7 | if [[ -z ${AMOSDATAROOT} ]]; then
8 | echo "Error: AMOSDATAROOT not set!"
9 | exit 1
10 | fi
11 |
12 | LOCKFILE=${AMOSDATAROOT}/install-packs-publish.lock
13 | REPO=${AMOSDATAROOT}/repos/moodle-install/
14 | SRCROOT=${AMOSDATAROOT}/export-install/
15 |
16 | if set -C; echo $$ 2>/dev/null > ${LOCKFILE}; then
17 | trap on_exit INT TERM EXIT
18 | else
19 | echo "Lock ${LOCKFILE} exists!"
20 | exit 1
21 | fi
22 |
23 | ##
24 | # To be executed on exiting.
25 | #
26 | on_exit() {
27 | rm -f ${LOCKFILE}
28 | }
29 |
30 | ##
31 | # Make sure that all required branches exist and are up to date.
32 | #
33 | # param $1 - name of the upstream branch such as master or MOODLE_311_STABLE
34 | # param $2 - name of the install branch such as install_master or install_311_STABLE
35 | #
36 | prepare_branches() {
37 | local upstreambranch=$1
38 | local installbranch=$2
39 |
40 | cd $REPO
41 |
42 | if git show-ref --quiet --verify refs/heads/${upstreambranch}; then
43 | git checkout $upstreambranch
44 | git merge --ff-only upstream/${upstreambranch}
45 | else
46 | git checkout --no-guess -b ${upstreambranch} --track upstream/${upstreambranch}
47 | fi
48 |
49 | if git show-ref --quiet --verify refs/heads/${installbranch}; then
50 | git checkout ${installbranch}
51 | else
52 | git checkout --no-guess -b ${installbranch} --no-track upstream/${upstreambranch}
53 | fi
54 |
55 | GIT_AUTHOR_NAME="AMOS bot" GIT_AUTHOR_EMAIL="amos@moodle.org" GIT_COMMITTER_NAME="AMOS bot" GIT_COMMITTER_EMAIL="amos@moodle.org" \
56 | git merge ${upstreambranch}
57 | }
58 |
59 | ##
60 | # Commit new install strings to the install branch.
61 | #
62 | # param $1 - name of the directory inside ${SRCROOT} to process such as master or 311_STABLE
63 | # param $2 - name of the install branch such as install_master or install_311_STABLE
64 | #
65 | commit_install_strings() {
66 | local dirname=$1
67 | local installbranch=$2
68 |
69 | cd ${REPO}
70 | git checkout ${installbranch}
71 |
72 | cd ${REPO}/install
73 | rm -rf lang
74 | cp -r ${AMOSDATAROOT}/export-install/${dirname}/install/lang .
75 | git add .
76 | GIT_AUTHOR_NAME="AMOS bot" GIT_AUTHOR_EMAIL="amos@moodle.org" GIT_COMMITTER_NAME="AMOS bot" GIT_COMMITTER_EMAIL="amos@moodle.org" \
77 | git commit -a -m "Automatically generated installer lang files"
78 | }
79 |
80 | ##
81 | # Push branches to remotes
82 | #
83 | # param $1 - name of the upstream branch such as master or MOODLE_311_STABLE
84 | # param $2 - name of the install branch such as install_master or install_311_STABLE
85 | #
86 | publish_branches() {
87 | local upstreambranch=$1
88 | local installbranch=$2
89 |
90 | git push gitlab ${upstreambranch}:${upstreambranch}
91 | git push gitlab ${installbranch}:${installbranch}
92 | }
93 |
94 | # Execution starts here.
95 |
96 | cd $REPO
97 | git remote update --prune
98 |
99 | for DIR in ${SRCROOT}/*; do
100 | if [[ -d ${DIR} ]]; then
101 | DIRNAME=$(basename ${DIR})
102 | if [[ ${DIRNAME} = "master" ]]; then
103 | UPSTREAMBRANCH="master"
104 | INSTALLBRANCH="install_master"
105 | else
106 | UPSTREAMBRANCH="MOODLE_${DIRNAME}"
107 | INSTALLBRANCH="install_${DIRNAME}"
108 | fi
109 |
110 | prepare_branches ${UPSTREAMBRANCH} ${INSTALLBRANCH}
111 | commit_install_strings ${DIRNAME} ${INSTALLBRANCH}
112 | publish_branches ${UPSTREAMBRANCH} ${INSTALLBRANCH}
113 | fi
114 | done
115 |
116 | cd ${REPO}
117 | git gc
118 |
--------------------------------------------------------------------------------
/untranslate.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Untranslate an existing translation
20 | *
21 | * @package local_amos
22 | * @copyright 2015 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require(__DIR__.'/../../config.php');
27 | require_once($CFG->dirroot.'/local/amos/mlanglib.php');
28 |
29 | $since = required_param('since', PARAM_INT);
30 | $component = required_param('component', PARAM_ALPHANUMEXT);
31 | $language = required_param('language', PARAM_ALPHANUMEXT);
32 | $stringid = required_param('stringid', PARAM_STRINGID);
33 | $confirm = optional_param('confirm', false, PARAM_BOOL);
34 |
35 | require_login(SITEID, false);
36 | require_capability('local/amos:commit', context_system::instance());
37 |
38 | $allowedlangs = mlang_tools::list_allowed_languages();
39 |
40 | if (empty($allowedlangs['X']) and empty($allowedlangs[$language])) {
41 | throw new moodle_exception('err_unexpected_language', 'local_amos');
42 | }
43 |
44 | $PAGE->set_pagelayout('standard');
45 | $PAGE->set_url(new moodle_url('/local/amos/untranslate.php', [
46 | 'component' => $component,
47 | 'language' => $language,
48 | 'stringid' => $stringid,
49 | 'since' => $since,
50 | ]));
51 | $PAGE->set_title('AMOS '.get_string('untranslating', 'local_amos'));
52 | $PAGE->navbar->add(get_string('untranslating', 'local_amos'));
53 |
54 | navigation_node::override_active_url(new moodle_url('/local/amos/view.php'));
55 |
56 | $mversion = mlang_version::by_code($since);
57 |
58 | if (!$mversion->translatable) {
59 | throw new moodle_exception('err_nontranslatable_version', 'local_amos');
60 | }
61 |
62 | if ($confirm) {
63 | require_sesskey();
64 |
65 | $mstage = new mlang_stage();
66 | $mcomponent = mlang_component::from_snapshot($component, $language, $mversion, null, false, false, [$stringid]);
67 | $cstring = $mcomponent->get_string($stringid);
68 |
69 | if ($cstring !== null) {
70 | $mstring = new mlang_string($cstring->id, $cstring->text, null, true);
71 | $mcomponent->add_string($mstring, true);
72 | $mstage->add($mcomponent);
73 |
74 | $message = 'Untranslate the string '.$stringid;
75 | $meta = [
76 | 'source' => 'amos',
77 | 'userid' => $USER->id,
78 | 'userinfo' => fullname($USER) . ' <' . $USER->email . '>',
79 | ];
80 | $mstage->commit($message, $meta);
81 | }
82 |
83 | redirect(new moodle_url('/local/amos/view.php'));
84 | }
85 |
86 | $output = $PAGE->get_renderer('local_amos');
87 |
88 | echo $output->header();
89 | echo $output->heading(get_string('untranslatetitle', 'local_amos'));
90 |
91 | $a = [
92 | 'component' => $component,
93 | 'language' => $language,
94 | 'stringid' => $stringid,
95 | 'since' => $mversion->label,
96 | ];
97 |
98 | echo $output->confirm(
99 | get_string('untranslateconfirm', 'local_amos', $a),
100 | new moodle_url($PAGE->url, ['sesskey' => sesskey(), 'confirm' => true]),
101 | new moodle_url('/local/amos/view.php')
102 | );
103 |
104 | echo $output->footer();
105 |
--------------------------------------------------------------------------------
/settings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Defines administration settings for AMOS
19 | *
20 | * @package local_amos
21 | * @category admin
22 | * @copyright 2010 David Mudrák , 2019 Pau Ferrer Ocaña
23 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | if ($hassiteconfig) {
29 | $settings = new admin_settingpage('local_amos', get_string('manageamos', 'local_amos'));
30 |
31 | if ($ADMIN->fulltree) {
32 | $settings->add(new admin_setting_configtextarea(
33 | 'local_amos/branchesall',
34 | get_string('branchesall', 'local_amos'),
35 | get_string('branchesall_desc', 'local_amos'),
36 | '20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,310,311,400',
37 | PARAM_RAW_TRIMMED,
38 | 60, 3
39 | ));
40 |
41 | $settings->add(new admin_setting_configtext(
42 | 'local_amos/branchsupported',
43 | get_string('branchsupported', 'local_amos'),
44 | get_string('branchsupported_desc', 'local_amos'),
45 | '35',
46 | PARAM_INT,
47 | 10
48 | ));
49 |
50 | $settings->add(new admin_setting_configtextarea(
51 | 'local_amos/standardcomponents',
52 | get_string('standardcomponents', 'local_amos'),
53 | get_string('standardcomponents_desc', 'local_amos'),
54 | '',
55 | PARAM_RAW_TRIMMED,
56 | 60, 10
57 | ));
58 |
59 | $settings->add(new admin_setting_configtextarea(
60 | 'local_amos/plugintypelocations',
61 | get_string('plugintypelocations', 'local_amos'),
62 | get_string('plugintypelocations_desc', 'local_amos'),
63 | implode(PHP_EOL, [
64 | 'assignment mod/assignment/type',
65 | 'datafield mod/data/field',
66 | 'datapreset mod/data/preset',
67 | 'quiz mod/quiz/report',
68 | 'quizaccess mod/quiz/accessrule',
69 | 'scormreport mod/scorm/report',
70 | 'workshopform mod/workshop/form',
71 | 'workshopallocation mod/workshop/allocation',
72 | 'workshopeval mod/workshop/eval',
73 | 'assignsubmission mod/assign/submission',
74 | 'assignfeedback mod/assign/feedback',
75 | 'booktool mod/book/tool',
76 | 'tinymce lib/editor/tinymce/plugins',
77 | 'atto lib/editor/atto/plugins',
78 | 'logstore admin/tool/log/store',
79 | 'ltisource mod/lti/source',
80 | 'ltiservice mod/lti/service',
81 | 'forumreport mod/forum/report',
82 | ]),
83 | PARAM_RAW_TRIMMED,
84 | 60, 10
85 | ));
86 |
87 | $settings->add(new admin_setting_configtext(
88 | 'local_amos/applangindexfile',
89 | get_string('applangindexfile', 'local_amos'),
90 | get_string('applangindexfile_desc', 'local_amos'),
91 | 'https://raw.githubusercontent.com/moodlehq/moodlemobile2/integration/scripts/langindex.json',
92 | PARAM_URL
93 | ));
94 | }
95 |
96 | $ADMIN->add('root', $settings, 'registrationmoodleorg');
97 | }
98 |
--------------------------------------------------------------------------------
/tests/fixtures/parserdata002.txt:
--------------------------------------------------------------------------------
1 |
2 | diff --git a/lang/en/admin.php b/lang/en/admin.php
3 | index 7c67ea9..6271297 100644
4 | --- a/lang/en/admin.php
5 | +++ b/lang/en/admin.php
6 | @@ -183,7 +183,7 @@ $string['configdefaultallowedmodules'] = 'For the courses which fall into the ab
7 | $string['configdefaulthomepage'] = 'This determines the home page for logged in users';
8 | $string['configdefaultrequestcategory'] = 'Courses requested by users will be automatically placed in this category.';
9 | $string['configdefaultrequestedcategory'] = 'Default category to put courses that were requested into, if they\'re approved.';
10 | -$string['configdefaultuserroleid'] = 'All logged in users will be given the capabilities of the role you specify here, at the site level, in ADDITION to any other roles they may have been given. The default is the Authenticated user role (or Guest role in older versions). Note that this will not conflict with other roles they have, it just ensures that all users have capabilities that are not assignable at the course level (eg post blog entries, manage own calendar, etc).';
11 | +$string['configdefaultuserroleid'] = 'All logged in users will be given the capabilities of the role you specify here, at the site level, in ADDITION to any other roles they may have been given. The default is the Authenticated user role. Note that this will not conflict with other roles they have unless you prohibit capabilities, it just ensures that all users have capabilities that are not assignable at the course level (eg post blog entries, manage own calendar, etc).';
12 | $string['configdeleteincompleteusers'] = 'After this period, old not fully setup accounts are deleted.';
13 | $string['configdeleteunconfirmed'] = 'If you are using email authentication,
14 |
15 | this is the period within which a response will be accepted from users. After this period, old unconfirmed accounts are deleted.';
16 | $string['configdenyemailaddresses'] = 'To deny email addresses from particular domains list them here in the same way. All other domains will be accepted. To deny subdomains add the domain with a preceding \'.\'. eg hotmail.com yahoo.co.uk .live.com';
17 | @@ -276,7 +276,6 @@ $string['configmypagelocked'] = 'This setting prevents the default page from bei
18 | $string['confignavcourselimit'] = 'Limits the number of courses shown to the user when they are either not logged in or are not enrolled in any courses.';
19 | $string['confignavshowallcourses'] = 'Setting this ensures that all courses on the site are shown in the navigation at all times.';
20 | $string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
21 | -$string['confignodefaultuserrolelists'] = 'This setting prevents all users from being returned from the database from deprecated calls of get_course_user, etc., for the site course if the default role provides that access. Check this, if you suffer a performance hit.';
22 | $string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private).';
23 | $string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out. Who should see these notifications?';
24 | $string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
25 | @@ -747,7 +746,6 @@ $string['navshowcategories'] = 'Show course categories';
26 | $string['neverdeleteruns'] = 'Never delete runs';
27 | $string['nobookmarksforuser'] = 'You do not have any bookmarks.';
28 | $string['nodatabase'] = 'No database';
29 | -$string['nodefaultuserrolelists'] = 'Don\'t return all default role users';
30 | $string['nochanges'] = 'No changes';
31 | +$string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed';
32 | $string['nomissingstrings'] = 'No missing strings';
33 | +$string['mod/something:really_nasty-like0098187.this'] ='Valid';
34 |
--------------------------------------------------------------------------------
/tests/external_get_string_timeline_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Unit tests for external function {@see \local_amos\external\get_string_timeline}.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2020 David Mudrák
23 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 | class local_amos_external_get_string_timeline_testcase extends local_amos_testcase {
26 |
27 | /**
28 | * Test that permission check is performed.
29 | */
30 | public function test_execute_without_capability() {
31 | $this->resetAfterTest(true);
32 |
33 | $user = self::getDataGenerator()->create_user();
34 | self::setUser($user);
35 |
36 | $spammer = create_role('Spammer', 'spammer', 'Prohibits contributions to the site');
37 | assign_capability('local/amos:stage', CAP_PROHIBIT, $spammer, SYSCONTEXTID);
38 |
39 | role_assign($spammer, $user->id, SYSCONTEXTID);
40 | accesslib_clear_all_caches_for_unit_testing();
41 |
42 | $this->expectException(required_capability_exception::class);
43 | \local_amos\external\get_string_timeline::execute('', '', '');
44 | }
45 |
46 | /**
47 | * Test basic behaviour of the method.
48 | */
49 | public function test_execute_basics() {
50 | global $DB, $USER;
51 | $this->resetAfterTest(true);
52 |
53 | self::setAdminUser();
54 |
55 | $this->register_language('en', 20);
56 | $this->register_language('cs', 20);
57 |
58 | $stage = new mlang_stage();
59 | $component = new mlang_component('foo_bar', 'en', mlang_version::by_code(39));
60 | $component->add_string(new mlang_string('foobar', 'Foo bar'));
61 | $stage->add($component);
62 | $stage->commit('First string', ['source' => 'unittest']);
63 |
64 | $stage = new mlang_stage();
65 | $component = new mlang_component('foo_bar', 'cs', mlang_version::by_code(39));
66 | $component->add_string(new mlang_string('foobar', 'Fů bár'));
67 | $stage->add($component);
68 | $stage->commit('První překlad', ['source' => 'unittest']);
69 |
70 | $stage = new mlang_stage();
71 | $component = new mlang_component('foo_bar', 'en', mlang_version::by_code(310));
72 | $component->add_string(new mlang_string('foobar', 'Foo bar!'));
73 | $stage->add($component);
74 | $stage->commit('Add exclamation mark in Moodle 3.10', ['source' => 'unittest']);
75 |
76 | $response = \local_amos\external\get_string_timeline::execute('foo_bar', 'foobar', 'cs');
77 | $response = external_api::clean_returnvalue(\local_amos\external\get_string_timeline::execute_returns(), $response);
78 |
79 | $this->assertEquals('foo_bar', $response['component']);
80 | $this->assertEquals('foobar', $response['strname']);
81 | $this->assertEquals('cs', $response['language']);
82 | $this->assertEquals('Foo bar!', $response['changes'][0]['english']['displaytext']);
83 | $this->assertEquals('en', $response['changes'][0]['english']['langcode']);
84 | $this->assertEquals('3.10+', $response['changes'][0]['english']['displaysince']);
85 | $this->assertFalse($response['changes'][0]['translation']['hascontent']);
86 |
87 | $this->assertFalse($response['changes'][1]['english']['hascontent']);
88 | $this->assertEquals('3.9+', $response['changes'][1]['translation']['displaysince']);
89 | $this->assertEquals('Fů bár', $response['changes'][1]['translation']['displaytext']);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/cli/compare-packs.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Cmpare the contents of two unzipped language packs
19 | *
20 | * @package local_amos
21 | * @subpackage cli
22 | * @copyright 2013 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | define('CLI_SCRIPT', 1);
27 |
28 | require(__DIR__ . '/../../../config.php');
29 | require_once($CFG->libdir . '/clilib.php');
30 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
31 |
32 | $usage = "Use this script to compare the contents of two unzipped language packs
33 |
34 | $ php compare-packs.php --old=/tmp/old/cs --new=/tmp/new/cs
35 | ";
36 |
37 | list($options, $unrecognised) = cli_get_params([
38 | 'help' => false,
39 | 'old' => '',
40 | 'new' => '',
41 | ], [
42 | 'h' => 'help',
43 | ]);
44 |
45 | if ($unrecognised) {
46 | $unrecognised = implode(PHP_EOL . ' ', $unrecognised);
47 | cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised));
48 | }
49 |
50 | if ($options['help']) {
51 | cli_writeln($usage);
52 | exit(2);
53 | }
54 |
55 | $old = $options['old'];
56 | $new = $options['new'];
57 |
58 | if (empty($old) || empty($new)) {
59 | cli_error($usage);
60 | }
61 |
62 | if (!is_dir($old)) {
63 | cli_error($old . ' is not a directory');
64 | }
65 |
66 | if (!is_dir($new)) {
67 | cli_error($new . ' is not a directory');
68 | }
69 |
70 | $oldpack = load_language_pack($old);
71 | $newpack = load_language_pack($new);
72 |
73 | if ($diff = array_diff(array_keys($oldpack), array_keys($newpack))) {
74 | cli_writeln('(+ ) component only in old: ' . implode(', ', $diff));
75 | }
76 |
77 | if ($diff = array_diff(array_keys($newpack), array_keys($oldpack))) {
78 | cli_writeln('( +) components only in new: ' . implode(', ', $diff));
79 | }
80 |
81 | foreach (array_intersect(array_keys($newpack), array_keys($oldpack)) as $component) {
82 | if ($diff = array_diff(array_keys($oldpack[$component]), array_keys($newpack[$component]))) {
83 | cli_writeln('[ +] strings only in old ' . $component . ': ' . implode(', ', $diff));
84 | }
85 |
86 | if ($diff = array_diff(array_keys($newpack[$component]), array_keys($oldpack[$component]))) {
87 | cli_writeln('[+ ] strings only in new ' . $component . ': ' . implode(', ', $diff));
88 | }
89 |
90 | foreach (array_intersect(array_keys($newpack[$component]), array_keys($oldpack[$component])) as $strname) {
91 | if ($newpack[$component][$strname] !== $oldpack[$component][$strname]) {
92 | cli_writeln('[!!] string mismatch in component ' . $component . ': ' . $strname);
93 | }
94 | }
95 | }
96 |
97 | /**
98 | * Load all strings from all files in the given language pack path.
99 | *
100 | * @param string $path
101 | * @return array (string)componentname => (string)strname => (string)strtext
102 | */
103 | function load_language_pack(string $path): array {
104 |
105 | $pack = [];
106 |
107 | foreach (new DirectoryIterator($path) as $file) {
108 | if ($file->isDot() or $file->isDir()) {
109 | continue;
110 | }
111 | if (substr($file->getFilename(), -4) !== '.php') {
112 | fputs(STDERR, 'Unexpected file ' . $file->getPathname());
113 | exit(1);
114 | }
115 | $component = mlang_component::name_from_filename($file->getFilename());
116 | $string = [];
117 | require($file->getPathname());
118 | $pack[$component] = $string;
119 | unset($string);
120 | }
121 |
122 | return $pack;
123 | }
124 |
--------------------------------------------------------------------------------
/classes/external/plugin_translation_stats.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides class {@see \local_amos\external\plugin_translation_stats}.
19 | *
20 | * @package local_amos
21 | * @category external
22 | * @copyright 2019 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | namespace local_amos\external;
27 |
28 | defined('MOODLE_INTERNAL') || die();
29 |
30 | /**
31 | * Implements external function plugin_translation_stats used e.g. by plugins directory.
32 | *
33 | * @package local_amos
34 | * @category external
35 | * @copyright 2019, 2020 David Mudrák
36 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 | */
38 | class plugin_translation_stats extends \external_api {
39 |
40 | /**
41 | * Describes parameters of the {@link execute()} method
42 | */
43 | public static function execute_parameters() {
44 | return new \external_function_parameters([
45 | 'component' => new \external_value(PARAM_COMPONENT, 'Name of the component to obtain stats for'),
46 | ]);
47 | }
48 |
49 | /**
50 | * Returns stats about the given plugin / component translations.
51 | *
52 | * @param string $component
53 | * @return stdClass
54 | */
55 | public static function execute($component) {
56 |
57 | // Validate parameters.
58 | $params = self::validate_parameters(self::execute_parameters(), ['component' => $component]);
59 | $component = $params['component'];
60 |
61 | // Validate the context.
62 | $context = \context_system::instance();
63 | self::validate_context($context);
64 |
65 | $statsman = new \local_amos_stats_manager();
66 |
67 | $data = $statsman->get_component_stats($component);
68 |
69 | if ($data === false) {
70 | throw new \invalid_parameter_exception('Stats requested for an unknown component.');
71 | }
72 |
73 | return $data;
74 | }
75 |
76 | /**
77 | * Describes the return value of the {@link execute()} method.
78 | *
79 | * @return external_description
80 | */
81 | public static function execute_returns() {
82 | return new \external_single_structure([
83 | 'lastmodified' => new \external_value(PARAM_INT, 'Timestamp of when the data was last modified'),
84 | 'langnames' => new \external_multiple_structure(
85 | new \external_single_structure([
86 | 'lang' => new \external_value(PARAM_SAFEDIR, 'Language code'),
87 | 'name' => new \external_value(PARAM_TEXT, 'International name of the language followed by its code')
88 | ])
89 | ),
90 | 'branches' => new \external_multiple_structure(
91 | new \external_single_structure([
92 | 'branch' => new \external_value(PARAM_FILE, 'Moodle branch (eg. 3.6)'),
93 | 'languages' => new \external_multiple_structure(
94 | new \external_single_structure([
95 | 'lang' => new \external_value(PARAM_SAFEDIR, 'Language code'),
96 | 'numofstrings' => new \external_value(PARAM_INT, 'Number of strings in the language pack'),
97 | 'ratio' => new \external_value(PARAM_INT, 'Completeness of the translation'),
98 | ])
99 | ),
100 | ])
101 | )
102 | ]);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/cli/enfix-merge.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * @package local_amos
20 | * @subpackage enfix
21 | * @copyright 2013 David Mudrak
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | */
24 |
25 | $help =
26 | "Merges en_fix strings into the Git working directory.
27 |
28 | Options:
29 |
30 | --symlinksdir Full path to the directory with symbolic links generated
31 | by the enfix-makesymlinks.sh script
32 | --enfixdir Full path to the directory containing en_fix string files
33 | generated by enfix-export.php script
34 | --help, -h Print out this help
35 |
36 | Example:
37 | \$ php enfix-merge.php --symlinksdir=/home/mudrd8mz/public_html/moodle25/amos --enfixdir=/home/mudrd8mz/moodledata/moodle24amos/amos/export-enfix/2.5
38 | ";
39 |
40 | define('CLI_SCRIPT', true);
41 |
42 | require_once(dirname(dirname(dirname(dirname(__FILE__)))) . '/config.php');
43 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
44 | require_once($CFG->dirroot . '/local/amos/cli/utilslib.php');
45 |
46 | list($options, $unrecognized) = cli_get_params(
47 | array(
48 | 'symlinksdir' => '',
49 | 'enfixdir' => '',
50 | 'help' => false),
51 | array('h' => 'help'));
52 |
53 |
54 | if ($options['help'] or empty($options['symlinksdir']) or empty($options['enfixdir'])) {
55 | cli_error($help, 2);
56 | }
57 |
58 | // Make sure that all target files exist, are symlinks and are writable.
59 |
60 | foreach (new DirectoryIterator($options['enfixdir']) as $enfixfileinfo) {
61 | if ($enfixfileinfo->isDot()) {
62 | continue;
63 | }
64 | $filename = $enfixfileinfo->getFilename();
65 |
66 | if (!is_link($options['symlinksdir'].'/'.$filename)) {
67 | cli_error('File not symlink: '.$options['symlinksdir'].'/'.$filename);
68 | }
69 |
70 | if (!is_writable($options['symlinksdir'].'/'.$filename)) {
71 | cli_error('File not writable: '.$options['symlinksdir'].'/'.$filename);
72 | }
73 | }
74 |
75 | // Let's rock!
76 |
77 | $logger = new amos_cli_logger();
78 | $helper = new amos_merge_string_files($logger);
79 | $total = 0;
80 |
81 | foreach (new DirectoryIterator($options['enfixdir']) as $enfixfileinfo) {
82 | if ($enfixfileinfo->isDot()) {
83 | continue;
84 | }
85 | $filename = $enfixfileinfo->getFilename();
86 |
87 | $logger->log('enfix-merge', 'Processing file '.$filename.' ...');
88 |
89 | if ($filename === 'langconfig.php') {
90 | $logger->log('enfix-merge', 'Skipping file '.$filename, amos_cli_logger::LEVEL_DEBUG);
91 | continue;
92 | }
93 |
94 | $filecontents = file_get_contents($options['symlinksdir'].'/'.$filename);
95 |
96 | $fromstrings = $helper->load_strings_from_file($options['symlinksdir'].'/'.$filename);
97 | $logger->log('enfix-merge', count($fromstrings).' string(s) found in '.$options['symlinksdir'].'/'.$filename, amos_cli_logger::LEVEL_DEBUG);
98 |
99 | $tostrings = $helper->load_strings_from_file($options['enfixdir'].'/'.$filename);
100 | $logger->log('enfix-merge', count($tostrings).' string(s) found in '.$options['enfixdir'].'/'.$filename, amos_cli_logger::LEVEL_DEBUG);
101 |
102 | $changes = $helper->replace_strings_in_file($filecontents, $fromstrings, $tostrings);
103 |
104 | if ($changes) {
105 | $total += $changes;
106 | file_put_contents($options['symlinksdir'].'/'.$filename, $filecontents);
107 | $logger->log('enfix-merge', $changes.' string(s) fixed in '.$filename);
108 | } else if ($changes === 0) {
109 | $logger->log('enfix-merge', 'No changes in '.$filename);
110 | } else {
111 | $logger->log('enfix-merge', 'Error while processing file '.$filename, amos_cli_logger::LEVEL_ERROR);
112 | }
113 | }
114 |
115 | $logger->log('enfix-merge', 'Finished! Total of '.$total.' string(s) merged.');
116 |
--------------------------------------------------------------------------------
/tests/git_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Provides {@link local_amos_git_testcase} class.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2019 David Mudrák
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | defined('MOODLE_INTERNAL') || die();
27 |
28 | global $CFG;
29 |
30 | /**
31 | * Test the implementation of {@link \local_amos\local\git} class.
32 | *
33 | * @copyright 2019 David Mudrák
34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 | */
36 | class local_amos_git_testcase extends basic_testcase {
37 |
38 | /**
39 | * Test {@link \local_amos\local\git::exec()}.
40 | */
41 | public function test_exec() {
42 |
43 | $repo = make_request_directory();
44 | $git = new \local_amos\local\git($repo);
45 |
46 | $out = $git->exec('init');
47 | $this->assertEquals('Initialized empty Git repository in '.$repo.'/.git/', $out[0]);
48 |
49 | file_put_contents($repo.'/README.txt', 'Hello world');
50 | $git->exec('add README.txt');
51 | $git->exec('commit -m "Adding a first file"');
52 |
53 | $out = $git->exec('log -n 1 --oneline');
54 | $this->assertTrue(strpos($out[0], 'Adding a first file') > 0);
55 |
56 | $this->expectException(Exception::class);
57 | $git->exec('add FOO.exe 2>/dev/null');
58 | }
59 |
60 | /**
61 | * Test {@link \local_amos\local\git::is_success()}.
62 | */
63 | public function test_is_success() {
64 |
65 | $repo = make_request_directory();
66 | $git = new \local_amos\local\git($repo);
67 |
68 | $git->exec('init');
69 | file_put_contents($repo.'/index.php', '');
70 | $git->exec('add .');
71 | $git->exec('commit -m "Initial commit"');
72 | $git->exec('checkout -b slave 2>/dev/null');
73 |
74 | $this->assertTrue($git->is_success('show-ref --verify --quiet refs/heads/master'));
75 | $this->assertTrue($git->is_success('show-ref --verify --quiet refs/heads/slave'));
76 | $this->assertFalse($git->is_success('show-ref --verify --quiet refs/heads/justice_exists'));
77 | }
78 |
79 | /**
80 | * Test {@link \local_amos\local\git::list_local_branches()}.
81 | */
82 | public function test_list_local_branches() {
83 |
84 | $repo = make_request_directory();
85 | $git = new \local_amos\local\git($repo);
86 |
87 | $git->exec('init');
88 | $this->assertSame([], $git->list_local_branches());
89 |
90 | file_put_contents($repo.'/index.php', '');
91 | $git->exec('add .');
92 | $git->exec('commit -m "Initial commit"');
93 | $this->assertEquals(['master'], $git->list_local_branches());
94 |
95 | $git->exec('checkout -b slave 2>/dev/null');
96 | $this->assertEquals(2, count($git->list_local_branches()));
97 | $this->assertContains('master', $git->list_local_branches());
98 | $this->assertContains('slave', $git->list_local_branches());
99 | }
100 |
101 | /**
102 | * Test {@link \local_amos\local\git::has_local_branch()}.
103 | */
104 | public function test_has_local_branch() {
105 |
106 | $repo = make_request_directory();
107 | $git = new \local_amos\local\git($repo);
108 |
109 | $git->exec('init');
110 | file_put_contents($repo.'/index.php', '');
111 | $git->exec('add .');
112 | $git->exec('commit -m "Initial commit"');
113 | $git->exec('checkout -b slave 2>/dev/null');
114 |
115 | $this->assertTrue($git->has_local_branch('master'));
116 | $this->assertTrue($git->has_local_branch('slave'));
117 | $this->assertFalse($git->has_local_branch('justice_exists'));
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/cli/import-strings.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Imports English strings for a given component from PHP file
19 | *
20 | * This can be used to manually import contributed plugins, for example. Note there is an external function for this
21 | * feature, too.
22 | *
23 | * @package local_amos
24 | * @copyright 2011 David Mudrak
25 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 | */
27 |
28 | define('CLI_SCRIPT', true);
29 |
30 | require(__DIR__ . '/../../../config.php');
31 | require_once($CFG->dirroot . '/local/amos/cli/config.php');
32 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
33 | require_once($CFG->libdir . '/clilib.php');
34 |
35 | list($options, $unrecognised) = cli_get_params([
36 | 'lang' => 'en',
37 | 'versioncode' => null,
38 | 'timemodified' => null,
39 | 'name' => null,
40 | 'format' => 2,
41 | 'message' => '',
42 | 'userinfo' => 'David Mudrak ',
43 | 'commithash' => null,
44 | 'yes' => false,
45 | 'help' => false
46 | ], [
47 | 'h' => 'help',
48 | 'y' => 'yes',
49 | ]);
50 |
51 | $usage = "
52 | Imports strings from a file into the AMOS repository.
53 |
54 | Usage:
55 | php import-strings.php --message='Commit message' [--other-options] /path/to/file.php
56 |
57 | Options:
58 | --message Commit message
59 | --lang Language code, defaults to 'en',
60 | --versioncode Code of the branch to commit to, defaults to most recent one
61 | --timemodified Timestamp of the commit, defaults to the file last modification time
62 | --name Name of the component, defaults to the filename
63 | --format Format of the file, defaults to 2 (Moodle 2.0+)
64 | --userinfo Committer information, defaults to 'David Mudrak '
65 | --commithash Allows to specify the git commit hash
66 | --yes | -y It won't ask to continue
67 | --help | -h Show this usage
68 |
69 | The file is directly included into the PHP processor. Make sure to review the file
70 | for a malicious contents before you import it via this script.
71 | ";
72 |
73 | if ($options['help'] || empty($options['message']) || empty($unrecognised)) {
74 | echo $usage . PHP_EOL;
75 | exit(1);
76 | }
77 |
78 | $filepath = $unrecognised[0];
79 | if (!is_readable($filepath)) {
80 | echo 'File "'.$filepath.'" not readable' . PHP_EOL;
81 | echo $usage . PHP_EOL;
82 | exit(2);
83 | }
84 |
85 | if ($options['versioncode']) {
86 | $version = mlang_version::by_code($options['versioncode']);
87 | } else {
88 | $version = mlang_version::latest_version();
89 | }
90 |
91 | $component = mlang_component::from_phpfile($filepath, $options['lang'], $version,
92 | $options['timemodified'], $options['name'], (int)$options['format']);
93 |
94 | fputs(STDOUT, "{$component->name} {$component->version->label} {$component->lang}" . PHP_EOL);
95 |
96 | $stage = new mlang_stage();
97 | $stage->add($component);
98 | $stage->rebase(null, true, $options['timemodified']);
99 |
100 | if (!$stage->has_component()) {
101 | echo 'No strings found (after rebase)' . PHP_EOL;
102 | exit(4);
103 | }
104 |
105 | foreach ($stage as $component) {
106 | foreach ($component as $string) {
107 | if ($string->deleted) {
108 | $sign = '-';
109 | } else {
110 | $sign = '+';
111 | }
112 | echo $sign . ' ' . $string->id . PHP_EOL;
113 | }
114 | }
115 |
116 | echo PHP_EOL;
117 | if (!$options['yes']) {
118 | $continue = cli_input('Continue? [y/n]', 'n', array('y', 'n'));
119 | if ($continue !== 'y') {
120 | echo 'Import aborted' . PHP_EOL;
121 | exit(5);
122 | }
123 | }
124 |
125 | $meta = array('source' => 'import', 'userinfo' => $options['userinfo']);
126 | if ($options['commithash']) {
127 | $meta['commithash'] = $commithash;
128 | }
129 |
130 | $stage->commit($options['message'], $meta, true);
131 |
--------------------------------------------------------------------------------
/cli/enfix-cleanup.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Deletes all en_fix strings that are merged into the en pack.
20 | *
21 | * @package local_amos
22 | * @copyright 2013 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | define('CLI_SCRIPT', true);
27 |
28 | require(dirname(dirname(dirname(dirname(__FILE__)))) . '/config.php');
29 | require_once($CFG->libdir . '/clilib.php');
30 | require_once($CFG->dirroot . '/local/amos/cli/config.php');
31 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
32 |
33 | cli_error('TODO - this needs to be updated to use the new storage system.');
34 |
35 | list($options, $unrecognized) = cli_get_params(array('execute' => false, 'aggresive' => false));
36 |
37 | fputs(STDOUT, "*****************************************\n");
38 | fputs(STDOUT, date('Y-m-d H:i', time()));
39 | fputs(STDOUT, " ENFIX CLEANUP JOB STARTED\n");
40 |
41 | // Get an information about existing strings in the en_fix
42 | $sql = "SELECT branch,lang,component,COUNT(stringid) AS numofstrings
43 | FROM {amos_repository}
44 | WHERE deleted=0
45 | AND lang='en_fix'
46 | GROUP BY branch,lang,component
47 | ORDER BY branch,lang,component";
48 | $rs = $DB->get_recordset_sql($sql);
49 | $tree = array(); // [branch][language][component] => numofstrings
50 | foreach ($rs as $record) {
51 | $tree[$record->branch][$record->lang][$record->component] = $record->numofstrings;
52 | }
53 | $rs->close();
54 |
55 | $stage = new mlang_stage();
56 |
57 | foreach ($tree as $vercode => $languages) {
58 | $version = mlang_version::by_code($vercode);
59 | foreach ($languages as $langcode => $components) {
60 | if ($langcode !== 'en_fix') {
61 | throw new coding_exception('Unexpected language');
62 | }
63 | foreach ($components as $componentname => $unused) {
64 | $en = mlang_component::from_snapshot($componentname, 'en', $version);
65 | $enfix = mlang_component::from_snapshot($componentname, $langcode, $version);
66 | $enfix->intersect($en);
67 | $removed = $enfix->complement($en);
68 |
69 | if ($options['aggresive']) {
70 | foreach ($enfix as $enfixstring) {
71 | $enstring = $en->get_string($enfixstring->id);
72 | if ($enstring === null) {
73 | fputs(STDERR, 'orphaned string '.$enfixstring->id.' in '.$componentname.' '.$version->label.PHP_EOL);
74 | continue;
75 | }
76 | if ($enstring->timemodified > $enfixstring->timemodified) {
77 | fputs(STDERR, 'string '.$enfixstring->id.' outdated in '.$componentname.' '.$version->label.PHP_EOL);
78 | $enfix->unlink_string($enfixstring->id);
79 | $removed++;
80 | }
81 | }
82 | }
83 |
84 | if ($removed) {
85 |
86 | if ($options['execute']) {
87 | $action = 'removing';
88 | } else {
89 | $action = 'would remove';
90 | }
91 |
92 | fputs(STDERR, $action.' '.$removed.' string(s) from '.$componentname.' '.$version->label.PHP_EOL);
93 |
94 | if ($options['execute']) {
95 | $stage->add($enfix);
96 | $stage->rebase(null, true);
97 | $msg = 'Clean-up strings that were merged into the English pack';
98 | $stage->commit($msg, array('source' => 'bot', 'userinfo' => 'AMOS-bot '), true);
99 | } else {
100 | $stage->clear();
101 | }
102 | } else {
103 | fputs(STDERR, 'nothing to do in '.$componentname.' '.$version->label.PHP_EOL);
104 | }
105 | $en->clear();
106 | $enfix->clear();
107 | }
108 | }
109 | }
110 |
111 | fputs(STDOUT, date('Y-m-d H:i', time()));
112 | fputs(STDOUT, " ENFIX CLEANUP JOB DONE\n");
113 |
--------------------------------------------------------------------------------
/cli/export-installer.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Exports the strings needed by the installer
19 | *
20 | * Moodle core contains a subset of strings needed for the start of the installation.
21 | * The list of required strings is maintained in install/stringnames.txt. This
22 | * script parses that file and exports the translations into a configured destination.
23 | *
24 | * @package local_amos
25 | * @copyright 2010 David Mudrak
26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 | */
28 |
29 | define('CLI_SCRIPT', true);
30 |
31 | require(__DIR__ . '/../../../config.php');
32 | require_once($CFG->dirroot . '/local/amos/cli/config.php');
33 | require_once($CFG->dirroot . '/local/amos/mlanglib.php');
34 |
35 | $versions = array_reverse(mlang_version::list_supported(), true);
36 |
37 | $git = new \local_amos\local\git(AMOS_REPO_MOODLE);
38 | $git->exec('remote update --prune');
39 |
40 | fputs(STDOUT, "*****************************************\n");
41 | fputs(STDOUT, date('Y-m-d H:i', time()));
42 | fputs(STDOUT, " EXPORT INSTALLER JOB STARTED\n");
43 |
44 | remove_dir(AMOS_EXPORT_INSTALLER_DIR, true);
45 |
46 | $exitstatus = 0;
47 |
48 | foreach ($versions as $version) {
49 | if ($git->has_remote_branch($version->branch)) {
50 | $gitbranch = 'origin/' . $version->branch;
51 | $exportdir = $version->code . '_STABLE';
52 |
53 | } else if ($version->code == mlang_version::latest_version()->code) {
54 | $gitbranch = 'origin/master';
55 | $exportdir = 'master';
56 |
57 | } else {
58 | fputs(STDERR, "GIT BRANCH NOT FOUND FOR MOODLE VERSION {$version->label}\n");
59 | exit(3);
60 | }
61 |
62 | fputs(STDOUT, "PROCESSING VERSION {$version->code} ({$gitbranch})\n");
63 |
64 | // Read the contents of stringnames.txt on the given branch.
65 | $gitout = $git->exec('show ' . escapeshellarg($gitbranch . ':install/stringnames.txt'));
66 |
67 | $list = [];
68 |
69 | foreach ($gitout as $string) {
70 | [$stringid, $component] = array_map('trim', explode(',', $string));
71 | $list[$component][$stringid] = true;
72 | }
73 | unset($gitout);
74 |
75 | $langs = array_keys(mlang_tools::list_languages());
76 |
77 | $phpdoc = << $stringids) {
95 | foreach ($langs as $lang) {
96 | if ($lang === 'en_fix') {
97 | continue;
98 | }
99 | $component = mlang_component::from_snapshot($componentname, $lang, $version, null, false, false,
100 | array_keys($stringids));
101 | if ($component->has_string()) {
102 | $file = AMOS_EXPORT_INSTALLER_DIR . '/' . $exportdir . '/install/lang/' . $lang . '/' . $component->name . '.php';
103 | if (!file_exists(dirname($file))) {
104 | mkdir(dirname($file), 0755, true);
105 | }
106 | $component->export_phpfile($file, $phpdoc);
107 | }
108 | if ($lang === 'en') {
109 | // Check that all string were exported.
110 | foreach (array_keys($stringids) as $stringid) {
111 | if (!$component->has_string($stringid)) {
112 | fputs(STDERR, "ERROR Unknown $stringid,$componentname\n");
113 | $exitstatus = 1;
114 | }
115 | }
116 | }
117 | $component->clear();
118 | }
119 | }
120 | }
121 |
122 | fputs(STDOUT, date('Y-m-d H:i', time()));
123 | fputs(STDOUT, " EXPORT INSTALLER JOB DONE\n");
124 |
125 | exit($exitstatus);
126 |
--------------------------------------------------------------------------------
/tests/external_get_translator_data_test.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Unit tests for external function {@see \local_amos\external\get_translator_data}.
19 | *
20 | * @package local_amos
21 | * @category test
22 | * @copyright 2020 David Mudrák
23 | * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 | class local_amos_external_get_translator_data_testcase extends local_amos_testcase {
26 |
27 | /**
28 | * Test that permission check is performed.
29 | */
30 | public function test_execute_without_capability() {
31 | $this->resetAfterTest(true);
32 |
33 | $user = self::getDataGenerator()->create_user();
34 | self::setUser($user);
35 |
36 | $spammer = create_role('Spammer', 'spammer', 'Prohibits contributions to the site');
37 | assign_capability('local/amos:stage', CAP_PROHIBIT, $spammer, SYSCONTEXTID);
38 |
39 | role_assign($spammer, $user->id, SYSCONTEXTID);
40 | accesslib_clear_all_caches_for_unit_testing();
41 |
42 | $this->expectException(required_capability_exception::class);
43 | \local_amos\external\get_translator_data::execute('');
44 | }
45 |
46 | /**
47 | * Test basic behaviour of the method.
48 | */
49 | public function test_execute_basics() {
50 | global $DB, $USER;
51 | $this->resetAfterTest(true);
52 |
53 | self::setAdminUser();
54 |
55 | $this->register_language('en', 20);
56 | $this->register_language('cs', 20);
57 |
58 | $stage = new mlang_stage();
59 |
60 | $component = new mlang_component('foo_bar', 'en', mlang_version::by_code(39));
61 | $component->add_string(new mlang_string('foobar', 'Foo bar'));
62 | $stage->add($component);
63 | $component->clear();
64 |
65 | $stage->commit('First string', ['source' => 'unittest']);
66 |
67 | // Emulate what URLSearchParams.toString() does on the client side.
68 | $filterquery = http_build_query([
69 | '__lazyform_amosfilter' => 1,
70 | 'sesskey' => sesskey(),
71 | 'fcmp' => ['foo_bar', 'baz_quix'],
72 | 'flng' => ['cs'],
73 | 'flast' => 1,
74 | 'ftxt' => 'Foo bar',
75 | ], '', '&');
76 |
77 | $response = \local_amos\external\get_translator_data::execute($filterquery);
78 | $response = external_api::clean_returnvalue(\local_amos\external\get_translator_data::execute_returns(), $response);
79 |
80 | $this->assertTrue(isset($response['json']));
81 |
82 | $data = json_decode($response['json'], true);
83 |
84 | $this->assertArrayHasKey('permalink', $data);
85 | $this->assertEquals(1, $data['found']);
86 | $this->assertEquals(1, $data['missing']);
87 | $this->assertEquals(1, $data['missingcurrentpage']);
88 | $this->assertEquals(1, count($data['strings']));
89 | $this->assertEquals('Foo bar', $data['strings'][0]['original']);
90 | $this->assertFalse($data['paginator']['hasmultiplepages']);
91 | $this->assertEquals(1, $data['paginator']['currentpage']);
92 | $this->assertEquals(1, $data['paginator']['navigation'][0]['label']);
93 |
94 | // Emulate what URLSearchParams.toString() does on the client side.
95 | $filterquery = http_build_query([
96 | '__lazyform_amosfilter' => 1,
97 | 'sesskey' => sesskey(),
98 | 'fcmp' => ['foo_bar', 'baz_quix'],
99 | 'flng' => ['cs'],
100 | 'flast' => 1,
101 | 'fpg' => 3,
102 | ], '', '&');
103 |
104 | $response = \local_amos\external\get_translator_data::execute($filterquery);
105 | $response = external_api::clean_returnvalue(\local_amos\external\get_translator_data::execute_returns(), $response);
106 |
107 | $this->assertTrue(isset($response['json']));
108 |
109 | $data = json_decode($response['json'], true);
110 |
111 | $this->assertArrayHasKey('permalink', $data);
112 | $this->assertEquals(1, $data['found']);
113 | $this->assertEquals(1, $data['missing']);
114 | $this->assertEquals(0, $data['missingcurrentpage']);
115 | $this->assertEquals(0, count($data['strings']));
116 | $this->assertFalse($data['paginator']['hasmultiplepages']);
117 | $this->assertEquals(3, $data['paginator']['currentpage']);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/templates/frontpage.mustache:
--------------------------------------------------------------------------------
1 | {{!
2 | This file is part of Moodle - https://moodle.org/
3 |
4 | Moodle is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | Moodle is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with Moodle. If not, see .
16 | }}
17 | {{!
18 | @template local_plugins/frontpage
19 |
20 | Template purpose and description.
21 |
22 | Classes required for JS:
23 | * none
24 |
25 | Data attributes required for JS:
26 | * none
27 |
28 | Context variables required for this template:
29 | * attributes Array of name / value pairs.
30 |
31 | Example context (json):
32 | {}
33 | }}
34 |
35 |
36 |
37 | {{#str}} amos, local_amos {{/str}}
38 |
39 | {{#str}} about, local_amos {{/str}}
40 |
41 |
42 |
43 | {{#str}} contribute, local_amos {{/str}}
44 |
45 | {{#str}} contributestats, local_amos, {"count": {{#quote}} {{{contributedstrings}}} {{/quote}} } {{/str}}
46 | {{#str}} contributethanks, local_amos, { "listcontributors": {{#quote}} {{{listcontributors}}} {{/quote}} } {{/str}}
47 |
48 | {{#str}} contributenow, local_amos {{/str}}
49 | {{#str}} creditstitleshort, local_amos {{/str}}
50 |
51 |
52 |
53 |
54 | {{#str}} quicklinks, local_amos {{/str}}
55 |
56 |
57 | -
58 |
59 | {{#str}} quicklinks_amos, local_amos {{/str}}
60 |
61 |
62 | -
63 |
64 | {{#str}} quicklinks_forum, local_amos {{/str}}
65 |
66 |
67 | -
68 |
69 | {{#str}} quicklinks_newcomers, local_amos {{/str}}
70 |
71 |
72 | -
73 |
74 | {{#str}} quicklinks_manual, local_amos {{/str}}
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | {{#str}} availablelangs, core_install {{/str}}
84 |
85 | {{#str}} languagepacks, local_amos {{/str}}
86 |
87 | {{#langpackstats}}
88 | -
89 |
90 |
91 | {{langname}}
92 |
93 |
94 | {{#childpacks}}
95 | - {{langname}} {{totalstrings}}
96 | {{/childpacks}}
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | {{ratio}}%{{totalstrings}} / {{totalenglish}}
106 |
107 |
108 |
109 |
110 | {{/langpackstats}}
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/credits.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Displays maintainers and contributors per language
20 | *
21 | * @package local_amos
22 | * @copyright 2013 David Mudrak
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 | */
25 |
26 | require_once(__DIR__.'/../../config.php');
27 | require_once($CFG->dirroot.'/local/amos/locallib.php');
28 | require_once($CFG->dirroot.'/local/amos/mlanglib.php');
29 | require_once($CFG->dirroot.'/local/amos/renderer.php');
30 |
31 | $editmode = optional_param('editmode', false, PARAM_BOOL);
32 | $canedit = has_capability('local/amos:manage', context_system::instance());
33 |
34 | if (!$canedit) {
35 | $editmode = false;
36 | } else if (!$editmode) {
37 | $editmode = null;
38 | } else {
39 | $editmode = true;
40 | }
41 |
42 | $PAGE->set_context(context_system::instance());
43 | $PAGE->set_pagelayout('standard');
44 | $PAGE->set_url('/local/amos/credits.php');
45 | $PAGE->set_title(get_string('creditstitleshort', 'local_amos'));
46 | $PAGE->set_heading(get_string('creditstitlelong', 'local_amos'));
47 |
48 | if ($canedit and $editmode) {
49 | $PAGE->set_button($OUTPUT->single_button(new moodle_url($PAGE->url, array('editmode' => 0)), get_string('turneditingoff'), 'get'));
50 | $PAGE->set_url(new moodle_url($PAGE->url, array('editmode' => 1)));
51 | } else if ($canedit and !$editmode) {
52 | $PAGE->set_button($OUTPUT->single_button(new moodle_url($PAGE->url, array('editmode' => 1)), get_string('turneditingon'), 'get'));
53 | }
54 |
55 | $languages = mlang_tools::list_languages(false, true, false);
56 |
57 | // Get the list of known languages.
58 |
59 | foreach ($languages as $langcode => $langname) {
60 | $list[$langcode] = (object)array('langname' => $langname, 'maintainers' => array(), 'contributors' => array());
61 | }
62 |
63 | // Get the list of maintainers, explicitly assigned contributors and
64 | // other contributors based on submitted contributions.
65 |
66 | $userfields = user_picture::fields('u');
67 | list($sortsql, $sortparams) = users_order_by_sql();
68 |
69 | $sql = "SELECT t.lang AS amoslang, t.status AS contribstatus, 1 AS iseditable, {$userfields}
70 | FROM {amos_translators} t
71 | JOIN {user} u ON t.userid = u.id
72 | WHERE t.lang <> 'X' AND t.lang <> 'en'
73 |
74 | UNION
75 |
76 | SELECT c.lang AS amoslang, ".AMOS_USER_CONTRIBUTOR." AS contribstatus, 0 AS iseditable, {$userfields}
77 | FROM {amos_contributions} c
78 | JOIN {user} u ON c.authorid = u.id
79 | WHERE c.status = :status
80 | GROUP BY c.lang, {$userfields}
81 | HAVING COUNT(*) >= 3
82 |
83 | ORDER BY amoslang, contribstatus, {$sortsql}, iseditable";
84 |
85 | $rs = $DB->get_recordset_sql($sql, array_merge($sortparams,
86 | array('status' => local_amos_contribution::STATE_ACCEPTED)));
87 |
88 | // Track credits with unexpected data.
89 | $issues = array();
90 |
91 | foreach ($rs as $user) {
92 |
93 | $lang = $user->amoslang;
94 | if (empty($lang)) {
95 | $issues[] = (object)array(
96 | 'problem' => 'Empty contribution language',
97 | 'record' => $user,
98 | );
99 | continue;
100 | }
101 | unset($user->amoslang);
102 |
103 | $status = $user->contribstatus;
104 | unset($user->contribstatus);
105 |
106 | if (empty($list[$lang])) {
107 | $issues[] = (object)array(
108 | 'problem' => 'Unknown language',
109 | 'record' => $user,
110 | );
111 | continue;
112 | }
113 |
114 | if ($status == AMOS_USER_MAINTAINER) {
115 | if (!isset($list[$lang]->maintainers[$user->id])) {
116 | $list[$lang]->maintainers[$user->id] = $user;
117 | }
118 |
119 | } else if ($status == AMOS_USER_CONTRIBUTOR) {
120 | if (!isset($list[$lang]->maintainers[$user->id]) and !isset($list[$lang]->contributors[$user->id])) {
121 | $list[$lang]->contributors[$user->id] = $user;
122 | }
123 |
124 | } else {
125 | $issues[] = (object)array(
126 | 'problem' => 'Unknown credit status',
127 | 'record' => $user,
128 | );
129 | continue;
130 | }
131 | }
132 |
133 | $rs->close();
134 |
135 | // Output starts here
136 | echo $OUTPUT->header();
137 |
138 | $output = $PAGE->get_renderer('local_amos');
139 | echo $output->page_credits($list, current_language(), $editmode);
140 |
141 | if (!empty($issues) and has_capability('local/amos:manage', $PAGE->context)) {
142 | echo $output->page_credits_issues($issues);
143 | }
144 |
145 | echo $OUTPUT->footer();
146 |
--------------------------------------------------------------------------------
/importfile.php:
--------------------------------------------------------------------------------
1 | .
17 |
18 | /**
19 | * Import strings from uploaded file and stage them
20 | *
21 | * @package local
22 | * @subpackage amos
23 | * @copyright 2010 David Mudrak
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 | */
26 |
27 | require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
28 | require_once(dirname(__FILE__).'/locallib.php');
29 | require_once(dirname(__FILE__).'/mlanglib.php');
30 | require_once(dirname(__FILE__).'/mlangparser.php');
31 | require_once(dirname(__FILE__).'/importfile_form.php');
32 |
33 | require_login(SITEID, false);
34 | require_capability('local/amos:importfile', context_system::instance());
35 |
36 | $PAGE->set_pagelayout('standard');
37 | $PAGE->set_url('/local/amos/importfile.php');
38 | navigation_node::override_active_url(new moodle_url('/local/amos/stage.php'));
39 | $PAGE->set_title('AMOS ' . get_string('importfile', 'local_amos'));
40 | $PAGE->set_heading('AMOS ' . get_string('importfile', 'local_amos'));
41 |
42 | $importform = new local_amos_importfile_form(null, local_amos_importfile_options());
43 |
44 | if (($data = $importform->get_data()) and has_capability('local/amos:stage', context_system::instance())) {
45 | $tmpdir = $CFG->dataroot . '/amos/temp/import-uploads/' . $USER->id;
46 | check_dir_exists($tmpdir);
47 | $filenameorig = basename($importform->get_new_filename('importfile'));
48 | $filename = $filenameorig . '-' . md5(time() . '-' . $USER->id . '-'. random_string(20));
49 | $pathname = $tmpdir . '/' . $filename;
50 |
51 | if ($importform->save_file('importfile', $pathname)) {
52 |
53 | // Prepare the list of files to import.
54 | $stringfiles = array();
55 |
56 | if (strtolower(substr($filenameorig, -4)) === '.zip') {
57 | $tmpzipdir = $pathname . '-content';
58 | check_dir_exists($tmpzipdir);
59 | $fp = get_file_packer('application/zip');
60 | $zipcontents = $fp->extract_to_pathname($pathname, $tmpzipdir);
61 | if (!$zipcontents) {
62 | notice(get_string('novalidzip', 'local_amos'), new moodle_url('/local/amos/stage.php'));
63 | @remove_dir($tmpzipdir);
64 | } else {
65 | foreach ($zipcontents as $zipfilename => $zipfilestatus) {
66 | // We want PHP files in the root of the ZIP only.
67 | if ($zipfilestatus === true and basename($zipfilename) === $zipfilename and strtolower(substr($zipfilename, -4)) === '.php') {
68 | $stringfiles[$zipfilename] = $tmpzipdir . '/' . $zipfilename;
69 | }
70 | }
71 | }
72 |
73 | } else if (strtolower(substr($filenameorig, -4)) === '.php') {
74 | $stringfiles = array($filenameorig => $pathname);
75 | }
76 |
77 | if (empty($stringfiles)) {
78 | notice(get_string('nostringtoimport', 'local_amos'), new moodle_url('/local/amos/stage.php'));
79 |
80 | } else {
81 | $stage = mlang_persistent_stage::instance_for_user($USER->id, sesskey());
82 | $version = mlang_version::by_code($data->version);
83 | $parser = mlang_parser_factory::get_parser('php');
84 |
85 | foreach ($stringfiles as $filenameorig => $pathname) {
86 | $name = mlang_component::name_from_filename($filenameorig);
87 | $component = new mlang_component($name, $data->language, $version);
88 |
89 | try {
90 | $parser->parse(file_get_contents($pathname), $component);
91 |
92 | } catch (mlang_parser_exception $e) {
93 | notice($e->getMessage(), new moodle_url('/local/amos/stage.php'));
94 | }
95 |
96 | $encomponent = mlang_component::from_snapshot($component->name, 'en', $version);
97 | $component->intersect($encomponent);
98 |
99 | if ($component->has_string()) {
100 | $stage->add($component, true);
101 | $component->clear();
102 | $stage->store();
103 | }
104 | }
105 | mlang_stash::autosave($stage);
106 | }
107 |
108 | if (!empty($tmpzipdir)) {
109 | @remove_dir($tmpzipdir);
110 | }
111 |
112 | } else {
113 | notice(get_string('nofiletoimport', 'local_amos'), new moodle_url('/local/amos/stage.php'));
114 | }
115 | }
116 |
117 | if (!isset($stage) or !$stage->has_component()) {
118 | notice(get_string('nostringtoimport', 'local_amos'), new moodle_url('/local/amos/stage.php'));
119 | }
120 |
121 | redirect(new moodle_url('/local/amos/stage.php'));
122 |
--------------------------------------------------------------------------------