aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/admission/CourseSet.class.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/CourseSet.class.php
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/admission/CourseSet.class.php')
-rw-r--r--lib/classes/admission/CourseSet.class.php1185
1 files changed, 0 insertions, 1185 deletions
diff --git a/lib/classes/admission/CourseSet.class.php b/lib/classes/admission/CourseSet.class.php
deleted file mode 100644
index d94bc05..0000000
--- a/lib/classes/admission/CourseSet.class.php
+++ /dev/null
@@ -1,1185 +0,0 @@
-<?php
-
-/**
- * CourseSet.class.php
- *
- * Represents groups of Stud.IP courses that have common rules for 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
- */
-
-class CourseSet
-{
- // --- ATTRIBUTES ---
-
- /**
- * Admission rules that are applied to the courses belonging to this set.
- */
- protected $admissionRules = [];
-
- /**
- * Seat distribution algorithm.
- */
- protected $algorithm = null;
-
- /**
- * IDs of courses that are aggregated into this set. The array is in the
- * form ($courseId1 => true, $courseId2 => true).
- */
- protected $courses = [];
-
- /**
- * Has the seat distribution algorithm already been executed?
- */
- protected $hasAlgorithmRun = false;
-
- /**
- * Unique identifier for this set.
- */
- protected $id = '';
-
- /**
- * Some extensive descriptional text for informing confused students.
- */
- protected $infoText = '';
-
- /**
- * Which Stud.IP institute does the course set belong to?
- */
- protected $institutes = [];
-
- /**
- * Some display name for this course set.
- */
- protected $name = '';
-
- /**
- * Is the course set only visible for the creator?
- */
- protected $private = false;
-
- /**
- * Who owns this course set?
- */
- protected $user_id = false;
-
- /**
- * When was the course set changed?
- */
- protected $chdate = null;
-
- /*
- * Lists of users who are treated differently on seat distribution
- */
- protected $userlists = [];
-
- // --- OPERATIONS ---
-
- public function __construct($setId='') {
- $this->id = $setId;
- $this->name = _("Anmeldeset");
- $this->algorithm = new RandomAlgorithm();
- // Autoload admission rules.
- AdmissionRule::getAvailableAdmissionRules();
- // Define autoload function for admission rules.
- spl_autoload_register(['UserFilterField', 'getAvailableFilterFields']);
- if ($setId) {
- $this->load();
- }
- }
-
- /**
- * Adds the given admission rule to the list of rules for the course set.
- *
- * @param AdmissionRule rule
- * @return CourseSet
- */
- public function addAdmissionRule($rule)
- {
- $this->admissionRules[$rule->getId()] = $rule;
- return $this;
- }
-
- /**
- * Adds the course with the given ID to the course set.
- *
- * @param String courseId
- * @return CourseSet
- */
- public function addCourse($courseId)
- {
- $this->courses[$courseId] = true;
- return $this;
- }
-
- /**
- * Adds a new institute ID.
- *
- * @param String newId
- * @return CourseSet
- */
- public function addInstitute($newId) {
- $this->institutes[$newId] = true;
- return $this;
- }
-
- /**
- * Adds several institute IDs to the existing institute assignments.
- *
- * @param Array newIds
- * @return CourseSet
- */
- public function addInstitutes($newIds) {
- foreach ($newIds as $newId) {
- $this->addInstitute($newId);
- }
- return $this;
- }
-
- /**
- * Adds a UserList to the course set. The list contains several users and a
- * factor that changes seat distribution chances for these users;
- *
- * @param String listId
- * @return CourseSet
- */
- public function addUserList($listId)
- {
- $this->userlists[$listId] = true;
- return $this;
- }
-
- /**
- * Is the given user allowed to register as participant in the given
- * course according to the rules of this course set?
- *
- * @param String userId
- * @param String courseId
- * @return Array Optional error messages from rules if something went wrong.
- */
- public function checkAdmission($userId, $courseId) {
- $errors = [];
- foreach ($this->admissionRules as $rule) {
- // All rules must be fulfilled.
- $ruleCheck = $rule->ruleApplies($userId, $courseId);
- if ($ruleCheck) {
- $errors = array_merge($errors, $ruleCheck);
- }
- }
- return $errors;
- }
-
- /**
- * Removes all admission rules at once.
- *
- * @return CourseSet
- */
- public function clearAdmissionRules() {
- $this->admissionRules = [];
- return $this;
- }
-
- /**
- * Deletes the course set and all associated data.
- */
- public function delete() {
- NotificationCenter::postNotification('CourseSetWillDelete', $this->id, $GLOBALS['user']->id);
- // Delete institute associations.
- $stmt = DBManager::get()->prepare("DELETE FROM `courseset_institute`
- WHERE `set_id`=?");
- $stmt->execute([$this->id]);
- // Delete course associations.
- $stmt = DBManager::get()->prepare("DELETE FROM `seminar_courseset`
- WHERE `set_id`=?");
- $stmt->execute([$this->id]);
- // Delete all rules...
- foreach ($this->admissionRules as $rule) {
- $rule->delete();
- }
- // ... and their association to the current course set.
- $stmt = DBManager::get()->prepare("DELETE FROM `courseset_rule`
- WHERE `set_id`=?");
- $stmt->execute([$this->id]);
- // Delete associations to user lists.
- $stmt = DBManager::get()->prepare("DELETE FROM `courseset_factorlist`
- WHERE `set_id`=?");
- $stmt->execute([$this->id]);
- // Delete course set data.
- $stmt = DBManager::get()->prepare("DELETE FROM `coursesets`
- WHERE `set_id`=?");
- $stmt->execute([$this->id]);
- /*
- * Delete waiting lists
- */
- foreach ($this->courses as $id => $assigned) {
- AdmissionApplication::deleteBySQL("status='awaiting' AND seminar_id=?", [$id]);
- }
- //Delete priorities
- AdmissionPriority::unsetAllPriorities($this->getId());
- NotificationCenter::postNotification('CourseSetDidDelete', $this->id, $GLOBALS['user']->id);
- }
-
- /**
- * Starts the seat distribution algorithm.
- */
- public function distributeSeats() {
- if ($this->algorithm) {
- // Call pre-distribution hooks on all assigned rules.
- foreach ($this->admissionRules as &$rule) {
- $rule->beforeSeatDistribution($this);
- }
- $this->algorithm->run($this);
- // Mark as "seats distributed".
- $this->setAlgorithmRun(true);
- // Call post-distribution hooks on all assigned rules.
- foreach ($this->admissionRules as &$rule) {
- $rule->afterSeatDistribution($this);
- }
- AdmissionPriority::unsetAllPriorities($this->getId());
- }
- }
-
- public function setAlgorithmRun($state)
- {
- NotificationCenter::postNotification('CourseSetAlgorithmWillStart', $state, $this->getId());
- $this->hasAlgorithmRun = (bool)$state;
- $db = DBManager::get();
- $ok = $db->execute("UPDATE coursesets SET algorithm_run = ? WHERE set_id = ?", [$this->hasAlgorithmRun, $this->getId()]);
- if ($ok) {
- NotificationCenter::postNotification('CourseSetAlgorithmDidStart', $state, $this->getId());
- }
- return $ok;
- }
-
- /**
- * returns true if the set allows only a limited number of places
- *
- * @return boolean
- */
- public function isSeatDistributionEnabled()
- {
- return $this->getSeatDistributionTime() !== null;
- }
-
- /**
- * returns timestamp of distribution time or null if no distribution time available
- * may return 0 if first-come-first-serve is enabled
- *
- * @return integer|null timestamp of distribution
- */
- public function getSeatDistributionTime()
- {
- $pr_admission = $this->getAdmissionRule('ParticipantRestrictedAdmission');
- if ($pr_admission) {
- return $pr_admission->getDistributionTime();
- }
- }
-
- /**
- * Get all admission rules belonging to the course set.
- *
- * @return AdmissionRule[]
- */
- public function getAdmissionRules()
- {
- return $this->admissionRules;
- }
-
- public function getAdmissionRule($class_name)
- {
- $result = array_filter($this->getAdmissionRules(), function($r) use ($class_name) {
- return $r instanceof $class_name;}
- );
- return array_pop($result);
- }
- /**
- * check if course set has given admission rule
- *
- * @param string $rule name of AdmissionRule class
- * @return boolean
- */
- public function hasAdmissionRule($rule)
- {
- return is_object($this->getAdmissionRule($rule));
- }
-
- /**
- * Get the currently used distribution algorithm.
- *
- * @return AdmissionAlgorithm
- */
- public function getAlgorithm()
- {
- return $this->algorithm;
- }
-
- /**
- * How many users will be allowed to register according to the defined
- * rules? This can help in estimating whether the combination of the
- * defined rules makes sense.
- *
- * @return int
- */
- public function getAllowedUserCount()
- {
- $users = [];
- foreach ($this->admissionRules as $rule) {
- $users = array_merge($users, $rule->getAffectedUsers());
- }
- return sizeof($users);
- }
-
- /**
- * Gets the course IDs belonging to the course set.
- *
- * @return Array
- */
- public function getCourses()
- {
- return array_keys($this->courses);
- }
-
- /**
- * Gets all courses belonging to the given course set ID.
- *
- * @param String $courseSetId
- * @return Array
- */
- public static function getCoursesByCourseSetId($courseSetId)
- {
- $query = "SELECT `seminar_id`
- FROM `seminar_courseset`
- WHERE `set_id` = ?";
- $stmt = DBManager::get()->prepare($query);
- $stmt->execute([$courseSetId]);
- return $stmt->fetchAll(PDO::FETCH_ASSOC);
- }
-
- /**
- * Gets all course sets belonging to the given institute ID.
- *
- * @param String $instituteId
- * @return Array
- */
- public static function getCoursesetsByInstituteId($instituteId, $filter = []) {
- $query = "SELECT DISTINCT ci.*
- FROM `courseset_institute` ci
- JOIN `coursesets` c ON (ci.`set_id`=c.`set_id`)
- LEFT JOIN courseset_rule cr ON cr.set_id=ci.set_id
- LEFT JOIN seminar_courseset sc ON c.set_id = sc.set_id
- LEFT JOIN seminare s ON s.seminar_id = sc.seminar_id
- WHERE ci.`institute_id`=?";
- $parameters = [$instituteId];
- if (!$GLOBALS['perm']->have_perm('admin')) {
- $query .= " AND (c.`private`=0 OR c.`user_id`=?)";
- $parameters[] = $GLOBALS['user']->id;
- }
- if (!empty($filter['course_set_name'])) {
- $query .= " AND c.name LIKE ?";
- $parameters[] = $filter['course_set_name'] . '%';
- }
- if (!empty($filter['rule_types']) && is_array($filter['rule_types']) && count($filter['rule_types'])) {
- $query .= " AND cr.type IN (?)";
- $parameters[] = $filter['rule_types'];
- }
- if (!empty($filter['semester_id'])) {
- $query .= " AND s.start_time = ?";
- $parameters[] = Semester::find($filter['semester_id'])->beginn;
- }
- if (!empty($filter['course_set_chdate'])) {
- $query .= " AND c.chdate > ?";
- $parameters[] = $filter['course_set_chdate'];
- }
- $query .= " ORDER BY c.name";
- $stmt = DBManager::get()->prepare($query);
- $stmt->execute($parameters);
- return $stmt->fetchAll(PDO::FETCH_ASSOC);
- }
-
- /**
- * Gets all global course sets
- *
- * @param array $filter
- * @return Array
- */
- public static function getGlobalCoursesets($filter = []) {
- $query = "SELECT DISTINCT c.set_id
- FROM coursesets c
- LEFT JOIN courseset_institute ci ON ci.`set_id`=c.`set_id`
- LEFT JOIN courseset_rule cr ON cr.set_id=ci.set_id
- LEFT JOIN seminar_courseset sc ON c.set_id = sc.set_id
- LEFT JOIN seminare s ON s.seminar_id = sc.seminar_id
- WHERE ci.institute_id IS NULL";
- $parameters = [];
- $query .= " AND (c.`private`=0 OR c.`user_id`=?)";
- $parameters[] = $GLOBALS['user']->id;
- if (!empty($filter['course_set_name'])) {
- $query .= " AND c.name LIKE ?";
- $parameters[] = $filter['course_set_name'] . '%';
- }
- if (!empty($filter['rule_types']) && is_array($filter['rule_types']) && count($filter['rule_types'])) {
- $query .= " AND cr.type IN (?)";
- $parameters[] = $filter['rule_types'];
- }
- if (!empty($filter['semester_id'])) {
- $query .= " AND s.start_time = ?";
- $parameters[] = Semester::find($filter['semester_id'])->beginn;
- }
- if (!empty($filter['course_set_chdate'])) {
- $query .= " AND c.chdate > ?";
- $parameters[] = $filter['course_set_chdate'];
- }
- $query .= " ORDER BY c.name";
- $stmt = DBManager::get()->prepare($query);
- $stmt->execute($parameters);
- return $stmt->fetchAll(PDO::FETCH_ASSOC);
- }
-
- /**
- * Get the identifier of the course set.
- *
- * @return String
- */
- public function getId()
- {
- return $this->id;
- }
-
- /**
- * Get the course set's info text.
- *
- * @return String
- */
- public function getInfoText()
- {
- return $this->infoText;
- }
-
- /**
- * Which institutes does the rule belong to?
- *
- * @return Array
- */
- public function getInstituteIds() {
- return $this->institutes;
- }
-
- public function isGlobal()
- {
- return count($this->institutes) == 0;
- }
- /**
- * Gets this course set's display name.
- */
- public function getName() {
- return $this->name;
- }
-
- /**
- * Returns the date of the last change.
- * @return int
- */
- public function getChdate()
- {
- return $this->chdate;
- }
-
- /**
- * Retrieves the priorities given to the courses in this set.
- *
- * @return Array
- */
- public function getPriorities()
- {
- return AdmissionPriority::getPriorities($this->id);
- }
-
- public function getNumApplicants()
- {
- return AdmissionPriority::getPrioritiesCount($this->id);
- }
-
- /**
- * Is the current courseset private?
- *
- * @return bool
- */
- public function getPrivate() {
- return $this->private;
- }
-
-
- /**
- * returns latest semester id from assigned courses
- * if no courses are assigned current semester
- *
- * @return string id of semester
- */
- public function getSemester() {
- $db = DBManager::get();
- $data = $db->fetchOne("
- SELECT semester_data.*
- FROM semester_data
- INNER JOIN semester_courses ON (semester_data.semester_id = semester_courses.semester_id)
- WHERE semester_courses.course_id IN (?)
- ORDER BY semester_data.ende DESC
- LIMIT 1
- ", [$this->getCourses()]);
- if ($data) {
- $semester = Semester::buildExisting($data);
- } else {
- $semester = $_SESSION['_default_sem'] ? Semester::find($_SESSION['_default_sem']) : Semester::findCurrent();
- }
- return $semester->id;
- }
-
- /**
- * Gets the owner of this course set.
- */
- public function getUserId() {
- return $this->user_id;
- }
-
- public function setUserId($user_id) {
- $this->user_id = $user_id;
- return $this;
- }
-
- /**
- * Gets the course sets the given course belongs to.
- *
- * @param String courseId
- * @return CourseSet
- */
- public static function getSetForCourse($courseId)
- {
- $stmt = DBManager::get()->prepare("SELECT `set_id`
- FROM `seminar_courseset` WHERE `seminar_id`=?");
- $stmt->execute([$courseId]);
- $set_id = $stmt->fetchColumn();
- if ($set_id) {
- return new CourseSet($set_id);
- }
- return null;
- }
-
- /**
- * Gets the course sets the given rule belongs to.
- *
- * @param String $rule_id
- * @return CourseSet
- */
- public static function getSetForRule($rule_id)
- {
- $set_id = DBManager::get()->fetchColumn("SELECT `set_id`
- FROM `courseset_rule` WHERE `rule_id`=?", [$rule_id]);
- if ($set_id) {
- return new CourseSet($set_id);
- }
- return null;
- }
-
- /**
- * Retrieves the lists of users that are considered specially in
- * seat distribution.
- *
- * @return Array
- */
- public function getUserLists()
- {
- return array_keys($this->userlists);
- }
-
- public function getUserFactorList()
- {
- $factored_users = [];
-
- foreach ($this->getUserLists() as $ul_id) {
- $user_list = new AdmissionUserList($ul_id);
-
- // Iterate through user list.
- foreach ($user_list->getUsers() as $user => $assigned) {
- switch ($user_list->getFactor()) {
- // Maximum factor, just set it and stop further processing of user lists.
- case PHP_INT_MAX:
- $factored_users[$user] = PHP_INT_MAX;
- break;
- // Backlist, set malus and stop further processing of user lists.
- case 0:
- $factored_users[$user] = 0;
- break;
- default:
- // Add up current bonus if it isn't already at 0 or PHP_INT_MAX.
- if ($factored_users[$user] !== 0 && $factored_users[$user] != PHP_INT_MAX) {
- $factored_users[$user] = isset($factored_users[$user]) ?
- $factored_users[$user] + $user_list->getFactor() :
- $user_list->getFactor();
- }
- }
- }
- }
-
- return $factored_users;
- }
-
- /**
- * Evaluates whether the seat distribution algorithm has already been
- * executed on this course set.
- *
- * @return boolean True if algorithm has already run, otherwise false.
- */
- public function hasAlgorithmRun() {
- return $this->hasAlgorithmRun;
- }
-
- /**
- * Helper function for loading data from DB.
- */
- public function load() {
- // Load basic data.
- $stmt = DBManager::get()->prepare(
- "SELECT * FROM `coursesets` WHERE set_id=? LIMIT 1");
- $stmt->execute([$this->id]);
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- $this->name = $data['name'];
- $this->infoText = $data['infotext'];
- $this->hasAlgorithmRun = (bool)$data['algorithm_run'];
- if ($data['algorithm']) {
- if (class_exists($data['algorithm'])) {
- $this->algorithm = new $data['algorithm']();
- }
- }
- $this->private = (bool) $data['private'];
- $this->user_id = $data['user_id'];
- $this->chdate = $data['chdate'];
- }
- // Load institute assigments.
- $stmt = DBManager::get()->prepare("
- SELECT courseset_institute.institute_id
- FROM `courseset_institute`
- INNER JOIN Institute ON (courseset_institute.institute_id = Institute.Institut_id)
- WHERE courseset_institute.set_id = ?
- ORDER BY Institute.Name ASC
- ");
- $stmt->execute([$this->id]);
- $this->institutes = [];
- while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- $this->institutes[$data['institute_id']] = true;
- }
- // Load courses.
- $stmt = DBManager::get()->prepare(
- "SELECT seminar_id FROM `seminar_courseset` WHERE set_id=?");
- $stmt->execute([$this->id]);
- $this->courses = [];
- while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- $this->courses[$data['seminar_id']] = true;
- }
- // Load admission rules.
- $stmt = DBManager::get()->prepare(
- "SELECT * FROM `courseset_rule` WHERE set_id=?");
- $stmt->execute([$this->id]);
- $this->admissionRules = [];
- while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- if (class_exists($data['type'])) {
- $this->admissionRules[$data['rule_id']] =
- new $data['type']($data['rule_id'], $this->id);
- }
- }
- // Load assigned user lists.
- $stmt = DBManager::get()->prepare("SELECT `factorlist_id`
- FROM `courseset_factorlist` WHERE `set_id`=?");
- $stmt->execute([$this->id]);
- $this->userlists = [];
- while ($current = $stmt->fetch(PDO::FETCH_ASSOC)) {
- $this->userlists[$current['factorlist_id']] = true;
- }
- return $this;
- }
-
- /**
- * Removes the course with the given ID from the set.
- *
- * @param String courseId
- * @return CourseSet
- */
- public function removeCourse($courseId)
- {
- unset($this->courses[$courseId]);
- return $this;
- }
-
- /**
- * Removes the rule with the given ID from the set.
- *
- * @param String ruleId
- * @return CourseSet
- */
- public function removeAdmissionRule($ruleId)
- {
- unset($this->admissionRules[$ruleId]);
- return $this;
- }
-
- /**
- * Removes the institute with the given ID from the set.
- *
- * @param String instituteId
- * @return CourseSet
- */
- public function removeInstitute($instituteId)
- {
- unset($this->institutes[$instituteId]);
- return $this;
- }
-
- /**
- * Removes the user list with the given ID from the set.
- *
- * @param String listId
- * @return CourseSet
- */
- public function removeUserlist($listId)
- {
- unset($this->userlists[$listId]);
- return $this;
- }
-
- /**
- * Adds several admission rules after clearing the existing rule
- * assignments.
- *
- * @param Array newIds
- * @return CourseSet
- */
- public function setAdmissionRules($newRules) {
- $this->admissionRules = [];
- foreach ($newRules as $newRule) {
- $rule = ObjectBuilder::build($newRule, 'AdmissionRule');
- $this->addAdmissionRule($rule);
- }
- return $this;
- }
-
- /**
- * Sets a seat distribution algorithm for this course set. This will only
- * have an effect in conjunction with a TimedAdmission, as the algorithm
- * needs a defined point in time where it will start.
- *
- * @param String newAlgorithm
- * @return CourseSet
- */
- public function setAlgorithm($newAlgorithm)
- {
- try {
- $this->algorithm = new $newAlgorithm();
- } catch (Exception $e) {
- }
- return $this;
- }
-
- /**
- * Adds several course IDs after clearing the existing course
- * assignments.
- *
- * @param Array newIds
- * @return CourseSet
- */
- public function setCourses($newIds) {
- $this->courses = array_fill_keys($newIds, true);
- return $this;
- }
-
- /**
- * Adds several institute IDs after clearing the existing institute
- * assignments.
- *
- * @param Array newIds
- * @return CourseSet
- */
- public function setInstitutes($newIds) {
- $this->institutes = [];
- $this->addInstitutes($newIds);
- return $this;
- }
-
- /**
- * Set the course set's info text.
- *
- * @return CourseSet
- */
- public function setInfoText($newText)
- {
- $this->infoText = $newText;
- return $this;
- }
-
- /* Sets a new name for this course set.
- *
- * @param String newName
- * @return CourseSet
- */
- public function setName($newName) {
- $this->name = $newName;
- return $this;
- }
-
- /**
- * Set a new value for courseset privacy.
- *
- * @param bool $newPrivate
- * @return CourseSet
- */
- public function setPrivate($newPrivate) {
- $this->private = $newPrivate;
- return $this;
- }
-
- /**
- * Adds several user list IDs after clearing the existing user list
- * assignments.
- *
- * @param Array newIds
- * @return CourseSet
- */
- public function setUserlists($newIds) {
- $this->userlists = [];
- foreach ($newIds as $newId) {
- $this->addUserlist($newId);
- }
- return $this;
- }
-
- public function store() {
- // Generate new ID if course set doesn't exist in DB yet.
- if (!$this->id) {
- do {
- $newid = md5(uniqid(get_class($this), true));
- $db = DBManager::get()->query("SELECT `set_id`
- FROM `coursesets` WHERE `set_id`='$newid'");
- } while ($db->fetch());
- $this->id = $newid;
- }
- if (!$this->user_id) {
- $this->user_id = $GLOBALS['user']->id;
- }
- if ($this->isSeatDistributionEnabled()) {
- if (!$this->getAlgorithm()) {
- $algorithm = new RandomAlgorithm();
- $this->setAlgorithm($algorithm);
- }
- if (!$this->getSeatDistributionTime()) {
- $this->setAlgorithmRun(true);
- //Delete priorities
- AdmissionPriority::unsetAllPriorities($this->getId());
- }
- if ($this->getSeatDistributionTime() > time()) {
- $this->setAlgorithmRun(false);
- }
- }
- // Store basic data.
- $stmt = DBManager::get()->prepare("INSERT INTO `coursesets`
- (`set_id`, `user_id`, `name`, `infotext`, `algorithm`, `algorithm_run`,
- `private`, `mkdate`, `chdate`)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE
- `name`=VALUES(`name`), `infotext`=VALUES(`infotext`),
- `algorithm`=VALUES(`algorithm`), `algorithm_run`=VALUES(`algorithm_run`), `private`=VALUES(`private`),
- `chdate`=VALUES(`chdate`)");
- $stmt->execute([$this->id, $this->user_id, $this->name, $this->infoText,
- get_class($this->algorithm), $this->hasAlgorithmRun(), intval($this->private), time(), time()]);
- // Delete removed institute assignments from database.
- DBManager::get()->exec("DELETE FROM `courseset_institute`
- WHERE `set_id`='".$this->id."' AND `institute_id` NOT IN ('".
- implode("', '", array_keys($this->institutes))."')");
- // Store associated institute IDs.
- foreach ($this->institutes as $institute => $associated) {
- $stmt = DBManager::get()->prepare("INSERT IGNORE INTO `courseset_institute`
- (`set_id`, `institute_id`, `mkdate`)
- VALUES (?, ?, ?)");
- $stmt->execute([$this->id, $institute, time()]);
- }
- // log removed course assignments.
- DBManager::get()->fetchAll("SELECT seminar_id,set_id FROM `seminar_courseset`
- WHERE `set_id` = ? AND `seminar_id` NOT IN (?)", [$this->id, count($this->courses) ? array_keys($this->courses) : ''],
- function ($row) {
- StudipLog::log('SEM_CHANGED_ACCESS', $row['seminar_id'],
- null, 'Entfernung von Anmeldeset', sprintf('Anmeldeset: %s', $row['set_id']));
- //Delete priorities
- AdmissionPriority::unsetAllPrioritiesForCourse($row['seminar_id']);
- Course::buildExisting(['seminar_id' => $row['seminar_id']])->triggerChdate();
- });
- //removed course assignments
- DBManager::get()->execute("DELETE FROM `seminar_courseset`
- WHERE `set_id` = ? AND `seminar_id` NOT IN (?)", [$this->id, count($this->courses) ? array_keys($this->courses) : '']);
- //log removing other associations
- DBManager::get()->execute("SELECT seminar_id,set_id FROM `seminar_courseset`
- WHERE `set_id` <> ? AND `seminar_id` IN (?)", [$this->id, array_keys($this->courses)],
- function ($row) {
- StudipLog::log('SEM_CHANGED_ACCESS', $row['seminar_id'],
- null, 'Entfernung von Anmeldeset', sprintf('Anmeldeset: %s', $row['set_id']));
- //Delete priorities
- AdmissionPriority::unsetAllPrioritiesForCourse($row['seminar_id']);
- Course::buildExisting(['seminar_id' => $row['seminar_id']])->triggerChdate();
- });
- //Delete other associations, only one set possible
- DBManager::get()->execute("DELETE FROM `seminar_courseset`
- WHERE `set_id` <> ? AND `seminar_id` IN (?)", [$this->id, array_keys($this->courses)]);
- // Store associated course IDs.
- foreach ($this->courses as $course => $associated) {
- $stmt = DBManager::get()->prepare("INSERT IGNORE INTO `seminar_courseset`
- (`set_id`, `seminar_id`, `mkdate`)
- VALUES (?, ?, ?)");
- $stmt->execute([$this->id, $course, time()]);
- if ($stmt->rowCount()) {
- StudipLog::log('SEM_CHANGED_ACCESS', $course,
- null, 'Zuordnung zu Anmeldeset', sprintf('Anmeldeset: %s', $this->id));
- Course::buildExisting(['seminar_id' => $course])->triggerChdate();
- }
- }
-
- // Delete removed user list assignments from database.
- DBManager::get()->exec("DELETE FROM `courseset_factorlist`
- WHERE `set_id`='".$this->id."' AND `factorlist_id` NOT IN ('".
- implode("', '", array_keys($this->userlists))."')");
- // Store associated user list IDs.
- foreach ($this->userlists as $list => $associated) {
- $stmt = DBManager::get()->prepare("INSERT IGNORE INTO `courseset_factorlist`
- (`set_id`, `factorlist_id`, `mkdate`)
- VALUES (?, ?, ?)");
- $stmt->execute([$this->id, $list, time()]);
- }
- // Delete removed admission rules from database.
- $stmt = DBManager::get()->query("SELECT `rule_id`, `type` FROM `courseset_rule`
- WHERE `set_id`='".$this->id."' AND `rule_id` NOT IN ('".
- implode("', '", array_keys($this->admissionRules))."')");
- $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
- foreach ($data as $ruleData) {
- $rule = new $ruleData['type']($ruleData['rule_id']);
- $rule->delete();
- }
- // Store all rules.
- foreach ($this->admissionRules as $rule) {
- // Store each rule...
- $rule->store();
- // ... and its connection to the current course set.
- $stmt = DBManager::get()->prepare("INSERT INTO `courseset_rule`
- (`set_id`, `rule_id`, `type`, `mkdate`)
- VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE
- `type`=VALUES(`type`)");
- $stmt->execute([$this->id, $rule->getId(), get_class($rule), time()]);
- }
- //fix free access courses
- if (count($this->courses)) {
- DBManager::get()->execute("UPDATE seminare SET Lesezugriff=1,Schreibzugriff=1 WHERE seminar_id IN(?)", [array_keys($this->courses)]);
- }
- //create general log
- $this->log_store();
-
- }
-
- /**
- * Generates a general log entry if the CourseSet rules were changed.
- */
- private function log_store()
- {
- $text = '';
- $rule_counter = 1;
- foreach ($this->getAdmissionRules() as $rule) {
- $rule_text = strip_tags(kill_format($rule->toString()));
- $semicolon = ($rule_counter < count($this->getAdmissionRules()) ? '; ' : '');
- $text .= '#' . $rule_counter . ' => ' . $rule_text . $semicolon;
- $rule_counter++;
- }
-
- $courses = $this->getCourses();
- foreach ($courses as $course_id) {
- StudipLog::log(
- 'SEM_CHANGED_ACCESS',
- $course_id,
- NULL,
- $text,
- sprintf('Anmeldeset: %s (%s)', strip_tags(kill_format(($this->name))), $this->id)
- );
- }
- }
-
- /**
- * A textual description of the current rule.
- *
- * @param bool short Show only short info without overview of assigned
- * courses and institutes.
- * @return String
- */
- public function toString($short=false) {
- $tpl = $GLOBALS['template_factory']->open('admission/courseset/info');
- $tpl->set_attribute('courseset', $this);
- $tpl->set_attribute('is_limited', false);
- $institutes = [];
- if (!$short) {
- $institutes = Institute::findAndMapMany(function($i) {return $i->name;}, array_keys($this->institutes), 'ORDER BY Name');
- $tpl->set_attribute('institutes', $institutes);
- }
- if (!$short || $this->hasAdmissionRule('LimitedAdmission')) {
- $courses = Course::findAndMapMany(function($c) {
- return [
- 'id' => $c->id,
- 'name' => $c->getFullName('number-name-semester'),
- 'visible' => $c->visible
- ];
- },
- array_keys($this->courses),
- 'ORDER BY start_time,VeranstaltungsNummer,Name');
- if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) {
- $courses = array_filter($courses,
- function ($c) {
- return $c['visible'];
- }
- );
- }
- $tpl->set_attribute('is_limited', $this->hasAdmissionRule('LimitedAdmission'));
- $tpl->set_attribute('courses', $courses);
- }
- $tpl->set_attribute('short', $short);
- return $tpl->render();
- }
-
- public function __toString() {
- return $this->toString();
- }
-
- /**
- * is user with given user id allowed to assign/unassign given course to courseset
- *
- * @param string $user_id
- * @param string $course_id
- * @return boolean
- */
- public function isUserAllowedToAssignCourse($user_id, $course_id)
- {
- global $perm;
- $is_dozent = $perm->have_studip_perm('tutor', $course_id, $user_id);
- $is_admin = $perm->have_perm('admin', $user_id) || ($perm->have_perm('dozent', $user_id) && Config::get()->ALLOW_DOZENT_COURSESET_ADMIN);
- $is_private = $this->getPrivate();
- $is_my_own = $this->getUserId() == $user_id;
- $is_correct_institute = $this->isGlobal() || isset($this->institutes[Course::find($course_id)->institut_id]);
- return $is_dozent && $is_correct_institute && ($is_my_own || $is_admin || !$is_private || $this->isGlobal()) || $perm->have_perm('root', $user_id);
- }
-
- /**
- * is user with given user id allowed to edit or delete the courseset
- *
- * @param string $user_id
- * @return boolean
- */
- public function isUserAllowedToEdit($user_id)
- {
- global $perm;
-
- if ($this->getUserId() == '') {
- return false;
- }
- if ($perm->have_perm('root', $user_id) || $this->getUserId() == $user_id) {
- return true;
- }
- if (count($this->institutes) == 0 && count($this->courses) == 1 && $perm->have_studip_perm('tutor', current($this->getCourses()), $user_id)) {
- return true;
- }
- if ($perm->have_perm('admin', $user_id) || ($perm->have_perm('dozent', $user_id) && Config::get()->ALLOW_DOZENT_COURSESET_ADMIN)) {
- foreach (array_keys($this->getInstituteIds()) as $one) {
- if ($perm->have_studip_perm('dozent', $one, $user_id)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * checks if given rule is allowed to be added to current set of rules
- *
- * @param AdmissionRule|string $admission_rule
- * @return boolean
- */
- public function isAdmissionRuleAllowed($admission_rule)
- {
- foreach ($this->getAdmissionRules() as $one) {
- if (!$one->isCombinationAllowed($admission_rule)) {
- return false;
- }
- }
- return true;
- }
-
- public static function getGlobalLockedAdmissionSetId()
- {
- $db = DBManager::get();
- $locked_set_id = $db->fetchColumn("SELECT cr.set_id FROM courseset_rule cr
- INNER JOIN coursesets USING(set_id)
- WHERE type='LockedAdmission' and private=1 and user_id='' LIMIT 1");
- if (!$locked_set_id) {
- $cs_insert = $db->prepare("INSERT INTO coursesets (set_id,user_id,name,infotext,algorithm,private,mkdate,chdate)
- VALUES (?,?,?,?,'',?,?,?)");
- $cs_r_insert = $db->prepare("INSERT INTO courseset_rule (set_id,rule_id,type,mkdate) VALUES (?,?,?,UNIX_TIMESTAMP())");
- $locked_insert = $db->prepare("INSERT INTO lockedadmissions (rule_id,message,mkdate,chdate) VALUES (?,'Die Anmeldung ist gesperrt',UNIX_TIMESTAMP(),UNIX_TIMESTAMP())");
- $locked_set_id = md5(uniqid('coursesets',1));
- $name = 'Anmeldung gesperrt (global)';
- $cs_insert->execute([$locked_set_id,'',$name,'',1,time(),time()]);
- $locked_rule_id = md5(uniqid('lockedadmissions',1));
- $locked_insert->execute([$locked_rule_id]);
- $cs_r_insert->execute([$locked_set_id,$locked_rule_id,'LockedAdmission']);
- }
- return $locked_set_id;
- }
-
- public static function addCourseToSet($set_id, $course_id)
- {
- $db = DBManager::get();
- $ok = $db->execute("INSERT IGNORE INTO seminar_courseset (set_id,seminar_id,mkdate) VALUES (?,?,UNIX_TIMESTAMP())", [$set_id, $course_id]);
- if ($ok) {
- StudipLog::log('SEM_CHANGED_ACCESS', $course_id,
- null, 'Zuordnung zu Anmeldeset', sprintf('Anmeldeset: %s', $set_id));
- $course = Course::find($course_id);
- if ($course) {
- $course->chdate = time();
- $course->lesezugriff = 1;
- $course->schreibzugriff = 1;
- $course->store();
- }
- }
- return $ok;
- }
-
- public static function removeCourseFromSet($set_id, $course_id)
- {
- $db = DBManager::get();
- $ok = $db->execute("DELETE FROM seminar_courseset WHERE set_id=? AND seminar_id=? LIMIT 1", [$set_id, $course_id]);
- if ($ok) {
- StudipLog::log('SEM_CHANGED_ACCESS', $course_id,
- null, 'Entfernung von Anmeldeset', sprintf('Anmeldeset: %s', $set_id));
- //Delete priorities
- AdmissionPriority::unsetAllPrioritiesForCourse($course_id);
- Course::buildExisting(['seminar_id' => $course_id])->triggerChdate();
- }
- return $ok;
- }
-
- public function __clone()
- {
- $this->courses = [];
- $this->id = null;
- $this->user_id = null;
- $cloned_rules = [];
- foreach ($this->admissionRules as $key => $rule) {
- $dolly = clone $rule;
- $cloned_rules[$dolly->id] = $dolly;
- }
- $this->admissionRules = $cloned_rules;
- }
-
-} /* end of class CourseSet */