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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 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