aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/admission/AdmissionRule.php
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/admission/AdmissionRule.php
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/admission/AdmissionRule.php')
-rw-r--r--lib/classes/admission/AdmissionRule.php456
1 files changed, 456 insertions, 0 deletions
diff --git a/lib/classes/admission/AdmissionRule.php b/lib/classes/admission/AdmissionRule.php
new file mode 100644
index 0000000..2b826e4
--- /dev/null
+++ b/lib/classes/admission/AdmissionRule.php
@@ -0,0 +1,456 @@
+<?php
+
+/**
+ * AdmissionRule.php
+ *
+ * An abstract representation of rules for course admission.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * @author Thomas Hackl <thomas.hackl@uni-passau.de>
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ */
+
+abstract class AdmissionRule
+{
+ // --- ATTRIBUTES ---
+
+ /**
+ * When does the validity end?
+ */
+ public $endTime = 0;
+
+ /**
+ * A unique identifier for this rule.
+ */
+ public $id = '';
+
+ /**
+ * A customizable message that is shown to users that are rejected for admission
+ * because of the current rule.
+ */
+ public $message = '';
+
+ /**
+ * default message that is shown to users that are rejected for admission
+ * because of the current rule.
+ */
+ public $default_message = '';
+
+ /**
+ * When does the validity start?
+ */
+ public $startTime = 0;
+
+ /**
+ * ID of the CourseSet this admission rule belongs to (is stored here for
+ * performance reasons).
+ */
+ public $courseSetId = '';
+
+ /**
+ * courseset siblings of this rule
+ */
+ public $siblings = [];
+
+ /**
+ * Are siblings set manually?
+ */
+ public $siblings_override = false;
+
+ // --- OPERATIONS ---
+
+ public function __construct($ruleId = '', $courseSetId = '')
+ {
+ $this->id = $ruleId;
+ $this->courseSetId = $courseSetId;
+ }
+
+ /**
+ * Hook that can be called after the seat distribution on the courseset
+ * has completed.
+ *
+ * @param CourseSet $courseset Current courseset.
+ */
+ public function afterSeatDistribution($courseset)
+ {
+ return true;
+ }
+
+ /**
+ * Checks if we are in the rule validity time frame.
+ *
+ * @return bool True if the rule is valid because the time frame applies,
+ * otherwise false.
+ */
+ public function checkTimeFrame()
+ {
+ $valid = true;
+ // Start time given, but still in the future.
+ if ($this->startTime && $this->startTime > time()) {
+ $valid = false;
+ }
+ // End time given, but already past.
+ if ($this->endTime && $this->endTime < time()) {
+ $valid = false;
+ }
+ return $valid;
+ }
+
+ /**
+ * Deletes the admission rule and all associated data.
+ */
+ public function delete()
+ {
+ // Delete rule assignment to coursesets.
+ $stmt = DBManager::get()->prepare("DELETE FROM `courseset_rule`
+ WHERE `rule_id`=?");
+ $stmt->execute([$this->id]);
+ }
+
+ /**
+ * Generate a new unique ID.
+ *
+ * @param String $tableName
+ */
+ public function generateId($tableName)
+ {
+ do {
+ $newid = md5(uniqid(get_class($this).microtime(), true));
+ $db = DBManager::get()->query("SELECT `rule_id`
+ FROM `".$tableName."` WHERE `rule_id`=" . DBManager::get()->quote($newid));
+ } while ($db->fetch());
+ return $newid;
+ }
+
+ /**
+ * Gets all users that are matched by thís rule.
+ *
+ * @return Array An array containing IDs of users who are matched by
+ * this rule.
+ */
+ public function getAffectedUsers()
+ {
+ return [];
+ }
+
+ /**
+ * Reads all available AdmissionRule subclasses and loads their definitions.
+ *
+ * @param bool $activeOnly Show only active rules.
+ * @return Array
+ */
+ public static function getAvailableAdmissionRules($activeOnly = true)
+ {
+ $rules = [];
+ $where = ($activeOnly ? " WHERE `active`=1" : "");
+ $data = DBManager::get()->query("SELECT * FROM `admissionrules`".$where.
+ " ORDER BY `id` ASC");
+ while ($current = $data->fetch(PDO::FETCH_ASSOC)) {
+ $className = $current['ruletype'];
+ if (is_dir($GLOBALS['STUDIP_BASE_PATH'] . DIRECTORY_SEPARATOR . $current['path'])) {
+ StudipAutoloader::addAutoloadPath($GLOBALS['STUDIP_BASE_PATH'] . DIRECTORY_SEPARATOR . $current['path']);
+ try {
+ $rule = new $className();
+ $rules[$className] = [
+ 'id' => $current['id'],
+ 'name' => $className::getName(),
+ 'description' => $className::getDescription(),
+ 'active' => $current['active']
+ ];
+ } catch (Exception $e) {
+ }
+ }
+ }
+ return $rules;
+ }
+
+ /**
+ * Get end of validity.
+ *
+ * @return Integer
+ */
+ public function getEndTime()
+ {
+ return $this->endTime;
+ }
+
+ /**
+ * Subclasses of AdmissionRule can require additional data to be entered on
+ * admission (like PasswordAdmission which needs a password for course
+ * access). Their corresponding method getInput only returns a HTML form
+ * fragment as the output can be concatenated with output from other
+ * rules.
+ * This static method provides the frame for rendering a full HTML form
+ * around the fragments from subclasses.
+ *
+ * @return Array Start and end templates which wrap input form fragments
+ * from subclasses.
+ */
+ public static final function getInputFrame()
+ {
+ return [
+ $GLOBALS['template_factory']->open('admission/rules/input_start')->render(),
+ $GLOBALS['template_factory']->open('admission/rules/input_end')->render()
+ ];
+ }
+
+ /**
+ * Gets some text that describes what this AdmissionRule (or respective
+ * subclass) does.
+ */
+ public static function getDescription()
+ {
+ return _("Legt eine Regel fest, die erfüllt sein muss, um sich ".
+ "erfolgreich zu einer Menge von Veranstaltungen anmelden zu ".
+ "können.");
+ }
+
+ public function getInput()
+ {
+ return '';
+ }
+ /**
+ * Gets the rule ID.
+ *
+ * @return String This rule's ID.
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * Gets the message that is shown to users rejected by this rule.
+ *
+ * @return String The message.
+ */
+ public function getMessage()
+ {
+ return $this->message ?: $this->default_message;
+ }
+
+ /**
+ * Return this rule's name.
+ */
+ public static function getName()
+ {
+ return _("Anmelderegel");
+ }
+
+ /**
+ * Gets start of validity.
+ *
+ * @return Integer
+ */
+ public function getStartTime()
+ {
+ return $this->startTime;
+ }
+
+ /**
+ * Gets the template that provides a configuration GUI for this rule.
+ *
+ * @return String
+ */
+ public function getTemplate()
+ {
+ return '';
+ }
+
+ /**
+ * Internal helper function for loading rule definition from database.
+ */
+ public function load()
+ {
+ }
+
+ /**
+ * Hook that can be called when the seat distribution on the courseset
+ * starts.
+ *
+ * @param CourseSet $courseset The courseset this rule belongs to.
+ */
+ public function beforeSeatDistribution($courseset)
+ {
+ return true;
+ }
+
+ /**
+ * Does the current rule allow the given user to register as participant
+ * in the given course?
+ *
+ * @param String $userId
+ * @param String $courseId
+ * @return Array
+ */
+ public function ruleApplies($userId, $courseId)
+ {
+ return [];
+ }
+
+ /**
+ * Uses the given data to fill the object values. This can be used
+ * as a generic function for storing data if the concrete rule type
+ * isn't known in advance.
+ *
+ * @param Array $data
+ * @return AdmissionRule This object.
+ */
+ public function setAllData($data)
+ {
+ if (!empty($data['start_date']) && empty($data['start_time'])) {
+ $data['start_time'] = strtotime($data['start_date']);
+ }
+ if (!empty($data['end_date']) && empty($data['end_time'])) {
+ $data['end_time'] = strtotime($data['end_date'] . ' 23:59:59');
+ }
+ $this->message = $data['message'] ?? '';
+ $this->startTime = $data['start_time'] ?? null;
+ $this->endTime = $data['end_time'] ?? null;
+ return $this;
+ }
+
+ /**
+ * Sets a new end time for condition validity.
+ *
+ * @param Integer $newEndTime
+ * @return AdmissionRule
+ */
+ public function setEndTime($newEndTime)
+ {
+ $this->endTime = $newEndTime;
+ return $this;
+ }
+
+ /**
+ * Sets a new message to show to users.
+ *
+ * @param String $newMessage A new message text.
+ * @return AdmissionRule This object
+ */
+ public function setMessage($newMessage)
+ {
+ $this->message = $newMessage;
+ return $this;
+ }
+
+ /**
+ * Sets a new start time for condition validity.
+ *
+ * @param Integer $newStartTime
+ * @return AdmissionRule
+ */
+ public function setStartTime($newStartTime)
+ {
+ $this->startTime = $newStartTime;
+ return $this;
+ }
+
+ /**
+ * Helper function for storing rule definition to database.
+ */
+ public function store()
+ {
+ }
+
+ /**
+ * A textual description of the current rule.
+ *
+ * @return String
+ */
+ public function toString()
+ {
+ return '';
+ }
+
+ /**
+ * Validates if the given request data is sufficient to configure this rule
+ * (e.g. if required values are present).
+ *
+ * @param Array $data Request data
+ * @return Array Error messages.
+ */
+ public function validate($data)
+ {
+ $errors = [];
+ if (!empty($data['start_date']) && !empty($data['end_date']) && strtotime($data['end_date']) < strtotime($data['start_date'])) {
+ $errors[] = _('Das Enddatum darf nicht vor dem Startdatum liegen.');
+ }
+ return $errors;
+ }
+
+ /**
+ * Standard string representation of this object.
+ *
+ * @return String
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * load sibling rules
+ *
+ */
+ public function loadSiblings()
+ {
+ if ($this->siblings_override) {
+ return false;
+ }
+ $this->siblings = [];
+ if ($this->courseSetId != '') {
+ $cs = new CourseSet($this->courseSetId);
+ foreach ($cs->getAdmissionRules() as $rule_id => $rule) {
+ if ($rule->getId() != $this->id) {
+ $this->siblings[$rule_id] = $rule;
+ }
+ }
+ }
+ }
+
+ /**
+ * get sibling rules
+ *
+ */
+ public function getSiblings()
+ {
+ $this->loadSiblings();
+ return $this->siblings;
+ }
+
+ /**
+ * set sibling rules
+ *
+ */
+ public function setSiblings($siblings = [])
+ {
+ $this->siblings_override = true;
+ $this->siblings = $siblings;
+ }
+
+ /**
+ * checks if given admission rule is allowed to be combined with this rule
+ *
+ * @param AdmissionRule|string $admission_rule
+ * @return boolean
+ */
+ public function isCombinationAllowed($admission_rule)
+ {
+ if (is_object($admission_rule)) {
+ $admission_rule = get_class($admission_rule);
+ }
+ return AdmissionRuleCompatibility::exists([get_class($this), $admission_rule]);
+ }
+
+ public function __clone()
+ {
+ $this->id = md5(uniqid(get_class($this)));
+ $this->courseSetId = null;
+ }
+}