Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alexander.vorwerk/studip
  • hochschule-wismar/stud-ip
  • tleilax/studip
  • marcus/studip
  • manschwa/studip
  • eberhardt/studip
  • uol/studip
  • pluta/studip
  • thienel/extern-uni-b
  • studip/studip
  • strohm/studip
  • uni-osnabrueck/studip
  • FloB/studip
  • universit-t-rostock/studip
  • Robinyyy/studip
  • jakob.diel/studip
  • HyperSpeeed/studip
  • ann/studip
  • nod3zer0/stud-ip-siple-saml-php-plugin
19 results
Show changes
Showing
with 1424 additions and 1137 deletions
<?php
final class CaptchaController extends StudipController
{
public function challenge_action(): void
{
$this->response->add_header(
'Expires',
gmdate('D, d M Y H:i:s', time() + CaptchaChallenge::CHALLENGE_EXPIRATION) . ' GMT'
);
$this->render_json(CaptchaChallenge::createNewChallenge());
}
}
......@@ -27,7 +27,7 @@ class Consultation_AdminController extends ConsultationController
$this->activateNavigation('admin');
if (Context::isCourse() || Context::isInstitute()) {
PageLayout::setTitle(Context::get()->getFullname() . ' - ' . _('Verwaltung der Termine'));
PageLayout::setTitle(Context::get()->getFullName() . ' - ' . _('Verwaltung der Termine'));
} else {
PageLayout::setTitle(_('Verwaltung der Termine'));
}
......@@ -69,10 +69,10 @@ class Consultation_AdminController extends ConsultationController
public function index_action($page = 0)
{
$this->count = ConsultationSlot::countByRange($this->range);
$this->limit = Config::get()->ENTRIES_PER_PAGE;
$count = ConsultationSlot::countByRange($this->range);
$limit = Config::get()->ENTRIES_PER_PAGE;
if ($page >= ceil($this->count / $this->limit)) {
if ($page >= ceil($count / $limit)) {
$page = 0;
}
......@@ -81,7 +81,7 @@ class Consultation_AdminController extends ConsultationController
if ($GLOBALS['user']->cfg->CONSULTATION_SHOW_GROUPED) {
$this->blocks = $this->groupSlots(ConsultationSlot::findByRange(
$this->range,
"ORDER BY start ASC LIMIT " . ($this->page * $this->limit) . ", {$this->limit}"
"ORDER BY start ASC LIMIT " . ($this->page * $limit) . ", {$limit}"
));
} else {
$this->blocks = ConsultationBlock::findByRange(
......@@ -90,20 +90,22 @@ class Consultation_AdminController extends ConsultationController
);
$this->slots = ConsultationSlot::findByRange(
$this->range,
"ORDER BY start ASC LIMIT " . ($this->page * $this->limit) . ", {$this->limit}"
"ORDER BY start ASC LIMIT " . ($this->page * $limit) . ", {$limit}"
);
}
$this->pagination = Pagination::create($count, $this->page, $limit);
$action = $GLOBALS['user']->cfg->CONSULTATION_SHOW_GROUPED ? 'index' : 'ungrouped';
$this->render_action($action);
}
public function expired_action($page = 0)
{
$this->count = ConsultationSlot::countByRange($this->range, true);
$this->limit = Config::get()->ENTRIES_PER_PAGE;
$count = ConsultationSlot::countByRange($this->range, true);
$limit = Config::get()->ENTRIES_PER_PAGE;
if ($page >= ceil($this->count / $this->limit)) {
if ($page >= ceil($count / $limit)) {
$page = 0;
}
......@@ -112,7 +114,7 @@ class Consultation_AdminController extends ConsultationController
if ($GLOBALS['user']->cfg->CONSULTATION_SHOW_GROUPED) {
$this->blocks = $this->groupSlots(ConsultationSlot::findByRange(
$this->range,
"ORDER BY start DESC LIMIT " . ($this->page * $this->limit) . ", {$this->limit}",
"ORDER BY start DESC LIMIT " . ($this->page * $limit) . ", {$limit}",
true
));
} else {
......@@ -123,11 +125,13 @@ class Consultation_AdminController extends ConsultationController
);
$this->slots = ConsultationSlot::findByRange(
$this->range,
"ORDER BY start DESC LIMIT " . ($this->page * $this->limit) . ", {$this->limit}",
"ORDER BY start DESC LIMIT " . ($this->page * $limit) . ", {$limit}",
true
);
}
$this->pagination = Pagination::create($count, $this->page, $limit);
$action = $GLOBALS['user']->cfg->CONSULTATION_SHOW_GROUPED ? 'index' : 'ungrouped';
$this->render_action($action);
}
......@@ -136,25 +140,56 @@ class Consultation_AdminController extends ConsultationController
{
PageLayout::setTitle(_('Neue Terminblöcke anlegen'));
$this->room = '';
$this->responsible = false;
$room = '';
$responsible = false;
// TODO: inst_default?
if ($this->range instanceof User) {
$rooms = $this->range->institute_memberships->pluck('Raum');
$rooms = array_filter($rooms);
$this->room = $rooms ? reset($rooms) : '';
$room = $rooms ? reset($rooms) : '';
} elseif ($this->range instanceof Course) {
$this->room = $this->range->ort;
$room = $this->range->ort;
$block = new ConsultationBlock();
$block->range = $this->range;
$this->responsible = $block->getPossibleResponsibilites();
$responsible = $block->getPossibleResponsibilites();
} elseif ($this->range instanceof Institute) {
$block = new ConsultationBlock();
$block->range = $this->range;
$this->responsible = $block->getPossibleResponsibilites();
$responsible = $block->getPossibleResponsibilites();
}
$convertResponsibilities = function ($input) {
if ($input === false) {
return false;
}
foreach ($input as $key => $values) {
$input[$key] = array_map(
fn($item) => [
'id' => $item->id,
'label' => $item instanceof Statusgruppen ? $item->getName() : $item->getFullName(),
],
$values
);
}
return $input;
};
$this->render_vue_app(
Studip\VueApp::create('ConsultationCreator')
->withProps([
'as-dialog' => Request::isXhr(),
'cancel-url' => $this->indexURL(),
'default-room' => $room,
'range-type' => get_class($this->range),
'slot-count-threshold' => self::SLOT_COUNT_THRESHOLD,
'store-url' => $this->storeURL(),
'with-responsible' => $convertResponsibilities($responsible),
])
);
}
public function store_action()
......@@ -162,18 +197,29 @@ class Consultation_AdminController extends ConsultationController
CSRFProtection::verifyUnsafeRequest();
try {
$interval = Request::int('interval');
$start = $this->getDateAndTime('start');
$end = $this->getDateAndTime('end');
$end = $this->getDateAndTime($interval <= 0 ? 'start' : 'end', 'end');
if (date('Hi', $end) <= date('Hi', $start)) {
throw new InvalidArgumentException(_('Die Endzeit liegt vor der Startzeit!'));
}
$dow = Request::int('day-of-week');
if ($interval <= 0) {
$dow = date('w', $start);
}
// Determine duration of a slot and pause times
$duration = Request::int('duration');
if ($duration === null && $interval === -1) {
$duration = (int) (($end - $start) / 60);
}
$pause_time = Request::bool('pause') ? Request::int('pause_time') : null;
$pause_duration = Request::bool('pause') ? Request::int('pause_duration') : null;
if ($pause_time && $pause_time < $duration) {
if ($interval >= 0 && $pause_time && $pause_time < $duration) {
throw new InvalidArgumentException(_('Die definierte Zeit bis zur Pause ist kleiner als die Dauer eines Termins.'));
}
......@@ -184,12 +230,13 @@ class Consultation_AdminController extends ConsultationController
$slot_count = ConsultationBlock::countSlots(
$start,
$end,
Request::int('day-of-week'),
Request::int('interval'),
Request::int('duration'),
$dow,
$interval,
$duration,
$pause_time,
$pause_duration
);
if ($slot_count >= self::SLOT_COUNT_THRESHOLD && !Request::int('confirmed')) {
$this->flash['confirm-many'] = $slot_count;
throw new Exception('', -1);
......@@ -199,8 +246,8 @@ class Consultation_AdminController extends ConsultationController
$this->range,
$start,
$end,
Request::int('day-of-week'),
Request::int('interval')
$dow,
$interval
);
$stored = 0;
......@@ -214,8 +261,9 @@ class Consultation_AdminController extends ConsultationController
$block->note = Request::get('note');
$block->size = Request::int('size', 1);
$block->lock_time = Request::int('lock_time');
$block->consecutive = Request::bool('consecutive', false);
$slots = $block->createSlots(Request::int('duration'), $pause_time, $pause_duration);
$slots = $block->createSlots($duration, $pause_time, $pause_duration);
if (count($slots) === 0) {
continue;
}
......@@ -356,24 +404,27 @@ class Consultation_AdminController extends ConsultationController
'sem_perm' => $permissions,
]);
}
}
if (Request::isPost()) {
CSRFProtection::verifyUnsafeRequest();
public function store_booking_action($block_id, $slot_id, $page = 0): void
{
CSRFProtection::verifyUnsafeRequest();
if ($this->slot->isOccupied()) {
PageLayout::postError(_('Dieser Termin ist bereits belegt.'));
} else {
$booking = new ConsultationBooking();
$booking->slot_id = $this->slot->id;
$booking->user_id = Request::option('user_id');
$booking->reason = trim(Request::get('reason'));
$booking->store();
$slot = $this->loadSlot($block_id, $slot_id);
PageLayout::postSuccess(_('Der Termin wurde reserviert.'));
}
if ($slot->isOccupied()) {
PageLayout::postError(_('Dieser Termin ist bereits belegt.'));
} else {
$booking = new ConsultationBooking();
$booking->slot_id = $slot->id;
$booking->user_id = Request::option('user_id');
$booking->reason = trim(Request::get('reason'));
$booking->store();
$this->redirect("consultation/admin/index/{$page}#slot-{$this->slot->id}");
PageLayout::postSuccess(_('Der Termin wurde reserviert.'));
}
$this->redirect("consultation/admin/index/{$page}#slot-{$slot->id}");
}
public function edit_action($block_id, $page = 0)
......@@ -403,6 +454,7 @@ class Consultation_AdminController extends ConsultationController
$this->block->mail_to_tutors = Request::bool('mail-to-tutors', false);
$this->block->confirmation_text = trim(Request::get('confirmation-text'));
$this->block->lock_time = Request::int('lock_time');
$this->block->consecutive = Request::bool('consecutive', false);
foreach ($this->block->slots as $slot) {
$slot->note = '';
......@@ -535,7 +587,7 @@ class Consultation_AdminController extends ConsultationController
public function toggle_action($what, $state, $expired = false)
{
if ($what === 'messages') {
// TODO: Applicable everywhere?
// TODO: Applicable everywhere?
$this->getUserConfig()->store(
'CONSULTATION_SEND_MESSAGES',
(bool) $state
......@@ -738,7 +790,7 @@ class Consultation_AdminController extends ConsultationController
// Redirect to message write
$_SESSION['sms_data'] = compact('p_rec');
page_close();
sess()->save();
$this->redirect(URLHelper::getURL(
'dispatch.php/messages/write',
compact('default_subject')
......@@ -808,7 +860,7 @@ class Consultation_AdminController extends ConsultationController
_('Terminblöcke anlegen'),
$this->createURL(),
Icon::create('add')
)->asDialog('size=auto');
)->asDialog('size=big');
$actions->addLink(
_('Namen des Reiters ändern'),
$this->tabURL($action === 'expired'),
......@@ -867,16 +919,34 @@ class Consultation_AdminController extends ConsultationController
}
}
private function getDateAndTime($index)
private function getDateAndTime(string $index, string $index_time = null)
{
if (!Request::submitted("{$index}-date") || !Request::submitted("{$index}-time")) {
if ($index_time === null) {
$index_time = $index;
}
if (!Request::submitted("{$index}-date") || !Request::submitted("{$index_time}-time")) {
throw new Exception("Date with index '{$index}' was not submitted properly");
}
return strtotime(implode(' ', [
Request::get("{$index}-date"),
Request::get("{$index}-time")
]));
$date = Datetime::createFromFormat(
DateTimeInterface::RFC3339_EXTENDED,
Request::get("{$index}-date")
);
if (!$date) {
throw new Exception("Date with index '{$index}' could not be parsed");
}
$date->setTimezone(new DateTimeZone(date_default_timezone_get()));
$date->setTime(
...array_map(
intval(...),
explode(':', Request::get("{$index_time}-time"))
)
);
return $date->getTimestamp();
}
private function getUserConfig(): RangeConfig
......
......@@ -19,7 +19,7 @@ abstract class ConsultationController extends AuthenticatedController
$this->range = Context::get();
$type = 'object';
} else {
$this->range = $GLOBALS['user']->getAuthenticatedUser();
$this->range = User::findCurrent();
}
if (!$this->range) {
......@@ -60,7 +60,7 @@ abstract class ConsultationController extends AuthenticatedController
$this->render_template('consultation/not_found', $this->layout);
}
protected function activateNavigation($path)
protected function activateNavigation($path): void
{
$path = ltrim($path, '/');
......@@ -73,7 +73,7 @@ abstract class ConsultationController extends AuthenticatedController
}
}
protected function getConsultationTitle()
protected function getConsultationTitle(): string
{
return $this->range->getConfiguration()->CONSULTATION_TAB_TITLE;
}
......@@ -103,7 +103,8 @@ abstract class ConsultationController extends AuthenticatedController
return $block;
}
protected function loadSlot($block_id, $slot_id)
protected function loadSlot($block_id, $slot_id): ConsultationSlot
{
$block = $this->loadBlock($block_id);
$slot = $block->slots->find($slot_id);
......@@ -115,7 +116,7 @@ abstract class ConsultationController extends AuthenticatedController
return $slot;
}
protected function loadBooking($block_id, $slot_id, $booking_id)
protected function loadBooking($block_id, $slot_id, $booking_id): ConsultationBooking
{
$slot = $this->loadSlot($block_id, $slot_id);
$booking = $slot->bookings->find($booking_id);
......
......@@ -71,6 +71,8 @@ class Consultation_OverviewController extends ConsultationController
if ($this->slot->isOccupied()) {
PageLayout::postError(_('Dieser Termin ist bereits belegt.'));
} elseif (!$this->slot->isBookable()) {
PageLayout::postError(_('Dieser Termin ist für Buchungen gesperrt.'));
} else {
$booking = new ConsultationBooking();
$booking->slot_id = $this->slot->id;
......
......@@ -145,7 +145,7 @@ class ContactController extends AuthenticatedController
$contact = Contact::find([User::findCurrent()->id, User::findByUsername(Request::username('user'))->id]);
if ($contact) {
if ($group) {
$contact->group_assignments->unsetBy('group_id', $group);
$contact->groups->unsetBy('group_id', $group);
if ($contact->store()) {
PageLayout::postSuccess(_('Der Kontakt wurde aus der Gruppe entfernt.'));
}
......@@ -166,7 +166,7 @@ class ContactController extends AuthenticatedController
$this->group->owner_id = User::findCurrent()->id;
}
if (Request::submitted('store')) {
CSRFProtection::verifyRequest();
CSRFProtection::verifyUnsafeRequest();
$this->group->name = Request::get('name');
$this->group->store();
$this->redirect('contact/index/' . $this->group->id);
......@@ -175,7 +175,7 @@ class ContactController extends AuthenticatedController
public function deleteGroup_action()
{
CSRFProtection::verifyRequest();
CSRFProtection::verifyUnsafeRequest();
$this->group->delete();
$this->redirect('contact/index');
}
......@@ -185,21 +185,34 @@ class ContactController extends AuthenticatedController
$charset = 'utf-8';
$filename = _('Kontakte');
$this->set_layout(null);
$users = [];
if (Request::submitted('user')) {
$user = User::findManyByUsername(Request::getArray('user'));
$users = User::findManyByUsername(Request::getArray('user'));
}
if ($group) {
$user = User::findMany(Statusgruppen::find($group)->members->pluck('user_id'));
$group_object = Statusgruppen::find($group);
if (!$group_object) {
$this->set_status(404);
$this->render_nothing();
return;
}
$users = User::findMany($group_object->members->pluck('user_id'));
}
if (!$user) {
$user = User::findCurrent()->contacts;
if (empty($users)) {
$user_object = User::findCurrent();
if (!$user_object) {
$this->set_status(404);
$this->render_nothing();
return;
}
$users = User::findCurrent()->contacts;
}
header("Content-type: text/x-vCard;charset=" . $charset);
header("Content-disposition: attachment; " . encode_header_parameter('filename', $filename . '.vcf'));
header("Pragma: private");
$this->vCard = vCard::export($user);
$this->vCard = vCard::export($users);
}
private function initSidebar($active_id = null)
......
......@@ -120,6 +120,14 @@ class Contents_CoursewareController extends CoursewareController
$this->user_id = $GLOBALS['user']->id;
}
public function pdf_export_action(Courseware\StructuralElement $element, bool $with_children = false): void
{
$this->render_pdf(
$element->pdfExport(User::findCurrent(), $with_children),
trim($element->title) . '.pdf'
);
}
private function setBookmarkSidebar(): void
{
$sidebar = Sidebar::Get();
......@@ -199,127 +207,77 @@ class Contents_CoursewareController extends CoursewareController
$courses = new SimpleCollection($courses);
if (!Config::get()->MY_COURSES_ENABLE_STUDYGROUPS) {
$courses = $courses->filter(function ($a) {
return !$a->isStudygroup();
$courses = $courses->filter(function (Course $course) {
return !$course->isStudygroup();
});
}
if ($sem_key != 'all') {
// Filter courses with enabled and visible courseware
$courses = $courses->filter(function (Course $course) {
return $this->isCoursewareEnabledAndVisible($course);
});
if ($sem_key !== 'all') {
$semester = Semester::find($sem_key);
$courses = $courses->filter(function ($a) use ($semester) {
if ($a->isInSemester($semester)) {
return true;
}
return false;
$courses = $courses->filter(function (Course $course) use ($semester) {
return $course->isInSemester($semester);
});
$coursewares = [];
foreach ($courses as $course) {
$element = StructuralElement::getCoursewareCourse($course->id);
if (!empty($element) && $this->isCoursewareEnabled($course->id)) {
$element['payload'] = json_decode($element['payload'], true);
$coursewares[] = $element;
}
$sem_courses = [];
foreach ($courses as $course) {
$units = Unit::findCoursesUnits($course);
foreach ($units as $unit) {
$element = $unit->structural_element;
if (!$element || !$element->canRead(User::findCurrent())) {
continue;
}
}
if (empty($coursewares)) {
return [];
}
$element['payload'] = json_decode($element['payload'], true);
return [$semester->id => [
'semester_name' => $semester->name,
'coursewares' => $coursewares
]];
} else {
$all_semesters = Semester::getAll();
$sem_courses = [];
foreach ($courses as $course) {
$element = StructuralElement::getCoursewareCourse($course->id);
if (!empty($element) && $this->isCoursewareEnabled($course->id)) {
$element['payload'] = json_decode($element['payload'], true);
if ($course->duration_time == -1) {
$sem_courses[$this->current_semester->id]['coursewares'][] = $element;
} else {
$end_semester = $course->getEndSemester();
$sem_courses[$end_semester->id]['coursewares'][] = $element;
}
if ($course->isOpenEnded()) {
$sem_courses[$this->current_semester->id]['coursewares'][] = $element;
} else {
$end_semester = $course->getEndSemester();
$sem_courses[$end_semester->id]['coursewares'][] = $element;
}
}
return $sem_courses;
}
return $sem_courses;
}
/**
* Returns true if the courseware module is enabled for the passed course
* Returns true if the courseware module is enabled and visible for the
* passed course and current user
*
* @param string $course_id the course to check
* @return boolean true if courseware is enabled, false otherwise
* @param Course $course the course to check
* @return boolean true if courseware is enabled and visible,
* false otherwise
*/
private function isCoursewareEnabled($course_id): bool
private function isCoursewareEnabledAndVisible(Course $course): bool
{
$studip_module = PluginManager::getInstance()->getPlugin('CoursewareModule');
if (!$studip_module || !$studip_module->isActivated($course_id)) {
// Check if courseware is globally enabled
$studip_module = PluginManager::getInstance()->getPlugin(CoursewareModule::class);
if (!$studip_module) {
return false;
}
return true;
}
private function getProjects($purpose): array
{
$elements = StructuralElement::findProjects($this->user->id, $purpose);
foreach($elements as &$element) {
$element['payload'] = json_decode($element['payload'], true);
// Check if courseware is enabled in course
$active_tool = ToolActivation::find([
$course->id,
$studip_module->getPluginId(),
]);
if (!$active_tool) {
return false;
}
return $elements;
}
public function pdf_export_action($element_id, $with_children): void
{
$element = \Courseware\StructuralElement::findOneById($element_id);
$this->render_pdf($element->pdfExport($this->user, $with_children), trim($element->title).'.pdf');
}
/**
* To display the shared courseware
*
* @param string $entry_element_id the shared struct element id
*/
public function shared_content_courseware_action($entry_element_id): void
{
global $user;
$navigation = new Navigation(_('Geteiltes Lernmaterial'), 'dispatch.php/contents/courseware/shared_content_courseware/' . $entry_element_id);
Navigation::addItem('/contents/courseware/shared_content_courseware', $navigation);
Navigation::activateItem('/contents/courseware/shared_content_courseware');
$this->entry_element_id = $entry_element_id;
$struct = \Courseware\StructuralElement::findOneBySQL(
"id = ? AND range_type = 'user'",
[$this->entry_element_id]
// Check visibility
return $GLOBALS['perm']->have_studip_perm(
$active_tool->getVisibilityPermission(),
$course->id,
User::findCurrent()->id
);
if (!$struct) {
throw new Trails_Exception(404, _('Der geteilte Inhalt kann nicht gefunden werden.'));
}
if (!$struct->canRead($user) && !$struct->canEdit($user)) {
throw new AccessDeniedException();
}
$this->user_id = $struct->owner_id;
$this->setCoursewareSidebar();
}
}
......@@ -31,13 +31,13 @@ class Course_AdmissionController extends AuthenticatedController
if (!get_object_type($this->course_id, ['sem']) ||
SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode ||
!$GLOBALS['perm']->have_studip_perm('tutor', $this->course_id)) {
throw new Trails_Exception(403);
throw new Trails\Exception(403);
}
$this->course = Course::find($this->course_id);
$this->user_id = $GLOBALS['user']->id;
PageLayout::setHelpKeyword("Basis.VeranstaltungenVerwaltenZugangsberechtigungen");
PageLayout::setTitle($this->course->getFullname()." - " ._("Verwaltung von Zugangsberechtigungen"));
PageLayout::setTitle($this->course->getFullName()." - " ._("Verwaltung von Zugangsberechtigungen"));
$lockrules = words('admission_turnout admission_type admission_endtime admission_binding passwort read_level write_level admission_prelim admission_prelim_txt admission_starttime admission_endtime_sem admission_disable_waitlist user_domain admission_binding admission_studiengang');
$this->is_locked = [];
......@@ -48,7 +48,6 @@ class Course_AdmissionController extends AuthenticatedController
$this->is_locked['write_level'] = 'disabled readonly';
}
AdmissionApplication::addMembers($this->course->id);
PageLayout::addScript('studip-admission.js');
URLHelper::addLinkParam('return_to_dialog', Request::get('return_to_dialog'));
}
......@@ -138,14 +137,18 @@ class Course_AdmissionController extends AuthenticatedController
if (Request::submittedSome('change_admission_prelim_no', 'change_admission_prelim_yes') || !$question) {
if ($this->course->admission_prelim == 1 && $this->course->getNumParticipants() && Request::submitted('change_admission_prelim_yes')) {
$num_moved = 0;
$seminar = new Seminar($this->course_id);
foreach ($this->course->members->findBy('status', ['user','autor'])->pluck('user_id') as $user_id) {
$seminar->addPreliminaryMember($user_id);
$num_moved += ($seminar->deleteMember($user_id) !== false);
setTempLanguage($user_id);
foreach ($this->course->members->findBy('status', ['user','autor'])->pluck('user') as $user) {
$this->course->addPreliminaryMember($user);
try {
$this->course->deleteMember($user);
} catch (\Studip\Exception $e) {
continue;
}
$num_moved++;
setTempLanguage($user->id);
$message_body = sprintf(_('Sie wurden in der Veranstaltung **%s** in den Status **vorläufig akzeptiert** befördert, da das Anmeldeverfahren geändert wurde.'), $this->course->name);
$message_title = sprintf(_("Statusänderung %s"), $this->course->name);
messaging::sendSystemMessage($user_id, $message_title, $message_body);
messaging::sendSystemMessage($user->id, $message_title, $message_body);
restoreLanguage();
}
if ($num_moved) {
......@@ -158,13 +161,17 @@ class Course_AdmissionController extends AuthenticatedController
if ($this->course->admission_prelim == 0 && $this->course->getNumPrelimParticipants()) {
if (Request::submitted('change_admission_prelim_yes')) {
$num_moved = 0;
$seminar = new Seminar($this->course_id);
foreach ($this->course->admission_applicants->findBy('status', 'accepted')->pluck('user_id') as $user_id) {
$num_moved += ($seminar->addMember($user_id, 'autor') !== false);
setTempLanguage($user_id);
foreach ($this->course->admission_applicants->findBy('status', 'accepted')->pluck('user') as $user) {
try {
$this->course->addMember($user, 'autor');
} catch (\Studip\Exception $e) {
continue;
}
$num_moved++;
setTempLanguage($user->id);
$message_body = sprintf(_('Sie wurden in der Veranstaltung **%s** in den Status **Autor** versetzt, da das Anmeldeverfahren geändert wurde.'), $this->course->name);
$message_title = sprintf(_("Statusänderung %s"), $this->course->name);
messaging::sendSystemMessage($user_id, $message_title, $message_body);
messaging::sendSystemMessage($user, $message_title, $message_body);
restoreLanguage();
}
if ($num_moved) {
......@@ -200,7 +207,7 @@ class Course_AdmissionController extends AuthenticatedController
}
}
if (empty($question)) {
$this->redirect($this->action_url('index'));
$this->relocate($this->action_url('index'));
} else {
$this->button_yes = 'change_admission_prelim_yes';
$this->button_no = 'change_admission_prelim_no';
......@@ -241,7 +248,7 @@ class Course_AdmissionController extends AuthenticatedController
PageLayout::postSuccess(_("Zugriff für externe Nutzer wurde geändert."));
}
}
$this->redirect($this->action_url('index'));
$this->relocate($this->action_url('index'));
}
function change_admission_turnout_action()
......@@ -305,10 +312,11 @@ class Course_AdmissionController extends AuthenticatedController
}
}
if (empty($question)) {
$this->redirect($this->action_url('index'));
$this->relocate($this->action_url('index'));
} else {
$this->request = $request;
$this->button_yes = 'change_admission_turnout_yes';
$this->button_no = 'change_admission_turnout_no';
PageLayout::postInfo($question);
$this->render_template('course/admission/_change_admission.php');
}
......@@ -329,7 +337,7 @@ class Course_AdmissionController extends AuthenticatedController
PageLayout::postSuccess(_('Die zugelassenen Nutzerdomänen wurden geändert.'));
}
}
$this->redirect($this->action_url('index'));
$this->relocate($this->action_url('index'));
}
function change_course_set_action()
......@@ -393,10 +401,11 @@ class Course_AdmissionController extends AuthenticatedController
}
}
if (empty($question)) {
$this->redirect($this->action_url('index'));
$this->relocate($this->action_url('index'));
} else {
$this->request = ['change_course_set_unassign' => 1];
$this->button_yes = 'change_course_set_unassign_yes';
$this->button_no = 'change_course_set_unassign_no';
PageLayout::postInfo($question);
$this->render_template('course/admission/_change_admission.php');
}
......@@ -427,68 +436,42 @@ class Course_AdmissionController extends AuthenticatedController
$rule_types = AdmissionRule::getAvailableAdmissionRules(true);
if (isset($rule_types[$type])) {
$rule = new $type($rule_id);
$another_rule = null;
if (isset($rule_types[$another_type])) {
$another_rule = new $another_type($another_rule_id);
}
$course_set = CourseSet::getSetForRule($rule_id) ?: new CourseSet();
if ((Request::isPost() && Request::submitted('save')) || $rule instanceof LockedAdmission) {
if ($rule instanceof LockedAdmission) {
$course_set_id = CourseSet::getGlobalLockedAdmissionSetId();
CourseSet::addCourseToSet($course_set_id, $this->course_id);
PageLayout::postSuccess(_('Die Veranstaltung wurde gesperrt.'));
$this->redirect($this->action_url('index'));
return;
} else {
CSRFProtection::verifyUnsafeRequest();
$errors = $rule->validate(Request::getInstance());
if (empty($errors)) {
$rule->setAllData(Request::getInstance());
}
if ($another_rule) {
$another_errors = $another_rule->validate(Request::getInstance());
if (empty($another_errors)) {
$another_rule->setAllData(Request::getInstance());
}
$errors = array_merge($errors, $another_errors);
}
if (!mb_strlen(trim(Request::get('instant_course_set_name')))) {
$errors[] = _("Bitte geben Sie einen Namen für die Anmelderegel ein!");
} else {
$course_set->setName(trim(Request::get('instant_course_set_name')));
}
if (count($errors)) {
PageLayout::postError(_('Speichern fehlgeschlagen'), array_map('htmlready', $errors));
} else {
$rule->store();
$course_set->setPrivate(true);
$course_set->addAdmissionRule($rule);
$course_set->setAlgorithm(new RandomAlgorithm());//TODO
$course_set->setCourses([$this->course_id]);
if ($another_rule) {
$course_set->addAdmissionRule($another_rule);
}
$course_set->store();
PageLayout::postSuccess(_("Die Anmelderegel wurde erzeugt und der Veranstaltung zugewiesen."));
$this->redirect($this->action_url('index'));
return;
}
if ($type === 'LockedAdmission') {
$courseset = CourseSet::getGlobalLockedAdmissionSetId();
CourseSet::addCourseToSet($courseset, $this->course_id);
PageLayout::postSuccess(_('Die Veranstaltung wurde gesperrt.'));
$this->relocate('course/admission');
} else {
$another_rule = null;
if (isset($rule_types[$another_type])) {
$another_rule = new $another_type($another_rule_id);
}
$course_set = CourseSet::getSetForRule($rule_id) ?: new CourseSet();
$types = [$type];
if ($another_rule) {
$types[] = $another_type;
}
$course_set_name = $rule->getName() . ': ' . $this->course->name;
$props = [
'rule-types' => $types,
'course-set-name' => $course_set_name,
'course-id' => $this->course_id
];
$this->render_vue_app(
Studip\VueApp::create('admission/InstantCourseSet')
->withProps($props)
);
}
if (!$course_set->getId()) {
$course_set->setName($rule->getName() . ': ' . $this->course->name);
}
$this->rule_template = $rule->getTemplate();
$this->type = $type;
$this->rule_id = $rule_id;
if ($another_rule) {
$this->type = $this->type . '_' . $another_type;
$this->rule_id = $this->rule_id . '_' . $another_rule->getId();
$this->rule_template = $this->rule_template . $another_rule->getTemplate();
}
$this->course_set_name = $course_set->getName();
} else {
throw new Trails_Exception(400);
throw new Trails\Exception(400);
}
}
......@@ -500,10 +483,10 @@ class Course_AdmissionController extends AuthenticatedController
$response = $this->relay('admission/courseset/configure/' . $cs->getId());
$this->body = $response->body;
if (!empty($response->headers['Location'])) {
$this->redirect($response->headers['Location']);
$this->relocate($response->headers['Location']);
}
} else {
throw new Trails_Exception(403);
throw new Trails\Exception(403);
}
}
......@@ -515,10 +498,10 @@ class Course_AdmissionController extends AuthenticatedController
$response = $this->relay('admission/courseset/save/' . $cs->getId());
$this->body = $response->body;
if ($response->headers['Location']) {
$this->redirect($response->headers['Location']);
$this->relocate($response->headers['Location']);
}
} else {
throw new Trails_Exception(403);
throw new Trails\Exception(403);
}
}
......
......@@ -165,9 +165,8 @@ class Course_ArchiveController extends AuthenticatedController
$course = Course::find($courseId);
if ($course) {
$seminar = new Seminar($course);
$coursename = $course->getFullname();
if ($seminar->delete()) {
if ($course->delete()) {
$this->deletedCourses[] = $courseId;
PageLayout::postSuccess(sprintf(
_('Die Veranstaltung %s wurde erfolgreich gelöscht.'),
......
<?php
class Course_AvatarController extends AuthenticatedController
{
public function index_action()
{
$this->course_id = Context::getId();
if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->course_id)) {
throw new AccessDeniedException(_("Sie haben keine Berechtigung diese " .
"Veranstaltung zu verändern."));
}
PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Veranstaltungsbild ändern'));
Navigation::activateItem('/course/admin/avatar');
$avatar = CourseAvatar::getAvatar($this->course_id);
$this->avatar_url = $avatar->getURL(Avatar::NORMAL);
}
}
\ No newline at end of file
......@@ -21,17 +21,14 @@ class Course_BasicdataController extends AuthenticatedController
/**
* Set up the list of input fields. Some fields may be locked for
* some reasons (lock rules, insufficient permissions etc.). This
* some reason (lock rules, insufficient permissions etc.). This
* method does not return anything, it just sets up $this->attributes
* and $this->descriptions.
*
* @param Seminar $sem
* @param Course $course
*/
private function setupInputFields($sem)
protected function setupInputFields(Course $course)
{
$course_id = $sem->getId();
$data = $sem->getData();
$this->attributes = [];
$this->attributes[] = [
'title' => _("Name der Veranstaltung"),
......@@ -39,16 +36,16 @@ class Course_BasicdataController extends AuthenticatedController
'must' => true,
'type' => 'text',
'i18n' => true,
'value' => $data['name'],
'locked' => LockRules::Check($course_id, 'Name')
'value' => $course->name,
'locked' => LockRules::Check($course->id, 'Name')
];
$this->attributes[] = [
'title' => _("Untertitel der Veranstaltung"),
'name' => "course_subtitle",
'title' => _('Untertitel der Veranstaltung'),
'name' => 'course_untertitel',
'type' => 'text',
'i18n' => true,
'value' => $data['subtitle'],
'locked' => LockRules::Check($course_id, 'Untertitel')
'value' => $course->untertitel,
'locked' => LockRules::Check($course->id, 'Untertitel')
];
$changable = true;
$this->attributes[] = [
......@@ -56,60 +53,60 @@ class Course_BasicdataController extends AuthenticatedController
'name' => 'course_status',
'must' => true,
'type' => 'select',
'value' => $data['status'],
'locked' => LockRules::Check($course_id, 'status'),
'choices' => $this->_getTypes($sem, $data, $changable),
'value' => $course->status,
'locked' => LockRules::Check($course->id, 'status'),
'choices' => $this->_getTypes($course, $changable),
'changable' => $changable,
];
$this->attributes[] = [
'title' => _("Art der Veranstaltung"),
'name' => "course_form",
'name' => 'course_art',
'type' => 'text',
'i18n' => true,
'value' => $data['form'],
'locked' => LockRules::Check($course_id, 'art')
'value' => $course->art,
'locked' => LockRules::Check($course->id, 'art')
];
$course_number_format_config = Config::get()->getMetadata('COURSE_NUMBER_FORMAT');
$this->attributes[] = [
'title' => _("Veranstaltungsnummer"),
'name' => "course_seminar_number",
'title' => _('Veranstaltungsnummer'),
'name' => 'course_veranstaltungsnummer',
'type' => 'text',
'value' => $data['seminar_number'],
'locked' => LockRules::Check($course_id, 'VeranstaltungsNummer'),
'value' => $course->veranstaltungsnummer,
'locked' => LockRules::Check($course->id, 'VeranstaltungsNummer'),
'description' => $course_number_format_config['comment'],
'pattern' => Config::get()->COURSE_NUMBER_FORMAT
];
$this->attributes[] = [
'title' => _("ECTS-Punkte"),
'name' => "course_ects",
'title' => _('ECTS-Punkte'),
'name' => 'course_ects',
'type' => 'text',
'value' => $data['ects'],
'locked' => LockRules::Check($course_id, 'ects')
'value' => $course->ects,
'locked' => LockRules::Check($course->id, 'ects')
];
$this->attributes[] = [
'title' => _("max. Teilnehmendenzahl"),
'name' => "course_admission_turnout",
'title' => _('max. Teilnehmendenzahl'),
'name' => 'course_admission_turnout',
'must' => false,
'type' => 'number',
'value' => $data['admission_turnout'],
'locked' => LockRules::Check($course_id, 'admission_turnout'),
'value' => $course->admission_turnout,
'locked' => LockRules::Check($course->id, 'admission_turnout'),
'min' => '0'
];
$this->attributes[] = [
'title' => _("Beschreibung"),
'name' => "course_description",
'title' => _('Beschreibung'),
'name' => 'course_beschreibung',
'type' => 'textarea',
'i18n' => true,
'value' => $data['description'],
'locked' => LockRules::Check($course_id, 'Beschreibung')
'value' => $course->beschreibung,
'locked' => LockRules::Check($course->id, 'Beschreibung')
];
$this->institutional = [];
$my_institutes = Institute::getMyInstitutes();
$institutes = Institute::getInstitutes();
foreach ($institutes as $institute) {
if ($institute['Institut_id'] === $data['institut_id']) {
if ($institute['Institut_id'] === $course->institut_id) {
$found = false;
foreach ($my_institutes as $inst) {
if ($inst['Institut_id'] === $institute['Institut_id']) {
......@@ -128,54 +125,53 @@ class Course_BasicdataController extends AuthenticatedController
'name' => 'course_institut_id',
'must' => true,
'type' => 'nested-select',
'value' => $data['institut_id'],
'value' => $course->institut_id,
'choices' => $this->instituteChoices($my_institutes),
'locked' => LockRules::Check($course_id, 'Institut_id')
'locked' => LockRules::Check($course->id, 'Institut_id')
];
$sem_institutes = $sem->getInstitutes();
$this->institutional[] = [
'title' => _('beteiligte Einrichtungen'),
'name' => 'related_institutes[]',
'type' => 'nested-select',
'value' => array_diff($sem_institutes, [$sem->institut_id]),
'value' => array_diff($course->institutes->pluck('id'), [$course->institut_id]),
'choices' => $this->instituteChoices($institutes),
'locked' => LockRules::Check($course_id, 'seminar_inst'),
'locked' => LockRules::Check($course->id, 'seminar_inst'),
'multiple' => true,
];
$this->descriptions = [];
$this->descriptions[] = [
'title' => _("Teilnehmende"),
'name' => "course_participants",
'title' => _('Teilnehmende'),
'name' => 'course_teilnehmer',
'type' => 'textarea',
'i18n' => true,
'value' => $data['participants'],
'locked' => LockRules::Check($course_id, 'teilnehmer')
'value' => $course->teilnehmer,
'locked' => LockRules::Check($course->id, 'teilnehmer')
];
$this->descriptions[] = [
'title' => _("Voraussetzungen"),
'name' => "course_requirements",
'title' => _('Voraussetzungen'),
'name' => 'course_vorrausetzungen',
'type' => 'textarea',
'i18n' => true,
'value' => $data['vorrausetzungen'],
'locked' => LockRules::Check($course_id, 'voraussetzungen')
'value' => $course->vorrausetzungen,
'locked' => LockRules::Check($course->id, 'voraussetzungen')
];
$this->descriptions[] = [
'title' => _("Lernorganisation"),
'name' => "course_orga",
'title' => _('Lernorganisation'),
'name' => 'course_lernorga',
'type' => 'textarea',
'i18n' => true,
'value' => $data['orga'],
'locked' => LockRules::Check($course_id, 'lernorga')
'value' => $course->lernorga,
'locked' => LockRules::Check($course->id, 'lernorga')
];
$this->descriptions[] = [
'title' => _("Leistungsnachweis"),
'name' => "course_leistungsnachweis",
'title' => _('Leistungsnachweis'),
'name' => 'course_leistungsnachweis',
'type' => 'textarea',
'i18n' => true,
'value' => $data['leistungsnachweis'],
'locked' => LockRules::Check($course_id, 'leistungsnachweis')
'value' => $course->leistungsnachweis,
'locked' => LockRules::Check($course->id, 'leistungsnachweis')
];
$this->descriptions[] = [
'title' => _("Ort") .
......@@ -186,18 +182,18 @@ class Course_BasicdataController extends AuthenticatedController
"Angaben aus Zeiten oder Sitzungsterminen gemacht werden können.") .
"</span>",
'i18n' => true,
'name' => "course_location",
'name' => 'course_ort',
'type' => 'textarea',
'value' => $data['ort'],
'locked' => LockRules::Check($course_id, 'Ort')
'value' => $course->ort,
'locked' => LockRules::Check($course->id, 'Ort')
];
$datenfelder = DataFieldEntry::getDataFieldEntries($course_id, 'sem', $data["status"]);
$datenfelder = DataFieldEntry::getDataFieldEntries($course->id, 'sem', $course->status);
if ($datenfelder) {
foreach($datenfelder as $datenfeld) {
if ($datenfeld->isVisible()) {
$locked = !$datenfeld->isEditable()
|| LockRules::Check($course_id, $datenfeld->getID());
|| LockRules::Check($course->id, $datenfeld->getID());
$desc = $locked ? _('Diese Felder werden zentral durch die zuständigen Administratoren erfasst.') : $datenfeld->getDescription();
$this->descriptions[] = [
'title' => $datenfeld->getName(),
......@@ -215,11 +211,11 @@ class Course_BasicdataController extends AuthenticatedController
}
}
$this->descriptions[] = [
'title' => _("Sonstiges"),
'name' => "course_misc",
'title' => _('Sonstiges'),
'name' => 'course_sonstiges',
'type' => 'textarea',
'value' => $data['misc'],
'locked' => LockRules::Check($course_id, 'Sonstiges')
'value' => $course->sonstiges,
'locked' => LockRules::Check($course->id, 'Sonstiges')
];
}
......@@ -286,27 +282,26 @@ class Course_BasicdataController extends AuthenticatedController
PageLayout::setHelpKeyword("Basis.VeranstaltungenVerwaltenGrunddaten");
PageLayout::setTitle(_("Verwaltung der Grunddaten"));
if ($this->course_id) {
PageLayout::setTitle(Course::find($this->course_id)->getFullname()." - ".PageLayout::getTitle());
PageLayout::setTitle(Course::find($this->course_id)->getFullName()." - ".PageLayout::getTitle());
}
//Daten sammeln:
$course = Course::find($this->course_id);
$sem = new Seminar($course);
$data = $sem->getData();
$data = $course->toRawArray();
//Erster, zweiter und vierter Reiter des Akkordions: Grundeinstellungen
$this->setupInputFields($sem);
$this->setupInputFields($course);
$sem_institutes = $sem->getInstitutes();
$sem_institutes = $course->institutes->pluck('id');
$this->dozent_is_locked = LockRules::Check($this->course_id, 'dozent');
$this->tutor_is_locked = LockRules::Check($this->course_id, 'tutor');
//Dritter Reiter: Personal
$this->dozenten = $sem->getMembers('dozent');
$instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($sem->getInstitutId(), 'dozent'));
$this->dozenten = $course->getMembersWithStatus('dozent');
$instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($course->institut_id, 'dozent'));
$this->lecturersOfInstitute = $instUsers->pluck('user_id');
if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) {
if (SeminarCategories::getByTypeId($course->status)->only_inst_user) {
$search_template = "user_inst_not_already_in_sem";
} else {
$search_template = "user_not_already_in_sem";
......@@ -314,7 +309,7 @@ class Course_BasicdataController extends AuthenticatedController
$this->dozentUserSearch = new PermissionSearch(
$search_template,
sprintf(_("%s suchen"), get_title_for_status('dozent', 1, $sem->status)),
sprintf(_('%s suchen'), get_title_for_status('dozent', 1, $course->status)),
"user_id",
[
'permission' => 'dozent',
......@@ -323,25 +318,25 @@ class Course_BasicdataController extends AuthenticatedController
'institute' => $sem_institutes
]
);
$this->dozenten_title = get_title_for_status('dozent', 1, $sem->status);
$this->dozenten_title = get_title_for_status('dozent', 1, $course->status);
$this->deputies_enabled = $deputies_enabled;
if ($this->deputies_enabled) {
$this->deputies = Deputy::findDeputies($this->course_id);
$this->deputySearch = new PermissionSearch(
"user_not_already_in_sem_or_deputy",
sprintf(_("%s suchen"), get_title_for_status('deputy', 1, $sem->status)),
sprintf(_("%s suchen"), get_title_for_status('deputy', 1, $course->status)),
"user_id",
['permission' => Deputy::getValidPerms(), 'seminar_id' => $this->course_id]
);
$this->deputy_title = get_title_for_status('deputy', 1, $sem->status);
$this->deputy_title = get_title_for_status('deputy', 1, $course->status);
}
$this->tutoren = $sem->getMembers('tutor');
$this->tutoren = $course->getMembersWithStatus('tutor');
$this->tutorUserSearch = new PermissionSearch(
$search_template,
sprintf(_("%s suchen"), get_title_for_status('tutor', 1, $sem->status)),
sprintf(_('%s suchen'), get_title_for_status('tutor', 1, $course->status)),
"user_id",
['permission' => ['dozent','tutor'],
'seminar_id' => $this->course_id,
......@@ -349,8 +344,8 @@ class Course_BasicdataController extends AuthenticatedController
'institute' => $sem_institutes
]
);
$this->tutor_title = get_title_for_status('tutor', 1, $sem->status);
$instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($sem->getInstitutId(), 'tutor'));
$this->tutor_title = get_title_for_status('tutor', 1, $course->status);
$instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($course->institut_id, 'tutor'));
$this->tutorsOfInstitute = $instUsers->pluck('user_id');
unset($instUsers);
......@@ -373,23 +368,20 @@ class Course_BasicdataController extends AuthenticatedController
_('Veranstaltung kopieren'),
$this->url_for(
'course/wizard/copy/' . $this->course_id,
['studip_ticket' => Seminar_Session::get_ticket()]
['studip_ticket' => get_ticket()]
),
Icon::create('seminar')
);
}
}
$widget->addLink(_('Bild ändern'),
$this->url_for('avatar/update/course', $this->course_id),
Icon::create('edit')
);
if ($GLOBALS['perm']->have_perm('admin')) {
$is_locked = $course->lock_rule;
$widget->addLink(
_('Sperrebene ändern') . ' (' . ($is_locked ? _('gesperrt') : _('nicht gesperrt')) . ')',
$this->url_for(
'course/management/lock',
['studip_ticket' => Seminar_Session::get_ticket()]
['studip_ticket' => get_ticket()]
),
Icon::create('lock-' . ($is_locked ? 'locked' : 'unlocked'))
)->asDialog('size=auto');
......@@ -405,7 +397,7 @@ class Course_BasicdataController extends AuthenticatedController
$is_visible ? _('Veranstaltung verstecken') : _('Veranstaltung sichtbar schalten'),
$this->url_for(
'course/management/change_visibility',
['studip_ticket' => Seminar_Session::get_ticket()]
['studip_ticket' => get_ticket()]
),
Icon::create('visibility-' . ($is_visible ? 'visible' : 'invisible'))
);
......@@ -424,10 +416,11 @@ class Course_BasicdataController extends AuthenticatedController
$text = '';
}
if ($newstatus !== '' && $text !== '') {
$widget->addLink($text,
$widget->addLink(
$text,
$this->url_for('course/basicdata/switchdeputy', $this->course_id, $newstatus),
Icon::create('persons')
);
)->asButton();
}
}
if (Config::get()->ALLOW_DOZENT_DELETE || $GLOBALS['perm']->have_perm('admin')) {
......@@ -435,7 +428,7 @@ class Course_BasicdataController extends AuthenticatedController
_('Veranstaltung löschen'),
$this->url_for(
'course/archive/confirm',
['studip_ticket' => Seminar_Session::get_ticket()]
['studip_ticket' => get_ticket()]
),
Icon::create('trash')
)->asDialog('size=auto');
......@@ -445,6 +438,14 @@ class Course_BasicdataController extends AuthenticatedController
$widget = new CourseManagementSelectWidget();
$sidebar->addWidget($widget);
}
foreach ($this->flash['msg'] ?? [] as $msg) {
match ($msg[0]) {
'msg' => PageLayout::postSuccess($msg[1]),
'error' => PageLayout::postError($msg[1]),
'info' => PageLayout::postInfo($msg[1]),
};
}
}
/**
......@@ -455,18 +456,22 @@ class Course_BasicdataController extends AuthenticatedController
{
global $perm;
CSRFProtection::verifySecurityToken();
CSRFProtection::verifyUnsafeRequest();
$course_number_format = Config::get()->COURSE_NUMBER_FORMAT;
$sem = Seminar::getInstance($course_id);
$this->msg = [];
$old_settings = $sem->getSettings();
$course = Course::find($course_id);
$this->msg = [
'success' => '',
'errors' => []
];
$old_settings = $course->toRawArray();
unset($old_settings['config']);
//Seminar-Daten:
if ($perm->have_studip_perm("tutor", $sem->getId())) {
$this->setupInputFields($sem);
if ($perm->have_studip_perm('tutor', $course_id)) {
$this->setupInputFields($course);
$changemade = false;
$invalid_datafields = [];
$all_fields_types = DataFieldEntry::getDataFieldEntries($sem->id, 'sem', $sem->status);
$all_fields_types = DataFieldEntry::getDataFieldEntries($course->id, 'sem', $course->status);
$datafield_values = Request::getArray('datafields');
foreach (array_merge($this->attributes, $this->institutional, $this->descriptions) as $field) {
......@@ -482,9 +487,17 @@ class Course_BasicdataController extends AuthenticatedController
} else {
$invalid_datafields[] = $datafield->getName();
}
} else if ($field['name'] == 'related_institutes[]') {
} else if ($field['name'] === 'related_institutes[]') {
// only related_institutes supported for now
if ($sem->setInstitutes(Request::optionArray('related_institutes'))) {
$related_institute_ids = Request::optionArray('related_institutes');
$current_institute_ids = $course->institutes->pluck('id');
$current_institute_ids = array_diff($current_institute_ids, [$course->institut_id]);
$institutes_changed = count($related_institute_ids) !== count($current_institute_ids)
|| count(array_diff($current_institute_ids, $related_institute_ids)) > 0;
if ($institutes_changed) {
$course->institutes = Institute::findMany($related_institute_ids);
$changemade = true;
}
} else {
......@@ -497,14 +510,14 @@ class Course_BasicdataController extends AuthenticatedController
}
if ($varname === "name" && !$req_value) {
$this->msg[] = ["error", _("Name der Veranstaltung darf nicht leer sein.")];
$this->msg['error'][] = _('Name der Veranstaltung darf nicht leer sein.');
} elseif ($varname === "seminar_number" && $req_value && $course_number_format &&
!preg_match('/^' . $course_number_format . '$/', $req_value)) {
$this->msg[] = ['error', _('Die Veranstaltungsnummer hat ein ungültiges Format.')];
$this->msg['error'][] = _('Die Veranstaltungsnummer hat ein ungültiges Format.');
} else if ($field['type'] == 'select' && !in_array($req_value, array_flatten(array_values(array_map('array_keys', $field['choices']))))) {
// illegal value - just ignore this
} else if ($sem->{$varname} != $req_value) {
$sem->{$varname} = $req_value;
} else if ($course->getValue($varname) != $req_value) {
$course->setValue($varname, $req_value);
$changemade = true;
}
}
......@@ -518,23 +531,25 @@ class Course_BasicdataController extends AuthenticatedController
count($invalid_datafields)
);
$message = sprintf($message, join(', ', array_map('htmlReady', $invalid_datafields)));
$this->msg[] = ['error', $message];
$this->msg['error'][] = $message;
}
$sem->store();
$course->store();
// Logging
$before = array_diff_assoc($old_settings, $sem->getSettings());
$after = array_diff_assoc($sem->getSettings(), $old_settings);
$current_settings = $course->toRawArray();
unset($current_settings['config']);
$before = array_diff_assoc($old_settings, $current_settings);
$after = array_diff_assoc($current_settings, $old_settings);
//update admission, if turnout was raised
if (
!empty($after['admission_turnout'])
&& !empty($before['admission_turnout'])
&& $after['admission_turnout'] > $before['admission_turnout']
&& $sem->isAdmissionEnabled()
&& $course->isAdmissionEnabled()
) {
AdmissionApplication::addMembers($sem->getId());
AdmissionApplication::addMembers($course_id);
}
if (sizeof($before) && sizeof($after)) {
......@@ -542,30 +557,30 @@ class Course_BasicdataController extends AuthenticatedController
foreach ($before as $k => $v) {
$log_message .= "$k: $v => " . $after[$k] . " \n";
}
StudipLog::log('CHANGE_BASIC_DATA', $sem->getId(), " ", $log_message);
NotificationCenter::postNotification('SeminarBasicDataDidUpdate', $sem->id , $GLOBALS['user']->id);
StudipLog::log('CHANGE_BASIC_DATA', $course_id, ' ', $log_message);
NotificationCenter::postNotification('SeminarBasicDataDidUpdate', $course->id , $GLOBALS['user']->id);
}
// end of logging
if ($changemade) {
$this->msg[] = ["msg", _("Die Grunddaten der Veranstaltung wurden verändert.")];
$this->msg['success'] = _('Die Grunddaten der Veranstaltung wurden verändert.');
}
} else {
$this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")];
$this->msg['error'][] = _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.');
}
//Labels/Funktionen für Dozenten und Tutoren
if ($perm->have_studip_perm('dozent', $sem->getId())) {
if ($perm->have_studip_perm('dozent', $course_id)) {
foreach (Request::getArray('label') as $user_id => $label) {
if ($GLOBALS['perm']->have_studip_perm('tutor', $sem->getId(), $user_id)) {
$mb = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $sem->getId()]);
if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id, $user_id)) {
$mb = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $course_id]);
if ($mb) {
$mb->label = $label;
if ($mb->store()) {
NotificationCenter::postNotification(
'CourseDidChangeMemberLabel',
$sem,
$course,
$mb
);
}
......@@ -574,55 +589,68 @@ class Course_BasicdataController extends AuthenticatedController
}
}
foreach($sem->getStackedMessages() as $key => $messages) {
foreach($messages['details'] as $message) {
$this->msg[] = [($key !== "success" ? $key : "msg"), $message];
}
if (!empty($this->msg['error'])) {
PageLayout::postError(
_('Die folgenden Fehler traten auf:'),
$this->msg['error']
);
} elseif ($this->msg['success']) {
PageLayout::postSuccess($this->msg['success']);
}
$this->flash['msg'] = $this->msg;
$this->flash['open'] = Request::get("open");
if (Request::isDialog()) {
$this->response->add_header('X-Dialog-Close', 1);
$this->response->add_header('X-Dialog-Execute', 'STUDIP.AdminCourses.App.loadCourse');
$this->render_text($course_id);
} else {
$this->redirect($this->url_for('course/basicdata/view/' . $sem->getId()));
$this->redirect($this->url_for('course/basicdata/view/' . $course_id));
}
}
public function add_member_action($course_id, $status = 'dozent')
{
CSRFProtection::verifySecurityToken();
if (!$GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
throw new AccessDeniedException();
}
// We don't need to check the csrf protection at this point since it
// is already checked by the multiperson search endpoint
// load MultiPersonSearch object
$mp = MultiPersonSearch::load("add_member_{$status}{$course_id}");
switch($status) {
case 'tutor' :
$func = 'addTutor';
break;
case 'deputy':
$func = 'addDeputy';
break;
default:
$func = 'addTeacher';
break;
}
$course = Course::find($course_id);
$succeeded = [];
$failed = [];
$failed = [];
foreach ($mp->getAddedUsers() as $a) {
$result = $this->$func($a, $course_id);
if ($result !== false) {
$succeeded[] = User::find($a)->getFullname('no_title_rev');
$user = User::find($a);
$result = false;
if ($status === 'deputy') {
$result = Deputy::addDeputy($user->id, $course->id) > 0;
} else {
$failed[] = User::find($a)->getFullname('no_title_rev');
try {
$course->addMember(
$user,
$status === 'tutor' ? 'tutor' : 'dozent'
);
$result = true;
} catch (\Studip\EnrolmentException $e) {
$result = $e->getMessage();
}
}
if ($result === true) {
$succeeded[] = $user->getFullName('no_title_rev');
} elseif (is_string($result)) {
$failed[] = [$user->getFullName('no_title_rev'), $result];
} else {
$failed[] = [$user->getFullName('no_title_rev')];
}
}
// Only show the success messagebox once
if ($succeeded) {
$sem = Seminar::GetInstance($course_id);
$status_title = get_title_for_status($status, count($succeeded), $sem->status);
$status_title = get_title_for_status($status, count($succeeded), $course->status);
if (count($succeeded) > 1) {
$messagetext = sprintf(
_("%u %s wurden hinzugefügt."),
......@@ -644,9 +672,17 @@ class Course_BasicdataController extends AuthenticatedController
// only show an error messagebox once with list of errors!
if ($failed) {
$messages = [];
foreach ($failed as $fail) {
if (is_array($fail)) {
$messages[] = sprintf('%s: %s', $fail[0], $fail[1]);
} else {
$messages[] = $fail;
}
}
PageLayout::postError(
_('Bei den folgenden Nutzer/-innen ist ein Fehler aufgetreten') ,
array_map('htmlReady', $failed)
array_map('htmlReady', $messages)
);
}
$this->flash['open'] = 'bd_personal';
......@@ -655,72 +691,28 @@ class Course_BasicdataController extends AuthenticatedController
$this->redirect($this->url_for($redirect));
}
private function addTutor($tutor, $course_id)
{
//Tutoren hinzufügen:
if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) {
$sem = Seminar::GetInstance($course_id);
if ($sem->addMember($tutor, 'tutor')) {
// Check if we need to add user to course parent as well.
if ($sem->parent_course) {
$this->addTutor($tutor, $sem->parent_course);
}
return true;
}
}
return false;
}
private function addDeputy($user_id, $course_id)
{
//Vertretung hinzufügen:
if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
$sem = Seminar::GetInstance($course_id);
if (Deputy::addDeputy($user_id, $sem->getId())) {
return true;
}
}
return false;
}
private function addTeacher($dozent, $course_id)
/**
* A helper method since the steps for removing someone are all the same in this controller.
* Only the actions differ.
*
* @param Course $course The course from which to remove a user.
* @param User $user The user to be removed.
* @return void
*/
protected function deleteUserFromCourse(Course $course, User $user)
{
$deputies_enabled = Config::get()->DEPUTIES_ENABLE;
$sem = Seminar::GetInstance($course_id);
if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
if ($sem->addMember($dozent, 'dozent')) {
// Check if we need to add user to course parent as well.
if ($sem->parent_course) {
$this->addTeacher($dozent, $sem->parent_course);
}
// Only applicable when globally enabled and user deputies enabled too
if ($deputies_enabled) {
// Check whether chosen person is set as deputy
// -> delete deputy entry.
$deputy = Deputy::find([$course_id, $dozent]);
if ($deputy) {
$deputy->delete();
}
// Add default deputies of the chosen lecturer...
if (Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) {
$deputies = Deputy::findDeputies($dozent)->pluck('user_id');
$lecturers = $sem->getMembers();
foreach ($deputies as $deputy) {
// ..but only if not already set as lecturer or deputy.
if (!isset($lecturers[$deputy])) {
Deputy::addDeputy($deputy, $course_id);
}
}
}
}
return true;
}
}
return false;
try {
$course->deleteMember($user);
} catch (\Studip\Exception $e) {
PageLayout::postError(_('Ein Fehler ist aufgetreten.'), $e->getMessage());
return;
}
PageLayout::postSuccess(
studip_interpolate(
_('%{name} wurde aus der Veranstaltung ausgetragen.'),
['name' => $user->getFullName()]
)
);
}
/**
......@@ -739,24 +731,10 @@ class Course_BasicdataController extends AuthenticatedController
} elseif ($teacher_id === $GLOBALS['user']->id) {
PageLayout::postError(_('Sie dürfen sich nicht selbst aus der Veranstaltung austragen.'));
} else {
$sem = Seminar::getInstance($course_id);
$sem->deleteMember($teacher_id);
// Remove user from subcourses as well.
foreach ($sem->children as $child) {
$child->deleteMember($teacher_id);
}
$this->msg = [];
foreach ($sem->getStackedMessages() as $key => $messages) {
foreach ($messages['details'] as $message) {
$this->msg[] = [
$key !== 'success' ? $key : 'msg',
$message
];
}
}
$this->flash['msg'] = $this->msg;
$this->deleteUserFromCourse(
Course::find($course_id),
User::find($teacher_id)
);
}
$this->flash['open'] = 'bd_personal';
......@@ -779,23 +757,23 @@ class Course_BasicdataController extends AuthenticatedController
} elseif ($deputy_id === $GLOBALS['user']->id) {
PageLayout::postError(_('Sie dürfen sich nicht selbst aus der Veranstaltung austragen.'));
} else {
$sem = Seminar::getInstance($course_id);
$course = Course::find($course_id);
$deputy = Deputy::find([$course_id, $deputy_id]);
if ($deputy && $deputy->delete()) {
// Remove user from subcourses as well.
if (count($sem->children)) {
$children_ids = $sem->children->pluck('seminar_id');
if (count($course->children) > 0) {
$children_ids = $course->children->pluck('seminar_id');
Deputy::deleteBySQL('user_id = ? AND range_id IN (?)', [$deputy_id, $children_ids]);
}
PageLayout::postSuccess(sprintf(
_('%s wurde entfernt.'),
htmlReady(get_title_for_status('deputy', 1, $sem->status))
htmlReady(get_title_for_status('deputy', 1, $course->status))
));
} else {
PageLayout::postError(sprintf(
_('%s konnte nicht entfernt werden.'),
htmlReady(get_title_for_status('deputy', 1, $sem->status))
htmlReady(get_title_for_status('deputy', 1, $course->status))
));
}
}
......@@ -818,24 +796,10 @@ class Course_BasicdataController extends AuthenticatedController
if (!$GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
PageLayout::postError( _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.'));
} else {
$sem = Seminar::getInstance($course_id);
$sem->deleteMember($tutor_id);
// Remove user from subcourses as well.
foreach ($sem->children as $child) {
$child->deleteMember($tutor_id);
}
$this->msg = [];
foreach ($sem->getStackedMessages() as $key => $messages) {
foreach ($messages['details'] as $message) {
$this->msg[] = [
$key !== 'success' ? $key : 'msg',
$message
];
}
}
$this->flash['msg'] = $this->msg;
$this->deleteUserFromCourse(
Course::find($course_id),
User::find($tutor_id)
);
}
$this->flash['open'] = 'bd_personal';
......@@ -843,82 +807,68 @@ class Course_BasicdataController extends AuthenticatedController
}
/**
* Falls eine Person in der >>Reihenfolge<< hochgestuft werden soll.
* Leitet danach weiter auf View und öffnet den Reiter Personal.
* Moves a course member up one position in the position list for the
* corresponding permission level in the course.
*
* @param string $course_id The course where to increase the priority.
*
* @param string $user_id The user for whom to increase the priority.
*
* @param md5 $user_id
* @param string $status
* @param string $status The permission level. This is an unused parameter that is only kept
* for compatibility reasons.
*/
public function priorityupfor_action($course_id, $user_id, $status = "dozent")
public function priorityupfor_action(string $course_id, string $user_id, string $status = 'dozent')
{
global $user, $perm;
CSRFProtection::verifySecurityToken();
CSRFProtection::verifyUnsafeRequest();
$sem = Seminar::getInstance($course_id);
$course = Course::find($course_id);
$user = User::find($user_id);
$this->msg = [];
if ($perm->have_studip_perm("dozent", $sem->getId())) {
$teilnehmer = $sem->getMembers($status);
$members = [];
foreach($teilnehmer as $key => $member) {
$members[] = $member["user_id"];
}
foreach($members as $key => $member) {
if ($key > 0 && $member == $user_id) {
$temp_member = $members[$key-1];
$members[$key-1] = $member;
$members[$key] = $temp_member;
}
if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) {
if ($course->moveMemberUp($user) < 0) {
$this->msg[] = ['error', _('Die Person konnte nicht nach oben verschoben werden.')];
}
$sem->setMemberPriority($members);
} else {
$this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")];
}
$this->flash['msg'] = $this->msg;
$this->flash['open'] = "bd_personal";
$this->redirect($this->url_for('course/basicdata/view/' . $sem->getId()));
$this->redirect($this->url_for('course/basicdata/view/' . $course->id));
}
/**
* Falls eine Person in der >>Reihenfolge<< runtergestuft werden soll.
* Leitet danach weiter auf View und öffnet den Reiter Personal.
* Moves a course member down one position in the position list for the
* corresponding permission level in the course.
*
* @param string $course_id The course where to decrease the priority.
*
* @param md5 $user_id
* @param string $status
* @param string $user_id The user for whom to decrease the priority.
*
* @param string $status The permission level. This is an unused parameter that is only kept
* for compatibility reasons.
*/
public function prioritydownfor_action($course_id, $user_id, $status = "dozent")
public function prioritydownfor_action($course_id, $user_id, $status = 'dozent')
{
global $user, $perm;
CSRFProtection::verifySecurityToken();
CSRFProtection::verifyUnsafeRequest();
$sem = Seminar::getInstance($course_id);
$course = Course::find($course_id);
$user = User::find($user_id);
$this->msg = [];
if ($perm->have_studip_perm("dozent", $sem->getId())) {
$teilnehmer = $sem->getMembers($status);
$members = [];
foreach($teilnehmer as $key => $member) {
$members[] = $member["user_id"];
if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) {
if ($course->moveMemberDown($user) < 0) {
$this->msg[] = ['error', _('Die Person konnte nicht nach unten verschoben werden.')];
}
foreach($members as $key => $member) {
if ($key < count($members)-1 && $member == $user_id) {
$temp_member = $members[$key+1];
$members[$key+1] = $member;
$members[$key] = $temp_member;
}
}
$sem->setMemberPriority($members);
} else {
$this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")];
$this->msg[] = ['error', _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.')];
}
$this->flash['msg'] = $this->msg;
$this->flash['open'] = "bd_personal";
$this->redirect($this->url_for('course/basicdata/view/' . $sem->getId()));
$this->redirect($this->url_for('course/basicdata/view/' . $course->id));
}
public function switchdeputy_action($course_id, $newstatus)
{
CSRFProtection::verifySecurityToken();
CSRFProtection::verifyUnsafeRequest();
switch($newstatus) {
case 'dozent':
......@@ -953,29 +903,38 @@ class Course_BasicdataController extends AuthenticatedController
$this->redirect($this->url_for('course/basicdata/view/'.$course_id));
}
private function _getTypes($sem, $data, &$changable = true)
private function _getTypes(Course $course, &$changable = true)
{
$sem_types = [];
$sem_classes = [];
if ($GLOBALS['perm']->have_perm("admin")) {
foreach (SemClass::getClasses() as $sc) {
if (!$sc['course_creation_forbidden']) {
$sem_types[$sc['name']] = array_map(function ($st) {
return $st['name'];
}, $sc->getSemTypes());
$sem_classes[] = $sc;
}
}
} else {
$sc = $sem->getSemClass();
$sem_classes[] = $course->getSemClass();
}
if (!$course->isStudyGroup()) {
$sem_classes = array_filter($sem_classes, function (SemClass $sc) {
return !$sc['studygroup_mode'];
});
}
foreach ($sem_classes as $sc) {
$sem_types[$sc['name']] = array_map(function ($st) {
return $st['name'];
}, $sc->getSemTypes());
}
if (!in_array($data['status'], array_flatten(array_values(array_map('array_keys', $sem_types))))) {
$class_name = $sem->getSemClass()->offsetGet('name');
if (!in_array($course->status, array_flatten(array_values(array_map('array_keys', $sem_types))))) {
$class_name = $course->getSemClass()->offsetGet('name');
if (!isset($sem_types[$class_name])) {
$sem_types[$class_name] = [];
}
$sem_types[$class_name][] = $sem->getSemType()->offsetGet('name');
$sem_types[$class_name][] = $course->getSemType()->offsetGet('name');
$changable = false;
}
......
......@@ -33,10 +33,10 @@ class Course_BlockAppointmentsController extends AuthenticatedController
SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode ||
!$GLOBALS['perm']->have_studip_perm("tutor", $this->course_id)
) {
throw new Trails_Exception(400);
throw new Trails\Exception(400);
}
PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen');
PageLayout::setTitle(Course::findCurrent()->getFullname() . " - " . _('Blockveranstaltungstermine anlegen'));
PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Blockveranstaltungstermine anlegen'));
}
......@@ -242,10 +242,10 @@ class Course_BlockAppointmentsController extends AuthenticatedController
$result = $d->store();
} else {
$result = $d->store();
$singledate = new SingleDate($d);
$singledate->bookRoom(Request::option('room_id'));
$room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance();
$d->bookRoom($room);
}
return $result ? $d->getFullname() : null;
return $result ? $d->getFullName() : null;
}, $dates));
if ($date_count > 1) {
$dates_created = array_count_values($dates_created);
......
......@@ -25,24 +25,24 @@ class Course_CancelDatesController extends AuthenticatedController
parent::before_filter($action, $args);
if (Request::get('termin_id')) {
$this->dates[0] = new SingleDate(Request::option('termin_id'));
$this->dates[0] = CourseDate::find(Request::option('termin_id'));
$this->course_id = $this->dates[0]->range_id;
}
if (Request::get('issue_id')) {
$this->issue_id = Request::option('issue_id');
$this->dates = array_values(array_map(function ($data) {
$d = new SingleDate();
$d->fillValuesFromArray($data);
return $d;
}, IssueDB::getDatesforIssue(Request::option('issue_id'))));
$this->dates = CourseDate::findBySQL(
"JOIN `themen_termine` USING (`termin_id`)
WHERE `issue_id` = :issue_id ORDER BY `date`",
['issue_id' => Request::option('issue_id')]
);
$this->course_id = $this->dates[0]->range_id;
}
if (!get_object_type($this->course_id, ['sem']) || !$perm->have_studip_perm("tutor", $this->course_id)) {
throw new Trails_Exception(400);
throw new Trails\Exception(400);
}
PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen');
PageLayout::setTitle(Course::findCurrent()->getFullname() . " - " . _('Veranstaltungstermine absagen'));
PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Veranstaltungstermine absagen'));
}
public function index_action()
......@@ -52,13 +52,13 @@ class Course_CancelDatesController extends AuthenticatedController
public function store_action()
{
CSRFProtection::verifyUnsafeRequest();
$sem = Seminar::getInstance($this->course_id);
$msg = '';
foreach ($this->dates as $date) {
$sem->cancelSingleDate($date->getTerminId(), $date->getMetadateId());
$date->setComment(Request::get('cancel_dates_comment'));
$date->setExTermin(true);
$date->store();
$ex_date = $date->cancelDate();
if ($ex_date) {
$ex_date->content = Request::get('cancel_dates_comment');
$ex_date->store();
}
}
if (Request::int('cancel_dates_snd_message') && count($this->dates) > 0) {
$snd_messages = raumzeit_send_cancel_message(Request::get('cancel_dates_comment'), $this->dates);
......@@ -67,7 +67,7 @@ class Course_CancelDatesController extends AuthenticatedController
}
}
PageLayout::postSuccess(_('Folgende Termine wurden abgesagt') . ($msg ? ' (' . $msg . '):' : ':'), array_map(function ($d) {
return $d->toString();
return $d->getFullName();
}, $this->dates));
$this->redirect($this->url_for('course/dates'));
......
......@@ -16,7 +16,6 @@
*/
class Course_ChangeViewController extends AuthenticatedController
{
// see Trails_Controller#before_filter
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
......@@ -28,7 +27,7 @@ class Course_ChangeViewController extends AuthenticatedController
* Sets the current course into participant view.
* Only available for tutor upwards.
*
* @throws Trails_Exception Someone with unfitting rights tried to call here.
* @throws Trails\Exception Someone with unfitting rights tried to call here.
*/
public function set_changed_view_action()
{
......@@ -43,7 +42,7 @@ class Course_ChangeViewController extends AuthenticatedController
* Resets a course currently in participant view to normal view
* with real rights.
*
* @throws Trails_Exception Someone with unfitting rights tried to call here.
* @throws Trails\Exception Someone with unfitting rights tried to call here.
*/
public function reset_changed_view_action()
{
......
<?php
class Course_ConnectedcoursesController extends AuthenticatedController
{
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
if (!$GLOBALS['perm']->have_studip_perm('tutor', Context::getId())) {
throw new AccessDeniedException();
}
}
public function index_action()
{
Navigation::activateItem('/course/admin/connectedcourses');
$this->connected = StudygroupCourse::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses.course_id) WHERE studygroup_courses.studygroup_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$this->proposals = StudygroupCourseProposal::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses_proposals.studygroup_id) WHERE studygroup_courses_proposals.studygroup_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$this->buildSidebar();
}
public function connect_action($course_id = null)
{
Navigation::activateItem('/course/admin/connectedcourses');
PageLayout::setTitle(_('Veranstaltung suchen und zur Verknüpfung vorschlagen'));
if (Request::isPost() && (Request::option('course_id') || $course_id)) {
CSRFProtection::verifySecurityToken();
$course_id = $course_id ?? Request::option('course_id');
$status = StudygroupModel::proposeAsStudygroupTo(Context::get(), $course_id);
if ($status === 'connected') {
PageLayout::postSuccess(_('Veranstaltung wurde verknüpft.'));
}
if ($status === 'proposed') {
PageLayout::postSuccess(_('Vorschlag wurde eingereicht.'));
}
$this->redirect('course/connectedcourses/index');
return;
}
$connected = StudygroupCourse::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses.course_id) WHERE studygroup_courses.studygroup_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$proposals = StudygroupCourseProposal::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses_proposals.studygroup_id) WHERE studygroup_courses_proposals.studygroup_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$already_covered = array_map(function($c) { return $c->course_id; }, $connected);
$already_covered = $already_covered + array_map(function($c) { return $c->course_id; }, $proposals);
$studygroup_ids = [];
foreach (SemClass::getClasses() as $sem_class) {
if ($sem_class['studygroup_mode'] > 0) {
foreach ($sem_class->getSemTypes() as $sem_type) {
$studygroup_ids[] = $sem_type['id'];
}
}
}
$this->my_courses = [];
if (!$GLOBALS['perm']->have_perm('admin')) {
$this->my_courses = Course::findBySQL('INNER JOIN `seminar_user` USING (`Seminar_id`)
LEFT JOIN `semester_courses` ON (`seminare`.`Seminar_id` = `semester_courses`.`course_id`)
WHERE `seminar_user`.`user_id` = :user_id
AND `seminare`.`status` NOT IN (:studygroup_sem_types)
AND (`semester_courses`.`semester_id` IS NULL OR `semester_courses`.`semester_id` = :semester_id)
AND `seminare`.`Seminar_id` NOT IN (:ignore)
ORDER BY `seminare`.`name` ASC ',
[
'user_id' => User::findCurrent()->id,
'studygroup_sem_types' => $studygroup_ids,
'semester_id' => Request::get('semester_id') ?? Semester::findCurrent()->id,
'ignore' => count($already_covered) ? $already_covered : ''
]);
foreach ($this->my_courses as $my_course) {
$already_covered[] = $my_course->id;
}
}
if (Request::get('search') && Request::get('search') != 1) {
//do the search:
$query = SQLQuery::table('seminare')
->where('search',
'`name` LIKE :search OR `VeranstaltungsNummer` LIKE :search',
['search' => '%' . Request::get('search') . '%']
)
->where(
'studygroups',
'`seminare`.`status` NOT IN (:sem_type_ids)',
['sem_type_ids' => $studygroup_ids]
)
->groupBy('`seminare`.`Seminar_id`');
if (count($already_covered) > 0) {
$query->where(
'ignore',
'`seminare`.`Seminar_id` NOT IN (:ignore)',
['ignore' => $already_covered]
);
}
if (!empty(Request::get('semester_id'))) {
$query->join(
'semester_courses',
'semester_courses',
'`semester_courses`.`course_id` = `seminare`.`Seminar_id`',
'LEFT JOIN'
);
$query->where(
'semester_id',
'semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL',
['semester_id' => Request::get('semester_id')]
);
}
$this->searchresults = $query->fetchAll(Course::class);
} else {
//get up to 10 courses with a lot of members of the current studygroup:
$statement = DBManager::get()->prepare("
SELECT `seminare`.*
FROM `seminar_user`
INNER JOIN `seminare` ON (`seminare`.`Seminar_id` = `seminar_user`.`Seminar_id`)
INNER JOIN `seminar_user` AS `su2` ON (`su2`.`user_id` = `seminar_user`.`user_id` AND `su2`.`Seminar_id` = :course_id)
LEFT JOIN `studygroup_courses` ON (`studygroup_courses`.`course_id` = `seminare`.`Seminar_id` AND `studygroup_courses`.`studygroup_id` = `su2`.`Seminar_id`)
WHERE `seminare`.`status` NOT IN (:studygroup_sem_types)
AND `studygroup_courses`.`id` IS NULL
AND `seminare`.`Seminar_id` NOT IN (:ignore)
GROUP BY `seminare`.`Seminar_id`
HAVING COUNT(`seminar_user`.`user_id`) > 1
ORDER BY COUNT(`seminar_user`.`user_id`) DESC
LIMIT 20
");
$statement->execute([
'course_id' => Context::getId(),
'studygroup_sem_types' => $studygroup_ids,
'ignore' => count($already_covered) ? $already_covered : ''
]);
$suggestions = $statement->fetchAll(PDO::FETCH_ASSOC);
$this->suggestions = array_map(function ($d) {
return Course::buildExisting($d);
}, $suggestions);
}
}
public function remove_action($course_id)
{
if (Request::isPost() && $course_id) {
CSRFProtection::verifySecurityToken();
StudygroupCourse::deleteBySQL('course_id = ? AND studygroup_id = ?', [
$course_id,
Context::getId()
]);
PageLayout::postSuccess(_('Verknüpfung zu der Veranstaltung wurde aufgehoben.'));
}
$this->redirect('course/connectedcourses/index');
}
public function decline_action(StudygroupCourseProposal $proposal)
{
if (Request::isPost()) {
CSRFProtection::verifySecurityToken();
if ($GLOBALS['perm']->have_studip_perm('tutor', $proposal['course_id']) || $GLOBALS['perm']->have_studip_perm('tutor', $proposal['studygroup_id'])) {
if ($proposal['proposed_from'] === 'course') {
PageLayout::postSuccess(_('Vorschlag wurde abgewiesen.'));
$statement = DBManager::get()->prepare("
SELECT `username`, `user_id`
FROM `auth_user_md5`
INNER JOIN `seminar_user` USING (`user_id`)
WHERE `seminar_user`.`Seminar_id` = ? AND `seminar_user`.`status` IN ('tutor', 'dozent')
");
$statement->execute([$proposal['course_id']]);
$messaging = new messaging();
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $user_data) {
setTempLanguage($user_data['user_id']);
$messaging->insert_message(
sprintf(
_('Ihr Vorschlag, die Studiengruppe „%1$s“ mit der Veranstaltung „%2$s“ zu verknüpfen, wurde leider abgewiesen.'),
Context::get()->getFullname(),
$proposal->studygroup->getFullname()
),
$user_data['username'],
'____%system%____',
'',
'',
'',
'',
_('Verknüpfungsvorschlag abgewiesen'),
'',
'normal',
['Studiengruppe']
);
restoreLanguage();
}
} else {
PageLayout::postSuccess(_('Vorschlag wurde zurückgezogen.'));
}
$proposal->delete();
}
}
$this->redirect('course/connectedcourses/index');
}
protected function buildSidebar()
{
$actions = new ActionsWidget();
$actions->addLink(
_('Verknüpfung vorschlagen'),
$this->url_for('course/connectedcourses/connect'),
Icon::create('add'),
['data-dialog' => 1]
);
Sidebar::Get()->addWidget($actions);
}
}
<?php
class Course_ConnectedstudygroupsController extends AuthenticatedController
{
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
if (!$GLOBALS['perm']->have_studip_perm('tutor', Context::getId())) {
throw new AccessDeniedException();
}
}
public function index_action()
{
Navigation::activateItem('/course/admin/connectedstudygroups');
$this->connected = StudygroupCourse::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses.studygroup_id) WHERE studygroup_courses.course_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$this->proposals = StudygroupCourseProposal::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses_proposals.studygroup_id) WHERE studygroup_courses_proposals.course_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$this->buildSidebar();
}
public function connect_action($course_id = null)
{
Navigation::activateItem('/course/admin/connectedstudygroups');
PageLayout::setTitle(_('Studiengruppe suchen und verknüpfen'));
if (Request::isPost() && (Request::option('course_id') || $course_id)) {
CSRFProtection::verifySecurityToken();
$course_id = $course_id ?? Request::option('course_id');
$proposal = StudygroupCourseProposal::findOneBySQL('course_id = ? AND studygroup_id = ?', [
Context::getId(),
$course_id
]);
if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id) || $proposal['proposed_from'] === 'studygroup') {
$connection = StudygroupCourse::findOneBySQL('course_id = ? AND studygroup_id = ?', [
Context::getId(),
$course_id
]);
if (!$connection) {
$connection = new StudygroupCourse();
$connection['course_id'] = Context::getId();
$connection['studygroup_id'] = $course_id;
$connection->store();
}
if ($proposal) {
if ($proposal['proposed_from'] === 'studygroup') {
$statement = DBManager::get()->prepare("
SELECT `username`, `user_id`
FROM `auth_user_md5`
INNER JOIN `seminar_user` USING (`user_id`)
WHERE `seminar_user`.`Seminar_id` = ? AND `seminar_user`.`status` IN ('tutor', 'dozent')
");
$statement->execute([$course_id]);
$messaging = new messaging();
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $user_data) {
setTempLanguage($user_data['user_id']);
$messaging->insert_message(
sprintf(
_('Ihr Vorschlag, die Studiengruppe „%1$s“ mit der Veranstaltung „%2$s“ zu verknüpfen, wurde angenommen.'),
Context::get()->getFullname(),
Course::find($course_id)->getFullname()
),
$user_data['username'],
'____%system%____',
'',
'',
'',
'',
_('Verknüpfungsvorschlag angenommen'),
'',
'normal',
['Studiengruppe']
);
restoreLanguage();
}
}
$proposal->delete();
}
PageLayout::postSuccess(_('Veranstaltung wurde verknüpft.'));
} else {
//send message:
if (!$proposal) {
$proposal = new StudygroupCourseProposal();
$proposal['course_id'] = Context::getId();
$proposal['studygroup_id'] = $course_id;
$proposal['proposed_from'] = 'course';
$proposal['user_id'] = User::findCurrent()->id;
$proposal->store();
$statement = DBManager::get()->prepare("
SELECT `username`, `user_id`
FROM `auth_user_md5`
INNER JOIN `seminar_user` USING (`user_id`)
WHERE `seminar_user`.`Seminar_id` = ? AND `seminar_user`.`status` IN ('tutor', 'dozent')
");
$statement->execute([$course_id]);
$messaging = new messaging();
$oldbase = URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']);
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $user_data) {
setTempLanguage($user_data['user_id']);
$messaging->insert_message(
sprintf(
_('Es wurde vorgeschlagen, die Veranstaltung „%1$s“ mit Ihrer Studiengruppe „%2$s“ zu verknüpfen. Sie können den Vorschlag unter folgendem Link annehmen oder ablehnen:'),
Context::get()->getFullname(),
Course::find($course_id)->getFullname()
)."\n\n".URLHelper::getURL('dispatch.php/course/connectedcourses/index', ['cid' => $course_id]),
$user_data['username'],
'____%system%____',
'',
'',
'',
'',
_('Verknüpfung Ihrer Studiengruppe zu einer Veranstaltung'),
'',
'normal',
['Studiengruppe']
);
restoreLanguage();
}
URLHelper::setBaseURL($oldbase);
}
PageLayout::postSuccess(_('Antrag wurde gestellt.'));
}
$this->redirect('course/connectedstudygroups/index');
return;
}
$connected = StudygroupCourse::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses.studygroup_id) WHERE studygroup_courses.course_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$proposals = StudygroupCourseProposal::findBySQL(
'INNER JOIN seminare ON (seminare.Seminar_id = studygroup_courses_proposals.course_id) WHERE studygroup_courses_proposals.course_id = ? ORDER BY seminare.name ASC',
[
Context::getId()
]
);
$already_covered = array_map(function ($c) {
return $c->course_id;
}, $connected);
$already_covered = $already_covered + array_map(function ($c) {
return $c->course_id;
}, $proposals);
$studygroup_ids = [];
foreach (SemClass::getClasses() as $sem_class) {
if ($sem_class['studygroup_mode'] > 0) {
foreach ($sem_class->getSemTypes() as $sem_type) {
$studygroup_ids[] = $sem_type['id'];
}
}
}
if (Request::get('search') && Request::get('search') != 1) {
$query = SQLQuery::table('seminare')
->where('search', '`name` LIKE :search', ['search' => '%' . Request::get('search') . '%'])
->where(
'studygroups',
'`seminare`.`status` IN (:sem_type_ids)',
['sem_type_ids' => $studygroup_ids]
)
->groupBy('`seminare`.`Seminar_id`');
if (count($already_covered) > 0) {
$query->where(
'ignore',
'`seminare`.`Seminar_id` NOT IN (:ignore)',
['ignore' => $already_covered]
);
}
if (!empty(Request::get('semester_id'))) {
$query->join(
'semester_courses',
'semester_courses',
'`semester_courses`.`course_id` = `seminare`.`Seminar_id`',
'LEFT JOIN'
);
$query->where(
'semester_id',
'semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL',
['semester_id' => Request::get('semester_id')]
);
}
$this->searchresults = $query->fetchAll(Course::class);
} else {
$this->my_studygroups = [];
if (!$GLOBALS['perm']->have_perm('admin')) {
$this->my_studygroups = Course::findBySQL('INNER JOIN `seminar_user` USING (`Seminar_id`)
WHERE `seminar_user`.`user_id` = :user_id
AND `seminare`.`status` IN (:studygroup_sem_types)
AND `seminare`.`Seminar_id` NOT IN (:ignore)
ORDER BY `seminare`.`name` ASC ',
[
'user_id' => User::findCurrent()->id,
'studygroup_sem_types' => $studygroup_ids,
'ignore' => count($already_covered) ? $already_covered : ''
]);
foreach ($this->my_studygroups as $my_studygroup) {
$already_covered[] = $my_studygroup->id;
}
}
//get all studygroups with a lot of members in the current course:
$statement = DBManager::get()->prepare("
SELECT `seminare`.*
FROM `seminar_user`
INNER JOIN `seminare` ON (`seminare`.`Seminar_id` = `seminar_user`.`Seminar_id`)
LEFT JOIN `seminar_user` AS `su2` ON (`su2`.`user_id` = `seminar_user`.`user_id` AND `su2`.`Seminar_id` = :course_id)
LEFT JOIN `studygroup_courses` ON (`studygroup_courses`.`studygroup_id` = `seminare`.`Seminar_id` AND `studygroup_courses`.`course_id` = `su2`.`Seminar_id`)
WHERE `seminare`.`status` IN (:studygroup_sem_types)
AND `studygroup_courses`.`id` IS NULL
GROUP BY `seminare`.`Seminar_id`
HAVING COUNT(`seminar_user`.`user_id`) > 1
ORDER BY COUNT(`seminar_user`.`user_id`) DESC
LIMIT 20
");
$statement->execute([
'course_id' => Context::getId(),
'studygroup_sem_types' => $studygroup_ids
]);
$this->suggestions = $statement->fetchAll(PDO::FETCH_ASSOC);
$this->suggestions = array_map(function ($d) {
return Course::buildExisting($d);
}, $this->suggestions);
}
}
public function remove_action($course_id)
{
if (Request::isPost() && $course_id) {
CSRFProtection::verifySecurityToken();
$connection = StudygroupCourse::deleteBySQL('course_id = ? AND studygroup_id = ?', [
Context::getId(),
$course_id
]);
PageLayout::postSuccess(_('Verknüpfung zu der Studiengruppe wurde aufgehoben.'));
}
$this->redirect('course/connectedstudygroups/index');
}
public function decline_action(StudygroupCourseProposal $proposal)
{
if (Request::isPost()) {
CSRFProtection::verifySecurityToken();
if ($GLOBALS['perm']->have_studip_perm('tutor', $proposal['course_id']) || $GLOBALS['perm']->have_studip_perm('tutor', $proposal['studygroup_id'])) {
if ($proposal['proposed_from'] === 'studygroup') {
PageLayout::postSuccess(_('Vorschlag wurde abgewiesen.'));
$statement = DBManager::get()->prepare("
SELECT `username`, `user_id`
FROM `auth_user_md5`
INNER JOIN `seminar_user` USING (`user_id`)
WHERE `seminar_user`.`Seminar_id` = ? AND `seminar_user`.`status` IN ('tutor', 'dozent')
");
$statement->execute([$proposal['studygroup_id']]);
$messaging = new messaging();
foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $user_data) {
setTempLanguage($user_data['user_id']);
$messaging->insert_message(
sprintf(
_('Ihr Vorschlag, die Studiengruppe „%1$s“ mit der Veranstaltung „%2$s“ zu verknüpfen, wurde leider abgewiesen.'),
$proposal->studygroup->getFullname(),
Context::get()->getFullname()
),
$user_data['username'],
'____%system%____',
'',
'',
'',
'',
_('Verknüpfungsvorschlag abgewiesen'),
'',
'normal',
['Studiengruppe']
);
restoreLanguage();
}
} else {
PageLayout::postSuccess(_('Vorschlag wurde zurückgezogen.'));
}
$proposal->delete();
}
}
$this->redirect('course/connectedstudygroups/index');
}
protected function buildSidebar()
{
$actions = new ActionsWidget();
$actions->addLink(
_('Studiengruppe verknüpfen'),
$this->url_for('course/connectedstudygroups/connect'),
Icon::create('add'),
['data-dialog' => 1]
);
Sidebar::Get()->addWidget($actions);
}
}
......@@ -51,10 +51,10 @@ class Course_ContentmodulesController extends AuthenticatedController
$this->categories[] = $module['category'];
}
if (!$module['category']) {
if (!in_array(_('Sonstige'), $this->categories)) {
$this->categories[] = _('Sonstige');
if (!in_array(_('Sonstiges'), $this->categories)) {
$this->categories[] = _('Sonstiges');
}
$this->modules[$i]['category'] = _('Sonstige');
$this->modules[$i]['category'] = _('Sonstiges');
}
}
sort($this->categories);
......@@ -83,37 +83,37 @@ class Course_ContentmodulesController extends AuthenticatedController
Sidebar::Get()->addWidget($widget);
}
PageLayout::addHeadElement('script', [
'type' => 'text/javascript',
], sprintf(
'window.ContentModulesStoreData = %s;',
json_encode([
'setCategories' => $this->categories,
'setHighlighted' => $this->highlighted_modules,
'setModules' => array_values($this->modules),
'setUserId' => User::findCurrent()->id,
'setView' => $GLOBALS['user']->cfg->CONTENTMODULES_TILED_DISPLAY ? 'tiles' : 'table',
])
));
$this->render_vue_app(
Studip\VueApp::create('ContentModules')
->withProps([
'range-type' => get_class($this->sem),
])
->withVuexStore('ContentModulesStore', 'contentmodules', [
'setCategories' => $this->categories,
'setHighlighted' => $this->highlighted_modules,
'setModules' => array_values($this->modules),
'setUserId' => User::findCurrent()->id,
'setView' => $GLOBALS['user']->cfg->CONTENTMODULES_TILED_DISPLAY ? 'tiles' : 'table',
])
);
}
public function trigger_action()
{
$context = Context::get();
$required_perm = $context->getRangeType() === 'course' ? 'tutor' : 'admin';
if (!$GLOBALS['perm']->have_studip_perm($required_perm, $context->id)) {
if (!$context->isEditableByUser()) {
throw new AccessDeniedException();
}
if (Request::isPost()) {
if ($context->getRangeType() === 'course') {
if ($context instanceof Course) {
$sem_class = $context->getSemClass();
} else {
$sem_class = SemClass::getDefaultInstituteClass($context->type);
}
$moduleclass = Request::get('moduleclass');
$active = Request::bool('active', false);
$module = new $moduleclass;
$module = PluginEngine::getPlugin($moduleclass);
if ($module->isActivatableForContext($context)) {
PluginManager::getInstance()->setPluginActivated($module->getPluginId(), $context->getId(), $active);
}
......@@ -128,6 +128,7 @@ class Course_ContentmodulesController extends AuthenticatedController
$this->redirect("course/contentmodules/trigger", ['cid' => $context->getId(), 'plugin_id' => $module->getPluginId()]);
return;
}
$active_tool = ToolActivation::find([$context->id, Request::int('plugin_id')]);
$template = $GLOBALS['template_factory']->open('tabs.php');
$template->navigation = Navigation::getItem('/course');
......@@ -141,11 +142,10 @@ class Course_ContentmodulesController extends AuthenticatedController
public function reorder_action()
{
$context = Context::get();
$required_perm = $context->getRangeType() === 'course' ? 'tutor' : 'admin';
if (!$GLOBALS['perm']->have_studip_perm($required_perm, $context->id)) {
if (!$context->isEditableByUser()) {
throw new AccessDeniedException();
}
if (Request::isPost()) {
$position = 0;
foreach (Request::getArray('order') as $plugin_id) {
......@@ -156,6 +156,7 @@ class Course_ContentmodulesController extends AuthenticatedController
$this->redirect($this->reorderURL());
return;
}
Navigation::getItem('/course/admin')->setActive(true);
$template = $GLOBALS['template_factory']->open('tabs.php');
$template->navigation = Navigation::getItem('/course');
......@@ -169,14 +170,14 @@ class Course_ContentmodulesController extends AuthenticatedController
if (!Request::isPost()) {
throw new AccessDeniedException();
}
$context = Context::get();
$required_perm = $context->getRangeType() === 'course' ? 'tutor' : 'admin';
if (!$GLOBALS['perm']->have_studip_perm($required_perm, $context->id)) {
$context = Context::get();
if (!$context->isEditableByUser()) {
throw new AccessDeniedException();
}
$moduleclass = Request::get('moduleclass');
$module = new $moduleclass;
$module = PluginEngine::getPlugin($moduleclass);
$active_tool = ToolActivation::find([$context->id, $module->getPluginId()]);
$metadata = $active_tool->metadata->getArrayCopy();
......@@ -207,15 +208,18 @@ class Course_ContentmodulesController extends AuthenticatedController
public function rename_action($module_id)
{
$context = Context::get();
$required_perm = $context->getRangeType() === 'course' ? 'tutor' : 'admin';
if (!$GLOBALS['perm']->have_studip_perm($required_perm, $context->id)) {
if (!$context->isEditableByUser()) {
throw new AccessDeniedException();
}
$this->module = PluginManager::getInstance()->getPluginById($module_id);
$this->metadata = $this->module->getMetadata();
$this->original_name = $this->metadata['displayname'] ?? $this->module->getPluginName();
PageLayout::setTitle(_('Werkzeug umbenennen'));
$this->tool = ToolActivation::find([$context->id, $module_id]);
if (Request::isPost()) {
$metadata = $this->tool->metadata->getArrayCopy();
if (!trim(Request::get('displayname')) || Request::submitted('delete')) {
......@@ -255,20 +259,25 @@ class Course_ContentmodulesController extends AuthenticatedController
}
if (isset($this->metadata['screenshots'])) {
foreach ($this->metadata['screenshots']['pictures'] as $picture) {
$title = $picture['title'];
$title = $picture['title'] ?? '';
$source = "{$this->plugin->getPluginURL()}/{$this->metadata['screenshots']['path']}/{$picture['source']}";
$this->screenshots[] = compact('title', 'source');
}
}
PageLayout::setTitle(sprintf(_('Informationen über %s'), $this->metadata['displayname']));
$this->metadata['icon'] = $this->getIconFromMetadata($this->metadata, $this->plugin);
PageLayout::setTitle(sprintf(
_('Informationen über %s'),
$this->metadata['displayname'] ?? $this->plugin->getPluginName()
));
}
private function getModules(Range $context)
{
$list = [];
foreach (PluginEngine::getPlugins('StudipModule') as $plugin) {
foreach (PluginEngine::getPlugins(StudipModule::class) as $plugin) {
if (!$plugin->isActivatableForContext($context)) {
continue;
}
......@@ -291,33 +300,67 @@ class Course_ContentmodulesController extends AuthenticatedController
$visibility = $tool ? $tool->getVisibilityPermission() : 'nobody';
$metadata = $plugin->getMetadata();
$icon = $this->getIconFromMetadata($metadata, $plugin);
$list[$plugin_id] = [
'id' => $plugin_id,
'moduleclass' => get_class($plugin),
'position' => $tool ? $tool->position : null,
'toolname' => $toolname,
'displayname' => $displayname,
'visibility' => $visibility,
'active' => (bool) $tool,
'id' => $plugin_id,
'moduleclass' => get_class($plugin),
'position' => $tool ? $tool->position : null,
'toolname' => $toolname,
'displayname' => $displayname,
'visibility' => $visibility,
'active' => (bool) $tool,
'icon' => $icon ? $icon->asImagePath() : null,
'summary' => $metadata['summary'] ?? null,
'mandatory' => $this->sem_class->isModuleMandatory(get_class($plugin)),
'highlighted' => (bool) $plugin->isHighlighted(),
'highlight_text' => $plugin->getHighlightText(),
'category' => $metadata['category'] ?? null,
];
if (!empty($metadata['icon_clickable'])) {
$list[$plugin_id]['icon'] = $metadata['icon_clickable'] instanceof Icon
? $metadata['icon_clickable']->asImagePath()
: Icon::create($plugin->getPluginURL().'/'.$metadata['icon_clickable'])->asImagePath();
} elseif (!empty($metadata['icon'])) {
$list[$plugin_id]['icon'] = $metadata['icon'] instanceof Icon
? $metadata['icon']->asImagePath()
: Icon::create($plugin->getPluginURL().'/'.$metadata['icon'])->asImagePath();
} else {
$list[$plugin_id]['icon'] = null;
}
$list[$plugin_id]['summary'] = $metadata['summary'] ?? null;
$list[$plugin_id]['mandatory'] = $this->sem_class->isModuleMandatory(get_class($plugin));
$list[$plugin_id]['highlighted'] = (bool) $plugin->isHighlighted();
$list[$plugin_id]['highlight_text'] = $plugin->getHighlightText();
$list[$plugin_id]['category'] = $metadata['category'] ?? null;
}
return $list;
}
/**
* @param array $metadata
* @param CorePlugin|StudIPPlugin $plugin
*/
private function getIconFromMetadata(array $metadata, $plugin): ?Icon
{
$icon = $metadata['icon_clickable'] ?? $metadata['icon'] ?? null;
if (!$icon) {
return null;
}
if ($plugin instanceof StudIPPlugin && str_starts_with($icon, '..')) {
$path = $GLOBALS['ABSOLUTE_PATH_STUDIP'] . '/' . $plugin->getPluginPath() . '/' . $icon;
$icon = $this->getCoreIcon($path) ?? $icon;
}
if (!$icon instanceof Icon) {
$icon = Icon::create($plugin->getPluginURL() . '/' . $icon);
}
return $icon->copyWithRole(Icon::ROLE_CLICKABLE);
}
private function getCoreIcon(string $path): ?Icon
{
$path = realpath($path);
if (!file_exists($path)) {
return null;
}
try {
$icon = basename($path, '.svg');
$color = basename(dirname($path));
$roles = Icon::colorToRoles($color);
return Icon::create($icon, $roles[0]);
} catch (Exception $e) {
return null;
}
}
}
......@@ -23,7 +23,7 @@ class Course_CoursewareController extends CoursewareController
if (!Context::get()) {
throw new CheckObjectException(_('Sie haben kein Objekt gewählt.'));
}
PageLayout::setTitle(Context::get()->getFullname() . ' - ' . _('Courseware'));
PageLayout::setTitle(Context::get()->getFullName() . ' - ' . _('Courseware'));
PageLayout::setHelpKeyword('Basis.Courseware');
checkObject();
......@@ -46,28 +46,31 @@ class Course_CoursewareController extends CoursewareController
public function index_action(): void
{
$this->isTeacher = $GLOBALS['perm']->have_studip_perm(
'tutor',
Context::getId(),
$GLOBALS['user']->id
);
Navigation::activateItem('course/courseware/shelf');
$this->setIndexSidebar();
}
public function courseware_action($unit_id = null): void
{
global $user;
Navigation::activateItem('course/courseware/unit');
if ($this->unitsNotFound) {
PageLayout::postMessage(MessageBox::info(_('Es wurde kein Lernmaterial gefunden.')));
return;
}
$user = User::findCurrent();
$this->setCoursewareSidebar();
$this->user_id = $user->id;
/** @var array<mixed> $last */
$last = UserConfig::get($this->user_id)->getValue('COURSEWARE_LAST_ELEMENT');
$last = UserConfig::get($user->id)->getValue('COURSEWARE_LAST_ELEMENT');
$lastStructuralElement = \Courseware\StructuralElement::findOneById($last);
if ($unit_id === null) {
if (isset($lastStructuralElement) && $lastStructuralElement->canVisit(User::findCurrent())) {
if (isset($lastStructuralElement) && $lastStructuralElement->canVisit($user)) {
$this->redirectToFirstUnit('course', Context::getId(), $last);
} else {
$this->redirectToFirstUnit('course', Context::getId(), []);
......@@ -90,30 +93,36 @@ class Course_CoursewareController extends CoursewareController
public function tasks_action($route = null): void
{
$this->is_teacher = $GLOBALS['perm']->have_studip_perm(
$this->isTeacher = $GLOBALS['perm']->have_studip_perm(
'tutor',
Context::getId(),
$GLOBALS['user']->id
);
Navigation::activateItem('course/courseware/tasks');
PageLayout::setTitle(_('Courseware: Aufgaben'));
switch ($route) {
case 'peer-review-processes':
Navigation::activateItem('course/courseware/peer-review');
PageLayout::setTitle(_('Courseware: Peer-Review-Prozesse'));
break;
default:
Navigation::activateItem('course/courseware/tasks');
PageLayout::setTitle(_('Courseware: Aufgaben'));
break;
}
$this->setTasksSidebar();
}
public function activities_action(): void
{
global $perm, $user;
$this->is_teacher = $perm->have_studip_perm('tutor', Context::getId(), $user->id);
Navigation::activateItem('course/courseware/activities');
$this->setActivitiesSidebar();
}
public function pdf_export_action($element_id, $with_children): void
public function pdf_export_action(Courseware\StructuralElement $element, bool $with_children = false): void
{
$element = \Courseware\StructuralElement::findOneById($element_id);
$user = User::find($GLOBALS['user']->id);
$this->render_pdf($element->pdfExport($user, $with_children), trim($element->title).'.pdf');
$this->render_pdf(
$element->pdfExport(User::findCurrent(), $with_children),
trim($element->title).'.pdf'
);
}
public function comments_overview_action(): void
......
<?php
require_once 'lib/raumzeit/raumzeit_functions.inc.php';
class Course_DatesController extends AuthenticatedController
{
......@@ -15,7 +14,7 @@ class Course_DatesController extends AuthenticatedController
$this->course = Context::get();
if ($this->course) {
PageLayout::setTitle($this->course->getFullname() . ' ' . _('Termine'));
PageLayout::setTitle($this->course->getFullName() . ' ' . _('Termine'));
} else {
PageLayout::setTitle(_('Termine'));
}
......@@ -55,6 +54,7 @@ class Course_DatesController extends AuthenticatedController
$this->assignLockRulesToTemplate();
$this->last_visitdate = object_get_visit($this->course->id, $this->studip_module->getPluginId());
$semester_id = Request::get('semester_id');
$semester = null;
if ($semester_id != 'all') {
......@@ -79,8 +79,11 @@ class Course_DatesController extends AuthenticatedController
Icon::create('add')
)->asDialog();
}
if (Seminar::setInstance(new Seminar(Course::findCurrent()))->getSlotModule('documents') && CourseDateFolder::availableInRange(Course::findCurrent(), User::findCurrent()->id)) {
if (
Course::exists(Context::getId())
&& $this->course->isToolActive(CoreDocuments::class)
&& CourseDateFolder::availableInRange($this->course, User::findCurrent()->id)
) {
$actions->addLink(
_('Sitzungsordner anlegen'),
$this->url_for('course/dates/create_folders'),
......@@ -98,24 +101,30 @@ class Course_DatesController extends AuthenticatedController
$this->url_for('course/dates/export_csv'),
Icon::create('file-excel')
);
if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) {
$actions->addLink(
_('Laufende Termine'),
$this->url_for('course/dates/current_day_dates'),
Icon::create('date')
)->asDialog();
}
$sidebar->addWidget($actions);
$course_end_time = $this->course->getEnd_Time();
if (($course_end_time == -1) || ($course_end_time > 0)) {
if (count($this->course->semesters) !== 1) {
//The course has more than one semester:
$semester_widget = new SemesterSelectorWidget(
$this->url_for('course/dates/index')
);
$semester_end_range = $course_end_time;
if ($semester_end_range == -1) {
//The end semester is set to unlimited.
$semester_end_range = PHP_INT_MAX;
}
$semester_widget->includeAll();
$semester_widget->setRange(
$this->course->start_time,
$semester_end_range
);
if ($this->course->start_semester && $this->course->end_semester) {
$semester_widget->setRange(
$this->course->start_semester->beginn,
$this->course->end_semester->ende
);
}
$sidebar->addWidget($semester_widget);
}
......@@ -129,6 +138,42 @@ class Course_DatesController extends AuthenticatedController
}
}
public function current_day_dates_action()
{
if (!$this->hasAccess() || !Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) {
throw new AccessDeniedException();
}
if (Request::isPost()) {
CSRFProtection::verifyUnsafeRequest();
foreach (Request::getArray('termin_id') as $index => $terminId) {
$numberOfParticipants = Request::intArray('number_of_participants')[$index];
if ($numberOfParticipants < 0) {
continue;
}
$courseDate = CourseDate::find($terminId);
$courseDate->number_of_participants = $numberOfParticipants;
$courseDate->store();
}
PageLayout::postSuccess(_('Die Anzahl der Teilnehmenden wurde gespeichert.'));
$this->redirect($this->indexURL());
}
$beginOfDay = strtotime('today 00:00:00');
$endOfDay = strtotime('today 23:59:59');
$this->dates = $this->course->getDatesWithExdates($beginOfDay, $endOfDay);
$resourceId = Request::option('resource_id');
if ($resourceId) {
$this->dates = $this->dates->filter(function ($date) use ($resourceId) {
return $date->room_booking->resource_id === $resourceId;
});
}
}
/**
* This method is called to show the dialog to edit a date for a course.
......@@ -143,7 +188,7 @@ class Course_DatesController extends AuthenticatedController
Navigation::activateItem('/course/schedule/dates');
PageLayout::setTitle(
$this->date->getTypeName() . ': ' .
$this->date->getFullname(CourseDate::FORMAT_VERBOSE)
$this->date->getFullName(CourseDate::FORMAT_VERBOSE)
);
if ($this->hasAccess()) {
......@@ -168,7 +213,7 @@ class Course_DatesController extends AuthenticatedController
Navigation::activateItem('/course/schedule/dates');
PageLayout::setTitle(
$this->date->getTypeName() . ': ' .
$this->date->getFullname(CourseDate::FORMAT_VERBOSE)
$this->date->getFullName(CourseDate::FORMAT_VERBOSE)
);
$this->render_action('details');
}
......@@ -224,7 +269,7 @@ class Course_DatesController extends AuthenticatedController
}
} elseif ($termin_id) {
$this->date = new CourseDate($termin_id);
$xtitle = $this->date->getTypeName() . ': ' . $this->date->getFullname();
$xtitle = $this->date->getTypeName() . ': ' . $this->date->getFullName();
} else {
$this->date = new CourseDate();
......@@ -249,6 +294,10 @@ class Course_DatesController extends AuthenticatedController
if ($termin) {
$termin->date_typ = Request::get('dateType');
if (Config::get()->ENABLE_NUMBER_OF_PARTICIPANTS) {
$termin->number_of_participants = strlen(Request::get('number_of_participants')) && Request::int('number_of_participants') >= 0 ? Request::int('number_of_participants') : null;
}
// Assign teachers
$assigned_teachers = Request::optionArray('assigned_teachers');
$current_count = CourseMember::countByCourseAndStatus(
......@@ -364,55 +413,59 @@ class Course_DatesController extends AuthenticatedController
public function export_action()
{
$sem = new Seminar($this->course);
$themen =& $sem->getIssues();
$termine = getAllSortedSingleDates($sem);
$termine = $this->course->getAllDatesInSemester()->getSingleDates(true, true, true);
$dates = [];
if (is_array($termine) && sizeof($termine) > 0) {
foreach ($termine as $singledate_id => $singledate) {
if (!$singledate->isExTermin()) {
$tmp_ids = $singledate->getIssueIDs();
$title = $description = '';
if (is_array($tmp_ids)) {
$title = trim(join("\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getTitle();}, $tmp_ids)));
$description = trim(join("\n\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getDescription();}, $tmp_ids)));
}
$dates[] = [
'date' => $singledate->toString(),
'title' => $title,
'description' => $description,
'start' => $singledate->getStartTime(),
'related_persons' => $singledate->getRelatedPersons(),
'groups' => $singledate->getRelatedGroups(),
'room' => $singledate->getRoom() ?: $singledate->raum,
'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name']
];
} elseif ($singledate->getComment()) {
$dates[] = [
'date' => $singledate->toString(),
'title' => _('fällt aus') . ' (' . _('Kommentar:') . ' ' . $singledate->getComment() . ')',
'description' => '',
'start' => $singledate->getStartTime(),
'related_persons' => [],
'groups' => [],
'room' => '',
'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name']
];
}
foreach ($termine as $singledate) {
if ($singledate instanceof CourseDate) {
$title = trim(implode(
"\n",
$singledate->topics->filter(function (CourseTopic $topic): bool {
return trim($topic->title) !== '';
})->map(function (CourseTopic $topic): string {
return trim($topic->title);
})
));
$description = trim(implode(
"\n\n",
$singledate->topics->filter(function (CourseTopic $topic): bool {
return trim($topic->description) !== '';
})->map(function (CourseTopic $topic): string {
return trim($topic->description);
})
));
$dates[] = [
'date' => (string) $singledate,
'title' => $title,
'description' => $description,
'start' => $singledate->date,
'related_persons' => $singledate->dozenten,
'groups' => $singledate->statusgruppen,
'room' => (string) ($singledate->getRoom() ?? $singledate->raum),
'type' => $GLOBALS['TERMIN_TYP'][$singledate->date_typ]['name'],
];
} elseif ($singledate instanceof CourseExDate && $singledate->content) {
$dates[] = [
'date' => (string) $singledate,
'title' => _('fällt aus') . ' (' . _('Kommentar:') . ' ' . $singledate->content . ')',
'description' => '',
'start' => $singledate->date,
'related_persons' => [],
'groups' => [],
'room' => '',
'type' => $GLOBALS['TERMIN_TYP'][$singledate->date_typ]['name'],
];
}
}
$factory = $this->get_template_factory();
$template = $factory->open($this->get_default_template('export'));
$template->set_attribute('dates', $dates);
$template->lecturer_count = $this->course->countMembersWithStatus('dozent');
$template->group_count = count($this->course->statusgruppen);
$content = $template->render();
$content = $template->render([
'dates' => $dates,
'lecturer_count' => $this->course->countMembersWithStatus('dozent'),
'group_count' => count($this->course->statusgruppen),
]);
$content = mb_encode_numericentity($content, [0x80, 0xffff, 0, 0xffff], 'utf-8');
$filename = FileManager::cleanFileName($this->course['name'] . '-' . _('Ablaufplan') . '.doc');
......@@ -431,10 +484,6 @@ class Course_DatesController extends AuthenticatedController
*/
public function export_csv_action()
{
$sem = new Seminar($this->course);
$dates = getAllSortedSingleDates($sem);
$issues = $sem->getIssues();
$columns = [
_('Wochentag'),
_('Termin'),
......@@ -447,14 +496,16 @@ class Course_DatesController extends AuthenticatedController
_('Gruppen'),
_('Raum'),
_('Raumbeschreibung'),
_('Sitzplätze')
_('Sitzplätze'),
_('Teilnehmende')
];
$data = [$columns];
$dates = $this->course->getAllDatesInSemester()->getSingleDates(true, true, true);
foreach ($dates as $date) {
// FIXME this should not be necessary, see https://develop.studip.de/trac/ticket/8101
if ($date->isExTermin() && $date->getComment() == '') {
if ($date instanceof CourseExDate && trim($date->content) === '') {
continue;
}
......@@ -465,49 +516,37 @@ class Course_DatesController extends AuthenticatedController
$row[] = strftime('%H:%M', $date->end_time);
$row[] = $date->getTypeName();
if ($date->isExTermin()) {
$row[] = $date->getComment();
if ($date instanceof CourseExDate) {
$row[] = trim($date->content);
$row[] = '';
} else {
$issue = $descr = '';
foreach ((array) $date->getIssueIDs() as $id) {
$issue .= $issues[$id]->getTitle() . "\n";
$descr .= kill_format($issues[$id]->getDescription()) . "\n";
foreach ($date->topics as $topic) {
$issue .= trim($topic->title) . "\n";
$descr .= kill_format($topic->description) . "\n";
}
$row[] = trim($issue);
$row[] = trim($descr);
}
$related_persons = '';
if ($date->related_persons) {
foreach ($date->related_persons as $user_id) {
$related_persons .= User::find($user_id)->getFullname() . "\n";
}
}
$row[] = trim($related_persons);
$related_groups = '';
if ($date->related_groups) {
foreach ($date->related_groups as $group_id) {
$related_groups .= Statusgruppen::find($group_id)->name . "\n";
}
}
$row[] = implode(
"\n",
$date->dozenten->map(function (User $user) {
return $user->getFullName();
})
);
$row[] = trim($related_groups);
$row[] = implode(
"\n",
$date->statusgruppen->map(function (Statusgruppen $group) {
return $group->name;
})
);
$room = null;
if ($date->resource_id) {
$resource_object = Resource::find($date->resource_id);
if ($resource_object) {
$room = $resource_object->getDerivedClassInstance();
}
}
if ($room instanceof Room) {
$room = $date->getRoom();
if ($room) {
$row[] = $room->name;
$row[] = $room->description;
$row[] = $room->seats;
......@@ -517,10 +556,12 @@ class Course_DatesController extends AuthenticatedController
$row[] = '';
}
$row[] = $date->number_of_participants;
$data[] = $row;
}
$filename = $sem->name . '-' . _('Ablaufplan') . '.csv';
$filename = $this->course->name . '-' . _('Ablaufplan') . '.csv';
$this->render_csv($data, $filename);
}
......@@ -605,16 +646,16 @@ class Course_DatesController extends AuthenticatedController
$this->previously_selected_dates = $this->course_date_folders;
if (count($dates_with_folders) === 1) {
PageLayout::postWarning(sprintf(
_('Für den Termin am %s existiert bereits ein Sitzungs-Ordner. Möchten Sie trotzdem einen weiteren Sitzungs-Ordner erstellen?'),
htmlReady($dates_with_folders[0]->getFullname())
_('Für den Termin am %s existiert bereits ein Sitzungsordner. Möchten Sie trotzdem einen weiteren Sitzungsordner erstellen?'),
htmlReady($dates_with_folders[0]->getFullName())
));
} else {
$dates_string = [];
foreach ($dates_with_folders as $date) {
$dates_string[] = $date->getFullname();
$dates_string[] = $date->getFullName();
}
PageLayout::postWarning(
_('Für die folgenden Termine gibt es bereits Sitzungs-Ordner. Möchten Sie trotzdem weitere Sitzungs-Ordner erstellen?'),
_('Für die folgenden Termine gibt es bereits Sitzungsordner. Möchten Sie trotzdem weitere Sitzungsordner erstellen?'),
array_map('htmlReady', $dates_string)
);
}
......
......@@ -32,14 +32,14 @@ class Course_DetailsController extends AuthenticatedController
$this->course = Course::find($course_id);
if (!$this->course) {
throw new Trails_Exception(
throw new Trails\Exception(
404,
_('Es konnte keine Veranstaltung gefunden werden')
);
}
$this->send_from_search_page = Request::get('send_from_search_page');
if ($GLOBALS['SessionSeminar'] != $this->course->id
if (isset($GLOBALS['SessionSeminar']) && $GLOBALS['SessionSeminar'] != $this->course->id
&& !(int)$this->course->visible
&& !($GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)
|| $GLOBALS['perm']->have_studip_perm('user', $this->course->id))) {
......@@ -52,7 +52,7 @@ class Course_DetailsController extends AuthenticatedController
if ($this->course->getSemClass()->offsetGet('studygroup_mode')) {
if ($GLOBALS['perm']->have_studip_perm('autor', $this->course->id)) { // participants may see seminar_main
$link = URLHelper::getUrl('seminar_main.php', ['auswahl' => $this->course->id]);
$link = URLHelper::getUrl('dispatch.php/course/go', ['to' => $this->course->id]);
} else {
$link = URLHelper::getUrl('dispatch.php/course/studygroup/details/' . $this->course->id, [
'send_from_search_page' => $this->send_from_search_page,
......@@ -68,9 +68,8 @@ class Course_DetailsController extends AuthenticatedController
public function index_action()
{
$this->prelim_discussion = vorbesprechung($this->course->id);
$this->title = $this->course->getFullname();
$this->title = $this->course->getFullName();
$this->course_domains = UserDomain::getUserDomainsForSeminar($this->course->id);
$this->sem = new Seminar($this->course);
$this->links = [];
//public folders
......@@ -99,11 +98,9 @@ class Course_DetailsController extends AuthenticatedController
// Ausgabe der Modulzuordnung MVV
if ($this->course->getSemClass()->offsetGet('module')) {
$course_start = $this->course->start_time;
$course_end = ($this->course->end_time < 0 || is_null($this->course->end_time))
? PHP_INT_MAX
: $this->course->end_time;
// set filter to show only pathes with valid semester data
$course_start = $this->course->start_semester?->beginn ?? 0;
$course_end = $this->course->end_semester?->ende ?? PHP_INT_MAX;
//Set the filter to show only paths with valid semester data:
ModuleManagementModelTreeItem::setObjectFilter('Modul',
function ($modul) use ($course_start, $course_end) {
// check for public status
......@@ -199,15 +196,15 @@ class Course_DetailsController extends AuthenticatedController
} else {
PageLayout::setHelpKeyword('Basis.InVeranstaltungDetails');
PageLayout::setTitle($this->title . ' - ' . _('Details'));
PageLayout::addScript('studip-admission.js');
$sidebar = Sidebar::Get();
if ($GLOBALS['SessionSeminar'] === $this->course->id) {
$enrolment_info = null;
if (isset($GLOBALS['SessionSeminar']) && $GLOBALS['SessionSeminar'] === $this->course->id) {
Navigation::activateItem('/course/main/details');
} else {
$sidebarlink = true;
$enrolment_info = $this->sem->getEnrolmentInfo($GLOBALS['user']->id);
$enrolment_info = $this->course->getEnrolmentInformation($GLOBALS['user']->id);
}
$links = new ActionsWidget();
......@@ -217,12 +214,12 @@ class Course_DetailsController extends AuthenticatedController
Icon::create('print'),
['class' => 'print_action', 'target' => '_blank']
);
if (isset($enrolment_info) && $enrolment_info['enrolment_allowed'] && $sidebarlink) {
if (in_array($enrolment_info['cause'], ['member', 'root', 'courseadmin'])) {
$abo_msg = _('direkt zur Veranstaltung');
if ($enrolment_info && $enrolment_info->isEnrolmentAllowed()) {
if (in_array($enrolment_info->getCodeword(), ['already_member', 'root', 'course_admin'])) {
$abo_msg = _('Direkt zur Veranstaltung');
} else {
$abo_msg = _('Zugang zur Veranstaltung');
if ($this->sem->admission_binding) {
if ($this->course->admission_binding) {
PageLayout::postInfo(_('Die Anmeldung ist verbindlich, Teilnehmende können sich nicht selbst austragen.'));
}
}
......@@ -244,25 +241,25 @@ class Course_DetailsController extends AuthenticatedController
if (Config::get()->SCHEDULE_ENABLE
&& !$GLOBALS['perm']->have_studip_perm('user', $this->course->id)
&& !$GLOBALS['perm']->have_perm('admin')
&& $this->sem->getMetaDateCount()
&& count($this->course->cycles)
) {
$query = "SELECT 1
FROM `schedule_seminare`
WHERE `seminar_id` = ? AND `user_id` = ?";
FROM `schedule_courses`
WHERE `course_id` = ? AND `user_id` = ?";
$penciled = DBManager::Get()->fetchColumn($query, [
$this->course->id,
$GLOBALS['user']->id,
]);
if (!$penciled) {
$links->addLink(
_('Nur im Stundenplan vormerken'),
$this->url_for("calendar/schedule/addvirtual/{$this->course->id}"),
_('Zum Stundenplan hinzufügen'),
$this->url_for('calendar/schedule/mark_course', $this->course),
Icon::create('info')
);
$this->links[] = [
'label' => _('Nur im Stundenplan vormerken'),
'url' => $this->url_for("calendar/schedule/addvirtual/{$this->course->id}"),
'label' => _('Zum Stundenplan hinzufügen'),
'url' => $this->url_for('calendar/schedule/mark_course', $this->course),
'attributes' => [],
];
}
......@@ -303,8 +300,8 @@ class Course_DetailsController extends AuthenticatedController
);
$sidebar->addWidget($share);
if (isset($enrolment_info) && $enrolment_info['description']) {
PageLayout::postInfo($enrolment_info['description']);
if ($enrolment_info) {
PageLayout::postMessage($enrolment_info->toMessageBox());
}
}
}
......
<?php
/**
* Elearning Interface für Veranstaltungen/ Einrichtungen
*
* 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 Arne Schröder <schroeder@data-quest.de>
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
* @since 3.1
*/
class Course_ElearningController extends AuthenticatedController
{
/**
* Before filter, set up the page by initializing the session and checking
* all conditions.
*
* @param String $action Name of the action to be invoked
* @param Array $args Arguments to be passed to the action method
*/
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
if (!Config::Get()->ELEARNING_INTERFACE_ENABLE ) {
throw new AccessDeniedException(_('Elearning-Interface ist nicht aktiviert.'));
} else
$this->elearning_active = true;
PageLayout::setHelpKeyword('Basis.Ilias');
PageLayout::setTitle(Context::getHeaderLine(). " - " . _("Lernmodule"));
checkObject(); // do we have an open object?
$module = checkObjectModule('ElearningInterface');
object_set_visit_module($module->getPluginId());
$this->search_key = Request::get('search_key');
$GLOBALS['search_key'] = $this->search_key;
$this->cms_select = Request::quoted('cms_select');
$GLOBALS['cms_select'] = $this->cms_select;
$this->open_all = Request::get('open_all');
$this->close_all = Request::get('close_all');
$this->new_account_cms = Request::get('new_account_cms');
$this->module_system_type = Request::get('module_system_type');
$this->module_id = Request::get('module_id');
$this->module_type = Request::get('module_type');
$this->anker_target = Request::get('anker_target');
$this->seminar_id = Context::getId();
$this->rechte = $GLOBALS['perm']->have_studip_perm('tutor', $this->seminar_id);
if (!isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->new_account_cms])) {
unset($this->new_account_cms);
}
if (!isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_select])) {
unset($this->cms_select);
}
if (
isset($_SESSION['elearning_open_close']['id'])
&& $this->seminar_id !== $_SESSION['elearning_open_close']['id']
) {
unset($_SESSION['cache_data']);
unset($_SESSION['elearning_open_close']);
}
if ($this->open_all != "")
$_SESSION['elearning_open_close']["all open"] = true;
elseif ($this->close_all != "")
$_SESSION['elearning_open_close']["all open"] = "";
$_SESSION['elearning_open_close']["type"] = "seminar";
$_SESSION['elearning_open_close']["id"] = $this->seminar_id;
if (Request::get('do_open')) {
$this->anker_target = Request::get('do_open');
$_SESSION['elearning_open_close'][Request::get('do_open')] = true;
} elseif (Request::get('do_close')) {
$this->anker_target = Request::get('do_close');
$_SESSION['elearning_open_close'][Request::get('do_close')] = false;
}
$this->sidebar = Sidebar::get();
$this->sidebar->setContextAvatar(CourseAvatar::getAvatar($this->seminar_id));
}
/**
* Displays a page.
*/
public function show_action($id = null)
{
global $connected_cms, $current_module;
Navigation::activateItem('/course/elearning/show');
$GLOBALS['view'] = 'show';
// Zugeordnete Ilias-Kurse ermitteln und ggf. aktualisieren
$this->course_output = ELearningUtils::getIliasCourses($this->seminar_id);
if (!empty($this->new_account_cms)) {
//Dummy-Instanz der Zuordnungs-Klasse ohne Verbindung zur Veranstaltung
$object_connections = new ObjectConnections();
} else {
//Instanz mit den Zuordnungen von Content-Modulen zur Veranstaltung
$object_connections = new ObjectConnections($this->seminar_id);
$connected_modules = $object_connections->getConnections();
}
$this->module_count = 0;
$content_modules_list = [];
if ($object_connections->isConnected()) {
$caching_active = true;
$type_tmp = [];
if (!empty($connected_modules)) {
foreach ($connected_modules as $key => $connection) {
if (ELearningUtils::isCMSActive($connection["cms"])) {
ELearningUtils::loadClass($connection["cms"]);
$connected_cms[$connection["cms"]]->newContentModule($connection["id"], $connection["type"], true);
$connected_modules[$key]['title'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getTitle();
$title_tmp[$key] = str_replace(['ä','ö','ü','ß'],['ae','oe','ue','ss'],mb_strtolower($connected_modules[$key]['title']));
$type_tmp[$key] = array_search($connection['type'], array_keys($GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]['types']));
$class_tmp[$key] = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]["CLASS_PREFIX"];
}
}
}
array_multisort($class_tmp, SORT_ASC, $type_tmp, SORT_ASC, $title_tmp, SORT_ASC, $connected_modules);
foreach ($connected_modules as $index => $connection) {
$current_module = $connection["id"];
if ($this->module_count == 0)
$content_modules_list[$index]['show_header'] = true;
$this->module_count++;
$this->module_system_count[$connection["cms"]]++;
if ($this->open_all != "")
$_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = true;
elseif ($this->close_all != "")
$_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = false;
$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->view->setChangeDate($connection["chdate"]);
$content_modules_list[$index]['module'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->view->show();
}
}
if (!$this->module_count && !$this->new_account_cms) {
if (Context::isInstitute()) {
PageLayout::postInfo(_('Momentan sind dieser Einrichtung keine Lernmodule zugeordnet.'));
} else {
PageLayout::postInfo(_('Momentan sind dieser Veranstaltung keine Lernmodule zugeordnet.'));
}
}
$widget = new ActionsWidget();
$widget->addLink(
_('Externe Accounts verwalten'),
URLHelper::getURL('dispatch.php/elearning/my_accounts'),
Icon::create('person')
);
if ($this->course_output['courses'])
foreach ($this->course_output['courses'] as $course) {
$widget->addLink(
sprintf(_('Direkt zum Kurs in %s'), $course['cms_name']),
$course['url'],
Icon::create('link-extern'),
['target' => '_blank', 'rel' => 'noopener noreferrer']
);
}
$this->sidebar->addWidget($widget);
$this->new_account = $this->new_account_cms;
$this->content_modules = $content_modules_list;
}
/**
* Displays a page.
*/
public function edit_action($id = null)
{
global $connected_cms, $current_module;
if (!$this->rechte) {
throw new AccessDeniedException();
}
Navigation::activateItem('/course/elearning/edit');
$GLOBALS['view'] = 'edit';
// ggf. neuen Ilias4-Kurs anlegen
if (Request::submitted('create_course') AND $this->rechte) {
ELearningUtils::loadClass($this->cms_select);
if ((method_exists($connected_cms[$this->cms_select], "createCourse")))
if ($connected_cms[$this->cms_select]->createCourse($this->seminar_id))
PageLayout::postInfo(_('Kurs wurde angelegt.'));
}
// ggf. bestehenden Ilias4-Kurs zuordnen
if (Request::submitted('connect_course')) {
if (
ObjectConnections::getConnectionModuleId(Request::option('connect_course_sem_id'), 'crs', $this->cms_select)
&& $GLOBALS['perm']->have_studip_perm('dozent', Request::option('connect_course_sem_id'))
) {
ObjectConnections::setConnection($this->seminar_id, ObjectConnections::getConnectionModuleId(Request::option("connect_course_sem_id"), "crs", $this->cms_select), "crs", $this->cms_select);
PageLayout::postInfo(_('Zuordnung wurde gespeichert.'));
ELearningUtils::loadClass($this->cms_select);
if ((method_exists($connected_cms[$this->cms_select], "updateConnections")))
$connected_cms[$this->cms_select]->updateConnections( ObjectConnections::getConnectionModuleId(Request::option("connect_course_sem_id"), "crs", $this->cms_select) );
}
}
// Zugeordnete Ilias-Kurse ermitteln und ggf. aktualisieren
$this->course_output = ELearningUtils::getIliasCourses($this->seminar_id);
if ($this->new_account_cms == "") {
if ($this->module_system_type != "") {
$user_crs_role = $connected_cms[$this->module_system_type]->crs_roles[$GLOBALS['auth']->auth["perm"]];
ELearningUtils::loadClass($this->module_system_type);
}
if (Request::submitted('remove')) {
$connected_cms[$this->module_system_type]->newContentModule($this->module_id, $this->module_type, true);
if ($connected_cms[$this->module_system_type]->content_module[$this->module_id]->unsetConnection($this->seminar_id, $this->module_id, $this->module_type, $this->module_system_type))
PageLayout::postInfo(_('Die Zuordnung wurde entfernt.'));
unset($connected_cms[$this->module_system_type]->content_module[$this->module_id]);
} elseif (Request::submitted('add')) {
$connected_cms[$this->module_system_type]->newContentModule($this->module_id, $this->module_type, true);
if ($connected_cms[$this->module_system_type]->content_module[$this->module_id]->setConnection($this->seminar_id))
PageLayout::postInfo(_('Die Zuordnung wurde gespeichert.'));
unset($connected_cms[$this->module_system_type]->content_module[$this->module_id]);
}
if ($this->search_key != "") {
ELearningUtils::loadClass($this->cms_select);
if ( mb_strlen( trim($this->search_key) ) > 2)
$searchresult_content_modules = $connected_cms[$this->cms_select]->searchContentModules($this->search_key);
else
PageLayout::postError(_('Jeder Suchbegriff muss mindestens 3 Zeichen lang sein!'));
}
}
//Instanz mit den Zuordnungen von Content-Modulen zur Veranstaltung
$object_connections = new ObjectConnections($this->seminar_id);
$connected_modules = $object_connections->getConnections();
$this->module_count = 0;
$content_modules_list = [];
$user_modules_list = [];
$search_modules_list = [];
if ($object_connections->isConnected()) {
$caching_active = true;
foreach ($connected_modules as $key => $connection) {
if (ELearningUtils::isCMSActive($connection["cms"])) {
ELearningUtils::loadClass($connection["cms"]);
$connected_cms[$connection["cms"]]->newContentModule($connection["id"], $connection["type"], true);
$connected_modules[$key]['title'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getTitle();
$title_tmp[$key] = str_replace(['ä','ö','ü','ß'],['ae','oe','ue','ss'],mb_strtolower($connected_modules[$key]['title']));
$type_tmp[$key] = array_search($connection['type'], array_keys($GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]['types']));
$class_tmp[$key] = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]["CLASS_PREFIX"];
}
}
array_multisort($class_tmp, SORT_ASC, $type_tmp, SORT_ASC, $title_tmp, SORT_ASC, $connected_modules);
foreach ($connected_modules as $index => $connection) {
$current_module = $connection["id"];
if ($this->module_count == 0)
$content_modules_list[$index]['show_header'] = true;
$this->module_count++;
$this->module_system_count[$connection["cms"]]++;
if ($this->open_all != "")
$_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = true;
elseif ($this->close_all != "")
$_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = false;
$content_modules_list[$index]['module'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->view->showAdmin();
}
}
if (($this->module_count == 0) AND ($this->new_account_cms == "")) {
if (Context::isInstitute()) {
PageLayout::postInfo(_('Momentan sind dieser Einrichtung keine Lernmodule zugeordnet.'));
} else {
PageLayout::postInfo(_('Momentan sind dieser Veranstaltung keine Lernmodule zugeordnet.'));
}
}
$this->caching_active = false;
if (isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_select]["name"])) {
ELearningUtils::loadClass($this->cms_select);
$user_content_modules = $connected_cms[$this->cms_select]->getUserContentModules();
if (! ($user_content_modules == false)) {
foreach ($user_content_modules as $key => $connection) {
// show only those modules which are not already connected to the seminar
if (is_object($connected_cms[$this->cms_select]->content_module[$connection["ref_id"]]))
continue;
$connected_cms[$this->cms_select]->setContentModule($connection, false);
$connected_cms[$this->cms_select]->content_module[$current_module]->view->showAdmin();
$user_modules_list[$key]['module'] = $connected_cms[$this->cms_select]->content_module[$current_module]->view->showAdmin();
}
}
if (!$connected_cms[$this->cms_select]->isAuthNecessary()
|| $connected_cms[$this->cms_select]->user->isConnected()) {
$this->show_search = true;
}
if (! ($searchresult_content_modules == false)) {
foreach ($searchresult_content_modules as $key => $connection) {
// show only those modules which are not already connected to the seminar
if (is_object($connected_cms[$this->cms_select]->content_module[$connection["ref_id"]]))
continue;
$connected_cms[$this->cms_select]->setContentModule($connection, false);
$search_modules_list[$key]['module'] = $connected_cms[$this->cms_select]->content_module[$current_module]->view->showAdmin();
}
}
// ILIAS 4: Leeren Kurs anlegen oder Kurse von anderen Veranstaltungen zuordnen
if ((method_exists($connected_cms[$this->cms_select], "updateConnections")) AND ! ($this->module_system_count[$this->cms_select]) AND ! (ObjectConnections::getConnectionModuleId($this->seminar_id, "crs", $this->cms_select)))
{
$show_ilias_empty_course = true;
if ($GLOBALS['perm']->have_perm('root')) {
$query = "SELECT DISTINCT object_id, module_id, Name
FROM object_contentmodules
LEFT JOIN seminare ON (object_id = Seminar_id)
WHERE module_type = 'crs' AND system_type = ?";
} else {
$query = "SELECT DISTINCT object_id, module_id, Name
FROM object_contentmodules
LEFT JOIN seminare ON (object_id = Seminar_id)
LEFT JOIN seminar_user USING (Seminar_id)
WHERE module_type = 'crs' AND system_type = ? AND seminar_user.status = 'dozent'";
}
$statement = DBManager::get()->prepare($query);
$statement->execute([$this->cms_select]);
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
if ($GLOBALS['perm']->have_studip_perm('dozent', $row['object_id'])) {
$existing_courses[$row['object_id']] = my_substr($row['Name'],0,60)." ".sprintf(_("(Kurs-ID %s)"), $row['module_id']);
}
}
}
// ILIAS 4: ggf. Hinweis auf Möglichkeit, weitere Modulformen als Link einzubinden
elseif (method_exists($connected_cms[$this->cms_select], "updateConnections") AND count($connected_cms[$this->cms_select]->types['webr'])) {
$this->show_ilias_link_info = true;
$crs_data = ObjectConnections::getConnectionModuleId($this->seminar_id, "crs", $this->cms_select);
}
}
// Cachen der SOAP-Daten
if (is_array($connected_cms))
foreach($connected_cms as $system)
$system->terminate();
$widget = new ActionsWidget();
if (is_array($this->course_output['courses']) && count($this->course_output['courses'])) {
$widget->addLink(
_('Zuordnungen aktualisieren'),
URLHelper::getURL('?', ['view' => 'edit', 'cms_select' => $this->cms_select,'update'=>1]),
Icon::create('refresh')
);
}
$this->sidebar->addWidget($widget);
$this->new_account = $this->new_account_cms;
$this->is_inst = Context::isInstitute();
if ($this->cms_select) {
$this->cms_name = $connected_cms[$this->cms_select]->getName();
$this->cms_logo = $connected_cms[$this->cms_select]->getLogo();
$this->user_modules = $user_modules_list;
$this->search_modules = $search_modules_list;
$this->existing_courses = $existing_courses;
$this->show_ilias_empty_course = $show_ilias_empty_course;
}
$this->content_modules = $content_modules_list;
}
}