Skip to content
Snippets Groups Projects
Seminar.class.php 89.2 KiB
Newer Older
                    '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 />';
        $return = '';
        if ($stat['open'] > 0 && $stat['open'] !== $stat['all']) {
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
            $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.
        $db_ar = CourseMember::deleteBySQL('Seminar_id = ?', [$s_id]);
        if ($db_ar > 0) {
            $this->createMessage(sprintf(_("%s Teilnehmende und Lehrende archiviert."), $db_ar));
        }

        // Alle Benutzer aus Wartelisten rauswerfen
        AdmissionApplication::deleteBySQL('seminar_id = ?', [$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));
        }

        // seminar_sem_tree entries are deleted automatically on deletion of the Course object.

        // 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
        $db_ar = StudipScmEntry::deleteBySQL('range_id = ?', [$s_id]);
        if ($db_ar > 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
        $db_wiki = WikiPage::deleteBySQL('range_id = ?', [$s_id]);
        if ($db_wiki > 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 = ?";
        $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);
        }

Moritz Strohm's avatar
Moritz Strohm committed
        if (!empty($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;
            }
        }
        $course_member = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $this->id]);
        $new_position = (int) DBManager::get()->fetchColumn(
            "SELECT MAX(position) + 1 FROM seminar_user WHERE status = ? AND Seminar_id = ?",
            [$status, $this->id]
        );
        $numberOfTeachers = CourseMember::countBySql("Seminar_id = ? AND status = 'dozent'", [$this->id]);

        if (!$course_member && !$force) {
            CourseMember::create([
                'Seminar_id' => $this->id,
                'user_id'    => $user_id,
                'status'     => $status,
                'position'   => $new_position?:0,
                'gruppe'     => (int) select_group($this->getSemesterStartTime()),
                'visible'    => in_array($status, ['tutor', 'dozent']) ? 'yes' : 'unknown',
            ]);
            // delete the entries, user is now in the seminar
            if (AdmissionApplication::deleteBySQL('user_id = ? AND seminar_id = ?', [$user_id, $this->getId()])) {
                //renumber the waiting/accepted/lot list, a user was deleted from it
                AdmissionApplication::renumberAdmission($this->getId());
            }
            $cs = $this->getCourseSet();
            if ($cs) {
                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[$course_member->status] < $rangordnung[$status])
            && ($course_member->status !== 'dozent' || $numberOfTeachers > 1)
        ) {
            $visibility = $course_member->visible;
            if (in_array($status, ['tutor', 'dozent'])) {
                $visibility = 'yes';
            }
            $course_member->status = $status;
            $course_member->visible = $visibility;
            $course_member->position = $new_position;
            $course_member->store();

            if ($course_member->status === 'dozent') {
                $termine = DBManager::get()->fetchFirst(
                    "SELECT termin_id FROM termine WHERE range_id = ?",
                    [$this->id]
                );
                DBManager::get()->execute(
                    "DELETE FROM termin_related_persons WHERE range_id IN (?) AND user_id = ?",
                    [$termine, $user_id]
                );
            NotificationCenter::postNotification('CourseDidChangeMember', $this, $user_id);
            $this->course->resetRelation('members');
            $this->course->resetRelation('admission_applicants');
            return $this;
        } else {
            if ($course_member->status === 'dozent' && $numberOfTeachers <= 1) {
                $this->createError(sprintf(_('Die Person kann nicht herabgestuft werden, ' .
'da mindestens ein/eine Veranstaltungsleiter/-in (%s) in die Veranstaltung eingetragen sein muss!'),
                        get_title_for_status('dozent', 1, $this->status)) .
                    ' ' . sprintf(_('Tragen Sie zunächst eine weitere Person als Veranstaltungsleiter/-in (%s) ein.'),
get_title_for_status('dozent', 1, $this->status)));
    /**
     * Cancels a subscription to an admission.
     *
     * @param array $users
     * @param string $status
     * @return array
     * @throws NotificationVetoException
     */
    public function cancelAdmissionSubscription(array $users, string $status): array
    {
        $msgs = [];
        $messaging = new messaging;
        $course_set = $this->getCourseSet();
        $users = User::findMany($users);
        foreach ($users as $user) {
            $prio_delete = false;
            if ($course_set) {
                $prio_delete = AdmissionPriority::unsetPriority($course_set->getId(), $user->id, $this->getId());
            }
            $result = AdmissionApplication::deleteBySQL(
                'seminar_id = ? AND user_id = ? AND status = ?',
                [$this->getId(), $user->id, $status]
            );
            if ($result || $prio_delete) {
                setTempLanguage($user->id);
                if ($status !== 'accepted') {
                    $message = sprintf(
                        _('Sie wurden von der Warteliste der Veranstaltung **%s** gestrichen und sind damit __nicht__ zugelassen worden.'),
                        $this->getFullName()
                    );
                } else {
                    $message = sprintf(
                        _('Sie wurden aus der Veranstaltung **%s** gestrichen und sind damit __nicht__ zugelassen worden.'),
                        $this->getFullName()
                    );
                }
                restoreLanguage();
                $messaging->insert_message(
                    $message,