Skip to content
Snippets Groups Projects
Commit 65a5354a authored by Thomas Hackl's avatar Thomas Hackl
Browse files

Resolve "Zertifikatsversand muss für neue Coursewarefunktionen angepasst werden"

Closes #2027

Merge request studip/studip!1320
parent f9e2a720
No related branches found
No related tags found
1 merge request!4Draft: Icon creation
<?php
class CwUnitAdjustments extends Migration
{
public function description()
{
return 'adjust courseware config to units';
}
public function up()
{
// Add column for storing per-unit configuration.
DBManager::get()->exec(
"ALTER TABLE `cw_units` ADD `config` TEXT NOT NULL DEFAULT '' AFTER `withdraw_date`"
);
// Which fields in config are relevant for this migration?
$fields = [
'COURSEWARE_SEQUENTIAL_PROGRESSION',
'COURSEWARE_EDITING_PERMISSION',
'COURSEWARE_CERTIFICATE_SETTINGS',
'COURSEWARE_REMINDER_SETTINGS',
'COURSEWARE_RESET_PROGRESS_SETTINGS',
'COURSEWARE_LAST_REMINDER',
'COURSEWARE_LAST_PROGRESS_RESET'
];
// Which courses do have custom courseware settings and need to be migrated?
$ranges = DBManager::get()->fetchFirst(
"SELECT DISTINCT `range_id` FROM `config_values` WHERE `field` IN (:fields)",
['fields' => $fields]
);
$update = DBManager::get()->prepare("UPDATE `cw_units` SET `config` = :config WHERE `id` = :unit");
// Get courseware settings per course as stored in config_values,
foreach ($ranges as $course) {
$global = DBManager::get()->fetchAll(
"SELECT `field`, `value` FROM `config_values` WHERE `range_id` = :range AND `field` IN (:fields)",
['range' => $course, 'fields' => $fields]
);
// Build configuration per unit.
$config = [];
// Convert values.
foreach ($global as $one) {
$decoded = json_decode($one['value'], true);
foreach ($decoded as $unit_id => $settings) {
switch ($one['field']) {
case 'COURSEWARE_SEQUENTIAL_PROGRESSION':
$config[$unit_id]['sequential_progression'] = $settings;
break;
case 'COURSEWARE_EDITING_PERMISSION':
$config[$unit_id]['editing_permission'] = $settings;
break;
case 'COURSEWARE_CERTIFICATE_SETTINGS':
$config[$unit_id]['certificate'] = $settings;
break;
case 'COURSEWARE_REMINDER_SETTINGS':
$config[$unit_id]['reminder'] = $settings;
break;
case 'COURSEWARE_RESET_PROGRESS_SETTINGS':
$config[$unit_id]['reset_progress'] = $settings;
break;
case 'COURSEWARE_LAST_REMINDER':
$config[$unit_id]['last_reminder'] = $settings;
break;
case 'COURSEWARE_LAST_PROGRESS_RESET':
$config[$unit_id]['last_progress_reset'] = $settings;
break;
}
}
}
// Now write per-unit configurations to database.
foreach ($config as $unit => $config) {
$update->execute(['config' => json_encode($config), 'unit' => $unit]);
}
}
// Drop old values from global config.
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]
);
// Add column for storing unit_id with certificate date.
DBManager::get()->exec(
"ALTER TABLE `cw_certificates` ADD `unit_id` INT NOT NULL AFTER `course_id`"
);
DBManager::get()->exec("ALTER TABLE `cw_certificates` DROP INDEX `index_course_id`, DROP INDEX `index_user_ourse`");
DBManager::get()->exec("ALTER TABLE `cw_certificates` ADD INDEX index_unit_id (`unit_id`)");
}
public function down()
{
// Drop columns for storing per-unit configuration.
DBManager::get()->exec("ALTER TABLE `cw_units` DROP `config`");
DBManager::get()->exec("ALTER TABLE `cw_certificates` DROP `unit_id`");
}
}
......@@ -133,6 +133,9 @@ class CoursewareInstancesUpdate extends JsonApiController
$resetProgressSettings = $get('data.attributes.reset-progress-settings');
$instance->setResetProgressSettings($resetProgressSettings);
// Store changes in unit configuration.
$instance->getUnit()->store();
return $instance;
}
}
......@@ -41,56 +41,33 @@ class CoursewareCronjob extends CronJob
$verbose = $parameters['verbose'];
/*
* Fetch all courses that have some relevant settings.
* Fetch all units 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'
]
]
$todo = Courseware\Unit::findBySQL(
"`range_type` = 'course' AND (`config` LIKE (:cert) OR `config` LIKE (:reminder) OR `config` LIKE (:reset))",
['cert' => '%"certificate":%', 'reminder' => '%"reminder":%', 'reset' => '%"reset_progress":%']
);
if (count($todo) > 0) {
if ($verbose) {
echo sprintf("Found %u courses to process.\n", count($todo));
printf("Found %u units 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']]
);
foreach ($todo as $unit) {
// extract details from JSON
$settings = json_decode($one['value'], true);
// Fetch all courseware block IDs belonging to the current unit.
$instance = new Courseware\Instance($unit->structural_element);
$blocks = array_column($instance->findAllBlocks(), 'id');
// 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 (isset($unit->config['certificate'])) {
if ($verbose) {
echo sprintf("Generating certificates for course %s.\n",
$one['range_id']);
printf("Generating certificates for course %s, unit %u.\n",
$unit->range_id, $unit->id);
}
// Fetch accumulated progress values for all users in this course.
......@@ -99,40 +76,33 @@ class CoursewareCronjob extends CronJob
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
SELECT `id` FROM `cw_certificates` WHERE `user_id` = p.`user_id` AND `unit_id` = :unit
)
GROUP BY `user_id`",
['blocks' => $blocks, 'course' => $one['range_id']]
['blocks' => $blocks, 'unit' => $unit->id]
);
// Calculate percentual progress and send certificates if necessary.
foreach ($progresses as $progress) {
$percent = ($progress['progress'] / count($blocks)) * 100;
if ($percent >= $settings['threshold']) {
printf("User %s has progress %u.\n", $progress['user_id'], $percent);
if ($percent >= $unit->config['certificate']['threshold']) {
if ($verbose) {
echo sprintf("User %s will get a certificate for course %s.\n",
$progress['user_id'], $one['range_id']);
printf("User %s will get a certificate for course %s and unit %u.\n",
$progress['user_id'], $unit->range_id, $unit->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();
if (!$this->sendCertificate($unit, $progress['user_id'], $percent,
$unit->config['certificate']['image'])) {
printf("Could not send certificate for course %s and unit %u to user %s.\n",
$unit->range_id, $unit->id, $progress['user_id']);
}
}
}
}
break;
// Send reminders to all course participants.
case 'COURSEWARE_REMINDER_SETTINGS':
// Send reminder messages to participants if necessary.
if (isset($unit->config['reminder'])) {
// Check when the last reminder was sent...
$now = new DateTime('', new DateTimeZone($timezone));
......@@ -141,18 +111,16 @@ class CoursewareCronjob extends CronJob
// The last reminder has been sent at?
$lastReminder = new DateTime('', new DateTimeZone($timezone));
$lastReminder->setTimestamp(
UserConfig::get($one['range_id'])->COURSEWARE_LAST_REMINDER ?: 0
);
$lastReminder->setTimestamp($unit->config['last_reminder'] ?? 0);
// Check if the settings specify a start and/or end date for reminders
$start = new DateTime($settings['startDate'] ?: '1970-01-01',
$start = new DateTime($unit->config['reminder']['startDate'] ?? '1970-01-01',
new DateTimeZone($timezone));
$end = new DateTime($settings['endDate'] ?: '2199-12-31',
$end = new DateTime($unit->config['reminder']['endDate'] ?? '2199-12-31',
new DateTimeZone($timezone));
$interval = new DateInterval('P1D');
switch ($settings['interval']) {
switch ($unit->config['reminder']['interval']) {
case 7:
$interval = new DateInterval('P7D');
break;
......@@ -177,32 +145,39 @@ class CoursewareCronjob extends CronJob
// ... 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']);
printf("Sending reminders for course %s and unit %u.\n",
$unit->range_id, $unit->id);
}
if ($this->sendReminders($one['range_id'], $settings)) {
UserConfig::get($one['range_id'])->store('COURSEWARE_LAST_REMINDER',
$now->getTimestamp()
);
if ($this->sendReminders($unit)) {
$unit->config['last_reminder'] = time();
}
}
}
break;
// Reset progress if necessary.
if (isset($unit->config['reset_progress'])) {
// Check when the last rest took place...
$now = new DateTime('', new DateTimeZone($timezone));
// Reset courseware progress to 0 for all course participants.
case 'COURSEWARE_RESET_PROGRESS_SETTINGS':
// What would be the minimum date for the last reset?
$minReset = clone $now;
// Check when the last reset was performed...
$now = new DateTime('', new DateTimeZone($timezone));
$checkLast = clone $now;
// The last reset was done at:
$lastReset = new DateTime('', new DateTimeZone($timezone));
$lastReset->setTimestamp(
UserConfig::get($one['range_id'])->COURSEWARE_LAST_PROGRESS_RESET ?: 0
);
$lastReset->setTimestamp($unit->config['last_progress_reset'] ?? 0);
// Check if the settings specify a start and/or end date for reminders
$start = new DateTime($unit->config['reset_progress']['startDate'] ?? '1970-01-01',
new DateTimeZone($timezone));
$end = new DateTime($unit->config['reset_progress']['endDate'] ?? '2199-12-31',
new DateTimeZone($timezone));
$interval = new DateInterval('P1D');
switch ($one['value']) {
switch ($unit->config['reset_progress']['interval']) {
case 7:
$interval = new DateInterval('P7D');
break;
case 14:
$interval = new DateInterval('P14D');
break;
......@@ -219,33 +194,34 @@ class CoursewareCronjob extends CronJob
$interval = new DateInterval('P1Y');
break;
}
$minReset->sub($interval);
// ... and reset again if necessary.
if ($lastReset <= $checkLast->sub($interval)) {
// ... and send a new one if necessary.
if ($lastReset <= $minReset && $now >= $start && $now <= $end) {
if ($verbose) {
echo sprintf("Resetting all progress for courseware in course %s.\n",
$one['range_id']);
printf("Resetting progress for course %s and unit %u.\n",
$unit->range_id, $unit->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()
);
if ($this->resetProgress($unit, $blocks, $unit->config['reset_progress']['mailText'])) {
$unit->config['last_progress_reset'] = time();
}
}
}
// Store config back, saving timestamps for reminders and progress reset.
$unit->store();
}
} else if ($verbose) {
echo "Nothing to do.\n";
}
}
private function sendCertificate($course_id, $user_id, $progress, $settings)
private function sendCertificate($unit, $user_id, $progress, $image = '')
{
$user = User::find($user_id);
$course = Course::find($course_id);
$course = Course::find($unit->range_id);
$template = $GLOBALS['template_factory']->open('courseware/mails/certificate');
$html = $template->render(
......@@ -253,7 +229,7 @@ class CoursewareCronjob extends CronJob
);
// Generate the PDF.
$pdf = new CoursewarePDFCertificate($settings['image']);
$pdf = new CoursewarePDFCertificate($image);
$pdf->AddPage();
$pdf->writeHTML($html, true, false, true, false, '');
$pdf_file_name = $user->nachname . '_' . $course->name . '_' . _('Zertifikat') . '.pdf';
......@@ -265,12 +241,12 @@ class CoursewareCronjob extends CronJob
$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);
'von %2$u %% im Lernmaterial "%s" erreicht haben.'),
$course->getFullname(), $progress, $unit->structural_element->title);
$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']);
URLHelper::getURL('dispatch.php/course/courseware/courseware/' . $unit->id, ['cid' => $course->id]);
$mail->addRecipient($user->email, $user->getFullname())
$sent = $mail->addRecipient($user->email, $user->getFullname())
->setSubject(_('Courseware: Zertifikat') . ' - ' . $course->getFullname())
->setBodyText($message)
->addFileAttachment($filename, $pdf_file_name)
......@@ -279,12 +255,20 @@ class CoursewareCronjob extends CronJob
@unlink($filename);
// Add database entry for the certificate.
if ($sent) {
$cert = new Courseware\Certificate();
$cert->user_id = $user_id;
$cert->course_id = $course->id;
$cert->unit_id = $unit->id;
return $cert->store();
} else {
return false;
}
}
private function sendReminders($course_id, $settings)
private function sendReminders($unit)
{
$course = Course::find($course_id);
$course = Course::find($unit->range_id);
$recipients = $course->getMembersWithStatus('autor', true);
......@@ -298,19 +282,19 @@ class CoursewareCronjob extends CronJob
);
}
$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']);
$message = $unit->config['reminder']['mailText'] . "\n\n" . _('Über folgenden Link kommen Sie direkt zur Courseware') . ': ' .
URLHelper::getURL('dispatch.php/course/courseware/courseware/' . $unit->id, ['cid' => $course->id]);
$mail->setSubject(_('Courseware: Erinnerung') . ' - ' . $course->getFullname())
$mail->setSubject(_('Courseware: Erinnerung') . ' - ' . $course->getFullname() .
', ' . $unit->structural_element->title)
->setBodyText($message);
return $mail->send();
}
private function resetProgress($course_id, $block_ids, $settings)
private function resetProgress($unit, $block_ids)
{
$course = Course::find($course_id);
$course = Course::find($unit->range_id);
DBManager::get()->execute(
"DELETE FROM `cw_user_progresses` WHERE `block_id` IN (:blocks)",
......@@ -329,9 +313,9 @@ class CoursewareCronjob extends CronJob
);
}
$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']);
$message = $unit->config['reset_progress']['mailText'] . "\n\n" .
_('Über folgenden Link kommen Sie direkt zur Courseware') . ': ' .
URLHelper::getURL('dispatch.php/course/courseware/courseware/' . $unit->id, ['cid' => $course->id]);
$mail->setSubject(_('Courseware: Fortschritt zurückgesetzt') . ' - ' . $course->getFullname())
->setBodyText($message);
......
......@@ -34,9 +34,6 @@ class Instance
$instance = new self($root);
$range->getConfiguration()->delete('COURSEWARE_SEQUENTIAL_PROGRESSION');
$range->getConfiguration()->delete('COURSEWARE_EDITING_PERMISSION');
$last_element_configs = \ConfigValue::findBySQL('field = ? AND value LIKE ?', [
'COURSEWARE_LAST_ELEMENT',
'%' . $range->getRangeId() . '%',
......@@ -62,6 +59,11 @@ class Instance
*/
private $root;
/**
* @var Unit
*/
private $unit;
/**
* Create a new representation of a a courseware instance.
*
......@@ -73,6 +75,7 @@ class Instance
public function __construct(StructuralElement $root)
{
$this->root = $root;
$this->unit = $root->findUnit();
}
/**
......@@ -85,6 +88,16 @@ class Instance
return $this->root;
}
/**
* Returns the unit belonging to this courseware instance.
*
* @return Unit the unit belonging this courseware instance
*/
public function getUnit(): Unit
{
return $this->unit;
}
/**
* Returns the range this courseware instance belongs to.
*
......@@ -164,9 +177,7 @@ class Instance
*/
public function getSequentialProgression(): bool
{
$range = $this->getRange();
$root = $this->getRoot();
$sequentialProgression = $range->getConfiguration()->COURSEWARE_SEQUENTIAL_PROGRESSION[$root->id];
$sequentialProgression = $this->unit->config['sequential_progression'] ?? false;
return (bool) $sequentialProgression;
}
......@@ -178,11 +189,7 @@ class Instance
*/
public function setSequentialProgression(bool $isSequentialProgression): void
{
$range = $this->getRange();
$root = $this->getRoot();
$progressions = $range->getConfiguration()->getValue('COURSEWARE_SEQUENTIAL_PROGRESSION');
$progressions[$root->id] = $isSequentialProgression ? 1 : 0;
$range->getConfiguration()->store('COURSEWARE_SEQUENTIAL_PROGRESSION', $progressions);
$this->unit->config['sequential_progression'] = $isSequentialProgression ? 1 : 0;
}
const EDITING_PERMISSION_DOZENT = 'dozent';
......@@ -195,10 +202,8 @@ class Instance
*/
public function getEditingPermissionLevel(): string
{
$range = $this->getRange();
$root = $this->getRoot();
/** @var string $editingPermissionLevel */
$editingPermissionLevel = $range->getConfiguration()->COURSEWARE_EDITING_PERMISSION[$root->id];
$editingPermissionLevel = $this->unit->config['editing_permission'];
if ($editingPermissionLevel) {
$this->validateEditingPermissionLevel($editingPermissionLevel);
return $editingPermissionLevel;
......@@ -216,11 +221,7 @@ class Instance
public function setEditingPermissionLevel(string $editingPermissionLevel): void
{
$this->validateEditingPermissionLevel($editingPermissionLevel);
$range = $this->getRange();
$root = $this->getRoot();
$permissions = $range->getConfiguration()->getValue('COURSEWARE_EDITING_PERMISSION');
$permissions[$root->id] = $editingPermissionLevel;
$range->getConfiguration()->store('COURSEWARE_EDITING_PERMISSION', $permissions);
$this->unit->config['editing_permission'] = $editingPermissionLevel;
}
/**
......@@ -250,13 +251,10 @@ class Instance
*/
public function getCertificateSettings(): array
{
$range = $this->getRange();
$root = $this->getRoot();
/** @var array $certificateSettings */
$certificateSettings = json_decode(
$range->getConfiguration()->COURSEWARE_CERTIFICATE_SETTINGS[$root->id],
true
)?: [];
$certificateSettings = isset($this->unit->config['certificate'])
? $this->unit->config['certificate']->getArrayCopy()
: [];
$this->validateCertificateSettings($certificateSettings);
return $certificateSettings;
......@@ -269,27 +267,27 @@ class Instance
*/
public function setCertificateSettings(array $certificateSettings): void
{
if (count($certificateSettings) > 0) {
$this->validateCertificateSettings($certificateSettings);
$range = $this->getRange();
$root = $this->getRoot();
$settings = $range->getConfiguration()->getValue('COURSEWARE_CERTIFICATE_SETTINGS');
$settings[$root->id] = count($certificateSettings) > 0 ? json_encode($certificateSettings) : null;
$range->getConfiguration()->store('COURSEWARE_CERTIFICATE_SETTINGS', $settings);
$this->unit->config['certificate'] = $certificateSettings;
} else {
unset($this->unit->config['certificate']);
}
}
/**
* Validates certificate settings.
*
* @param array $certificateSettings settings for certificate creation
* @param \JSONArrayObject $certificateSettings settings for certificate creation
*
* @return bool true if all given values are valid, false otherwise
*/
public function isValidCertificateSettings(array $certificateSettings): bool
public function isValidCertificateSettings($certificateSettings): bool
{
return (int) $certificateSettings['threshold'] >= 0 && (int) $certificateSettings['threshold'] <= 100;
}
private function validateCertificateSettings(array $certificateSettings): void
private function validateCertificateSettings($certificateSettings): void
{
if (!$this->isValidCertificateSettings($certificateSettings)) {
throw new \InvalidArgumentException('Invalid certificate settings given.');
......@@ -303,13 +301,10 @@ class Instance
*/
public function getReminderSettings(): array
{
$range = $this->getRange();
$root = $this->getRoot();
/** @var int $reminderInterval */
$reminderSettings = json_decode(
$range->getConfiguration()->COURSEWARE_REMINDER_SETTINGS[$root->id],
true
)?: [];
/** @var array $reminderSettings */
$reminderSettings = isset($this->unit->config['reminder'])
? $this->unit->config['reminder']->getArrayCopy()
: [];
$this->validateReminderSettings($reminderSettings);
return $reminderSettings;
......@@ -318,33 +313,34 @@ class Instance
/**
* Sets the reminder message settings this courseware instance.
*
* @param array $reminderSettings an array of parameters
* @param \JSONArrayObject $reminderSettings an array of parameters
*/
public function setReminderSettings(array $reminderSettings): void
public function setReminderSettings($reminderSettings): void
{
if (count($reminderSettings) > 0) {
$this->validateReminderSettings($reminderSettings);
$range = $this->getRange();
$root = $this->getRoot();
$settings = $range->getConfiguration()->getValue('COURSEWARE_REMINDER_SETTINGS');
$settings[$root->id] = count($reminderSettings) > 0 ? json_encode($reminderSettings) : null;
$range->getConfiguration()->store('COURSEWARE_REMINDER_SETTINGS', $settings);
$this->unit->config['reminder'] = $reminderSettings;
} else {
unset($this->unit->config['reminder']);
unset($this->unit->config['last_reminder']);
}
}
/**
* Validates reminder message settings.
*
* @param array $reminderSettings settings for reminder mail sending
* @param \JSONArrayObject $reminderSettings settings for reminder mail sending
*
* @return bool true if all given values are valid, false otherwise
*/
public function isValidReminderSettings(array $reminderSettings): bool
public function isValidReminderSettings($reminderSettings): bool
{
$valid = in_array($reminderSettings['interval'], [0, 7, 14, 30, 90, 180, 365]);
return $valid;
}
private function validateReminderSettings(array $reminderSettings): void
private function validateReminderSettings($reminderSettings): void
{
if (!$this->isValidReminderSettings($reminderSettings)) {
throw new \InvalidArgumentException('Invalid reminder settings given.');
......@@ -358,13 +354,10 @@ class Instance
*/
public function getResetProgressSettings(): array
{
$range = $this->getRange();
$root = $this->getRoot();
/** @var int $reminderInterval */
$resetProgressSettings = json_decode(
$range->getConfiguration()->COURSEWARE_RESET_PROGRESS_SETTINGS[$root->id],
true
)?: [];
/** @var array $resetProgressSettings */
$resetProgressSettings = isset($this->unit->config['reset_progress'])
? $this->unit->config['reset_progress']->getArrayCopy()
: [];
$this->validateResetProgressSettings($resetProgressSettings);
return $resetProgressSettings;
......@@ -373,33 +366,34 @@ class Instance
/**
* Sets the progress resetting settings this courseware instance.
*
* @param array $reminderSettings an array of parameters
* @param \JSONArrayObject $resetProgressSettings an array of parameters
*/
public function setResetProgressSettings(array $resetProgressSettings): void
public function setResetProgressSettings($resetProgressSettings): void
{
if (count($resetProgressSettings) > 0) {
$this->validateResetProgressSettings($resetProgressSettings);
$range = $this->getRange();
$root = $this->getRoot();
$settings = $range->getConfiguration()->getValue('COURSEWARE_RESET_PROGRESS_SETTINGS');
$settings[$root->id] = count($resetProgressSettings) > 0 ? json_encode($resetProgressSettings) : null;
$range->getConfiguration()->store('COURSEWARE_RESET_PROGRESS_SETTINGS', $settings);
$this->unit->config['reset_progress'] = $resetProgressSettings;
} else {
unset($this->unit->config['reset_progress']);
unset($this->unit->config['last_progress_reset']);
}
}
/**
* Validates progress resetting settings.
*
* @param array $resetProgressSettings settings for progress resetting
* @param \JSONArrayObject $resetProgressSettings settings for progress resetting
*
* @return bool true if all given values are valid, false otherwise
*/
public function isValidResetProgressSettings(array $resetProgressSettings): bool
public function isValidResetProgressSettings($resetProgressSettings): bool
{
$valid = in_array($resetProgressSettings['interval'], [0, 14, 30, 90, 180, 365]);
return $valid;
}
private function validateResetProgressSettings(array $resetProgressSettings): void
private function validateResetProgressSettings($resetProgressSettings): void
{
if (!$this->isValidResetProgressSettings($resetProgressSettings)) {
throw new \InvalidArgumentException('Invalid progress resetting settings given.');
......@@ -491,4 +485,5 @@ class Instance
return $data;
}
}
......@@ -21,6 +21,7 @@ use User;
* @property string $creator_id database column
* @property int $release_date database column
* @property int $withdraw_date database column
* @property \JSONArrayObject $config database column
* @property int $mkdate database column
* @property int $chdate database column
* @property \User $creator belongs_to User
......@@ -36,6 +37,8 @@ class Unit extends \SimpleORMap
{
$config['db_table'] = 'cw_units';
$config['serialized_fields']['config'] = 'JSONArrayObject';
$config['has_one']['structural_element'] = [
'class_name' => StructuralElement::class,
'foreign_key' => 'structural_element_id',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment