Compare commits
82 commits
main
...
MOODLE_34_
Author | SHA1 | Date | |
---|---|---|---|
|
cc0d7c343b | ||
|
d451ed8f01 | ||
|
f28b698781 | ||
|
bb5bce94a0 | ||
|
ff0652e3ac | ||
|
61e18a647b | ||
|
c85d7e0edc | ||
|
922389b770 | ||
|
9f9ce2a380 | ||
|
af3121f19c | ||
|
cddc2c4b41 | ||
|
6f7ad60f09 | ||
|
74a8a2f06c | ||
|
83f3fce127 | ||
|
1d27bece75 | ||
|
d9576aac13 | ||
|
d06da0993f | ||
|
3bed3b83ae | ||
|
0771ec8a4b | ||
|
149e3cfc6c | ||
|
30f80d70f7 | ||
|
93b00b27b4 | ||
|
1e30f4d05a | ||
|
c8ab936b34 | ||
|
17934659b6 | ||
|
e9ed3b28c7 | ||
|
2cdbc60c76 | ||
|
ce4da8c1b2 | ||
|
64e91c2716 | ||
|
04b0fde432 | ||
|
5b369e84c1 | ||
|
67aa5a7850 | ||
|
65dbda6378 | ||
|
7118f7966c | ||
|
2731008401 | ||
|
928e70d5e7 | ||
|
0f5aaffd8d | ||
|
0d68d4891d | ||
|
ed24576728 | ||
|
5f80f246cb | ||
|
3f082b7e56 | ||
|
83f337f5c4 | ||
|
7e9414313e | ||
|
7b35bcee9e | ||
|
b928fd33a7 | ||
|
520d6a2a5d | ||
|
f63d61d164 | ||
|
2736eceb6a | ||
|
9589bad2d8 | ||
|
752c7d17a9 | ||
|
7f12ab8a40 | ||
|
bb627df42e | ||
|
6fafe6aea9 | ||
|
c1a70c763e | ||
|
9d27015a5f | ||
|
e5939c8076 | ||
|
2e146373dd | ||
|
930850ac3b | ||
|
3680c4586c | ||
|
18ce8da214 | ||
|
75a9357dd1 | ||
|
5b56acad9b | ||
|
9f4492e7e9 | ||
|
3f4e2be973 | ||
|
aeee01b7be | ||
|
9c633f1b28 | ||
|
fab998e07d | ||
|
7038b60c51 | ||
|
743d1fb86a | ||
|
ff31b4b824 | ||
|
9bfaa5da66 | ||
|
0e5ef79ab9 | ||
|
a42bc9ebe1 | ||
|
24068856f1 | ||
|
2fa7191d12 | ||
|
9bf0fc4e94 | ||
|
c80fee36ec | ||
|
b93a12a74f | ||
|
45494e3586 | ||
|
adb17cf61e | ||
|
f28c2324e2 | ||
|
f7732690ab |
63 changed files with 2985 additions and 659 deletions
24
.travis.yml
24
.travis.yml
|
@ -1,30 +1,39 @@
|
|||
language: php
|
||||
|
||||
sudo: false
|
||||
# For javascript behat tests we need sudo
|
||||
sudo: true
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
- $HOME/.npm
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.2
|
||||
|
||||
addons:
|
||||
firefox: 47.0.1
|
||||
postgresql: 9.3
|
||||
apt:
|
||||
packages:
|
||||
- oracle-java8-installer
|
||||
- oracle-java8-set-default
|
||||
|
||||
env:
|
||||
global:
|
||||
- MOODLE_BRANCH=MOODLE_34_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 8.9
|
||||
- nvm use 8.9
|
||||
- cd ../..
|
||||
- composer selfupdate
|
||||
- composer create-project -n --no-dev --prefer-dist moodlerooms/moodle-plugin-ci ci ^1
|
||||
- composer create-project -n --no-dev --prefer-dist blackboard-open-source/moodle-plugin-ci ci ^2
|
||||
- export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
|
||||
|
||||
install:
|
||||
|
@ -32,11 +41,12 @@ 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 csslint
|
||||
- moodle-plugin-ci shifter
|
||||
- moodle-plugin-ci jshint
|
||||
- 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
|
||||
|
||||
|
|
101
CHANGES.md
101
CHANGES.md
|
@ -4,6 +4,107 @@ 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/markn86/moodle-mod_customcert/issues/169.
|
||||
|
||||
## [3.4.7] - 2018-12-31
|
||||
|
||||
### Changed
|
||||
|
||||
- Make it clear what element values are just an example when previewing the PDF (#144).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Missing implementation for privacy provider (#260).
|
||||
- Use course module context when calling format_string/text (#200).
|
||||
- Exception being thrown when adding the 'teachername' element to site template (#261).
|
||||
|
||||
## [3.4.6] - 2018-12-20
|
||||
### Added
|
||||
|
||||
- GDPR: Add support for removal of users from a context (see MDL-62560) (#252).
|
||||
- Images can be made transparent (#186).
|
||||
- Set default values of activity instance settings (#180).
|
||||
- Allow element plugins to control if they can be added to a certificate (#225).
|
||||
- Allow element plugins to have their own admin settings (#213).
|
||||
- Added plaintext language variants for email bodies (#231).
|
||||
- Added possibility to selectively disable activity instance settings (#179).
|
||||
|
||||
### Changed
|
||||
|
||||
- Allow verification of deleted users (#159).
|
||||
- The 'element' field in the 'customcert_elements' table has been changed from a Text field to varchar(255) (#241).
|
||||
- The 'Completion date' option in the 'date' element is only displayed when completion is enabled (#160).
|
||||
- Instead of assuming 2 decimal points for percentages, we now make use of the decimal value setting, which the
|
||||
function `grade_format_gradevalue` does by default if no decimal value is passed.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Issue with scales not displaying correctly (#242).
|
||||
- The report now respects the setting 'Show user identity' (#224).
|
||||
- Removed incorrect course reset logic (#223).
|
||||
- Description strings referring to the wrong setting (#254).
|
||||
|
||||
## [3.4.5] - 2018-07-13
|
||||
### Fixed
|
||||
|
||||
- Use custom fonts if present (#211).
|
||||
- Fix broken SQL on Oracle in the email certificate task (#187).
|
||||
- Fixed exception when clicking 'Add page' when template has not been saved (#154).
|
||||
- Only email teachers who are enrolled within the course (#176).
|
||||
- Only display teachers who are enrolled within the course in the dropdown (#171).
|
||||
|
||||
### Changed
|
||||
|
||||
- Multiple UX improvements to both the browser and mobile views (#207).
|
||||
- One big change here is combining the report and activity view page into one.
|
||||
- Allow short dates with leading zeros (#210).
|
||||
|
||||
## [3.4.4] - 2018-06-26
|
||||
### Fixed
|
||||
|
||||
- Respect filters in the 'My certificates' and 'Verify certificate' pages (#197).
|
||||
- Fixed reference to 'mod/certificate' capability.
|
||||
- Provided access to necessary web services for mobile functionality to the local_mobile plugin (#202).
|
||||
|
||||
### Changed
|
||||
|
||||
- Multiple UX improvements to both the browser and mobile views (#203).
|
||||
|
||||
## [3.4.3] - 2018-06-07
|
||||
### Fixed
|
||||
|
||||
- Hotfix to prevent misalignment of 'text' elements after last release (#196).
|
||||
|
||||
## [3.4.2] - 2018-06-06
|
||||
### Added
|
||||
- Mobile app support (#70).
|
||||
```
|
||||
This allows students to view the activity and download
|
||||
their certificate. It also allows teachers to view the
|
||||
list of issued certificates, with the ability to revoke
|
||||
any.
|
||||
|
||||
This is for the soon-to-be released Moodle Mobile v3.5.0
|
||||
(not to be confused with your Moodle site version) and
|
||||
will not work on Mobile versions earlier than this.
|
||||
|
||||
If you are running a Moodle site on version 3.4 or below
|
||||
you will need to install the local_mobile plugin in order
|
||||
for this to work.
|
||||
|
||||
If you are running a Moodle site on version 3.0 or below
|
||||
then you will need to upgrade.
|
||||
```
|
||||
- More font sizes (#148).
|
||||
- Added new download icon.
|
||||
```
|
||||
This was done because the core 'import' icon was mapped
|
||||
to the Font Awesome icon 'fa-level-up' which did not look
|
||||
appropriate. So, a new icon was added and that was mapped
|
||||
to the 'fa-download' icon.
|
||||
```
|
||||
### Fixed
|
||||
- No longer display the 'action' column and user picture URL when downloading the user report (#192).
|
||||
- Elements no longer ignore filters (#170).
|
||||
|
||||
## [3.4.1] - 2018-05-17
|
||||
### Added
|
||||
- GDPR Compliance (#189).
|
||||
|
|
674
LICENSE.md
Normal file
674
LICENSE.md
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -86,8 +86,8 @@ class restore_customcert_activity_task extends restore_activity_task {
|
|||
$rules[] = new restore_log_rule('customcert', 'add', 'view.php?id={course_module}', '{customcert}');
|
||||
$rules[] = new restore_log_rule('customcert', 'update', 'view.php?id={course_module}', '{customcert}');
|
||||
$rules[] = new restore_log_rule('customcert', 'view', 'view.php?id={course_module}', '{customcert}');
|
||||
$rules[] = new restore_log_rule('customcert', 'received', 'report.php?a={customcert}', '{customcert}');
|
||||
$rules[] = new restore_log_rule('customcert', 'view report', 'report.php?id={customcert}', '{customcert}');
|
||||
$rules[] = new restore_log_rule('customcert', 'received', 'view.php?id={course_module}', '{customcert}');
|
||||
$rules[] = new restore_log_rule('customcert', 'view report', 'view.php?id={course_module}', '{customcert}');
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
|
|
@ -102,23 +102,20 @@ class certificate {
|
|||
public static function get_fonts() {
|
||||
global $CFG;
|
||||
|
||||
// Array to store the available fonts.
|
||||
$options = array();
|
||||
require_once($CFG->libdir . '/pdflib.php');
|
||||
|
||||
// Location of fonts in Moodle.
|
||||
$fontdir = "$CFG->dirroot/lib/tcpdf/fonts";
|
||||
// Check that the directory exists.
|
||||
if (file_exists($fontdir)) {
|
||||
// Get directory contents.
|
||||
$fonts = new \DirectoryIterator($fontdir);
|
||||
// Loop through the font folder.
|
||||
foreach ($fonts as $font) {
|
||||
// If it is not a file, or either '.' or '..', or
|
||||
// the extension is not php, or we can not open file,
|
||||
// skip it.
|
||||
if (!$font->isFile() || $font->isDot() || ($font->getExtension() != 'php')) {
|
||||
continue;
|
||||
$arrfonts = [];
|
||||
$pdf = new \pdf();
|
||||
$fontfamilies = $pdf->get_font_families();
|
||||
foreach ($fontfamilies as $fontfamily => $fontstyles) {
|
||||
foreach ($fontstyles as $fontstyle) {
|
||||
$fontstyle = strtolower($fontstyle);
|
||||
if ($fontstyle == 'r') {
|
||||
$filenamewoextension = $fontfamily;
|
||||
} else {
|
||||
$filenamewoextension = $fontfamily . $fontstyle;
|
||||
}
|
||||
$fullpath = \TCPDF_FONTS::_getfontpath() . $filenamewoextension;
|
||||
// Set the name of the font to null, the include next should then set this
|
||||
// value, if it is not set then the file does not include the necessary data.
|
||||
$name = null;
|
||||
|
@ -127,25 +124,24 @@ class certificate {
|
|||
$displayname = null;
|
||||
// Some of the TCPDF files include files that are not present, so we have to
|
||||
// suppress warnings, this is the TCPDF libraries fault, grrr.
|
||||
@include("$fontdir/$font");
|
||||
@include($fullpath . '.php');
|
||||
// If no $name variable in file, skip it.
|
||||
if (is_null($name)) {
|
||||
continue;
|
||||
}
|
||||
// Remove the extension of the ".php" file that contains the font information.
|
||||
$filename = basename($font, ".php");
|
||||
// Check if there is no display name to use.
|
||||
if (is_null($displayname)) {
|
||||
// Format the font name, so "FontName-Style" becomes "Font Name - Style".
|
||||
$displayname = preg_replace("/([a-z])([A-Z])/", "$1 $2", $name);
|
||||
$displayname = preg_replace("/([a-zA-Z])-([a-zA-Z])/", "$1 - $2", $displayname);
|
||||
}
|
||||
$options[$filename] = $displayname;
|
||||
}
|
||||
ksort($options);
|
||||
}
|
||||
|
||||
return $options;
|
||||
$arrfonts[$filenamewoextension] = $displayname;
|
||||
}
|
||||
}
|
||||
ksort($arrfonts);
|
||||
|
||||
return $arrfonts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +151,7 @@ class certificate {
|
|||
// Array to store the sizes.
|
||||
$sizes = array();
|
||||
|
||||
for ($i = 1; $i <= 60; $i++) {
|
||||
for ($i = 1; $i <= 200; $i++) {
|
||||
$sizes[$i] = $i;
|
||||
}
|
||||
|
||||
|
@ -247,7 +243,7 @@ class certificate {
|
|||
* @param int $limitfrom
|
||||
* @param int $limitnum
|
||||
* @param string $sort
|
||||
* @return \stdClass the users
|
||||
* @return array the users
|
||||
*/
|
||||
public static function get_issues($customcertid, $groupmode, $cm, $limitfrom, $limitnum, $sort = '') {
|
||||
global $DB;
|
||||
|
@ -264,7 +260,8 @@ class certificate {
|
|||
$allparams = $conditionsparams + array('customcertid' => $customcertid);
|
||||
|
||||
// Return the issues.
|
||||
$ufields = \user_picture::fields('u');
|
||||
$extrafields = get_extra_user_fields(\context_module::instance($cm->id));
|
||||
$ufields = \user_picture::fields('u', $extrafields);
|
||||
$sql = "SELECT $ufields, ci.id as issueid, ci.code, ci.timecreated
|
||||
FROM {user} u
|
||||
INNER JOIN {customcert_issues} ci
|
||||
|
@ -421,6 +418,27 @@ class certificate {
|
|||
return $DB->get_records_sql($sql, array('userid' => $userid), $limitfrom, $limitnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a certificate to a user.
|
||||
*
|
||||
* @param int $certificateid The ID of the certificate
|
||||
* @param int $userid The ID of the user to issue the certificate to
|
||||
* @return int The ID of the issue
|
||||
*/
|
||||
public static function issue_certificate($certificateid, $userid) {
|
||||
global $DB;
|
||||
|
||||
$issue = new \stdClass();
|
||||
$issue->userid = $userid;
|
||||
$issue->customcertid = $certificateid;
|
||||
$issue->code = self::generate_code();
|
||||
$issue->emailed = 0;
|
||||
$issue->timecreated = time();
|
||||
|
||||
// Insert the record into the database.
|
||||
return $DB->insert_record('customcert_issues', $issue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a 10-digit code of random letters and numbers.
|
||||
*
|
||||
|
|
|
@ -80,18 +80,20 @@ class edit_form extends \moodleform {
|
|||
$this->add_customcert_page_elements($page);
|
||||
}
|
||||
|
||||
// Link to add another page.
|
||||
$addpagelink = new \moodle_url('/mod/customcert/edit.php',
|
||||
array(
|
||||
'tid' => $this->tid,
|
||||
'aid' => 1,
|
||||
'action' => 'addpage',
|
||||
'sesskey' => sesskey()
|
||||
)
|
||||
);
|
||||
$icon = $OUTPUT->pix_icon('t/switch_plus', get_string('addcertpage', 'customcert'));
|
||||
$addpagehtml = \html_writer::link($addpagelink, $icon . get_string('addcertpage', 'customcert'));
|
||||
$mform->addElement('html', \html_writer::tag('div', $addpagehtml, array('class' => 'addpage')));
|
||||
// Link to add another page, only display it when the template has been created.
|
||||
if (isset($this->_customdata['tid'])) {
|
||||
$addpagelink = new \moodle_url('/mod/customcert/edit.php',
|
||||
array(
|
||||
'tid' => $this->tid,
|
||||
'aid' => 1,
|
||||
'action' => 'addpage',
|
||||
'sesskey' => sesskey()
|
||||
)
|
||||
);
|
||||
$icon = $OUTPUT->pix_icon('t/switch_plus', get_string('addcertpage', 'customcert'));
|
||||
$addpagehtml = \html_writer::link($addpagelink, $icon . get_string('addcertpage', 'customcert'));
|
||||
$mform->addElement('html', \html_writer::tag('div', $addpagehtml, array('class' => 'addpage')));
|
||||
}
|
||||
|
||||
// Add the submit buttons.
|
||||
$group = array();
|
||||
|
|
|
@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die();
|
|||
/**
|
||||
* Class element
|
||||
*
|
||||
* All customercert element plugins are based on this class.
|
||||
* All customcert element plugins are based on this class.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2013 Mark Nelson <markn@moodle.com>
|
||||
|
@ -352,6 +352,16 @@ abstract class element {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines if an element plugin can be added to a certificate.
|
||||
* Can be overridden if an element plugin wants to take over the control.
|
||||
*
|
||||
* @return bool returns true if the element can be added, false otherwise
|
||||
*/
|
||||
public static function can_add() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles rendering the element on the pdf.
|
||||
*
|
||||
|
|
|
@ -383,6 +383,27 @@ class element_helper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the context for this element.
|
||||
*
|
||||
* @param int $elementid The element id
|
||||
* @return \context The context
|
||||
*/
|
||||
public static function get_context(int $elementid) : \context {
|
||||
global $DB;
|
||||
|
||||
$sql = "SELECT ct.contextid
|
||||
FROM {customcert_templates} ct
|
||||
INNER JOIN {customcert_pages} cp
|
||||
ON ct.id = cp.templateid
|
||||
INNER JOIN {customcert_elements} ce
|
||||
ON cp.id = ce.pageid
|
||||
WHERE ce.id = :elementid";
|
||||
$contextid = $DB->get_field_sql($sql, array('elementid' => $elementid), MUST_EXIST);
|
||||
|
||||
return \context::instance_by_id($contextid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of possible elements to add.
|
||||
*
|
||||
|
@ -412,8 +433,11 @@ class element_helper {
|
|||
$classname = '\\customcertelement_' . $foldername . '\\element';
|
||||
// Ensure the necessary class exists.
|
||||
if (class_exists($classname)) {
|
||||
$component = "customcertelement_{$foldername}";
|
||||
$options[$foldername] = get_string('pluginname', $component);
|
||||
// Additionally, check if the user is allowed to add the element at all.
|
||||
if ($classname::can_add()) {
|
||||
$component = "customcertelement_{$foldername}";
|
||||
$options[$foldername] = get_string('pluginname', $component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -510,18 +534,12 @@ class element_helper {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Define how many decimals to display.
|
||||
$decimals = 2;
|
||||
if ($gradeformat == GRADE_DISPLAY_TYPE_PERCENTAGE) {
|
||||
$decimals = 0;
|
||||
}
|
||||
|
||||
$grade = new \grade_grade(array('itemid' => $courseitem->id, 'userid' => $userid));
|
||||
|
||||
return new grade_information(
|
||||
$courseitem->get_name(),
|
||||
$grade->finalgrade,
|
||||
grade_format_gradevalue($grade->finalgrade, $courseitem, true, $gradeformat, $decimals),
|
||||
grade_format_gradevalue($grade->finalgrade, $courseitem, true, $gradeformat),
|
||||
$grade->get_dategraded()
|
||||
);
|
||||
}
|
||||
|
@ -545,37 +563,44 @@ class element_helper {
|
|||
return false;
|
||||
}
|
||||
|
||||
$gradeitem = grade_get_grades($cm->course, 'mod', $module->name, $cm->instance, $userid);
|
||||
$params = [
|
||||
'itemtype' => 'mod',
|
||||
'itemmodule' => $module->name,
|
||||
'iteminstance' => $cm->instance,
|
||||
'courseid' => $cm->course,
|
||||
'itemnumber' => 0
|
||||
];
|
||||
$gradeitem = \grade_item::fetch($params);
|
||||
|
||||
if (empty($gradeitem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Define how many decimals to display.
|
||||
$decimals = 2;
|
||||
if ($gradeformat == GRADE_DISPLAY_TYPE_PERCENTAGE) {
|
||||
$decimals = 0;
|
||||
$grade = grade_get_grades(
|
||||
$cm->course,
|
||||
'mod',
|
||||
$module->name,
|
||||
$cm->instance,
|
||||
$userid
|
||||
);
|
||||
|
||||
if (!isset($grade->items[0]->grades[$userid])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$item = new \grade_item();
|
||||
$item->gradetype = GRADE_TYPE_VALUE;
|
||||
$item->courseid = $cm->course;
|
||||
$itemproperties = reset($gradeitem->items);
|
||||
foreach ($itemproperties as $key => $value) {
|
||||
$item->$key = $value;
|
||||
}
|
||||
|
||||
$objgrade = $item->grades[$userid];
|
||||
$gradebookgrade = $grade->items[0]->grades[$userid];
|
||||
|
||||
$dategraded = null;
|
||||
if (!empty($objgrade->dategraded)) {
|
||||
$dategraded = $objgrade->dategraded;
|
||||
if (!empty($gradebookgrade->dategraded)) {
|
||||
$dategraded = $gradebookgrade->dategraded;
|
||||
}
|
||||
|
||||
$displaygrade = grade_format_gradevalue($gradebookgrade->grade, $gradeitem, true, $gradeformat);
|
||||
|
||||
return new grade_information(
|
||||
$item->name,
|
||||
$objgrade->grade,
|
||||
grade_format_gradevalue($objgrade->grade, $item, true, $gradeformat, $decimals),
|
||||
$gradeitem->get_name(),
|
||||
$gradebookgrade->grade,
|
||||
$displaygrade,
|
||||
$dategraded
|
||||
);
|
||||
}
|
||||
|
@ -593,18 +618,12 @@ class element_helper {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Define how many decimals to display.
|
||||
$decimals = 2;
|
||||
if ($gradeformat == GRADE_DISPLAY_TYPE_PERCENTAGE) {
|
||||
$decimals = 0;
|
||||
}
|
||||
|
||||
$grade = new \grade_grade(array('itemid' => $gradeitem->id, 'userid' => $userid));
|
||||
|
||||
return new grade_information(
|
||||
$gradeitem->get_name(),
|
||||
$grade->finalgrade,
|
||||
grade_format_gradevalue($grade->finalgrade, $gradeitem, true, $gradeformat, $decimals),
|
||||
grade_format_gradevalue($grade->finalgrade, $gradeitem, true, $gradeformat),
|
||||
$grade->get_dategraded()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -174,4 +174,57 @@ class external extends \external_api {
|
|||
public static function get_element_html_returns() {
|
||||
return new \external_value(PARAM_RAW, 'The HTML');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delete_issue() parameters.
|
||||
*
|
||||
* @return \external_function_parameters
|
||||
*/
|
||||
public static function delete_issue_parameters() {
|
||||
return new \external_function_parameters(
|
||||
array(
|
||||
'certificateid' => new \external_value(PARAM_INT, 'The certificate id'),
|
||||
'issueid' => new \external_value(PARAM_INT, 'The issue id'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles deleting a customcert issue.
|
||||
*
|
||||
* @param int $certificateid The certificate id.
|
||||
* @param int $issueid The issue id.
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete_issue($certificateid, $issueid) {
|
||||
global $DB;
|
||||
|
||||
$params = [
|
||||
'certificateid' => $certificateid,
|
||||
'issueid' => $issueid
|
||||
];
|
||||
self::validate_parameters(self::delete_issue_parameters(), $params);
|
||||
|
||||
$certificate = $DB->get_record('customcert', ['id' => $certificateid], '*', MUST_EXIST);
|
||||
$issue = $DB->get_record('customcert_issues', ['id' => $issueid, 'customcertid' => $certificateid], '*', MUST_EXIST);
|
||||
|
||||
$cm = get_coursemodule_from_instance('customcert', $certificate->id, 0, false, MUST_EXIST);
|
||||
|
||||
// Make sure the user has the required capabilities.
|
||||
$context = \context_module::instance($cm->id);
|
||||
self::validate_context($context);
|
||||
require_capability('mod/customcert:manage', $context);
|
||||
|
||||
// Delete the issue.
|
||||
return $DB->delete_records('customcert_issues', ['id' => $issue->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delete_issue result value.
|
||||
*
|
||||
* @return \external_value
|
||||
*/
|
||||
public static function delete_issue_returns() {
|
||||
return new \external_value(PARAM_BOOL, 'True if successful, false otherwise');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,10 @@ class my_certificates_table extends \table_sql {
|
|||
* @return string
|
||||
*/
|
||||
public function col_name($certificate) {
|
||||
return $certificate->name;
|
||||
$cm = get_coursemodule_from_instance('customcert', $certificate->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
|
||||
return format_string($certificate->name, true, ['context' => $context]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,7 +107,10 @@ class my_certificates_table extends \table_sql {
|
|||
* @return string
|
||||
*/
|
||||
public function col_coursename($certificate) {
|
||||
return $certificate->coursename;
|
||||
$cm = get_coursemodule_from_instance('customcert', $certificate->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
|
||||
return format_string($certificate->coursename, true, ['context' => $context]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,7 +142,7 @@ class my_certificates_table extends \table_sql {
|
|||
public function col_download($certificate) {
|
||||
global $OUTPUT;
|
||||
|
||||
$icon = new \pix_icon('i/import', get_string('download'));
|
||||
$icon = new \pix_icon('download', get_string('download'), 'customcert');
|
||||
$link = new \moodle_url('/mod/customcert/my_certificates.php',
|
||||
array('userid' => $this->userid,
|
||||
'certificateid' => $certificate->id,
|
||||
|
|
|
@ -102,12 +102,14 @@ class email_certificate implements \renderable, \templatable {
|
|||
if ($this->isstudent) {
|
||||
$data->emailgreeting = get_string('emailstudentgreeting', 'customcert', $this->userfullname);
|
||||
$data->emailbody = get_string('emailstudentbody', 'customcert', $info);
|
||||
$data->emailbodyplaintext = get_string('emailstudentbodyplaintext', 'customcert', $info);
|
||||
$data->emailcertificatelink = new \moodle_url('/mod/customcert/view.php', array('id' => $this->cmid));
|
||||
$data->emailcertificatetext = get_string('emailstudentcertificatelinktext', 'customcert');
|
||||
} else {
|
||||
$data->emailgreeting = get_string('emailnonstudentgreeting', 'customcert');
|
||||
$data->emailbody = get_string('emailnonstudentbody', 'customcert', $info);
|
||||
$data->emailcertificatelink = new \moodle_url('/mod/customcert/report.php', array('id' => $this->cmid));
|
||||
$data->emailbodyplaintext = get_string('emailnonstudentbodyplaintext', 'customcert', $info);
|
||||
$data->emailcertificatelink = new \moodle_url('/mod/customcert/view.php', array('id' => $this->cmid));
|
||||
$data->emailcertificatetext = get_string('emailnonstudentcertificatelinktext', 'customcert');
|
||||
}
|
||||
|
||||
|
|
209
classes/output/mobile.php
Normal file
209
classes/output/mobile.php
Normal file
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains the mobile output class for the custom certificate.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2018 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_customcert\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Mobile output class for the custom certificate.
|
||||
*
|
||||
* @copyright 2018 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mobile {
|
||||
|
||||
/**
|
||||
* Returns the initial page when viewing the activity for the mobile app.
|
||||
*
|
||||
* @param array $args Arguments from tool_mobile_get_content WS
|
||||
* @return array HTML, javascript and other data
|
||||
*/
|
||||
public static function mobile_view_activity($args) {
|
||||
global $OUTPUT, $DB, $USER;
|
||||
|
||||
$args = (object) $args;
|
||||
|
||||
$cmid = $args->cmid;
|
||||
$groupid = empty($args->group) ? 0 : $args->group; // By default, group 0.
|
||||
|
||||
// Capabilities check.
|
||||
$cm = get_coursemodule_from_id('customcert', $cmid);
|
||||
$context = \context_module::instance($cm->id);
|
||||
self::require_capability($cm, $context, 'mod/customcert:view');
|
||||
|
||||
// Set some variables we are going to be using.
|
||||
$certificate = $DB->get_record('customcert', ['id' => $cm->instance], '*', MUST_EXIST);
|
||||
$certificate->name = format_string($certificate->name);
|
||||
list($certificate->intro, $certificate->introformat) = external_format_text($certificate->intro,
|
||||
$certificate->introformat, $context->id, 'mod_customcert', 'intro');
|
||||
|
||||
// Get any issues this person may have.
|
||||
$issue = false;
|
||||
if ($issues = $DB->get_records('customcert_issues', ['userid' => $USER->id, 'customcertid' => $certificate->id],
|
||||
'timecreated DESC')) {
|
||||
$issue = reset($issues);
|
||||
}
|
||||
|
||||
$requiredtimemet = true;
|
||||
$canmanage = has_capability('mod/customcert:manage', $context);
|
||||
if ($certificate->requiredtime && !$canmanage) {
|
||||
if (\mod_customcert\certificate::get_course_time($certificate->course) < ($certificate->requiredtime * 60)) {
|
||||
$requiredtimemet = false;
|
||||
}
|
||||
}
|
||||
|
||||
$fileurl = "";
|
||||
if ($requiredtimemet) {
|
||||
$fileurl = new \moodle_url('/mod/customcert/mobile/pluginfile.php', ['certificateid' => $certificate->id,
|
||||
'userid' => $USER->id]);
|
||||
$fileurl = $fileurl->out(true);
|
||||
}
|
||||
|
||||
$showreport = false;
|
||||
$groups = [];
|
||||
$recipients = [];
|
||||
if (has_capability('mod/customcert:viewreport', $context)) {
|
||||
$showreport = true;
|
||||
|
||||
// Get the groups (if any) to display - also sets active group.
|
||||
$groups = self::get_groups($cm, $groupid, $USER->id);
|
||||
$groupmode = groups_get_activity_groupmode($cm);
|
||||
if (has_capability('moodle/site:accessallgroups', $context)) {
|
||||
$groupmode = 'aag';
|
||||
}
|
||||
|
||||
$recipients = \mod_customcert\certificate::get_issues($certificate->id, $groupmode, $cm, 0, 0);
|
||||
foreach ($recipients as $recipient) {
|
||||
$recipient->displayname = fullname($recipient);
|
||||
$recipient->fileurl = new \moodle_url('/mod/customcert/mobile/pluginfile.php', ['certificateid' => $certificate->id,
|
||||
'userid' => $recipient->id]);
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'certificate' => $certificate,
|
||||
'cmid' => $cm->id,
|
||||
'issue' => $issue,
|
||||
'showgroups' => !empty($groups),
|
||||
'groups' => array_values($groups),
|
||||
'canmanage' => $canmanage,
|
||||
'requiredtimemet' => $requiredtimemet,
|
||||
'fileurl' => $fileurl,
|
||||
'showreport' => $showreport,
|
||||
'hasrecipients' => !empty($recipients),
|
||||
'recipients' => array_values($recipients),
|
||||
'currenttimestamp' => time()
|
||||
];
|
||||
|
||||
return [
|
||||
'templates' => [
|
||||
[
|
||||
'id' => 'main',
|
||||
'html' => $OUTPUT->render_from_template('mod_customcert/mobile_view_activity_page', $data),
|
||||
],
|
||||
],
|
||||
'javascript' => '',
|
||||
'otherdata' => ''
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of groups to be displayed (if applicable) for the activity.
|
||||
*
|
||||
* The groups API is a mess hence the hackiness.
|
||||
*
|
||||
* @param \stdClass $cm The course module
|
||||
* @param int $groupid The group id
|
||||
* @param int $userid The user id
|
||||
* @return array The array of groups, may be empty.
|
||||
*/
|
||||
protected static function get_groups($cm, $groupid, $userid) {
|
||||
$arrgroups = [];
|
||||
if ($groupmode = groups_get_activity_groupmode($cm)) {
|
||||
if ($groups = groups_get_activity_allowed_groups($cm, $userid)) {
|
||||
$context = \context_module::instance($cm->id);
|
||||
if ($groupmode == VISIBLEGROUPS || has_capability('moodle/site:accessallgroups', $context)) {
|
||||
$allparticipants = new \stdClass();
|
||||
$allparticipants->id = 0;
|
||||
$allparticipants->name = get_string('allparticipants');
|
||||
$allparticipants->selected = $groupid === 0;
|
||||
$arrgroups[0] = $allparticipants;
|
||||
}
|
||||
self::update_active_group($groupmode, $groupid, $groups, $cm);
|
||||
// Detect which group is selected.
|
||||
foreach ($groups as $gid => $group) {
|
||||
$group->selected = $gid == $groupid;
|
||||
$arrgroups[] = $group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $arrgroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the active group in the session.
|
||||
*
|
||||
* This is a hack. We can't call groups_get_activity_group to update the active group as it relies
|
||||
* on optional_param('group' .. which we won't have when using the mobile app.
|
||||
*
|
||||
* @param int $groupmode The group mode we are in, eg. NOGROUPS, VISIBLEGROUPS
|
||||
* @param int $groupid The id of the group that has been selected
|
||||
* @param array $allowedgroups The allowed groups this user can access
|
||||
* @param \stdClass $cm The course module
|
||||
*/
|
||||
private static function update_active_group($groupmode, $groupid, $allowedgroups, $cm) {
|
||||
global $SESSION;
|
||||
|
||||
$context = \context_module::instance($cm->id);
|
||||
|
||||
if (has_capability('moodle/site:accessallgroups', $context)) {
|
||||
$groupmode = 'aag';
|
||||
}
|
||||
|
||||
if ($groupid == 0) {
|
||||
// The groups are only all visible in VISIBLEGROUPS mode or if the user can access all groups.
|
||||
if ($groupmode == VISIBLEGROUPS || has_capability('moodle/site:accessallgroups', $context)) {
|
||||
$SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = 0;
|
||||
}
|
||||
} else {
|
||||
if ($allowedgroups && array_key_exists($groupid, $allowedgroups)) {
|
||||
$SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = $groupid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms the user is logged in and has the specified capability.
|
||||
*
|
||||
* @param \stdClass $cm
|
||||
* @param \context $context
|
||||
* @param string $cap
|
||||
*/
|
||||
protected static function require_capability(\stdClass $cm, \context $context, string $cap) {
|
||||
require_login($cm->course, false, $cm, true, true);
|
||||
require_capability($cap, $context);
|
||||
}
|
||||
}
|
|
@ -69,12 +69,15 @@ class verify_certificate_result implements templatable, renderable {
|
|||
* @param \stdClass $result
|
||||
*/
|
||||
public function __construct($result) {
|
||||
$cm = get_coursemodule_from_instance('customcert', $result->certificateid);
|
||||
$context = \context_module::instance($cm->id);
|
||||
|
||||
$this->userprofileurl = new \moodle_url('/user/view.php', array('id' => $result->userid,
|
||||
'course' => $result->courseid));
|
||||
$this->userfullname = fullname($result);
|
||||
$this->courseurl = new \moodle_url('/course/view.php', array('id' => $result->courseid));
|
||||
$this->coursefullname = $result->coursefullname;
|
||||
$this->certificatename = $result->certificatename;
|
||||
$this->coursefullname = format_string($result->coursefullname, true, ['context' => $context]);
|
||||
$this->certificatename = format_string($result->certificatename, true, ['context' => $context]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,4 +44,44 @@ class customcertelement extends base {
|
|||
public function is_uninstall_allowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads plugin settings to the settings tree.
|
||||
*
|
||||
* @param \part_of_admin_tree $adminroot
|
||||
* @param string $parentnodename
|
||||
* @param bool $hassiteconfig whether the current user has moodle/site:config capability
|
||||
*/
|
||||
public function load_settings(\part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) {
|
||||
global $CFG, $USER, $DB, $OUTPUT, $PAGE;
|
||||
$ADMIN = $adminroot;
|
||||
$plugininfo = $this;
|
||||
|
||||
if (!$this->is_installed_and_upgraded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$hassiteconfig or !file_exists($this->full_path('settings.php'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$section = $this->get_settings_section_name();
|
||||
$settings = new \admin_settingpage($section, $this->displayname, 'moodle/site:config', false);
|
||||
|
||||
include($this->full_path('settings.php'));
|
||||
$ADMIN->add($parentnodename, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings section name.
|
||||
*
|
||||
* @return null|string the settings section name.
|
||||
*/
|
||||
public function get_settings_section_name() {
|
||||
if (file_exists($this->full_path('settings.php'))) {
|
||||
return 'customcertelement_' . $this->name;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,11 @@ namespace mod_customcert\privacy;
|
|||
|
||||
use core_privacy\local\metadata\collection;
|
||||
use core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\approved_userlist;
|
||||
use core_privacy\local\request\contextlist;
|
||||
use core_privacy\local\request\helper;
|
||||
use core_privacy\local\request\transform;
|
||||
use core_privacy\local\request\userlist;
|
||||
use core_privacy\local\request\writer;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
@ -40,7 +42,8 @@ defined('MOODLE_INTERNAL') || die();
|
|||
*/
|
||||
class provider implements
|
||||
\core_privacy\local\metadata\provider,
|
||||
\core_privacy\local\request\plugin\provider {
|
||||
\core_privacy\local\request\plugin\provider,
|
||||
\core_privacy\local\request\core_userlist_provider {
|
||||
|
||||
/**
|
||||
* Return the fields which contain personal data.
|
||||
|
@ -96,6 +99,37 @@ class provider implements
|
|||
return $contextlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of users who have data within a context.
|
||||
*
|
||||
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
|
||||
*/
|
||||
public static function get_users_in_context(userlist $userlist) {
|
||||
$context = $userlist->get_context();
|
||||
|
||||
if (!$context instanceof \context_module) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch all users who have a custom certificate.
|
||||
$sql = "SELECT customcertissues.userid
|
||||
FROM {course_modules} cm
|
||||
JOIN {modules} m
|
||||
ON m.id = cm.module AND m.name = :modname
|
||||
JOIN {customcert} customcert
|
||||
ON customcert.id = cm.instance
|
||||
JOIN {customcert_issues} customcertissues
|
||||
ON customcertissues.customcertid = customcert.id
|
||||
WHERE cm.id = :cmid";
|
||||
|
||||
$params = [
|
||||
'cmid' => $context->instanceid,
|
||||
'modname' => 'customcert',
|
||||
];
|
||||
|
||||
$userlist->add_from_sql('userid', $sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export personal data for the given approved_contextlist. User and context information is contained within the contextlist.
|
||||
*
|
||||
|
@ -182,6 +216,33 @@ class provider implements
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple users within a single context.
|
||||
*
|
||||
* @param approved_userlist $userlist The approved context and user information to delete information for.
|
||||
*/
|
||||
public static function delete_data_for_users(approved_userlist $userlist) {
|
||||
global $DB;
|
||||
|
||||
$context = $userlist->get_context();
|
||||
if (!$context instanceof \context_module) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cm = get_coursemodule_from_id('customcert', $context->instanceid);
|
||||
if (!$cm) {
|
||||
// Only customcert module will be handled.
|
||||
return;
|
||||
}
|
||||
|
||||
$userids = $userlist->get_userids();
|
||||
list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
|
||||
|
||||
$select = "customcertid = :customcertid AND userid $usersql";
|
||||
$params = ['customcertid' => $cm->instance] + $userparams;
|
||||
$DB->delete_records_select('customcert_issues', $select, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of Customcert IDs mapped to their course module ID.
|
||||
*
|
||||
|
|
|
@ -65,16 +65,22 @@ class report_table extends \table_sql {
|
|||
public function __construct($customcertid, $cm, $groupmode, $download = null) {
|
||||
parent::__construct('mod_customcert_report_table');
|
||||
|
||||
$columns = array(
|
||||
'fullname',
|
||||
'timecreated',
|
||||
'code'
|
||||
);
|
||||
$headers = array(
|
||||
get_string('fullname'),
|
||||
get_string('receiveddate', 'customcert'),
|
||||
get_string('code', 'customcert')
|
||||
);
|
||||
$context = \context_module::instance($cm->id);
|
||||
$extrafields = get_extra_user_fields($context);
|
||||
|
||||
$columns = [];
|
||||
$columns[] = 'fullname';
|
||||
foreach ($extrafields as $extrafield) {
|
||||
$columns[] = $extrafield;
|
||||
}
|
||||
$columns[] = 'timecreated';
|
||||
|
||||
$headers = [];
|
||||
$headers[] = get_string('fullname');
|
||||
foreach ($extrafields as $extrafield) {
|
||||
$headers[] = get_user_field_name($extrafield);
|
||||
}
|
||||
$headers[] = get_string('receiveddate', 'customcert');
|
||||
|
||||
// Check if we were passed a filename, which means we want to download it.
|
||||
if ($download) {
|
||||
|
@ -86,7 +92,7 @@ class report_table extends \table_sql {
|
|||
$headers[] = get_string('file');
|
||||
}
|
||||
|
||||
if (has_capability('mod/customcert:manage', \context_module::instance($cm->id))) {
|
||||
if (!$this->is_downloading() && has_capability('mod/customcert:manage', $context)) {
|
||||
$columns[] = 'actions';
|
||||
$headers[] = '';
|
||||
}
|
||||
|
@ -95,7 +101,6 @@ class report_table extends \table_sql {
|
|||
$this->define_headers($headers);
|
||||
$this->collapsible(false);
|
||||
$this->sortable(true);
|
||||
$this->no_sorting('code');
|
||||
$this->no_sorting('download');
|
||||
$this->is_downloadable(true);
|
||||
|
||||
|
@ -113,7 +118,11 @@ class report_table extends \table_sql {
|
|||
public function col_fullname($user) {
|
||||
global $OUTPUT;
|
||||
|
||||
return $OUTPUT->user_picture($user) . ' ' . fullname($user);
|
||||
if (!$this->is_downloading()) {
|
||||
return $OUTPUT->user_picture($user) . ' ' . fullname($user);
|
||||
} else {
|
||||
return fullname($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,16 +135,6 @@ class report_table extends \table_sql {
|
|||
return userdate($user->timecreated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the code column.
|
||||
*
|
||||
* @param \stdClass $user
|
||||
* @return string
|
||||
*/
|
||||
public function col_code($user) {
|
||||
return $user->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the download column.
|
||||
*
|
||||
|
@ -145,11 +144,13 @@ class report_table extends \table_sql {
|
|||
public function col_download($user) {
|
||||
global $OUTPUT;
|
||||
|
||||
$icon = new \pix_icon('i/import', get_string('download'));
|
||||
$link = new \moodle_url('/mod/customcert/report.php',
|
||||
array('id' => $this->cm->id,
|
||||
'downloadcert' => '1',
|
||||
'userid' => $user->id));
|
||||
$icon = new \pix_icon('download', get_string('download'), 'customcert');
|
||||
$link = new \moodle_url('/mod/customcert/view.php',
|
||||
[
|
||||
'id' => $this->cm->id,
|
||||
'downloadissue' => $user->id
|
||||
]
|
||||
);
|
||||
|
||||
return $OUTPUT->action_link($link, '', null, null, $icon);
|
||||
}
|
||||
|
@ -164,7 +165,7 @@ class report_table extends \table_sql {
|
|||
global $OUTPUT;
|
||||
|
||||
$icon = new \pix_icon('i/delete', get_string('delete'));
|
||||
$link = new \moodle_url('/mod/customcert/report.php',
|
||||
$link = new \moodle_url('/mod/customcert/view.php',
|
||||
[
|
||||
'id' => $this->cm->id,
|
||||
'deleteissue' => $user->issueid,
|
||||
|
|
|
@ -50,6 +50,7 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
global $DB, $PAGE;
|
||||
|
||||
// Get all the certificates that have requested someone get emailed.
|
||||
$emailotherslengthsql = $DB->sql_length('c.emailothers');
|
||||
$sql = "SELECT c.*, ct.id as templateid, ct.name as templatename, ct.contextid, co.id as courseid,
|
||||
co.fullname as coursefullname, co.shortname as courseshortname
|
||||
FROM {customcert} c
|
||||
|
@ -59,179 +60,175 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
ON c.course = co.id
|
||||
WHERE (c.emailstudents = :emailstudents
|
||||
OR c.emailteachers = :emailteachers
|
||||
OR c.emailothers != '')";
|
||||
if ($customcerts = $DB->get_records_sql($sql, array('emailstudents' => 1, 'emailteachers' => 1))) {
|
||||
// The renderers used for sending emails.
|
||||
$htmlrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'htmlemail');
|
||||
$textrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'textemail');
|
||||
foreach ($customcerts as $customcert) {
|
||||
// Get the context.
|
||||
$context = \context::instance_by_id($customcert->contextid);
|
||||
OR $emailotherslengthsql >= 3)";
|
||||
if (!$customcerts = $DB->get_records_sql($sql, array('emailstudents' => 1, 'emailteachers' => 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the person we are going to send this email on behalf of.
|
||||
// Look through the teachers.
|
||||
if ($teachers = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC',
|
||||
'', '', '', '', false, true)) {
|
||||
$teachers = sort_by_roleassignment_authority($teachers, $context);
|
||||
$userfrom = reset($teachers);
|
||||
} else { // Ok, no teachers, use administrator name.
|
||||
$userfrom = get_admin();
|
||||
// The renderers used for sending emails.
|
||||
$htmlrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'htmlemail');
|
||||
$textrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'textemail');
|
||||
foreach ($customcerts as $customcert) {
|
||||
// Get the context.
|
||||
$context = \context::instance_by_id($customcert->contextid);
|
||||
|
||||
// Get the person we are going to send this email on behalf of.
|
||||
// Look through the teachers.
|
||||
if ($teachers = get_enrolled_users($context, 'moodle/course:update')) {
|
||||
$teachers = sort_by_roleassignment_authority($teachers, $context);
|
||||
$userfrom = reset($teachers);
|
||||
} else { // Ok, no teachers, use administrator name.
|
||||
$userfrom = get_admin();
|
||||
}
|
||||
|
||||
$courseshortname = format_string($customcert->courseshortname, true, array('context' => $context));
|
||||
$coursefullname = format_string($customcert->coursefullname, true, array('context' => $context));
|
||||
$certificatename = format_string($customcert->name, true, array('context' => $context));
|
||||
|
||||
// Used to create the email subject.
|
||||
$info = new \stdClass;
|
||||
$info->coursename = $courseshortname; // Added for BC, so users who have edited the string don't lose this value.
|
||||
$info->courseshortname = $courseshortname;
|
||||
$info->coursefullname = $coursefullname;
|
||||
$info->certificatename = $certificatename;
|
||||
|
||||
// Get a list of all the issues.
|
||||
$userfields = get_all_user_name_fields(true, 'u');
|
||||
$sql = "SELECT u.id, u.username, $userfields, u.email, ci.id as issueid, ci.emailed
|
||||
FROM {customcert_issues} ci
|
||||
JOIN {user} u
|
||||
ON ci.userid = u.id
|
||||
WHERE ci.customcertid = :customcertid";
|
||||
$issuedusers = $DB->get_records_sql($sql, array('customcertid' => $customcert->id));
|
||||
|
||||
// Now, get a list of users who can access the certificate but have not yet.
|
||||
$enrolledusers = get_enrolled_users(\context_course::instance($customcert->courseid), 'mod/customcert:view');
|
||||
foreach ($enrolledusers as $enroluser) {
|
||||
// Check if the user has already been issued.
|
||||
if (in_array($enroluser->id, array_keys((array) $issuedusers))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$courseshortname = format_string($customcert->courseshortname, true, array('context' => $context));
|
||||
$coursefullname = format_string($customcert->coursefullname, true, array('context' => $context));
|
||||
$certificatename = format_string($customcert->name, true, array('context' => $context));
|
||||
|
||||
// Used to create the email subject.
|
||||
$info = new \stdClass;
|
||||
$info->coursename = $courseshortname; // Added for BC, so users who have edited the string don't lose this value.
|
||||
$info->courseshortname = $courseshortname;
|
||||
$info->coursefullname = $coursefullname;
|
||||
$info->certificatename = $certificatename;
|
||||
|
||||
// Get a list of all the issues.
|
||||
$userfields = get_all_user_name_fields(true, 'u');
|
||||
$sql = "SELECT u.id, u.username, $userfields, u.email, ci.id as issueid, ci.emailed
|
||||
FROM {customcert_issues} ci
|
||||
JOIN {user} u
|
||||
ON ci.userid = u.id
|
||||
WHERE ci.customcertid = :customcertid";
|
||||
$issuedusers = $DB->get_records_sql($sql, array('customcertid' => $customcert->id));
|
||||
|
||||
// Now, get a list of users who can access the certificate but have not yet.
|
||||
$enrolledusers = get_enrolled_users(\context_course::instance($customcert->courseid), 'mod/customcert:view');
|
||||
foreach ($enrolledusers as $enroluser) {
|
||||
// Check if the user has already been issued.
|
||||
if (in_array($enroluser->id, array_keys((array) $issuedusers))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now check if the certificate is not visible to the current user.
|
||||
$cm = get_fast_modinfo($customcert->courseid, $enroluser->id)->instances['customcert'][$customcert->id];
|
||||
if (!$cm->uservisible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't want to email those with the capability to manage the certificate.
|
||||
if (has_capability('mod/customcert:manage', $context, $enroluser->id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check that they have passed the required time.
|
||||
if (!empty($customcert->requiredtime)) {
|
||||
if (\mod_customcert\certificate::get_course_time($customcert->courseid,
|
||||
$enroluser->id) < ($customcert->requiredtime * 60)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the cert hasn't already been issued, e.g via the UI (view.php) - a race condition.
|
||||
$issueid = $DB->get_field('customcert_issues', 'id',
|
||||
array('userid' => $enroluser->id, 'customcertid' => $customcert->id));
|
||||
if (empty($issueid)) {
|
||||
// Ok, issue them the certificate.
|
||||
$customcertissue = new \stdClass();
|
||||
$customcertissue->customcertid = $customcert->id;
|
||||
$customcertissue->userid = $enroluser->id;
|
||||
$customcertissue->code = \mod_customcert\certificate::generate_code();
|
||||
$customcertissue->emailed = 0;
|
||||
$customcertissue->timecreated = time();
|
||||
|
||||
// Insert the record into the database.
|
||||
$issueid = $DB->insert_record('customcert_issues', $customcertissue);
|
||||
}
|
||||
|
||||
// Add them to the array so we email them.
|
||||
$enroluser->issueid = $issueid;
|
||||
$enroluser->emailed = 0;
|
||||
$issuedusers[] = $enroluser;
|
||||
// Now check if the certificate is not visible to the current user.
|
||||
$cm = get_fast_modinfo($customcert->courseid, $enroluser->id)->instances['customcert'][$customcert->id];
|
||||
if (!$cm->uservisible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove all the users who have already been emailed.
|
||||
foreach ($issuedusers as $key => $issueduser) {
|
||||
if ($issueduser->emailed) {
|
||||
unset($issuedusers[$key]);
|
||||
// Don't want to email those with the capability to manage the certificate.
|
||||
if (has_capability('mod/customcert:manage', $context, $enroluser->id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check that they have passed the required time.
|
||||
if (!empty($customcert->requiredtime)) {
|
||||
if (\mod_customcert\certificate::get_course_time($customcert->courseid,
|
||||
$enroluser->id) < ($customcert->requiredtime * 60)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Now, email the people we need to.
|
||||
if ($issuedusers) {
|
||||
foreach ($issuedusers as $user) {
|
||||
$userfullname = fullname($user);
|
||||
// Ensure the cert hasn't already been issued, e.g via the UI (view.php) - a race condition.
|
||||
$issueid = $DB->get_field('customcert_issues', 'id',
|
||||
array('userid' => $enroluser->id, 'customcertid' => $customcert->id));
|
||||
if (empty($issueid)) {
|
||||
// Ok, issue them the certificate.
|
||||
$issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $enroluser->id);
|
||||
}
|
||||
|
||||
// Create a directory to store the PDF we will be sending.
|
||||
$tempdir = make_temp_directory('certificate/attachment');
|
||||
if (!$tempdir) {
|
||||
return false;
|
||||
}
|
||||
// Add them to the array so we email them.
|
||||
$enroluser->issueid = $issueid;
|
||||
$enroluser->emailed = 0;
|
||||
$issuedusers[] = $enroluser;
|
||||
}
|
||||
|
||||
// Now, get the PDF.
|
||||
$template = new \stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = $customcert->templatename;
|
||||
$template->contextid = $customcert->contextid;
|
||||
$template = new \mod_customcert\template($template);
|
||||
$filecontents = $template->generate_pdf(false, $user->id, true);
|
||||
// Remove all the users who have already been emailed.
|
||||
foreach ($issuedusers as $key => $issueduser) {
|
||||
if ($issueduser->emailed) {
|
||||
unset($issuedusers[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the name of the file we are going to send.
|
||||
$filename = $courseshortname . '_' . $certificatename;
|
||||
$filename = \core_text::entities_to_utf8($filename);
|
||||
$filename = strip_tags($filename);
|
||||
$filename = rtrim($filename, '.');
|
||||
$filename = str_replace('&', '_', $filename) . '.pdf';
|
||||
// If there are no users to email we can return early.
|
||||
if (!$issuedusers) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the file we will be sending.
|
||||
$tempfile = $tempdir . '/' . md5(microtime() . $user->id) . '.pdf';
|
||||
file_put_contents($tempfile, $filecontents);
|
||||
// Create a directory to store the PDF we will be sending.
|
||||
$tempdir = make_temp_directory('certificate/attachment');
|
||||
if (!$tempdir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($customcert->emailstudents) {
|
||||
$renderable = new \mod_customcert\output\email_certificate(true, $userfullname, $courseshortname,
|
||||
$coursefullname, $certificatename, $customcert->contextid);
|
||||
// Now, email the people we need to.
|
||||
foreach ($issuedusers as $user) {
|
||||
$userfullname = fullname($user);
|
||||
|
||||
$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);
|
||||
}
|
||||
// Now, get the PDF.
|
||||
$template = new \stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = $customcert->templatename;
|
||||
$template->contextid = $customcert->contextid;
|
||||
$template = new \mod_customcert\template($template);
|
||||
$filecontents = $template->generate_pdf(false, $user->id, true);
|
||||
|
||||
if ($customcert->emailteachers) {
|
||||
$renderable = new \mod_customcert\output\email_certificate(false, $userfullname, $courseshortname,
|
||||
$coursefullname, $certificatename, $customcert->contextid);
|
||||
// Set the name of the file we are going to send.
|
||||
$filename = $courseshortname . '_' . $certificatename;
|
||||
$filename = \core_text::entities_to_utf8($filename);
|
||||
$filename = strip_tags($filename);
|
||||
$filename = rtrim($filename, '.');
|
||||
$filename = str_replace('&', '_', $filename) . '.pdf';
|
||||
|
||||
// Create the file we will be sending.
|
||||
$tempfile = $tempdir . '/' . md5(microtime() . $user->id) . '.pdf';
|
||||
file_put_contents($tempfile, $filecontents);
|
||||
|
||||
if ($customcert->emailstudents) {
|
||||
$renderable = new \mod_customcert\output\email_certificate(true, $userfullname, $courseshortname,
|
||||
$coursefullname, $certificatename, $customcert->contextid);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
if ($customcert->emailteachers) {
|
||||
$renderable = new \mod_customcert\output\email_certificate(false, $userfullname, $courseshortname,
|
||||
$coursefullname, $certificatename, $customcert->contextid);
|
||||
|
||||
$subject = get_string('emailnonstudentsubject', 'customcert', $info);
|
||||
$message = $textrenderer->render($renderable);
|
||||
$messagehtml = $htmlrenderer->render($renderable);
|
||||
foreach ($teachers as $teacher) {
|
||||
email_to_user($teacher, fullname($userfrom), $subject, $message, $messagehtml, $tempfile,
|
||||
$filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($customcert->emailothers)) {
|
||||
$others = explode(',', $customcert->emailothers);
|
||||
foreach ($others as $email) {
|
||||
$email = trim($email);
|
||||
if (validate_email($email)) {
|
||||
$renderable = new \mod_customcert\output\email_certificate(false, $userfullname,
|
||||
$courseshortname, $coursefullname, $certificatename, $customcert->contextid);
|
||||
|
||||
$subject = get_string('emailnonstudentsubject', 'customcert', $info);
|
||||
$message = $textrenderer->render($renderable);
|
||||
$messagehtml = $htmlrenderer->render($renderable);
|
||||
foreach ($teachers as $teacher) {
|
||||
email_to_user($teacher, fullname($userfrom), $subject, $message, $messagehtml, $tempfile,
|
||||
$filename);
|
||||
}
|
||||
|
||||
$emailuser = new \stdClass();
|
||||
$emailuser->id = -1;
|
||||
$emailuser->email = $email;
|
||||
email_to_user($emailuser, fullname($userfrom), $subject, $message, $messagehtml, $tempfile,
|
||||
$filename);
|
||||
}
|
||||
|
||||
if (!empty($customcert->emailothers)) {
|
||||
$others = explode(',', $customcert->emailothers);
|
||||
foreach ($others as $email) {
|
||||
$email = trim($email);
|
||||
if (validate_email($email)) {
|
||||
$renderable = new \mod_customcert\output\email_certificate(false, $userfullname,
|
||||
$courseshortname, $coursefullname, $certificatename, $customcert->contextid);
|
||||
|
||||
$subject = get_string('emailnonstudentsubject', 'customcert', $info);
|
||||
$message = $textrenderer->render($renderable);
|
||||
$messagehtml = $htmlrenderer->render($renderable);
|
||||
|
||||
$emailuser = new \stdClass();
|
||||
$emailuser->id = -1;
|
||||
$emailuser->email = $email;
|
||||
email_to_user($emailuser, fullname($userfrom), $subject, $message, $messagehtml, $tempfile,
|
||||
$filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the field so that it is emailed.
|
||||
$DB->set_field('customcert_issues', 'emailed', 1, array('id' => $user->issueid));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the field so that it is emailed.
|
||||
$DB->set_field('customcert_issues', 'emailed', 1, array('id' => $user->issueid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,4 +96,64 @@ $capabilities = array(
|
|||
'manager' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
|
||||
'mod/customcert:manageemailstudents' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/course:manageactivities'
|
||||
),
|
||||
|
||||
'mod/customcert:manageemailteachers' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/course:manageactivities'
|
||||
),
|
||||
|
||||
'mod/customcert:manageemailothers' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/course:manageactivities'
|
||||
),
|
||||
|
||||
'mod/customcert:manageverifyany' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/course:manageactivities'
|
||||
),
|
||||
|
||||
'mod/customcert:managerequiredtime' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/course:manageactivities'
|
||||
),
|
||||
|
||||
'mod/customcert:manageprotection' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/course:manageactivities'
|
||||
),
|
||||
);
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="pageid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="element" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="element" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="data" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="font" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="fontsize" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
|
|
55
db/mobile.php
Normal file
55
db/mobile.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines mobile handlers.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2018 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$addons = [
|
||||
'mod_customcert' => [ // Plugin identifier.
|
||||
'handlers' => [ // Different places where the plugin will display content.
|
||||
'issueview' => [ // Handler unique name.
|
||||
'displaydata' => [
|
||||
'icon' => $CFG->wwwroot . '/mod/customcert/pix/icon.png',
|
||||
'class' => '',
|
||||
],
|
||||
'delegate' => 'CoreCourseModuleDelegate', // Delegate (where to display the link to the plugin).
|
||||
'method' => 'mobile_view_activity', // Main function in \mod_customcert\output\mobile.
|
||||
'styles' => [
|
||||
'url' => '/mod/customcert/mobile/styles.css',
|
||||
'version' => 1
|
||||
]
|
||||
]
|
||||
],
|
||||
'lang' => [ // Language strings that are used in all the handlers.
|
||||
['deleteissueconfirm', 'customcert'],
|
||||
['getcustomcert', 'customcert'],
|
||||
['listofissues', 'customcert'],
|
||||
['nothingtodisplay', 'moodle'],
|
||||
['notissued', 'customcert'],
|
||||
['pluginname', 'customcert'],
|
||||
['receiveddate', 'customcert'],
|
||||
['requiredtimenotmet', 'customcert'],
|
||||
['selectagroup', 'moodle']
|
||||
]
|
||||
]
|
||||
];
|
|
@ -25,6 +25,15 @@
|
|||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = array(
|
||||
'mod_customcert_delete_issue' => array(
|
||||
'classname' => 'mod_customcert\external',
|
||||
'methodname' => 'delete_issue',
|
||||
'classpath' => '',
|
||||
'description' => 'Delete an issue for a certificate',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE, 'local_mobile')
|
||||
),
|
||||
'mod_customcert_save_element' => array(
|
||||
'classname' => 'mod_customcert\external',
|
||||
'methodname' => 'save_element',
|
||||
|
|
|
@ -135,5 +135,16 @@ function xmldb_customcert_upgrade($oldversion) {
|
|||
upgrade_mod_savepoint(true, 2017050506, 'customcert');
|
||||
}
|
||||
|
||||
if ($oldversion < 2017111306) {
|
||||
$table = new xmldb_table('customcert_elements');
|
||||
$field = new xmldb_field('element', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, 'name');
|
||||
|
||||
// Alter the 'element' column to be characters, rather than text.
|
||||
$dbman->change_field_type($table, $field);
|
||||
|
||||
// Savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2017111306, 'customcert');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
24
edit.php
24
edit.php
|
@ -51,19 +51,31 @@ $context = context::instance_by_id($contextid);
|
|||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
$cm = get_coursemodule_from_id('customcert', $context->instanceid, 0, false, MUST_EXIST);
|
||||
require_login($cm->course, false, $cm);
|
||||
|
||||
$customcert = $DB->get_record('customcert', ['id' => $cm->instance], '*', MUST_EXIST);
|
||||
$title = $customcert->name;
|
||||
$heading = format_string($title);
|
||||
} else {
|
||||
require_login();
|
||||
$title = $SITE->fullname;
|
||||
$heading = $title;
|
||||
}
|
||||
|
||||
require_capability('mod/customcert:manage', $context);
|
||||
|
||||
// Set up the page.
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, get_string('editcustomcert', 'customcert'));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, $title);
|
||||
|
||||
if ($context->contextlevel == CONTEXT_SYSTEM) {
|
||||
// We are managing a template - add some navigation.
|
||||
$PAGE->navbar->add(get_string('managetemplates', 'customcert'),
|
||||
new moodle_url('/mod/customcert/manage_templates.php'));
|
||||
$PAGE->navbar->add(get_string('editcustomcert', 'customcert'));
|
||||
if (!$tid) {
|
||||
$PAGE->navbar->add(get_string('editcustomcert', 'customcert'));
|
||||
} else {
|
||||
$PAGE->navbar->add(get_string('editcustomcert', 'customcert'),
|
||||
new moodle_url('/mod/customcert/edit.php', ['tid' => $tid]));
|
||||
}
|
||||
}
|
||||
|
||||
// Flag to determine if we are deleting anything.
|
||||
|
@ -140,11 +152,9 @@ if ($tid) {
|
|||
// Check if we are deleting either a page or an element.
|
||||
if ($deleting) {
|
||||
// Show a confirmation page.
|
||||
$strheading = get_string('deleteconfirm', 'customcert');
|
||||
$PAGE->navbar->add($strheading);
|
||||
$PAGE->set_title($strheading);
|
||||
$PAGE->navbar->add(get_string('deleteconfirm', 'customcert'));
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strheading);
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->confirm($message, $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
|
@ -230,7 +240,7 @@ if ($data = $mform->get_data()) {
|
|||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('editcustomcert', 'customcert'));
|
||||
echo $OUTPUT->heading($heading);
|
||||
$mform->display();
|
||||
if ($tid && $context->contextlevel == CONTEXT_MODULE) {
|
||||
$loadtemplateurl = new moodle_url('/mod/customcert/load_template.php', array('tid' => $tid));
|
||||
|
|
|
@ -41,6 +41,15 @@ if ($cm = $template->get_cm()) {
|
|||
// Make sure the user has the required capabilities.
|
||||
$template->require_manage();
|
||||
|
||||
if ($template->get_context()->contextlevel == CONTEXT_MODULE) {
|
||||
$customcert = $DB->get_record('customcert', ['id' => $cm->instance], '*', MUST_EXIST);
|
||||
$title = $customcert->name;
|
||||
$heading = format_string($title);
|
||||
} else {
|
||||
$title = $SITE->fullname;
|
||||
$heading = $title;
|
||||
}
|
||||
|
||||
if ($action == 'edit') {
|
||||
// The id of the element must be supplied if we are currently editing one.
|
||||
$id = required_param('id', PARAM_INT);
|
||||
|
@ -56,7 +65,6 @@ if ($action == 'edit') {
|
|||
}
|
||||
|
||||
// Set up the page.
|
||||
$title = get_string('editelement', 'customcert');
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $template->get_context(), $title);
|
||||
|
||||
// Additional page setup.
|
||||
|
@ -66,7 +74,7 @@ if ($template->get_context()->contextlevel == CONTEXT_SYSTEM) {
|
|||
}
|
||||
$PAGE->navbar->add(get_string('editcustomcert', 'customcert'), new moodle_url('/mod/customcert/edit.php',
|
||||
array('tid' => $tid)));
|
||||
$PAGE->navbar->add($title);
|
||||
$PAGE->navbar->add(get_string('editelement', 'customcert'));
|
||||
|
||||
$mform = new \mod_customcert\edit_element_form($pageurl, array('element' => $element));
|
||||
|
||||
|
@ -95,6 +103,6 @@ if ($data = $mform->get_data()) {
|
|||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('editelement', 'customcert'));
|
||||
echo $OUTPUT->heading($heading);
|
||||
$mform->display();
|
||||
echo $OUTPUT->footer();
|
||||
|
|
|
@ -43,7 +43,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, self::get_category_name($this->get_id()));
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_category_name());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,28 +55,28 @@ class element extends \mod_customcert\element {
|
|||
* @return string the html
|
||||
*/
|
||||
public function render_html() {
|
||||
global $COURSE;
|
||||
|
||||
return \mod_customcert\element_helper::render_html_content($this, $COURSE->fullname);
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_category_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the category name.
|
||||
*
|
||||
* @param int $elementid
|
||||
* @return string
|
||||
*/
|
||||
protected static function get_category_name($elementid) {
|
||||
protected function get_category_name() : string {
|
||||
global $DB, $SITE;
|
||||
|
||||
$courseid = \mod_customcert\element_helper::get_courseid($elementid);
|
||||
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
|
||||
$course = get_course($courseid);
|
||||
$context = \mod_customcert\element_helper::get_context($this->get_id());
|
||||
|
||||
// Check that there is a course category available.
|
||||
if (!empty($course->category)) {
|
||||
return $DB->get_field('course_categories', 'name', array('id' => $course->category), MUST_EXIST);
|
||||
$categoryname = $DB->get_field('course_categories', 'name', array('id' => $course->category), MUST_EXIST);
|
||||
} else { // Must be in a site template.
|
||||
return $SITE->fullname;
|
||||
$categoryname = $SITE->fullname;
|
||||
}
|
||||
|
||||
return format_string($categoryname, true, ['context' => $context]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,10 +43,7 @@ class element extends \mod_customcert\element {
|
|||
* @param \stdClass $user the user we are rendering this for
|
||||
*/
|
||||
public function render($pdf, $preview, $user) {
|
||||
$courseid = \mod_customcert\element_helper::get_courseid($this->get_id());
|
||||
$course = get_course($courseid);
|
||||
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $course->fullname);
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_course_name());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,8 +55,19 @@ class element extends \mod_customcert\element {
|
|||
* @return string the html
|
||||
*/
|
||||
public function render_html() {
|
||||
global $COURSE;
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_course_name());
|
||||
}
|
||||
|
||||
return \mod_customcert\element_helper::render_html_content($this, $COURSE->fullname);
|
||||
/**
|
||||
* Helper function that returns the category name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_course_name() : 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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,12 +68,15 @@ class element extends \mod_customcert\element {
|
|||
* @param \mod_customcert\edit_element_form $mform the edit_form instance
|
||||
*/
|
||||
public function render_form_elements($mform) {
|
||||
global $COURSE;
|
||||
global $CFG, $COURSE;
|
||||
|
||||
// Get the possible date options.
|
||||
$dateoptions = array();
|
||||
$dateoptions[CUSTOMCERT_DATE_ISSUE] = get_string('issueddate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_COMPLETION] = get_string('completiondate', 'customcertelement_date');
|
||||
$completionenabled = $CFG->enablecompletion && ($COURSE->id == SITEID || $COURSE->enablecompletion);
|
||||
if ($completionenabled) {
|
||||
$dateoptions[CUSTOMCERT_DATE_COMPLETION] = get_string('completiondate', 'customcertelement_date');
|
||||
}
|
||||
$dateoptions[CUSTOMCERT_DATE_COURSE_START] = get_string('coursestartdate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_COURSE_END] = get_string('courseenddate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_COURSE_GRADE] = get_string('coursegradedate', 'customcertelement_date');
|
||||
|
@ -187,7 +190,12 @@ class element extends \mod_customcert\element {
|
|||
|
||||
// Ensure that a date has been set.
|
||||
if (!empty($date)) {
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_date_format_string($date, $dateformat));
|
||||
$date = $this->get_date_format_string($date, $dateformat);
|
||||
// If we are previewing, we want to let the user know it's an example date so they don't get confused.
|
||||
if ($preview) {
|
||||
$date = get_string('exampledata', 'customcert', 'date') . ' ' . $date;
|
||||
}
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $date);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,27 +264,44 @@ class element extends \mod_customcert\element {
|
|||
* @return array the list of date formats
|
||||
*/
|
||||
public static function get_date_formats() {
|
||||
$date = time();
|
||||
// Hard-code date so users can see the difference between short dates with and without the leading zero.
|
||||
// Eg. 06/07/18 vs 6/07/18.
|
||||
$date = 1530849658;
|
||||
|
||||
$suffix = self::get_ordinal_number_suffix(userdate($date, '%d'));
|
||||
|
||||
$dateformats = array(
|
||||
$dateformats = [
|
||||
1 => userdate($date, '%B %d, %Y'),
|
||||
2 => userdate($date, '%B %d' . $suffix . ', %Y'),
|
||||
'strftimedate' => userdate($date, get_string('strftimedate', 'langconfig')),
|
||||
'strftimedatefullshort' => userdate($date, get_string('strftimedatefullshort', 'langconfig')),
|
||||
'strftimedateshort' => userdate($date, get_string('strftimedateshort', 'langconfig')),
|
||||
'strftimedatetime' => userdate($date, get_string('strftimedatetime', 'langconfig')),
|
||||
'strftimedatetimeshort' => userdate($date, get_string('strftimedatetimeshort', 'langconfig')),
|
||||
'strftimedaydate' => userdate($date, get_string('strftimedaydate', 'langconfig')),
|
||||
'strftimedaydatetime' => userdate($date, get_string('strftimedaydatetime', 'langconfig')),
|
||||
'strftimedayshort' => userdate($date, get_string('strftimedayshort', 'langconfig')),
|
||||
'strftimedaytime' => userdate($date, get_string('strftimedaytime', 'langconfig')),
|
||||
'strftimemonthyear' => userdate($date, get_string('strftimemonthyear', 'langconfig')),
|
||||
'strftimerecent' => userdate($date, get_string('strftimerecent', 'langconfig')),
|
||||
'strftimerecentfull' => userdate($date, get_string('strftimerecentfull', 'langconfig')),
|
||||
'strftimetime' => userdate($date, get_string('strftimetime', 'langconfig'))
|
||||
);
|
||||
2 => userdate($date, '%B %d' . $suffix . ', %Y')
|
||||
];
|
||||
|
||||
$strdateformats = [
|
||||
'strftimedate',
|
||||
'strftimedatefullshort',
|
||||
'strftimedatefullshortwleadingzero',
|
||||
'strftimedateshort',
|
||||
'strftimedatetime',
|
||||
'strftimedatetimeshort',
|
||||
'strftimedatetimeshortwleadingzero',
|
||||
'strftimedaydate',
|
||||
'strftimedaydatetime',
|
||||
'strftimedayshort',
|
||||
'strftimedaytime',
|
||||
'strftimemonthyear',
|
||||
'strftimerecent',
|
||||
'strftimerecentfull',
|
||||
'strftimetime'
|
||||
];
|
||||
|
||||
foreach ($strdateformats as $strdateformat) {
|
||||
if ($strdateformat == 'strftimedatefullshortwleadingzero') {
|
||||
$dateformats[$strdateformat] = userdate($date, get_string('strftimedatefullshort', 'langconfig'), 99, false);
|
||||
} else if ($strdateformat == 'strftimedatetimeshortwleadingzero') {
|
||||
$dateformats[$strdateformat] = userdate($date, get_string('strftimedatetimeshort', 'langconfig'), 99, false);
|
||||
} else {
|
||||
$dateformats[$strdateformat] = userdate($date, get_string($strdateformat, 'langconfig'));
|
||||
}
|
||||
}
|
||||
|
||||
return $dateformats;
|
||||
}
|
||||
|
@ -312,7 +337,13 @@ class element extends \mod_customcert\element {
|
|||
|
||||
// Ok, so we must have been passed the actual format in the lang file.
|
||||
if (!isset($certificatedate)) {
|
||||
$certificatedate = userdate($date, get_string($dateformat, 'langconfig'));
|
||||
if ($dateformat == 'strftimedatefullshortwleadingzero') {
|
||||
$certificatedate = userdate($date, get_string('strftimedatefullshort', 'langconfig'), 99, false);
|
||||
} else if ($dateformat == 'strftimedatetimeshortwleadingzero') {
|
||||
$certificatedate = userdate($date, get_string('strftimedatetimeshort', 'langconfig'), 99, false);
|
||||
} else {
|
||||
$certificatedate = userdate($date, get_string($dateformat, 'langconfig'));
|
||||
}
|
||||
}
|
||||
|
||||
return $certificatedate;
|
||||
|
|
|
@ -106,14 +106,9 @@ class element extends \mod_customcert\element {
|
|||
|
||||
// If we are previewing this certificate then just show a demonstration grade.
|
||||
if ($preview) {
|
||||
// Define how many decimals to display.
|
||||
$decimals = 2;
|
||||
if ($gradeinfo->gradeformat == GRADE_DISPLAY_TYPE_PERCENTAGE) {
|
||||
$decimals = 0;
|
||||
}
|
||||
|
||||
$courseitem = \grade_item::fetch_course_item($courseid);
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat, $decimals);
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat);
|
||||
$grade = get_string('exampledata', 'customcert', 'grade') . ' ' . $grade;
|
||||
} else {
|
||||
if ($gradeitem == CUSTOMCERT_GRADE_COURSE) {
|
||||
$grade = \mod_customcert\element_helper::get_course_grade_info(
|
||||
|
@ -165,13 +160,7 @@ class element extends \mod_customcert\element {
|
|||
|
||||
$courseitem = \grade_item::fetch_course_item($COURSE->id);
|
||||
|
||||
// Define how many decimals to display.
|
||||
$decimals = 2;
|
||||
if ($gradeinfo->gradeformat == GRADE_DISPLAY_TYPE_PERCENTAGE) {
|
||||
$decimals = 0;
|
||||
}
|
||||
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat, $decimals);
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat);
|
||||
|
||||
return \mod_customcert\element_helper::render_html_content($this, $grade);
|
||||
}
|
||||
|
|
|
@ -73,18 +73,9 @@ class element extends \mod_customcert\element {
|
|||
* @param \stdClass $user the user we are rendering this for
|
||||
*/
|
||||
public function render($pdf, $preview, $user) {
|
||||
global $DB;
|
||||
|
||||
// Check that the grade item is not empty.
|
||||
if (!empty($this->get_data())) {
|
||||
// Get the course module information.
|
||||
$cm = $DB->get_record('course_modules', array('id' => $this->get_data()), '*', MUST_EXIST);
|
||||
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
|
||||
|
||||
// Get the name of the item.
|
||||
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
|
||||
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $itemname);
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_grade_item_name());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,18 +88,9 @@ class element extends \mod_customcert\element {
|
|||
* @return string the html
|
||||
*/
|
||||
public function render_html() {
|
||||
global $DB;
|
||||
|
||||
// Check that the grade item is not empty.
|
||||
if (!empty($this->get_data())) {
|
||||
// Get the course module information.
|
||||
$cm = $DB->get_record('course_modules', array('id' => $this->get_data()), '*', MUST_EXIST);
|
||||
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
|
||||
|
||||
// Get the name of the item.
|
||||
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
|
||||
|
||||
return \mod_customcert\element_helper::render_html_content($this, $itemname);
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_grade_item_name());
|
||||
}
|
||||
|
||||
return '';
|
||||
|
@ -126,4 +108,22 @@ class element extends \mod_customcert\element {
|
|||
}
|
||||
parent::definition_after_data($mform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the category name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_grade_item_name() : string {
|
||||
global $DB;
|
||||
|
||||
// Get the course module information.
|
||||
$cm = $DB->get_record('course_modules', array('id' => $this->get_data()), '*', MUST_EXIST);
|
||||
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
|
||||
|
||||
// Get the name of the item.
|
||||
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
|
||||
|
||||
return format_string($itemname, true, ['context' => \mod_customcert\element_helper::get_context($this->get_id())]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,24 @@ class element extends \mod_customcert\element {
|
|||
$mform->setDefault('height', 0);
|
||||
$mform->addHelpButton('height', 'height', 'customcertelement_image');
|
||||
|
||||
$alphachannelvalues = [
|
||||
'0' => 0,
|
||||
'0.1' => 0.1,
|
||||
'0.2' => 0.2,
|
||||
'0.3' => 0.3,
|
||||
'0.4' => 0.4,
|
||||
'0.5' => 0.5,
|
||||
'0.6' => 0.6,
|
||||
'0.7' => 0.7,
|
||||
'0.8' => 0.8,
|
||||
'0.9' => 0.9,
|
||||
'1' => 1
|
||||
];
|
||||
$mform->addElement('select', 'alphachannel', get_string('alphachannel', 'customcertelement_image'), $alphachannelvalues);
|
||||
$mform->setType('alphachannel', PARAM_FLOAT);
|
||||
$mform->setDefault('alphachannel', 1);
|
||||
$mform->addHelpButton('alphachannel', 'alphachannel', 'customcertelement_image');
|
||||
|
||||
if (get_config('customcert', 'showposxy')) {
|
||||
\mod_customcert\element_helper::render_form_element_position($mform);
|
||||
}
|
||||
|
@ -148,6 +166,10 @@ class element extends \mod_customcert\element {
|
|||
'height' => !empty($data->height) ? (int) $data->height : 0
|
||||
];
|
||||
|
||||
if (isset($data->alphachannel)) {
|
||||
$arrtostore['alphachannel'] = (float) $data->alphachannel;
|
||||
}
|
||||
|
||||
if (!empty($data->fileid)) {
|
||||
// Array of data we will be storing in the database.
|
||||
$fs = get_file_storage();
|
||||
|
@ -189,12 +211,20 @@ class element extends \mod_customcert\element {
|
|||
$location = make_request_directory() . '/target';
|
||||
$file->copy_content_to($location);
|
||||
|
||||
// Check if the alpha channel is set, if it is, use it.
|
||||
if (isset($imageinfo->alphachannel)) {
|
||||
$pdf->SetAlpha($imageinfo->alphachannel);
|
||||
}
|
||||
|
||||
$mimetype = $file->get_mimetype();
|
||||
if ($mimetype == 'image/svg+xml') {
|
||||
$pdf->ImageSVG($location, $this->get_posx(), $this->get_posy(), $imageinfo->width, $imageinfo->height);
|
||||
} else {
|
||||
$pdf->Image($location, $this->get_posx(), $this->get_posy(), $imageinfo->width, $imageinfo->height);
|
||||
}
|
||||
|
||||
// Restore to full opacity.
|
||||
$pdf->SetAlpha(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,7 +287,7 @@ class element extends \mod_customcert\element {
|
|||
public function definition_after_data($mform) {
|
||||
global $COURSE, $SITE;
|
||||
|
||||
// Set the image, width and height for this element.
|
||||
// Set the image, width, height and alpha channel for this element.
|
||||
if (!empty($this->get_data())) {
|
||||
$imageinfo = json_decode($this->get_data());
|
||||
if (!empty($imageinfo->filename)) {
|
||||
|
@ -276,6 +306,11 @@ class element extends \mod_customcert\element {
|
|||
$element = $mform->getElement('height');
|
||||
$element->setValue($imageinfo->height);
|
||||
}
|
||||
|
||||
if (isset($imageinfo->alphachannel) && $mform->elementExists('alphachannel')) {
|
||||
$element = $mform->getElement('alphachannel');
|
||||
$element->setValue($imageinfo->alphachannel);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the context.
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['alphachannel'] = 'Alpha channel';
|
||||
$string['alphachannel_help'] = 'This value determines how transparent the image is. You can set the alpha channel from 0 (fully transparent) to 1 (fully opaque).';
|
||||
$string['height'] = 'Height';
|
||||
$string['height_help'] = 'Height of the image in mm. If equal to zero, it is automatically calculated.';
|
||||
$string['image'] = 'Image';
|
||||
|
|
|
@ -102,11 +102,16 @@ class element extends \mod_customcert\element {
|
|||
protected function get_list_of_teachers() {
|
||||
global $PAGE;
|
||||
|
||||
// Return early if we are in a site template.
|
||||
if ($PAGE->context->id == \context_system::instance()->id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// The list of teachers to return.
|
||||
$teachers = array();
|
||||
|
||||
// Now return all users who can manage the customcert in this context.
|
||||
if ($users = get_users_by_capability($PAGE->context, 'mod/customcert:manage')) {
|
||||
if ($users = get_enrolled_users($PAGE->context, 'mod/customcert:manage')) {
|
||||
foreach ($users as $user) {
|
||||
$teachers[$user->id] = fullname($user);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,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_data());
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_text());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +79,7 @@ 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_data());
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_text());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,4 +94,14 @@ class element extends \mod_customcert\element {
|
|||
}
|
||||
parent::definition_after_data($mform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_text() : string {
|
||||
$context = \mod_customcert\element_helper::get_context($this->get_id());
|
||||
return format_text($this->get_data(), FORMAT_HTML, ['context' => $context]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,28 +98,7 @@ class element extends \mod_customcert\element {
|
|||
* @param \stdClass $user the user we are rendering this for
|
||||
*/
|
||||
public function render($pdf, $preview, $user) {
|
||||
global $CFG, $DB;
|
||||
|
||||
// The user field to display.
|
||||
$field = $this->get_data();
|
||||
// The value to display on the PDF.
|
||||
$value = '';
|
||||
if (is_number($field)) { // Must be a custom user profile field.
|
||||
if ($field = $DB->get_record('user_info_field', array('id' => $field))) {
|
||||
$file = $CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php';
|
||||
if (file_exists($file)) {
|
||||
require_once($CFG->dirroot . '/user/profile/lib.php');
|
||||
require_once($file);
|
||||
$class = "profile_field_{$field->datatype}";
|
||||
$field = new $class($field->id, $user->id);
|
||||
$value = $field->display_data();
|
||||
}
|
||||
}
|
||||
} else if (!empty($user->$field)) { // Field in the user table.
|
||||
$value = $user->$field;
|
||||
}
|
||||
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $value);
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_user_field_value($user, $preview));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,33 +108,9 @@ class element extends \mod_customcert\element {
|
|||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $CFG, $DB, $USER;
|
||||
global $USER;
|
||||
|
||||
// The user field to display.
|
||||
$field = $this->get_data();
|
||||
// The value to display - we always want to show a value here so it can be repositioned.
|
||||
$value = $field;
|
||||
if (is_number($field)) { // Must be a custom user profile field.
|
||||
if ($field = $DB->get_record('user_info_field', array('id' => $field))) {
|
||||
// Found the field name, let's update the value to display.
|
||||
$value = $field->name;
|
||||
$file = $CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php';
|
||||
if (file_exists($file)) {
|
||||
require_once($CFG->dirroot . '/user/profile/lib.php');
|
||||
require_once($file);
|
||||
$class = "profile_field_{$field->datatype}";
|
||||
$field = new $class($field->id, $USER->id);
|
||||
if ($fieldvalue = $field->display_data()) {
|
||||
// Ok, found a value for the user, let's show that instead.
|
||||
$value = $fieldvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!empty($USER->$field)) { // Field in the user table.
|
||||
$value = $USER->$field;
|
||||
}
|
||||
|
||||
return \mod_customcert\element_helper::render_html_content($this, $value);
|
||||
return \mod_customcert\element_helper::render_html_content($this, $this->get_user_field_value($USER, true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,4 +125,43 @@ class element extends \mod_customcert\element {
|
|||
}
|
||||
parent::definition_after_data($mform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the text.
|
||||
*
|
||||
* @param \stdClass $user the user we are rendering this for
|
||||
* @param bool $preview Is this a preview?
|
||||
* @return string
|
||||
*/
|
||||
protected function get_user_field_value(\stdClass $user, bool $preview) : string {
|
||||
global $CFG, $DB;
|
||||
|
||||
// The user field to display.
|
||||
$field = $this->get_data();
|
||||
// The value to display - we always want to show a value here so it can be repositioned.
|
||||
if ($preview) {
|
||||
$value = $field;
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
if (is_number($field)) { // Must be a custom user profile field.
|
||||
if ($field = $DB->get_record('user_info_field', array('id' => $field))) {
|
||||
// Found the field name, let's update the value to display.
|
||||
$value = $field->name;
|
||||
$file = $CFG->dirroot . '/user/profile/field/' . $field->datatype . '/field.class.php';
|
||||
if (file_exists($file)) {
|
||||
require_once($CFG->dirroot . '/user/profile/lib.php');
|
||||
require_once($file);
|
||||
$class = "profile_field_{$field->datatype}";
|
||||
$field = new $class($field->id, $user->id);
|
||||
$value = $field->display_data();
|
||||
}
|
||||
}
|
||||
} else if (!empty($user->$field)) { // Field in the user table.
|
||||
$value = $user->$field;
|
||||
}
|
||||
|
||||
$context = \mod_customcert\element_helper::get_context($this->get_id());
|
||||
return format_string($value, true, ['context' => $context]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,9 +60,9 @@ $table = new html_table();
|
|||
|
||||
if ($usesections = course_format_uses_sections($course->format)) {
|
||||
$table->head = array(get_string('sectionname', 'format_'.$course->format), get_string('name'),
|
||||
get_string('issued', 'customcert'));
|
||||
get_string('receiveddate', 'customcert'));
|
||||
} else {
|
||||
$table->head = array(get_string('name'), get_string('issued', 'customcert'));
|
||||
$table->head = array(get_string('name'), get_string('receiveddate', 'customcert'));
|
||||
}
|
||||
|
||||
$currentsection = '';
|
||||
|
|
|
@ -33,14 +33,20 @@ $string['coursetimereq'] = 'Required minutes in course';
|
|||
$string['coursetimereq_help'] = 'Enter here the minimum amount of time, in minutes, that a student must be logged into the course before they will be able to receive
|
||||
the certificate.';
|
||||
$string['createtemplate'] = 'Create template';
|
||||
$string['customcertreport'] = 'Custom certificate report';
|
||||
$string['customcert:addinstance'] = 'Add a new custom certificate instance';
|
||||
$string['customcert:manage'] = 'Manage a custom certificate';
|
||||
$string['customcert:manageemailstudents'] = 'Manage email students setting';
|
||||
$string['customcert:manageemailteachers'] = 'Manage email teachers setting';
|
||||
$string['customcert:manageemailothers'] = 'Manage email others setting';
|
||||
$string['customcert:manageverifyany'] = 'Manage verification setting';
|
||||
$string['customcert:managerequiredtime'] = 'Manage time required setting';
|
||||
$string['customcert:manageprotection'] = 'Manage protection setting';
|
||||
$string['customcert:view'] = 'View a custom certificate';
|
||||
$string['customcert:viewreport'] = 'View course report';
|
||||
$string['customcert:viewallcertificates'] = 'View all certificates';
|
||||
$string['customcert:verifyallcertificates'] = 'Verify all certificates on the site';
|
||||
$string['customcert:verifycertificate'] = 'Verify a certificate';
|
||||
$string['customcertsettings'] = 'Custom certificate settings';
|
||||
$string['deletecertpage'] = 'Delete page';
|
||||
$string['deleteconfirm'] = 'Delete confirmation';
|
||||
$string['deleteelement'] = 'Delete element';
|
||||
|
@ -58,6 +64,7 @@ $string['editelement'] = 'Edit element';
|
|||
$string['edittemplate'] = 'Edit template';
|
||||
$string['elementname'] = 'Element name';
|
||||
$string['elementname_help'] = 'This will be the name used to identify this element when editing a certificate. Note: this will not displayed on the PDF.';
|
||||
$string['elementplugins'] = 'Element plugins';
|
||||
$string['elements'] = 'Elements';
|
||||
$string['elements_help'] = 'This is the list of elements that will be displayed on the certificate.
|
||||
|
||||
|
@ -65,10 +72,12 @@ Please note: The elements are rendered in this order. The order can be changed b
|
|||
$string['elementwidth'] = 'Width';
|
||||
$string['elementwidth_help'] = 'Specify the width of the element - \'0\' means that there is no width constraint.';
|
||||
$string['emailnonstudentbody'] = 'Attached is the certificate \'{$a->certificatename}\' for \'{$a->userfullname}\' for the course \'{$a->coursefullname}\'.';
|
||||
$string['emailnonstudentbodyplaintext'] = 'Attached is the certificate \'{$a->certificatename}\' for \'{$a->userfullname}\' for the course \'{$a->coursefullname}\'.';
|
||||
$string['emailnonstudentcertificatelinktext'] = 'View certificate report';
|
||||
$string['emailnonstudentgreeting'] = 'Hi';
|
||||
$string['emailnonstudentsubject'] = '{$a->coursefullname}: {$a->certificatename}';
|
||||
$string['emailstudentbody'] = 'Attached is your certificate \'{$a->certificatename}\' for the course \'{$a->coursefullname}\'.';
|
||||
$string['emailstudentbodyplaintext'] = 'Attached is your certificate \'{$a->certificatename}\' for the course \'{$a->coursefullname}\'.';
|
||||
$string['emailstudentcertificatelinktext'] = 'View certificate';
|
||||
$string['emailstudentgreeting'] = 'Dear {$a}';
|
||||
$string['emailstudentsubject'] = '{$a->coursefullname}: {$a->certificatename}';
|
||||
|
@ -78,13 +87,15 @@ $string['emailteachers'] = 'Email teachers';
|
|||
$string['emailteachers_help'] = 'If set this will email the teachers a copy of the certificate when it becomes available.';
|
||||
$string['emailothers'] = 'Email others';
|
||||
$string['emailothers_help'] = 'If set this will email the email addresses listed here (separated by a comma) with a copy of the certificate when it becomes available.';
|
||||
$string['exampledata'] = 'Example {$a}:';
|
||||
$string['exampledatawarning'] = 'Some of these values may just be an example to ensure positioning of the elements is possible.';
|
||||
$string['font'] = 'Font';
|
||||
$string['font_help'] = 'The font used when generating this element.';
|
||||
$string['fontcolour'] = 'Colour';
|
||||
$string['fontcolour_help'] = 'The colour of the font.';
|
||||
$string['fontsize'] = 'Size';
|
||||
$string['fontsize_help'] = 'The size of the font in points.';
|
||||
$string['getcustomcert'] = 'Download certificate';
|
||||
$string['getcustomcert'] = 'View certificate';
|
||||
$string['height'] = 'Height';
|
||||
$string['height_help'] = 'This is the height of the certificate PDF in mm. For reference an A4 piece of paper is 297mm high and a letter is 279mm high.';
|
||||
$string['invalidcode'] = 'Invalid code supplied.';
|
||||
|
@ -94,10 +105,10 @@ $string['invalidposition'] = 'Please select a positive number for position {$a}.
|
|||
$string['invalidheight'] = 'The height has to be a valid number greater than 0.';
|
||||
$string['invalidmargin'] = 'The margin has to be a valid number greater than 0.';
|
||||
$string['invalidwidth'] = 'The width has to be a valid number greater than 0.';
|
||||
$string['issued'] = 'Issued';
|
||||
$string['landscape'] = 'Landscape';
|
||||
$string['leftmargin'] = 'Left margin';
|
||||
$string['leftmargin_help'] = 'This is the left margin of the certificate PDF in mm.';
|
||||
$string['listofissues'] = 'Recipients';
|
||||
$string['load'] = 'Load';
|
||||
$string['loadtemplate'] = 'Load template';
|
||||
$string['loadtemplatemsg'] = 'Are you sure you wish to load this template? This will remove any existing pages and elements for this certificate.';
|
||||
|
@ -114,8 +125,9 @@ $string['name'] = 'Name';
|
|||
$string['nametoolong'] = 'You have exceeded the maximum length allowed for the name';
|
||||
$string['nocustomcerts'] = 'There are no certificates for this course';
|
||||
$string['noimage'] = 'No image';
|
||||
$string['norecipients'] = 'No recipients';
|
||||
$string['notemplates'] = 'No templates';
|
||||
$string['notissued'] = 'Not issued';
|
||||
$string['notissued'] = 'Not awarded';
|
||||
$string['notverified'] = 'Not verified';
|
||||
$string['options'] = 'Options';
|
||||
$string['page'] = 'Page {$a}';
|
||||
|
@ -126,6 +138,12 @@ $string['posx'] = 'Position X';
|
|||
$string['posx_help'] = 'This is the position in mm from the top left corner you wish the element\'s reference point to locate in the x direction.';
|
||||
$string['posy'] = 'Position Y';
|
||||
$string['posy_help'] = 'This is the position in mm from the top left corner you wish the element\'s reference point to locate in the y direction.';
|
||||
$string['preventcopy'] = 'Prevent copy';
|
||||
$string['preventcopy_desc'] = 'Enable protection from copy action.';
|
||||
$string['preventprint'] = 'Prevent print';
|
||||
$string['preventprint_desc'] = 'Enable protection from print action.';
|
||||
$string['preventmodify'] = 'Prevent modify';
|
||||
$string['preventmodify_desc'] = 'Enable protection from modify action.';
|
||||
$string['print'] = 'Print';
|
||||
$string['privacy:metadata:customcert_issues'] = 'The list of issued certificates';
|
||||
$string['privacy:metadata:customcert_issues:code'] = 'The code that belongs to the certificate';
|
||||
|
@ -135,7 +153,7 @@ $string['privacy:metadata:customcert_issues:timecreated'] = 'The time the certif
|
|||
$string['privacy:metadata:customcert_issues:userid'] = 'The ID of the user who was issued the certificate';
|
||||
$string['rearrangeelements'] = 'Reposition elements';
|
||||
$string['rearrangeelementsheading'] = 'Drag and drop elements to change where they are positioned on the certificate.';
|
||||
$string['receiveddate'] = 'Received date';
|
||||
$string['receiveddate'] = 'Awarded on';
|
||||
$string['refpoint'] = 'Reference point location';
|
||||
$string['refpoint_help'] = 'The reference point is the location of an element from which its x and y coordinates are determined. It is indicated by the \'+\' that appears in the centre or corners of the element.';
|
||||
$string['replacetemplate'] = 'Replace';
|
||||
|
@ -154,7 +172,6 @@ $string['showposxy'] = 'Show position X and Y';
|
|||
$string['showposxy_desc'] = 'This will show the X and Y position when editing of an element, allowing the user to accurately specify the location.
|
||||
|
||||
This isn\'t required if you plan on solely using the drag and drop interface for this purpose.';
|
||||
$string['summaryofissue'] = 'Summary of issue';
|
||||
$string['taskemailcertificate'] = 'Handles emailing certificates.';
|
||||
$string['templatename'] = 'Template name';
|
||||
$string['templatenameexists'] = 'That template name is currently in use, please choose another.';
|
||||
|
@ -172,8 +189,8 @@ $string['verifyallcertificates_desc'] = 'When this setting is enabled any person
|
|||
|
||||
Note - this only applies to certificates where \'Allow anyone to verify a certificate\' has been set to \'Yes\' in the certificate settings.';
|
||||
$string['verifycertificate'] = 'Verify certificate';
|
||||
$string['verifycertificatedesc'] = 'This link will take you to a new screen where you will be able to verify certificates on the site';
|
||||
$string['verifycertificateanyone'] = 'Allow anyone to verify a certificate';
|
||||
$string['verifycertificateanyone_help'] = 'This setting enables anyone with the certificate verification link (including users not logged in) to verify a certificate.';
|
||||
$string['viewcustomcertissues'] = 'View {$a} issued certificates';
|
||||
$string['width'] = 'Width';
|
||||
$string['width_help'] = 'This is the width of the certificate PDF in mm. For reference an A4 piece of paper is 210mm wide and a letter is 216mm wide.';
|
||||
|
|
21
lib.php
21
lib.php
|
@ -136,12 +136,6 @@ function customcert_reset_userdata($data) {
|
|||
'error' => false);
|
||||
}
|
||||
|
||||
// Updating dates - shift may be negative too.
|
||||
if ($data->timeshift) {
|
||||
shift_course_mod_dates('customcert', array('timeopen', 'timeclose'), $data->timeshift, $data->courseid);
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
@ -181,7 +175,7 @@ function customcert_user_outline($course, $user, $mod, $customcert) {
|
|||
|
||||
$result = new stdClass();
|
||||
if ($issue = $DB->get_record('customcert_issues', array('customcertid' => $customcert->id, 'userid' => $user->id))) {
|
||||
$result->info = get_string('issued', 'customcert');
|
||||
$result->info = get_string('receiveddate', 'customcert');
|
||||
$result->time = $issue->timecreated;
|
||||
} else {
|
||||
$result->info = get_string('notissued', 'customcert');
|
||||
|
@ -205,11 +199,11 @@ function customcert_user_complete($course, $user, $mod, $customcert) {
|
|||
|
||||
if ($issue = $DB->get_record('customcert_issues', array('customcertid' => $customcert->id, 'userid' => $user->id))) {
|
||||
echo $OUTPUT->box_start();
|
||||
echo get_string('issued', 'customcert') . ": ";
|
||||
echo get_string('receiveddate', 'customcert') . ": ";
|
||||
echo userdate($issue->timecreated);
|
||||
echo $OUTPUT->box_end();
|
||||
} else {
|
||||
print_string('notissuedyet', 'customcert');
|
||||
print_string('notissued', 'customcert');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,3 +412,12 @@ function mod_customcert_inplace_editable($itemtype, $itemid, $newvalue) {
|
|||
$updateelement->name, $updateelement->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get icon mapping for font-awesome.
|
||||
*/
|
||||
function mod_customcert_get_fontawesome_icon_map() {
|
||||
return [
|
||||
'mod_customcert:download' => 'fa-download'
|
||||
];
|
||||
}
|
||||
|
|
|
@ -41,6 +41,15 @@ if ($cm = $template->get_cm()) {
|
|||
}
|
||||
$template->require_manage();
|
||||
|
||||
if ($template->get_context()->contextlevel == CONTEXT_MODULE) {
|
||||
$customcert = $DB->get_record('customcert', ['id' => $cm->instance], '*', MUST_EXIST);
|
||||
$title = $customcert->name;
|
||||
$heading = format_string($title);
|
||||
} else {
|
||||
$title = $SITE->fullname;
|
||||
$heading = $title;
|
||||
}
|
||||
|
||||
// Check that they have confirmed they wish to load the template.
|
||||
if ($confirm && confirm_sesskey()) {
|
||||
// First, remove all the existing elements and pages.
|
||||
|
@ -77,9 +86,15 @@ $yesurl = new moodle_url('/mod/customcert/load_template.php', array('tid' => $ti
|
|||
'sesskey' => sesskey()));
|
||||
|
||||
$pageurl = new moodle_url('/mod/customcert/load_template.php', array('tid' => $tid, 'ltid' => $ltid));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $template->get_context(), get_string('loadtemplate', 'customcert'));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $template->get_context(), $title);
|
||||
|
||||
$str = get_string('editcustomcert', 'customcert');
|
||||
$link = new moodle_url('/mod/customcert/edit.php', array('tid' => $template->get_id()));
|
||||
$PAGE->navbar->add($str, new \action_link($link, $str));
|
||||
$PAGE->navbar->add(get_string('loadtemplate', 'customcert'));
|
||||
|
||||
// Show a confirmation page.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->confirm(get_string('loadtemplatemsg', 'customcert'), $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
|
@ -46,12 +46,20 @@ $context = context::instance_by_id($contextid);
|
|||
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');
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, get_string('managetemplates', 'customcert'));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, $title);
|
||||
|
||||
// Additional page setup.
|
||||
$PAGE->navbar->add(get_string('managetemplates', 'customcert'));
|
||||
if ($tid && $action && confirm_sesskey()) {
|
||||
$PAGE->navbar->add(get_string('managetemplates', 'customcert'),
|
||||
new moodle_url('/mod/customcert/manage_templates.php'));
|
||||
} else {
|
||||
$PAGE->navbar->add(get_string('managetemplates', 'customcert'));
|
||||
}
|
||||
|
||||
if ($tid) {
|
||||
if ($action && confirm_sesskey()) {
|
||||
|
@ -69,12 +77,10 @@ if ($tid) {
|
|||
if ($action == 'delete') {
|
||||
if (!$confirm) {
|
||||
// Show a confirmation page.
|
||||
$strheading = get_string('deleteconfirm', 'customcert');
|
||||
$PAGE->navbar->add($strheading);
|
||||
$PAGE->set_title($strheading);
|
||||
$PAGE->navbar->add(get_string('deleteconfirm', 'customcert'));
|
||||
$message = get_string('deletetemplateconfirm', 'customcert');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strheading);
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->confirm($message, $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
|
@ -88,12 +94,10 @@ if ($tid) {
|
|||
} else if ($action == 'duplicate') {
|
||||
if (!$confirm) {
|
||||
// Show a confirmation page.
|
||||
$strheading = get_string('duplicateconfirm', 'customcert');
|
||||
$PAGE->navbar->add($strheading);
|
||||
$PAGE->set_title($strheading);
|
||||
$PAGE->navbar->add(get_string('duplicateconfirm', 'customcert'));
|
||||
$message = get_string('duplicatetemplateconfirm', 'customcert');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strheading);
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->confirm($message, $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
|
@ -120,6 +124,7 @@ $table = new \mod_customcert\manage_templates_table($context);
|
|||
$table->define_baseurl($pageurl);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($heading);
|
||||
$table->out($perpage, false);
|
||||
$url = new moodle_url('/mod/customcert/edit.php?contextid=' . $contextid);
|
||||
echo $OUTPUT->single_button($url, get_string('createtemplate', 'customcert'), 'get');
|
||||
|
|
88
mobile/pluginfile.php
Normal file
88
mobile/pluginfile.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Serves files for the mobile app.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2018 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* AJAX_SCRIPT - exception will be converted into JSON.
|
||||
*/
|
||||
define('AJAX_SCRIPT', true);
|
||||
|
||||
/**
|
||||
* NO_MOODLE_COOKIES - we don't want any cookie.
|
||||
*/
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
|
||||
require_once('../../../config.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
|
||||
// Allow CORS requests.
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
// Authenticate the user.
|
||||
$token = required_param('token', PARAM_ALPHANUM);
|
||||
$certificateid = required_param('certificateid', PARAM_INT);
|
||||
$userid = required_param('userid', PARAM_INT);
|
||||
|
||||
$webservicelib = new webservice();
|
||||
$authenticationinfo = $webservicelib->authenticate_user($token);
|
||||
|
||||
// Check the service allows file download.
|
||||
$enabledfiledownload = (int) ($authenticationinfo['service']->downloadfiles);
|
||||
if (empty($enabledfiledownload)) {
|
||||
throw new webservice_access_exception('Web service file downloading must be enabled in external service settings');
|
||||
}
|
||||
|
||||
$cm = get_coursemodule_from_instance('customcert', $certificateid, 0, false, MUST_EXIST);
|
||||
$certificate = $DB->get_record('customcert', ['id' => $certificateid], '*', MUST_EXIST);
|
||||
$template = $DB->get_record('customcert_templates', ['id' => $certificate->templateid], '*', MUST_EXIST);
|
||||
|
||||
// Capabilities check.
|
||||
require_capability('mod/customcert:view', \context_module::instance($cm->id));
|
||||
if ($userid != $USER->id) {
|
||||
require_capability('mod/customcert:viewreport', \context_module::instance($cm->id));
|
||||
} else {
|
||||
// Make sure the user has met the required time.
|
||||
if ($certificate->requiredtime) {
|
||||
if (\mod_customcert\certificate::get_course_time($certificate->course) < ($certificate->requiredtime * 60)) {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$issue = $DB->get_record('customcert_issues', ['customcertid' => $certificateid, 'userid' => $userid]);
|
||||
|
||||
// If we are doing it for the logged in user then we want to issue the certificate.
|
||||
if (!$issue) {
|
||||
// If the other user doesn't have an issue, then there is nothing to do.
|
||||
if ($userid != $USER->id) {
|
||||
exit();
|
||||
}
|
||||
|
||||
\mod_customcert\certificate::issue_certificate($certificate->id, $USER->id);
|
||||
}
|
||||
|
||||
// Now we want to generate the PDF.
|
||||
$template = new \mod_customcert\template($template);
|
||||
$template->generate_pdf(false, $userid);
|
||||
exit();
|
3
mobile/styles.css
Normal file
3
mobile/styles.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.timerewarded {
|
||||
font-size: 14px;
|
||||
}
|
172
mod_form.php
172
mod_form.php
|
@ -55,33 +55,63 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
|
||||
$this->standard_intro_elements(get_string('description', 'customcert'));
|
||||
|
||||
$mform->addElement('header', 'options', get_string('options', 'customcert'));
|
||||
$optionsheader = $mform->createElement('header', 'options', get_string('options', 'customcert'));
|
||||
|
||||
$mform->addElement('selectyesno', 'emailstudents', get_string('emailstudents', 'customcert'));
|
||||
$mform->setType('emailstudents', 0);
|
||||
$mform->addHelpButton('emailstudents', 'emailstudents', 'customcert');
|
||||
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';
|
||||
}
|
||||
|
||||
$mform->addElement('selectyesno', 'emailteachers', get_string('emailteachers', 'customcert'));
|
||||
$mform->setDefault('emailteachers', 0);
|
||||
$mform->addHelpButton('emailteachers', 'emailteachers', 'customcert');
|
||||
if (has_capability('mod/customcert:manageemailteachers', $this->get_context())) {
|
||||
$mform->addElement('selectyesno', 'emailteachers', get_string('emailteachers', 'customcert'));
|
||||
$mform->setDefault('emailteachers', get_config('customcert', 'emailteachers'));
|
||||
$mform->addHelpButton('emailteachers', 'emailteachers', 'customcert');
|
||||
$mform->setType('emailteachers', PARAM_INT);
|
||||
$firstoption = empty($firstoption) ? 'emailteachers' : $firstoption;
|
||||
}
|
||||
|
||||
$mform->addElement('text', 'emailothers', get_string('emailothers', 'customcert'), array('size' => '40'));
|
||||
$mform->setType('emailothers', PARAM_TEXT);
|
||||
$mform->addHelpButton('emailothers', 'emailothers', 'customcert');
|
||||
if (has_capability('mod/customcert:manageemailothers', $this->get_context())) {
|
||||
$mform->addElement('text', 'emailothers', get_string('emailothers', 'customcert'), array('size' => '40'));
|
||||
$mform->addHelpButton('emailothers', 'emailothers', 'customcert');
|
||||
$mform->setDefault('emailothers', get_config('customcert', 'emailothers'));
|
||||
$mform->setType('emailothers', PARAM_TEXT);
|
||||
$firstoption = empty($firstoption) ? 'emailothers' : $firstoption;
|
||||
}
|
||||
|
||||
$mform->addElement('selectyesno', 'verifyany', get_string('verifycertificateanyone', 'customcert'));
|
||||
$mform->setType('verifyany', 0);
|
||||
$mform->addHelpButton('verifyany', 'verifycertificateanyone', 'customcert');
|
||||
if (has_capability('mod/customcert:manageverifyany', $this->get_context())) {
|
||||
$mform->addElement('selectyesno', 'verifyany', get_string('verifycertificateanyone', 'customcert'));
|
||||
$mform->addHelpButton('verifyany', 'verifycertificateanyone', 'customcert');
|
||||
$mform->setDefault('verifyany', get_config('customcert', 'verifyany'));
|
||||
$mform->setType('verifyany', PARAM_INT);
|
||||
$firstoption = empty($firstoption) ? 'verifyany' : $firstoption;
|
||||
}
|
||||
|
||||
$mform->addElement('text', 'requiredtime', get_string('coursetimereq', 'customcert'), array('size' => '3'));
|
||||
$mform->setType('requiredtime', PARAM_INT);
|
||||
$mform->addHelpButton('requiredtime', 'coursetimereq', 'customcert');
|
||||
if (has_capability('mod/customcert:managerequiredtime', $this->get_context())) {
|
||||
$mform->addElement('text', 'requiredtime', get_string('coursetimereq', 'customcert'), array('size' => '3'));
|
||||
$mform->addHelpButton('requiredtime', 'coursetimereq', 'customcert');
|
||||
$mform->setDefault('requiredtime', get_config('customcert', 'requiredtime'));
|
||||
$mform->setType('requiredtime', PARAM_INT);
|
||||
$firstoption = empty($firstoption) ? 'requiredtime' : $firstoption;
|
||||
}
|
||||
|
||||
$mform->addElement('checkbox', 'protection_print', get_string('setprotection', 'customcert'),
|
||||
get_string('print', 'customcert'));
|
||||
$mform->addElement('checkbox', 'protection_modify', '', get_string('modify', 'customcert'));
|
||||
$mform->addElement('checkbox', 'protection_copy', '', get_string('copy', 'customcert'));
|
||||
$mform->addHelpButton('protection_print', 'setprotection', 'customcert');
|
||||
if (has_capability('mod/customcert:manageprotection', $this->get_context())) {
|
||||
$mform->addElement('checkbox', 'protection_print', get_string('setprotection', 'customcert'),
|
||||
get_string('print', 'customcert'));
|
||||
$mform->addElement('checkbox', 'protection_modify', '', get_string('modify', 'customcert'));
|
||||
$mform->addElement('checkbox', 'protection_copy', '', get_string('copy', 'customcert'));
|
||||
$mform->addHelpButton('protection_print', 'setprotection', 'customcert');
|
||||
$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();
|
||||
|
||||
|
@ -94,17 +124,51 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
* @param array $defaultvalues
|
||||
*/
|
||||
public function data_preprocessing(&$defaultvalues) {
|
||||
if (!empty($defaultvalues['protection'])) {
|
||||
$protection = explode(', ', $defaultvalues['protection']);
|
||||
// Set the values in the form to what has been set in database.
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_PRINT, $protection)) {
|
||||
$defaultvalues['protection_print'] = 1;
|
||||
// Set the values in the form to what has been set in database if updating
|
||||
// or set default configured values if creating.
|
||||
if (!empty($defaultvalues['update'])) {
|
||||
if (!empty($defaultvalues['protection'])) {
|
||||
$protection = $this->build_protection_data($defaultvalues['protection']);
|
||||
|
||||
$defaultvalues['protection_print'] = $protection->protection_print;
|
||||
$defaultvalues['protection_modify'] = $protection->protection_modify;
|
||||
$defaultvalues['protection_copy'] = $protection->protection_copy;
|
||||
}
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_MODIFY, $protection)) {
|
||||
$defaultvalues['protection_modify'] = 1;
|
||||
} else {
|
||||
$defaultvalues['protection_print'] = get_config('customcert', 'protection_print');
|
||||
$defaultvalues['protection_modify'] = get_config('customcert', 'protection_modify');
|
||||
$defaultvalues['protection_copy'] = get_config('customcert', 'protection_copy');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post process form data.
|
||||
*
|
||||
* @param \stdClass $data
|
||||
*
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public function data_postprocessing($data) {
|
||||
global $DB;
|
||||
|
||||
parent::data_postprocessing($data);
|
||||
|
||||
// If creating a new activity.
|
||||
if (!empty($data->add)) {
|
||||
foreach ($this->get_options_elements_with_required_caps() as $name => $capability) {
|
||||
if (!isset($data->$name) && !has_capability($capability, $this->get_context())) {
|
||||
$data->$name = get_config('customcert', $name);
|
||||
}
|
||||
}
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_COPY, $protection)) {
|
||||
$defaultvalues['protection_copy'] = 1;
|
||||
} else {
|
||||
// If updating, but a user can't manage protection, then get data from database.
|
||||
if (!has_capability('mod/customcert:manageprotection', $this->get_context())) {
|
||||
$customcert = $DB->get_record('customcert', array('id' => $data->instance));
|
||||
|
||||
$protection = $this->build_protection_data($customcert->protection);
|
||||
$data->protection_print = $protection->protection_print;
|
||||
$data->protection_modify = $protection->protection_modify;
|
||||
$data->protection_copy = $protection->protection_copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,4 +192,52 @@ class mod_customcert_mod_form extends moodleform_mod {
|
|||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all options form elements with required capabilities for managing each element.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_options_elements_with_required_caps() {
|
||||
return [
|
||||
'emailstudents' => 'mod/customcert:manageemailstudents',
|
||||
'emailteachers' => 'mod/customcert:manageemailteachers',
|
||||
'emailothers' => 'mod/customcert:manageemailothers',
|
||||
'verifyany' => 'mod/customcert:manageverifyany',
|
||||
'requiredtime' => 'mod/customcert:managerequiredtime',
|
||||
'protection_print' => 'mod/customcert:manageprotection',
|
||||
'protection_modify' => 'mod/customcert:manageprotection',
|
||||
'protection_copy' => 'mod/customcert:manageprotection'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a protection data to be able to set to the form.
|
||||
*
|
||||
* @param string $protection Protection sting from database.
|
||||
*
|
||||
* @return \stdClass
|
||||
*/
|
||||
protected function build_protection_data($protection) {
|
||||
$data = new stdClass();
|
||||
|
||||
$data->protection_print = 0;
|
||||
$data->protection_modify = 0;
|
||||
$data->protection_copy = 0;
|
||||
|
||||
$protection = explode(', ', $protection);
|
||||
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_PRINT, $protection)) {
|
||||
$data->protection_print = 1;
|
||||
}
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_MODIFY, $protection)) {
|
||||
$data->protection_modify = 1;
|
||||
}
|
||||
if (in_array(\mod_customcert\certificate::PROTECTION_COPY, $protection)) {
|
||||
$data->protection_copy = 1;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
BIN
pix/download.png
Normal file
BIN
pix/download.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 207 B |
3
pix/download.svg
Normal file
3
pix/download.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M16 9v6c0 .5-.5 1-1 1H1c-.5 0-1-.5-1-1V9c0-.5.5-1 1-1h1c.5 0 1 .5 1 1v4h10V9c0-.5.5-1 1-1h1c.5 0 1 .5 1 1zm-3.6-3.9l-.7-.7c-.4-.4-1-.4-1.4 0l-.8.8V1c0-.5-.4-1-1-1h-1c-.5 0-1 .5-1 1v4.2l-.8-.8c-.4-.4-1-.4-1.4 0l-.7.7c-.4.4-.4 1 0 1.4l3.7 3.7c.2.2.5.3.7.3.3 0 .5-.1.7-.3l3.7-3.7c.4-.3.4-1 0-1.4z" fill="#999"/></svg>
|
After Width: | Height: | Size: 618 B |
|
@ -42,9 +42,18 @@ if ($cm = $template->get_cm()) {
|
|||
// Make sure the user has the required capabilities.
|
||||
$template->require_manage();
|
||||
|
||||
if ($template->get_context()->contextlevel == CONTEXT_MODULE) {
|
||||
$customcert = $DB->get_record('customcert', ['id' => $cm->instance], '*', MUST_EXIST);
|
||||
$title = $customcert->name;
|
||||
$heading = format_string($title);
|
||||
} else {
|
||||
$title = $SITE->fullname;
|
||||
$heading = $title;
|
||||
}
|
||||
|
||||
// Set the $PAGE settings.
|
||||
$pageurl = new moodle_url('/mod/customcert/rearrange.php', array('pid' => $pid));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $template->get_context(), get_string('rearrangeelements', 'customcert'));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $template->get_context(), $title);
|
||||
|
||||
// Add more links to the navigation.
|
||||
if (!$cm = $template->get_cm()) {
|
||||
|
@ -115,7 +124,9 @@ if ($page->rightmargin) {
|
|||
$html .= html_writer::end_tag('div');
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('rearrangeelementsheading', 'customcert'), 4);
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->heading(get_string('rearrangeelementsheading', 'customcert'), 3);
|
||||
echo $OUTPUT->notification(get_string('exampledatawarning', 'customcert'), \core\output\notification::NOTIFY_WARNING);
|
||||
echo $html;
|
||||
$PAGE->requires->js_call_amd('mod_customcert/rearrange-area', 'init', array('#pdf'));
|
||||
echo $OUTPUT->footer();
|
||||
|
|
89
report.php
89
report.php
|
@ -17,6 +17,8 @@
|
|||
/**
|
||||
* Handles viewing a report that shows who has received a customcert.
|
||||
*
|
||||
* This is now just a stub page - all logic has been moved to view.php.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2013 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
@ -25,95 +27,10 @@
|
|||
require_once('../../config.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$download = optional_param('download', null, PARAM_ALPHA);
|
||||
$downloadcert = optional_param('downloadcert', '', PARAM_BOOL);
|
||||
$deleteissue = optional_param('deleteissue', 0, PARAM_INT);
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
if ($downloadcert) {
|
||||
$userid = required_param('userid', PARAM_INT);
|
||||
}
|
||||
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$perpage = optional_param('perpage', \mod_customcert\certificate::CUSTOMCERT_PER_PAGE, PARAM_INT);
|
||||
$pageurl = $url = new moodle_url('/mod/customcert/report.php', array('id' => $id, 'page' => $page, 'perpage' => $perpage));
|
||||
|
||||
$cm = get_coursemodule_from_id('customcert', $id, 0, false, MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
|
||||
$customcert = $DB->get_record('customcert', array('id' => $cm->instance), '*', MUST_EXIST);
|
||||
|
||||
// Requires a course login.
|
||||
require_login($course, false, $cm);
|
||||
|
||||
// Check capabilities.
|
||||
$context = context_module::instance($cm->id);
|
||||
require_capability('mod/customcert:viewreport', $context);
|
||||
|
||||
if ($deleteissue && confirm_sesskey()) {
|
||||
require_capability('mod/customcert:manage', $context);
|
||||
|
||||
if (!$confirm) {
|
||||
$nourl = new moodle_url('/mod/customcert/report.php', ['id' => $id]);
|
||||
$yesurl = new moodle_url('/mod/customcert/report.php',
|
||||
[
|
||||
'id' => $id,
|
||||
'deleteissue' => $deleteissue,
|
||||
'confirm' => 1,
|
||||
'sesskey' => sesskey()
|
||||
]
|
||||
);
|
||||
|
||||
// Show a confirmation page.
|
||||
$strheading = get_string('deleteconfirm', 'customcert');
|
||||
$PAGE->navbar->add($strheading);
|
||||
$PAGE->set_title($strheading);
|
||||
$PAGE->set_url($url);
|
||||
$message = get_string('deleteissueconfirm', 'customcert');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strheading);
|
||||
echo $OUTPUT->confirm($message, $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
|
||||
// Delete the issue.
|
||||
$DB->delete_records('customcert_issues', array('id' => $deleteissue, 'customcertid' => $customcert->id));
|
||||
|
||||
// Redirect back to the manage templates page.
|
||||
redirect(new moodle_url('/mod/customcert/report.php', array('id' => $id)));
|
||||
}
|
||||
|
||||
// Check if we requested to download another user's certificate.
|
||||
if ($downloadcert) {
|
||||
$template = $DB->get_record('customcert_templates', array('id' => $customcert->templateid), '*', MUST_EXIST);
|
||||
$template = new \mod_customcert\template($template);
|
||||
$template->generate_pdf(false, $userid);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if we are in group mode.
|
||||
if ($groupmode = groups_get_activity_groupmode($cm)) {
|
||||
groups_get_activity_group($cm, true);
|
||||
}
|
||||
|
||||
$table = new \mod_customcert\report_table($customcert->id, $cm, $groupmode, $download);
|
||||
$table->define_baseurl($pageurl);
|
||||
|
||||
if ($table->is_downloading()) {
|
||||
$table->download();
|
||||
exit();
|
||||
}
|
||||
|
||||
// Set up the page.
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, get_string('customcertreport', 'customcert'));
|
||||
|
||||
// Additional page setup.
|
||||
$PAGE->navbar->add(get_string('customcertreport', 'customcert'));
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('modulenameplural', 'customcert'));
|
||||
|
||||
groups_print_activity_menu($cm, $url);
|
||||
|
||||
$table->out($perpage, false);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
redirect(new moodle_url('/mod/customcert/view.php', ['id' => $id]));
|
||||
|
|
52
settings.php
52
settings.php
|
@ -25,6 +25,10 @@
|
|||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$url = $CFG->wwwroot . '/mod/customcert/verify_certificate.php';
|
||||
|
||||
$ADMIN->add('modsettings', new admin_category('customcert', get_string('pluginname', 'mod_customcert')));
|
||||
$settings = new admin_settingpage('modsettingcustomcert', new lang_string('customcertsettings', 'mod_customcert'));
|
||||
|
||||
$settings->add(new admin_setting_configcheckbox('customcert/verifyallcertificates',
|
||||
get_string('verifyallcertificates', 'customcert'),
|
||||
get_string('verifyallcertificates_desc', 'customcert', $url),
|
||||
|
@ -35,6 +39,10 @@ $settings->add(new admin_setting_configcheckbox('customcert/showposxy',
|
|||
get_string('showposxy_desc', 'customcert'),
|
||||
0));
|
||||
|
||||
$settings->add(new \mod_customcert\admin_setting_link('customcert/verifycertificate',
|
||||
get_string('verifycertificate', 'customcert'), get_string('verifycertificatedesc', 'customcert'),
|
||||
get_string('verifycertificate', 'customcert'), new moodle_url('/mod/customcert/verify_certificate.php'), ''));
|
||||
|
||||
$settings->add(new \mod_customcert\admin_setting_link('customcert/managetemplates',
|
||||
get_string('managetemplates', 'customcert'), get_string('managetemplatesdesc', 'customcert'),
|
||||
get_string('managetemplates', 'customcert'), new moodle_url('/mod/customcert/manage_templates.php'), ''));
|
||||
|
@ -42,3 +50,47 @@ $settings->add(new \mod_customcert\admin_setting_link('customcert/managetemplate
|
|||
$settings->add(new \mod_customcert\admin_setting_link('customcert/uploadimage',
|
||||
get_string('uploadimage', 'customcert'), get_string('uploadimagedesc', 'customcert'),
|
||||
get_string('uploadimage', 'customcert'), new moodle_url('/mod/customcert/upload_image.php'), ''));
|
||||
|
||||
$settings->add(new admin_setting_heading('defaults',
|
||||
get_string('modeditdefaults', 'admin'), get_string('condifmodeditdefaults', 'admin')));
|
||||
|
||||
$yesnooptions = [
|
||||
0 => get_string('no'),
|
||||
1 => get_string('yes'),
|
||||
];
|
||||
|
||||
$settings->add(new admin_setting_configselect('customcert/emailstudents',
|
||||
get_string('emailstudents', 'customcert'), get_string('emailstudents_help', 'customcert'), 0, $yesnooptions));
|
||||
$settings->add(new admin_setting_configselect('customcert/emailteachers',
|
||||
get_string('emailteachers', 'customcert'), get_string('emailteachers_help', 'customcert'), 0, $yesnooptions));
|
||||
$settings->add(new admin_setting_configtext('customcert/emailothers',
|
||||
get_string('emailothers', 'customcert'), get_string('emailothers_help', 'customcert'), '', PARAM_TEXT));
|
||||
$settings->add(new admin_setting_configselect('customcert/verifyany',
|
||||
get_string('verifycertificateanyone', 'customcert'), get_string('verifycertificateanyone_help', 'customcert'),
|
||||
0, $yesnooptions));
|
||||
$settings->add(new admin_setting_configtext('customcert/requiredtime',
|
||||
get_string('coursetimereq', 'customcert'), get_string('coursetimereq_help', 'customcert'), 0, PARAM_INT));
|
||||
$settings->add(new admin_setting_configcheckbox('customcert/protection_print',
|
||||
get_string('preventprint', 'customcert'),
|
||||
get_string('preventprint_desc', 'customcert'),
|
||||
0));
|
||||
$settings->add(new admin_setting_configcheckbox('customcert/protection_modify',
|
||||
get_string('preventmodify', 'customcert'),
|
||||
get_string('preventmodify_desc', 'customcert'),
|
||||
0));
|
||||
$settings->add(new admin_setting_configcheckbox('customcert/protection_copy',
|
||||
get_string('preventcopy', 'customcert'),
|
||||
get_string('preventcopy_desc', 'customcert'),
|
||||
0));
|
||||
|
||||
$ADMIN->add('customcert', $settings);
|
||||
|
||||
// Element plugin settings.
|
||||
$ADMIN->add('customcert', new admin_category('customcertelements', get_string('elementplugins', 'customcert')));
|
||||
$plugins = \core_plugin_manager::instance()->get_plugins_of_type('customcertelement');
|
||||
foreach ($plugins as $plugin) {
|
||||
$plugin->load_settings($ADMIN, 'customcertelements', $hassiteconfig);
|
||||
}
|
||||
|
||||
// Tell core we already added the settings structure.
|
||||
$settings = null;
|
||||
|
|
|
@ -27,18 +27,18 @@
|
|||
|
||||
Context variables required for this template:
|
||||
* emailgreeting
|
||||
* emailbody
|
||||
* emailbodyplaintext
|
||||
* emailcertificatelink
|
||||
* emailcertificatelinktext
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"emailgreeting": "Dear Angus MacGyver",
|
||||
"emailbody": "Attached is your certificate 'The basics' for the course 'Survival as an '80s action hero'",
|
||||
"emailbodyplaintext": "Attached is your certificate 'The basics' for the course 'Survival as an '80s action hero'",
|
||||
"emailcertificatelink": "http://yoursite.com/mod/customcert/view.php?id=4",
|
||||
"emailcertificatelinktext": "Certificate report"
|
||||
}
|
||||
}}
|
||||
{{{emailgreeting}}}
|
||||
|
||||
{{{emailbody}}}
|
||||
{{{emailbodyplaintext}}}
|
||||
|
|
175
templates/mobile_view_activity_page.mustache
Normal file
175
templates/mobile_view_activity_page.mustache
Normal file
|
@ -0,0 +1,175 @@
|
|||
{{!
|
||||
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"
|
||||
}
|
||||
}}
|
||||
{{=<% %>=}}
|
||||
<div>
|
||||
<core-course-module-description description="<% certificate.intro %>" component="mod_customcert" componentId="<% cmid %>"></core-course-module-description>
|
||||
<%^canmanage%>
|
||||
<%#requiredtimemet%>
|
||||
<ion-item>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col col-6 class="text-left">
|
||||
{{ 'plugin.mod_customcert.receiveddate' | translate }}
|
||||
<br />
|
||||
<div class="timerewarded">
|
||||
<%#issue%>
|
||||
{{ <% timecreated %> | coreToLocaleString }}
|
||||
<%/issue%>
|
||||
<%^issue%>
|
||||
{{ 'plugin.mod_customcert.notissued' | translate }}
|
||||
<%/issue%>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col col-6 class="text-right">
|
||||
<button ion-button icon-only clear [core-download-file]="{fileurl: '<% fileurl %>', timemodified: '<% currenttimestamp %>'}" moduleId="<% cmid %>" courseId="<% certificate.course %>" component="mod_customcert">
|
||||
<ion-icon name="download"></ion-icon>
|
||||
</button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<%/requiredtimemet%>
|
||||
<%^requiredtimemet%>
|
||||
<ion-item>
|
||||
<p>{{ 'plugin.mod_customcert.requiredtimenotmet' | translate: {$a: { requiredtime: <% certificate.requiredtime %>} } }}</p>
|
||||
</ion-item>
|
||||
<%/requiredtimemet%>
|
||||
<%/canmanage%>
|
||||
<%#canmanage%>
|
||||
<ion-item>
|
||||
<button ion-button block core-course-download-module-main-file moduleId="<% cmid %>" courseId="<% certificate.course %>" component="mod_customcert" [files]="[{fileurl: '<% fileurl %>', timemodified: '<% currenttimestamp %>'}]">
|
||||
<ion-icon name="download" item-start></ion-icon>
|
||||
{{ 'plugin.mod_customcert.getcustomcert' | translate }}
|
||||
</button>
|
||||
</ion-item>
|
||||
<%/canmanage%>
|
||||
<%#showreport%>
|
||||
<ion-item>
|
||||
{{ 'plugin.mod_customcert.listofissues' | translate }}
|
||||
</ion-item>
|
||||
<%#showgroups%>
|
||||
<ion-item>
|
||||
<ion-label>{{ 'plugin.mod_customcert.selectagroup' | translate }}</ion-label>
|
||||
<ion-select (ionChange)="updateContent({cmid: <% cmid %>, courseid: <% certificate.course %>, group: $event})" interface="popover">
|
||||
<%#groups%>
|
||||
<ion-option value="<% id %>" <%#selected%>selected<%/selected%>><% name %></ion-option>
|
||||
<%/groups%>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<%/showgroups%>
|
||||
<%#hasrecipients%>
|
||||
<ion-list>
|
||||
<%#recipients%>
|
||||
<ion-item>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col col-6 class="text-left">
|
||||
<% displayname %>
|
||||
<br />
|
||||
<div class="timerewarded">{{ <% timecreated %> | coreToLocaleString }}</div>
|
||||
</ion-col>
|
||||
<ion-col col-6 class="text-right">
|
||||
<button ion-button icon-only clear [core-download-file]="{fileurl: '<% fileurl %>', timemodified: '<% currenttimestamp %>'}" moduleId="<% cmid %>" courseId="<% certificate.course %>" component="mod_customcert">
|
||||
<ion-icon name="download"></ion-icon>
|
||||
</button>
|
||||
<%#canmanage%>
|
||||
<button ion-button icon-only 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">
|
||||
<ion-icon name="trash"></ion-icon>
|
||||
</button>
|
||||
<%/canmanage%>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<%/recipients%>
|
||||
</ion-list>
|
||||
<%/hasrecipients%>
|
||||
<%^hasrecipients%>
|
||||
<ion-item>
|
||||
{{ 'plugin.mod_customcert.nothingtodisplay' | translate }}
|
||||
</ion-item>
|
||||
<%/hasrecipients%>
|
||||
<%/showreport%>
|
||||
</div>
|
142
tests/behat/activtiy_options.feature
Normal file
142
tests/behat/activtiy_options.feature
Normal file
|
@ -0,0 +1,142 @@
|
|||
@mod @mod_customcert
|
||||
Feature: Being able to correctly display options on the certificate activity edit form
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| manager1 | Manager | 1 | Manager1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| manager1 | C1 | manager |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| customcert | Custom certificate 1 | Custom certificate 1 intro | C1 | customcert1 |
|
||||
|
||||
Scenario: Edit an activity as an Editing Teacher I can see all custom certificate options
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Custom certificate 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I should see "Email students"
|
||||
And I should see "Email teachers"
|
||||
And I should see "Email others"
|
||||
And I should see "Allow anyone to verify a certificate"
|
||||
And I should see "Required minutes in course"
|
||||
And I should see "Set protection"
|
||||
|
||||
Scenario: Create an activity as an Editing Teacher I can see all custom certificate options
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Custom certificate" to section "1"
|
||||
And I should see "Email students"
|
||||
And I should see "Email teachers"
|
||||
And I should see "Email others"
|
||||
And I should see "Allow anyone to verify a certificate"
|
||||
And I should see "Required minutes in course"
|
||||
And I should see "Set protection"
|
||||
|
||||
Scenario: Add an activity as a Manager I can see all custom certificate options
|
||||
And I log in as "manager1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Custom certificate" to section "1"
|
||||
And I should see "Email students"
|
||||
And I should see "Email teachers"
|
||||
And I should see "Email others"
|
||||
And I should see "Allow anyone to verify a certificate"
|
||||
And I should see "Required minutes in course"
|
||||
And I should see "Set protection"
|
||||
|
||||
Scenario: Edit an activity as a Manager Teacher I can see all custom certificate options
|
||||
And I log in as "manager1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Custom certificate 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I should see "Email students"
|
||||
And I should see "Email teachers"
|
||||
And I should see "Email others"
|
||||
And I should see "Allow anyone to verify a certificate"
|
||||
And I should see "Required minutes in course"
|
||||
And I should see "Set protection"
|
||||
|
||||
Scenario: Create an activity as an Editing Teacher without required capabilities I can't see all custom certificate options
|
||||
And I log in as "admin"
|
||||
And I set the following system permissions of "Teacher" role:
|
||||
| capability | permission |
|
||||
| mod/customcert:manageemailstudents | Prevent |
|
||||
| mod/customcert:manageemailteachers | Prevent |
|
||||
| mod/customcert:manageemailothers | Prevent |
|
||||
| mod/customcert:manageverifyany | Prevent |
|
||||
| mod/customcert:managerequiredtime | Prevent |
|
||||
| mod/customcert:manageprotection | Prevent |
|
||||
And I log out
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Custom certificate" to section "1"
|
||||
And I should not see "Email students"
|
||||
And I should not see "Email teachers"
|
||||
And I should not see "Email others"
|
||||
And I should not see "Allow anyone to verify a certificate"
|
||||
And I should not see "Required minutes in course"
|
||||
And I should not see "Set protection"
|
||||
|
||||
Scenario: Edit an activity as an Editing Teacher without required capabilities I can't see all custom certificate options
|
||||
And I log in as "admin"
|
||||
And I set the following system permissions of "Teacher" role:
|
||||
| capability | permission |
|
||||
| mod/customcert:manageemailstudents | Prevent |
|
||||
| mod/customcert:manageemailteachers | Prevent |
|
||||
| mod/customcert:manageemailothers | Prevent |
|
||||
| mod/customcert:manageverifyany | Prevent |
|
||||
| mod/customcert:managerequiredtime | Prevent |
|
||||
| mod/customcert:manageprotection | Prevent |
|
||||
And I log out
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Custom certificate 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I should not see "Email students"
|
||||
And I should not see "Email teachers"
|
||||
And I should not see "Email others"
|
||||
And I should not see "Allow anyone to verify a certificate"
|
||||
And I should not see "Required minutes in course"
|
||||
And I should not see "Set protection"
|
||||
|
||||
Scenario: Add an activity using default custom certificate options
|
||||
And I log in as "manager1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Custom certificate" to section "0"
|
||||
And the field "emailstudents" matches value "0"
|
||||
And the field "emailteachers" matches value "0"
|
||||
And the field "emailothers" matches value ""
|
||||
And the field "verifyany" matches value "0"
|
||||
And the field "requiredtime" matches value "0"
|
||||
And the field "protection_print" matches value "0"
|
||||
And the field "protection_modify" matches value "0"
|
||||
And the field "protection_copy" matches value "0"
|
||||
|
||||
Scenario: Add an activity using configured custom certificate options
|
||||
And the following config values are set as admin:
|
||||
| emailstudents | 1 | customcert |
|
||||
| emailteachers | 1 | customcert |
|
||||
| emailothers | test@moodle.com | customcert |
|
||||
| verifyany | 1 | customcert |
|
||||
| requiredtime | 5 | customcert |
|
||||
| protection_print | 1 | customcert |
|
||||
| protection_modify | 1 | customcert |
|
||||
| protection_copy | 1 | customcert |
|
||||
And I log in as "manager1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Custom certificate" to section "1"
|
||||
And the field "emailstudents" matches value "1"
|
||||
And the field "emailteachers" matches value "1"
|
||||
And the field "emailothers" matches value "test@moodle.com"
|
||||
And the field "verifyany" matches value "1"
|
||||
And the field "requiredtime" matches value "5"
|
||||
And the field "protection_print" matches value "1"
|
||||
And the field "protection_modify" matches value "1"
|
||||
And the field "protection_copy" matches value "1"
|
|
@ -186,14 +186,16 @@ Feature: Being able to manage elements in a certificate template
|
|||
# Image.
|
||||
And I add the element "Image" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
| Width | 25 |
|
||||
| Height | 15 |
|
||||
| Width | 25 |
|
||||
| Height | 15 |
|
||||
| Alpha channel | 0.7 |
|
||||
And I press "Save changes"
|
||||
And I should see "Image" in the "elementstable" "table"
|
||||
And I click on ".edit-icon" "css_element" in the "Image" "table_row"
|
||||
And the following fields match these values:
|
||||
| Width | 25 |
|
||||
| Height | 15 |
|
||||
| Width | 25 |
|
||||
| Height | 15 |
|
||||
| Alpha channel | 0.7 |
|
||||
And I press "Save changes"
|
||||
# Student name.
|
||||
And I add the element "Student name" to page "1" of the "Custom certificate 1" certificate template
|
||||
|
|
|
@ -25,14 +25,14 @@ Feature: Being able to view the certificates you have been issued
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I follow "Profile" in the user menu
|
||||
And I follow "My certificates"
|
||||
And I should see "Custom certificate 1"
|
||||
And I should not see "Custom certificate 2"
|
||||
And I am on "Course 2" course homepage
|
||||
And I follow "Custom certificate 2"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I follow "Profile" in the user menu
|
||||
And I follow "My certificates"
|
||||
And I should see "Custom certificate 1"
|
||||
|
|
|
@ -25,7 +25,7 @@ Feature: Being able to set the required minutes in a course before viewing the c
|
|||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I should see "You must spend at least a minimum of"
|
||||
And I should not see "Download certificate"
|
||||
And I should not see "View certificate"
|
||||
And I press "Continue"
|
||||
And I should see "Custom certificate 1"
|
||||
|
||||
|
@ -36,4 +36,4 @@ Feature: Being able to set the required minutes in a course before viewing the c
|
|||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I should not see "You must spend at least a minimum of"
|
||||
And I should see "Download certificate"
|
||||
And I should see "View certificate"
|
||||
|
|
|
@ -25,7 +25,7 @@ Feature: Being able to verify that a certificate is valid or not
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
|
@ -45,7 +45,7 @@ Feature: Being able to verify that a certificate is valid or not
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 2"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I visit the verification url for the "Custom certificate 2" certificate
|
||||
And I set the field "Code" to "NOTAVALIDCODE"
|
||||
|
@ -74,10 +74,10 @@ Feature: Being able to verify that a certificate is valid or not
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 2"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I log in as "admin"
|
||||
# The admin (or anyone with the capability 'mod/customcert:verifyallcertificates') can visit the URL regardless of the setting.
|
||||
|
@ -95,10 +95,10 @@ Feature: Being able to verify that a certificate is valid or not
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 2"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I visit the verification url for the site
|
||||
And I set the field "Code" to "NOTAVALIDCODE"
|
||||
|
|
|
@ -26,17 +26,16 @@ Feature: Being able to view the certificates that have been issued
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I follow "View 2 issued certificates"
|
||||
And I should see "Student 1"
|
||||
And I should see "Student 2"
|
||||
|
||||
|
@ -44,17 +43,16 @@ Feature: Being able to view the certificates that have been issued
|
|||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I press "Download certificate"
|
||||
And I press "View certificate"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Custom certificate 1"
|
||||
And I follow "View 2 issued certificates"
|
||||
And I should see "Student 1"
|
||||
And I should see "Student 2"
|
||||
And I click on ".delete-icon" "css_element" in the "Student 2" "table_row"
|
||||
|
|
|
@ -101,6 +101,64 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
$this->assertEquals($SITE->id, \mod_customcert\element_helper::get_courseid($element->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests we are returning the correct course module id for an element in a course customcert activity.
|
||||
*/
|
||||
public function test_get_context_element_in_course_certificate() {
|
||||
global $DB;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create a custom certificate in the course.
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
|
||||
|
||||
// Get the template to add elements to.
|
||||
$template = $DB->get_record('customcert_templates', array('contextid' => context_module::instance($customcert->cmid)->id));
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to the template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to this page.
|
||||
$element = new \stdClass();
|
||||
$element->name = 'Test element';
|
||||
$element->element = 'testelement';
|
||||
$element->pageid = $pageid;
|
||||
$element->sequence = \mod_customcert\element_helper::get_element_sequence($element->pageid);
|
||||
$element->timecreated = time();
|
||||
$element->id = $DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Confirm the correct course module id is returned.
|
||||
$this->assertEquals(context_module::instance($customcert->cmid),
|
||||
\mod_customcert\element_helper::get_context($element->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests we are returning the correct course module id for an element in a site template.
|
||||
*/
|
||||
public function test_get_context_element_in_site_template() {
|
||||
global $DB;
|
||||
|
||||
// Add a template to the site.
|
||||
$template = \mod_customcert\template::create('Site template', context_system::instance()->id);
|
||||
|
||||
// Add a page to the template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to this page.
|
||||
$element = new \stdClass();
|
||||
$element->name = 'Test element';
|
||||
$element->element = 'testelement';
|
||||
$element->pageid = $pageid;
|
||||
$element->sequence = \mod_customcert\element_helper::get_element_sequence($element->pageid);
|
||||
$element->timecreated = time();
|
||||
$element->id = $DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Confirm the correct course module id is returned.
|
||||
$this->assertEquals(context_system::instance(), \mod_customcert\element_helper::get_context($element->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test we return the correct grade items in a course.
|
||||
*/
|
||||
|
@ -136,6 +194,11 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
* Test we return the correct grade information for an activity.
|
||||
*/
|
||||
public function test_get_mod_grade_info() {
|
||||
global $CFG;
|
||||
|
||||
// Set that we want 3 decimals to display.
|
||||
$CFG->grade_decimalpoints = 3;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
|
@ -181,7 +244,7 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
|
||||
$this->assertEquals($assign->name, $grade->get_name());
|
||||
$this->assertEquals('50.00000', $grade->get_grade());
|
||||
$this->assertEquals('50 %', $grade->get_displaygrade());
|
||||
$this->assertEquals('50.000 %', $grade->get_displaygrade());
|
||||
$this->assertEquals($time, $grade->get_dategraded());
|
||||
|
||||
// Check that the user we did not grade has no grade.
|
||||
|
@ -205,6 +268,9 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
// Including to use constant.
|
||||
require_once($CFG->dirroot . '/mod/customcert/element/grade/classes/element.php');
|
||||
|
||||
// Set that we want 3 decimals to display.
|
||||
$CFG->grade_decimalpoints = 3;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
|
@ -241,7 +307,7 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
|
||||
$this->assertEquals(get_string('coursetotal', 'grades'), $grade->get_name());
|
||||
$this->assertEquals('50.00000', $grade->get_grade());
|
||||
$this->assertEquals('50 %', $grade->get_displaygrade());
|
||||
$this->assertEquals('50.000 %', $grade->get_displaygrade());
|
||||
$this->assertEquals($time, $grade->get_dategraded());
|
||||
|
||||
// Check that the user we did not grade has no grade.
|
||||
|
@ -260,6 +326,11 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
* Test we return the correct grade information for a grade item.
|
||||
*/
|
||||
public function test_get_grade_item_info() {
|
||||
global $CFG;
|
||||
|
||||
// Set that we want 3 decimals to display.
|
||||
$CFG->grade_decimalpoints = 3;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
|
@ -298,7 +369,7 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
|
||||
$this->assertEquals('Grade item yo', $grade->get_name());
|
||||
$this->assertEquals('50.00000', $grade->get_grade());
|
||||
$this->assertEquals('50 %', $grade->get_displaygrade());
|
||||
$this->assertEquals('50.000 %', $grade->get_displaygrade());
|
||||
$this->assertEquals($time, $grade->get_dategraded());
|
||||
|
||||
// Check that the user we did not grade has no grade.
|
||||
|
|
|
@ -71,15 +71,7 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
'emailstudents' => 1));
|
||||
|
||||
// Ok, now issue this to one user.
|
||||
$customcertissue = new stdClass();
|
||||
$customcertissue->customcertid = $customcert->id;
|
||||
$customcertissue->userid = $user1->id;
|
||||
$customcertissue->code = \mod_customcert\certificate::generate_code();
|
||||
$customcertissue->timecreated = time();
|
||||
$customcertissue->emailed = 0;
|
||||
|
||||
// Insert the record into the database.
|
||||
$DB->insert_record('customcert_issues', $customcertissue);
|
||||
\mod_customcert\certificate::issue_certificate($customcert->id, $user1->id);
|
||||
|
||||
// Confirm there is only one entry in this table.
|
||||
$this->assertEquals(1, $DB->count_records('customcert_issues'));
|
||||
|
|
150
tests/external_test.php
Normal file
150
tests/external_test.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File contains the unit tests for the webservices.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @category test
|
||||
* @copyright 2018 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
/**
|
||||
* Unit tests for the webservices.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @category test
|
||||
* @copyright 2018 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_customcert_external_test_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete_issue web service.
|
||||
*/
|
||||
public function test_delete_issue() {
|
||||
global $DB;
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create a custom certificate in the course.
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
|
||||
|
||||
// Create two users.
|
||||
$student1 = $this->getDataGenerator()->create_user();
|
||||
$student2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
// Enrol them into the course.
|
||||
$this->getDataGenerator()->enrol_user($student1->id, $course->id);
|
||||
$this->getDataGenerator()->enrol_user($student2->id, $course->id);
|
||||
|
||||
// Issue them both certificates.
|
||||
$i1 = \mod_customcert\certificate::issue_certificate($customcert->id, $student1->id);
|
||||
$i2 = \mod_customcert\certificate::issue_certificate($customcert->id, $student2->id);
|
||||
|
||||
$this->assertEquals(2, $DB->count_records('customcert_issues'));
|
||||
|
||||
$result = \mod_customcert\external::delete_issue($customcert->id, $i2);
|
||||
|
||||
// We need to execute the return values cleaning process to simulate the web service server.
|
||||
external_api::clean_returnvalue(\mod_customcert\external::delete_issue_returns(), $result);
|
||||
|
||||
$issues = $DB->get_records('customcert_issues');
|
||||
$this->assertCount(1, $issues);
|
||||
|
||||
$issue = reset($issues);
|
||||
$this->assertEquals($student1->id, $issue->userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete_issue web service.
|
||||
*/
|
||||
public function test_delete_issue_no_login() {
|
||||
global $DB;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create a custom certificate in the course.
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
|
||||
|
||||
// Create two users.
|
||||
$student1 = $this->getDataGenerator()->create_user();
|
||||
$student2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
// Enrol them into the course.
|
||||
$this->getDataGenerator()->enrol_user($student1->id, $course->id);
|
||||
$this->getDataGenerator()->enrol_user($student2->id, $course->id);
|
||||
|
||||
// Issue them both certificates.
|
||||
$i1 = \mod_customcert\certificate::issue_certificate($customcert->id, $student1->id);
|
||||
$i2 = \mod_customcert\certificate::issue_certificate($customcert->id, $student2->id);
|
||||
|
||||
$this->assertEquals(2, $DB->count_records('customcert_issues'));
|
||||
|
||||
// Try and delete without logging in.
|
||||
$this->expectException('require_login_exception');
|
||||
\mod_customcert\external::delete_issue($customcert->id, $i2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete_issue web service.
|
||||
*/
|
||||
public function test_delete_issue_no_capability() {
|
||||
global $DB;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create a custom certificate in the course.
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
|
||||
|
||||
// Create two users.
|
||||
$student1 = $this->getDataGenerator()->create_user();
|
||||
$student2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->setUser($student1);
|
||||
|
||||
// Enrol them into the course.
|
||||
$this->getDataGenerator()->enrol_user($student1->id, $course->id);
|
||||
$this->getDataGenerator()->enrol_user($student2->id, $course->id);
|
||||
|
||||
// Issue them both certificates.
|
||||
$i1 = \mod_customcert\certificate::issue_certificate($customcert->id, $student1->id);
|
||||
$i2 = \mod_customcert\certificate::issue_certificate($customcert->id, $student2->id);
|
||||
|
||||
$this->assertEquals(2, $DB->count_records('customcert_issues'));
|
||||
|
||||
// Try and delete without the required capability.
|
||||
$this->expectException('required_capability_exception');
|
||||
\mod_customcert\external::delete_issue($customcert->id, $i2);
|
||||
}
|
||||
}
|
|
@ -64,6 +64,57 @@ class mod_customcert_privacy_provider_testcase extends \core_privacy\tests\provi
|
|||
$this->assertEquals($cmcontext->id, $contextformodule->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::get_users_in_context().
|
||||
*/
|
||||
public function test_get_users_in_context() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// The customcert activity the user will have an issue from.
|
||||
$customcert1 = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
|
||||
$customcert2 = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]);
|
||||
|
||||
// Call get_users_in_context() when the customcert hasn't any user.
|
||||
$cm = get_coursemodule_from_instance('customcert', $customcert1->id);
|
||||
$cmcontext = context_module::instance($cm->id);
|
||||
$userlist = new \core_privacy\local\request\userlist($cmcontext, 'mod_customcert');
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
// Check no user has been returned.
|
||||
$this->assertCount(0, $userlist->get_userids());
|
||||
|
||||
// Create some users who will be issued a certificate.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->create_certificate_issue($customcert1->id, $user1->id);
|
||||
$this->create_certificate_issue($customcert1->id, $user2->id);
|
||||
$this->create_certificate_issue($customcert2->id, $user3->id);
|
||||
|
||||
// Call get_users_in_context() again.
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
// Check this time there are 2 users.
|
||||
$this->assertCount(2, $userlist->get_userids());
|
||||
$this->assertContains($user1->id, $userlist->get_userids());
|
||||
$this->assertContains($user2->id, $userlist->get_userids());
|
||||
$this->assertNotContains($user3->id, $userlist->get_userids());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::get_users_in_context() with invalid context type.
|
||||
*/
|
||||
public function test_get_users_in_context_invalid_context_type() {
|
||||
$systemcontext = context_system::instance();
|
||||
|
||||
$userlist = new \core_privacy\local\request\userlist($systemcontext, 'mod_customcert');
|
||||
\mod_customcert\privacy\provider::get_users_in_context($userlist);
|
||||
|
||||
$this->assertCount(0, $userlist->get_userids());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::export_user_data().
|
||||
*/
|
||||
|
@ -179,6 +230,52 @@ class mod_customcert_privacy_provider_testcase extends \core_privacy\tests\provi
|
|||
$this->assertEquals($user2->id, $lastissue->userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::delete_data_for_users().
|
||||
*/
|
||||
public function test_delete_data_for_users() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course, customcert and users who will be issued a certificate.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$customcert1 = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
|
||||
$customcert2 = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id));
|
||||
$cm1 = get_coursemodule_from_instance('customcert', $customcert1->id);
|
||||
$cm2 = get_coursemodule_from_instance('customcert', $customcert2->id);
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->create_certificate_issue($customcert1->id, $user1->id);
|
||||
$this->create_certificate_issue($customcert1->id, $user2->id);
|
||||
$this->create_certificate_issue($customcert1->id, $user3->id);
|
||||
$this->create_certificate_issue($customcert2->id, $user1->id);
|
||||
$this->create_certificate_issue($customcert2->id, $user2->id);
|
||||
|
||||
// Before deletion we should have 3 + 2 issued certificates.
|
||||
$count = $DB->count_records('customcert_issues', ['customcertid' => $customcert1->id]);
|
||||
$this->assertEquals(3, $count);
|
||||
$count = $DB->count_records('customcert_issues', ['customcertid' => $customcert2->id]);
|
||||
$this->assertEquals(2, $count);
|
||||
|
||||
$context1 = context_module::instance($cm1->id);
|
||||
$approveduserlist = new \core_privacy\local\request\approved_userlist($context1, 'customcert',
|
||||
[$user1->id, $user2->id]);
|
||||
provider::delete_data_for_users($approveduserlist);
|
||||
|
||||
// After deletion, the customcert of the 2 students provided above should have been deleted
|
||||
// from the activity. So there should only remain 1 certificate which is for $user3.
|
||||
$customcertissues1 = $DB->get_records('customcert_issues', ['customcertid' => $customcert1->id]);
|
||||
$this->assertCount(1, $customcertissues1);
|
||||
$lastissue = reset($customcertissues1);
|
||||
$this->assertEquals($user3->id, $lastissue->userid);
|
||||
|
||||
// Confirm that the certificates issues in the other activity are intact.
|
||||
$customcertissues1 = $DB->get_records('customcert_issues', ['customcertid' => $customcert2->id]);
|
||||
$this->assertCount(2, $customcertissues1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimicks the creation of a customcert issue.
|
||||
*
|
||||
|
|
|
@ -33,7 +33,7 @@ $struploadimage = get_string('uploadimage', 'customcert');
|
|||
|
||||
// Set the page variables.
|
||||
$pageurl = new moodle_url('/mod/customcert/upload_image.php');
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, $struploadimage, $SITE->fullname);
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, $SITE->fullname);
|
||||
|
||||
// Additional page setup.
|
||||
$PAGE->navbar->add($struploadimage);
|
||||
|
@ -50,5 +50,6 @@ if ($uploadform->is_cancelled()) {
|
|||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($SITE->fullname);
|
||||
$uploadform->display();
|
||||
echo $OUTPUT->footer();
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// This file does not need require_login because capability to verify can be granted to guests, skip codechecker here.
|
||||
// @codingStandardsIgnoreLine
|
||||
require_once('../../config.php');
|
||||
|
||||
|
@ -33,6 +34,10 @@ $context = context::instance_by_id($contextid);
|
|||
// Set up the page.
|
||||
$pageurl = new moodle_url('/mod/customcert/verify_certificate.php', array('contextid' => $contextid));
|
||||
|
||||
if ($code) {
|
||||
$pageurl->param('code', $code);
|
||||
}
|
||||
|
||||
// Ok, a certificate was specified.
|
||||
if ($context->contextlevel != CONTEXT_SYSTEM) {
|
||||
$cm = get_coursemodule_from_id('customcert', $context->instanceid, 0, false, MUST_EXIST);
|
||||
|
@ -49,36 +54,36 @@ if ($context->contextlevel != CONTEXT_SYSTEM) {
|
|||
$PAGE->set_cm($cm, $course);
|
||||
}
|
||||
|
||||
$title = $customcert->name;
|
||||
$heading = format_string($title);
|
||||
$checkallofsite = false;
|
||||
} else {
|
||||
$title = $SITE->fullname;
|
||||
$heading = $title;
|
||||
$checkallofsite = true;
|
||||
}
|
||||
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, $title);
|
||||
|
||||
// Additional page setup.
|
||||
if ($context->contextlevel == CONTEXT_SYSTEM) {
|
||||
$PAGE->navbar->add(get_string('verifycertificate', 'customcert'));
|
||||
}
|
||||
|
||||
if ($checkallofsite) {
|
||||
// If the 'verifyallcertificates' is not set and the user does not have the capability 'mod/customcert:verifyallcertificates'
|
||||
// then show them a message letting them know they can not proceed.
|
||||
$verifyallcertificates = get_config('customcert', 'verifyallcertificates');
|
||||
$canverifyallcertificates = has_capability('mod/customcert:verifyallcertificates', $context);
|
||||
if (!$verifyallcertificates && !$canverifyallcertificates) {
|
||||
$strheading = get_string('verifycertificate', 'customcert');
|
||||
$PAGE->navbar->add($strheading);
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->set_title($strheading);
|
||||
$PAGE->set_url($pageurl);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strheading);
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $OUTPUT->notification(get_string('cannotverifyallcertificates', 'customcert'));
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
|
||||
$checkallofsite = true;
|
||||
}
|
||||
|
||||
if ($code) {
|
||||
$pageurl->param('code', $code);
|
||||
}
|
||||
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_title(get_string('verifycertificate', 'customcert'));
|
||||
|
||||
// The form we are using to verify these codes.
|
||||
$form = new \mod_customcert\verify_certificate_form($pageurl);
|
||||
|
||||
|
@ -89,7 +94,8 @@ if ($form->get_data()) {
|
|||
// Ok, now check if the code is valid.
|
||||
$userfields = get_all_user_name_fields(true, 'u');
|
||||
$sql = "SELECT ci.id, u.id as userid, $userfields, co.id as courseid,
|
||||
co.fullname as coursefullname, c.name as certificatename, c.verifyany
|
||||
co.fullname as coursefullname, c.id as certificateid,
|
||||
c.name as certificatename, c.verifyany
|
||||
FROM {customcert} c
|
||||
JOIN {customcert_issues} ci
|
||||
ON c.id = ci.customcertid
|
||||
|
@ -110,8 +116,6 @@ if ($form->get_data()) {
|
|||
$params = ['code' => $code, 'customcertid' => $customcert->id];
|
||||
}
|
||||
|
||||
$sql .= " AND u.deleted = 0";
|
||||
|
||||
// It is possible (though unlikely) that there is the same code for issued certificates.
|
||||
if ($issues = $DB->get_records_sql($sql, $params)) {
|
||||
$result->success = true;
|
||||
|
@ -123,7 +127,7 @@ if ($form->get_data()) {
|
|||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('verifycertificate', 'customcert'));
|
||||
echo $OUTPUT->heading($heading);
|
||||
echo $form->display();
|
||||
if (isset($result)) {
|
||||
$renderer = $PAGE->get_renderer('mod_customcert');
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
|
||||
$plugin->version = 2017111301; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2017111308; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2017111300; // Requires this Moodle version (3.4).
|
||||
$plugin->cron = 0; // Period for cron to check this module (secs).
|
||||
$plugin->component = 'mod_customcert';
|
||||
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
$plugin->release = "3.4 release (Build: 2017111301)"; // User-friendly version number.
|
||||
$plugin->release = "3.4.7"; // User-friendly version number.
|
||||
|
|
137
view.php
137
view.php
|
@ -25,7 +25,13 @@
|
|||
require_once('../../config.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$action = optional_param('action', '', PARAM_ALPHA);
|
||||
$downloadown = optional_param('downloadown', false, PARAM_BOOL);
|
||||
$downloadtable = optional_param('download', null, PARAM_ALPHA);
|
||||
$downloadissue = optional_param('downloadissue', 0, PARAM_INT);
|
||||
$deleteissue = optional_param('deleteissue', 0, PARAM_INT);
|
||||
$confirm = optional_param('confirm', false, PARAM_BOOL);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$perpage = optional_param('perpage', \mod_customcert\certificate::CUSTOMCERT_PER_PAGE, PARAM_INT);
|
||||
|
||||
$cm = get_coursemodule_from_id('customcert', $id, 0, false, MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
|
||||
|
@ -37,12 +43,15 @@ require_login($course, false, $cm);
|
|||
$context = context_module::instance($cm->id);
|
||||
require_capability('mod/customcert:view', $context);
|
||||
|
||||
$canmanage = has_capability('mod/customcert:manage', $context);
|
||||
$canviewreport = has_capability('mod/customcert:viewreport', $context);
|
||||
|
||||
// Initialise $PAGE.
|
||||
$pageurl = new moodle_url('/mod/customcert/view.php', array('id' => $cm->id));
|
||||
\mod_customcert\page_helper::page_setup($pageurl, $context, format_string($customcert->name));
|
||||
|
||||
// Check if the user can view the certificate based on time spent in course.
|
||||
if ($customcert->requiredtime && !has_capability('mod/customcert:manage', $context)) {
|
||||
if ($customcert->requiredtime && !$canmanage) {
|
||||
if (\mod_customcert\certificate::get_course_time($course->id) < ($customcert->requiredtime * 60)) {
|
||||
$a = new stdClass;
|
||||
$a->requiredtime = $customcert->requiredtime;
|
||||
|
@ -51,6 +60,36 @@ if ($customcert->requiredtime && !has_capability('mod/customcert:manage', $conte
|
|||
}
|
||||
}
|
||||
|
||||
// Check if we are deleting an issue.
|
||||
if ($deleteissue && $canmanage && confirm_sesskey()) {
|
||||
if (!$confirm) {
|
||||
$nourl = new moodle_url('/mod/customcert/view.php', ['id' => $id]);
|
||||
$yesurl = new moodle_url('/mod/customcert/view.php',
|
||||
[
|
||||
'id' => $id,
|
||||
'deleteissue' => $deleteissue,
|
||||
'confirm' => 1,
|
||||
'sesskey' => sesskey()
|
||||
]
|
||||
);
|
||||
|
||||
// Show a confirmation page.
|
||||
$PAGE->navbar->add(get_string('deleteconfirm', 'customcert'));
|
||||
$message = get_string('deleteissueconfirm', 'customcert');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(format_string($customcert->name));
|
||||
echo $OUTPUT->confirm($message, $yesurl, $nourl);
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
|
||||
// Delete the issue.
|
||||
$DB->delete_records('customcert_issues', array('id' => $deleteissue, 'customcertid' => $customcert->id));
|
||||
|
||||
// Redirect back to the manage templates page.
|
||||
redirect(new moodle_url('/mod/customcert/view.php', array('id' => $id)));
|
||||
}
|
||||
|
||||
$event = \mod_customcert\event\course_module_viewed::create(array(
|
||||
'objectid' => $customcert->id,
|
||||
'context' => $context,
|
||||
|
@ -59,22 +98,23 @@ $event->add_record_snapshot('course', $course);
|
|||
$event->add_record_snapshot('customcert', $customcert);
|
||||
$event->trigger();
|
||||
|
||||
// Check that no action was passed, if so that means we are not outputting to PDF.
|
||||
if (empty($action)) {
|
||||
// Check that we are not downloading a certificate PDF.
|
||||
if (!$downloadown && !$downloadissue) {
|
||||
// Get the current groups mode.
|
||||
if ($groupmode = groups_get_activity_groupmode($cm)) {
|
||||
groups_get_activity_group($cm, true);
|
||||
}
|
||||
|
||||
// Generate the link to the report if there are issues to display.
|
||||
$reportlink = '';
|
||||
if (has_capability('mod/customcert:viewreport', $context)) {
|
||||
// Generate the table to the report if there are issues to display.
|
||||
if ($canviewreport) {
|
||||
// Get the total number of issues.
|
||||
$numissues = \mod_customcert\certificate::get_number_of_issues($customcert->id, $cm, $groupmode);
|
||||
$href = new moodle_urL('/mod/customcert/report.php', array('id' => $cm->id));
|
||||
$url = html_writer::tag('a', get_string('viewcustomcertissues', 'customcert', $numissues),
|
||||
array('href' => $href->out()));
|
||||
$reportlink = html_writer::tag('div', $url, array('class' => 'reportlink'));
|
||||
$reporttable = new \mod_customcert\report_table($customcert->id, $cm, $groupmode, $downloadtable);
|
||||
$reporttable->define_baseurl($pageurl);
|
||||
|
||||
if ($reporttable->is_downloading()) {
|
||||
$reporttable->download();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the intro content if it exists.
|
||||
|
@ -84,55 +124,50 @@ if (empty($action)) {
|
|||
}
|
||||
|
||||
// If the current user has been issued a customcert generate HTML to display the details.
|
||||
$issuelist = '';
|
||||
if ($issues = $DB->get_records('customcert_issues', array('userid' => $USER->id, 'customcertid' => $customcert->id))) {
|
||||
$header = $OUTPUT->heading(get_string('summaryofissue', 'customcert'));
|
||||
|
||||
$table = new html_table();
|
||||
$table->class = 'generaltable';
|
||||
$table->head = array(get_string('issued', 'customcert'));
|
||||
$table->align = array('left');
|
||||
$table->attributes = array('style' => 'width:20%; margin:auto');
|
||||
|
||||
foreach ($issues as $issue) {
|
||||
$row = array();
|
||||
$row[] = userdate($issue->timecreated);
|
||||
$table->data[$issue->id] = $row;
|
||||
}
|
||||
|
||||
$issuelist = $header . html_writer::table($table) . "<br />";
|
||||
$issuehtml = '';
|
||||
$issues = $DB->get_records('customcert_issues', array('userid' => $USER->id, 'customcertid' => $customcert->id));
|
||||
if ($issues && !$canmanage) {
|
||||
// Get the most recent issue (there should only be one).
|
||||
$issue = reset($issues);
|
||||
$issuestring = get_string('receiveddate', 'customcert') . ': ' . userdate($issue->timecreated);
|
||||
$issuehtml = $OUTPUT->box($issuestring);
|
||||
}
|
||||
|
||||
// Create the button to download the customcert.
|
||||
$linkname = get_string('getcustomcert', 'customcert');
|
||||
$link = new moodle_url('/mod/customcert/view.php', array('id' => $cm->id, 'action' => 'download'));
|
||||
$downloadbutton = new single_button($link, $linkname);
|
||||
$downloadbutton = html_writer::tag('div', $OUTPUT->render($downloadbutton), array('style' => 'text-align:center'));
|
||||
$link = new moodle_url('/mod/customcert/view.php', array('id' => $cm->id, 'downloadown' => true));
|
||||
$downloadbutton = new single_button($link, $linkname, 'post', true);
|
||||
$downloadbutton->class .= ' m-b-1'; // Seems a bit hackish, ahem.
|
||||
$downloadbutton = $OUTPUT->render($downloadbutton);
|
||||
|
||||
// Output all the page data.
|
||||
echo $OUTPUT->header();
|
||||
groups_print_activity_menu($cm, $pageurl);
|
||||
echo $reportlink;
|
||||
echo $OUTPUT->heading(format_string($customcert->name));
|
||||
echo $intro;
|
||||
echo $issuelist;
|
||||
echo $issuehtml;
|
||||
echo $downloadbutton;
|
||||
echo $OUTPUT->footer($course);
|
||||
exit;
|
||||
} else { // Output to pdf.
|
||||
// Create new customcert issue record if one does not already exist.
|
||||
if (!$DB->record_exists('customcert_issues', array('userid' => $USER->id, 'customcertid' => $customcert->id))) {
|
||||
$customcertissue = new stdClass();
|
||||
$customcertissue->customcertid = $customcert->id;
|
||||
$customcertissue->userid = $USER->id;
|
||||
$customcertissue->code = \mod_customcert\certificate::generate_code();
|
||||
$customcertissue->timecreated = time();
|
||||
// Insert the record into the database.
|
||||
$DB->insert_record('customcert_issues', $customcertissue);
|
||||
if (isset($reporttable)) {
|
||||
echo $OUTPUT->heading(get_string('listofissues', 'customcert'), 3);
|
||||
groups_print_activity_menu($cm, $pageurl);
|
||||
echo $reporttable->out($perpage, false);
|
||||
}
|
||||
echo $OUTPUT->footer($course);
|
||||
exit();
|
||||
} else { // Output to pdf.
|
||||
// Set the userid value of who we are downloading the certificate for.
|
||||
$userid = $USER->id;
|
||||
if ($downloadown) {
|
||||
// Create new customcert issue record if one does not already exist.
|
||||
if (!$DB->record_exists('customcert_issues', array('userid' => $USER->id, 'customcertid' => $customcert->id))) {
|
||||
\mod_customcert\certificate::issue_certificate($customcert->id, $USER->id);
|
||||
}
|
||||
|
||||
// Set the custom certificate as viewed.
|
||||
$completion = new completion_info($course);
|
||||
$completion->set_module_viewed($cm);
|
||||
// Set the custom certificate as viewed.
|
||||
$completion = new completion_info($course);
|
||||
$completion->set_module_viewed($cm);
|
||||
} else if ($downloadissue && $canviewreport) {
|
||||
$userid = $downloadissue;
|
||||
}
|
||||
|
||||
// Hack alert - don't initiate the download when running Behat.
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
|
@ -141,6 +176,6 @@ if (empty($action)) {
|
|||
|
||||
// Now we want to generate the PDF.
|
||||
$template = new \mod_customcert\template($template);
|
||||
$template->generate_pdf();
|
||||
$template->generate_pdf(false, $userid);
|
||||
exit();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue