aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorRasmus Fuhse <fuhse@data-quest.de>2025-01-10 12:13:24 +0000
committerRasmus Fuhse <fuhse@data-quest.de>2025-01-10 12:13:24 +0000
commit39745c9aa8bb099e8bda1f4d775ed229dbe97be4 (patch)
treea2a96deecf48e62d995507c5c8b39eea9ae9293d /app
parent03e8e1d8f9100cf9bfcb111b63ac4077f510a026 (diff)
Resolve "Studiengruppen erweitern" - Hauptbronch
Closes #3616 Merge request studip/studip!2509
Diffstat (limited to 'app')
-rw-r--r--app/controllers/admin/tags.php67
-rw-r--r--app/controllers/course/connectedcourses.php234
-rw-r--r--app/controllers/course/connectedstudygroups.php315
-rw-r--r--app/controllers/course/overview.php11
-rw-r--r--app/controllers/course/studygroup.php209
-rw-r--r--app/controllers/course/wizard.php11
-rw-r--r--app/controllers/my_courses.php34
-rw-r--r--app/controllers/my_studygroups.php100
-rw-r--r--app/controllers/search/angebot.php12
-rw-r--r--app/controllers/search/globalsearch.php28
-rw-r--r--app/controllers/search/studiengaenge.php14
-rw-r--r--app/views/admin/tags/index.php65
-rw-r--r--app/views/admin/tags/view_objects.php51
-rw-r--r--app/views/course/connectedcourses/_course_to_connect.php21
-rw-r--r--app/views/course/connectedcourses/connect.php78
-rw-r--r--app/views/course/connectedcourses/index.php112
-rw-r--r--app/views/course/connectedstudygroups/_studygroup_to_connect.php21
-rw-r--r--app/views/course/connectedstudygroups/connect.php79
-rw-r--r--app/views/course/connectedstudygroups/index.php110
-rw-r--r--app/views/course/overview/index.php4
-rw-r--r--app/views/course/studygroup/details.php19
-rw-r--r--app/views/course/studygroup/edit.php27
-rw-r--r--app/views/course/studygroup/widget.php88
-rw-r--r--app/views/course/wizard/step.php14
-rw-r--r--app/views/course/wizard/steps/basicdata/index_studygroup.php7
-rw-r--r--app/views/course/wizard/steps/studygroups/index.php110
-rw-r--r--app/views/my_studygroups/_course.php46
-rw-r--r--app/views/my_studygroups/index.php17
-rw-r--r--app/views/my_studygroups/proposals.php31
-rw-r--r--app/views/search/studiengaenge/verlauf.php55
-rw-r--r--app/views/studygroup/browse.php54
31 files changed, 1935 insertions, 109 deletions
diff --git a/app/controllers/admin/tags.php b/app/controllers/admin/tags.php
new file mode 100644
index 0000000..03819bd
--- /dev/null
+++ b/app/controllers/admin/tags.php
@@ -0,0 +1,67 @@
+<?php
+
+class Admin_TagsController extends AuthenticatedController
+{
+ /**
+ * Common tasks for all actions.
+ */
+ public function before_filter(&$action, &$args)
+ {
+ parent::before_filter($action, $args);
+
+ $GLOBALS['perm']->check('root');
+ Navigation::activateItem('/admin/locations/tags');
+ PageLayout::setTitle(_('Schlagwortverwaltung'));
+ }
+
+ public function index_action()
+ {
+ Tag::deleteBySQL('LEFT JOIN `tags_relations` ON (`tags`.`id` = `tags_relations`.`tag_id`) WHERE `tags_relations`.`range_id` IS NULL');
+ $this->page = Request::int('page', 0);
+ $this->tags = Tag::findBySQL('1 ORDER BY `name` ASC LIMIT :offset, :limit', [
+ 'offset' => $this->page * Config::get()->ENTRIES_PER_PAGE,
+ 'limit' => Config::get()->ENTRIES_PER_PAGE
+ ]);
+ $this->all_tags = Tag::countBySql('1');
+ }
+
+ public function edit_action(Tag $tag)
+ {
+ PageLayout::setTitle(sprintf(_('Schlagwort „%s“ bearbeiten'), $tag->name));
+ $form = \Studip\Forms\Form::fromSORM(
+ $tag,
+ [
+ 'legend' => _('Grunddaten'),
+ 'fields' => [
+ 'name' => [
+ 'label' =>_('Name'),
+ 'validate' => function ($value) use ($tag) {
+ $output = '';
+ if ($value !== mb_strtolower($value)) {
+ $output .= _('Schlagwörter sollen keine Großbuchstaben entahlten').' ';
+ }
+ foreach (['\n', '#', '|', ' '] as $forbidden) {
+ if (str_contains($value, $forbidden)) {
+ $output .= _('Schlagwörter dürfen keine Zeilenumbrüche, Leerzeichen, Doppelkreuze (#) oder Pipe-Zeichen (|) enthalten.').' ';
+ break;
+ }
+ }
+ if (Tag::findOneByName($value) && $value !== $tag->name) {
+ $output .= _('Dieses Schlagwort ist schon vergeben.').' ';
+ }
+ return $output !== '' ? $output : true;
+ }
+ ],
+ 'active' => _('Aktiv')
+ ]
+ ]
+ )->autoStore()->setURL($this->indexURL());
+ $this->render_form($form);
+ }
+
+ public function view_objects_action(Tag $tag)
+ {
+ $this->tag = $tag;
+ PageLayout::setTitle(sprintf(_("Verknüpfte Objekte mit Schlagwort „%s“"), $tag->name));
+ }
+}
diff --git a/app/controllers/course/connectedcourses.php b/app/controllers/course/connectedcourses.php
new file mode 100644
index 0000000..dcbc3ae
--- /dev/null
+++ b/app/controllers/course/connectedcourses.php
@@ -0,0 +1,234 @@
+<?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);
+ }
+}
diff --git a/app/controllers/course/connectedstudygroups.php b/app/controllers/course/connectedstudygroups.php
new file mode 100644
index 0000000..9ef6b92
--- /dev/null
+++ b/app/controllers/course/connectedstudygroups.php
@@ -0,0 +1,315 @@
+<?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);
+ }
+}
diff --git a/app/controllers/course/overview.php b/app/controllers/course/overview.php
index e1da00e..4313cdc 100644
--- a/app/controllers/course/overview.php
+++ b/app/controllers/course/overview.php
@@ -108,6 +108,17 @@ class Course_OverviewController extends AuthenticatedController
$this->avatar = StudygroupAvatar::getAvatar($this->course_id);
}
+ $connections = StudygroupCourse::countBySql(
+ "`studygroup_id` = :cid OR `course_id` = :cid",
+ [
+ 'cid' => $this->course_id
+ ]
+ );
+ if ($connections > 0) {
+ $response = $this->relay('course/studygroup/widget/' . $this->course_id);
+ $this->connectedstudygroups = $response->body;
+ }
+
$this->plugins = PluginEngine::getPlugins(StandardPlugin::class, $this->course_id);
$sidebar = Sidebar::get();
diff --git a/app/controllers/course/studygroup.php b/app/controllers/course/studygroup.php
index 981a152..c95c20e 100644
--- a/app/controllers/course/studygroup.php
+++ b/app/controllers/course/studygroup.php
@@ -170,43 +170,168 @@ class Course_StudygroupController extends AuthenticatedController
*/
public function edit_action()
{
- global $perm;
-
- $id = Context::getId();
-
+ PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Studiengruppe bearbeiten'));
+ Navigation::activateItem('/course/admin/main');
PageLayout::setHelpKeyword('Basis.StudiengruppenBearbeiten');
- // if we are permitted to edit the studygroup get some data...
- if ($id && $perm->have_studip_perm('dozent', $id)) {
- $this->course = Course::find($id);
+ $course = Context::get();
- PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Studiengruppe bearbeiten'));
- Navigation::activateItem('/course/admin/main');
+ $expiration_date = CourseConfig::get($course->id)->STUDYGROUP_EXPIRATION_DATE;
+ if (!$expiration_date) {
+ $expiration_date = _('Unbegrenzt');
+ }
- $this->course_id = $id;
- $this->sem_class = $GLOBALS['SEM_CLASS'][$GLOBALS['SEM_TYPE'][$this->course->status]['class']];
- $this->tutors = CourseMember::findByCourseAndStatus($this->course->id, 'tutor');
- $this->founders = StudygroupModel::getFounders($id);
+ $zugang_options = [
+ 'all' => _('Offen für alle'),
+ 'invite' => _('Auf Anfrage'),
+ 'connectedcourse' => _('Für Mitglieder der zugehörigen Lehrveranstaltung')
+ ];
+ if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED) {
+ $zugang_options['invisible'] = _('Unsichtbar');
+ }
- $actions = new ActionsWidget();
+ $form = \Studip\Forms\Form::fromSORM(Context::get(), [
+ 'legend' => _('Grunddaten'),
+ 'fields' => [
+ 'name' => [
+ 'label' => _('Name'),
+ 'required' => true
+ ],
+ 'beschreibung' => _('Beschreibung'),
+ 'zugang' => [
+ 'label' => _('Zugang'),
+ 'type' => 'select',
+ 'options' => $zugang_options,
+ 'value' => function () use ($course) {
+ $courseset = CourseSet::getSetForCourse($course->id);
+ if ($courseset && $courseset->getId() === CourseSet::getConnectedcourseAdmissionSetId()) {
+ return 'connectedcourse';
+ } elseif (!$course->visible) {
+ return 'invisible';
+ } else {
+ return $course->admission_prelim > 0 ? 'invite' : 'all';
+ }
+ },
+ 'store' => function ($value, $input) {
+ $course = $input->getContextObject();
+ switch ($value) {
+ case 'connectedcourse':
+ CourseSet::addCourseToSet(CourseSet::getConnectedcourseAdmissionSetId(), $course->id);
+ $course->visible = 1;
+ break;
+ case 'invisible':
+ CourseSet::removeCourseFromSet(CourseSet::getConnectedcourseAdmissionSetId(), $course->id);
+ if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED) {
+ $course->visible = 0;
+ break;
+ }
+ case 'invite':
+ CourseSet::removeCourseFromSet(CourseSet::getConnectedcourseAdmissionSetId(), $course->id);
+ $course->visible = 1;
+ $course->admission_prelim = 1;
+ $course->admission_prelim_txt = _('Die Moderator:innen der Studiengruppe können Ihren Aufnahmewunsch bestätigen oder ablehnen. Erst nach Bestätigung erhalten Sie vollen Zugriff auf die Gruppe.');
+ break;
+ case 'all':
+ CourseSet::removeCourseFromSet(CourseSet::getConnectedcourseAdmissionSetId(), $course->id);
+ $course->visible = 1;
+ $course->admission_prelim = 0;
+ break;
+ }
+ $course->store();
+ }
+ ]
+ ]
+ ])->addSORM(
+ Context::get(), [
+ 'legend' => _('Erweiterte Einstellungen'),
+ 'fields' => [
+ 'ablaufdatum' => [
+ 'label' => _('Ablaufdatum / Löschdatum'),
+ 'type' => 'datetimepicker',
+ 'value' => $expiration_date,
+ 'store' => function ($value) {
+ CourseConfig::get(Context::getId())->store('STUDYGROUP_EXPIRATION_DATE', $value);
+ }
+ ],
+ 'tags' => [
+ 'label' => _('Schlagwörter'),
+ 'type' => 'multiquicksearch',
+ 'addlabel' => _('Schlagwort hinzufügen'),
+ 'value' => function () {
+ $course = Context::get();
+ $tags = Tag::getByRange($course->id, 'course');
+ return array_map(function ($t) { return $t->name; }, $tags);
+ },
+ 'searchtype' => (string) SQLSearch::get('SELECT `name`, `name` FROM `tags` WHERE `active` = 1 AND `name` LIKE :input', _('Schlagwort suchen')),
+ 'autocomplete' => true,
+ 'mapper' => function ($value, $obj) {
+ $tags = [];
+ foreach ($value as $name) {
+ if ($name) {
+ if ($tag = Tag::findOneByName($name)) {
+ if ($tag->active) {
+ $tags[] = $tag;
+ }
+ } else {
+ $tag = new Tag();
+ $tag->name = $name;
+ $tag->store();
+ $tags[] = $tag;
+ }
+ }
+ }
+ return $tags;
+ },
+ 'store' => function ($tags, $input) {
+ $course = $input->getContextObject();
+ $tag_ids = [];
+ foreach ($tags as $tag) {
+ $tag_ids[] = $tag->id;
+ $relation = TagRelation::findOneBySQL(
+ "`range_id` = :course_id AND `range_type` = 'course' AND `tag_id` = :tag_id",
+ [
+ 'tag_id' => $tag->id,
+ 'course_id' => $course->id
+ ]
+ );
+ if (!$relation) {
+ $relation = TagRelation::create([
+ 'range_id' => $course->id,
+ 'range_type' => 'course',
+ 'tag_id' => $tag->id,
+ ]);
+ }
+ }
+ TagRelation::deleteBySQL(
+ "`range_id` = :course_id AND `range_type` = 'course' AND `tag_id` NOT IN (:ids)",
+ [
+ 'ids' => $tag_ids,
+ 'course_id' => $course->id
+ ]
+ );
+ }
+ ]
+ ]
+ ]
+ )->setURL($this->editURL())
+ ->autoStore();
- $actions->addLink(
- _('Neue Studiengruppe anlegen'),
- $this->url_for('course/wizard?studygroup=1'),
- Icon::create('add')
- );
+ $actions = new ActionsWidget();
- $actions->addLink(
- _('Diese Studiengruppe löschen'),
- $this->deleteURL(),
- Icon::create('trash')
- );
+ $actions->addLink(
+ _('Neue Studiengruppe anlegen'),
+ $this->url_for('course/wizard?studygroup=1'),
+ Icon::create('add')
+ );
+ $actions->addLink(
+ _('Diese Studiengruppe löschen'),
+ $this->deleteURL(),
+ Icon::create('trash')
+ );
- Sidebar::get()->addWidget($actions);
- } // ... otherwise redirect us to the seminar
- else {
- $this->redirect(URLHelper::getURL('dispatch.php/course/go?to=' . $id));
- }
+ Sidebar::get()->addWidget($actions);
+
+ $this->render_form($form);
}
/**
@@ -255,14 +380,20 @@ class Course_StudygroupController extends AuthenticatedController
$course->schreibzugriff = 1;
$course->visible = 1;
- if (Request::get('groupaccess') == 'all') {
+ $cs_id = CourseSet::getConnectedcourseAdmissionSetId();
+ if (Request::get('groupaccess') === 'all') {
$course->admission_prelim = 0;
+ CourseSet::removeCourseFromSet($cs_id, $id);
+ } elseif(Request::get('groupaccess') === 'top-course') {
+ CourseSet::addCourseToSet($cs_id, $id);
} else {
$course->admission_prelim = 1;
- if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED && Request::get('groupaccess') == 'invisible') {
+ if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED && Request::get('groupaccess') === 'invisible') {
$course->visible = 0;
}
$course->admission_prelim_txt = _('Die für die Moderation zuständigen Personen der Studiengruppe können Ihren Aufnahmewunsch bestätigen oder ablehnen. Erst nach Bestätigung erhalten Sie vollen Zugriff auf die Gruppe.');
+
+ CourseSet::removeCourseFromSet($cs_id, $id);
}
$course->store();
}
@@ -783,4 +914,20 @@ class Course_StudygroupController extends AuthenticatedController
$this->avatar_url = $avatar->getURL(Avatar::NORMAL);
}
+ public function widget_action($range_id)
+ {
+ if (get_class($this->parent_controller) === __CLASS__) {
+ throw new RuntimeException('widget_action must be relayed');
+ }
+ $this->course = Course::find($range_id);
+
+ if ($this->course->isStudygroup()) {
+ $sql = "INNER JOIN `seminare` ON (`seminare`.`Seminar_id` = `studygroup_courses`.`course_id`) WHERE `studygroup_id` = ? ORDER BY `seminare`.`name` ASC";
+ } else {
+ $sql = "INNER JOIN `seminare` ON (`seminare`.`Seminar_id` = `studygroup_courses`.`studygroup_id`) WHERE `course_id` = ? ORDER BY `seminare`.`name` ASC ";
+ }
+ $this->connections = StudygroupCourse::findBySQL($sql, [$range_id]);
+ }
+
+
}
diff --git a/app/controllers/course/wizard.php b/app/controllers/course/wizard.php
index b4244b6..ad289ed 100644
--- a/app/controllers/course/wizard.php
+++ b/app/controllers/course/wizard.php
@@ -64,7 +64,7 @@ class Course_WizardController extends AuthenticatedController
*/
public function index_action()
{
- $this->redirect('course/wizard/step/0' . ($this->studygroup ? '?studygroup=1' : ''));
+ $this->redirect('course/wizard/step/0' . ($this->studygroup ? '?studygroup=1&stgteil_id='.Request::option('stgteil_id') : ''));
}
/**
@@ -93,7 +93,10 @@ class Course_WizardController extends AuthenticatedController
// Add special studygroup flag to set values.
$this->setStepValues(
get_class($step),
- array_merge($this->getValues(get_class($step)), ['studygroup' => 1])
+ array_merge($this->getValues(get_class($step)), [
+ 'studygroup' => 1,
+ 'stgteil_id' => Request::option('stgteil_id')
+ ])
);
}
$this->values = $this->getValues();
@@ -193,11 +196,13 @@ class Course_WizardController extends AuthenticatedController
}
// A studygroup has been created.
if (in_array($this->course->status, studygroup_sem_types())) {
+
$message = MessageBox::success(sprintf(
- _('Die Studien-/Arbeitsgruppe "%s" wurde angelegt. '
+ _('Die Studien-/Arbeitsgruppe „%s“ wurde angelegt. '
. 'Sie können sie direkt hier weiter verwalten.'),
htmlReady($this->course->name)
));
+
$target = $this->url_for('course/studygroup/edit', ['cid' => $this->course->id]);
// "Normal" course.
diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php
index c7a6771..a8d9797 100644
--- a/app/controllers/my_courses.php
+++ b/app/controllers/my_courses.php
@@ -704,17 +704,19 @@ class MyCoursesController extends AuthenticatedController
}
}
- $groups[] = [
- 'id' => $_outer_index,
- 'name' => (string) $sem_data[$_outer_index]['name'],
- 'data' => [
- [
- 'id' => md5($_outer_index),
- 'label' => false,
- 'ids' => array_keys($_courses),
+ if ($_outer_index) {
+ $groups[] = [
+ 'id' => $_outer_index,
+ 'name' => (string)$sem_data[$_outer_index]['name'],
+ 'data' => [
+ [
+ 'id' => md5($_outer_index),
+ 'label' => false,
+ 'ids' => array_keys($_courses),
+ ],
],
- ],
- ];
+ ];
+ }
$temp_courses = array_merge($temp_courses, $_courses);
} else {
$count = 1;
@@ -747,11 +749,13 @@ class MyCoursesController extends AuthenticatedController
$temp_courses = array_merge($temp_courses, $_courses);
}
- $groups[] = [
- 'id' => $_outer_index,
- 'name' => (string) $sem_data[$_outer_index]['name'],
- 'data' => $_groups,
- ];
+ if ($_outer_index) {
+ $groups[] = [
+ 'id' => $_outer_index,
+ 'name' => (string)$sem_data[$_outer_index]['name'],
+ 'data' => $_groups,
+ ];
+ }
}
}
}
diff --git a/app/controllers/my_studygroups.php b/app/controllers/my_studygroups.php
index 579d47e..ac55cf4 100644
--- a/app/controllers/my_studygroups.php
+++ b/app/controllers/my_studygroups.php
@@ -10,15 +10,28 @@ class MyStudygroupsController extends AuthenticatedController
}
}
- public function index_action()
+ public function index_action($is_widget = false)
{
PageLayout::setHelpKeyword('Basis.MeineStudiengruppen');
PageLayout::setTitle(_('Meine Studiengruppen'));
URLHelper::removeLinkParam('cid');
- $this->studygroups = MyRealmModel::getStudygroups();
+ $this->is_widget = (bool)$is_widget;
+ $this->studygroups = StudygroupModel::getStudygroups();
$this->nav_elements = MyRealmModel::calc_single_navigation($this->studygroups);
- $this->set_sidebar();
+
+ // do not render sidebar if this is the widget
+ if (!$this->is_widget) {
+ $this->set_sidebar();
+ }
+ }
+
+ public function proposals_action()
+ {
+ PageLayout::setHelpKeyword('Basis.MeineStudiengruppen');
+ PageLayout::setTitle(_('Meine Studiengruppen'));
+ URLHelper::removeLinkParam('cid');
+ $this->proposed_studygroups = $this->proposeStudygroups();
}
public function set_sidebar()
@@ -44,4 +57,85 @@ class MyStudygroupsController extends AuthenticatedController
}
$sidebar->addWidget($actions);
}
+
+ public function proposeStudygroups($user_id = null, $amount = 4)
+ {
+ $user_id ??= User::findCurrent()->id;
+ $cache_id = 'core/studygroups/proposals/' . $user_id;
+ $cache = \Studip\Cache\Factory::getCache();
+ $studygroup_ids = $cache->read($cache_id);
+ if ($studygroup_ids !== false) {
+ return Course::findMany($studygroup_ids);
+ }
+
+ // Vorgeschlagen werden sollen Studiengruppen,
+ // a) in denen Personen sitzen, die auch in anderen Veranstaltungen sitzen, in denen der aktive Nutzer Mitglied ist
+ // b) die zu dem Studienbereich des Studierenden gehören
+ // c) die einfach neu sind
+ // und die zudem aktiv sind. Es wird eine Liste von 36 Studiengruppen gebaut, wovon drei alle 15 Minuten im Widget
+ // angezeigt werden.
+
+ $studygroup_sem_types = array_filter(
+ array_keys($GLOBALS['SEM_TYPE']),
+ function ($sem_type_id) {
+ return (bool) $GLOBALS['SEM_CLASS'][$GLOBALS['SEM_TYPE'][$sem_type_id]['class']]['studygroup_mode'];
+ }
+ );
+
+ $statement = DBManager::get()->prepare("
+ SELECT `Seminar_id` FROM (
+ SELECT `seminare`.`Seminar_id`, COUNT(`seminar_user`.`user_id`) AS `count_colleages`
+ FROM `seminar_user` AS `my_courses`
+ LEFT JOIN `seminar_user` AS `my_colleages` ON (`my_colleages`.`Seminar_id` = `my_courses`.`Seminar_id`)
+ LEFT JOIN `seminar_user` ON (`my_colleages`.`user_id` = `seminar_user`.`user_id`)
+ LEFT JOIN `seminar_user` AS `am_i_connected` ON (`seminar_user`.`Seminar_id` = `am_i_connected`.`Seminar_id` AND `am_i_connected`.`user_id` = :me)
+ LEFT JOIN `seminare` ON (`seminare`.`Seminar_id` = `seminar_user`.`Seminar_id`)
+ WHERE `seminare`.`status` IN (:studygroup_types)
+ AND `am_i_connected`.`user_id` IS NULL
+ AND `my_courses`.`user_id` = :me
+ GROUP BY `seminare`.`seminar_id`
+ ORDER BY `count_colleages` DESC
+ LIMIT 12
+ ) AS `colleages_groups`
+
+ UNION SELECT `Seminar_id` FROM (
+ SELECT `seminare`.`Seminar_id`
+ FROM `seminare`
+ LEFT JOIN `seminar_user` AS `am_i_connected` ON (`am_i_connected`.`Seminar_id` = `seminare`.`Seminar_id` AND `am_i_connected`.`user_id` = :me)
+ INNER JOIN `studygroup_stgteil` ON (`studygroup_stgteil`.`studygroup_id` = `seminare`.`Seminar_id`)
+ INNER JOIN `mvv_stgteil` ON (`studygroup_stgteil`.`stgteil_id` = `mvv_stgteil`.`stgteil_id`)
+ INNER JOIN `user_studiengang` ON (`user_studiengang`.`fach_id` = `mvv_stgteil`.`fach_id`)
+ INNER JOIN `mvv_stg_stgteil` ON (`mvv_stg_stgteil`.`stgteil_id` = `mvv_stgteil`.`stgteil_id`)
+ INNER JOIN `mvv_studiengang` ON (`mvv_studiengang`.`studiengang_id` = `mvv_stg_stgteil`.`studiengang_id`
+ AND `mvv_studiengang`.`abschluss_id` = `user_studiengang`.`abschluss_id`)
+ WHERE `am_i_connected`.`user_id` IS NULL
+ AND `seminare`.`status` IN (:studygroup_types)
+ AND `user_studiengang`.`user_id` = :me
+ ORDER BY rand()
+ LIMIT 12
+ ) AS `same_studyarea_groups`
+
+ UNION SELECT `Seminar_id` FROM (
+ SELECT `seminare`.`Seminar_id`
+ FROM `seminare`
+ LEFT JOIN `seminar_user` AS `am_i_connected` ON (`am_i_connected`.`Seminar_id` = `seminare`.`Seminar_id` AND `am_i_connected`.`user_id` = :me)
+ WHERE `am_i_connected`.`user_id` IS NULL
+ AND `seminare`.`status` IN (:studygroup_types)
+ ORDER BY `seminare`.`mkdate` DESC
+ LIMIT 12
+ ) AS `new_groups`
+
+ GROUP BY `Seminar_id`
+ ORDER BY rand()
+ LIMIT :amount
+ ");
+ $statement->execute([
+ 'studygroup_types' => $studygroup_sem_types,
+ 'me' => $user_id,
+ 'amount' => $amount
+ ]);
+ $group_ids = $statement->fetchAll(PDO::FETCH_COLUMN);
+ $cache->write($cache_id, $group_ids, 15 * 60);
+ return Course::findMany($group_ids);
+ }
}
diff --git a/app/controllers/search/angebot.php b/app/controllers/search/angebot.php
index 0c0f402..4f749d4 100644
--- a/app/controllers/search/angebot.php
+++ b/app/controllers/search/angebot.php
@@ -179,4 +179,16 @@ class Search_AngebotController extends MVVController
$this->content = $response->body;
$this->render_template('shared/content', $this->layout);
}
+
+ public function remove_studygroup_action($course_id, $stgteil_id)
+ {
+ CSRFProtection::verifyUnsafeRequest();
+ if (!$GLOBALS['perm']->have_studip_perm('tutor', $course_id) && !$GLOBALS['perm']->have_perm('admin')) {
+ throw new AccessDeniedException();
+ }
+ StudygroupStgteil::deleteBySQL('`studygroup_id` = ? AND `stgteil_id` = ?', [$course_id, $stgteil_id]);
+ PageLayout::postSuccess(_('Zuordnung wurde aufgehoben.'));
+ $stgteil = StudiengangTeil::find($stgteil_id);
+ $this->redirect('search/angebot/studiengang/'.$stgteil->studiengang[0]->id);
+ }
}
diff --git a/app/controllers/search/globalsearch.php b/app/controllers/search/globalsearch.php
index b31663f..fd82103 100644
--- a/app/controllers/search/globalsearch.php
+++ b/app/controllers/search/globalsearch.php
@@ -107,6 +107,17 @@ class Search_GlobalsearchController extends AuthenticatedController
),
'institute_filter'
);
+
+ $filter_widget->addElement(
+ new SelectListElement(
+ _('Studiengang'),
+ 'study_course',
+ $this->getStudyCourses(),
+ '',
+ ['id' => 'study_course_select']
+ ),
+ 'study_course_filter'
+ );
}
/**
@@ -171,6 +182,23 @@ class Search_GlobalsearchController extends AuthenticatedController
}
/**
+ * @return array
+ */
+ private function getStudyCourses()
+ {
+
+ $this->user = User::findCurrent();
+ $study_courses = [];
+
+ foreach ($this->user->studycourses as $usc)
+ {
+ $study_courses[] = $usc->studycourse->name;
+ }
+
+ return $study_courses;
+ }
+
+ /**
* Add some information on how to use the search.
*/
private function addInfoText()
diff --git a/app/controllers/search/studiengaenge.php b/app/controllers/search/studiengaenge.php
index 8f08c32..1745ba6 100644
--- a/app/controllers/search/studiengaenge.php
+++ b/app/controllers/search/studiengaenge.php
@@ -200,12 +200,12 @@ class Search_StudiengaengeController extends MVVController
$this->with_courses = Request::option('with_courses', $_SESSION['MVV_SEARCH_SEQUENCE_WITH_COURSES'] ?? null);
$_SESSION['MVV_SEARCH_SEQUENCE_WITH_COURSES'] = $this->with_courses;
- $studiengangTeil = StudiengangTeil::find($stgteil_id);
+ $this->studiengangTeil = StudiengangTeil::find($stgteil_id);
$versionen = StgteilVersion::findByStgteil($stgteil_id, 'start', 'DESC')->filter(function ($version) {
$public = $GLOBALS['MVV_STGTEILVERSION']['STATUS']['values'][$version->stat]['public'];
return (bool) $public;
});
- if (!$studiengangTeil || count($versionen) === 0) {
+ if (!$this->studiengangTeil || count($versionen) === 0) {
PageLayout::postInfo(_('Kein Verlaufsplan im gewählten Bereich verfügbar.'));
} else {
$version_id = Request::option('version', $this->sessGet('selected_version'));
@@ -307,26 +307,24 @@ class Search_StudiengaengeController extends MVVController
if ($studiengang_id) {
if ($stgteil_bez_id) {
$this->stgTeilBez = StgteilBezeichnung::get($stgteil_bez_id);
- $this->breadcrumb->append([$this->stgTeilBez, $studiengangTeil], 'verlauf');
+ $this->breadcrumb->append([$this->stgTeilBez, $this->studiengangTeil], 'verlauf');
} else {
- $this->breadcrumb->append($studiengangTeil, 'verlauf');
+ $this->breadcrumb->append($this->studiengangTeil, 'verlauf');
}
$this->studiengang = Studiengang::get($studiengang_id);
}
$this->setVersionSelectWidget(
$versionen,
- $this->action_url('verlauf', $studiengangTeil->id, $stgteil_bez_id, $studiengang_id)
+ $this->action_url('verlauf', $this->studiengangTeil->id, $stgteil_bez_id, $studiengang_id)
);
ksort($fachsemesterData);
$this->fachsemesterData = $fachsemesterData;
$this->abschnitteData = $abschnitteData;
$this->versionen = $versionen;
- // Augsburg
// Ausgabe des Namens ohne Fach (dieses ist im Zusatz bereits enthalten)
- // $this->studiengangTeilName = $studiengangTeil->getDisplayName(0);
- $this->studiengangTeilName = $studiengangTeil->getDisplayName();
+ $this->studiengangTeilName = $this->studiengangTeil->getDisplayName();
// add option widget to show only modules with courses in the
// selected semester
diff --git a/app/views/admin/tags/index.php b/app/views/admin/tags/index.php
new file mode 100644
index 0000000..4d5067a
--- /dev/null
+++ b/app/views/admin/tags/index.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * @var Admin_TagsController $controller
+ * @var Tag[] $tags
+ * @var integer $all_tags
+ * @var integer $page
+ * */
+?>
+<table class="default">
+ <caption>
+ <?= _('Schlagwörter') ?>
+ <span class="actions">
+ <?= sprintf(_('%s Schlagwörter'), $all_tags) ?>
+ </span>
+ </caption>
+ <thead>
+ <tr>
+ <th><?= _('Schlagwort') ?></th>
+ <th><?= _('Verknüpfte Objekte') ?></th>
+ <th><?= _('Aktiv') ?></th>
+ <th class="actions">
+ <?= _('Aktion') ?>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($tags as $tag) : ?>
+ <tr>
+ <td>
+ <?= htmlReady($tag['name']) ?>
+ </td>
+ <td>
+ <a href="<?= URLHelper::getLink('dispatch.php/admin/tags/view_objects/'.$tag->id) ?>" data-dialog>
+ <?= TagRelation::countBySql('`tag_id` = ?', [$tag->id]) ?>
+ </a>
+ </td>
+ <td>
+ <?= $tag['active']
+ ? Icon::create('checkbox-checked', Icon::ROLE_INFO)
+ : Icon::create('checkbox-unchecked', Icon::ROLE_INFO) ?>
+ </td>
+ <td class="actions">
+ <a href="<?= $controller->edit($tag) ?>" data-dialog>
+ <?= Icon::create('edit') ?>
+ </a>
+ </td>
+ </tr>
+ <? endforeach ?>
+ <? if (count($tags) === 0) : ?>
+ <tr>
+ <td colspan="2">
+ <?= _('Noch keine Schlagwörter vorhanden.') ?>
+ </td>
+ </tr>
+ <? endif ?>
+ </tbody>
+
+ <tfoot>
+ <tr>
+ <td colspan="4" class="actions">
+ <?= Pagination::create($all_tags, $page)->asLinks() ?>
+ </td>
+ </tr>
+ </tfoot>
+</table>
diff --git a/app/views/admin/tags/view_objects.php b/app/views/admin/tags/view_objects.php
new file mode 100644
index 0000000..0d90f66
--- /dev/null
+++ b/app/views/admin/tags/view_objects.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @var Admin_TagsController $controller
+ * @var Tag $tag
+ * */
+?>
+<table class="default">
+ <thead>
+ <tr>
+ <th><?= _('Objekt') ?></th>
+ <th><?= _('Typ') ?></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($tag->related_objects as $relation) : ?>
+ <tr>
+ <td>
+ <?
+ switch ($relation->range_type) {
+ case 'course':
+ $course = Course::find($relation->range_id);
+ if ($course) {
+ echo '<a href="'.URLHelper::getLink($course->isStudygroup() ? 'dispatch.php/course/studygroup/details/' . $relation->range_id : 'dispatch.php/course/details/index/' . $relation->range_id) . '">';
+ echo htmlReady($course->getFullName());
+ echo '</a>';
+ } else {
+ echo $relation->range_id;
+ }
+ break;
+ default:
+ echo $relation->range_id;
+ break;
+ }
+ ?>
+ </td>
+ <td><?
+ switch ($relation->range_type) {
+ case 'course':
+ echo _('Veranstaltung');
+ break;
+ default:
+ echo $relation->range_type;
+ break;
+ }
+ ?></td>
+ <td></td>
+ </tr>
+ <? endforeach ?>
+ </tbody>
+</table>
diff --git a/app/views/course/connectedcourses/_course_to_connect.php b/app/views/course/connectedcourses/_course_to_connect.php
new file mode 100644
index 0000000..0235785
--- /dev/null
+++ b/app/views/course/connectedcourses/_course_to_connect.php
@@ -0,0 +1,21 @@
+<tr>
+ <td>
+ <?= CourseAvatar::getAvatar($course->id)->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($course->getFullName()) ?>
+ </td>
+ <td>
+ <? if ($course->start_semester) : ?>
+ <?= htmlReady($course->start_semester->name) ?>
+ <? if ($course->end_semester && $course->end_semester->id !== $course->start_semester->id) : ?>
+ - <?= htmlReady($course->end_semester->name) ?>
+ <? endif ?>
+ <? endif ?>
+ </td>
+ <td class="actions">
+ <?= Icon::create('add')->asInput([
+ 'title' => _('Verknüpfung mit dieser Veranstaltung vorschlagen.'),
+ 'formaction' => $controller->connectURL($course->id),
+ 'formmethod' => 'post'
+ ]) ?>
+ </td>
+</tr>
diff --git a/app/views/course/connectedcourses/connect.php b/app/views/course/connectedcourses/connect.php
new file mode 100644
index 0000000..4c6a2e5
--- /dev/null
+++ b/app/views/course/connectedcourses/connect.php
@@ -0,0 +1,78 @@
+<form method="get"
+ action="<?= $controller->link_for('course/connectedcourses/connect', ['search' => 1]) ?>">
+ <?= CSRFProtection::tokenTag() ?>
+ <table class="default" style="margin-top: 20px;">
+ <caption>
+ <?= _('Lehrveranstaltungen') ?>
+ <span class="actions">
+ <? if (Request::get('search')) : ?>
+ <select name="semester_id" aria-label="<?= _('Filtern Sie optional nach einem Semester') ?>">
+ <option value=""><?= _('In Semester') ?></option>
+ <? foreach (array_reverse(Semester::getAll()) as $semester) : ?>
+ <option value="<?= htmlReady($semester->id) ?>"<?= $semester->id === Request::option('semester_id') ? ' selected' : '' ?>>
+ <?= htmlReady($semester->name) ?>
+ </option>
+ <? endforeach ?>
+ </select>
+
+ <input type="text"
+ name="search"
+ id="search_connectable_courses"
+ autofocus
+ placeholder="<?= _('Veranstaltung suchen ...') ?>"
+ value="<?= htmlReady(Request::get('search') != 1 ? Request::get('search') : '') ?>">
+ <?= Icon::create('search')->asInput([
+ 'title' => _('Suchen Sie nach beliebigen Veranstaltungen'),
+ 'data-dialog' => 1
+ ]) ?>
+ <a href="<?= $controller->connect() ?>" data-dialog title="<?= _('Suche schließen') ?>">
+ <?= Icon::create('decline') ?>
+ </a>
+ <? else : ?>
+ <?= Icon::create('search')->asInput([
+ 'title' => _('Suchen Sie nach beliebigen Veranstaltungen'),
+ 'data-dialog' => 1,
+ 'formaction' => $controller->connectURL(['search' => 1])
+ ]) ?>
+ <? endif ?>
+ </span>
+ </caption>
+ <thead>
+ <tr>
+ <th><?= _('Name') ?></th>
+ <th><?= _('Semester') ?></th>
+ <th class="actions"><?= _('Aktion') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? if (!Request::get('search') || Request::get('search') == 1) : ?>
+ <? if (count($my_courses) + count($suggestions) > 0) : ?>
+ <? foreach ($my_courses as $my_course) : ?>
+ <?= $this->render_partial('course/connectedcourses/_course_to_connect', ['course' => $my_course]) ?>
+ <? endforeach ?>
+ <? foreach ($suggestions as $suggested_course) : ?>
+ <?= $this->render_partial('course/connectedcourses/_course_to_connect', ['course' => $suggested_course]) ?>
+ <? endforeach ?>
+ <? else : ?>
+ <tr>
+ <td colspan="3">
+ <?= _('Suchen Sie nach Veranstaltungen.') ?>
+ </td>
+ </tr>
+ <? endif ?>
+ <? else : ?>
+ <? if (isset($searchresults) && count($searchresults)) : ?>
+ <? foreach ($searchresults as $course) : ?>
+ <?= $this->render_partial('course/connectedcourses/_course_to_connect', ['course' => $course]) ?>
+ <? endforeach ?>
+ <? else : ?>
+ <tr>
+ <td colspan="3">
+ <?= _('Keine passenden Ergebnisse gefunden.') ?>
+ </td>
+ </tr>
+ <? endif ?>
+ <? endif ?>
+ </tbody>
+ </table>
+</form>
diff --git a/app/views/course/connectedcourses/index.php b/app/views/course/connectedcourses/index.php
new file mode 100644
index 0000000..fa8006b
--- /dev/null
+++ b/app/views/course/connectedcourses/index.php
@@ -0,0 +1,112 @@
+<? if (count($connected) + count($proposals) > 0) : ?>
+ <? if (count($connected) > 0) : ?>
+ <form method="post">
+ <?= CSRFProtection::tokenTag() ?>
+ <table class="default">
+ <caption>
+ <?= _('Verknüpfte Veranstaltungen') ?>
+ <thead>
+ <tr>
+ <th><?= _('Name') ?></th>
+ <th class="actions"><?= _('Aktion') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($connected as $connection) : ?>
+ <tr>
+ <td>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/details/' . $connection['course_id']) ?>" target="_blank">
+ <?= CourseAvatar::getAvatar($connection['course_id'])->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($connection->course->getFullName()) ?>
+ </a>
+ </td>
+ <td class="actions">
+ <?= Icon::create('trash')->asInput([
+ 'title' => _('Verknüpfung aufheben'),
+ 'data-confirm' => _('Wirklich die Zuweisung zu der Veranstaltung aufheben?'),
+ 'formaction' => $controller->url_for('course/connectedcourses/remove/'.$connection['course_id'])
+ ]) ?>
+ </td>
+ </tr>
+ <? endforeach ?>
+ </tbody>
+ </caption>
+ </table>
+ </form>
+ <? endif ?>
+
+ <? if (count($proposals) > 0) : ?>
+ <form method="post">
+ <?= CSRFProtection::tokenTag() ?>
+ <table class="default">
+ <caption>
+ <?= _('Eingereichte Vorschläge') ?>
+ </caption>
+ <thead>
+ <tr>
+ <th><?= _('Name') ?></th>
+ <th><?= _('Vorgeschlagen von') ?></th>
+ <th class="actions"><?= _('Aktion') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($proposals as $proposal) : ?>
+ <tr>
+ <td>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/details/' . $connection['course_id']) ?>" target="_blank">
+ <?= CourseAvatar::getAvatar($proposal['course_id'])->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($proposal->course->getFullName()) ?>
+ </a>
+ </td>
+ <td>
+ <?= htmlReady($proposal->user->getFullName()) ?>
+ </td>
+ <td class="actions">
+ <? if ($proposal['proposed_from'] === 'course') : ?>
+ <?= Icon::create('accept')->asInput([
+ 'title' => _('Vorschlag annehmen'),
+ 'data-confirm' => _('Wirklich die Veranstaltung mit dieser Studiengruppe verknüpfen?'),
+ 'formaction' => $controller->connectURL($proposal['course_id'])
+ ]) ?>
+ <? endif ?>
+ <? if ($proposal['proposed_from'] === 'course') : ?>
+ <?= Icon::create('decline')->asInput([
+ 'title' => _('Vorschlag ablehnen'),
+ 'data-confirm' => _('Wirklich den Vorschlag ablehnen?'),
+ 'formaction' => $controller->declineURL($proposal->id)
+ ]) ?>
+ <? else : ?>
+ <?= Icon::create('decline')->asInput([
+ 'title' => _('Vorschlag zurückziehen'),
+ 'data-confirm' => _('Wirklich den Vorschlag zurückziehen?'),
+ 'formaction' => $controller->declineURL($proposal->id)
+ ]) ?>
+ <? endif ?>
+ </td>
+ </tr>
+ <? endforeach ?>
+ </tbody>
+ </table>
+ </form>
+ <? endif ?>
+
+<? else : ?>
+
+ <div class="studip-contents-overview-teaser">
+ <div class="teaser-content">
+
+ <div>
+ <header><?= _('Verknüpfung zu Lehrveranstaltungen') ?></header>
+ <?= _('Verknüpfen Sie diese Studiengruppen mit Lehrveranstaltungen, mit deren Inhalten sich diese Studiengruppe beschäftigt. Dadurch machen Sie diese Studiengruppe sichtbarer für andere Teilnehmende der Veranstaltung.') ?>
+ </div>
+
+ <?= \Studip\LinkButton::create(
+ _('Verknüpfung zu Lehrveranstaltung vorschlagen'),
+ $controller->connect(),
+ ['data-dialog' => 1]
+ )?>
+ </div>
+ </div>
+
+<? endif ?>
+
diff --git a/app/views/course/connectedstudygroups/_studygroup_to_connect.php b/app/views/course/connectedstudygroups/_studygroup_to_connect.php
new file mode 100644
index 0000000..d438cf1
--- /dev/null
+++ b/app/views/course/connectedstudygroups/_studygroup_to_connect.php
@@ -0,0 +1,21 @@
+<tr>
+ <td>
+ <?= StudygroupAvatar::getAvatar($course->id)->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($course->getFullName()) ?>
+ </td>
+ <td>
+ <? if ($course->start_semester) : ?>
+ <?= htmlReady($course->start_semester->name) ?>
+ <? if ($course->end_semester && $course->end_semester->id !== $course->start_semester->id) : ?>
+ - <?= htmlReady($course->end_semester->name) ?>
+ <? endif ?>
+ <? endif ?>
+ </td>
+ <td class="actions">
+ <?= Icon::create('add')->asInput([
+ 'title' => _('Verknüpfung mit dieser Studiengruppe vorschlagen.'),
+ 'formaction' => $controller->connectURL($course->id),
+ 'formmethod' => 'post'
+ ]) ?>
+ </td>
+</tr>
diff --git a/app/views/course/connectedstudygroups/connect.php b/app/views/course/connectedstudygroups/connect.php
new file mode 100644
index 0000000..9f7c094
--- /dev/null
+++ b/app/views/course/connectedstudygroups/connect.php
@@ -0,0 +1,79 @@
+<form method="get" action="<?= $controller->connect(['search' => 1]) ?>">
+ <?= CSRFProtection::tokenTag() ?>
+ <table class="default" style="margin-top: 20px;">
+ <caption>
+ <?= _('Studiengruppen') ?>
+ <span class="actions">
+ <? if (Request::get('search') || Request::get('semester_id')) : ?>
+ <select name="semester_id" aria-label="<?= _('Filtern Sie optional nach einem Semester') ?>">
+ <option value=""><?= _('In Semester') ?></option>
+ <? foreach (array_reverse(Semester::getAll()) as $semester) : ?>
+ <option value="<?= htmlReady($semester->id) ?>"<?= $semester->id === Request::option('semester_id') ? ' selected' : '' ?>><?= htmlReady($semester->name) ?></option>
+ <? endforeach ?>
+ </select>
+
+ <input type="text"
+ name="search"
+ id="search_connectable_courses"
+ autofocus
+ placeholder="<?= _('Veranstaltung suchen ...') ?>"
+ value="<?= htmlReady(Request::get('search') != 1 ? Request::get('search') : '') ?>">
+ <?= Icon::create('search')->asInput([
+ 'title' => _('Suchen Sie nach beliebigen Veranstaltungen'),
+ 'data-dialog' => 1
+ ]) ?>
+ <a href="<?= $controller->connect() ?>" data-dialog title="<?= _('Suche schließen') ?>">
+ <?= Icon::create('decline') ?>
+ </a>
+ <? else : ?>
+ <form action="<?= $controller->connect(['search' => 1]) ?>"
+ method="get"
+ class="default"
+ data-dialog>
+ <?= Icon::create('search')->asInput([
+ 'title' => _('Suchen Sie nach beliebiger Studiengruppe'),
+ 'data-dialog' => 1
+ ]) ?>
+ </form>
+ <? endif ?>
+ </span>
+ </caption>
+ <thead>
+ <tr>
+ <th><?= _('Name') ?></th>
+ <th><?= _('Semester') ?></th>
+ <th class="actions"><?= _('Aktion') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? if (!Request::get('search') || Request::get('search') == 1) : ?>
+ <? if (count($my_studygroups) + count($suggestions) > 0) : ?>
+ <? foreach ($my_studygroups as $my_course) : ?>
+ <?= $this->render_partial('course/connectedstudygroups/_studygroup_to_connect', ['course' => $my_course]) ?>
+ <? endforeach ?>
+ <? foreach ($suggestions as $suggested_course) : ?>
+ <?= $this->render_partial('course/connectedstudygroups/_studygroup_to_connect', ['course' => $suggested_course]) ?>
+ <? endforeach ?>
+ <? else : ?>
+ <tr>
+ <td colspan="3">
+ <?= _('Suchen Sie nach Studiengruppen.') ?>
+ </td>
+ </tr>
+ <? endif ?>
+ <? else : ?>
+ <? if (isset($searchresults) && count($searchresults)) : ?>
+ <? foreach ($searchresults as $course) : ?>
+ <?= $this->render_partial('course/connectedstudygroups/_studygroup_to_connect', ['course' => $course]) ?>
+ <? endforeach ?>
+ <? else : ?>
+ <tr>
+ <td colspan="3">
+ <?= _('Keine passenden Ergebnisse gefunden.') ?>
+ </td>
+ </tr>
+ <? endif ?>
+ <? endif ?>
+ </tbody>
+ </table>
+</form>
diff --git a/app/views/course/connectedstudygroups/index.php b/app/views/course/connectedstudygroups/index.php
new file mode 100644
index 0000000..4611b6c
--- /dev/null
+++ b/app/views/course/connectedstudygroups/index.php
@@ -0,0 +1,110 @@
+<? if (count($connected) + count($proposals) > 0) : ?>
+ <? if (count($connected) > 0) : ?>
+ <form method="post">
+ <table class="default">
+ <caption>
+ <?= _('Verknüpfte Studiengruppen') ?>
+ <thead>
+ <tr>
+ <th><?= _('Name') ?></th>
+ <th class="actions"><?= _('Aktion') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($connected as $connection) : ?>
+ <tr>
+ <td>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/studygroup/details/' . $connection['studygroup_id'], [], true) ?>">
+ <?= StudygroupAvatar::getAvatar($connection['studygroup_id'])->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($connection->studygroup->getFullName()) ?>
+ </a>
+ </td>
+ <td class="actions">
+ <?= CSRFProtection::tokenTag() ?>
+ <?= Icon::create('trash')->asInput([
+ 'title' => _('Verknüpfung aufheben'),
+ 'data-confirm' => _('Wirklich die Zuweisung zu der Studiengruppe aufheben?'),
+ 'formaction' => $controller->removeURL($connection['studygroup_id'])
+ ]) ?>
+ </td>
+ </tr>
+ <? endforeach ?>
+ </tbody>
+ </caption>
+ </table>
+ </form>
+ <? endif ?>
+
+ <? if (count($proposals) > 0) : ?>
+ <form method="post">
+ <table class="default">
+ <?= CSRFProtection::tokenTag() ?>
+ <caption>
+ <?= _('Eingereichte Vorschläge') ?>
+ </caption>
+ <thead>
+ <tr>
+ <th><?= _('Name') ?></th>
+ <th><?= _('Vorgeschlagen von') ?></th>
+ <th class="actions"><?= _('Aktion') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($proposals as $proposal) : ?>
+ <tr>
+ <td>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/studygroup/details/' . $proposal['studygroup_id']) ?>" target="_blank">
+ <?= StudygroupAvatar::getAvatar($proposal['studygroup_id'])->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($proposal->studygroup->getFullName()) ?>
+ </a>
+ </td>
+ <td>
+ <?= htmlReady($proposal->user->getFullName()) ?>
+ </td>
+ <td class="actions">
+ <? if ($proposal['proposed_from'] === 'studygroup') : ?>
+ <?= Icon::create('accept')->asInput([
+ 'title' => _('Vorschlag annehmen'),
+ 'data-confirm' => _('Wirklich die Studiengruppe mit dieser Veranstaltung verknüpfen?'),
+ 'formaction' => $controller->connectURL($proposal['studygroup_id'])
+ ]) ?>
+ <? endif ?>
+ <? if ($proposal['proposed_from'] === 'studycourse') : ?>
+ <?= Icon::create('decline')->asInput([
+ 'title' => _('Vorschlag ablehnen'),
+ 'data-confirm' => _('Wirklich den Vorschlag ablehnen?'),
+ 'formaction' => $controller->declineURL($proposal->id)
+ ]) ?>
+ <? else : ?>
+ <?= Icon::create('decline')->asInput([
+ 'title' => _('Vorschlag zurückziehen'),
+ 'data-confirm' => _('Wirklich den Vorschlag zurückziehen?'),
+ 'formaction' => $controller->declineURL($proposal->id)
+ ]) ?>
+ <? endif ?>
+ </td>
+ </tr>
+ <? endforeach ?>
+ </tbody>
+ </table>
+ </form>
+ <? endif ?>
+<? else : ?>
+
+ <div class="studip-contents-overview-teaser">
+ <div class="teaser-content">
+
+ <div>
+ <header><?= _('Verknüpfung zu Studiengruppen') ?></header>
+ <?= _('Verknüpfen Sie Studiengruppen, die sich mit den Inhalten dieser Veranstaltung beschäftigen.') ?>
+ </div>
+
+ <?= \Studip\LinkButton::create(
+ _('Verknüpfung zu Studiengruppe vorschlagen'),
+ $controller->connect(),
+ ['data-dialog' => 1]
+ )?>
+ </div>
+ </div>
+
+<? endif ?>
diff --git a/app/views/course/overview/index.php b/app/views/course/overview/index.php
index e538a6f..03fc848 100644
--- a/app/views/course/overview/index.php
+++ b/app/views/course/overview/index.php
@@ -68,6 +68,10 @@ if (!empty($questionnaires)) {
echo $questionnaires;
}
+if (!empty($connectedstudygroups)) {
+ echo $connectedstudygroups;
+}
+
// display plugins
if (!empty($plugins)) {
diff --git a/app/views/course/studygroup/details.php b/app/views/course/studygroup/details.php
index 26a3ef5..7fbbc39 100644
--- a/app/views/course/studygroup/details.php
+++ b/app/views/course/studygroup/details.php
@@ -12,6 +12,10 @@
<dl style="margin: 0">
<dt><?= _('Name der Studiengruppe') ?></dt>
<dd><?= htmlReady($studygroup->name) ?></dd>
+ <? if ((string) $studygroup->Beschreibung): ?>
+ <dt><?= _('Beschreibung') ?></dt>
+ <dd><?= formatLinks($studygroup->Beschreibung) ?></dd>
+ <? endif; ?>
<? if ((string) $studygroup->beschreibung): ?>
<dt><?= _('Beschreibung') ?></dt>
@@ -33,6 +37,21 @@
</section>
</article>
+<? if (count($studygroup->tags) > 0) : ?>
+<article class="studip">
+ <header>
+ <h1><?= _('Schlagwörter') ?></h1>
+ </header>
+ <section>
+ <? foreach ($studygroup->tags as $tag) : ?>
+ <a href="<?= URLHelper::getLink('dispatch.php/studygroup/browse', ['q' => $tag['name']]) ?>">
+ <?= htmlReady('#'.$tag['name']) ?>
+ </a>
+ <? endforeach ?>
+ </section>
+</article>
+<? endif ?>
+
<div class="hidden-medium-up">
<? foreach ($sidebarActions as $action) : ?>
<?= Studip\LinkButton::create($action->label, $action->url) ?>
diff --git a/app/views/course/studygroup/edit.php b/app/views/course/studygroup/edit.php
index e3189f7..3891e94 100644
--- a/app/views/course/studygroup/edit.php
+++ b/app/views/course/studygroup/edit.php
@@ -4,7 +4,7 @@
<?= CSRFProtection::tokenTag() ?>
<fieldset>
<legend>
- <?= _('Studiengruppe bearbeiten') ?>
+ <?= _('Grunddaten') ?>
</legend>
<input type='submit' class="invisible" name="<?=_('Änderungen übernehmen') ?>" aria-hidden="true">
@@ -35,12 +35,37 @@
<option value="invisible" <? if (!$course->visible) echo 'selected'; ?> <? if (!Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED) echo 'disabled'; ?>>
<?= _('Unsichtbar') ?>
</option>
+ <? endif; ?>
+ <? if (true) : ?>
+ <? $courseset = CourseSet::getSetForCourse($sem_id) ?>
+ <option value="top-course"<?= $courseset && $courseset->getId() === CourseSet::getConnectedcourseAdmissionSetId() ? ' selected' : '' ?>>
+ <?= _('Für Mitglieder der zugehörigen Lehrveranstaltung') ?>
+ </option>
+ <? endif ?>
+ <? if (true) : ?>
+ <? $courseset = CourseSet::getSetForCourse($sem_id) ?>
+ <option value="top-course"<?= $courseset && $courseset->getId() === CourseSet::getConnectedcourseAdmissionSetId() ? ' selected' : '' ?>>
+ <?= _('Für Mitglieder der zugehörigen Lehrveranstaltung') ?>
+ </option>
<? endif ?>
</select>
</label>
</fieldset>
+ <fieldset>
+ <legend><?= _('Erweiterte Einstellungen') ?></legend>
+
+ <label>
+ <?= _('Ablaufdatum') ?>
+ <input type="text" name="expiration_date">
+ </label>
+
+ <label>
+ <?= _('Schlagwörter') ?>
+ </label>
+ </fieldset>
+
<footer>
<?= Studip\Button::createAccept(_('Übernehmen'), ['title' => _("Änderungen übernehmen")]); ?>
<?= Studip\LinkButton::createCancel(_('Abbrechen'), URLHelper::getURL('dispatch.php/course/go')); ?>
diff --git a/app/views/course/studygroup/widget.php b/app/views/course/studygroup/widget.php
new file mode 100644
index 0000000..fc0f133
--- /dev/null
+++ b/app/views/course/studygroup/widget.php
@@ -0,0 +1,88 @@
+<article class="studip connectedcourses_widget">
+ <header>
+ <h1>
+
+ <? if ($course->isStudygroup()) : ?>
+ <?= Icon::create('seminar', Icon::ROLE_INFO)->asimg(['class' => "text-bottom"]) ?>
+ <?= _('Zugehörige Veranstaltung') ?>
+ <? else : ?>
+ <?= Icon::create('studygroup', Icon::ROLE_INFO)->asimg(['class' => "text-bottom"]) ?>
+ <?= _('Verknüpfte Studiengruppen') ?>
+ <? endif ?>
+ </h1>
+
+ </header>
+
+ <section>
+ <? if ($course->isStudygroup()) : ?>
+ <ul>
+ <? foreach ($connections as $connection) : ?>
+ <li>
+ <? $link = $connection->course->isAccessibleToUser()
+ ? URLHelper::getLink('seminar_main.php', ['auswahl' => $connection->course->id])
+ : URLHelper::getLink('dispatch.php/course/details', ['cid' => $connection->course->id]) ?>
+ <a href="<?= $link ?>">
+ <?= htmlReady($connection->course->getFullname()) ?>
+ </a>
+ </li>
+ <? endforeach ?>
+ </ul>
+ <? else : ?>
+ <table class="default">
+ <colgroup>
+ <col style="width: 60px;">
+ </colgroup>
+ <thead>
+ <tr>
+ <th><?= _('Avatar') ?></th>
+ <th><?= _('Name / Beschreibung') ?></th>
+ <th><?= _('Mitglieder') ?></th>
+ <th><?= _('Gründer:in') ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <? foreach ($connections as $connection) : ?>
+ <tr>
+ <td>
+ <? $link = $connection->studygroup->isAccessibleToUser()
+ ? URLHelper::getLink('seminar_main.php', ['auswahl' => $connection->studygroup->id])
+ : URLHelper::getLink('dispatch.php/course/studygroup/details/'.$connection->studygroup->id) ?>
+ <a href="<?= $link ?>">
+ <?= CourseAvatar::getAvatar($connection->studygroup->id)->getImageTag(Avatar::SMALL) ?>
+ </a>
+ </td>
+ <td>
+ <a href="<?= $link ?>">
+ <?= htmlReady($connection->studygroup->getFullname()) ?>
+ </a>
+ <? if ($connection->studygroup->beschreibung) : ?>
+ <div>
+ <?= htmlReady($connection->studygroup->beschreibung) ?>
+ </div>
+ <? endif ?>
+ </td>
+ <td>
+ <?= count($connection->studygroup->members) ?>
+ </td>
+ <td>
+ <?
+ $founders = $connection->studygroup->members->filter(function ($m) { return $m['status'] === 'dozent'; });
+ foreach ($founders as $index => $founder) : ?>
+ <? if ($index > 0) : ?>
+ ,
+ <? endif ?>
+ <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $founder->user->username]) ?>">
+ <?= Avatar::getAvatar($founder->user->id)->getImageTag(Avatar::SMALL) ?>
+ <?= htmlReady($founder->user->getFullname()) ?>
+ </a>
+ <? endforeach ?>
+ </td>
+ </tr>
+ <? endforeach ?>
+ </tbody>
+ </table>
+ <? endif ?>
+
+ </section>
+
+</article>
diff --git a/app/views/course/wizard/step.php b/app/views/course/wizard/step.php
index 0fe1dfc..214515a 100644
--- a/app/views/course/wizard/step.php
+++ b/app/views/course/wizard/step.php
@@ -10,10 +10,14 @@
?>
<? if ($content) : ?>
<form class="default course-wizard-step-<?= $stepnumber ?>" action="<?= $controller->link_for('course/wizard/process', $stepnumber, $temp_id) ?>" method="post" data-secure>
- <fieldset>
- <?= $content ?>
- </fieldset>
+ <? if (!$studygroup) : ?>
+ <fieldset>
+ <? endif; ?>
+ <?= $content ?>
+ <? if (!$studygroup) : ?>
+ </fieldset>
+ <? endif; ?>
<footer data-dialog-button>
<input type="hidden" name="step" value="<?= $stepnumber ?>">
<? if (empty($first_step)): ?>
@@ -23,11 +27,15 @@
!empty($dialog) ? ['data-dialog' => 'size=50%'] : []
) ?>
<? endif; ?>
+ <? if (!$studygroup) : ?>
<?= Studip\Button::create(
_('Weiter'),
'next',
!empty($dialog) ? ['data-dialog' => 'size=50%'] : []
) ?>
+ <? else : ?>
+ <?= Studip\Button::createAccept(_('Studiengruppe anlegen'), 'create') ?>
+ <? endif; ?>
</footer>
</form>
<? else : ?>
diff --git a/app/views/course/wizard/steps/basicdata/index_studygroup.php b/app/views/course/wizard/steps/basicdata/index_studygroup.php
index 9f75da5..10368b9 100644
--- a/app/views/course/wizard/steps/basicdata/index_studygroup.php
+++ b/app/views/course/wizard/steps/basicdata/index_studygroup.php
@@ -34,6 +34,12 @@
rows="4"><?= htmlReady($values['description'] ?? '') ?></textarea>
</label>
+<label class="col-3">
+ <?= _('Bezieht sich auf Lehrveranstaltung (optional)') ?>
+ <?= QuickSearch::get('lv_course_id', new StandardSearch('Seminar_id'))
+ ->defaultValue($values['lv_course_id'], $values['lv_course_id'] ? Course::find($values['lv_course_id'])->getFullname() : '')
+ ->render() ?>
+</label>
<label class="col-3">
<span class="required"><?= _('Zugang') ?></span>
@@ -74,6 +80,7 @@
<input type="hidden" name="institute" value="<?= $values['institute'] ?>"/>
<input type="hidden" name="start_semester" value="<?= htmlReady($values['start_semester']) ?>">
<input type="hidden" name="studygroup" value="1"/>
+<input type="hidden" name="stgteil_id" value="<?= htmlReady($values['stgteil_id']) ?>"/>
<?php foreach ($values['lecturers'] as $id => $assigned) : ?>
<input type="hidden" name="lecturers[<?= $id ?>]" value="1"/>
<?php endforeach ?>
diff --git a/app/views/course/wizard/steps/studygroups/index.php b/app/views/course/wizard/steps/studygroups/index.php
new file mode 100644
index 0000000..b7327a9
--- /dev/null
+++ b/app/views/course/wizard/steps/studygroups/index.php
@@ -0,0 +1,110 @@
+<fieldset>
+<legend>
+ <?= _('Grunddaten') ?>
+</legend>
+
+<label class="">
+ <span class="required"><?= _('Name') ?></span>
+ <input type="text" name="name" id="wizard-name" maxlength="254" value="<?= htmlReady($values['name'] ?? '') ?>" required>
+</label>
+
+<? if(count($types) > 1) : ?>
+ <label class="">
+ <span class="required"><?= _('Typ') ?></span>
+ <select name="coursetype" id="wizard-coursetype">
+ <?php foreach ($types as $class => $subtypes) : ?>
+ <optgroup label="<?= htmlReady($class) ?>">
+ <?php foreach ($subtypes as $type) : ?>
+ <option value="<?= $type['id'] ?>"<?= $type['id'] == $values['coursetype'] ? ' selected="selected"' : '' ?>>
+ <?= htmlReady($type['name']) ?>
+ </option>
+ <?php endforeach ?>
+ </optgroup>
+ <?php endforeach ?>
+ </select>
+ </label>
+<? else : ?>
+ <? $type = array_values($types)[0]; ?>
+ <input type="hidden" name="coursetype" value="<?= htmlReady($type[0]['id']) ?>">
+<? endif ?>
+
+
+<label class="">
+ <?= _('Beschreibung') ?>
+ <textarea name="description" id="wizard-description"
+ rows="4"><?= htmlReady($values['description'] ?? '') ?></textarea>
+</label>
+
+
+<label class="">
+ <span class="required"><?= _('Zugang') ?></span>
+
+ <select name="access" id="wizard-access">
+ <option value="all"
+ <? if (isset($values['access']) && $values['access'] === 'all') echo 'selected'; ?>>
+ <?= _('offen für alle') ?>
+ </option>
+ <option value="invite"
+ <? if (isset($values['access']) && $values['access'] === 'invite') echo 'selected'; ?>>
+ <?= _('auf Anfrage') ?>
+ </option>
+ <?php if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED) : ?>
+ <option value="invisible"
+ <? if (isset($values['access']) && $values['access'] === 'invisible') echo 'selected'; ?>>
+ <?= _('unsichtbar') ?>
+ </option>
+ <?php endif ?>
+ </select>
+</label>
+
+
+<label><span class="required"><?= _('Nutzungsbedingungen')?></span></label>
+
+<? if ($GLOBALS['perm']->have_perm('admin')) : ?>
+ <p style="font-weight: bold;">
+ <?= _('Ich habe die eingetragenen Personen darüber informiert, dass in Ihrem Namen eine Studiengruppe angelegt wird und versichere, dass Sie mit folgenden Nutzungsbedingungen einverstandenen sind:') ?>
+ </p>
+<? endif ?>
+<?= formatReady(Config::Get()->STUDYGROUP_TERMS) ?>
+
+<label>
+ <input type="checkbox" name="accept" id="wizard-accept" required>
+ <?= _('Einverstanden') ?>
+</label>
+</fieldset>
+
+<fieldset>
+ <legend>
+ <?= _('Erweiterte Einstellungen') ?>
+ </legend>
+
+ <label>
+ <?= _('Ablaufdatum / Löschdatum') ?>
+ <input type="text" aria-label="<?= _('Ablaufdatum / Löschdatum') ?>" title="<?= _('Ablaufdatum / Löschdatum') ?>"
+ data-date-picker
+ name="exp_date"
+ value="<?= date('d.m.Y H:i', time() + 86400 * 365 * 2) ?>"
+ class="hasDatePicker">
+ </label>
+
+ <label>
+ <?= _('Schlagwörter') ?>
+ <?= Studip\VueApp::create('Multiquicksearch')
+ ->withProps([
+ 'name' => 'tags[]',
+ 'searchtype' => (string) SQLSearch::get('SELECT `name`, `name` FROM `tags` WHERE `active` = 1 AND `name` LIKE :input', _('Schlagwort suchen')),
+ 'autocomplete' => true,
+ 'addlabel' => _('Schlagwort hinzufügen')
+ ])
+ ?>
+ </label>
+
+</fieldset>
+
+
+<input type="hidden" name="institute" value="<?= $values['institute'] ?>">
+<input type="hidden" name="studygroup" value="1">
+<input type="hidden" name="stgteil_id" value="<?= htmlReady($values['stgteil_id']) ?>">
+<?php foreach ($values['lecturers'] as $id => $assigned) : ?>
+ <input type="hidden" name="lecturers[<?= $id ?>]" value="1">
+<?php endforeach ?>
diff --git a/app/views/my_studygroups/_course.php b/app/views/my_studygroups/_course.php
index 37c081e..e554ddb 100644
--- a/app/views/my_studygroups/_course.php
+++ b/app/views/my_studygroups/_course.php
@@ -4,6 +4,7 @@
<td>
<?= StudygroupAvatar::getAvatar($group['seminar_id'])->getImageTag(Avatar::SMALL, ['title' => $group['name']]) ?>
</td>
+
<td style="text-align: left">
<a href="<?= URLHelper::getLink('dispatch.php/course/go', ['to' => $group['seminar_id']]) ?>"
<?= $group['last_visitdate'] < $group['chdate'] ? 'style="color: red;"' : '' ?>>
@@ -21,6 +22,9 @@
<?= tooltipicon($infotext) ?>
<? endif ?>
</td>
+ <td data-sort-value="<?= $group['mkdate'] ?>">
+ <?= htmlReady(date('d.m.Y', $group['mkdate'])) ?>
+ </td>
<td style="text-align: left; white-space: nowrap;">
<? if (!empty($group['navigation'])) : ?>
<ul class="my-courses-navigation" style="flex-wrap: nowrap">
@@ -43,28 +47,30 @@
</ul>
<? endif ?>
</td>
- <td style="text-align: right">
- <? if (in_array($group["user_status"], ["dozent", "tutor"])) : ?>
- <? $adminmodule = $group["sem_class"]->getAdminModuleObject(); ?>
- <? if ($adminmodule) : ?>
- <? $adminnavigation = $adminmodule->getIconNavigation($group['seminar_id'], 0, $GLOBALS['user']->id); ?>
- <? endif ?>
- <? if ($adminnavigation) : ?>
- <a href="<?= URLHelper::getLink($adminnavigation->getURL(), ['cid' => $group['seminar_id']]) ?>">
- <?= $adminnavigation->getImage()->asImg($adminnavigation->getLinkAttributes())?>
+ <? if (!$is_widget) : ?>
+ <td style="text-align: right">
+ <? if (in_array($group["user_status"], ["dozent", "tutor"])) : ?>
+ <? $adminmodule = $group["sem_class"]->getAdminModuleObject(); ?>
+ <? if ($adminmodule) : ?>
+ <? $adminnavigation = $adminmodule->getIconNavigation($group['seminar_id'], 0, $GLOBALS['user']->id); ?>
+ <? endif ?>
+ <? if ($adminnavigation) : ?>
+ <a href="<?= URLHelper::getLink($adminnavigation->getURL(), ['cid' => $group['seminar_id']]) ?>">
+ <?= $adminnavigation->getImage()->asImg($adminnavigation->getLinkAttributes())?>
+ </a>
+ <? endif ?>
+
+ <? elseif (!empty($group['binding'])) : ?>
+ <a href="<?= URLHelper::getLink('', ['to' => $group['seminar_id'], 'cmd' => 'no_kill']) ?>">
+ <?= Icon::create('door-leave', Icon::ROLE_INACTIVE)->asImg(['title' => _('Die Teilnahme ist bindend. Bitte wenden Sie sich an die Lehrenden.')]) ?>
+ </a>
+ <?
+ else : ?>
+ <a href="<?= URLHelper::getLink("dispatch.php/my_courses/decline/{$group['seminar_id']}", ['cmd' => 'suppose_to_kill']) ?>">
+ <?= Icon::create('door-leave', Icon::ROLE_INACTIVE)->asImg(['title' => _('aus der Studiengruppe abmelden')]) ?>
</a>
<? endif ?>
-
- <? elseif (!empty($group['binding'])) : ?>
- <a href="<?= URLHelper::getLink('', ['to' => $group['seminar_id'], 'cmd' => 'no_kill']) ?>">
- <?= Icon::create('door-leave', Icon::ROLE_INACTIVE)->asImg(['title' => _('Die Teilnahme ist bindend. Bitte wenden Sie sich an die Lehrenden.')]) ?>
- </a>
- <?
- else : ?>
- <a href="<?= URLHelper::getLink("dispatch.php/my_courses/decline/{$group['seminar_id']}", ['cmd' => 'suppose_to_kill']) ?>">
- <?= Icon::create('door-leave', Icon::ROLE_INACTIVE)->asImg(['title' => _('aus der Studiengruppe abmelden')]) ?>
- </a>
+ </td>
<? endif ?>
- </td>
</tr>
<? endforeach ?>
diff --git a/app/views/my_studygroups/index.php b/app/views/my_studygroups/index.php
index 6fd2d20..cfdd2e2 100644
--- a/app/views/my_studygroups/index.php
+++ b/app/views/my_studygroups/index.php
@@ -1,5 +1,5 @@
<? if (!empty($studygroups)) : ?>
- <table class="default" id="my_seminars">
+ <table class="default sortable-table" id="my_seminars">
<caption>
<?= _('Meine Studiengruppen') ?>
</caption>
@@ -7,20 +7,27 @@
<col width="10px">
<col width="25px">
<col>
+ <col>
<col width="<?= $nav_elements * 27 ?>px">
- <col width="45px">
+ <? if (!$is_widget) : ?>
+ <col width="45px">
+ <? endif ?>
</colgroup>
<thead>
- <tr>
+ <tr class="sortable" title="<?= _('Klicken, um die Sortierung zu ändern') ?>">
+
<th colspan="2" nowrap align="center">
<a href="<?= URLHelper::getLink('dispatch.php/my_courses/groups/all/true') ?>"
data-dialog="size=normal">
<?= Icon::create('group')->asImg(['title' => _('Gruppe ändern'), 'class' => 'middle']) ?>
</a>
</th>
- <th><?= _('Name') ?></th>
+ <th data-sort="text"><?= _('Name') ?></th>
+ <th data-sort="digit"><?= _('gegründet') ?></th>
<th><?= _('Inhalt') ?></th>
- <th></th>
+ <? if (!$is_widget) : ?>
+ <th><?= _('Aktionen') ?></th>
+ <? endif ?>
</tr>
</thead>
<?= $this->render_partial('my_studygroups/_course', compact('studygroups')) ?>
diff --git a/app/views/my_studygroups/proposals.php b/app/views/my_studygroups/proposals.php
new file mode 100644
index 0000000..7347849
--- /dev/null
+++ b/app/views/my_studygroups/proposals.php
@@ -0,0 +1,31 @@
+<section class="studip-tiles">
+ <? foreach ($proposed_studygroups as $course) : ?>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/studygroup/details/'.$course->id) ?>">
+ <div>
+ <?= StudygroupAvatar::getAvatar($course->id)->getImageTag(Avatar::MEDIUM) ?>
+ <div>
+ <strong>
+ <?= htmlReady($course->getFullname()) ?>
+ </strong>
+ <div>
+ <?= sprintf(
+ ngettext(
+ '1 Mitglied',
+ '%s Mitglieder',
+ count($course->members)
+ ),
+ count($course->members)
+ ) ?>
+ </div>
+ </div>
+ </div>
+ <? if (count($course->tags)) : ?>
+ <div>
+ <? foreach ($course->tags as $tag) : ?>
+ <?= '#'.htmlReady($tag->name) ?>
+ <? endforeach ?>
+ </div>
+ <? endif ?>
+ </a>
+ <? endforeach ?>
+</section>
diff --git a/app/views/search/studiengaenge/verlauf.php b/app/views/search/studiengaenge/verlauf.php
index 4464e66..540f46e 100644
--- a/app/views/search/studiengaenge/verlauf.php
+++ b/app/views/search/studiengaenge/verlauf.php
@@ -143,4 +143,59 @@
<? endforeach ?>
</tbody>
</table>
+
+ <h2><?= _('Studentische Arbeitsgruppen') ?></h2>
+
+ <section class="studip-tiles">
+ <? foreach ($studiengangTeil->studygroups as $course) : ?>
+ <div>
+ <div class="with-action-menu">
+ <div>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/studygroup/details/'.$course->id) ?>">
+ <?= CourseAvatar::getAvatar($course->id)->getImageTag(Avatar::MEDIUM) ?>
+ </a>
+ <a href="<?= URLHelper::getLink('dispatch.php/course/studygroup/details/'.$course->id) ?>">
+ <strong>
+ <?= htmlReady($course->name) ?>
+ </strong>
+ <div>
+ <?= sprintf(
+ ngettext(
+ '1 Mitglied',
+ '%s Mitglieder',
+ count($course->members)
+ ),
+ $course->members
+ ) ?>
+ </div>
+ </a>
+ </div>
+ <? if ($GLOBALS['perm']->have_perm('admin')) : ?>
+ <form method="post">
+ <?= CSRFProtection::tokenTag() ?>
+ <button class="undecorated"
+ data-confirm="<?= sprintf(_('Wirklich diese Studiengruppe aus dem Studiengang %s entfernen?'), $studiengangTeilName) ?>"
+ formaction="<?= $controller->remove_studygroup($course->id, $studiengangTeil->id) ?>">
+ <?= Icon::create('trash') ?>
+ </button>
+ </form>
+ <? endif ?>
+ </div>
+ <? if (count($course->tags)) : ?>
+ <div>
+ <? foreach ($course->tags as $tag) : ?>
+ <?= '#'.htmlReady($tag->name) ?>
+ <? endforeach ?>
+ </div>
+ <? endif ?>
+ </div>
+ <? endforeach ?>
+
+ <a href="<?= URLHelper::getLink('dispatch.php/course/wizard', ['studygroup' => 1, 'stgteil_id' => $studiengangTeil->id] )?>">
+ <div>
+ <?= Icon::create('add')->asImg(50) ?>
+ <strong><?= _('Neue Studiengruppe erstellen') ?></strong>
+ </div>
+ </a>
+ </section>
<? endif ?>
diff --git a/app/views/studygroup/browse.php b/app/views/studygroup/browse.php
index 6362d6a..cf8fe3e 100644
--- a/app/views/studygroup/browse.php
+++ b/app/views/studygroup/browse.php
@@ -18,16 +18,16 @@
<?php
$headers = [
- 'name' => _('Name'),
- 'founded' => _('gegründet'),
- 'member' => _('Mitglieder'),
- 'founder' => _('GründerIn'),
- 'ismember' => _('Mitglied'),
+ 'name' => _('Name'),
+ 'tags' => _('Schlagwörter'),
+ 'last_activity' => _('Letzte Aktivität'),
+ 'member' => _('Mitglieder'),
+ 'founder' => _('Gründer:in')
];
?>
<? if ($anzahl > 0): ?>
- <table class="default studygroup-browse">
+ <table class="default studygroup-browse sortable-table" data-sortlist="[[3, 1]]">
<caption>
<?= sprintf(ngettext('%u Studiengruppe', '%u Studiengruppen', $anzahl), $anzahl)?>
</caption>
@@ -36,19 +36,30 @@ $headers = [
<col>
<col style="width: 10%">
<col style="width: 10%">
- <col style="width: 20%">
<col style="width: 10%">
+ <col style="width: 20%">
</colgroup>
<thead>
<tr class="sortable" title="<?= _('Klicken, um die Sortierung zu ändern') ?>">
<th class="nosort hidden-small-down"></th>
- <? foreach ($headers as $key => $label): ?>
- <th <? if ($sort_type === $key) echo 'class="sort' . $sort_order . '"'; ?>>
- <a href="<?= $controller->link_for("studygroup/browse/1/{$key}_" . ($sort_order === 'asc' ? 'desc' : 'asc'), compact('q', 'closed')) ?>">
- <?= htmlReady($label) ?>
- </a>
- </th>
- <? endforeach; ?>
+ <? foreach ($headers as $key => $label): ?>
+ <? if ($key !== 'last_activity' && $key !== 'tags') : ?>
+ <th <? if ($sort_type === $key) echo 'class="sort' . $sort_order . '"'; ?>>
+ <a href="<?= $controller->link_for("studygroup/browse/1/{$key}_" . ($sort_order === 'asc' ? 'desc' : 'asc'), compact('q', 'closed')) ?>">
+ <?= htmlReady($label) ?>
+ </a>
+ </th>
+ <? elseif($key !== 'tags') : ?>
+ <th data-sort="htmldata">
+ <?= htmlReady($label) ?>
+ </th>
+ <? else : ?>
+ <th>
+ <?= htmlReady($label) ?>
+ </th>
+ <? endif; ?>
+ <? endforeach; ?>
+ <th></th>
</tr>
</thead>
<tbody>
@@ -71,7 +82,15 @@ $headers = [
<? } ?>
</a>
</td>
- <td><?= strftime('%x', $group['mkdate']) ?>
+ <td>
+ <? foreach ($group['course']->tags as $tag) : ?>
+ <a href="<?= $controller->browse(['q' => $tag['name']]) ?>">
+ <?= htmlReady('#'.$tag['name']) ?>
+ </a>
+ <? endforeach ?>
+ </td>
+ <td data-sort-value="<?= htmlReady($group['last_visit_date']) ?>">
+ <?= htmlReady(date('d.m.Y', $group['last_visit_date'])) ?>
</td>
<td align="center">
<?= StudygroupModel::countMembers($group['Seminar_id']) ?>
@@ -88,11 +107,6 @@ $headers = [
<br>
<? endforeach; ?>
</td>
- <td align="center">
- <? if ($is_member) : ?>
- <?= Icon::create('person', Icon::ROLE_INACTIVE, ['title' => _('Sie sind Mitglied in dieser Gruppe')])->asImg() ?>
- <? endif; ?>
- </td>
</tr>
<? endforeach; ?>
</tbody>