diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php
index c28c49485..12cd77048 100644
--- a/application/controllers/api/frontend/v1/stv/Config.php
+++ b/application/controllers/api/frontend/v1/stv/Config.php
@@ -91,6 +91,10 @@ class Config extends FHCAPI_Controller
'title' => $this->p->t('stv', 'tab_resources'),
'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js'
];
+ $result['groups'] = [
+ 'title' => $this->p->t('stv', 'tab_groups'),
+ 'component' => './Stv/Studentenverwaltung/Details/Gruppen.js'
+ ];
/* TODO(chris): Ausgeblendet für Testing
$result['grades'] = [
'title' => $this->p->t('stv', 'tab_grades'),
diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/stv/Favorites.php
index 8d7a6cd14..b8fe6f3d7 100644
--- a/application/controllers/api/frontend/v1/stv/Favorites.php
+++ b/application/controllers/api/frontend/v1/stv/Favorites.php
@@ -48,7 +48,7 @@ class Favorites extends FHCAPI_Controller
if (!$data)
$this->terminateWithSuccess(null);
else
- $this->terminateWithSuccess($data['stv_favorites']);
+ $this->terminateWithSuccess($data['stv_favorites'] ?? null);
}
public function set()
diff --git a/application/controllers/api/frontend/v1/stv/Gruppen.php b/application/controllers/api/frontend/v1/stv/Gruppen.php
new file mode 100644
index 000000000..39c5efe21
--- /dev/null
+++ b/application/controllers/api/frontend/v1/stv/Gruppen.php
@@ -0,0 +1,81 @@
+ ['admin:r', 'assistenz:r'],
+ 'deleteGruppe' => ['admin:rw', 'assistenz:rw'],
+ ]);
+
+ // Load Libraries
+ $this->load->library('VariableLib', ['uid' => getAuthUID()]);
+
+ // Load language phrases
+ $this->loadPhrases([
+ 'ui', 'gruppenmanagement'
+ ]);
+
+ // Load models
+ $this->load->model('person/Benutzergruppe_model', 'BenutzergruppeModel');
+ $this->load->model('organisation/Gruppe_model', 'GruppeModel');
+ }
+
+ public function getGruppen($student_uid)
+ {
+ $this->BenutzergruppeModel ->addSelect('gruppe_kurzbz');
+ $this->BenutzergruppeModel ->addSelect('bezeichnung');
+ $this->BenutzergruppeModel ->addSelect('generiert');
+ $this->BenutzergruppeModel ->addSelect('uid');
+ $this->BenutzergruppeModel ->addSelect('studiensemester_kurzbz');
+ $this->BenutzergruppeModel ->addSelect('public.tbl_benutzergruppe.insertvon');
+ $this->BenutzergruppeModel ->addJoin('public.tbl_gruppe', 'gruppe_kurzbz');
+ $this->BenutzergruppeModel-> addOrder('bezeichnung', 'ASC');
+
+ $result = $this->BenutzergruppeModel->loadWhere(
+ array(
+ 'uid' => $student_uid
+ )
+ );
+
+ $data = $this->getDataOrTerminateWithError($result);
+
+ $this->terminateWithSuccess($data);
+ }
+
+ public function deleteGruppe()
+ {
+ $student_uid = $this->input->post('id');
+ $gruppe_kurzbz = $this->input->post('gruppe_kurzbz');
+
+ //Validate if automatic group generation
+ $result = $this->GruppeModel-> loadWhere(
+ array(
+ 'gruppe_kurzbz' => $gruppe_kurzbz
+ )
+ );
+ $data = $this->getDataOrTerminateWithError($result);
+ $generation = current($data);
+
+ if($generation->generiert)
+ {
+ $this->terminateWithError($this->p->t('gruppenmanagement', 'error_deleteGeneratedGroups'), self::ERROR_TYPE_GENERAL);
+ }
+
+ $result = $this->BenutzergruppeModel->delete(
+ array(
+ 'gruppe_kurzbz' => $gruppe_kurzbz,
+ 'uid' => $student_uid
+ )
+ );
+
+ $data = $this->getDataOrTerminateWithError($result);
+
+ return $this->terminateWithSuccess($data);
+ }
+}
diff --git a/public/js/api/stv.js b/public/js/api/stv.js
index 14fcc6661..8b14beb14 100644
--- a/public/js/api/stv.js
+++ b/public/js/api/stv.js
@@ -2,12 +2,14 @@ import verband from './stv/verband.js';
import students from './stv/students.js';
import filter from './stv/filter.js';
import konto from './stv/konto.js';
+import group from './stv/group.js';
export default {
verband,
students,
filter,
konto,
+ group,
configStudent() {
return this.$fhcApi.get('api/frontend/v1/stv/config/student');
},
diff --git a/public/js/api/stv/group.js b/public/js/api/stv/group.js
new file mode 100644
index 000000000..af6e6e122
--- /dev/null
+++ b/public/js/api/stv/group.js
@@ -0,0 +1,8 @@
+export default {
+ getGruppen(url, config, params) {
+ return this.$fhcApi.get('api/frontend/v1/stv/Gruppen/getGruppen/' + params.id);
+ },
+ deleteGroup(params) {
+ return this.$fhcApi.post('api/frontend/v1/stv/Gruppen/deleteGruppe/', params);
+ }
+}
\ No newline at end of file
diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js
index 8779e4bf1..eaa253c2c 100644
--- a/public/js/components/Stv/Studentenverwaltung.js
+++ b/public/js/components/Stv/Studentenverwaltung.js
@@ -57,6 +57,7 @@ export default {
hasPermissionToSkipStatusCheck: this.permissions['student/keine_studstatuspruefung'],
hasPermissionRtAufsicht: this.permissions['lehre/reihungstestAufsicht'],
lists: this.lists,
+ currentSemester: Vue.computed(() => this.studiensemesterKurzbz),
defaultSemester: this.defaultSemester,
$reloadList: () => {
this.$refs.stvList.reload();
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js
new file mode 100644
index 000000000..1c7c47d6b
--- /dev/null
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js
@@ -0,0 +1,19 @@
+import GruppenList from './Gruppen/Gruppen.js';
+
+export default {
+ components: {
+ GruppenList
+ },
+ props: {
+ modelValue: Object
+ },
+ methods: {
+ reload() {
+ this.$refs.gruppen.$refs.table.reloadTable();
+ }
+ },
+ template: `
+
+
+
`
+};
\ No newline at end of file
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js
new file mode 100644
index 000000000..6a657a793
--- /dev/null
+++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js
@@ -0,0 +1,182 @@
+import {CoreFilterCmpt} from "../../../../filter/Filter.js";
+
+export default {
+ components: {
+ CoreFilterCmpt,
+ },
+ inject: {
+ currentSemester: {
+ from: 'currentSemester',
+ },
+ },
+ props: {
+ student: Object
+ },
+ data() {
+ return {
+ tabulatorOptions: {
+ ajaxURL: 'dummy',
+ ajaxRequestFunc: this.$fhcApi.factory.stv.group.getGruppen,
+ ajaxParams: () => {
+ return {
+ id: this.student.uid
+ };
+ },
+ ajaxResponse: (url, params, response) => response.data,
+ initialFilter: [
+ {field: "uid", type: "=", value: this.student.uid},
+ [
+ {field: "studiensemester_kurzbz", type: "=", value: this.currentSemester},
+ {field: "insertvon", type: "=", value: "mlists_generate"}
+ ]
+ ],
+ columns: [
+ {title: "Gruppe", field: "gruppe_kurzbz"},
+ {title: "Bezeichnung", field: "bezeichnung"},
+ {title: "Semester", field: "studiensemester_kurzbz"},
+ {
+ title: "automatisch generiert",
+ field: "generiert",
+ formatter: "tickCross",
+ hozAlign: "center",
+ formatterParams: {
+ tickElement: '',
+ crossElement: ''
+ }
+ },
+ {title: "UID", field: "uid"},
+ {title: "InsertVon", field: "insertvon", visible: false},
+ {
+ title: 'Aktionen', field: 'actions',
+ minWidth: 150, // Ensures Action-buttons will be always fully displayed
+ formatter: (cell, formatterParams, onRendered) => {
+ const container = document.createElement('div');
+ container.className = "d-flex gap-2";
+
+ const data = cell.getData();
+
+ const button = document.createElement('button');
+ button.className = 'btn btn-outline-secondary btn-action';
+ button.innerHTML = '';
+ button.title = this.$p.t('ui', 'loeschen');
+ button.addEventListener('click', () =>
+ this.actionDeleteGroup(data.gruppe_kurzbz)
+ );
+ if (data.generiert)
+ button.disabled = true;
+ container.append(button);
+
+ return container;
+ },
+ frozen: true
+ },
+ ],
+ layout: 'fitDataFill',
+ height: 'auto',
+ selectable: true,
+ index: 'group_id',
+ persistenceID: 'stv-details-gruppe'
+ },
+ tabulatorEvents: [
+ {
+ event: 'tableBuilt',
+ handler: async () => {
+
+ await this.$p.loadCategory(['global', 'person', 'stv', 'ui', 'gruppenmanagement']);
+
+ let cm = this.$refs.table.tabulator.columnManager;
+
+ cm.getColumnByField('gruppe_kurzbz').component.updateDefinition({
+ title: this.$p.t('gruppenmanagement', 'gruppe')
+ });
+
+ cm.getColumnByField('bezeichnung').component.updateDefinition({
+ title: this.$p.t('ui', 'bezeichnung')
+ });
+
+ cm.getColumnByField('generiert').component.updateDefinition({
+ title: this.$p.t('gruppenmanagement', 'automatisch_generiert')
+ });
+
+ cm.getColumnByField('uid').component.updateDefinition({
+ title: this.$p.t('ui', 'student_uid')
+ });
+
+ //Interference with Filter if not commented out
+ /*
+ cm.getColumnByField('studiensemester_kurzbz').component.updateDefinition({
+ title: this.$p.t('lehre', 'studiensemester')
+ });*/
+
+ }
+ }
+ ],
+ }
+ },
+ methods: {
+ actionDeleteGroup(gruppe_kurzbz) {
+ this.$fhcAlert
+ .confirmDelete()
+ .then(result => result
+ ? gruppe_kurzbz
+ : Promise.reject({handled: true}))
+ .then(this.deleteGroup)
+ .catch(this.$fhcAlert.handleSystemError);
+
+ },
+ deleteGroup(gruppe_kurzbz) {
+ const group_id = {
+ id: this.student.uid,
+ gruppe_kurzbz: gruppe_kurzbz
+ };
+
+ return this.$fhcApi.factory.stv.group.deleteGroup(group_id)
+ .then(response => {
+ this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
+ }).catch(this.$fhcAlert.handleSystemError)
+ .finally(() => {
+ window.scrollTo(0, 0);
+ this.reload();
+ });
+ },
+ reload() {
+ this.$refs.table.reloadTable();
+ },
+ },
+ watch: {
+ currentSemester(newVal) {
+ if (newVal) {
+
+ this.$refs.table.tabulator.clearFilter(); // Clear old filters
+
+ this.$refs.table.tabulator.setFilter([
+ {field: "uid", type: "=", value: this.student.uid},
+ [
+ {field: "studiensemester_kurzbz", type: "=", value: newVal},
+ {field: "insertvon", type: "=", value: "mlists_generate"}
+ ]
+ ]);
+
+
+ }
+ },
+ student() {
+ this.$refs.table.reloadTable();
+ }
+ },
+ template: `
+
+
{{$p.t('stv', 'tab_groups')}}
+
+
+
+
+ `
+}
\ No newline at end of file
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php
index 746c24da3..160db2853 100644
--- a/system/phrasesupdate.php
+++ b/system/phrasesupdate.php
@@ -37297,7 +37297,90 @@ array(
'insertvon' => 'system'
)
)
+ ),
+ //////////// FHC4 Phrases Gruppen Start ////////////
+ array(
+ 'app' => 'core',
+ 'category' => 'stv',
+ 'phrase' => 'tab_groups',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Gruppen',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Groups',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'gruppenmanagement',
+ 'phrase' => 'gruppe',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Gruppe',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Group',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'gruppenmanagement',
+ 'phrase' => 'automatisch_generiert',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'automatisch generiert',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'automatically generated',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'gruppenmanagement',
+ 'phrase' => 'error_deleteGeneratedGroups',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Automatisch generierte Gruppenzuordnungen können nicht gelöscht werden.',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Automatically generated group assignments cannot be deleted.',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
)
+ //////////// FHC4 Phrases Gruppen End ////////////
+
);