. /** * Class represents a customcert template. * * @package mod_customcert * @copyright 2016 Mark Nelson , 2022 Kumi Systems e.U. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace mod_customcert; error_reporting(E_ALL); require_once(__DIR__ . "/../vendor/autoload.php"); require_once($CFG->dirroot.'/user/profile/lib.php'); use mikehaertl\wkhtmlto\Pdf; #defined('MOODLE_INTERNAL') || die(); /** * Class represents a customcert template. * * @package mod_customcert * @copyright 2016 Mark Nelson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class template { /** * @var int $id The id of the template. */ protected $id; /** * @var string $name The name of this template */ protected $name; /** * @var int $contextid The context id of this template */ protected $contextid; protected $html; /** * The constructor. * * @param \stdClass $template */ public function __construct($template) { $this->id = $template->id; $this->name = $template->name; $this->contextid = $template->contextid; $this->html = $template->html; } /** * Handles saving data. * * @param \stdClass $data the template data */ public function save($data) { global $DB; $savedata = new \stdClass(); $savedata->id = $this->id; $savedata->name = $data->name; $savedata->timemodified = time(); $DB->update_record('customcert_templates', $savedata); } /** * Handles adding another page to the template. * * @return int the id of the page */ public function add_page() { global $DB; // Set the page number to 1 to begin with. $sequence = 1; // Get the max page number. $sql = "SELECT MAX(sequence) as maxpage FROM {customcert_pages} cp WHERE cp.templateid = :templateid"; if ($maxpage = $DB->get_record_sql($sql, array('templateid' => $this->id))) { $sequence = $maxpage->maxpage + 1; } // New page creation. $page = new \stdClass(); $page->templateid = $this->id; $page->width = '210'; $page->height = '297'; $page->sequence = $sequence; $page->timecreated = time(); $page->timemodified = $page->timecreated; // Insert the page. return $DB->insert_record('customcert_pages', $page); } /** * Handles saving page data. * * @param \stdClass $data the template data */ public function save_page($data) { global $DB; // Set the time to a variable. $time = time(); // Get the existing pages and save the page data. if ($pages = $DB->get_records('customcert_pages', array('templateid' => $data->tid))) { // Loop through existing pages. foreach ($pages as $page) { // Get the name of the fields we want from the form. $width = 'pagewidth_' . $page->id; $height = 'pageheight_' . $page->id; $leftmargin = 'pageleftmargin_' . $page->id; $rightmargin = 'pagerightmargin_' . $page->id; // Create the page data to update the DB with. $p = new \stdClass(); $p->id = $page->id; $p->width = $data->$width; $p->height = $data->$height; $p->leftmargin = $data->$leftmargin; $p->rightmargin = $data->$rightmargin; $p->timemodified = $time; // Update the page. $DB->update_record('customcert_pages', $p); } } } /** * Handles deleting the template. * * @return bool return true if the deletion was successful, false otherwise */ public function delete() { global $DB; // Delete the elements. $sql = "SELECT e.* FROM {customcert_elements} e INNER JOIN {customcert_pages} p ON e.pageid = p.id WHERE p.templateid = :templateid"; if ($elements = $DB->get_records_sql($sql, array('templateid' => $this->id))) { foreach ($elements as $element) { // Get an instance of the element class. if ($e = \mod_customcert\element_factory::get_element_instance($element)) { $e->delete(); } else { // The plugin files are missing, so just remove the entry from the DB. $DB->delete_records('customcert_elements', array('id' => $element->id)); } } } // Delete the pages. if (!$DB->delete_records('customcert_pages', array('templateid' => $this->id))) { return false; } // Now, finally delete the actual template. if (!$DB->delete_records('customcert_templates', array('id' => $this->id))) { return false; } return true; } /** * Handles deleting a page from the template. * * @param int $pageid the template page */ public function delete_page($pageid) { global $DB; // Get the page. $page = $DB->get_record('customcert_pages', array('id' => $pageid), '*', MUST_EXIST); // Delete this page. $DB->delete_records('customcert_pages', array('id' => $page->id)); // The element may have some extra tasks it needs to complete to completely delete itself. if ($elements = $DB->get_records('customcert_elements', array('pageid' => $page->id))) { foreach ($elements as $element) { // Get an instance of the element class. if ($e = \mod_customcert\element_factory::get_element_instance($element)) { $e->delete(); } else { // The plugin files are missing, so just remove the entry from the DB. $DB->delete_records('customcert_elements', array('id' => $element->id)); } } } // Now we want to decrease the page number values of // the pages that are greater than the page we deleted. $sql = "UPDATE {customcert_pages} SET sequence = sequence - 1 WHERE templateid = :templateid AND sequence > :sequence"; $DB->execute($sql, array('templateid' => $this->id, 'sequence' => $page->sequence)); } /** * Handles deleting an element from the template. * * @param int $elementid the template page */ public function delete_element($elementid) { global $DB; // Ensure element exists and delete it. $element = $DB->get_record('customcert_elements', array('id' => $elementid), '*', MUST_EXIST); // Get an instance of the element class. if ($e = \mod_customcert\element_factory::get_element_instance($element)) { $e->delete(); } else { // The plugin files are missing, so just remove the entry from the DB. $DB->delete_records('customcert_elements', array('id' => $elementid)); } // Now we want to decrease the sequence numbers of the elements // that are greater than the element we deleted. $sql = "UPDATE {customcert_elements} SET sequence = sequence - 1 WHERE pageid = :pageid AND sequence > :sequence"; $DB->execute($sql, array('pageid' => $element->pageid, 'sequence' => $element->sequence)); } /** * Generate the PDF for the template. * * @param bool $preview true if it is a preview, false otherwise * @param int $userid the id of the user whose certificate we want to view * @param bool $return Do we want to return the contents of the PDF? * @return string|void Can return the PDF in string format if specified. */ public function generate_pdf(bool $preview = false, int $userid = null, bool $return = false) { global $CFG, $DB, $USER, $SITE; if (empty($userid)) { $user = $USER; } else { $user = \core_user::get_user($userid); } require_once($CFG->libdir . '/pdflib.php'); profile_load_data($user); // Get the pages for the template, there should always be at least one page for each template. if ($pages = $DB->get_records('customcert_pages', array('templateid' => $this->id), 'sequence ASC')) { // Create the pdf object. $pdf = new \pdf(); $customcert = $DB->get_record('customcert', ['templateid' => $this->id]); // If the template belongs to a certificate then we need to check what permissions we set for it. if (!empty($customcert->protection)) { $protection = explode(', ', $customcert->protection); $pdf->SetProtection($protection); } if (empty($customcert->deliveryoption)) { $deliveryoption = certificate::DELIVERY_OPTION_INLINE; } else { $deliveryoption = $customcert->deliveryoption; } // Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename. $filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.'); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); $pdf->SetTitle($filename); $pdf->SetAutoPageBreak(true, 0); // This is the logic the TCPDF library uses when processing the name. This makes names // such as 'الشهادة' become empty, so set a default name in these cases. $filename = preg_replace('/[\s]+/', '_', $filename); $filename = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $filename); if (empty($filename)) { $filename = get_string('certificate', 'customcert'); } $filename = clean_filename($filename . '.pdf'); // Loop through the pages and display their content. foreach ($pages as $page) { // Add the page to the PDF. if ($page->width > $page->height) { $orientation = 'L'; } else { $orientation = 'P'; } $pdf->AddPage($orientation, array($page->width, $page->height)); if ($this->html) { $pdf = new Pdf(array( "disable-smart-shrinking", "margin-bottom" => "0", "margin-right" => "0", "margin-left" => "0", "margin-top" => "0" )); $html = $this->html; $context = \context_user::instance($user->id); $fs = get_file_storage(); $files = $fs->get_area_files($context->id, 'user', 'icon', 0); $file = null; $content = ""; foreach ($files as $filefound) { if (!$filefound->is_directory()) { $file = $filefound; break; } } if ($file) { $location = make_request_directory() . '/target'; $content = $file->get_content(); } else if ($preview) { } $html = str_replace("__PROFILEPIC__", 'data: ' . mime_content_type($file) . ';base64,' . $content, $html); $html = str_replace("__NAME__", $user->firstname . " " . $user->lastname, $html); if ($preview) { $code = \mod_customcert\certificate::generate_code(); } else { $issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id), '*', IGNORE_MULTIPLE); $code = $issue->code; } $html = str_replace("__CERTNUM__", $code, $html); if ($preview) { $courseid = $SITE->id; } else { $courseid = $customcert->course; } $course = get_course($courseid); $coursename = $course->fullname; $html = str_replace("__COURSE__", $coursename, $html); $date = $issue->timecreated; $html = str_replace("__DATE__", userdate($date, '%B %d, %Y'), $html); $html = str_replace("__PIN__", $user->username, $html); $pdf->addPage($html); $pdf->send(); die($pdf->getError()); } else { $pdf->SetMargins($page->leftmargin, 0, $page->rightmargin); // Get the elements for the page. if ($elements = $DB->get_records('customcert_elements', array('pageid' => $page->id), 'sequence ASC')) { // Loop through and display. foreach ($elements as $element) { // Get an instance of the element class. if ($e = \mod_customcert\element_factory::get_element_instance($element)) { $e->render($pdf, $preview, $user); } } } } } if ($return && !$this->html) { return $pdf->Output('', 'S'); } if (!$this->html) { $pdf->Output($filename, $deliveryoption); } } } /** * Handles copying this template into another. * * @param int $copytotemplateid The template id to copy to */ public function copy_to_template($copytotemplateid) { global $DB; $copytotemplate = $DB->get_record('customcert_templates', array('id' => $copytotemplateid)); $copytotemplate->html = $this->html; $DB->update_record('customcert_templates', $copytotemplate); // Get the pages for the template, there should always be at least one page for each template. if ($templatepages = $DB->get_records('customcert_pages', array('templateid' => $this->id))) { // Loop through the pages. foreach ($templatepages as $templatepage) { $page = clone($templatepage); $page->templateid = $copytotemplateid; $page->timecreated = time(); $page->timemodified = $page->timecreated; // Insert into the database. $page->id = $DB->insert_record('customcert_pages', $page); // Now go through the elements we want to load. if ($templateelements = $DB->get_records('customcert_elements', array('pageid' => $templatepage->id))) { foreach ($templateelements as $templateelement) { $element = clone($templateelement); $element->pageid = $page->id; $element->timecreated = time(); $element->timemodified = $element->timecreated; // Ok, now we want to insert this into the database. $element->id = $DB->insert_record('customcert_elements', $element); // Load any other information the element may need to for the template. if ($e = \mod_customcert\element_factory::get_element_instance($element)) { if (!$e->copy_element($templateelement)) { // Failed to copy - delete the element. $e->delete(); } } } } } } } /** * Handles moving an item on a template. * * @param string $itemname the item we are moving * @param int $itemid the id of the item * @param string $direction the direction */ public function move_item($itemname, $itemid, $direction) { global $DB; $table = 'customcert_'; if ($itemname == 'page') { $table .= 'pages'; } else { // Must be an element. $table .= 'elements'; } if ($moveitem = $DB->get_record($table, array('id' => $itemid))) { // Check which direction we are going. if ($direction == 'up') { $sequence = $moveitem->sequence - 1; } else { // Must be down. $sequence = $moveitem->sequence + 1; } // Get the item we will be swapping with. Make sure it is related to the same template (if it's // a page) or the same page (if it's an element). if ($itemname == 'page') { $params = array('templateid' => $moveitem->templateid); } else { // Must be an element. $params = array('pageid' => $moveitem->pageid); } $swapitem = $DB->get_record($table, $params + array('sequence' => $sequence)); } // Check that there is an item to move, and an item to swap it with. if ($moveitem && !empty($swapitem)) { $DB->set_field($table, 'sequence', $swapitem->sequence, array('id' => $moveitem->id)); $DB->set_field($table, 'sequence', $moveitem->sequence, array('id' => $swapitem->id)); } } /** * Returns the id of the template. * * @return int the id of the template */ public function get_id() { return $this->id; } /** * Returns the name of the template. * * @return string the name of the template */ public function get_name() { return $this->name; } public function get_html() { return $this->html; } /** * Returns the context id. * * @return int the context id */ public function get_contextid() { return $this->contextid; } /** * Returns the context id. * * @return \context the context */ public function get_context() { return \context::instance_by_id($this->contextid); } /** * Returns the context id. * * @return \context_module|null the context module, null if there is none */ public function get_cm() { $context = $this->get_context(); if ($context->contextlevel === CONTEXT_MODULE) { return get_coursemodule_from_id('customcert', $context->instanceid, 0, false, MUST_EXIST); } return null; } /** * Ensures the user has the proper capabilities to manage this template. * * @throws \required_capability_exception if the user does not have the necessary capabilities (ie. Fred) */ public function require_manage() { require_capability('mod/customcert:manage', $this->get_context()); } /** * Creates a template. * * @param string $templatename the name of the template * @param int $contextid the context id * @return \mod_customcert\template the template object */ public static function create($templatename, $contextid) { global $DB; $template = new \stdClass(); $template->name = $templatename; $template->contextid = $contextid; $template->timecreated = time(); $template->timemodified = $template->timecreated; $template->id = $DB->insert_record('customcert_templates', $template); return new \mod_customcert\template($template); } }