/** * Distribute seats for several courses in a course set. * No priorities are given. * * @param CourseSet $courseSet The course set containing the courses * that seats shall be distributed for. * @see CourseSet */ private function distributeByCourses($courseSet) { Log::DEBUG('start seat distribution for course set: ' . $courseSet->getId()); foreach ($courseSet->getCourses() as $course_id) { $course = Course::find($course_id); $free_seats = $course->getFreeSeats(); $claiming_users = AdmissionPriority::getPrioritiesByCourse($courseSet->getId(), $course->id); $factored_users = $courseSet->getUserFactorList(); //apply bonus/malus to users, exclude participants foreach (array_keys($claiming_users) as $user_id) { if (!$course->getParticipantStatus($user_id)) { $claiming_users[$user_id] = 1; if (isset($factored_users[$user_id])) { $claiming_users[$user_id] *= $factored_users[$user_id]; } Log::DEBUG(sprintf('user %s gets factor %s', $user_id, $claiming_users[$user_id])); } else { unset($claiming_users[$user_id]); Log::DEBUG(sprintf('user %s is already %s, ignoring', $user_id, $course->getParticipantStatus($user_id))); } } Log::DEBUG(sprintf('distribute %s seats on %s claiming in course %s', $free_seats, count($claiming_users), $course->id)); $claiming_users = $this->rollTheDice($claiming_users); Log::DEBUG('the die is cast: ' . print_r($claiming_users, 1)); $chosen_ones = array_slice(array_keys($claiming_users), 0, $free_seats); Log::DEBUG('chosen ones: ' . print_r($chosen_ones, 1)); $this->addUsersToCourse($chosen_ones, $course); if ($free_seats < count($claiming_users)) { if (!$course->admission_disable_waitlist) { $free_seats_waitlist = $course->admission_waitlist_max ?: count($claiming_users) - $free_seats; $waiting_list_ones = array_slice(array_keys($claiming_users), $free_seats, $free_seats_waitlist); Log::DEBUG('waiting list ones: ' . print_r($waiting_list_ones, 1)); $this->addUsersToWaitlist($waiting_list_ones, $course); } else { $free_seats_waitlist = 0; } if ($free_seats_waitlist + $free_seats < count($claiming_users)) { $remaining_ones = array_slice(array_keys($claiming_users), $free_seats_waitlist + $free_seats); Log::DEBUG('remaining ones: ' . print_r($remaining_ones, 1)); $this->notifyRemainingUsers($remaining_ones, $course); } } } }
function change_course_set_action() { CSRFProtection::verifyUnsafeRequest(); if (Request::submitted('change_course_set_assign') && Request::get('course_set_assign') && !LockRules::Check($this->course_id, 'admission_type')) { $cs = new CourseSet(Request::option('course_set_assign')); if ($cs->isUserAllowedToAssignCourse($this->user_id, $this->course_id)) { CourseSet::addCourseToSet($cs->getId(), $this->course_id); $cs->load(); if (in_array($this->course_id, $cs->getCourses())) { PageLayout::postMessage(MessageBox::success(sprintf(_("Die Zuordnung zum Anmeldeset %s wurde durchgeführt."), htmlReady($cs->getName())))); } } } if (Request::submitted('change_course_set_unassign') && !LockRules::Check($this->course_id, 'admission_type')) { $this->response->add_header('X-Title', _('Anmelderegeln aufheben')); if ($this->course->getNumWaiting() && !Request::submitted('change_course_set_unassign_yes')) { $question = sprintf(_("In dieser Veranstaltung existiert eine Warteliste. Die bestehende Warteliste mit %s Einträgen wird gelöscht. Sind sie sicher?"), $this->course->getNumWaiting()); } $cs = CourseSet::getSetForCourse($this->course_id); if ($cs) { $priorities = AdmissionPriority::getPrioritiesByCourse($cs->getId(), $this->course_id); if (count($priorities) && !Request::submitted('change_course_set_unassign_yes')) { $question = sprintf(_("In dieser Veranstaltung existiert eine Anmeldeliste (Losverfahren am %s). Die bestehende Anmeldeliste mit %s Einträgen wird gelöscht. Sind sie sicher?"), strftime('%x %R', $cs->getSeatDistributionTime()), count($priorities)); } } if (!$question && $cs) { CourseSet::removeCourseFromSet($cs->getId(), $this->course_id); $cs->load(); if (!in_array($this->course_id, $cs->getCourses())) { PageLayout::postMessage(MessageBox::success(sprintf(_("Die Zuordnung zum Anmeldeset %s wurde aufgehoben."), htmlReady($cs->getName())))); } if (!count($cs->getCourses()) && $cs->isGlobal() && $cs->getUserid() != '') { $cs->delete(); } if ($this->course->getNumWaiting()) { $num_moved = 0; foreach ($this->course->admission_applicants->findBy('status', 'awaiting') as $applicant) { setTempLanguage($applicant->user_id); $message_body = sprintf(_('Die Warteliste der Veranstaltung **%s** wurde deaktiviert, Sie sind damit __nicht__ zugelassen worden.'), $this->course->name); $message_title = sprintf(_("Statusänderung %s"), $this->course->name); messaging::sendSystemMessage($applicant->user_id, $message_title, $message_body); restoreLanguage(); $num_moved += $applicant->delete(); } if ($num_moved) { PageLayout::postMessage(MessageBox::success(sprintf(_("%s Wartende wurden entfernt."), $num_moved))); } } } } if (!$question) { $this->redirect($this->url_for('/index')); } else { $this->request = array('change_course_set_unassign' => 1); $this->button_yes = 'change_course_set_unassign_yes'; PageLayout::postMessage(MessageBox::info($question)); $this->render_template('course/admission/_change_admission.php'); } }
/** * Gets the list of applicants for the courses belonging to this course set. * * @param String $set_id course set ID * @param String $csv export users to file */ public function applications_list_action($set_id, $csv = null) { if (Request::isXhr()) { $this->response->add_header('X-Title', _('Liste der Anmeldungen')); } $courseset = new CourseSet($set_id); $applicants = AdmissionPriority::getPriorities($set_id); $users = User::findMany(array_keys($applicants), 'ORDER BY Nachname'); $courses = SimpleCollection::createFromArray(Course::findMany($courseset->getCourses())); $captions = array(_("Nachname"), _("Vorname"), _("Nutzername"), _("Veranstaltung"), _("Nummer"), _("Priorität")); $data = array(); foreach ($users as $user) { $row = array(); $app_courses = $applicants[$user->id]; asort($app_courses); foreach ($app_courses as $course_id => $prio) { $row = array(); $row[] = $user->nachname; $row[] = $user->vorname; $row[] = $user->username; $row[] = $courses->findOneBy('id', $course_id)->name; $row[] = $courses->findOneBy('id', $course_id)->veranstaltungsnummer; $row[] = $prio; if ($csv) { $row[] = $user->email; } $data[] = $row; } } if ($csv) { $tmpname = md5(uniqid('tmp')); $captions[] = _("Email"); if (array_to_csv($data, $GLOBALS['TMP_PATH'] . '/' . $tmpname, $captions)) { $this->redirect(GetDownloadLink($tmpname, 'Anmeldungen_' . $courseset->getName() . '.csv', 4, 'force')); return; } } $this->captions = $captions; $this->data = $data; $this->set_id = $courseset->getId(); }
public function execute($last_result, $parameters = array()) { $verbose = $parameters['verbose']; $sets = DbManager::get()->fetchFirst("SELECT DISTINCT cr.set_id FROM courseset_rule cr INNER JOIN coursesets USING(set_id)\n WHERE type = 'ParticipantRestrictedAdmission' AND algorithm_run = 0"); if (count($sets)) { if ($verbose) { echo date('r') . ' - Starting seat distribution ' . chr(10); $old_logger = Log::get()->getHandler(); $old_log_level = Log::get()->getLogLevel(); @mkdir($GLOBALS['TMP_PATH'] . '/seat_distribution_logs'); $logfile = $GLOBALS['TMP_PATH'] . '/seat_distribution_logs/' . date('Y-m-d-H-i') . '_seat_distribution.log'; if (is_dir($GLOBALS['TMP_PATH'] . '/seat_distribution_logs')) { Log::get()->setHandler($logfile); Log::get()->setLogLevel(Log::DEBUG); echo 'logging to ' . $logfile . chr(10); } else { echo 'could not create directory ' . $GLOBALS['TMP_PATH'] . '/seat_distribution_logs' . chr(10); } } foreach ($sets as $set_id) { $courseset = new CourseSet($set_id); if ($courseset->isSeatDistributionEnabled() && !$courseset->hasAlgorithmRun() && $courseset->getSeatDistributionTime() < time()) { if ($verbose) { echo ++$i . ' ' . $courseset->getId() . ' : ' . $courseset->getName() . chr(10); $applicants = AdmissionPriority::getPriorities($set_id); $courses = SimpleCollection::createFromArray(Course::findMany($courseset->getCourses()))->toGroupedArray('seminar_id', words('name veranstaltungsnummer')); $captions = array(_("Nachname"), _("Vorname"), _("Nutzername"), _('Nutzer-ID'), _('Veranstaltung-ID'), _("Veranstaltung"), _("Nummer"), _("Priorität")); $data = array(); $users = User::findEachMany(function ($user) use($courses, $applicants, &$data) { $app_courses = $applicants[$user->id]; asort($app_courses); foreach ($app_courses as $course_id => $prio) { $row = array(); $row[] = $user->nachname; $row[] = $user->vorname; $row[] = $user->username; $row[] = $user->id; $row[] = $course_id; $row[] = $courses[$course_id]['name']; $row[] = $courses[$course_id]['veranstaltungsnummer']; $row[] = $prio; $data[] = $row; } }, array_keys($applicants), 'ORDER BY Nachname'); $applicants_file = $GLOBALS['TMP_PATH'] . '/seat_distribution_logs/applicants_' . $set_id . '.csv'; if (array_to_csv($data, $applicants_file, $captions)) { echo 'applicants written to ' . $applicants_file . chr(10); } } $courseset->distributeSeats(); } } if ($verbose) { Log::get()->setHandler($old_logger); Log::get()->setLogLevel($old_log_level); } } else { if ($verbose) { echo date('r') . ' - Nothing to do' . chr(10); } } }