diff --git a/classes/Report.php b/classes/Report.php index c1753d2..ae370fc 100644 --- a/classes/Report.php +++ b/classes/Report.php @@ -565,7 +565,7 @@ public function generate_full_page(int $attemptid, array $sections, bool $fix_re // Build HTML tree $html = ""; $html .= $OUTPUT->header(); - // $html .= \quiz_archiver\local\coversheet\create_coversheet::get_coversheet($attemptid); + $html .= \quiz_archiver\coversheet\create_coversheet::get_coversheet($attemptid); $html .= self::generate($attemptid, $sections); $html .= $OUTPUT->footer(); diff --git a/classes/coversheet/create_coversheet.php b/classes/coversheet/create_coversheet.php index 71cbf1d..7999423 100644 --- a/classes/coversheet/create_coversheet.php +++ b/classes/coversheet/create_coversheet.php @@ -23,9 +23,11 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -namespace quiz_archiver\local\coversheet; +namespace quiz_archiver\coversheet; use admin_setting_heading; +use coding_exception; +use quiz_archiver\external\get_attempts_metadata; defined('MOODLE_INTERNAL') || die(); @@ -40,7 +42,7 @@ class create_coversheet { /** - * Create the coversheet. Only this method should be called from outside. + * Create the coversheet. * @param int $attemptid * @return string */ @@ -48,11 +50,137 @@ public static function get_coversheet(int $attemptid): string { $config = get_config('quiz_archiver'); - if(empty($config->enable_pdf_coversheet)) { + if (empty($config->enable_pdf_coversheet)) { return ''; } - return $config->dynamic_pdf_content; + // Get all needed attempt metadata. E.g. User, timestarted, timefinished etc. + $attemptmetadata = self::get_attempt_metadata($attemptid); + // Find all placeholders. + preg_match_all('/{{(.*)_(.*)}}/', $config->dynamic_pdf_content, $matches); + + // Now replace all placeholders. + $html = $config->dynamic_pdf_content; + foreach ($matches[0] as $key => $placeholder) { + $classpath = '\quiz_archiver\coversheet\placeholder\\' . $matches[1][$key]; + $method = $matches[2][$key]; + $replacement = self::check_class_and_method($classpath, $method, $attemptmetadata); + $html = preg_replace('/' . $placeholder . '/', $replacement, $html); + } + + \local_debugger\performance\debugger::print_debug('test', 'get_coversheet', $html); + return '
' . $config->dynamic_pdf_content . '
'; + } + + /** + * Gets the metadata of all attempts made inside this quiz, excluding previews. + * + * @param array|null $filter_attemptids If given, only attempts with the given + * IDs will be returned. + * + * @return object + * @throws \dml_exception + */ + private static function get_attempt_metadata(int $attemptid): object { + global $DB; + + $fields = [ + 'qa.id AS attemptid', + 'qa.userid', + 'qa.quiz as quizinstance', + 'qa.attempt as attemptnumber', + 'qa.state', + 'qa.timestart', + 'qa.timefinish', + 'q.course as courseid', + ]; + + $sql = "SELECT " . join(", ", $fields) . + " FROM {quiz_attempts} qa " . + "LEFT JOIN {user} u ON qa.userid = u.id " . + "LEFT JOIN {quiz} q on q.id = qa.quiz " . + "WHERE qa.id = :qaid"; + + // Get all requested attempt + return $DB->get_record_sql($sql, ["qaid" => $attemptid]); + } + + /** + * Checks and executes the callback method. + * @param string $classpath + * @param string $method + * @param string|int|object|array $params + * @return string + */ + private static function check_class_and_method(string $classpath, string $method, string|int|object|array $params): string { + + if (!class_exists($classpath)) { + return 'Class ' . $classpath . ' not found.'; + } + + $class = new $classpath(); + if (!method_exists($class, $method)) { + return 'Placeholder for ' . $method . ' not found.'; + } + + return $class::$method($params); + } + + /** + * Get all possible placeholders in a mustache context format. + * + * @return array + */ + public static function get_possible_placeholders(): array { + global $CFG; + $placeholders = []; + $dir = $CFG->dirroot . "/mod/quiz/report/archiver/classes/coversheet/placeholder"; + $basenames = self::get_all_files_in_directory($dir); + foreach ($basenames as $basename) { + $placeholders[] = [ + 'placeholders' => self::get_placeholders($basename, "\quiz_archiver\coversheet\placeholder\\$basename"), + 'metadata' => [ + 'tabid' => 'qa_' . $basename . '_tab', + 'tab' => get_string($basename, 'quiz_archiver'), + ], + ]; + } + + return $placeholders; + } + + /** + * Get the array of the placeholders. + * + * @param string $basename + * @param string $classname + * @return array + */ + private static function get_placeholders(string $basename, string $classname): array { + $methods = get_class_methods($classname); + $placeholders = []; + foreach ($methods as $method) { + $placeholders[] = $basename . "_" . $method; + } + return $placeholders; + } + + /** + * Get all basenames of files in a specific directory + * + * @param string $dir + * @return array + * @throws coding_exception + */ + private static function get_all_files_in_directory(string $dir): array { + $files = scandir($dir); + $basenames = []; + foreach ($files as $file) { + if (is_file($dir . '/' . $file)) { + $basenames[] = basename($file, '.php'); + } + } + return $basenames; } } diff --git a/classes/coversheet/placeholder/course.php b/classes/coversheet/placeholder/course.php new file mode 100644 index 0000000..e14d07c --- /dev/null +++ b/classes/coversheet/placeholder/course.php @@ -0,0 +1,101 @@ +. + +/** + * Handles course callback to get corse info. + * + * @package quiz_archiver + * @copyright ISB Bayern, 2024 + * @author Dr. Peter Mayer + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace quiz_archiver\coversheet\placeholder; + +use dml_exception; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Handles course callback to get corse info. + * + * @package quiz_archiver + * @copyright ISB Bayern, 2024 + * @author Dr. Peter Mayer + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class course { + + /** + * Get course fullname. + * @param object $params + * @return string + */ + public static function fullname(object $params): string { + $course = get_course($params->courseid); + return $course->fullname; + } + + /** + * Get course shortname. + * @param object $params + * @return string + */ + public static function shortname(object $params): string { + $course = get_course($params->courseid); + return $course->shortname; + } + + /** + * Get course summary. + * @param object $params + * @return string + */ + public static function summary(object $params): string { + $course = get_course($params->courseid); + return $course->summary; + } + + /** + * Get course format. + * @param object $params + * @return string + */ + public static function format(object $params): string { + $course = get_course($params->courseid); + return $course->format; + } + + /** + * Get course startdate. + * @param object $params + * @return string + */ + public static function startdate(object $params): string { + $course = get_course($params->courseid); + return $course->startdate; + } + + /** + * Get course enddate. + * @param object $params + * @return string + */ + public static function enddate(object $params): string { + $course = get_course($params->courseid); + return $course->enddate; + } +} diff --git a/classes/coversheet/placeholder/profile.php b/classes/coversheet/placeholder/profile.php index e69de29..4cc364e 100644 --- a/classes/coversheet/placeholder/profile.php +++ b/classes/coversheet/placeholder/profile.php @@ -0,0 +1,183 @@ +. + +/** + * Handles everything that is needed for coversheet creation. + * + * @package quiz_archiver + * @copyright ISB Bayern, 2024 + * @author Dr. Peter Mayer + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace quiz_archiver\coversheet\placeholder; + +use dml_exception; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Handles everything that is needed for coversheet creation. + * + * @package quiz_archiver + * @copyright ISB Bayern, 2024 + * @author Dr. Peter Mayer + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class profile { + + // @var userprofilefilds + var $userprofilefiels = [ + 'id', + 'auth', + 'confirmed', + 'policyagreed', + 'deleted', + 'suspended', + 'mnethostid', + 'username', + 'password', + 'idnumber', + 'firstname', + 'lastname', + 'email', + 'emailstop', + 'phone1', + 'phone2', + 'institution', + 'department', + 'address', + 'city', + 'country', + 'lang', + 'calendartype', + 'theme', + 'timezone', + 'firstaccess', + 'lastaccess', + 'lastlogin', + 'currentlogin', + 'lastip', + 'secret', + 'picture', + 'description', + 'descriptionformat', + 'mailformat', + 'maildigest', + 'maildisplay', + 'autosubscribe', + 'trackforums', + 'timecreated', + 'timemodified', + 'trustbitmask', + 'imagealt', + 'lastnamephonetic', + 'firstnamephonetic', + 'middlename', + 'alternatename', + 'moodlenetprofile', + ]; + + /** + * Get user firstname. + * @param object $params + * @return string + */ + public static function firstname( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->firstname; + } + + /** + * Get user lastname. + * @param object $params + * @return string + */ + public static function lastname( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->lastname; + } + + /** + * Get user fullname. + * @param object $params + * @return string + */ + public static function userfullname( object $params): string { + $user = \core_user::get_user($params->userid); + return \core_user::get_fullname($user); + } + + /** + * Get user institution. + * @param object $params + * @return string + */ + public static function institution( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->institution; + } + + /** + * Get user department. + * @param object $params + * @return string + */ + public static function department( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->department; + } + + /** + * Get user address. + * @param object $params + * @return string + */ + public static function address( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->address; + } + + /** + * Get user city. + * @param object $params + * @return string + */ + public static function city( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->city; + } + + /** + * Get user country. + * @param object $params + * @return string + */ + public static function country( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->country; + } + + /** + * Get user language. + * @param object $params + * @return string + */ + public static function language( object $params): string { + $user = \core_user::get_user($params->userid); + return $user->lang; + } +} diff --git a/classes/local/admin/setting/setting_button.php b/classes/local/admin/setting/setting_button.php index d225417..25f1bf7 100644 --- a/classes/local/admin/setting/setting_button.php +++ b/classes/local/admin/setting/setting_button.php @@ -23,7 +23,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -namespace quiz_archiver\local\setting\admin; +namespace quiz_archiver\local\admin\setting; use admin_setting_heading; diff --git a/lang/en/quiz_archiver.php b/lang/en/quiz_archiver.php index 8622ed5..3d5647f 100644 --- a/lang/en/quiz_archiver.php +++ b/lang/en/quiz_archiver.php @@ -83,6 +83,8 @@ $string['export_report_section_attachments_help'] = 'Include all file attachments (e.g., essay file submissions) inside the archive. Warning: This can significantly increase the archive size.'; $string['job_overview'] = 'Archives'; $string['num_attempts'] = 'Number of attempts'; + +// Language strings for pdf cover sheet. $string['pdfcoversheet_settings'] = 'PDF Cover Sheet'; $string['pdfcoversheet_settings_desc'] = 'Define a default cover sheet'; $string['enable_pdf_coversheet'] = 'Ad PDF cover sheet'; @@ -93,6 +95,10 @@ $string['pdf_coversheet_html_area_help'] = 'Use placeholders for dynamic cover sheet contents'; $string['pdfcoversheet_heading'] = 'PDF Cover Sheet'; $string['define_pdfcoversheet'] = 'Define Cover Sheet'; +$string['exiting_placeholders'] = 'Possible Placeholders'; +$string['exiting_placeholders_desc'] = 'You can use the placeholder by writing {{placeholder}} e.g. {{profile_userfullname}} to the template above.'; +$string['profile'] = 'Profile'; +$string['course'] = 'Course'; // Job creation form: Filename pattern $string['archive_filename_pattern'] = 'Archive name'; diff --git a/settings_coversheet.php b/settings_coversheet.php index 03e7e69..69d7087 100644 --- a/settings_coversheet.php +++ b/settings_coversheet.php @@ -90,6 +90,8 @@ if(!empty($dynamicpdfcontent = get_config('quiz_archiver', 'dynamic_pdf_content'))) { $templatecontext['storedhtml'] = get_config('quiz_archiver', 'dynamic_pdf_content'); } + +$templatecontext['placeholderdata'] = \quiz_archiver\coversheet\create_coversheet::get_possible_placeholders(); // print_r(get_config('quiz_archiver', 'dynamic_pdf_content'));die; echo $OUTPUT->header(); diff --git a/templates/define_pdfcoversheet.mustache b/templates/define_pdfcoversheet.mustache index b142b8c..1441e75 100644 --- a/templates/define_pdfcoversheet.mustache +++ b/templates/define_pdfcoversheet.mustache @@ -32,12 +32,36 @@
-
- +
+
+

{{#str}}exiting_placeholders, quiz_archiver{{/str}}

+

{{#str}}exiting_placeholders_desc, quiz_archiver{{/str}}

+ +
+ {{#placeholderdata}} +
+
    + {{#placeholders}} +
  • {{.}}
  • + {{/placeholders}} +
+
+ {{/placeholderdata}} +
+
+