Forked from
Stud.IP / Stud.IP
3416 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Seminar.class.php 87.81 KiB
<?
# Lifter002: TODO
# Lifter003: TEST
# Lifter007: TODO
# Lifter010: TODO
/**
* Seminar.class.php - This class represents a Seminar in Stud.IP
*
* This class provides functions for seminar-members, seminar-dates, and seminar-modules
*
* 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 Till Glöggler <tgloeggl@uni-osnabrueck.de>
* @author Stefan Suchi <suchi@data-quest>
* @author Suchi & Berg GmbH <info@data-quest.de>
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
*/
require_once 'lib/admission.inc.php';
require_once 'lib/dates.inc.php';
class Seminar
{
var $issues = null; // Array of Issue
var $irregularSingleDates = null; // Array of SingleDates
var $messages = []; // occured errors, infos, and warnings
var $semester = null;
var $filterStart = 0;
var $filterEnd = 0;
var $hasDatesOutOfDuration = -1;
var $message_stack = [];
var $user_number = 0;//?
var $commands; //?
var $BookedRoomsStatTemp; //???
var $request_id;//TODO
var $requestData;
var $room_request;
private $_metadate = null; // MetaDate
private $alias = [
'seminar_number' => 'VeranstaltungsNummer',
'subtitle' => 'Untertitel',
'description' => 'Beschreibung',
'location' => 'Ort',
'misc' => 'Sonstiges',
'read_level' => 'Lesezugriff',
'write_level' => 'Schreibzugriff',
'semester_start_time' => 'start_time',
'semester_duration_time' => 'duration_time',
'form' => 'art',
'participants' => 'teilnehmer',
'requirements' => 'vorrausetzungen',
'orga' => 'lernorga',
];
private $course = null;
private $course_set = null;
private static $seminar_object_pool;
public static function GetInstance($id = false, $refresh_cache = false)
{
if ($id) {
if ($refresh_cache) {
self::$seminar_object_pool[$id] = null;
}
if (is_object(self::$seminar_object_pool[$id]) && self::$seminar_object_pool[$id]->getId() == $id) {
return self::$seminar_object_pool[$id];
} else {
self::$seminar_object_pool[$id] = new Seminar($id);
return self::$seminar_object_pool[$id];
}
} else {
return new Seminar(false);
}
}
public static function setInstance(Seminar $seminar)
{
return self::$seminar_object_pool[$seminar->id] = $seminar;
}
/**
* Constructor
*
* Pass nothing to create a seminar, or the seminar_id from an existing seminar to change or delete
* @access public
* @param string $seminar_id the seminar to be retrieved
*/
public function __construct($course_or_id = FALSE)
{
$course = Course::toObject($course_or_id);
if ($course) {
$this->course = $course;
} elseif ($course_or_id === false) {
$this->course = new Course();
$this->course->setId($this->course->getNewId());
} else { //hmhmhm
throw new Exception(sprintf(_('Fehler: Konnte das Seminar mit der ID %s nicht finden!'), $course_or_id));
}
}
public function __get($field)
{
if ($field == 'is_new') {
return $this->course->isNew();
}
if ($field == 'metadate') {
if ($this->_metadate === null) {
$this->_metadate = new MetaDate($this->id);
$this->_metadate->setSeminarStartTime($this->start_time);
$this->_metadate->setSeminarDurationTime($this->duration_time);
}
return $this->_metadate;
}
if(isset($this->alias[$field])) {
$field = $this->alias[$field];
}
return $this->course->$field;
}
public function __set($field, $value)
{
if(isset($this->alias[$field])) {
$field = $this->alias[$field];
}
if ($field == 'metadate') {
return $this->_metadate = $value;
}
return $this->course->$field = $value;
}
public function __isset($field)
{
if ($field == 'metadate') {
return is_object($this->_metadate);
}
if(isset($this->alias[$field])) {
$field = $this->alias[$field];
}
return isset($this->course->$field);
}
public function __call($method, $params)
{
return call_user_func_array([$this->course, $method], $params);
}
public static function GetSemIdByDateId($date_id)
{
$stmt = DBManager::get()->prepare("SELECT range_id FROM termine WHERE termin_id = ? LIMIT 1");
$stmt->execute([$date_id]);
return $stmt->fetchColumn();
}
/**
*
* creates an new id for this object
* @access private
* @return string the unique id
*/
public function createId()
{
return $this->course->getNewId();
}
public function getMembers($status = 'dozent')
{
$ret = [];
foreach($this->course->getMembersWithStatus($status) as $m) {
$ret[$m->user_id]['user_id'] = $m->user_id;
$ret[$m->user_id]['username'] = $m->username;
$ret[$m->user_id]['Vorname'] = $m->vorname;
$ret[$m->user_id]['Nachname'] = $m->nachname;
$ret[$m->user_id]['Email'] = $m->email;
$ret[$m->user_id]['position'] = $m->position;
$ret[$m->user_id]['label'] = $m->label;
$ret[$m->user_id]['status'] = $m->status;
$ret[$m->user_id]['mkdate'] = $m->mkdate;
$ret[$m->user_id]['fullname'] = $m->getUserFullname();
}
return $ret;
}
public function getAdmissionMembers($status = 'awaiting')
{
$ret = [];
foreach($this->course->admission_applicants->findBy('status', $status)->orderBy('position nachname') as $m) {
$ret[$m->user_id]['user_id'] = $m->user_id;
$ret[$m->user_id]['username'] = $m->username;
$ret[$m->user_id]['Vorname'] = $m->vorname;
$ret[$m->user_id]['Nachname'] = $m->nachname;
$ret[$m->user_id]['Email'] = $m->email;
$ret[$m->user_id]['position'] = $m->position;
$ret[$m->user_id]['status'] = $m->status;
$ret[$m->user_id]['mkdate'] = $m->mkdate;
$ret[$m->user_id]['fullname'] = $m->getUserFullname();
}
return $ret;
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
/**
* return the field VeranstaltungsNummer for the seminar
*
* @return string the seminar-number for the current seminar
*/
public function getNumber()
{
return $this->seminar_number;
}
public function isVisible()
{
return $this->visible;
}
public function getInstitutId()
{
return $this->institut_id;
}
public function getSemesterStartTime()
{
return $this->semester_start_time;
}
public function getSemesterDurationTime()
{
return $this->semester_duration_time;
}
public function getNextDate($return_mode = 'string')
{
$next_date = '';
if ($return_mode == 'int') {
echo __class__.'::'.__function__.', line '.__line__.', return_mode "int" ist not supported by this function!';die;
}
if (!$termine = SeminarDB::getNextDate($this->id))
return false;
foreach ($termine['termin'] as $singledate_id) {
$next_date .= DateFormatter::formatDateAndRoom($singledate_id, $return_mode) . '<br>';
}
if (!empty($termine['ex_termin'])) {
foreach ($termine['ex_termin'] as $ex_termin_id) {
$ex_termin = new SingleDate($ex_termin_id);
$template = $GLOBALS['template_factory']->open('dates/missing_date.php');
$template->formatted_date = DateFormatter::formatDateAndRoom($ex_termin_id, $return_mode);
$template->ex_termin = $ex_termin;
$missing_date = $template->render();
if (!empty($termine['termin'])) {
$termin = new SingleDate($termine['termin'][0]);
if ($ex_termin->getStartTime() <= $termin->getStartTime()) {
return $next_date . $missing_date;
} else {
return $next_date;
}
} else {
return $missing_date;
}
}
} else {
return $next_date;
}
return false;
}
public function getFirstDate($return_mode = 'string') {
if (!$dates = SeminarDB::getFirstDate($this->id)) {
return false;
}
return DateFormatter::formatDateWithAllRooms(['termin' => $dates], $return_mode);
}
/**
* This function returns an associative array of the dates owned by this seminar
*
* @returns mixed a multidimensional array of seminar-dates
*/
public function getUndecoratedData($filter = false)
{
// Caching
$cache = StudipCacheFactory::getCache();
$cache_key = 'course/undecorated_data/'. $this->id;
if ($filter) {
$sub_key = $_SESSION['_language'] .'/'. $this->filterStart .'-'. $this->filterEnd;
} else {
$sub_key = $_SESSION['_language'] .'/unfiltered';
}
$data = unserialize($cache->read($cache_key));
// build cache from scratch
if (!$data || !$data[$sub_key]) {
$cycles = $this->metadate->getCycleData();
$dates = $this->getSingleDates($filter, $filter);
$rooms = [];
foreach (array_keys($cycles) as $id) {
if ($this->filterStart && $this->filterEnd
&& !$this->metadate->hasDates($id, $this->filterStart, $this->filterEnd))
{
unset($cycles[$id]);
continue;
}
$cycles[$id]['first_date'] = CycleDataDB::getFirstDate($id);
if (!empty($cycles[$id]['assigned_rooms'])) {
foreach ($cycles[$id]['assigned_rooms'] as $room_id => $count) {
$rooms[$room_id] += $count;
}
}
}
// besser wieder mit direktem Query statt Objekten
if (is_array($cycles) && count($cycles) === 0) {
$cycles = false;
}
$ret['regular']['turnus_data'] = $cycles;
// the irregular single-dates
foreach ($dates as $val) {
$zw = [
'metadate_id' => $val->getMetaDateID(),
'termin_id' => $val->getTerminID(),
'date_typ' => $val->getDateType(),
'start_time' => $val->getStartTime(),
'end_time' => $val->getEndTime(),
'mkdate' => $val->getMkDate(),
'chdate' => $val->getMkDate(),
'ex_termin' => $val->isExTermin(),
'orig_ex' => $val->isExTermin(),
'range_id' => $val->getRangeID(),
'author_id' => $val->getAuthorID(),
'resource_id' => $val->getResourceID(),
'raum' => $val->getFreeRoomText(),
'typ' => $val->getDateType(),
'tostring' => $val->toString()
];
if ($val->getResourceID()) {
$rooms[$val->getResourceID()]++;
}
$ret['irregular'][$val->getTerminID()] = $zw;
}
$ret['rooms'] = $rooms;
$ret['ort'] = $this->location;
$data[$sub_key] = $ret;
// write data to cache
$cache->write($cache_key, serialize($data), 600);
}
return $data[$sub_key];
}
public function getFormattedTurnus($short = FALSE)
{
// activate this with StEP 00077
/* $cache = Cache::instance();
* $cache_key = "formatted_turnus".$this->id;
* if (! $return_string = $cache->read($cache_key))
* {
*/
return $this->getDatesExport(['short' => $short, 'shrink' => true]);
// activate this with StEP 00077
// $cache->write($cache_key, $return_string, 60*60);
// }
}
public function getFormattedTurnusDates($short = FALSE)
{
if ($cycles = $this->metadate->getCycles()) {
$return_string = [];
foreach ($cycles as $id => $c) {
$return_string[$id] = $c->toString($short);
//hmm tja...
if ($c->description){
$return_string[$id] .= ' ('. htmlReady($c->description) .')';
}
}
return $return_string;
} else
return FALSE;
}
public function getMetaDateCount()
{
return sizeof($this->metadate->cycles);
}
public function getMetaDateValue($key, $value_name)
{
return $this->metadate->cycles[$key]->$value_name;
}
public function setMetaDateValue($key, $value_name, $value)
{
$this->metadate->cycles[$key]->$value_name = $value;
}
/**
* restore the data
*
* the complete data of the object will be loaded from the db
* @access public
* @throws Exception if there is no such course
* @return boolean always true
*/
public function restore()
{
if ($this->course->id) {
$this->course->restore();
}
$this->irregularSingleDates = null;
$this->issues = null;
$this->_metadate = null;
$this->course_set = null;
return TRUE;
}
/**
* returns an array of variables from the seminar-object, excluding variables
* containing objects or arrays
*
* @return array
*/
public function getSettings() {
$settings = $this->course->toRawArray();
unset($settings['config']);
return $settings;
}
public function store($trigger_chdate = true)
{
// activate this with StEP 00077
// $cache = Cache::instance();
// $cache->expire("formatted_turnus".$this->id);
//check for security consistency
if ($this->write_level < $this->read_level) // hier wusste ein Lehrender nicht, was er tat
$this->write_level = $this->read_level;
if ($this->irregularSingleDates) {
foreach ($this->irregularSingleDates as $val) {
$val->store();
}
}
if ($this->issues) {
foreach ($this->issues as $val) {
$val->store();
}
}
$metadate_changed = isset($this->metadate) ? $this->metadate->store() : 0;
$course_changed = $this->course->store();
if ($metadate_changed && $trigger_chdate) {
return $this->course->triggerChdate();
} else {
return $course_changed ?: false;
}
}
public function setStartSemester($start)
{
global $perm;
if ($perm->have_perm('tutor') && $start != $this->semester_start_time) {
// logging >>>>>>
StudipLog::log("SEM_SET_STARTSEMESTER", $this->getId(), $start);
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
// logging <<<<<<
$this->semester_start_time = $start;
$this->metadate->setSeminarStartTime($start);
$this->createMessage(_("Das Startsemester wurde geändert."));
$this->createInfo(_("Beachten Sie, dass Termine, die nicht mit den Einstellungen der regelmäßigen Zeit übereinstimmen (z.B. auf Grund einer Verschiebung der regelmäßigen Zeit), teilweise gelöscht sein könnten!"));
return TRUE;
}
return FALSE;
}
public function removeAndUpdateSingleDates()
{
SeminarCycleDate::removeOutRangedSingleDates(
$this->semester_start_time,
$this->getEndSemesterVorlesEnde(),
$this->id
);
foreach ($this->metadate->cycles as $key => $val) {
$this->metadate->cycles[$key]->readSingleDates();
$this->metadate->createSingleDates($key);
$this->metadate->cycles[$key]->termine = NULL;
}
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
}
public function getStartSemester()
{
return $this->semester_start_time;
}
/*
* setEndSemester
* @param end integer 0 (one Semester), -1 (eternal), or timestamp of last happening semester
* @returns TRUE on success, FALSE on failure
*/
public function setEndSemester($end)
{
global $perm;
$previousEndSemester = $this->getEndSemester(); // save the end-semester before it is changed, so we can choose lateron in which semesters we need to be rebuilt the SingleDates
if ($end != $this->getEndSemester()) { // only change Duration if it differs from the current one
if ($end == 0) { // the seminar takes place just in the selected start-semester
$this->semester_duration_time = 0;
$this->metadate->setSeminarDurationTime(0);
// logging >>>>>>
StudipLog::log("SEM_SET_ENDSEMESTER", $this->getId(), $end, 'Laufzeit: 1 Semester');
// logging <<<<<<
} else if ($end == -1) { // the seminar takes place in every semester above and including the start-semester
// logging >>>>>>
StudipLog::log("SEM_SET_ENDSEMESTER", $this->getId(), $end, 'Laufzeit: unbegrenzt');
// logging <<<<<<
$this->semester_duration_time = -1;
$this->metadate->setSeminarDurationTime(-1);
SeminarCycleDate::removeOutRangedSingleDates(
$this->semester_start_time,
$this->getEndSemesterVorlesEnde(),
$this->id
);
} else { // the seminar takes place between the selected start~ and end-semester
// logging >>>>>>
StudipLog::log("SEM_SET_ENDSEMESTER", $this->getId(), $end);
// logging <<<<<<
$this->semester_duration_time = $end - $this->semester_start_time; // the duration is stored, not the real end-point
$this->metadate->setSeminarDurationTime($this->semester_duration_time);
}
$this->createMessage(_("Die Dauer wurde geändert."));
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
/*
* If the duration has been changed, we have to create new SingleDates
* if the new duration is longer than the previous one
*/
if ( ($previousEndSemester != -1) && ( ($previousEndSemester < $this->getEndSemester()) || (($previousEndSemester == 0) && ($this->getEndSemester() == -1) ) )) {
// if the previous duration was unlimited, the only option choosable is
// a shorter duration then 'ever', so there cannot be any new SingleDates
// special case: if the previous selection was 'one semester' and the new one is 'eternal',
// than we have to find out the end of the only semester, the start-semester
if ($previousEndSemester == 0) {
$startAfterTimeStamp = $this->course->start_semester->ende;
} else {
$startAfterTimeStamp = $previousEndSemester;
}
foreach ($this->metadate->cycles as $key => $val) {
$this->metadate->createSingleDates(['metadate_id' => $key, 'startAfterTimeStamp' => $startAfterTimeStamp]);
$this->metadate->cycles[$key]->termine = NULL; // emtpy the SingleDates for each cycle, so that SingleDates, which were not in the current view, are not loaded and therefore should not be visible
}
}
}
return TRUE;
}
/*
* getEndSemester
* @returns 0 (one Semester), -1 (eternal), or TimeStamp of last Semester for this Seminar
*/
public function getEndSemester()
{
if ($this->semester_duration_time == 0) return 0; // seminar takes place only in the start-semester
if ($this->semester_duration_time == -1) return -1; // seminar takes place eternally
return $this->semester_start_time + $this->semester_duration_time; // seminar takes place between start~ and end-semester
}
public function getEndSemesterVorlesEnde()
{
if ($this->semester_duration_time == -1) {
$semesters = Semester::getAll();
$very_last_semester = array_pop($semesters);
return $very_last_semester->vorles_ende;
}
return $this->course->end_semester->vorles_ende;
}
/**
* return the name of the seminars start-semester
*
* @return string the name of the start-semester or false if there is no start-semester
*/
public function getStartSemesterName()
{
return $this->course->start_semester->name;
}
/**
* return an array of singledate-objects for the submitted cycle identified by metadate_id
*
* @param string $metadate_id the id identifying the cycle
*
* @return mixed an array of singledate-objects
*/
public function readSingleDatesForCycle($metadate_id)
{
return $this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd);
}
public function readSingleDates($force = FALSE, $filter = FALSE)
{
if (!$force) {
if (is_array($this->irregularSingleDates)) {
return TRUE;
}
}
$this->irregularSingleDates = [];
if ($filter) {
$data = SeminarDB::getSingleDates($this->id, $this->filterStart, $this->filterEnd);
} else {
$data = SeminarDB::getSingleDates($this->id);
}
foreach ($data as $val) {
unset($termin);
$termin = new SingleDate();
$termin->fillValuesFromArray($val);
$this->irregularSingleDates[$val['termin_id']] =& $termin;
}
}
public function &getSingleDate($singleDateID, $cycle_id = '')
{
if ($cycle_id == '') {
$this->readSingleDates();
return $this->irregularSingleDates[$singleDateID];
} else {
$dates = $this->metadate->getSingleDates($cycle_id, $this->filterStart, $this->filterEnd);
$data =& $dates;
return $data[$singleDateID];
}
}
public function &getSingleDates($filter = false, $force = false, $include_deleted_dates = false)
{
$this->readSingleDates($force, $filter);
if (!$include_deleted_dates) {
return $this->irregularSingleDates;
} else {
$deleted_dates = [];
foreach (SeminarDB::getDeletedSingleDates($this->getId(), $this->filterStart, $this->filterEnd) as $val) {
$termin = new SingleDate();
$termin->fillValuesFromArray($val);
$deleted_dates[$val['termin_id']] = $termin;
}
$dates = array_merge($this->irregularSingleDates, $deleted_dates);
uasort($dates, function($a,$b) {
if ($a->getStartTime() == $b->getStartTime()) return 0;
return $a->getStartTime() < $b->getStartTime() ? -1 : 1;}
);
return $dates;
}
}
public function getCycles()
{
return $this->metadate->getCycles();
}
public function &getSingleDatesForCycle($metadate_id)
{
if (!$this->metadate->cycles[$metadate_id]->termine) {
$this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd);
if (!$this->metadate->cycles[$metadate_id]->termine) {
$this->readSingleDates();
$this->metadate->createSingleDates($metadate_id, $this->irregularSingleDates);
$this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd);
}
//$this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd);
}
$dates = $this->metadate->getSingleDates($metadate_id, $this->filterStart, $this->filterEnd);
return $dates;
}
public function readIssues($force = false)
{
if (!is_array($this->issues) || $force) {
$this->issues = [];
$data = SeminarDB::getIssues($this->id);
foreach ($data as $val) {
unset($issue);
$issue = new Issue();
$issue->fillValuesFromArray($val);
$this->issues[$val['issue_id']] =& $issue;
}
}
}
public function addSingleDate(&$singledate)
{
// logging >>>>>>
StudipLog::log("SEM_ADD_SINGLEDATE", $this->getId(), $singledate->toString(), 'SingleDateID: '.$singledate->getTerminID());
// logging <<<<<<
$cache = StudipCacheFactory::getCache();
$cache->expire('course/undecorated_data/'. $this->getId());
$this->readSingleDates();
$this->irregularSingleDates[$singledate->getSingleDateID()] =& $singledate;
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
return TRUE;
}
public function addIssue(&$issue)
{
$this->readIssues();
if ($issue instanceof Issue) {
$max = -1;
if (is_array($this->issues)) foreach ($this->issues as $val) {
if ($val->getPriority() > $max) {
$max = $val->getPriority();
}
}
$max++;
$issue->setPriority($max);
$this->issues[$issue->getIssueID()] =& $issue;
return TRUE;
} else {
return FALSE;
}
}
public function deleteSingleDate($date_id, $cycle_id = '')
{
$this->readSingleDates();
// logging >>>>>>
StudipLog::log("SEM_DELETE_SINGLEDATE",$date_id, $this->getId(), 'Cycle_id: '.$cycle_id);
// logging <<<<<<
if ($cycle_id == '') {
$this->irregularSingleDates[$date_id]->delete(true);
unset ($this->irregularSingleDates[$date_id]);
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
return TRUE;
} else {
$this->metadate->deleteSingleDate($cycle_id, $date_id, $this->filterStart, $this->filterEnd);
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
return TRUE;
}
}
public function cancelSingleDate($date_id, $cycle_id = '')
{
if ($cycle_id) {
return $this->deleteSingleDate($date_id, $cycle_id);
}
$this->readSingleDates();
// logging >>>>>>
StudipLog::log("SEM_DELETE_SINGLEDATE",$date_id, $this->getId(), 'appointment cancelled');
// logging <<<<<<
$this->irregularSingleDates[$date_id]->setExTermin(true);
$this->irregularSingleDates[$date_id]->store();
unset ($this->irregularSingleDates[$date_id]);
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
return TRUE;
}
public function unDeleteSingleDate($date_id, $cycle_id = '')
{
// logging >>>>>>
StudipLog::log("SEM_UNDELETE_SINGLEDATE",$date_id, $this->getId(), 'Cycle_id: '.$cycle_id);
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
// logging <<<<<<
if ($cycle_id == '') {
$termin = new SingleDate($date_id);
if (!$termin->isExTermin()) {
return false;
}
$termin->setExTermin(false);
$termin->store();
return true;
} else {
return $this->metadate->unDeleteSingleDate($cycle_id, $date_id, $this->filterStart, $this->filterEnd);
}
}
/**
* return all stacked messages as a multidimensional array
*
* The array has the following structure:
* array( 'type' => ..., 'message' ... )
* where type is one of error, info and success
*
* @return mixed the array of stacked messages
*/
public function getStackedMessages()
{
if ( is_array( $this->message_stack ) ) {
$ret = [];
// cycle through message types and set title and details appropriate
foreach ($this->message_stack as $type => $messages ) {
switch ( $type ) {
case 'error':
$ret['error'] = [
'title' => _("Es sind Fehler/Probleme aufgetreten!"),
'details' => $this->message_stack['error']
];
break;
case 'info':
$ret['info'] = [
'title' => implode('<br>', $this->message_stack['info']),
'details' => []
];
break;
case 'success':
$ret['success'] = [
'title' => _("Ihre Änderungen wurden gespeichert!"),
'details' => $this->message_stack['success']
];
break;
}
}
return $ret;
}
return false;
}
/**
* return the next stacked messag-string
*
* @return string a message-string
*/
public function getNextMessage()
{
if ($this->messages[0]) {
$ret = $this->messages[0];
unset ($this->messages[0]);
sort($this->messages);
return $ret;
}
return FALSE;
}
/**
* stack an error-message
*
* @param string $text the message to stack
*/
public function createError($text)
{
$this->messages[] = 'error§'.$text.'§';
$this->message_stack['error'][] = $text;
}
/**
* stack an info-message
*
* @param string $text the message to stack
*/
public function createInfo($text)
{
$this->messages[] = 'info§'.$text.'§';
$this->message_stack['info'][] = $text;
}
/**
* stack a success-message
*
* @param string $text the message to stack
*/
public function createMessage($text)
{
$this->messages[] = 'msg§'.$text.'§';
$this->message_stack['success'][] = $text;
}
/**
* add an array of messages to the message-stack
*
* @param mixed $messages array of pre-marked message-strings
* @param bool returns true on success
*/
public function appendMessages( $messages )
{
if (!is_array($messages)) return false;
foreach ( $messages as $type => $msgs ) {
foreach ($msgs as $msg) {
$this->message_stack[$type][] = $msg;
}
}
return true;
}
public function addCycle($data = [])
{
$new_id = $this->metadate->addCycle($data);
if($new_id){
$this->setStartWeek($data['startWeek'], $new_id);
$this->setTurnus($data['turnus'], $new_id);
}
// logging >>>>>>
if($new_id){
$cycle_info = $this->metadate->cycles[$new_id]->toString();
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
StudipLog::log("SEM_ADD_CYCLE", $this->getId(), NULL, $cycle_info, '<pre>'.print_r($data,true).'</pre>');
}
// logging <<<<<<
return $new_id;
}
/**
* Change a regular timeslot of the seminar. The data is passed as an array
* conatining the following fields:
* start_stunde, start_minute, end_stunde, end_minute
* description, turnus, startWeek, day, sws
*
* @param array $data the cycle-data
*
* @return void
*/
public function editCycle($data = [])
{
$cycle = $this->metadate->cycles[$data['cycle_id']];
$new_start = mktime($data['start_stunde'], $data['start_minute']);
$new_end = mktime($data['end_stunde'], $data['end_minute']);
$old_start = mktime($cycle->getStartStunde(),$cycle->getStartMinute());
$old_end = mktime($cycle->getEndStunde(), $cycle->getEndMinute());
$do_changes = false;
// check, if the new timeslot exceeds the old one
if (($new_start < $old_start) || ($new_end > $old_end) || ($data['day'] != $cycle->day) ) {
$has_bookings = false;
// check, if there are any booked rooms
foreach($cycle->getSingleDates() as $singleDate) {
if ($singleDate->getStarttime() > (time() - 3600) && $singleDate->hasRoom()) {
$has_bookings = true;
break;
}
}
// if the timeslot exceeds the previous one and has some booked rooms
// they would be lost, so ask the user for permission to do so.
if (!$data['really_change'] && $has_bookings) {
$link_params = [
'editCycle_x' => '1',
'editCycle_y' => '1',
'cycle_id' => $data['cycle_id'],
'start_stunde' => $data['start_stunde'],
'start_minute' => $data['start_minute'],
'end_stunde' => $data['end_stunde'],
'end_minute' => $data['end_minute'],
'day' => $data['day'],
'really_change' => 'true'
];
$question = _("Wenn Sie die regelmäßige Zeit auf %s ändern, verlieren Sie die Raumbuchungen für alle in der Zukunft liegenden Termine!")
."\n". _("Sind Sie sicher, dass Sie die regelmäßige Zeit ändern möchten?");
$question_time = '**'. strftime('%A', $data['day']) .', '. $data['start_stunde'] .':'. $data['start_minute']
.' - '. $data['end_stunde'] .':'. $data['end_minute'] .'**';
echo (string)QuestionBox::create(
sprintf($question, $question_time),
URLHelper::getURL('', $link_params)
);
} else {
$do_changes = true;
}
} else {
$do_changes = true;
}
$messages = false;
$same_time = false;
// only apply changes, if the user approved the change or
// the change does not need any approval
if ($do_changes) {
if ($data['description'] != $cycle->getDescription()) {
$this->createMessage(_("Die Beschreibung des regelmäßigen Eintrags wurde geändert."));
$message = true;
$do_changes = true;
}
if ($old_start == $new_start && $old_end == $new_end) {
$same_time = true;
}
if ($data['startWeek'] != $cycle->week_offset) {
$this->setStartWeek($data['startWeek'], $cycle->metadate_id);
$message = true;
$do_changes = true;
}
if ($data['turnus'] != $cycle->cycle) {
$this->setTurnus($data['turnus'], $cycle->metadate_id);
$message = true;
$do_changes = true;
}
if ($data['day'] != $cycle->day) {
$message = true;
$same_time = false;
$do_changes = true;
}
if (round(str_replace(',','.', $data['sws']),1) != $cycle->sws) {
$cycle->sws = $data['sws'];
$this->createMessage(_("Die Semesterwochenstunden für Lehrende des regelmäßigen Eintrags wurden geändert."));
$message = true;
$do_changes = true;
}
$change_from = $cycle->toString();
if ($this->metadate->editCycle($data)) {
if (!$same_time) {
// logging >>>>>>
StudipLog::log("SEM_CHANGE_CYCLE", $this->getId(), NULL, $change_from .' -> '. $cycle->toString());
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
// logging <<<<<<
$this->createMessage(sprintf(_("Die regelmäßige Veranstaltungszeit wurde auf \"%s\" für alle in der Zukunft liegenden Termine geändert!"),
'<b>'.getWeekday($data['day']) . ', ' . $data['start_stunde'] . ':' . $data['start_minute'].' - '.
$data['end_stunde'] . ':' . $data['end_minute'] . '</b>'));
$message = true;
}
} else {
if (!$same_time) {
$this->createInfo(sprintf(_("Die regelmäßige Veranstaltungszeit wurde auf \"%s\" geändert, jedoch gab es keine Termine die davon betroffen waren."),
'<b>'.getWeekday($data['day']) . ', ' . $data['start_stunde'] . ':' . $data['start_minute'].' - '.
$data['end_stunde'] . ':' . $data['end_minute'] . '</b>'));
$message = true;
}
}
$this->metadate->sortCycleData();
if (!$message) {
$this->createInfo("Sie haben keine Änderungen vorgenommen!");
}
}
}
public function deleteCycle($cycle_id)
{
// logging >>>>>>
$cycle_info = $this->metadate->cycles[$cycle_id]->toString();
StudipLog::log("SEM_DELETE_CYCLE", $this->getId(), NULL, $cycle_info);
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
// logging <<<<<<
return $this->metadate->deleteCycle($cycle_id);
}
public function setTurnus($turnus, $metadate_id = false)
{
if ($this->metadate->getTurnus($metadate_id) != $turnus) {
$this->metadate->setTurnus($turnus, $metadate_id);
$key = $metadate_id ? $metadate_id : $this->metadate->getFirstMetadate()->metadate_id;
$this->createMessage(sprintf(_("Der Turnus für den Termin %s wurde geändert."), $this->metadate->cycles[$key]->toString()));
$this->metadate->createSingleDates($key);
$this->metadate->cycles[$key]->termine = null;
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
}
return TRUE;
}
public function getTurnus($metadate_id = false)
{
return $this->metadate->getTurnus($metadate_id);
}
/**
* get StatOfNotBookedRooms returns an array:
* open: number of rooms with no booking
* all: number of singleDates, which can have a booking
* open_rooms: array of singleDates which have no booking
*
* @param String $cycle_id Id of cycle
* @return array as described above
*/
public function getStatOfNotBookedRooms($cycle_id)
{
if (!isset($this->BookedRoomsStatTemp[$cycle_id])) {
$this->BookedRoomsStatTemp[$cycle_id] = SeminarDB::getStatOfNotBookedRooms($cycle_id, $this->id, $this->filterStart, $this->filterEnd);
}
return $this->BookedRoomsStatTemp[$cycle_id];
}
public function getStatus()
{
return $this->status;
}
public function getBookedRoomsTooltip($cycle_id)
{
$stat = $this->getStatOfNotBookedRooms($cycle_id);
$pattern = '%s , %s, %s-%s <br />';
if (($stat['open'] > 0) && ($stat['open'] == $stat['all'])) {
$return = '';
} else if ($stat['open'] > 0) {
$return = _('Folgende Termine haben keine Raumbuchung:') . '<br />';
foreach ($stat['open_rooms'] as $aSingleDate) {
$return .= sprintf($pattern,strftime('%a', $aSingleDate['date']),
strftime('%d.%m.%Y', $aSingleDate['date']),
strftime('%H:%M', $aSingleDate['date']),
strftime('%H:%M', $aSingleDate['end_time']));
}
}
// are there any dates with declined room-requests?
if ($stat['declined'] > 0) {
$return .= _('Folgende Termine haben eine abgelehnte Raumanfrage') . '<br />';
foreach ($stat['declined_dates'] as $aSingleDate) {
$return .= sprintf($pattern,strftime('%a', $aSingleDate['date']),
strftime('%d.%m.%Y', $aSingleDate['date']),
strftime('%H:%M', $aSingleDate['date']),
strftime('%H:%M', $aSingleDate['end_time']));
}
}
return $return;
}
/**
* @param $cycle_id
* @return string
*/
public function getCycleColorClass($cycle_id)
{
if (Config::get()->RESOURCES_ENABLE && Config::get()->RESOURCES_ENABLE_BOOKINGSTATUS_COLORING) {
if (!$this->metadate->hasDates($cycle_id, $this->filterStart, $this->filterEnd)) {
return 'red';
}
$stat = $this->getStatOfNotBookedRooms($cycle_id);
if ($stat['open'] > 0 && $stat['open'] == $stat['all']) {
return 'red';
}
if ($stat['open'] > 0) {
return 'yellow ';
}
return 'green ';
}
return '';
}
public function &getIssues($force = false)
{
$this->readIssues($force);
$this->renumberIssuePrioritys();
if (is_array($this->issues)) {
uasort($this->issues, function ($a, $b) {
return $a->getPriority() - $b->getPriority();
});
}
return $this->issues;
}
public function deleteIssue($issue_id)
{
$this->issues[$issue_id]->delete();
unset($this->issues[$issue_id]);
return TRUE;
}
public function &getIssue($issue_id)
{
$this->readIssues();
return $this->issues[$issue_id];
}
/*
* changeIssuePriority
*
* changes an issue with an given id to a new priority
*
* @param
* issue_id the issue_id of the issue to be changed
* new_priority the new priority
*/
public function changeIssuePriority($issue_id, $new_priority)
{
/* REMARK:
* This function only works, when an issue is moved ONE slote higher or lower
* It does NOT work with ARBITRARY movements!
*/
$this->readIssues();
$old_priority = $this->issues[$issue_id]->getPriority(); // get old priority, so we can just exchange prioritys of two issues
foreach ($this->issues as $id => $issue) { // search for the concuring issue
if ($issue->getPriority() == $new_priority) {
$this->issues[$id]->setPriority($old_priority); // the concuring issue gets the old id of the changed issue
$this->issues[$id]->store(); // ###store_problem###
}
}
$this->issues[$issue_id]->setPriority($new_priority); // changed issue gets the new priority
$this->issues[$issue_id]->store(); // ###store_problem###
}
public function renumberIssuePrioritys()
{
if (is_array($this->issues)) {
$sorter = [];
foreach ($this->issues as $id => $issue) {
$sorter[$id] = $issue->getPriority();
}
asort($sorter);
$i = 0;
foreach ($sorter as $id => $old_priority) {
$this->issues[$id]->setPriority($i);
$i++;
}
}
}
public function autoAssignIssues($themen, $cycle_id)
{
$this->metadate->cycles[$cycle_id]->autoAssignIssues($themen, $this->filterStart, $this->filterEnd);
}
public function applyTimeFilter($start, $end)
{
$this->filterStart = $start;
$this->filterEnd = $end;
}
public function setFilter($timestamp)
{
if ($timestamp == 'all') {
$_SESSION['raumzeitFilter'] = 'all';
$this->applyTimeFilter(0, 0);
} else {
$filterSemester = Semester::findByTimestamp($timestamp);
$_SESSION['raumzeitFilter'] = $filterSemester->beginn;
$this->applyTimeFilter($filterSemester->beginn, $filterSemester->ende);
}
}
public function registerCommand($command, $function)
{
$this->commands[$command] = $function;
}
public function processCommands()
{
global $cmd;
// workaround for multiple submit-buttons with new Button-API
foreach ($this->commands as $r_cmd => $func) {
if (Request::submitted($r_cmd)) {
$cmd = $r_cmd;
}
}
if (!isset($cmd) && Request::option('cmd')) $cmd = Request::option('cmd');
if (!isset($cmd)) return FALSE;
if (isset($this->commands[$cmd])) {
call_user_func($this->commands[$cmd], $this);
}
}
public function getFreeTextPredominantRoom($cycle_id)
{
if (!($room = $this->metadate->cycles[$cycle_id]->getFreeTextPredominantRoom($this->filterStart, $this->filterEnd))) {
return FALSE;
}
return $room;
}
public function getPredominantRoom($cycle_id, $list = FALSE)
{
if (!($rooms = $this->metadate->cycles[$cycle_id]->getPredominantRoom($this->filterStart, $this->filterEnd))) {
return FALSE;
}
if ($list) {
return $rooms;
} else {
return $rooms[0];
}
}
public function hasDatesOutOfDuration($force = false)
{
if ($this->hasDatesOutOfDuration == -1 || $force) {
$this->hasDatesOutOfDuration = SeminarDB::hasDatesOutOfDuration($this->getStartSemester(), $this->getEndSemesterVorlesEnde(), $this->id);
}
return $this->hasDatesOutOfDuration;
}
public function getStartWeek($metadate_id = false)
{
return $this->metadate->getStartWoche($metadate_id);
}
public function setStartWeek($week, $metadate_id = false)
{
if ($this->metadate->getStartWoche($metadate_id) == $week) {
return FALSE;
} else {
$this->metadate->setStartWoche($week, $metadate_id);
$key = $metadate_id ? $metadate_id : $this->metadate->getFirstMetadate()->metadate_id;
$this->createMessage(sprintf(_("Die Startwoche für den Termin %s wurde geändert."), $this->metadate->cycles[$key]->toString()));
$this->metadate->createSingleDates($key);
$this->metadate->cycles[$key]->termine = null;
NotificationCenter::postNotification("CourseDidChangeSchedule", $this);
}
}
/**
* instance method
*
* returns number of participants for each usergroup in seminar,
* total, lecturers, tutors, authors, users
*
* @param string (optional) return count only for given usergroup
*
* @return array <description>
*/
public function getNumberOfParticipants()
{
$args = func_get_args();
array_unshift($args, $this->id);
return call_user_func_array(["Seminar", "getNumberOfParticipantsBySeminarId"], $args);
}
/**
* class method
*
* returns number of participants for each usergroup in given seminar,
* total, lecturers, tutors, authors, users
*
* @param string seminar_id
*
* @param string (optional) return count only for given usergroup
*
* @return array <description>
*/
public function getNumberOfParticipantsBySeminarId($sem_id)
{
$db = DBManager::get();
$stmt1 = $db->prepare("SELECT
COUNT(Seminar_id) AS anzahl,
COUNT(IF(status='dozent',Seminar_id,NULL)) AS anz_dozent,
COUNT(IF(status='tutor',Seminar_id,NULL)) AS anz_tutor,
COUNT(IF(status='autor',Seminar_id,NULL)) AS anz_autor,
COUNT(IF(status='user',Seminar_id,NULL)) AS anz_user
FROM seminar_user
WHERE Seminar_id = ?
GROUP BY Seminar_id");
$stmt1->execute([$sem_id]);
$numbers = $stmt1->fetch(PDO::FETCH_ASSOC);
$stmt2 = $db->prepare("SELECT COUNT(*) as anzahl
FROM admission_seminar_user
WHERE seminar_id = ?
AND status = 'accepted'");
$stmt2->execute([$sem_id]);
$acceptedUsers = $stmt2->fetch(PDO::FETCH_ASSOC);
$count = 0;
if ($numbers["anzahl"]) {
$count += $numbers["anzahl"];
}
if ($acceptedUsers["anzahl"]) {
$count += $acceptedUsers["anzahl"];
}
$participant_count = [];
$participant_count['total'] = $count;
$participant_count['lecturers'] = $numbers['anz_dozent'] ? (int) $numbers['anz_dozent'] : 0;
$participant_count['tutors'] = $numbers['anz_tutor'] ? (int) $numbers['anz_tutor'] : 0;
$participant_count['authors'] = $numbers['anz_autor'] ? (int) $numbers['anz_autor'] : 0;
$participant_count['users'] = $numbers['anz_user'] ? (int) $numbers['anz_user'] : 0;
// return specific parameter if
$params = func_get_args();
if (sizeof($params) > 1) {
if (in_array($params[1], array_keys($participant_count))) {
return $participant_count[$params[1]];
} else {
trigger_error(get_class($this)."::__getParticipantInfos - unknown parameter requested");
}
}
return $participant_count;
}
/**
* Returns the IDs of this course's study areas.
*
* @return array an array of IDs
*/
public function getStudyAreas()
{
$stmt = DBManager::get()->prepare("SELECT DISTINCT sem_tree_id ".
"FROM seminar_sem_tree ".
"WHERE seminar_id=?");
$stmt->execute([$this->id]);
return $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
}
/**
* Sets the study areas of this course.
*
* @param array an array of IDs
*
* @return void
*/
public function setStudyAreas($selected)
{
$old = $this->getStudyAreas();
$sem_tree = TreeAbstract::GetInstance("StudipSemTree");
$removed = array_diff($old, $selected);
$added = array_diff($selected, $old);
$count_removed = 0;
$count_added = 0;
foreach($removed as $one){
$count_removed += $sem_tree->DeleteSemEntries($one, $this->getId());
}
foreach($added as $one){
$count_added += $sem_tree->InsertSemEntry($one, $this->getId());
}
if ($count_added || $count_removed) {
NotificationCenter::postNotification("CourseDidChangeStudyArea", $this);
}
return count($old) + $count_added - $count_removed;
}
/**
* @return boolean returns TRUE if this course is publicly visible,
* FALSE otherwise
*/
public function isPublic()
{
return Config::get()->ENABLE_FREE_ACCESS && $this->read_level == 0;
}
/**
* @return boolean returns TRUE if this course is a studygroup,
* FALSE otherwise
*/
public function isStudygroup()
{
global $SEM_CLASS, $SEM_TYPE;
return $SEM_CLASS[$SEM_TYPE[$this->status]["class"]]["studygroup_mode"];
}
/**
* @return int returns default colour group for new members (shown in meine_seminare.php)
*
**/
public function getDefaultGroup()
{
if ($this->isStudygroup()) {
return 8;
} else {
return select_group ($this->semester_start_time);
}
}
/**
* Deletes the current seminar
*
* @return void returns success-message if seminar could be deleted
* otherwise an error-message
*/
public function delete()
{
$s_id = $this->id;
// Delete that Seminar.
// Alle Benutzer aus dem Seminar rauswerfen.
$query = "DELETE FROM seminar_user WHERE Seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
if (($db_ar = $statement->rowCount()) > 0) {
$this->createMessage(sprintf(_("%s Teilnehmende und Lehrende archiviert."), $db_ar));
}
// Alle Benutzer aus Wartelisten rauswerfen
$query = "DELETE FROM admission_seminar_user WHERE seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
// Alle beteiligten Institute rauswerfen
$query = "DELETE FROM seminar_inst WHERE Seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
if (($db_ar = $statement->rowCount()) > 0) {
$this->createMessage(sprintf(_("%s Zuordnungen zu Einrichtungen archiviert."), $db_ar));
}
// user aus den Statusgruppen rauswerfen
$count = Statusgruppen::deleteBySQL('range_id = ?', [$s_id]);
if ($count > 0) {
$this->createMessage(sprintf(_('%s Funktionen/Gruppen gelöscht.'), $count));
}
// Alle Eintraege aus dem Vorlesungsverzeichnis rauswerfen
$sem_tree = TreeAbstract::GetInstance('StudipSemTree');
$db_ar = $sem_tree->DeleteSemEntries(null, $s_id);
if ($db_ar > 0) {
$this->createMessage(sprintf(_("%s Zuordnungen zu Bereichen archiviert."), $db_ar));
}
// Alle Termine mit allem was dranhaengt zu diesem Seminar loeschen.
if (($db_ar = SingleDateDB::deleteAllDates($s_id)) > 0) {
$this->createMessage(sprintf(_("%s Veranstaltungstermine archiviert."), $db_ar));
}
//Themen
IssueDB::deleteAllIssues($s_id);
//Cycles
SeminarCycleDate::deleteBySQL('seminar_id = ' . DBManager::get()->quote($s_id));
// Alle weiteren Postings zu diesem Seminar in den Forums-Modulen löschen
foreach (PluginEngine::getPlugins('ForumModule') as $plugin) {
$plugin->deleteContents($s_id); // delete content irrespective of plugin-activation in the seminar
if ($plugin->isActivated($s_id)) { // only show a message, if the plugin is activated, to not confuse the user
$this->createMessage(sprintf(_('Einträge in %s archiviert.'), $plugin->getPluginName()));
}
}
// Alle Pluginzuordnungen entfernen
PluginManager::getInstance()->deactivateAllPluginsForRange('sem', $s_id);
// Alle Dokumente zu diesem Seminar loeschen.
$folder = Folder::findTopFolder($s_id);
if($folder) {
if($folder->delete()) {
$this->createMessage(_("Dokumente und Ordner archiviert."));
}
}
// Freie Seite zu diesem Seminar löschen
$query = "DELETE FROM scm WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
if (($db_ar = $statement->rowCount()) > 0) {
$this->createMessage(_("Freie Seite der Veranstaltung archiviert."));
}
// Alle News-Verweise auf dieses Seminar löschen
if ( ($db_ar = StudipNews::DeleteNewsRanges($s_id)) ) {
$this->createMessage(sprintf(_("%s Ankündigungen gelöscht."), $db_ar));
}
//delete entry in news_rss_range
StudipNews::UnsetRssId($s_id);
//kill the datafields
DataFieldEntry::removeAll($s_id);
//kill all wiki-pages
$query = "DELETE FROM wiki WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
if (($db_wiki = $statement->rowCount()) > 0) {
$this->createMessage(sprintf(_("%s Wiki-Seiten archiviert."), $db_wiki));
}
$query = "DELETE FROM wiki_links WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
$query = "DELETE FROM wiki_locks WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
// remove wiki page config
WikiPageConfig::deleteBySQL('range_id = ?', [$s_id]);
// delete course config values
ConfigValue::deleteBySQL('range_id = ?', [$s_id]);
// kill all the ressources that are assigned to the Veranstaltung (and all the linked or subordinated stuff!)
if (Config::get()->RESOURCES_ENABLE) {
ResourceBooking::deleteBySql(
'range_id = :course_id',
[
'course_id' => $s_id
]
);
if ($rr = RoomRequest::existsByCourse($s_id)) {
RoomRequest::find($rr)->delete();
}
}
// kill virtual seminar-entries in calendar
$query = "DELETE FROM schedule_seminare WHERE seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
if(Config::get()->ELEARNING_INTERFACE_ENABLE){
global $connected_cms;
$del_cms = 0;
$cms_types = ObjectConnections::GetConnectedSystems($s_id);
if(count($cms_types)){
foreach($cms_types as $system){
ELearningUtils::loadClass($system);
$del_cms += $connected_cms[$system]->deleteConnectedModules($s_id);
}
$this->createMessage(sprintf(_("%s Verknüpfungen zu externen Systemen gelöscht."), $del_cms ));
}
}
//kill the object_user_vists for this seminar
object_kill_visits(null, $s_id);
// Logging...
$query = "SELECT CONCAT(seminare.VeranstaltungsNummer, ' ', seminare.name, '(', semester_data.name, ')')
FROM seminare
LEFT JOIN semester_data ON (seminare.start_time = semester_data.beginn)
WHERE seminare.Seminar_id='$s_id'";
$statement = DBManager::get()->prepare($query);
$statement->execute([$s_id]);
$semlogname = $statement->fetchColumn() ?: sprintf('unknown sem_id: %s', $s_id);
StudipLog::log("SEM_ARCHIVE",$s_id,NULL,$semlogname);
// ...logged
// delete deputies if necessary
Deputy::deleteByRange_id($s_id);
UserDomain::removeUserDomainsForSeminar($s_id);
AutoInsert::deleteSeminar($s_id);
//Anmeldeset Zordnung entfernen
$cs = $this->getCourseSet();
if ($cs) {
CourseSet::removeCourseFromSet($cs->getId(), $this->getId());
$cs->load();
if (!count($cs->getCourses())
&& $cs->isGlobal()
&& $cs->getUserid() != '') {
$cs->delete();
}
}
AdmissionPriority::unsetAllPrioritiesForCourse($this->getId());
// und das Seminar loeschen.
$this->course->delete();
$this->restore();
return true;
}
/**
* returns a html representation of the seminar-dates
*
* @param array optional variables which are passed to the template
* @return string the html-representation of the dates
*
* @author Till Glöggler <tgloeggl@uos.de>
*/
public function getDatesHTML($params = [])
{
return $this->getDatesTemplate('dates/seminar_html.php', $params);
}
/**
* returns a representation without html of the seminar-dates
*
* @param array optional variables which are passed to the template
* @return string the representation of the dates without html
*
* @author Till Glöggler <tgloeggl@uos.de>
*/
public function getDatesExport($params = [])
{
return $this->getDatesTemplate('dates/seminar_export.php', $params);
}
/**
* returns a xml-representation of the seminar-dates
*
* @param array optional variables which are passed to the template
* @return string the xml-representation of the dates
*
* @author Till Glöggler <tgloeggl@uos.de>
*/
public function getDatesXML($params = [])
{
return $this->getDatesTemplate('dates/seminar_xml.php', $params);
}
/**
* returns a representation of the seminar-dates with a specifiable template
*
* @param mixed this can be a template-object or a string pointing to a template in path_to_studip/templates
* @param array optional parameters which are passed to the template
* @return string the template output of the dates
*
* @author Till Glöggler <tgloeggl@uos.de>
*/
public function getDatesTemplate($template, $params = [])
{
if (!$template instanceof Flexi_Template && is_string($template)) {
$template = $GLOBALS['template_factory']->open($template);
}
if ($params['semester_id']) {
$semester = Semester::find($params['semester_id']);
if ($semester) {
// apply filter
$this->applyTimeFilter($semester->beginn, $semester->ende);
}
}
$template->dates = $this->getUndecoratedData(isset($params['semester_id']));
$template->seminar_id = $this->getId();
$template->set_attributes($params);
return trim($template->render());
}
/**
* returns an asscociative array with the attributes of the seminar depending
* on the field-names in the database
* @return array
*/
public function getData()
{
$data = $this->course->toArray();
foreach($this->alias as $a => $o) {
$data[$a] = $this->course->$o;
}
return $data;
}
/**
* returns an array with all IDs of Institutes this seminar is related to
* @param sem_id string: optional ID of a seminar, when null, this ID will be used
* @return: array of IDs (not associative)
*/
public function getInstitutes($sem_id = null)
{
if (!$sem_id && $this) {
$sem_id = $this->id;
}
$query = "SELECT institut_id FROM seminar_inst WHERE seminar_id = :sem_id
UNION
SELECT Institut_id FROM seminare WHERE Seminar_id = :sem_id";
$statement = DBManager::get()->prepare($query);
$statement->execute(compact('sem_id'));
return $statement->fetchAll(PDO::FETCH_COLUMN);
}
/**
* set the entries for seminar_inst table in database
* seminare.institut_id will always be added
* @param institutes array: array of Institut_id's
* @return bool: if something changed
*/
public function setInstitutes($institutes = [])
{
if (is_array($institutes)) {
$institutes[] = $this->institut_id;
$institutes = array_unique($institutes);
$query = "SELECT institut_id FROM seminar_inst WHERE seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$this->id]);
$old_inst = $statement->fetchAll(PDO::FETCH_COLUMN);
$todelete = array_diff($old_inst, $institutes);
$query = "DELETE FROM seminar_inst WHERE seminar_id = ? AND institut_id = ?";
$statement = DBManager::get()->prepare($query);
foreach($todelete as $inst) {
$tmp_instname= get_object_name($inst, 'inst');
StudipLog::log('CHANGE_INSTITUTE_DATA', $this->id, $inst, 'Die beteiligte Einrichtung "'. $tmp_instname['name'] .'" wurde gelöscht.');
$statement->execute([$this->id, $inst]);
NotificationCenter::postNotification('SeminarInstitutionDidDelete', $inst, $this->id);
}
$toinsert = array_diff($institutes, $old_inst);
$query = "INSERT INTO seminar_inst (seminar_id, institut_id) VALUES (?, ?)";
$statement = DBManager::get()->prepare($query);
foreach($toinsert as $inst) {
$tmp_instname= get_object_name($inst, 'inst');
StudipLog::log('CHANGE_INSTITUTE_DATA', $this->id, $inst, 'Die beteiligte Einrichtung "'. $tmp_instname['name'] .'" wurde hinzugefügt.');
$statement->execute([$this->id, $inst]);
NotificationCenter::postNotification('SeminarInstitutionDidCreate', $inst, $this->id);
}
if ($todelete || $toinsert) {
NotificationCenter::postNotification("CourseDidChangeInstitutes", $this);
}
return $todelete || $toinsert;
} else {
$this->createError(_("Ungültige Eingabe der Institute. Es muss " .
"mindestens ein Institut angegeben werden."));
return false;
}
}
/**
* adds a user to the seminar with the given status
* @param user_id string: ID of the user
* @param status string: status of the user for the seminar "user", "autor", "tutor", "dozent"
* @param force bool: if false (default) the user will only be upgraded and not degraded in his/her status
*/
public function addMember($user_id, $status = 'autor', $force = false)
{
if (in_array($GLOBALS['perm']->get_perm($user_id), ["admin", "root"])) {
$this->createError(_("Admin und Root dürfen nicht Mitglied einer Veranstaltung sein."));
return false;
}
$db = DBManager::get();
$rangordnung = array_flip(['user', 'autor', 'tutor', 'dozent']);
if ($rangordnung[$status] > $rangordnung['autor'] && SeminarCategories::getByTypeId($this->status)->only_inst_user) {
//überprüfe, ob im richtigen Institut:
$user_institute_stmt = $db->prepare(
"SELECT Institut_id " .
"FROM user_inst " .
"WHERE user_id = :user_id " .
"");
$user_institute_stmt->execute(['user_id' => $user_id]);
$user_institute = $user_institute_stmt->fetchAll(PDO::FETCH_COLUMN, 0);
if (!in_array($this->institut_id, $user_institute) && !count(array_intersect($user_institute, $this->getInstitutes()))) {
$this->createError(_("Einzutragender Nutzer stammt nicht einem beteiligten Institut an."));
return false;
}
}
if (!$force) {
$query = "SELECT status FROM seminar_user WHERE user_id = ? AND Seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$user_id, $this->id]);
$old_status = $statement->fetchColumn();
}
$query = "SELECT MAX(position) + 1 FROM seminar_user WHERE status = ? AND Seminar_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$status, $this->id]);
$new_position = $statement->fetchColumn();
$query = "SELECT COUNT(*) FROM seminar_user WHERE Seminar_id = ? AND status = 'dozent'";
$statement = DBManager::get()->prepare($query);
$statement->execute([$this->id]);
$numberOfTeachers = $statement->fetchColumn();
if (!$old_status) {
$query = "INSERT INTO seminar_user (Seminar_id, user_id, status, position, gruppe, visible, mkdate)
VALUES (?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP())";
$statement = DBManager::get()->prepare($query);
$statement->execute([
$this->id,
$user_id,
$status,
$new_position ?: 0,
(int)select_group($this->getSemesterStartTime()),
in_array($status, words('tutor dozent')) ? 'yes' : 'unknown',
]);
// delete the entries, user is now in the seminar
$stmt = DBManager::get()->prepare('DELETE FROM admission_seminar_user
WHERE user_id = ? AND seminar_id = ?');
$stmt->execute([$user_id, $this->getId()]);
if ($stmt->rowCount()) {
//renumber the waiting/accepted/lot list, a user was deleted from it
renumber_admission($this->getId());
}
$cs = $this->getCourseSet();
if ($cs) {
$prio_delete = AdmissionPriority::unsetPriority($cs->getId(), $user_id, $this->getId());
}
CalendarScheduleModel::deleteSeminarEntries($user_id, $this->getId());
NotificationCenter::postNotification("CourseDidGetMember", $this, $user_id);
NotificationCenter::postNotification('UserDidEnterCourse', $this->id, $user_id);
StudipLog::log('SEM_USER_ADD', $this->id, $user_id, $status, 'Wurde in die Veranstaltung eingetragen');
$this->course->resetRelation('members');
$this->course->resetRelation('admission_applicants');
// Check if we need to add user to parent course as well.
if ($this->parent_course) {
$parent = new Seminar($this->parent);
$parent->addMember($user_id, $status, $force);
}
return $this;
} elseif (($force || $rangordnung[$old_status] < $rangordnung[$status])
&& ($old_status !== "dozent" || $numberOfTeachers > 1)) {
$query = "UPDATE seminar_user
SET status = ?, visible = IFNULL(?, visible), position = ?
WHERE Seminar_id = ? AND user_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([
$status,
in_array($status, words('tutor dozent')) ? 'yes' : null,
$new_position,
$this->id,
$user_id,
]);
if ($old_status === 'dozent') {
$query = "SELECT termin_id FROM termine WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$this->id]);
$termine = $statement->fetchAll(PDO::FETCH_COLUMN);
$query = "DELETE FROM termin_related_persons WHERE range_id = ? AND user_id = ?";
$statement = DBManager::get()->prepare($query);
foreach ($termine as $termin_id) {
$statement->execute([$termin_id, $user_id]);
}
}
NotificationCenter::postNotification("CourseDidChangeMember", $this, $user_id);
$this->course->resetRelation('members');
$this->course->resetRelation('admission_applicants');
return $this;
} else {
if ($old_status === "dozent" && $numberOfTeachers <= 1) {
$this->createError(sprintf(_("Die Veranstaltung muss wenigstens <b>einen/eine</b> VeranstaltungsleiterIn (%s) eingetragen haben!"),
get_title_for_status('dozent', 1, $this->status)) .
' ' . _("Tragen Sie zunächst einen anderen ein, um diesen herabzustufen."));
}
return false;
}
}
/**
* deletes a user from the seminar by respecting the rule that at least one
* user with status "dozent" must stay there
* @param user_id string: user_id of the user to delete
* @param return: false or $this for chaining
*/
public function deleteMember($user_id)
{
$dozenten = $this->getMembers('dozent');
if (count($dozenten) >= 2 || !$dozenten[$user_id]) {
$query = "DELETE FROM seminar_user WHERE Seminar_id = ? AND user_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$this->id, $user_id]);
if ($statement->rowCount() === 0) {
return $this;
}
// If this course is a child of another course...
if ($this->parent_course) {
// ... check if user is member in another sibling ...
$other = CourseMember::countBySQL(
"`user_id` = :user AND `Seminar_id` IN (:courses) AND `Seminar_id` != :this",
['user' => $user_id, 'courses' => $this->parent->children->pluck('seminar_id'), 'this' => $this->id]
);
// ... and delete from parent course if this was the only
// course membership in this family.
if ($other == 0) {
$s = new Seminar($this->parent);
$s->deleteMember($user_id);
}
}
if ($this->children != null) {
foreach ($this->children as $child) {
$s = new Seminar($child);
$s->deleteMember($user_id);
}
}
if ($dozenten[$user_id]) {
$query = "SELECT termin_id FROM termine WHERE range_id = ?";
$statement = DBManager::get()->prepare($query);
$statement->execute([$this->id]);
$termine = $statement->fetchAll(PDO::FETCH_COLUMN);
$query = "DELETE FROM termin_related_persons WHERE range_id = ? AND user_id = ?";
$statement = DBManager::get()->prepare($query);
foreach ($termine as $termin_id) {
$statement->execute([$termin_id, $user_id]);
}
if (Deputy::isActivated()) {
$other_dozenten = array_diff(array_keys($dozenten), [$user_id]);
foreach (Deputy::findByRange_id($user_id) as $default_deputy) {
if ($default_deputy->user_id != $GLOBALS['user']->id &&
!Deputy::countBySql("range_id IN (?)", [$other_dozenten])) {
Deputy::deleteBySQL("range_id = ? AND user_id = ?", [$this->id, $default_deputy->user_id]);
}
}
}
}
// Delete course related datafield entries
DatafieldEntryModel::deleteBySQL('range_id = ? AND sec_range_id = ?', [$user_id, $this->id]);
// Remove from associated status groups
foreach (Statusgruppen::findBySeminar_id($this->id) as $group) {
$group->removeUser($user_id, true);
}
$this->createMessage(sprintf(
_('Nutzer %s wurde aus der Veranstaltung entfernt.'),
'<i>' . htmlReady(get_fullname($user_id)) . '</i>'
));
NotificationCenter::postNotification('CourseDidChangeMember', $this, $user_id);
NotificationCenter::postNotification('UserDidLeaveCourse', $this->id, $user_id);
StudipLog::log('SEM_USER_DEL', $this->id, $user_id, 'Wurde aus der Veranstaltung entfernt');
$this->course->resetRelation('members');
return $this;
} else {
$this->createError(
sprintf(
_('Die Veranstaltung muss wenigstens <b>einen/eine</b> VeranstaltungsleiterIn (%s) eingetragen haben!'),
get_title_for_status('dozent', 1, $this->status)
)
. ' ' . _('Tragen Sie zunächst einen anderen ein, um diesen zu löschen.')
);
return false;
}
}
/**
* sets the almost never used column position in the table seminar_user
* @param members array: array of user_id's - wrong IDs will be ignored
* @return $this
*/
public function setMemberPriority($members)
{
$query = "UPDATE seminar_user
SET position = ?
WHERE Seminar_id = ? AND user_id = ?";
$statement = DBManager::get()->prepare($query);
foreach(array_values($members) as $num => $member) {
$statement->execute([$num, $this->id, $member]);
}
return $this;
}
public function setLabel($user_id, $label) {
if ($GLOBALS['perm']->have_studip_perm('tutor', $this->getId(), $user_id)) {
$statement = DBManager::get()->prepare(
"UPDATE seminar_user " .
"SET label = :label " .
"WHERE user_id = :user_id " .
"AND Seminar_id = :seminar_id " .
"");
$statement->execute([
'user_id' => $user_id,
'seminar_id' => $this->getId(),
'label' => $label
]);
NotificationCenter::postNotification("CourseDidChangeMemberLabel", $this);
}
}
/**
* returns array with information about enrolment to this course for given user_id
* ['enrolment_allowed'] : true or false
* ['cause']: keyword to describe the cause
* ['description'] : readable description of the cause
*
* @param string $user_id
* @return array
*/
public function getEnrolmentInfo($user_id)
{
$info = [];
$user = User::find($user_id);
if ($this->getSemClass()->isGroup()) {
$info['enrolment_allowed'] = false;
$info['cause'] = 'grouped';
$info['description'] = _("Dies ist eine Veranstaltungsgruppe. Sie können sich nur in deren Unterveranstaltungen eintragen.");
return $info;
}
if ($this->read_level == 0 && Config::get()->ENABLE_FREE_ACCESS && !$GLOBALS['perm']->get_studip_perm($this->getId(), $user_id)) {
$info['enrolment_allowed'] = true;
$info['cause'] = 'free_access';
$info['description'] = _("Für die Veranstaltung ist keine Anmeldung erforderlich.");
return $info;
}
if (!$user) {
$info['enrolment_allowed'] = false;
$info['cause'] = 'nobody';
$info['description'] = _("Sie sind nicht in Stud.IP angemeldet.");
return $info;
}
if ($GLOBALS['perm']->have_perm('root', $user_id)) {
$info['enrolment_allowed'] = true;
$info['cause'] = 'root';
$info['description'] = _("Sie dürfen ALLES.");
return $info;
}
if ($GLOBALS['perm']->have_studip_perm('admin', $this->getId(), $user_id)) {
$info['enrolment_allowed'] = true;
$info['cause'] = 'courseadmin';
$info['description'] = _("Sie sind Administrator_in der Veranstaltung.");
return $info;
}
if ($GLOBALS['perm']->have_perm('admin', $user_id)) {
$info['enrolment_allowed'] = false;
$info['cause'] = 'admin';
$info['description'] = _("Als Administrator_in können Sie sich nicht für eine Veranstaltung anmelden.");
return $info;
}
//Ist bereits Teilnehmer
if ($GLOBALS['perm']->have_studip_perm('user', $this->getId(), $user_id)) {
$info['enrolment_allowed'] = true;
$info['cause'] = 'member';
$info['description'] = _("Sie sind für die Veranstaltung angemeldet.");
return $info;
}
$admission_status = $user->admission_applications->findBy('seminar_id', $this->getId())->val('status');
if ($admission_status == 'accepted') {
$info['enrolment_allowed'] = false;
$info['cause'] = 'accepted';
$info['description'] = _("Sie wurden für diese Veranstaltung vorläufig akzeptiert.");
return $info;
}
if ($admission_status == 'awaiting') {
$info['enrolment_allowed'] = false;
$info['cause'] = 'awaiting';
$info['description'] = _("Sie stehen auf der Warteliste für diese Veranstaltung.");
return $info;
}
if ($GLOBALS['perm']->get_perm($user_id) == 'user') {
$info['enrolment_allowed'] = false;
$info['cause'] = 'user';
$info['description'] = _("Sie haben nicht die erforderliche Berechtigung sich für eine Veranstaltung anzumelden.");
return $info;
}
//falsche Nutzerdomäne
$same_domain = true;
$user_domains = UserDomain::getUserDomainsForUser($user_id);
if (count($user_domains) > 0) {
$seminar_domains = UserDomain::getUserDomainsForSeminar($this->getId());
$same_domain = UserDomain::checkUserVisibility($seminar_domains, $user_domains);;
}
if (!$same_domain && !$this->isStudygroup()) {
$info['enrolment_allowed'] = false;
$info['cause'] = 'domain';
$info['description'] = _("Sie sind nicht in einer zugelassenenen Nutzerdomäne, Sie können sich nicht eintragen!");
return $info;
}
//Teilnehmerverwaltung mit Sperregel belegt
if (LockRules::Check($this->getId(), 'participants')) {
$info['enrolment_allowed'] = false;
$info['cause'] = 'locked';
$lockdata = LockRules::getObjectRule($this->getId());
$info['description'] = _("In diese Veranstaltung können Sie sich nicht eintragen!") . ($lockdata['description'] ? '<br>' . formatLinks($lockdata['description']) : '');
return $info;
}
//Veranstaltung unsichtbar für aktuellen Nutzer
if (!$this->visible && !$this->isStudygroup() && !$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM, $user_id)) {
$info['enrolment_allowed'] = false;
$info['cause'] = 'invisible';
$info['description'] = _("Die Veranstaltung ist gesperrt, Sie können sich nicht eintragen!");
return $info;
}
if ($courseset = $this->getCourseSet()) {
$info['enrolment_allowed'] = true;
$info['cause'] = 'courseset';
$info['description'] = _("Die Anmeldung zu dieser Veranstaltung folgt speziellen Regeln. Lesen Sie den Hinweistext.");
$user_prio = AdmissionPriority::getPrioritiesByUser($courseset->getId(), $user_id);
if (isset($user_prio[$this->getId()])) {
if ($courseset->hasAdmissionRule('LimitedAdmission')) {
$info['description'] .= ' ' . sprintf(_("(Sie stehen auf der Anmeldeliste für die automatische Platzverteilung mit der Priorität %s.)"), $user_prio[$this->getId()]);
} else {
$info['description'] .= ' ' . _("(Sie stehen auf der Anmeldeliste für die automatische Platzverteilung.)");
}
}
return $info;
}
$info['enrolment_allowed'] = true;
$info['cause'] = 'normal';
$info['description'] = '';
return $info;
}
/**
* adds user with given id as preliminary member to course
*
* @param string $user_id
* @return integer 1 if successfull
*/
public function addPreliminaryMember($user_id, $comment = '')
{
$new_admission_member = new AdmissionApplication();
$new_admission_member->user_id = $user_id;
$new_admission_member->position = 0;
$new_admission_member->status = 'accepted';
$new_admission_member->comment = $comment;
$this->course->admission_applicants[] = $new_admission_member;
$ok = $new_admission_member->store();
if ($ok && $this->isStudygroup()) {
StudygroupModel::applicationNotice($this->getId(), $user_id);
}
$cs = $this->getCourseSet();
if ($cs) {
$prio_delete = AdmissionPriority::unsetPriority($cs->getId(), $user_id, $this->getId());
}
// LOGGING
StudipLog::log('SEM_USER_ADD', $this->getId(), $user_id, 'accepted', 'Vorläufig akzeptiert');
return $ok;
}
/**
* returns courseset object for this course
*
* @return CourseSet courseset object or null
*/
public function getCourseSet()
{
if ($this->course_set === null) {
$this->course_set = CourseSet::getSetForCourse($this->id);
if ($this->course_set === null) {
$this->course_set = false;
}
}
return $this->course_set ?: null;
}
/**
* returns true if the number of participants of this course is limited
*
* @return boolean
*/
public function isAdmissionEnabled()
{
$cs = $this->getCourseSet();
return ($cs && $cs->isSeatDistributionEnabled());
}
/**
* returns the number of free seats in the course or true if not limited
*
* @return integer
*/
public function getFreeAdmissionSeats()
{
if ($this->isAdmissionEnabled()) {
return $this->course->getFreeSeats();
} else {
return true;
}
}
/**
* returns true if the course is locked
*
* @return boolean
*/
public function isAdmissionLocked()
{
$cs = $this->getCourseSet();
return ($cs && $cs->hasAdmissionRule('LockedAdmission'));
}
/**
* returns true if the course is password protected
*
* @return boolean
*/
public function isPasswordProtected()
{
$cs = $this->getCourseSet();
return ($cs && $cs->hasAdmissionRule('PasswordAdmission'));
}
/**
* returns array with start and endtime of course enrolment timeframe
* return null if there is no timeframe
*
* @return array assoc array with start_time end_time as keys timestamps as values
*/
public function getAdmissionTimeFrame()
{
$cs = $this->getCourseSet();
return ($cs && $cs->hasAdmissionRule('TimedAdmission')) ?
['start_time' => $cs->getAdmissionRule('TimedAdmission')->getStartTime(),
'end_time' => $cs->getAdmissionRule('TimedAdmission')->getEndTime()] : [];
}
/**
* returns StudipModule object for given slot, null when deactivated or not available
*
* @param string $slot
* @return StudipModule
*/
public function getSlotModule($slot)
{
$module = 'Core' . ucfirst($slot);
if ($this->course->isToolActive($module)) {
return PluginEngine::getPlugin($module);
}
}
/**
* adds user with given id on waitinglist
*
* @param string $user_id
* @param string $which_end 'last' or 'first'
* @return integer|bool number on waitlist or false if not successful
*/
public function addToWaitlist($user_id, $which_end = 'last')
{
if (AdmissionApplication::exists([$user_id, $this->id]) || CourseMember::find([$this->id, $user_id])) {
return false;
}
switch ($which_end) {
// Append users to waitlist end.
case 'last':
$maxpos = DBManager::get()->fetchColumn("SELECT MAX(`position`)
FROM `admission_seminar_user`
WHERE `seminar_id`=?
AND `status`='awaiting'", [$this->id]);
$waitpos = $maxpos+1;
break;
// Prepend users to waitlist start.
case 'first':
default:
// Move all others on the waitlist up by the number of people to add.
DBManager::get()->execute("UPDATE `admission_seminar_user`
SET `position`=`position`+1
WHERE `seminar_id`=?
AND `status`='awaiting'", [$this->id]);
$waitpos = 1;
}
$new_admission_member = new AdmissionApplication();
$new_admission_member->user_id = $user_id;
$new_admission_member->position = $waitpos;
$new_admission_member->status = 'awaiting';
$new_admission_member->seminar_id = $this->id;
if ($new_admission_member->store()) {
StudipLog::log('SEM_USER_ADD', $this->id, $user_id, 'awaiting', 'Auf Warteliste gesetzt, Position: ' . $waitpos);
$this->course->resetRelation('admission_applicants');
return $waitpos;
}
return false;
}
}