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 ...@@ -133,6 +133,9 @@ class CoursewareInstancesUpdate extends JsonApiController
$resetProgressSettings = $get('data.attributes.reset-progress-settings'); $resetProgressSettings = $get('data.attributes.reset-progress-settings');
$instance->setResetProgressSettings($resetProgressSettings); $instance->setResetProgressSettings($resetProgressSettings);
// Store changes in unit configuration.
$instance->getUnit()->store();
return $instance; return $instance;
} }
} }
This diff is collapsed.
...@@ -34,9 +34,6 @@ class Instance ...@@ -34,9 +34,6 @@ class Instance
$instance = new self($root); $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 ?', [ $last_element_configs = \ConfigValue::findBySQL('field = ? AND value LIKE ?', [
'COURSEWARE_LAST_ELEMENT', 'COURSEWARE_LAST_ELEMENT',
'%' . $range->getRangeId() . '%', '%' . $range->getRangeId() . '%',
...@@ -62,6 +59,11 @@ class Instance ...@@ -62,6 +59,11 @@ class Instance
*/ */
private $root; private $root;
/**
* @var Unit
*/
private $unit;
/** /**
* Create a new representation of a a courseware instance. * Create a new representation of a a courseware instance.
* *
...@@ -73,6 +75,7 @@ class Instance ...@@ -73,6 +75,7 @@ class Instance
public function __construct(StructuralElement $root) public function __construct(StructuralElement $root)
{ {
$this->root = $root; $this->root = $root;
$this->unit = $root->findUnit();
} }
/** /**
...@@ -85,6 +88,16 @@ class Instance ...@@ -85,6 +88,16 @@ class Instance
return $this->root; 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. * Returns the range this courseware instance belongs to.
* *
...@@ -164,9 +177,7 @@ class Instance ...@@ -164,9 +177,7 @@ class Instance
*/ */
public function getSequentialProgression(): bool public function getSequentialProgression(): bool
{ {
$range = $this->getRange(); $sequentialProgression = $this->unit->config['sequential_progression'] ?? false;
$root = $this->getRoot();
$sequentialProgression = $range->getConfiguration()->COURSEWARE_SEQUENTIAL_PROGRESSION[$root->id];
return (bool) $sequentialProgression; return (bool) $sequentialProgression;
} }
...@@ -178,11 +189,7 @@ class Instance ...@@ -178,11 +189,7 @@ class Instance
*/ */
public function setSequentialProgression(bool $isSequentialProgression): void public function setSequentialProgression(bool $isSequentialProgression): void
{ {
$range = $this->getRange(); $this->unit->config['sequential_progression'] = $isSequentialProgression ? 1 : 0;
$root = $this->getRoot();
$progressions = $range->getConfiguration()->getValue('COURSEWARE_SEQUENTIAL_PROGRESSION');
$progressions[$root->id] = $isSequentialProgression ? 1 : 0;
$range->getConfiguration()->store('COURSEWARE_SEQUENTIAL_PROGRESSION', $progressions);
} }
const EDITING_PERMISSION_DOZENT = 'dozent'; const EDITING_PERMISSION_DOZENT = 'dozent';
...@@ -195,10 +202,8 @@ class Instance ...@@ -195,10 +202,8 @@ class Instance
*/ */
public function getEditingPermissionLevel(): string public function getEditingPermissionLevel(): string
{ {
$range = $this->getRange();
$root = $this->getRoot();
/** @var string $editingPermissionLevel */ /** @var string $editingPermissionLevel */
$editingPermissionLevel = $range->getConfiguration()->COURSEWARE_EDITING_PERMISSION[$root->id]; $editingPermissionLevel = $this->unit->config['editing_permission'];
if ($editingPermissionLevel) { if ($editingPermissionLevel) {
$this->validateEditingPermissionLevel($editingPermissionLevel); $this->validateEditingPermissionLevel($editingPermissionLevel);
return $editingPermissionLevel; return $editingPermissionLevel;
...@@ -216,11 +221,7 @@ class Instance ...@@ -216,11 +221,7 @@ class Instance
public function setEditingPermissionLevel(string $editingPermissionLevel): void public function setEditingPermissionLevel(string $editingPermissionLevel): void
{ {
$this->validateEditingPermissionLevel($editingPermissionLevel); $this->validateEditingPermissionLevel($editingPermissionLevel);
$range = $this->getRange(); $this->unit->config['editing_permission'] = $editingPermissionLevel;
$root = $this->getRoot();
$permissions = $range->getConfiguration()->getValue('COURSEWARE_EDITING_PERMISSION');
$permissions[$root->id] = $editingPermissionLevel;
$range->getConfiguration()->store('COURSEWARE_EDITING_PERMISSION', $permissions);
} }
/** /**
...@@ -250,13 +251,10 @@ class Instance ...@@ -250,13 +251,10 @@ class Instance
*/ */
public function getCertificateSettings(): array public function getCertificateSettings(): array
{ {
$range = $this->getRange();
$root = $this->getRoot();
/** @var array $certificateSettings */ /** @var array $certificateSettings */
$certificateSettings = json_decode( $certificateSettings = isset($this->unit->config['certificate'])
$range->getConfiguration()->COURSEWARE_CERTIFICATE_SETTINGS[$root->id], ? $this->unit->config['certificate']->getArrayCopy()
true : [];
)?: [];
$this->validateCertificateSettings($certificateSettings); $this->validateCertificateSettings($certificateSettings);
return $certificateSettings; return $certificateSettings;
...@@ -269,27 +267,27 @@ class Instance ...@@ -269,27 +267,27 @@ class Instance
*/ */
public function setCertificateSettings(array $certificateSettings): void public function setCertificateSettings(array $certificateSettings): void
{ {
$this->validateCertificateSettings($certificateSettings); if (count($certificateSettings) > 0) {
$range = $this->getRange(); $this->validateCertificateSettings($certificateSettings);
$root = $this->getRoot(); $this->unit->config['certificate'] = $certificateSettings;
$settings = $range->getConfiguration()->getValue('COURSEWARE_CERTIFICATE_SETTINGS'); } else {
$settings[$root->id] = count($certificateSettings) > 0 ? json_encode($certificateSettings) : null; unset($this->unit->config['certificate']);
$range->getConfiguration()->store('COURSEWARE_CERTIFICATE_SETTINGS', $settings); }
} }
/** /**
* Validates certificate settings. * 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 * @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; return (int) $certificateSettings['threshold'] >= 0 && (int) $certificateSettings['threshold'] <= 100;
} }
private function validateCertificateSettings(array $certificateSettings): void private function validateCertificateSettings($certificateSettings): void
{ {
if (!$this->isValidCertificateSettings($certificateSettings)) { if (!$this->isValidCertificateSettings($certificateSettings)) {
throw new \InvalidArgumentException('Invalid certificate settings given.'); throw new \InvalidArgumentException('Invalid certificate settings given.');
...@@ -303,13 +301,10 @@ class Instance ...@@ -303,13 +301,10 @@ class Instance
*/ */
public function getReminderSettings(): array public function getReminderSettings(): array
{ {
$range = $this->getRange(); /** @var array $reminderSettings */
$root = $this->getRoot(); $reminderSettings = isset($this->unit->config['reminder'])
/** @var int $reminderInterval */ ? $this->unit->config['reminder']->getArrayCopy()
$reminderSettings = json_decode( : [];
$range->getConfiguration()->COURSEWARE_REMINDER_SETTINGS[$root->id],
true
)?: [];
$this->validateReminderSettings($reminderSettings); $this->validateReminderSettings($reminderSettings);
return $reminderSettings; return $reminderSettings;
...@@ -318,33 +313,34 @@ class Instance ...@@ -318,33 +313,34 @@ class Instance
/** /**
* Sets the reminder message settings this courseware 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
{ {
$this->validateReminderSettings($reminderSettings); if (count($reminderSettings) > 0) {
$range = $this->getRange(); $this->validateReminderSettings($reminderSettings);
$root = $this->getRoot(); $this->unit->config['reminder'] = $reminderSettings;
$settings = $range->getConfiguration()->getValue('COURSEWARE_REMINDER_SETTINGS'); } else {
$settings[$root->id] = count($reminderSettings) > 0 ? json_encode($reminderSettings) : null; unset($this->unit->config['reminder']);
$range->getConfiguration()->store('COURSEWARE_REMINDER_SETTINGS', $settings); unset($this->unit->config['last_reminder']);
}
} }
/** /**
* Validates reminder message settings. * 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 * @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]); $valid = in_array($reminderSettings['interval'], [0, 7, 14, 30, 90, 180, 365]);
return $valid; return $valid;
} }
private function validateReminderSettings(array $reminderSettings): void private function validateReminderSettings($reminderSettings): void
{ {
if (!$this->isValidReminderSettings($reminderSettings)) { if (!$this->isValidReminderSettings($reminderSettings)) {
throw new \InvalidArgumentException('Invalid reminder settings given.'); throw new \InvalidArgumentException('Invalid reminder settings given.');
...@@ -358,13 +354,10 @@ class Instance ...@@ -358,13 +354,10 @@ class Instance
*/ */
public function getResetProgressSettings(): array public function getResetProgressSettings(): array
{ {
$range = $this->getRange(); /** @var array $resetProgressSettings */
$root = $this->getRoot(); $resetProgressSettings = isset($this->unit->config['reset_progress'])
/** @var int $reminderInterval */ ? $this->unit->config['reset_progress']->getArrayCopy()
$resetProgressSettings = json_decode( : [];
$range->getConfiguration()->COURSEWARE_RESET_PROGRESS_SETTINGS[$root->id],
true
)?: [];
$this->validateResetProgressSettings($resetProgressSettings); $this->validateResetProgressSettings($resetProgressSettings);
return $resetProgressSettings; return $resetProgressSettings;
...@@ -373,33 +366,34 @@ class Instance ...@@ -373,33 +366,34 @@ class Instance
/** /**
* Sets the progress resetting settings this courseware 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
{ {
$this->validateResetProgressSettings($resetProgressSettings); if (count($resetProgressSettings) > 0) {
$range = $this->getRange(); $this->validateResetProgressSettings($resetProgressSettings);
$root = $this->getRoot(); $this->unit->config['reset_progress'] = $resetProgressSettings;
$settings = $range->getConfiguration()->getValue('COURSEWARE_RESET_PROGRESS_SETTINGS'); } else {
$settings[$root->id] = count($resetProgressSettings) > 0 ? json_encode($resetProgressSettings) : null; unset($this->unit->config['reset_progress']);
$range->getConfiguration()->store('COURSEWARE_RESET_PROGRESS_SETTINGS', $settings); unset($this->unit->config['last_progress_reset']);
}
} }
/** /**
* Validates progress resetting settings. * 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 * @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]); $valid = in_array($resetProgressSettings['interval'], [0, 14, 30, 90, 180, 365]);
return $valid; return $valid;
} }
private function validateResetProgressSettings(array $resetProgressSettings): void private function validateResetProgressSettings($resetProgressSettings): void
{ {
if (!$this->isValidResetProgressSettings($resetProgressSettings)) { if (!$this->isValidResetProgressSettings($resetProgressSettings)) {
throw new \InvalidArgumentException('Invalid progress resetting settings given.'); throw new \InvalidArgumentException('Invalid progress resetting settings given.');
...@@ -491,4 +485,5 @@ class Instance ...@@ -491,4 +485,5 @@ class Instance
return $data; return $data;
} }
} }
...@@ -11,7 +11,7 @@ use User; ...@@ -11,7 +11,7 @@ use User;
* @license GPL2 or any later version * @license GPL2 or any later version
* *
* @since Stud.IP 5.3 * @since Stud.IP 5.3
* *
* @property int $id database column * @property int $id database column
* @property string $range_id database column * @property string $range_id database column
* @property string $range_type database column * @property string $range_type database column
...@@ -21,11 +21,12 @@ use User; ...@@ -21,11 +21,12 @@ use User;
* @property string $creator_id database column * @property string $creator_id database column
* @property int $release_date database column * @property int $release_date database column
* @property int $withdraw_date database column * @property int $withdraw_date database column
* @property \JSONArrayObject $config database column
* @property int $mkdate database column * @property int $mkdate database column
* @property int $chdate database column * @property int $chdate database column
* @property \User $creator belongs_to User * @property \User $creator belongs_to User
* @property \Courseware\StructuralElement $structural_element belongs_to Courseware\StructuralElement * @property \Courseware\StructuralElement $structural_element belongs_to Courseware\StructuralElement
* *
* @SuppressWarnings(PHPMD.TooManyPublicMethods) * @SuppressWarnings(PHPMD.TooManyPublicMethods)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
*/ */
...@@ -36,6 +37,8 @@ class Unit extends \SimpleORMap ...@@ -36,6 +37,8 @@ class Unit extends \SimpleORMap
{ {
$config['db_table'] = 'cw_units'; $config['db_table'] = 'cw_units';
$config['serialized_fields']['config'] = 'JSONArrayObject';
$config['has_one']['structural_element'] = [ $config['has_one']['structural_element'] = [
'class_name' => StructuralElement::class, 'class_name' => StructuralElement::class,
'foreign_key' => 'structural_element_id', 'foreign_key' => 'structural_element_id',
...@@ -102,7 +105,7 @@ class Unit extends \SimpleORMap ...@@ -102,7 +105,7 @@ class Unit extends \SimpleORMap
'release_date' => null, 'release_date' => null,
'withdraw_date' => null, 'withdraw_date' => null,
]); ]);
$newUnit->store(); $newUnit->store();
return $newUnit; return $newUnit;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment