first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+330
View File
@@ -0,0 +1,330 @@
<?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/>.
/**
* Classes to manage manual badge award.
*
* @package core
* @subpackage badges
* @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Yuliya Bozhko <yuliya.bozhko@totaralms.com>
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/badgeslib.php');
require_once($CFG->dirroot . '/user/selector/lib.php');
abstract class badge_award_selector_base extends user_selector_base {
/**
* The id of the badge this selector is being used for
* @var int
*/
protected $badgeid = null;
/**
* The context of the badge this selector is being used for
* @var object
*/
protected $context = null;
/**
* The id of the role of badge issuer in current context
* @var int
*/
protected $issuerrole = null;
/**
* The id of badge issuer
* @var int
*/
protected $issuerid = null;
/**
* The return address. Accepts either a string or a moodle_url.
* @var string $url
*/
public $url;
/**
* The current group being displayed.
* @var int $currentgroup
*/
public $currentgroup;
/**
* Constructor method
* @param string $name
* @param array $options
*/
public function __construct($name, array $options) {
$options['accesscontext'] = $options['context'];
parent::__construct($name, $options);
if (isset($options['context'])) {
if ($options['context'] instanceof context_system) {
// If it is a site badge, we need to get context of frontpage.
$this->context = context_course::instance(SITEID);
} else {
$this->context = $options['context'];
}
}
if (isset($options['badgeid'])) {
$this->badgeid = $options['badgeid'];
}
if (isset($options['issuerid'])) {
$this->issuerid = $options['issuerid'];
}
if (isset($options['issuerrole'])) {
$this->issuerrole = $options['issuerrole'];
}
if (isset($options['url'])) {
$this->url = $options['url'];
}
if (isset($options['currentgroup'])) {
$this->currentgroup = $options['currentgroup'];
} else {
// Returns group active in course, changes the group by default if 'group' page param present.
$this->currentgroup = groups_get_course_group($COURSE, true);
}
}
/**
* Returns an array of options to seralise and store for searches
*
* @return array
*/
protected function get_options() {
global $CFG;
$options = parent::get_options();
$options['file'] = 'badges/lib/awardlib.php';
$options['context'] = $this->context;
$options['badgeid'] = $this->badgeid;
$options['issuerid'] = $this->issuerid;
$options['issuerrole'] = $this->issuerrole;
// These will be used to filter potential badge recipients when searching.
$options['currentgroup'] = $this->currentgroup;
return $options;
}
/**
* Restricts the selection of users to display, according to the groups they belong.
*
* @return array
*/
protected function get_groups_sql() {
$groupsql = '';
$groupwheresql = '';
$groupwheresqlparams = array();
if ($this->currentgroup) {
$groupsql = ' JOIN {groups_members} gm ON gm.userid = u.id ';
$groupwheresql = ' AND gm.groupid = :gr_grpid ';
$groupwheresqlparams = array('gr_grpid' => $this->currentgroup);
}
return array($groupsql, $groupwheresql, $groupwheresqlparams);
}
}
/**
* A user selector control for potential users to award badge
*/
class badge_potential_users_selector extends badge_award_selector_base {
const MAX_USERS_PER_PAGE = 100;
/**
* Existing recipients
*/
protected $existingrecipients = array();
/**
* Finds all potential badge recipients
*
* Potential badge recipients are all enroled users
* who haven't got a badge from current issuer role.
*
* @param string $search
* @return array
*/
public function find_users($search) {
global $DB;
$whereconditions = array();
list($wherecondition, $params) = $this->search_sql($search, 'u');
if ($wherecondition) {
$whereconditions[] = $wherecondition;
}
$existingids = array();
foreach ($this->existingrecipients as $group) {
foreach ($group as $user) {
$existingids[] = $user->id;
}
}
if ($existingids) {
list($usertest, $userparams) = $DB->get_in_or_equal($existingids, SQL_PARAMS_NAMED, 'ex', false);
$whereconditions[] = 'u.id ' . $usertest;
$params = array_merge($params, $userparams);
}
if ($whereconditions) {
$wherecondition = ' WHERE ' . implode(' AND ', $whereconditions);
}
list($groupsql, $groupwheresql, $groupwheresqlparams) = $this->get_groups_sql();
list($esql, $eparams) = get_enrolled_sql($this->context, 'moodle/badges:earnbadge', 0, true);
$params = array_merge($params, $eparams, $groupwheresqlparams);
$fields = 'SELECT ' . $this->required_fields_sql('u');
$countfields = 'SELECT COUNT(u.id)';
$params['badgeid'] = $this->badgeid;
$params['issuerrole'] = $this->issuerrole;
$sql = " FROM {user} u JOIN ($esql) je ON je.id = u.id
LEFT JOIN {badge_manual_award} bm
ON (bm.recipientid = u.id AND bm.badgeid = :badgeid AND bm.issuerrole = :issuerrole)
$groupsql
$wherecondition AND bm.id IS NULL
$groupwheresql";
list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext);
$order = ' ORDER BY ' . $sort;
if (!$this->is_validating()) {
$potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
if ($potentialmemberscount > self::MAX_USERS_PER_PAGE) {
return $this->too_many_results($search, $potentialmemberscount);
}
}
$availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams));
if (empty($availableusers)) {
return array();
}
return array(get_string('potentialrecipients', 'badges') => $availableusers);
}
/**
* Sets the existing recipients
* @param array $users
*/
public function set_existing_recipients(array $users) {
$this->existingrecipients = $users;
}
}
/**
* A user selector control for existing users to award badge
*/
class badge_existing_users_selector extends badge_award_selector_base {
/**
* Finds all users who already have been awarded a badge by current role
*
* @param string $search
* @return array
*/
public function find_users($search) {
global $DB;
list($wherecondition, $params) = $this->search_sql($search, 'u');
$params['badgeid'] = $this->badgeid;
$params['issuerrole'] = $this->issuerrole;
list($esql, $eparams) = get_enrolled_sql($this->context, 'moodle/badges:earnbadge', 0, true);
$fields = $this->required_fields_sql('u');
list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext);
list($groupsql, $groupwheresql, $groupwheresqlparams) = $this->get_groups_sql();
$params = array_merge($params, $eparams, $sortparams, $groupwheresqlparams);
$recipients = $DB->get_records_sql("SELECT $fields
FROM {user} u
JOIN ($esql) je ON je.id = u.id
JOIN {badge_manual_award} s ON s.recipientid = u.id
$groupsql
WHERE $wherecondition AND s.badgeid = :badgeid AND s.issuerrole = :issuerrole
$groupwheresql
ORDER BY $sort", $params);
return array(get_string('existingrecipients', 'badges') => $recipients);
}
}
function process_manual_award($recipientid, $issuerid, $issuerrole, $badgeid) {
global $DB;
$params = array(
'badgeid' => $badgeid,
'issuerid' => $issuerid,
'issuerrole' => $issuerrole,
'recipientid' => $recipientid
);
if (!$DB->record_exists('badge_manual_award', $params)) {
$award = new stdClass();
$award->badgeid = $badgeid;
$award->issuerid = $issuerid;
$award->issuerrole = $issuerrole;
$award->recipientid = $recipientid;
$award->datemet = time();
if ($DB->insert_record('badge_manual_award', $award)) {
return true;
}
}
return false;
}
/**
* Manually revoke awarded badges.
*
* @param int $recipientid
* @param int $issuerid
* @param int $issuerrole
* @param int $badgeid
* @return bool
*/
function process_manual_revoke($recipientid, $issuerid, $issuerrole, $badgeid) {
global $DB;
$params = array(
'badgeid' => $badgeid,
'issuerid' => $issuerid,
'issuerrole' => $issuerrole,
'recipientid' => $recipientid
);
if ($DB->record_exists('badge_manual_award', $params)) {
if ($DB->delete_records('badge_manual_award', array('badgeid' => $badgeid,
'issuerid' => $issuerid,
'recipientid' => $recipientid))
&& $DB->delete_records('badge_issued', array('badgeid' => $badgeid,
'userid' => $recipientid))) {
// Trigger event, badge revoked.
$badge = new \badge($badgeid);
$eventparams = array(
'objectid' => $badgeid,
'relateduserid' => $recipientid,
'context' => $badge->get_context()
);
$event = \core\event\badge_revoked::create($eventparams);
$event->trigger();
return true;
}
} else {
throw new moodle_exception('error:badgenotfound', 'badges');
}
return false;
}
+177
View File
@@ -0,0 +1,177 @@
<?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/>.
/**
* Baking badges library.
*
* @package core
* @subpackage badges
* @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Yuliya Bozhko <yuliya.bozhko@totaralms.com>
*/
defined('MOODLE_INTERNAL') || die();
/**
* Information on PNG file chunks can be found at http://www.w3.org/TR/PNG/#11Chunks
* Some other info on PNG that I used http://garethrees.org/2007/11/14/pngcrush/
*
* Example of use:
* $png = new PNG_MetaDataHandler('file.png');
*
* if ($png->check_chunks("tEXt", "openbadge")) {
* $newcontents = $png->add_chunks("tEXt", "openbadge", 'http://some.public.url/to.your.assertion.file');
* }
*
* file_put_contents('file.png', $newcontents);
*/
class PNG_MetaDataHandler
{
/** @var string File content as a string */
private $_contents;
/** @var int Length of the image file */
private $_size;
/** @var array Variable for storing parsed chunks */
private $_chunks;
/**
* Prepares file for handling metadata.
* Verifies that this file is a valid PNG file.
* Unpacks file chunks and reads them into an array.
*
* @param string $contents File content as a string
*/
public function __construct($contents) {
$this->_contents = $contents;
$png_signature = pack("C8", 137, 80, 78, 71, 13, 10, 26, 10);
// Read 8 bytes of PNG header and verify.
$header = substr($this->_contents, 0, 8);
if ($header != $png_signature) {
debugging('This is not a valid PNG image');
}
$this->_size = strlen($this->_contents);
$this->_chunks = array();
// Skip 8 bytes of IHDR image header.
$position = 8;
do {
$chunk = @unpack('Nsize/a4type', substr($this->_contents, $position, 8));
$this->_chunks[$chunk['type']][] = substr($this->_contents, $position + 8, $chunk['size']);
// Skip 12 bytes chunk overhead.
$position += $chunk['size'] + 12;
} while ($position < $this->_size);
}
/**
* Checks if a key already exists in the chunk of said type.
* We need to avoid writing same keyword into file chunks.
*
* @param string $type Chunk type, like iTXt, tEXt, etc.
* @param string $check Keyword that needs to be checked.
*
* @return boolean (true|false) True if file is safe to write this keyword, false otherwise.
*/
public function check_chunks($type, $check) {
if (array_key_exists($type, $this->_chunks)) {
foreach (array_keys($this->_chunks[$type]) as $typekey) {
list($key, $data) = explode("\0", $this->_chunks[$type][$typekey]);
if (strcmp($key, $check) == 0) {
debugging('Key "' . $check . '" already exists in "' . $type . '" chunk.');
return false;
}
}
}
return true;
}
/**
* Adds a chunk with keyword and data to the file content.
* Chunk is added to the end of the file, before IEND image trailer.
*
* @param string $type Chunk type, like iTXt, tEXt, etc.
* @param string $key Keyword that needs to be added.
* @param string $value Currently an assertion URL that is added to an image metadata.
*
* @return string $result File content with a new chunk as a string. Can be used in file_put_contents() to write to a file.
* @throws \moodle_exception when unsupported chunk type is defined.
*/
public function add_chunks($type, $key, $value) {
if (strlen($key) > 79) {
debugging('Key is too big');
}
$dataparts = [];
if ($type === 'iTXt') {
// International textual data (iTXt).
// Keyword: 1-79 bytes (character string).
$dataparts[] = $key;
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Compression flag: 1 byte
// A value of 0 means no compression.
$dataparts[] = "\x00";
// Compression method: 1 byte
// If compression is disabled, the method should also be 0.
$dataparts[] = "\x00";
// Language tag: 0 or more bytes (character string)
// When there is no language specified leave empty.
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Translated keyword: 0 or more bytes
// When there is no translation specified, leave empty.
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Text: 0 or more bytes.
$dataparts[] = $value;
} else if ($type === 'tEXt') {
// Textual data (tEXt).
// Keyword: 1-79 bytes (character string).
$dataparts[] = $key;
// Null separator: 1 byte.
$dataparts[] = "\0";
// Text: n bytes (character string).
$dataparts[] = $value;
} else {
throw new \moodle_exception('Unsupported chunk type: ' . $type);
}
$data = implode($dataparts);
$crc = pack("N", crc32($type . $data));
$len = pack("N", strlen($data));
// Chunk format: length + type + data + CRC.
// CRC is a CRC-32 computed over the chunk type and chunk data.
$newchunk = $len . $type . $data . $crc;
$this->_chunks[$type] = $data;
$result = substr($this->_contents, 0, $this->_size - 12)
. $newchunk
. substr($this->_contents, $this->_size - 12, 12);
return $result;
}
}