From 3d8cb20aef2c55cadd38dccc3f51128d7e357ecf Mon Sep 17 00:00:00 2001 From: Thomas Hackl <hackl@data-quest.de> Date: Wed, 7 Dec 2022 07:17:21 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20"Erweiterung=20Courseware:=20Zertifik?= =?UTF-8?q?ate,=20Erinnerungen=20und=20R=C3=BCcksetzen=20des=20Fortschritt?= =?UTF-8?q?s"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1660 Merge request studip/studip!1172 --- .../5.3.11_courseware_cron_events.php | 49 +++ lib/classes/CoursewarePDFCertificate.php | 40 ++ .../Courseware/CoursewareInstancesUpdate.php | 33 ++ .../JsonApi/Schemas/Courseware/Instance.php | 3 + lib/cronjobs/courseware.php | 341 ++++++++++++++++++ lib/models/Courseware/Certificate.php | 39 ++ lib/models/Courseware/Instance.php | 155 ++++++++ .../images/pdf/pdf_default_background.jpg | Bin 0 -> 135997 bytes .../courseware/CoursewareToolsAdmin.vue | 222 +++++++++++- .../vue/store/courseware/courseware.module.js | 7 +- templates/courseware/mails/certificate.php | 22 ++ 11 files changed, 902 insertions(+), 9 deletions(-) create mode 100644 db/migrations/5.3.11_courseware_cron_events.php create mode 100644 lib/classes/CoursewarePDFCertificate.php create mode 100644 lib/cronjobs/courseware.php create mode 100644 lib/models/Courseware/Certificate.php create mode 100755 public/assets/images/pdf/pdf_default_background.jpg create mode 100644 templates/courseware/mails/certificate.php diff --git a/db/migrations/5.3.11_courseware_cron_events.php b/db/migrations/5.3.11_courseware_cron_events.php new file mode 100644 index 00000000000..48dbfcf130a --- /dev/null +++ b/db/migrations/5.3.11_courseware_cron_events.php @@ -0,0 +1,49 @@ +<?php + +require_once('lib/cronjobs/courseware.php'); + +class CoursewareCronEvents extends Migration +{ + public function description() + { + return 'Prepares database tables for storing timestamps of courseware cron events, ' . + 'like certificate sending and reminders.'; + } + + public function up() + { + // Create a table for certificates + DBManager::get()->exec("CREATE TABLE IF NOT EXISTS `cw_certificates` ( + `id` CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, + `user_id` CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, + `course_id` CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, + `mkdate` INT(11) NOT NULL, + PRIMARY KEY (`id`), + INDEX index_user_id (`user_id`), + INDEX index_course_id (`course_id`), + INDEX index_user_ourse (`user_id`, `course_id`) + )"); + + CoursewareCronjob::register()->schedulePeriodic(41, 1)->activate(); + } + + public function down() + { + CoursewareCronjob::unregister(); + + DBManager::get()->exec("DROP TABLE IF EXISTS `cw_certificates`"); + + $fields = [ + 'COURSEWARE_CERTIFICATE_SETTINGS', + 'COURSEWARE_REMINDER_SETTINGS', + 'COURSEWARE_RESET_PROGRESS_SETTINGS', + 'COURSEWARE_LAST_REMINDER', + 'COURSEWARE_LAST_PROGRESS_RESET' + ]; + DBManager::get()->execute("DELETE FROM `config` WHERE `field` IN (:fields)", + ['fields' => $fields]); + DBManager::get()->execute("DELETE FROM `config_values` WHERE `field` IN (:fields)", + ['fields' => $fields]); + } + +} diff --git a/lib/classes/CoursewarePDFCertificate.php b/lib/classes/CoursewarePDFCertificate.php new file mode 100644 index 00000000000..e3ef02f70bb --- /dev/null +++ b/lib/classes/CoursewarePDFCertificate.php @@ -0,0 +1,40 @@ +<?php + +class CoursewarePDFCertificate extends TCPDF +{ + public function __construct($background = false, $orientation = 'P', $unit = 'mm', $format = 'A4', $unicode = true, $encoding = 'UTF-8') + { + $this->config = Config::get(); + if ($this->config->getValue('LOAD_EXTERNAL_MEDIA') === 'proxy') { + $this->media_proxy = new MediaProxy(); + } + parent::__construct($orientation, $unit, $format, $unicode, $encoding, false); + if ($background) { + $fileRef = FileRef::find($background); + $this->background = $fileRef->file->getPath(); + } else { + $this->background = $GLOBALS['STUDIP_BASE_PATH'] . '/public/assets/images/pdf/pdf_default_background.jpg'; + } + + $this->setDefaults(); + } + + public function Header() + { + $bMargin = $this->getBreakMargin(); + $auto_page_break = $this->AutoPageBreak; + $this->SetAutoPageBreak(false, 0); + $this->Image($this->background, 0, 0, 210, 297, '', '', '', false, 300, '', false, false, 0); + $this->setFont('helvetica', 'B', 50); + $this->Cell(0, 160, 'Z E R T I F I K A T', 0, false, 'C', 0, '', 0, false, 'T', 'M'); + $this->SetAutoPageBreak($auto_page_break, $bMargin); + $this->setPageMark(); + } + + private function setDefaults() + { + $this->SetTopMargin(110); + $this->SetLeftMargin(20); + $this->SetRightMargin(20); + } +} diff --git a/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php b/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php index 965e3b64980..2b70cbf90b6 100644 --- a/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php +++ b/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php @@ -78,6 +78,30 @@ class CoursewareInstancesUpdate extends JsonApiController return 'Attribute `editing-permission-level` contains an invalid value.'; } } + + if (self::arrayHas($json, 'data.attributes.certificate-settings')) { + $certificateSettings = self::arrayGet($json, 'data.attributes.certificate-settings'); + + if (!$resource->isValidCertificateSettings($certificateSettings)) { + return 'Attribute `certificate-settings` contains an invalid value.'; + } + } + + if (self::arrayHas($json, 'data.attributes.reminder-settings')) { + $reminderSettings = self::arrayGet($json, 'data.attributes.reminder-settings'); + + if (!$resource->isValidReminderSettings($reminderSettings)) { + return 'Attribute `reminder-settings` contains an invalid value.'; + } + } + + if (self::arrayHas($json, 'data.attributes.reset-progress-settings')) { + $resetProgressSettings = self::arrayGet($json, 'data.attributes.reset-progress-settings'); + + if (!$resource->isValidResetProgressSettings($resetProgressSettings)) { + return 'Attribute `reset-progress-settings` contains an invalid value.'; + } + } } private function updateInstance(\User $user, Instance $instance, array $json): Instance @@ -95,6 +119,15 @@ class CoursewareInstancesUpdate extends JsonApiController $editingPermissionLevel = $get('data.attributes.editing-permission-level'); $instance->setEditingPermissionLevel($editingPermissionLevel); + $certificateSettings = $get('data.attributes.certificate-settings'); + $instance->setCertificateSettings($certificateSettings); + + $reminderSettings = $get('data.attributes.reminder-settings'); + $instance->setReminderSettings($reminderSettings); + + $resetProgressSettings = $get('data.attributes.reset-progress-settings'); + $instance->setResetProgressSettings($resetProgressSettings); + return $instance; } } diff --git a/lib/classes/JsonApi/Schemas/Courseware/Instance.php b/lib/classes/JsonApi/Schemas/Courseware/Instance.php index 055c387defd..63a4d950b83 100644 --- a/lib/classes/JsonApi/Schemas/Courseware/Instance.php +++ b/lib/classes/JsonApi/Schemas/Courseware/Instance.php @@ -36,6 +36,9 @@ class Instance extends SchemaProvider 'favorite-block-types' => $resource->getFavoriteBlockTypes($user), 'sequential-progression' => (bool) $resource->getSequentialProgression(), 'editing-permission-level' => $resource->getEditingPermissionLevel(), + 'certificate-settings' => $resource->getCertificateSettings(), + 'reminder-settings' => $resource->getReminderSettings(), + 'reset-progress-settings' => $resource->getResetProgressSettings() ]; } diff --git a/lib/cronjobs/courseware.php b/lib/cronjobs/courseware.php new file mode 100644 index 00000000000..16e0ad96475 --- /dev/null +++ b/lib/cronjobs/courseware.php @@ -0,0 +1,341 @@ +<?php +/** + * courseware.php + * + * @author Thomas Hackl <hackl@data-quest.de> + * @access public + * @since 5.3 + */ + +class CoursewareCronjob extends CronJob +{ + public static function getName() + { + return _('Courseware-Erinnerungen und -zertifikate verschicken sowie Fortschritt zurücksetzen'); + } + + public static function getDescription() + { + return _('Versendet Erinnerungen, Zertifikate bei Erreichen eines bestimmten Fortschritts und setzt ' . + 'Fortschritt bei derartig konfigurierten Coursewares zurück.'); + } + + public static function getParameters() + { + return [ + 'verbose' => [ + 'type' => 'boolean', + 'default' => false, + 'status' => 'optional', + 'description' => _('Sollen Ausgaben erzeugt werden (sind später im Log des Cronjobs sichtbar)'), + ] + ]; + } + + public function setUp() + { + } + + public function execute($last_result, $parameters = []) + { + $verbose = $parameters['verbose']; + + /* + * Fetch all courses that have some relevant settings. + */ + $todo = DBManager::get()->fetchAll( + "SELECT c.`range_id`, c. `field`, c.`value` + FROM `config_values` c + JOIN `seminare` s ON (s.`Seminar_id` = c.`range_id`) + WHERE c.`field` IN (:fields)", + ['fields' => [ + // Send certificate when this progress is reached + 'COURSEWARE_CERTIFICATE_SETTINGS', + // Remind all users about courseware + 'COURSEWARE_REMINDER_SETTINGS', + // Reset user progress to 0 + 'COURSEWARE_RESET_PROGRESS_SETTINGS' + ] + ] + ); + + if (count($todo) > 0) { + + if ($verbose) { + echo sprintf("Found %u courses to process.\n", count($todo)); + } + + $timezone = Config::get()->DEFAULT_TIMEZONE; + + // Process all found entries... + foreach ($todo as $one) { + + // Fetch all courseware blocks belonging to the current course. + $blocks = DBManager::get()->fetchFirst( + "SELECT DISTINCT b.`id` + FROM `cw_blocks` b + JOIN `cw_containers` c ON (c.`id` = b.`container_id`) + JOIN `cw_structural_elements` e ON (e.`id` = c.`structural_element_id`) + WHERE e.`range_id` = :course", + ['course' => $one['range_id']] + ); + + // extract details from JSON + $settings = json_decode($one['value'], true); + + // differentiate by setting type + switch ($one['field']) { + // Send certificates to those who have progressed far enough and have not yet gotten one. + case 'COURSEWARE_CERTIFICATE_SETTINGS': + + if ($verbose) { + echo sprintf("Generating certificates for course %s.\n", + $one['range_id']); + } + + // Fetch accumulated progress values for all users in this course. + $progresses = DBManager::get()->fetchAll( + "SELECT DISTINCT p.`user_id`, SUM(p.`grade`) AS progress + FROM `cw_user_progresses` p + WHERE `block_id` IN (:blocks) + AND NOT EXISTS ( + SELECT `id` FROM `cw_certificates` WHERE `user_id` = p.`user_id` AND `course_id` = :course + ) + GROUP BY `user_id`", + ['blocks' => $blocks, 'course' => $one['range_id']] + ); + + // Calculate percentual progress and send certificates if necessary. + foreach ($progresses as $progress) { + $percent = ($progress['progress'] / count($blocks)) * 100; + if ($percent >= $settings['threshold']) { + if ($verbose) { + echo sprintf("User %s will get a certificate for course %s.\n", + $progress['user_id'], $one['range_id']); + } + + $this->sendCertificate($one['range_id'], $progress['user_id'], + $percent, $settings); + + /* + * Insert a new entry into database for tracking who already got a certificate. + * This can be useful if certificates get a validity time or such. + */ + $entry = new Courseware\Certificate(); + $entry->user_id = $progress['user_id']; + $entry->course_id = $one['range_id']; + $entry->store(); + } + } + + break; + + // Send reminders to all course participants. + case 'COURSEWARE_REMINDER_SETTINGS': + + // Check when the last reminder was sent... + $now = new DateTime('', new DateTimeZone($timezone)); + + // What would be the minimum date for the last reminder? + $minReminder = clone $now; + + // The last reminder has been sent at? + $lastReminder = new DateTime('', new DateTimeZone($timezone)); + $lastReminder->setTimestamp( + UserConfig::get($one['range_id'])->COURSEWARE_LAST_REMINDER ?: 0 + ); + + // Check if the settings specify a start and/or end date for reminders + $start = new DateTime($settings['startDate'] ?: '1970-01-01', + new DateTimeZone($timezone)); + $end = new DateTime($settings['endDate'] ?: '2199-12-31', + new DateTimeZone($timezone)); + + $interval = new DateInterval('P1D'); + switch ($settings['interval']) { + case 7: + $interval = new DateInterval('P7D'); + break; + case 14: + $interval = new DateInterval('P14D'); + break; + case 30: + $interval = new DateInterval('P1M'); + break; + case 90: + $interval = new DateInterval('P3M'); + break; + case 180: + $interval = new DateInterval('P6M'); + break; + case 365: + $interval = new DateInterval('P1Y'); + break; + } + $minReminder->sub($interval); + + // ... and send a new one if necessary. + if ($lastReminder <= $minReminder && $now >= $start && $now <= $end) { + if ($verbose) { + echo sprintf("Sending reminders for course %s.\n", + $one['range_id']); + } + + if ($this->sendReminders($one['range_id'], $settings)) { + UserConfig::get($one['range_id'])->store('COURSEWARE_LAST_REMINDER', + $now->getTimestamp() + ); + } + } + + break; + + // Reset courseware progress to 0 for all course participants. + case 'COURSEWARE_RESET_PROGRESS_SETTINGS': + + // Check when the last reset was performed... + $now = new DateTime('', new DateTimeZone($timezone)); + $checkLast = clone $now; + $lastReset = new DateTime('', new DateTimeZone($timezone)); + $lastReset->setTimestamp( + UserConfig::get($one['range_id'])->COURSEWARE_LAST_PROGRESS_RESET ?: 0 + ); + + $interval = new DateInterval('P1D'); + switch ($one['value']) { + case 14: + $interval = new DateInterval('P14D'); + break; + case 30: + $interval = new DateInterval('P1M'); + break; + case 90: + $interval = new DateInterval('P3M'); + break; + case 180: + $interval = new DateInterval('P6M'); + break; + case 365: + $interval = new DateInterval('P1Y'); + break; + } + + // ... and reset again if necessary. + if ($lastReset <= $checkLast->sub($interval)) { + if ($verbose) { + echo sprintf("Resetting all progress for courseware in course %s.\n", + $one['range_id']); + } + + // Remove all progress in the given blocks. + $this->resetProgress($one['range_id'], $blocks, $settings); + + UserConfig::get($one['range_id'])->store('COURSEWARE_LAST_PROGRESS_RESET', + $now->getTimestamp() + ); + } + } + } + + } else if ($verbose) { + echo "Nothing to do.\n"; + } + } + + private function sendCertificate($course_id, $user_id, $progress, $settings) + { + $user = User::find($user_id); + $course = Course::find($course_id); + + $template = $GLOBALS['template_factory']->open('courseware/mails/certificate'); + $html = $template->render( + compact('user', 'course') + ); + + // Generate the PDF. + $pdf = new CoursewarePDFCertificate($settings['image']); + $pdf->AddPage(); + $pdf->writeHTML($html, true, false, true, false, ''); + $pdf_file_name = $user->nachname . '_' . $course->name . '_' . _('Zertifikat') . '.pdf'; + $filename = $GLOBALS['TMP_PATH'] . '/' . $pdf_file_name; + $pdf->Output($filename, 'F'); + + // Send the mail with PDF attached. + $mail = new StudipMail(); + + $message = sprintf( + _('Anbei erhalten Sie Ihr Courseware-Zertifikat zur Veranstaltung %1$s, in der Sie einen Fortschritt ' . + 'von %2$u %% erreicht haben.'), $course->getFullname(), $progress); + $message .= "\n\n" . _('Über folgenden Link kommen Sie direkt zur Courseware') . ': ' . + URLHelper::getURL('seminar_main.php', ['auswahl' => $course->id, + 'redirect_to' => 'dispatch.php/course/courseware']); + + $mail->addRecipient($user->email, $user->getFullname()) + ->setSubject(_('Courseware: Zertifikat') . ' - ' . $course->getFullname()) + ->setBodyText($message) + ->addFileAttachment($filename, $pdf_file_name) + ->send(); + + @unlink($filename); + + // Add database entry for the certificate. + + } + + private function sendReminders($course_id, $settings) + { + $course = Course::find($course_id); + + $recipients = $course->getMembersWithStatus('autor', true); + + $mail = new StudipMail(); + + foreach ($recipients as $rec) { + $mail->addRecipient( + $rec->email, + $rec->getUserFullname(), + 'bcc' + ); + } + + $message = $settings['mailText'] . "\n\n" . _('Über folgenden Link kommen Sie direkt zur Courseware') . ': ' . + URLHelper::getURL('seminar_main.php', ['auswahl' => $course->id, + 'redirect_to' => 'dispatch.php/course/courseware']); + + $mail->setSubject(_('Courseware: Erinnerung') . ' - ' . $course->getFullname()) + ->setBodyText($message); + + return $mail->send(); + } + + private function resetProgress($course_id, $block_ids, $settings) + { + $course = Course::find($course_id); + + DBManager::get()->execute( + "DELETE FROM `cw_user_progresses` WHERE `block_id` IN (:blocks)", + ['blocks' => $block_ids] + ); + + $recipients = $course->getMembersWithStatus('autor', true); + + $mail = new StudipMail(); + + foreach ($recipients as $rec) { + $mail->addRecipient( + $rec->email, + $rec->getUserFullname(), + 'bcc' + ); + } + + $message = $settings['mailText'] . "\n\n" . _('Über folgenden Link kommen Sie direkt zur Courseware') . ': ' . + URLHelper::getURL('seminar_main.php', ['auswahl' => $course->id, + 'redirect_to' => 'dispatch.php/course/courseware']); + + $mail->setSubject(_('Courseware: Fortschritt zurückgesetzt') . ' - ' . $course->getFullname()) + ->setBodyText($message); + + return $mail->send(); + } +} diff --git a/lib/models/Courseware/Certificate.php b/lib/models/Courseware/Certificate.php new file mode 100644 index 00000000000..d0c9fd9a5e1 --- /dev/null +++ b/lib/models/Courseware/Certificate.php @@ -0,0 +1,39 @@ +<?php + +namespace Courseware; + +use \User, \Course; + +/** + * Courseware's certificates. + * + * @author Thomas Hackl <hackl@data-quest.de> + * @license GPL2 or any later version + * + * @since Stud.IP 5.3 + * + * @property string $id database column + * @property string $user_id database column + * @property string $course_id database column + * @property int $mkdate database column + */ +class Certificate extends \SimpleORMap +{ + protected static function configure($config = []) + { + $config['db_table'] = 'cw_certificates'; + + $config['belongs_to']['user'] = [ + 'class_name' => User::class, + 'foreign_key' => 'user_id', + ]; + + $config['belongs_to']['course'] = [ + 'class_name' => Course::class, + 'foreign_key' => 'course_id', + ]; + + parent::configure($config); + } + +} diff --git a/lib/models/Courseware/Instance.php b/lib/models/Courseware/Instance.php index c823a4edbde..0b388fe93ca 100644 --- a/lib/models/Courseware/Instance.php +++ b/lib/models/Courseware/Instance.php @@ -231,6 +231,161 @@ class Instance } } + + /** + * Returns the certificate creation settings. + * + * @return array + */ + public function getCertificateSettings(): array + { + $range = $this->getRange(); + /** @var array $certificateSettings */ + $certificateSettings = json_decode( + $range->getConfiguration()->getValue('COURSEWARE_CERTIFICATE_SETTINGS'), + true + )?: []; + $this->validateCertificateSettings($certificateSettings); + + return $certificateSettings; + } + + /** + * Sets the certificate settings for this courseware instance. + * + * @param array $certificateSettings an array of parameters + */ + public function setCertificateSettings(array $certificateSettings): void + { + $this->validateCertificateSettings($certificateSettings); + $range = $this->getRange(); + $range->getConfiguration()->store('COURSEWARE_CERTIFICATE_SETTINGS', + count($certificateSettings) > 0 ? json_encode($certificateSettings) : null); + } + + /** + * Validates certificate settings. + * + * @param array $certificateSettings settings for certificate creation + * + * @return bool true if all given values are valid, false otherwise + */ + public function isValidCertificateSettings(array $certificateSettings): bool + { + return (int) $certificateSettings['threshold'] >= 0 && (int) $certificateSettings['threshold'] <= 100; + } + + private function validateCertificateSettings(array $certificateSettings): void + { + if (!$this->isValidCertificateSettings($certificateSettings)) { + throw new \InvalidArgumentException('Invalid certificate settings given.'); + } + } + + /** + * Returns the reminder message sending settings. + * + * @return array + */ + public function getReminderSettings(): array + { + $range = $this->getRange(); + /** @var int $reminderInterval */ + $reminderSettings = json_decode( + $range->getConfiguration()->getValue('COURSEWARE_REMINDER_SETTINGS'), + true + )?: []; + $this->validateReminderSettings($reminderSettings); + + return $reminderSettings; + } + + /** + * Sets the reminder message settings this courseware instance. + * + * @param array $reminderSettings an array of parameters + */ + public function setReminderSettings(array $reminderSettings): void + { + $this->validateReminderSettings($reminderSettings); + $range = $this->getRange(); + $range->getConfiguration()->store('COURSEWARE_REMINDER_SETTINGS', + count($reminderSettings) > 0 ? json_encode($reminderSettings) : null); + } + + /** + * Validates reminder message settings. + * + * @param array $reminderSettings settings for reminder mail sending + * + * @return bool true if all given values are valid, false otherwise + */ + public function isValidReminderSettings(array $reminderSettings): bool + { + $valid = in_array($reminderSettings['interval'], [0, 7, 14, 30, 90, 180, 365]); + + return $valid; + } + + private function validateReminderSettings(array $reminderSettings): void + { + if (!$this->isValidReminderSettings($reminderSettings)) { + throw new \InvalidArgumentException('Invalid reminder settings given.'); + } + } + + /** + * Returns the progress resetting settings. + * + * @return array + */ + public function getResetProgressSettings(): array + { + $range = $this->getRange(); + /** @var int $reminderInterval */ + $resetProgressSettings = json_decode( + $range->getConfiguration()->getValue('COURSEWARE_RESET_PROGRESS_SETTINGS'), + true + )?: []; + $this->validateResetProgressSettings($resetProgressSettings); + + return $resetProgressSettings; + } + + /** + * Sets the progress resetting settings this courseware instance. + * + * @param array $reminderSettings an array of parameters + */ + public function setResetProgressSettings(array $resetProgressSettings): void + { + $this->validateResetProgressSettings($resetProgressSettings); + $range = $this->getRange(); + $range->getConfiguration()->store('COURSEWARE_RESET_PROGRESS_SETTINGS', + count($resetProgressSettings) > 0 ? json_encode($resetProgressSettings) : null); + } + + /** + * Validates progress resetting settings. + * + * @param array $resetProgressSettings settings for progress resetting + * + * @return bool true if all given values are valid, false otherwise + */ + public function isValidResetProgressSettings(array $resetProgressSettings): bool + { + $valid = in_array($resetProgressSettings['interval'], [0, 14, 30, 90, 180, 365]); + + return $valid; + } + + private function validateResetProgressSettings(array $resetProgressSettings): void + { + if (!$this->isValidResetProgressSettings($resetProgressSettings)) { + throw new \InvalidArgumentException('Invalid progress resetting settings given.'); + } + } + /** * Returns all bookmarks of a user associated to this courseware instance. * diff --git a/public/assets/images/pdf/pdf_default_background.jpg b/public/assets/images/pdf/pdf_default_background.jpg new file mode 100755 index 0000000000000000000000000000000000000000..e91edda46beb097e11b4bc1f64eaf0e71029dd53 GIT binary patch literal 135997 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 W)xp!H;E7Z46zYG5m1pYz-vj_poic0y literal 0 HcmV?d00001 diff --git a/resources/vue/components/courseware/CoursewareToolsAdmin.vue b/resources/vue/components/courseware/CoursewareToolsAdmin.vue index 337a39e47fe..974e6fbbf8d 100644 --- a/resources/vue/components/courseware/CoursewareToolsAdmin.vue +++ b/resources/vue/components/courseware/CoursewareToolsAdmin.vue @@ -2,37 +2,195 @@ <div class="cw-tools cw-tools-admin"> <form class="default" @submit.prevent=""> <fieldset> - <legend><translate>Allgemeine Einstellungen</translate></legend> + <legend>{{ $gettext('Allgemeine Einstellungen') }}</legend> <label> - <span><translate>Art der Inhaltsabfolge</translate></span> + <span>{{ $gettext('Art der Inhaltsabfolge') }}</span> <select class="size-s" v-model="currentProgression"> - <option value="0"><translate>Frei</translate></option> - <option value="1"><translate>Sequentiell</translate></option> + <option value="0">{{ $gettext('Frei') }}</option> + <option value="1">{{ $gettext('Sequentiell') }}</option> </select> </label> <label> - <span><translate>Editierberechtigung für Tutor/-innen</translate></span> + <span>{{ $gettext('Editierberechtigung für Tutor/-innen') }}</span> <select class="size-s" v-model="currentPermissionLevel"> - <option value="dozent"><translate>Nein</translate></option> - <option value="tutor"><translate>Ja</translate></option> + <option value="dozent">{{ $gettext('Nein') }}</option> + <option value="tutor">{{ $gettext('Ja') }}</option> </select> </label> </fieldset> + <fieldset> + <legend> + {{ $gettext('Zertifikate') }} + </legend> + <label> + <input type="checkbox" name="makecert" v-model="makeCert"> + <span> + {{ $gettext('Zertifikat bei Erreichen einer Fortschrittsgrenze versenden') }} + </span> + <studip-tooltip-icon :text="$gettext('Erreicht eine Person in diesem Lernmaterial den ' + + 'hier eingestellten Fortschritt, so erhält Sie ein PDF-Zertifikat per E-Mail.')"/> + </label> + <label v-if="makeCert"> + <span> + {{ $gettext('Erforderlicher Fortschritt (in Prozent), um ein Zertifikat zu erhalten') }} + </span> + <input type="number" min="1" max="100" name="threshold" v-model="certThreshold"> + </label> + <label v-if="makeCert"> + <span> + {{ $gettext('Hintergrundbild des Zertifikats wählen') }} + </span> + <courseware-file-chooser :isImage="true" v-model="certImage" + @selectFile="updateCertImage"></courseware-file-chooser> + </label> + </fieldset> + <fieldset> + <legend> + {{ $gettext('Erinnerungen') }} + </legend> + <label> + <input type="checkbox" name="sendreminders" v-model="sendReminders"> + <span> + {{ $gettext('Erinnerungsnachrichten an alle Teilnehmenden schicken') }} + </span> + <studip-tooltip-icon :text="$gettext('Hier können periodisch Nachrichten an alle ' + + 'Teilnehmenden verschickt werden, um z.B. an die Bearbeitung dieses Lernmaterials zu erinnern.')"/> + </label> + + <label v-if="sendReminders"> + <span> + {{ $gettext('Zeitraum zwischen Erinnerungen') }} + </span> + <select name="reminder_interval" v-model="reminderInterval"> + <option value="7"> + {{ $gettext('wöchentlich') }} + </option> + <option value="14"> + {{ $gettext('14-tägig') }} + </option> + <option value="30"> + {{ $gettext('monatlich') }} + </option> + <option value="90"> + {{ $gettext('vierteljährlich') }} + </option> + <option value="180"> + {{ $gettext('halbjährlich') }} + </option> + <option value="365"> + {{ $gettext('jährlich') }} + </option> + </select> + </label> + <label v-if="sendReminders" class="col-3"> + <span> + {{ $gettext('Erstmalige Erinnerung am') }} + <input type="date" name="reminder_start_date" + v-model="reminderStartDate"> + </span> + </label> + <label v-if="sendReminders" class="col-3"> + <span> + {{ $gettext('Letztmalige Erinnerung am') }} + <input type="date" name="reminder_end_date" + v-model="reminderEndDate"> + </span> + </label> + <label v-if="sendReminders"> + <span> + {{ $gettext('Text der Erinnerungsmail') }} + <textarea cols="70" rows="4" name="reminder_mail_text" data-editor="minimal" + v-model="reminderMailText"></textarea> + </span> + </label> + </fieldset> + <fieldset> + <legend> + {{ $gettext('Fortschritt') }} + </legend> + <label> + <input type="checkbox" name="resetprogress" v-model="resetProgress"> + <span> + {{ $gettext('Fortschritt periodisch auf 0 zurücksetzen') }} + </span> + <studip-tooltip-icon :text="$gettext('Hier kann eingestellt werden, den Fortschritt ' + + 'aller Teilnehmenden periodisch auf 0 zurückzusetzen.')"/> + </label> + <label v-if="resetProgress"> + <span> + {{ $gettext('Zeitraum zum Rücksetzen des Fortschritts') }} + </span> + <select name="reset_progress_interval" v-model="resetProgressInterval"> + <option value="14"> + {{ $gettext('14-tägig') }} + </option> + <option value="30"> + {{ $gettext('monatlich') }} + </option> + <option value="90"> + {{ $gettext('vierteljährlich') }} + </option> + <option value="180"> + {{ $gettext('halbjährlich') }} + </option> + <option value="365"> + {{ $gettext('jährlich') }} + </option> + </select> + </label> + <label v-if="resetProgress" class="col-3"> + <span> + {{ $gettext('Erstmaliges Zurücksetzen am') }} + <input type="date" dataformatas="" name="reset_progress_start_date" + v-model="resetProgressStartDate"> + </span> + </label> + <label v-if="resetProgress" class="col-3"> + <span> + {{ $gettext('Letztmaliges Zurücksetzen am') }} + <input type="date" name="reset_progress_end_date" + v-model="resetProgressEndDate"> + </span> + </label> + <label v-if="resetProgress"> + <span> + {{ $gettext('Text der Rücksetzungsmail') }} + <textarea cols="70" rows="4" name="reset_progress_mail_text" data-editor="minimal" + v-model="resetProgressMailText"></textarea> + </span> + </label> + </fieldset> </form> - <button class="button" @click="store"><translate>Übernehmen</translate></button> + <button class="button" @click="store">{{ $gettext('Übernehmen') }}</button> </div> </template> <script> import { mapActions, mapGetters } from 'vuex'; +import CoursewareFileChooser from "./CoursewareFileChooser.vue"; +import StudipTooltipIcon from '../StudipTooltipIcon.vue'; export default { name: 'cw-tools-admin', + components: { StudipTooltipIcon, CoursewareFileChooser }, data() { return { currentPermissionLevel: '', currentProgression: '', + makeCert: false, + certThreshold: 0, + certImage: '', + sendReminders: false, + reminderInterval: 7, + reminderStartDate: '', + reminderEndDate: '', + reminderMailText: '', + resetProgress: false, + resetProgressInterval: 180, + resetProgressStartDate: '', + resetProgressEndDate: '', + resetProgressMailText: '' }; }, computed: { @@ -46,8 +204,28 @@ export default { companionSuccess: 'companionSuccess', }), initData() { + console.log(this.courseware.attributes); this.currentPermissionLevel = this.courseware.attributes['editing-permission-level']; this.currentProgression = this.courseware.attributes['sequential-progression'] ? '1' : '0'; + this.certSettings = this.courseware.attributes['certificate-settings']; + this.makeCert = typeof(this.certSettings) === 'object' && + Object.keys(this.certSettings).length > 0; + this.certThreshold = this.certSettings.threshold; + this.certImage = this.certSettings.image; + this.reminderSettings = this.courseware.attributes['reminder-settings']; + this.sendReminders = typeof(this.reminderSettings) === 'object' && + Object.keys(this.reminderSettings).length > 0; + this.reminderInterval = this.reminderSettings.interval; + this.reminderStartDate = this.reminderSettings.startDate; + this.reminderEndDate = this.reminderSettings.endDate; + this.reminderMailText = this.reminderSettings.mailText; + this.resetProgressSettings = this.courseware.attributes['reset-progress-settings']; + this.resetProgress = typeof(this.resetProgressSettings) === 'object' && + Object.keys(this.resetProgressSettings).length > 0; + this.resetProgressInterval = this.resetProgressSettings.interval; + this.resetProgressStartDate = this.resetProgressSettings.startDate; + this.resetProgressEndDate = this.resetProgressSettings.endDate; + this.resetProgressMailText = this.resetProgressSettings.mailText; }, store() { this.companionSuccess({ @@ -56,8 +234,36 @@ export default { this.storeCoursewareSettings({ permission: this.currentPermissionLevel, progression: this.currentProgression, + certificateSettings: this.generateCertificateSettings(), + reminderSettings: this.generateReminderSettings(), + resetProgressSettings: this.generateResetProgressSettings() }); }, + generateCertificateSettings() { + return this.makeCert ? { + threshold: this.certThreshold, + image: this.certImage + } : {}; + }, + generateReminderSettings() { + return this.sendReminders ? { + interval: this.reminderInterval, + startDate: this.reminderStartDate, + endDate: this.reminderEndDate, + mailText: this.reminderMailText + } : {}; + }, + generateResetProgressSettings() { + return this.resetProgress ? { + interval: this.resetProgressInterval, + startDate: this.resetProgressStartDate, + endDate: this.resetProgressEndDate, + mailText: this.resetProgressMailText + } : {}; + }, + updateCertImage(file) { + this.certImage = file.id; + } }, mounted() { this.initData(); diff --git a/resources/vue/store/courseware/courseware.module.js b/resources/vue/store/courseware/courseware.module.js index 1380ea008db..e6e14acea08 100644 --- a/resources/vue/store/courseware/courseware.module.js +++ b/resources/vue/store/courseware/courseware.module.js @@ -536,10 +536,15 @@ export const actions = { return dispatch('loadContainer', containerId); }, - async storeCoursewareSettings({ dispatch, getters }, { permission, progression }) { + async storeCoursewareSettings({ dispatch, getters }, + { permission, progression, certificateSettings, reminderSettings, + resetProgressSettings }) { const courseware = getters.courseware; courseware.attributes['editing-permission-level'] = permission; courseware.attributes['sequential-progression'] = progression; + courseware.attributes['certificate-settings'] = certificateSettings; + courseware.attributes['reminder-settings'] = reminderSettings; + courseware.attributes['reset-progress-settings'] = resetProgressSettings; return dispatch('courseware-instances/update', courseware, { root: true }); }, diff --git a/templates/courseware/mails/certificate.php b/templates/courseware/mails/certificate.php new file mode 100644 index 00000000000..ed1e099de03 --- /dev/null +++ b/templates/courseware/mails/certificate.php @@ -0,0 +1,22 @@ +<?php +$p = '<p style="font-size: 20px; text-align: center;">'; +$span_bold = '<br /><br /><span style="font-size: 20px; text-align: center; font-weight: bold">'; +$span_close = '</span><br /><br />'; +switch($user->geschlecht) { + case 1: + $anrede = _('Herr'); + break; + case 2: + $anrede = _('Frau'); + break; + default: + $anrede= ''; +} +echo $p; +printf( + _("Hiermit wird bescheinigt, dass %s am %s erfolgreich am Seminar %s teilgenommen hat."), + $span_bold . $anrede . ' ' . $user->getFullname() . $span_close, + $span_bold . date('d.m.Y', time()) . $span_close, + $span_bold . $course->name . $span_close +); +echo '</p>'; -- GitLab