Compare commits
40 commits
main
...
MOODLE_39_
Author | SHA1 | Date | |
---|---|---|---|
|
68b53cf67b | ||
|
a6a7b24898 | ||
|
fae09fbadf | ||
|
62d1bbdedc | ||
|
f3050a3ebf | ||
|
904a83e2b9 | ||
|
29779a32f2 | ||
|
c3942c3b75 | ||
|
56bdfdea6a | ||
|
32b255cb0d | ||
|
471b5cce73 | ||
|
c0c6bd1d47 | ||
|
d6d10d21ac | ||
|
227b162721 | ||
|
b20eafe22f | ||
|
af28f5bad1 | ||
|
a07c81a409 | ||
|
3024bf1516 | ||
|
e99d25a18b | ||
|
8effac9d93 | ||
|
c3a9172d8d | ||
|
8a80ab82d8 | ||
|
135630487c | ||
|
39e2bdd95d | ||
|
0f66037b8f | ||
|
810c4b2fcf | ||
|
29deb01aaf | ||
|
52be3400f7 | ||
|
54be90f5c4 | ||
|
00e9eaba4d | ||
|
4881963650 | ||
|
8e2e1a2336 | ||
|
05b523eaa6 | ||
|
7df31f16fb | ||
|
89516bf17d | ||
|
dfea4af2b6 | ||
|
4c8564a9b4 | ||
|
698b4563d1 | ||
|
26e72d770c | ||
|
63160279f5 |
40 changed files with 652 additions and 144 deletions
120
.github/workflows/moodle-ci.yml
vendored
Normal file
120
.github/workflows/moodle-ci.yml
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
name: Moodle Plugin CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:9.6
|
||||
env:
|
||||
POSTGRES_USER: 'postgres'
|
||||
POSTGRES_HOST_AUTH_METHOD: 'trust'
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
|
||||
mariadb:
|
||||
image: mariadb:10.5
|
||||
env:
|
||||
MYSQL_USER: 'root'
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- php: '7.4'
|
||||
moodle-branch: 'MOODLE_39_STABLE'
|
||||
database: pgsql
|
||||
- php: '7.4'
|
||||
moodle-branch: 'MOODLE_39_STABLE'
|
||||
database: mariadb
|
||||
- php: '7.2'
|
||||
moodle-branch: 'MOODLE_39_STABLE'
|
||||
database: pgsql
|
||||
- php: '7.2'
|
||||
moodle-branch: 'MOODLE_39_STABLE'
|
||||
database: mariadb
|
||||
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: plugin
|
||||
|
||||
- name: Setup PHP ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: none
|
||||
|
||||
- name: Initialise moodle-plugin-ci
|
||||
run: |
|
||||
composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
|
||||
echo $(cd ci/bin; pwd) >> $GITHUB_PATH
|
||||
echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
|
||||
sudo locale-gen en_AU.UTF-8
|
||||
echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV
|
||||
|
||||
- name: Install moodle-plugin-ci
|
||||
run: moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1
|
||||
env:
|
||||
DB: ${{ matrix.database }}
|
||||
MOODLE_BRANCH: ${{ matrix.moodle-branch }}
|
||||
MUSTACHE_IGNORE_NAMES: 'mobile_*.mustache'
|
||||
|
||||
- name: PHP Lint
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci phplint
|
||||
|
||||
- name: PHP Copy/Paste Detector
|
||||
continue-on-error: true # This step will show errors but will not fail
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci phpcpd
|
||||
|
||||
- name: PHP Mess Detector
|
||||
continue-on-error: true # This step will show errors but will not fail
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci phpmd
|
||||
|
||||
- name: Moodle Code Checker
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci codechecker --max-warnings 0
|
||||
|
||||
- name: Moodle PHPDoc Checker
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci phpdoc
|
||||
|
||||
- name: Validating
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci validate
|
||||
|
||||
- name: Check upgrade savepoints
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci savepoints
|
||||
|
||||
- name: Mustache Lint
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci mustache
|
||||
|
||||
- name: Grunt
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci grunt --max-lint-warnings 0
|
||||
|
||||
- name: PHPUnit tests
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
moodle-plugin-ci phpunit
|
||||
cd moodle
|
||||
vendor/bin/phpunit --fail-on-risky --disallow-test-output -v admin/tool/dataprivacy/tests/metadata_registry_test.php
|
||||
vendor/bin/phpunit --fail-on-risky --disallow-test-output -v lib/tests/externallib_test.php
|
||||
vendor/bin/phpunit --fail-on-risky --disallow-test-output -v privacy/tests/provider_test.php
|
||||
|
||||
- name: Behat features
|
||||
if: ${{ always() }}
|
||||
run: moodle-plugin-ci behat --profile chrome
|
52
.travis.yml
52
.travis.yml
|
@ -1,52 +0,0 @@
|
|||
language: php
|
||||
|
||||
# For javascript behat tests we need sudo
|
||||
sudo: true
|
||||
dist: trusty
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
- $HOME/.npm
|
||||
|
||||
php:
|
||||
- 7.2
|
||||
- 7.4
|
||||
|
||||
addons:
|
||||
firefox: 47.0.1
|
||||
postgresql: 9.5
|
||||
apt:
|
||||
packages:
|
||||
- openjdk-8-jre-headless
|
||||
|
||||
env:
|
||||
global:
|
||||
- MOODLE_BRANCH=MOODLE_39_STABLE
|
||||
- IGNORE_NAMES=mobile_*.mustache # Mobile mustache has specific syntax, ignore their templates
|
||||
matrix:
|
||||
- DB=pgsql
|
||||
- DB=mysqli
|
||||
|
||||
before_install:
|
||||
- phpenv config-rm xdebug.ini
|
||||
- nvm install 14.0
|
||||
- nvm use 14.0
|
||||
- cd ../..
|
||||
- composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
|
||||
- export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
|
||||
|
||||
install:
|
||||
- moodle-plugin-ci install
|
||||
|
||||
script:
|
||||
- moodle-plugin-ci phplint
|
||||
# - moodle-plugin-ci phpcpd # subplugins often have similar code and cause "duplicated code" errors
|
||||
# - moodle-plugin-ci phpmd # too much noise from this check, maybe, some day...
|
||||
- moodle-plugin-ci codechecker
|
||||
- moodle-plugin-ci validate
|
||||
- moodle-plugin-ci savepoints
|
||||
- moodle-plugin-ci mustache
|
||||
- moodle-plugin-ci grunt -t stylelint:css -t js
|
||||
- moodle-plugin-ci phpunit
|
||||
- moodle-plugin-ci behat
|
26
CHANGES.md
26
CHANGES.md
|
@ -4,6 +4,32 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/mdjnelson/moodle-mod_customcert/issues/169.
|
||||
|
||||
## [3.9.2] - 2021-??-??
|
||||
|
||||
### Fixed
|
||||
- Fix places not using the multi-language filter (#433).
|
||||
- Fix user IDs in the issue table not being mapped during restore (#449).
|
||||
- Fix emails displaying HTML entities encoded (#457).
|
||||
- Respect multiple languages in manage template page title (#467).
|
||||
|
||||
### Added
|
||||
- You can now choose the course short or full name to display (#415).
|
||||
- You can now select the alignment for all text elements (#121).
|
||||
|
||||
## [3.9.1] - 2021-06-13
|
||||
|
||||
### Added
|
||||
- Usage of github actions (#407).
|
||||
- The ability to show the description on the course page (#406).
|
||||
- The ability to choose how to deliver the certificate (#401).
|
||||
|
||||
### Fixed
|
||||
- Managers are now able to download their students' certificates (#412).
|
||||
- Users being able to view the certificate before the required time set (#403).
|
||||
- Fixed the issue with displaying PDF when debugging is ON (#420).
|
||||
- Using incorrect context when sending emails (#402).
|
||||
- Use `cron_setup_user` when sending emails (#414).
|
||||
|
||||
## [3.8.5] - 2020-11-26
|
||||
|
||||
### Added
|
||||
|
|
2
ajax.php
2
ajax.php
|
@ -54,4 +54,4 @@ foreach ($values as $value) {
|
|||
$element->posx = $value->posx;
|
||||
$element->posy = $value->posy;
|
||||
$DB->update_record('customcert_elements', $element);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ class backup_customcert_activity_task extends backup_activity_task {
|
|||
* @param string $content
|
||||
* @return mixed|string
|
||||
*/
|
||||
static public function encode_content_links($content) {
|
||||
public static function encode_content_links($content) {
|
||||
global $CFG;
|
||||
|
||||
$base = preg_quote($CFG->wwwroot, "/");
|
||||
|
|
|
@ -59,7 +59,7 @@ class backup_customcert_activity_structure_step extends backup_activity_structur
|
|||
$element = new backup_nested_element('element', array('id'), array(
|
||||
'pageid', 'name', 'element', 'data', 'font', 'fontsize',
|
||||
'colour', 'posx', 'posy', 'width', 'refpoint', 'sequence',
|
||||
'timecreated', 'timemodified'));
|
||||
'alignment', 'timecreated', 'timemodified'));
|
||||
|
||||
// The issues.
|
||||
$issues = new backup_nested_element('issues');
|
||||
|
|
|
@ -53,7 +53,7 @@ class restore_customcert_activity_task extends restore_activity_task {
|
|||
/**
|
||||
* Define the contents in the activity that must be processed by the link decoder.
|
||||
*/
|
||||
static public function define_decode_contents() {
|
||||
public static function define_decode_contents() {
|
||||
$contents = array();
|
||||
|
||||
$contents[] = new restore_decode_content('customcert', array('intro'), 'customcert');
|
||||
|
@ -64,7 +64,7 @@ class restore_customcert_activity_task extends restore_activity_task {
|
|||
/**
|
||||
* Define the decoding rules for links belonging to the activity to be executed by the link decoder.
|
||||
*/
|
||||
static public function define_decode_rules() {
|
||||
public static function define_decode_rules() {
|
||||
$rules = array();
|
||||
|
||||
$rules[] = new restore_decode_rule('CUSTOMCERTVIEWBYID', '/mod/customcert/view.php?id=$1', 'course_module');
|
||||
|
@ -75,12 +75,12 @@ class restore_customcert_activity_task extends restore_activity_task {
|
|||
}
|
||||
|
||||
/**
|
||||
* Define the restore log rules that will be applied by the {@link restore_logs_processor} when restoring
|
||||
* customcert logs. It must return one array of {@link restore_log_rule} objects.
|
||||
* Define the restore log rules that will be applied by the {@see restore_logs_processor} when restoring
|
||||
* customcert logs. It must return one array of {@see restore_log_rule} objects.
|
||||
*
|
||||
* @return array the restore log rules
|
||||
*/
|
||||
static public function define_restore_log_rules() {
|
||||
public static function define_restore_log_rules() {
|
||||
$rules = array();
|
||||
|
||||
$rules[] = new restore_log_rule('customcert', 'add', 'view.php?id={course_module}', '{customcert}');
|
||||
|
|
|
@ -159,6 +159,7 @@ class restore_customcert_activity_structure_step extends restore_activity_struct
|
|||
|
||||
$data->customcertid = $this->get_new_parentid('customcert');
|
||||
$data->timecreated = $this->apply_date_offset($data->timecreated);
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
|
||||
$newitemid = $DB->insert_record('customcert_issues', $data);
|
||||
$this->set_mapping('customcert_issue', $oldid, $newitemid);
|
||||
|
|
|
@ -80,4 +80,4 @@ class admin_setting_link extends \admin_setting_configtext {
|
|||
return format_admin_setting($this, $this->visiblename,
|
||||
\html_writer::link($this->link, $this->linkname), $this->description, true, '', null, $query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,16 @@ defined('MOODLE_INTERNAL') || die();
|
|||
*/
|
||||
class certificate {
|
||||
|
||||
/**
|
||||
* Send the file inline to the browser.
|
||||
*/
|
||||
const DELIVERY_OPTION_INLINE = 'I';
|
||||
|
||||
/**
|
||||
* Send to the browser and force a file download
|
||||
*/
|
||||
const DELIVERY_OPTION_DOWNLOAD = 'D';
|
||||
|
||||
/**
|
||||
* @var string the print protection variable
|
||||
*/
|
||||
|
@ -165,7 +175,7 @@ class certificate {
|
|||
* @param int $userid
|
||||
* @return int the total time spent in seconds
|
||||
*/
|
||||
public static function get_course_time($courseid, $userid = 0) {
|
||||
public static function get_course_time(int $courseid, int $userid = 0): int {
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
if (empty($userid)) {
|
||||
|
@ -217,7 +227,7 @@ class certificate {
|
|||
$totaltime = 0;
|
||||
}
|
||||
$delay = $log->$timefield - $lasthit;
|
||||
if ($delay > ($CFG->sessiontimeout * 60)) {
|
||||
if ($delay > $CFG->sessiontimeout) {
|
||||
// The difference between the last log and the current log is more than
|
||||
// the timeout Register session value so that we have found a session!
|
||||
$login = $log->$timefield;
|
||||
|
|
|
@ -247,7 +247,7 @@ class edit_form extends \moodleform {
|
|||
// Create a table to display these elements.
|
||||
$table = new \html_table();
|
||||
$table->attributes = array('class' => 'generaltable elementstable');
|
||||
$table->head = array(get_string('name', 'customcert'), get_string('type', 'customcert'), '');
|
||||
$table->head = array(get_string('name', 'customcert'), get_string('type', 'customcert'), get_string('actions'));
|
||||
$table->align = array('left', 'left', 'left');
|
||||
// Loop through and add the elements to the table.
|
||||
foreach ($elements as $element) {
|
||||
|
|
|
@ -37,6 +37,21 @@ defined('MOODLE_INTERNAL') || die();
|
|||
*/
|
||||
abstract class element {
|
||||
|
||||
/**
|
||||
* @var string The left alignment constant.
|
||||
*/
|
||||
const ALIGN_LEFT = 'L';
|
||||
|
||||
/**
|
||||
* @var string The centered alignment constant.
|
||||
*/
|
||||
const ALIGN_CENTER = 'C';
|
||||
|
||||
/**
|
||||
* @var string The right alignment constant.
|
||||
*/
|
||||
const ALIGN_RIGHT = 'R';
|
||||
|
||||
/**
|
||||
* @var \stdClass $element The data for the element we are adding - do not use, kept for legacy reasons.
|
||||
*/
|
||||
|
@ -97,6 +112,11 @@ abstract class element {
|
|||
*/
|
||||
protected $refpoint;
|
||||
|
||||
/**
|
||||
* @var string The alignment.
|
||||
*/
|
||||
protected $alignment;
|
||||
|
||||
/**
|
||||
* @var bool $showposxy Show position XY form elements?
|
||||
*/
|
||||
|
@ -130,6 +150,7 @@ abstract class element {
|
|||
$this->width = $element->width;
|
||||
$this->refpoint = $element->refpoint;
|
||||
$this->showposxy = isset($showposxy) && $showposxy;
|
||||
$this->set_alignment($element->alignment ?? self::ALIGN_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,6 +252,31 @@ abstract class element {
|
|||
return $this->refpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alignment.
|
||||
*
|
||||
* @return string The current alignment value.
|
||||
*/
|
||||
public function get_alignment() {
|
||||
return $this->alignment ?? self::ALIGN_LEFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alignment.
|
||||
*
|
||||
* @param string $alignment The new alignment.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the provided new alignment is not valid.
|
||||
*/
|
||||
protected function set_alignment(string $alignment) {
|
||||
$validvalues = array(self::ALIGN_LEFT, self::ALIGN_CENTER, self::ALIGN_RIGHT);
|
||||
if (!in_array($alignment, $validvalues)) {
|
||||
throw new \InvalidArgumentException("'$alignment' is not a valid alignment value. It has to be one of " .
|
||||
implode(', ', $validvalues));
|
||||
}
|
||||
$this->alignment = $alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function renders the form elements when adding a customcert element.
|
||||
* Can be overridden if more functionality is needed.
|
||||
|
@ -246,6 +292,7 @@ abstract class element {
|
|||
}
|
||||
element_helper::render_form_element_width($mform);
|
||||
element_helper::render_form_element_refpoint($mform);
|
||||
element_helper::render_form_element_alignment($mform);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -265,7 +312,8 @@ abstract class element {
|
|||
'posx' => $this->posx,
|
||||
'posy' => $this->posy,
|
||||
'width' => $this->width,
|
||||
'refpoint' => $this->refpoint
|
||||
'refpoint' => $this->refpoint,
|
||||
'alignment' => $this->get_alignment()
|
||||
];
|
||||
foreach ($properties as $property => $value) {
|
||||
if (!is_null($value) && $mform->elementExists($property)) {
|
||||
|
@ -311,15 +359,16 @@ abstract class element {
|
|||
$element = new \stdClass();
|
||||
$element->name = $data->name;
|
||||
$element->data = $this->save_unique_data($data);
|
||||
$element->font = (isset($data->font)) ? $data->font : null;
|
||||
$element->fontsize = (isset($data->fontsize)) ? $data->fontsize : null;
|
||||
$element->colour = (isset($data->colour)) ? $data->colour : null;
|
||||
$element->font = $data->font ?? null;
|
||||
$element->fontsize = $data->fontsize ?? null;
|
||||
$element->colour = $data->colour ?? null;
|
||||
if ($this->showposxy) {
|
||||
$element->posx = (isset($data->posx)) ? $data->posx : null;
|
||||
$element->posy = (isset($data->posy)) ? $data->posy : null;
|
||||
$element->posx = $data->posx ?? null;
|
||||
$element->posy = $data->posy ?? null;
|
||||
}
|
||||
$element->width = (isset($data->width)) ? $data->width : null;
|
||||
$element->refpoint = (isset($data->refpoint)) ? $data->refpoint : null;
|
||||
$element->width = $data->width ?? null;
|
||||
$element->refpoint = $data->refpoint ?? null;
|
||||
$element->alignment = $data->alignment ?? self::ALIGN_LEFT;
|
||||
$element->timemodified = time();
|
||||
|
||||
// Check if we are updating, or inserting a new element.
|
||||
|
@ -377,7 +426,7 @@ abstract class element {
|
|||
* @param bool $preview true if it is a preview, false otherwise
|
||||
* @param \stdClass $user the user we are rendering this for
|
||||
*/
|
||||
public abstract function render($pdf, $preview, $user);
|
||||
abstract public function render($pdf, $preview, $user);
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
|
@ -389,7 +438,7 @@ abstract class element {
|
|||
*
|
||||
* @return string the html
|
||||
*/
|
||||
public abstract function render_html();
|
||||
abstract public function render_html();
|
||||
|
||||
/**
|
||||
* Handles deleting any data this element may have introduced.
|
||||
|
|
|
@ -59,6 +59,7 @@ class element_factory {
|
|||
$data->posy = $element->posy ?? null;
|
||||
$data->width = $element->width ?? null;
|
||||
$data->refpoint = $element->refpoint ?? null;
|
||||
$data->alignment = $element->alignment ?? null;
|
||||
|
||||
// Ensure the necessary class exists.
|
||||
if (class_exists($classname)) {
|
||||
|
|
|
@ -74,6 +74,7 @@ class element_helper {
|
|||
$w = $element->get_width();
|
||||
$refpoint = $element->get_refpoint();
|
||||
$actualwidth = $pdf->GetStringWidth($content);
|
||||
$alignment = $element->get_alignment();
|
||||
|
||||
if ($w and $w < $actualwidth) {
|
||||
$actualwidth = $w;
|
||||
|
@ -104,7 +105,7 @@ class element_helper {
|
|||
$w += 0.0001;
|
||||
}
|
||||
$pdf->setCellPaddings(0, 0, 0, 0);
|
||||
$pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true);
|
||||
$pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true, $alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,6 +206,23 @@ class element_helper {
|
|||
$mform->addHelpButton('refpoint', 'refpoint', 'customcert');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to render the alignment form element.
|
||||
*
|
||||
* @param \MoodleQuickForm $mform the edit_form instance.
|
||||
*/
|
||||
public static function render_form_element_alignment($mform) {
|
||||
$alignmentoptions = array();
|
||||
$alignmentoptions[element::ALIGN_LEFT] = get_string('alignleft', 'customcert');
|
||||
$alignmentoptions[element::ALIGN_CENTER] = get_string('aligncenter', 'customcert');
|
||||
$alignmentoptions[element::ALIGN_RIGHT] = get_string('alignright', 'customcert');
|
||||
|
||||
$mform->addElement('select', 'alignment', get_string('alignment', 'customcert'), $alignmentoptions);
|
||||
$mform->setType('alignment', PARAM_ALPHA);
|
||||
$mform->setDefault('alignment', element::ALIGN_LEFT);
|
||||
$mform->addHelpButton('alignment', 'alignment', 'customcert');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to performs validation on the colour element.
|
||||
*
|
||||
|
|
|
@ -43,10 +43,20 @@ class course_module_viewed extends \core\event\course_module_viewed {
|
|||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_objectid_mapping() {
|
||||
return array('db' => 'customcert', 'restore' => 'customcert');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function get_other_mapping() {
|
||||
// No need to map.
|
||||
return false;
|
||||
|
|
|
@ -47,19 +47,23 @@ class load_template_form extends \moodleform {
|
|||
|
||||
// Get the context.
|
||||
$context = $this->_customdata['context'];
|
||||
$syscontext = \context_system::instance();
|
||||
|
||||
$mform->addElement('header', 'loadtemplateheader', get_string('loadtemplate', 'customcert'));
|
||||
|
||||
// Display a link to the manage templates page.
|
||||
if ($context->contextlevel != CONTEXT_SYSTEM && has_capability('mod/customcert:manage', \context_system::instance())) {
|
||||
if ($context->contextlevel != CONTEXT_SYSTEM && has_capability('mod/customcert:manage', $syscontext)) {
|
||||
$link = \html_writer::link(new \moodle_url('/mod/customcert/manage_templates.php'),
|
||||
get_string('managetemplates', 'customcert'));
|
||||
$mform->addElement('static', 'managetemplates', '', $link);
|
||||
}
|
||||
|
||||
$templates = $DB->get_records_menu('customcert_templates',
|
||||
array('contextid' => \context_system::instance()->id), 'name ASC', 'id, name');
|
||||
if ($templates) {
|
||||
$arrtemplates = $DB->get_records_menu('customcert_templates', ['contextid' => $syscontext->id], 'name ASC', 'id, name');
|
||||
if ($arrtemplates) {
|
||||
$templates = [];
|
||||
foreach ($arrtemplates as $key => $template) {
|
||||
$templates[$key] = format_string($template, true, ['context' => $context]);
|
||||
}
|
||||
$group = array();
|
||||
$group[] = $mform->createElement('select', 'ltid', '', $templates);
|
||||
$group[] = $mform->createElement('submit', 'loadtemplatesubmit', get_string('load', 'customcert'));
|
||||
|
|
|
@ -77,7 +77,7 @@ class manage_templates_table extends \table_sql {
|
|||
* @return string
|
||||
*/
|
||||
public function col_name($template) {
|
||||
return $template->name;
|
||||
return format_string($template->name, true, ['context' => $this->context]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,9 +44,10 @@ class mobile {
|
|||
global $OUTPUT, $DB, $USER;
|
||||
|
||||
$args = (object) $args;
|
||||
$versionname = $args->appversioncode >= 3950 ? 'latest' : 'ionic3';
|
||||
|
||||
$cmid = $args->cmid;
|
||||
$groupid = empty($args->group) ? 0 : $args->group; // By default, group 0.
|
||||
$groupid = empty($args->group) ? 0 : (int) $args->group; // By default, group 0.
|
||||
|
||||
// Capabilities check.
|
||||
$cm = get_coursemodule_from_id('customcert', $cmid);
|
||||
|
@ -114,6 +115,7 @@ class mobile {
|
|||
'showreport' => $showreport,
|
||||
'hasrecipients' => !empty($recipients),
|
||||
'recipients' => array_values($recipients),
|
||||
'numrecipients' => count($recipients),
|
||||
'currenttimestamp' => time()
|
||||
];
|
||||
|
||||
|
@ -121,11 +123,13 @@ class mobile {
|
|||
'templates' => [
|
||||
[
|
||||
'id' => 'main',
|
||||
'html' => $OUTPUT->render_from_template('mod_customcert/mobile_view_activity_page', $data),
|
||||
'html' => $OUTPUT->render_from_template("mod_customcert/mobile_view_activity_page_$versionname", $data),
|
||||
],
|
||||
],
|
||||
'javascript' => '',
|
||||
'otherdata' => ''
|
||||
'otherdata' => [
|
||||
'group' => $groupid,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,9 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
// Get the context.
|
||||
$context = \context::instance_by_id($customcert->contextid);
|
||||
|
||||
// Set the $PAGE context - this ensure settings, such as language, are kept and don't default to the site settings.
|
||||
$PAGE->set_context($context);
|
||||
|
||||
// Get the person we are going to send this email on behalf of.
|
||||
$userfrom = \core_user::get_noreply_user();
|
||||
|
||||
|
@ -176,6 +179,9 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
|
||||
// Now, email the people we need to.
|
||||
foreach ($issuedusers as $user) {
|
||||
// Set up the user.
|
||||
cron_setup_user($user);
|
||||
|
||||
$userfullname = fullname($user);
|
||||
$info->userfullname = $userfullname;
|
||||
|
||||
|
@ -205,7 +211,8 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
$subject = get_string('emailstudentsubject', 'customcert', $info);
|
||||
$message = $textrenderer->render($renderable);
|
||||
$messagehtml = $htmlrenderer->render($renderable);
|
||||
email_to_user($user, fullname($userfrom), $subject, $message, $messagehtml, $tempfile, $filename);
|
||||
email_to_user($user, fullname($userfrom), html_entity_decode($subject), $message, $messagehtml,
|
||||
$tempfile, $filename);
|
||||
}
|
||||
|
||||
if ($customcert->emailteachers) {
|
||||
|
@ -216,8 +223,8 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
$message = $textrenderer->render($renderable);
|
||||
$messagehtml = $htmlrenderer->render($renderable);
|
||||
foreach ($teachers as $teacher) {
|
||||
email_to_user($teacher, fullname($userfrom), $subject, $message, $messagehtml, $tempfile,
|
||||
$filename);
|
||||
email_to_user($teacher, fullname($userfrom), html_entity_decode($subject), $message, $messagehtml,
|
||||
$tempfile, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,8 +243,8 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
$emailuser = new \stdClass();
|
||||
$emailuser->id = -1;
|
||||
$emailuser->email = $email;
|
||||
email_to_user($emailuser, fullname($userfrom), $subject, $message, $messagehtml, $tempfile,
|
||||
$filename);
|
||||
email_to_user($emailuser, fullname($userfrom), html_entity_decode($subject), $message,
|
||||
$messagehtml, $tempfile, $filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ class template {
|
|||
* @param bool $return Do we want to return the contents of the PDF?
|
||||
* @return string|void Can return the PDF in string format if specified.
|
||||
*/
|
||||
public function generate_pdf($preview = false, $userid = null, $return = false) {
|
||||
public function generate_pdf(bool $preview = false, int $userid = null, bool $return = false) {
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
if (empty($userid)) {
|
||||
|
@ -269,20 +269,27 @@ class template {
|
|||
// Create the pdf object.
|
||||
$pdf = new \pdf();
|
||||
|
||||
$customcert = $DB->get_record('customcert', ['templateid' => $this->id]);
|
||||
|
||||
// If the template belongs to a certificate then we need to check what permissions we set for it.
|
||||
if ($protection = $DB->get_field('customcert', 'protection', array('templateid' => $this->id))) {
|
||||
if (!empty($protection)) {
|
||||
$protection = explode(', ', $protection);
|
||||
$pdf->SetProtection($protection);
|
||||
}
|
||||
if (!empty($customcert->protection)) {
|
||||
$protection = explode(', ', $customcert->protection);
|
||||
$pdf->SetProtection($protection);
|
||||
}
|
||||
|
||||
if (empty($customcert->deliveryoption)) {
|
||||
$deliveryoption = certificate::DELIVERY_OPTION_INLINE;
|
||||
} else {
|
||||
$deliveryoption = $customcert->deliveryoption;
|
||||
}
|
||||
|
||||
// Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename.
|
||||
$filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.');
|
||||
|
||||
$pdf->setPrintHeader(false);
|
||||
$pdf->setPrintFooter(false);
|
||||
$pdf->SetTitle($this->name);
|
||||
$pdf->SetTitle($filename);
|
||||
$pdf->SetAutoPageBreak(true, 0);
|
||||
// Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename.
|
||||
$filename = rtrim($this->name, '.');
|
||||
|
||||
// This is the logic the TCPDF library uses when processing the name. This makes names
|
||||
// such as 'الشهادة' become empty, so set a default name in these cases.
|
||||
|
@ -320,7 +327,7 @@ class template {
|
|||
return $pdf->Output('', 'S');
|
||||
}
|
||||
|
||||
$pdf->Output($filename, 'I');
|
||||
$pdf->Output($filename, $deliveryoption);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="requiredtime" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="verifyany" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="deliveryoption" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="emailstudents" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="emailteachers" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="emailothers" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
|
||||
|
@ -84,6 +85,7 @@
|
|||
<FIELD NAME="posy" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="width" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="refpoint" TYPE="int" LENGTH="4" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="alignment" TYPE="char" LENGTH="1" NOTNULL="true" DEFAULT="L" SEQUENCE="false"/>
|
||||
<FIELD NAME="sequence" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
|
|
|
@ -166,5 +166,26 @@ function xmldb_customcert_upgrade($oldversion) {
|
|||
upgrade_mod_savepoint(true, 2019111803, 'customcert');
|
||||
}
|
||||
|
||||
if ($oldversion < 2020061501) {
|
||||
$table = new xmldb_table('customcert');
|
||||
$field = new xmldb_field('deliveryoption', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'verifyany');
|
||||
|
||||
// Conditionally launch add field.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
upgrade_mod_savepoint(true, 2020061501, 'customcert');
|
||||
}
|
||||
|
||||
if ($oldversion < 2020061503) {
|
||||
$table = new xmldb_table('customcert_elements');
|
||||
$field = new xmldb_field('alignment', XMLDB_TYPE_CHAR, '1', null, XMLDB_NOTNULL, null, 'L', 'refpoint');
|
||||
|
||||
$dbman->add_field($table, $field);
|
||||
|
||||
upgrade_mod_savepoint(true, 2020061503, 'customcert'); // Replace with the actual version number.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ class element extends \mod_customcert\element {
|
|||
/**
|
||||
* Helper function that returns the field value in a human-readable format.
|
||||
*
|
||||
* @param \stdClass $user the user we are rendering this for
|
||||
* @param \stdClass $course the course we are rendering this for
|
||||
* @param bool $preview Is this a preview?
|
||||
* @return string
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,42 @@ defined('MOODLE_INTERNAL') || die();
|
|||
*/
|
||||
class element extends \mod_customcert\element {
|
||||
|
||||
/**
|
||||
* The course short name.
|
||||
*/
|
||||
const COURSE_SHORT_NAME = 1;
|
||||
|
||||
/**
|
||||
* The course fullname.
|
||||
*/
|
||||
const COURSE_FULL_NAME = 2;
|
||||
|
||||
/**
|
||||
* This function renders the form elements when adding a customcert element.
|
||||
*
|
||||
* @param \MoodleQuickForm $mform the edit_form instance
|
||||
*/
|
||||
public function render_form_elements($mform) {
|
||||
// The course name display options.
|
||||
$mform->addElement('select', 'coursenamedisplay', get_string('coursenamedisplay', 'customcertelement_coursename'),
|
||||
self::get_course_name_display_options());
|
||||
$mform->setType('coursenamedisplay', PARAM_INT);
|
||||
$mform->addHelpButton('coursenamedisplay', 'coursenamedisplay', 'customcertelement_coursename');
|
||||
|
||||
parent::render_form_elements($mform);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will handle how form data will be saved into the data column in the
|
||||
* customcert_elements table.
|
||||
*
|
||||
* @param \stdClass $data the form data
|
||||
* @return string the text
|
||||
*/
|
||||
public function save_unique_data($data) {
|
||||
return $data->coursenamedisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles rendering the element on the pdf.
|
||||
*
|
||||
|
@ -43,7 +79,7 @@ class element extends \mod_customcert\element {
|
|||
* @param \stdClass $user the user we are rendering this for
|
||||
*/
|
||||
public function render($pdf, $preview, $user) {
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_course_name());
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_course_name_detail());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,19 +91,52 @@ class element extends \mod_customcert\element {
|
|||
* @return string the html
|
||||
*/
|
||||
public function render_html() {
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_course_name());
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_course_name_detail());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the category name.
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
* @param \MoodleQuickForm $mform the edit_form instance
|
||||
*/
|
||||
public function definition_after_data($mform) {
|
||||
if (!empty($this->get_data())) {
|
||||
$element = $mform->getElement('coursenamedisplay');
|
||||
$element->setValue($this->get_data());
|
||||
}
|
||||
parent::definition_after_data($mform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the selected course name detail (i.e. name or short description) for display.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_course_name() : string {
|
||||
protected function get_course_name_detail(): string {
|
||||
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
|
||||
$course = get_course($courseid);
|
||||
$context = \mod_customcert\element_helper::get_context($this->get_id());
|
||||
|
||||
return format_string($course->fullname, true, ['context' => $context]);
|
||||
// The name field to display.
|
||||
$field = $this->get_data();
|
||||
// The name value to display.
|
||||
$value = $course->fullname;
|
||||
if ($field == self::COURSE_SHORT_NAME) {
|
||||
$value = $course->shortname;
|
||||
}
|
||||
|
||||
return format_string($value, true, ['context' => $context]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return all the possible name display options.
|
||||
*
|
||||
* @return array returns an array of name options
|
||||
*/
|
||||
public static function get_course_name_display_options(): array {
|
||||
return [
|
||||
self::COURSE_FULL_NAME => get_string('coursefullname', 'customcertelement_coursename'),
|
||||
self::COURSE_SHORT_NAME => get_string('courseshortname', 'customcertelement_coursename')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,5 +22,10 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['coursenamedisplay'] = 'Type';
|
||||
$string['coursenamedisplay_help'] = 'Display the course full name or short name?';
|
||||
$string['coursefullname'] = 'Full name';
|
||||
$string['courseshortname'] = 'Short name';
|
||||
$string['pluginname'] = 'Course name';
|
||||
$string['privacy:metadata'] = 'The Course name plugin does not store any personal data.';
|
||||
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
$string['activity'] = 'Activity';
|
||||
$string['addcertpage'] = 'Add page';
|
||||
$string['addelement'] = 'Add element';
|
||||
$string['aligncenter'] = 'Centered';
|
||||
$string['alignleft'] = 'Left alignment';
|
||||
$string['alignment'] = 'Alignment';
|
||||
$string['alignment_help'] = 'This property sets the horizontal alignment of the element. Some elements may not support this, while the behaviour of others may differ.';
|
||||
$string['alignright'] = 'Right alignment';
|
||||
$string['awardedto'] = 'Awarded to';
|
||||
$string['cannotverifyallcertificates'] = 'You do not have the permission to verify all certificates on the site.';
|
||||
$string['certificate'] = 'Certificate';
|
||||
|
@ -57,6 +62,9 @@ $string['deleteissueconfirm'] = 'Are you sure you want to delete this certificat
|
|||
$string['deleteissuedcertificates'] = 'Delete issued certificates';
|
||||
$string['deletepageconfirm'] = 'Are you sure you want to delete this certificate page?';
|
||||
$string['deletetemplateconfirm'] = 'Are you sure you want to delete this certificate template?';
|
||||
$string['deliveryoptiondownload'] = 'Send to the browser and force a file download';
|
||||
$string['deliveryoptioninline'] = 'Send the file inline to the browser';
|
||||
$string['deliveryoptions'] = 'Delivery options';
|
||||
$string['description'] = 'Description';
|
||||
$string['duplicate'] = 'Duplicate';
|
||||
$string['duplicateconfirm'] = 'Duplicate confirmation';
|
||||
|
|
2
lib.php
2
lib.php
|
@ -264,6 +264,8 @@ function customcert_supports($feature) {
|
|||
return true;
|
||||
case FEATURE_MOD_INTRO:
|
||||
return true;
|
||||
case FEATURE_SHOW_DESCRIPTION:
|
||||
return true;
|
||||
case FEATURE_COMPLETION_TRACKS_VIEWS:
|
||||
return true;
|
||||
case FEATURE_BACKUP_MOODLE2:
|
||||
|
|
|
@ -97,4 +97,4 @@ $PAGE->navbar->add(get_string('loadtemplate', 'customcert'));
|
|||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->confirm(get_string('loadtemplatemsg', 'customcert'), $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
||||
echo $OUTPUT->footer();
|
||||
|
|
|
@ -47,7 +47,6 @@ require_login();
|
|||
require_capability('mod/customcert:manage', $context);
|
||||
|
||||
$title = $SITE->fullname;
|
||||
$heading = $title;
|
||||
|
||||
// Set up the page.
|
||||
$pageurl = new moodle_url('/mod/customcert/manage_templates.php');
|
||||
|
@ -61,6 +60,8 @@ if ($tid && $action && confirm_sesskey()) {
|
|||
$PAGE->navbar->add(get_string('managetemplates', 'customcert'));
|
||||
}
|
||||
|
||||
$heading = format_string($title, true, ['context' => $context]);
|
||||
|
||||
if ($tid) {
|
||||
if ($action && confirm_sesskey()) {
|
||||
$nourl = new moodle_url('/mod/customcert/manage_templates.php');
|
||||
|
|
27
mod_form.php
27
mod_form.php
|
@ -22,6 +22,8 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_customcert\certificate;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
|
||||
require_once($CFG->dirroot.'/course/moodleform_mod.php');
|
||||
|
@ -55,14 +57,20 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
|
||||
$this->standard_intro_elements(get_string('description', 'customcert'));
|
||||
|
||||
$optionsheader = $mform->createElement('header', 'options', get_string('options', 'customcert'));
|
||||
$mform->addElement('header', 'options', get_string('options', 'customcert'));
|
||||
|
||||
$deliveryoptions = [
|
||||
certificate::DELIVERY_OPTION_INLINE => get_string('deliveryoptioninline', 'customcert'),
|
||||
certificate::DELIVERY_OPTION_DOWNLOAD => get_string('deliveryoptiondownload', 'customcert')
|
||||
];
|
||||
$mform->addElement('select', 'deliveryoption', get_string('deliveryoptions', 'customcert'), $deliveryoptions);
|
||||
$mform->setDefault('deliveryoption', certificate::DELIVERY_OPTION_INLINE);
|
||||
|
||||
if (has_capability('mod/customcert:manageemailstudents', $this->get_context())) {
|
||||
$mform->addElement('selectyesno', 'emailstudents', get_string('emailstudents', 'customcert'));
|
||||
$mform->setDefault('emailstudents', get_config('customcert', 'emailstudents'));
|
||||
$mform->addHelpButton('emailstudents', 'emailstudents', 'customcert');
|
||||
$mform->setType('emailstudents', PARAM_INT);
|
||||
$firstoption = 'emailstudents';
|
||||
}
|
||||
|
||||
if (has_capability('mod/customcert:manageemailteachers', $this->get_context())) {
|
||||
|
@ -70,7 +78,6 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
$mform->setDefault('emailteachers', get_config('customcert', 'emailteachers'));
|
||||
$mform->addHelpButton('emailteachers', 'emailteachers', 'customcert');
|
||||
$mform->setType('emailteachers', PARAM_INT);
|
||||
$firstoption = empty($firstoption) ? 'emailteachers' : $firstoption;
|
||||
}
|
||||
|
||||
if (has_capability('mod/customcert:manageemailothers', $this->get_context())) {
|
||||
|
@ -78,7 +85,6 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
$mform->addHelpButton('emailothers', 'emailothers', 'customcert');
|
||||
$mform->setDefault('emailothers', get_config('customcert', 'emailothers'));
|
||||
$mform->setType('emailothers', PARAM_TEXT);
|
||||
$firstoption = empty($firstoption) ? 'emailothers' : $firstoption;
|
||||
}
|
||||
|
||||
if (has_capability('mod/customcert:manageverifyany', $this->get_context())) {
|
||||
|
@ -86,7 +92,6 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
$mform->addHelpButton('verifyany', 'verifycertificateanyone', 'customcert');
|
||||
$mform->setDefault('verifyany', get_config('customcert', 'verifyany'));
|
||||
$mform->setType('verifyany', PARAM_INT);
|
||||
$firstoption = empty($firstoption) ? 'verifyany' : $firstoption;
|
||||
}
|
||||
|
||||
if (has_capability('mod/customcert:managerequiredtime', $this->get_context())) {
|
||||
|
@ -94,7 +99,6 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
$mform->addHelpButton('requiredtime', 'coursetimereq', 'customcert');
|
||||
$mform->setDefault('requiredtime', get_config('customcert', 'requiredtime'));
|
||||
$mform->setType('requiredtime', PARAM_INT);
|
||||
$firstoption = empty($firstoption) ? 'requiredtime' : $firstoption;
|
||||
}
|
||||
|
||||
if (has_capability('mod/customcert:manageprotection', $this->get_context())) {
|
||||
|
@ -106,11 +110,6 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
$mform->setType('protection_print', PARAM_BOOL);
|
||||
$mform->setType('protection_modify', PARAM_BOOL);
|
||||
$mform->setType('protection_copy', PARAM_BOOL);
|
||||
$firstoption = empty($firstoption) ? 'protection_print' : $firstoption;
|
||||
}
|
||||
|
||||
if (!empty($firstoption)) {
|
||||
$mform->insertElementBefore($optionsheader, $firstoption);
|
||||
}
|
||||
|
||||
$this->standard_coursemodule_elements();
|
||||
|
@ -227,13 +226,13 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
|
||||
$protection = explode(', ', $protection);
|
||||
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_PRINT, $protection)) {
|
||||
if (in_array(certificate::PROTECTION_PRINT, $protection)) {
|
||||
$data->protection_print = 1;
|
||||
}
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_MODIFY, $protection)) {
|
||||
if (in_array(certificate::PROTECTION_MODIFY, $protection)) {
|
||||
$data->protection_modify = 1;
|
||||
}
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_COPY, $protection)) {
|
||||
if (in_array(certificate::PROTECTION_COPY, $protection)) {
|
||||
$data->protection_copy = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,9 +49,15 @@ $user = \core_user::get_user($userid, '*', MUST_EXIST);
|
|||
|
||||
// If we are viewing certificates that are not for the currently logged in user then do a capability check.
|
||||
if (($userid != $USER->id) && !has_capability('mod/customcert:viewallcertificates', context_system::instance())) {
|
||||
print_error('You are not allowed to view these certificates');
|
||||
throw new moodle_exception('You are not allowed to view these certificates');
|
||||
}
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context(context_user::instance($userid));
|
||||
$PAGE->set_title(get_string('mycertificates', 'customcert'));
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->navigation->extend_for_user($user);
|
||||
|
||||
// Check if we requested to download a certificate.
|
||||
if ($downloadcert) {
|
||||
$template = $DB->get_record('customcert_templates', array('id' => $customcert->templateid), '*', MUST_EXIST);
|
||||
|
@ -68,12 +74,6 @@ if ($table->is_downloading()) {
|
|||
exit();
|
||||
}
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context(context_user::instance($userid));
|
||||
$PAGE->set_title(get_string('mycertificates', 'customcert'));
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->navigation->extend_for_user($user);
|
||||
|
||||
// Additional page setup.
|
||||
$PAGE->navbar->add(get_string('profile'), new moodle_url('/user/profile.php', array('id' => $userid)));
|
||||
$PAGE->navbar->add(get_string('mycertificates', 'customcert'));
|
||||
|
|
|
@ -112,6 +112,18 @@ if ($elements) {
|
|||
default:
|
||||
$class = 'element refpoint-left';
|
||||
}
|
||||
switch ($element->alignment) {
|
||||
case \mod_customcert\element::ALIGN_CENTER:
|
||||
$class .= ' align-center';
|
||||
break;
|
||||
case \mod_customcert\element::ALIGN_RIGHT:
|
||||
$class .= ' align-right';
|
||||
break;
|
||||
case \mod_customcert\element::ALIGN_LEFT:
|
||||
default:
|
||||
$class .= ' align-left';
|
||||
break;
|
||||
}
|
||||
$html .= html_writer::tag('div', $e->render_html(), array('class' => $class,
|
||||
'data-refpoint' => $element->refpoint, 'id' => 'element-' . $element->id));
|
||||
}
|
||||
|
|
12
styles.css
12
styles.css
|
@ -57,6 +57,18 @@
|
|||
margin: -4px -5px -5px 4px;
|
||||
}
|
||||
|
||||
#page-mod-customcert-rearrange .element.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#page-mod-customcert-rearrange .element.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#page-mod-customcert-rearrange .element.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#page-mod-customcert-rearrange #pdf {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
|
|
169
templates/mobile_view_activity_page_latest.mustache
Normal file
169
templates/mobile_view_activity_page_latest.mustache
Normal file
|
@ -0,0 +1,169 @@
|
|||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_customcert/mobile_view_activity_page
|
||||
|
||||
The main page to view the custom certificate activity
|
||||
|
||||
Classes required for JS:
|
||||
* None
|
||||
|
||||
Data attibutes required for JS:
|
||||
* All data attributes are required
|
||||
|
||||
Context variables required for this template:
|
||||
* certificate
|
||||
* cmid
|
||||
* hasissues
|
||||
* issues
|
||||
* showgroups
|
||||
* groups
|
||||
* canmanage
|
||||
* requiredtimemet
|
||||
* hasrecipients
|
||||
* recipients
|
||||
* fileurl
|
||||
* showreport
|
||||
* currenttimestamp
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"certificate": {
|
||||
"id": "1",
|
||||
"course": "2",
|
||||
"name": "A rad certificate name!",
|
||||
"intro": "A certificate",
|
||||
"requiredtime": "60"
|
||||
},
|
||||
"cmid": "25",
|
||||
"issue": {
|
||||
"timecreated": "1528370177"
|
||||
},
|
||||
"showgroups": "true",
|
||||
"groups": [
|
||||
{
|
||||
"id": "2",
|
||||
"selected": "false",
|
||||
"name": "Group A"
|
||||
}
|
||||
],
|
||||
"canmanage": "true",
|
||||
"requiredtimemet": "true",
|
||||
"fileurl": "http://yoursite.com/mod/customcert/mobile/pluginfile.php?id=4",
|
||||
"showreport": "true",
|
||||
"hasrecipients": "true",
|
||||
"recipients": [
|
||||
{
|
||||
"id": "2",
|
||||
"issueid": "3",
|
||||
"displayname": "Michaelangelo (Mickey)",
|
||||
"fileurl": "http://yoursite.com/mod/customcert/mobile/pluginfile.php?id=4",
|
||||
"timecreated": "1528370177"
|
||||
}
|
||||
],
|
||||
"currenttimestamp": "1528370177"
|
||||
}
|
||||
}}
|
||||
{{=<% %>=}}
|
||||
<core-course-module-description description="<% certificate.intro %>" component="mod_customcert" componentId="<% cmid %>"></core-course-module-description>
|
||||
<ion-list>
|
||||
<%^canmanage%>
|
||||
<%#requiredtimemet%>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
{{ 'plugin.mod_customcert.receiveddate' | translate }}
|
||||
<br />
|
||||
<div class="timerewarded">
|
||||
<%#issue%>
|
||||
{{ <% timecreated %> | coreToLocaleString }}
|
||||
<%/issue%>
|
||||
<%^issue%>
|
||||
{{ 'plugin.mod_customcert.notissued' | translate }}
|
||||
<%/issue%>
|
||||
</div>
|
||||
</ion-label>
|
||||
<div slot="end" class="flex-row">
|
||||
<ion-button fill="clear" [core-download-file]="{fileurl: '<% fileurl %>', timemodified: '<% currenttimestamp %>'}" moduleId="<% cmid %>" courseId="<% certificate.course %>" component="mod_customcert" [attr.aria-label]="'core.download' | translate">
|
||||
<ion-icon name="cloud-download" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-item>
|
||||
<%/requiredtimemet%>
|
||||
<%^requiredtimemet%>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<p>{{ 'plugin.mod_customcert.requiredtimenotmet' | translate: {$a: { requiredtime: <% certificate.requiredtime %>} } }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<%/requiredtimemet%>
|
||||
<%/canmanage%>
|
||||
<%#canmanage%>
|
||||
<ion-button expand="block" class="ion-margin" core-course-download-module-main-file moduleId="<% cmid %>" courseId="<% certificate.course %>" component="mod_customcert" [files]="[{fileurl: '<% fileurl %>', timemodified: '<% currenttimestamp %>'}]">
|
||||
<ion-icon name="cloud-download" slot="start" aria-hidden="true"></ion-icon>
|
||||
{{ 'plugin.mod_customcert.getcustomcert' | translate }}
|
||||
</ion-button>
|
||||
<%/canmanage%>
|
||||
<%#showreport%>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
{{ 'plugin.mod_customcert.listofissues' | translate: { $a: <% numrecipients %> } }}
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<%#showgroups%>
|
||||
<ion-item>
|
||||
<ion-label>{{ 'plugin.mod_customcert.selectagroup' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="CONTENT_OTHERDATA.group" name="group" (ionChange)="updateContent({cmid: <% cmid %>, courseid: <% certificate.course %>, group: CONTENT_OTHERDATA.group})" interface="popover">
|
||||
<%#groups%>
|
||||
<ion-select-option [value]="<% id %>"><% name %></ion-select-option>
|
||||
<%/groups%>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<%/showgroups%>
|
||||
<%#hasrecipients%>
|
||||
<%#recipients%>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<% displayname %>
|
||||
<br />
|
||||
<div class="timerewarded">{{ <% timecreated %> | coreToLocaleString }}</div>
|
||||
</ion-label>
|
||||
<div slot="end" class="flex-row">
|
||||
<ion-button fill="clear" [core-download-file]="{fileurl: '<% fileurl %>', timemodified: '<% currenttimestamp %>'}" moduleId="<% cmid %>" courseId="<% certificate.course %>" component="mod_customcert" [attr.aria-label]="'core.download' | translate">
|
||||
<ion-icon name="cloud-download" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
<%#canmanage%>
|
||||
<ion-button fill="clear" core-site-plugins-call-ws name="mod_customcert_delete_issue"
|
||||
[params]="{certificateid: <% certificate.id %>, issueid: <% issueid %>}"
|
||||
[preSets]="{getFromCache: 0, saveToCache: 0, typeExpected: 'boolean'}"
|
||||
confirmMessage="{{ 'plugin.mod_customcert.deleteissueconfirm' | translate }}"
|
||||
refreshOnSuccess="true" [attr.aria-label]="'core.delete' | translate">
|
||||
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
<%/canmanage%>
|
||||
</div>
|
||||
</ion-item>
|
||||
<%/recipients%>
|
||||
<%/hasrecipients%>
|
||||
<%^hasrecipients%>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
{{ 'plugin.mod_customcert.nothingtodisplay' | translate }}
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<%/hasrecipients%>
|
||||
<%/showreport%>
|
||||
</ion-list>
|
|
@ -40,7 +40,7 @@ class behat_mod_customcert extends behat_base {
|
|||
/**
|
||||
* Adds an element to the specified page of a template.
|
||||
*
|
||||
* @codingStandardsIgnoreLine
|
||||
* phpcs:ignore
|
||||
* @Given /^I add the element "(?P<element_name>(?:[^"]|\\")*)" to page "(?P<page_number>\d+)" of the "(?P<template_name>(?:[^"]|\\")*)" certificate template$/
|
||||
* @param string $elementname
|
||||
* @param int $pagenum
|
||||
|
|
|
@ -100,20 +100,22 @@ Feature: Being able to manage elements in a certificate template
|
|||
# Course name.
|
||||
And I add the element "Course name" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Font | Helvetica |
|
||||
| Type | Short name |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
And I should see "Course name" in the "elementstable" "table"
|
||||
And I click on ".edit-icon" "css_element" in the "Course name" "table_row"
|
||||
And the following fields match these values:
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Font | Helvetica |
|
||||
| Type | Short name |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
# Date.
|
||||
And I add the element "Date" to page "1" of the "Custom certificate 1" certificate template
|
||||
|
|
|
@ -55,7 +55,7 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
// Create a custom certificate with no elements.
|
||||
$this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
|
||||
|
||||
// Enrol the user as a student
|
||||
// Enrol the user as a student.
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
|
||||
// Run the task.
|
||||
|
@ -416,4 +416,4 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
// Confirm no emails were sent.
|
||||
$this->assertCount(0, $emails);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
|
||||
$plugin->version = 2020061500; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2020061503; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020061500; // Requires this Moodle version (3.9).
|
||||
$plugin->cron = 0; // Period for cron to check this module (secs).
|
||||
$plugin->component = 'mod_customcert';
|
||||
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
$plugin->release = "3.9.0"; // User-friendly version number.
|
||||
$plugin->release = "3.9.1"; // User-friendly version number.
|
||||
|
|
5
view.php
5
view.php
|
@ -56,7 +56,8 @@ if ($customcert->requiredtime && !$canmanage) {
|
|||
if (\mod_customcert\certificate::get_course_time($course->id) < ($customcert->requiredtime * 60)) {
|
||||
$a = new stdClass;
|
||||
$a->requiredtime = $customcert->requiredtime;
|
||||
notice(get_string('requiredtimenotmet', 'customcert', $a), "$CFG->wwwroot/course/view.php?id=$course->id");
|
||||
$url = new moodle_url('/course/view.php', ['id' => $course->id]);
|
||||
notice(get_string('requiredtimenotmet', 'customcert', $a), $url);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +159,7 @@ if (!$downloadown && !$downloadissue) {
|
|||
}
|
||||
echo $OUTPUT->footer($course);
|
||||
exit();
|
||||
} else if ($canreceive) { // Output to pdf.
|
||||
} else if ($canreceive || $canmanage) { // Output to pdf.
|
||||
// Set the userid value of who we are downloading the certificate for.
|
||||
$userid = $USER->id;
|
||||
if ($downloadown) {
|
||||
|
|
Loading…
Reference in a new issue