mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-01 20:29:29 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fe5a685f1 | |||
| b05cd88f14 | |||
| 9e6c15a10d | |||
| 7603f8f12b | |||
| 96745525f1 | |||
| 8d6e04ea77 | |||
| d9e5acb52c | |||
| 6ec32b0ca3 | |||
| 4778bb82c3 | |||
| e20ff52f5b | |||
| df05af98d2 | |||
| 5ef1dccfc9 | |||
| 6d28b8986d | |||
| b43f1ec920 | |||
| 56a6aa993e | |||
| db75cd2f62 | |||
| f3986688f2 | |||
| f068b56083 | |||
| fa7a125727 |
@@ -511,10 +511,11 @@ class Abgabe extends FHCAPI_Controller
|
||||
return $projektarbeit->projektarbeit_id;
|
||||
};
|
||||
$projektarbeiten_ids = array_map($mapFunc, $projektarbeiten->retval);
|
||||
|
||||
$ret = $this->ProjektarbeitModel->getProjektarbeitenAbgabetermine($projektarbeiten_ids);
|
||||
$projektabgaben = $this->getDataOrTerminateWithError($ret, 'general');
|
||||
|
||||
if(count($projektarbeiten_ids) > 0) {
|
||||
$ret = $this->ProjektarbeitModel->getProjektarbeitenAbgabetermine($projektarbeiten_ids);
|
||||
$projektabgaben = $this->getDataOrTerminateWithError($ret, 'general');
|
||||
}
|
||||
|
||||
forEach($projektarbeiten->retval as $pa) {
|
||||
|
||||
@@ -846,9 +847,10 @@ class Abgabe extends FHCAPI_Controller
|
||||
private function getProjektbetreuerEmailByProjektarbeitID($projektarbeit_id) {
|
||||
$this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
|
||||
$result = $this->ProjektarbeitModel->getProjektbetreuerEmail($projektarbeit_id);
|
||||
$email = $this->getDataOrTerminateWithError($result, 'general');
|
||||
|
||||
return $email[0]->uid ? $email[0]->uid.'@'.DOMAIN : $email[0]->private_email;
|
||||
if(count($result->retval) > 0) {
|
||||
$email = getData($result);
|
||||
return $email[0]->uid ? $email[0]->uid.'@'.DOMAIN : $email[0]->private_email;
|
||||
} else return '';
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,6 @@ class Documents extends FHCAPI_Controller
|
||||
$this->load->model('system/Vorlage_model', 'VorlageModel');
|
||||
|
||||
$result = $this->VorlageModel->load($xsl);
|
||||
$this->addMeta("ress", $result);
|
||||
$vorlage = current($this->getDataOrTerminateWithError($result));
|
||||
if (!$vorlage)
|
||||
show_404();
|
||||
@@ -221,7 +220,7 @@ class Documents extends FHCAPI_Controller
|
||||
'gedruckt' => true,
|
||||
'insertamum' => date('c'),
|
||||
'insertvon' => getAuthUID(),
|
||||
'uid' => $this->input->post_get('uid') ?: '',
|
||||
'uid' => $this->input->post_get('uid') ?: null,
|
||||
'archiv' => true,
|
||||
'signiert' => !!$sign_user,
|
||||
'stud_selfservice' => $vorlage->stud_selfservice
|
||||
@@ -251,6 +250,9 @@ class Documents extends FHCAPI_Controller
|
||||
'studiensemester_kurzbz' => $ss,
|
||||
'student_uid' => $akteData['uid']
|
||||
]);
|
||||
|
||||
if (!hasData($result)) $this->terminateWithError($this->p->t("stv", "error_noLehrverbandAssigned"));
|
||||
|
||||
$res = current($this->getDataOrTerminateWithError($result));
|
||||
|
||||
$studiengang_kz = $res->studiengang_kz;
|
||||
@@ -332,6 +334,7 @@ class Documents extends FHCAPI_Controller
|
||||
if ($prestudent_id) {
|
||||
$this->load->model('crm/prestudent_model', 'PrestudentModel');
|
||||
$this->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz', 'LEFT');
|
||||
$this->PrestudentModel->addSelect('tbl_prestudent.*, UPPER(typ || kurzbz) AS kuerzel');
|
||||
$result = $this->PrestudentModel->load($prestudent_id);
|
||||
$prestudent = current($this->getDataOrTerminateWithError($result));
|
||||
|
||||
|
||||
@@ -495,6 +495,10 @@ class AbgabetoolJob extends JOB_Controller
|
||||
// get all new or changed termine in interval
|
||||
$result = $this->_ci->PaabgabeModel->findAbgabenNewOrUpdatedSince($interval, $relevantTypes);
|
||||
$retval = getData($result);
|
||||
if(!$retval) {
|
||||
$this->_ci->logInfo("Keine Emails an Betreuer über neue oder veränderte Termine versandt");
|
||||
return;
|
||||
}
|
||||
|
||||
// group changed/new abgaben for projektarbeiten
|
||||
$projektarbeiten = [];
|
||||
@@ -557,6 +561,8 @@ class AbgabetoolJob extends JOB_Controller
|
||||
$anredeFillString = $data->anrede == "Herr" ? "r" : "";
|
||||
$fullFormattedNameString = $data->first;
|
||||
|
||||
$relevantCounter = 0; // workaround to check if a betreuer needs to have any notification about relevant
|
||||
// abgaben at all to avoid sending empty emails since we filter on certain conditions
|
||||
forEach($tupelArr as $tupel) {
|
||||
$projektarbeit_id = $tupel[0];
|
||||
$betreuerRow = $tupel[1];
|
||||
@@ -575,6 +581,8 @@ class AbgabetoolJob extends JOB_Controller
|
||||
continue;
|
||||
}
|
||||
|
||||
$relevantCounter++;
|
||||
|
||||
// format the Student Name
|
||||
$s = $relevantAbgaben[0];
|
||||
$nameParts = [];
|
||||
@@ -633,6 +641,11 @@ class AbgabetoolJob extends JOB_Controller
|
||||
// done with building the change list, now send it
|
||||
$betreuerRow = $tupelArr[0][1];
|
||||
|
||||
if($relevantCounter == 0) {
|
||||
$this->_ci->logInfo('No Relevant Abgaben to notify Betreuer PersonID: "'.$betreuerRow->person_id.'".');
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $this->_ci->config->item('URL_MITARBEITER');
|
||||
$url = CIS_ROOT.$path;
|
||||
|
||||
|
||||
@@ -111,9 +111,7 @@ function generateJSDataStorageObject($indexPage, $calledPath, $calledMethod)
|
||||
'theme' => [
|
||||
'name'=>$ci->config->item('theme_name'),
|
||||
'modes'=>$ci->config->item('theme_modes'),
|
||||
],
|
||||
'fhcomplete_build_version' => $ci->config->item('fhcomplete_build_version'),
|
||||
'use_fhcomplete_build_version_in_path' => $ci->config->item('use_fhcomplete_build_version_in_path'),
|
||||
]
|
||||
);
|
||||
|
||||
$toPrint = "\n";
|
||||
@@ -180,8 +178,6 @@ function generateJSModulesInclude($JSModules)
|
||||
|
||||
$ci =& get_instance();
|
||||
$cachetoken = '?'.$ci->config->item('fhcomplete_build_version');
|
||||
$ci->load->config('javascript');
|
||||
$use_bundled_javascript = $ci->config->item('use_bundled_javascript');
|
||||
|
||||
if (isset($JSModules))
|
||||
{
|
||||
@@ -189,20 +185,14 @@ function generateJSModulesInclude($JSModules)
|
||||
|
||||
for ($tmpJSsCounter = 0; $tmpJSsCounter < count($tmpJSs); $tmpJSsCounter++)
|
||||
{
|
||||
$item = $tmpJSs[$tmpJSsCounter];
|
||||
if($use_bundled_javascript && preg_match('#/js/apps/#', $item))
|
||||
{
|
||||
$item = preg_replace('#^public/#', 'public/dist/', $item);
|
||||
}
|
||||
echo "<!--{$item}-->".PHP_EOL;
|
||||
if($ci->config->item('use_fhcomplete_build_version_in_path'))
|
||||
{
|
||||
$relurl = preg_replace('#public/#', 'public/' . $ci->config->item('fhcomplete_build_version') . '/', $item);
|
||||
$relurl = preg_replace('#public/#', 'public/' . $ci->config->item('fhcomplete_build_version') . '/', $tmpJSs[$tmpJSsCounter]);
|
||||
$toPrint = sprintf($jsInclude, base_url($relurl)).PHP_EOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$toPrint = sprintf($jsInclude, base_url($item.$cachetoken)).PHP_EOL;
|
||||
$toPrint = sprintf($jsInclude, base_url($tmpJSs[$tmpJSsCounter].$cachetoken)).PHP_EOL;
|
||||
}
|
||||
|
||||
if ($tmpJSsCounter > 0) $toPrint = "\t\t".$toPrint;
|
||||
|
||||
@@ -42,7 +42,7 @@ class ExtensionsLib
|
||||
// Directories that are part of the extension archive
|
||||
private $SOFTLINK_TARGET_DIRECTORIES = array(
|
||||
APPPATH => array('config', 'components', 'controllers', 'helpers', 'hooks', 'libraries', 'models', 'views', 'widgets'),
|
||||
DOC_ROOT => array('public', 'public/dist')
|
||||
DOC_ROOT => array('public')
|
||||
);
|
||||
|
||||
private $_errorOccurred; // boolean, true if an error occurred while installing an extension
|
||||
|
||||
@@ -270,6 +270,8 @@ class LehreListHelper
|
||||
} else if ($row->bisio_id != '' && $row->status != 'Incoming' && ($row->von > $stsemdatumvon || $row->von == '')) {
|
||||
// if bis datum is not yet known but von is available already
|
||||
$zusatz .= '(o)(ab '.$datum->formatDatum($row->von, 'd.m.Y').')';
|
||||
} else if ($row->bisio_id != '' && $row->status != 'Incoming' && ($row->von <= $stsemdatumvon || $row->von == '') && ($row->bis == '' || $row->bis > date('Y-m-d'))){
|
||||
$zusatz .= '(o)(ab '.$datum->formatDatum($row->von, 'd.m.Y').')';
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "fhc-core",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"watch": "rollup --watch -c"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"glob": "^13.0.6",
|
||||
"node-sass": "^9.0.0",
|
||||
"rollup": "^4.52.4",
|
||||
"rollup-plugin-postcss": "^4.0.2",
|
||||
"rollup-plugin-vue": "^6.0.0"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-2
@@ -1,2 +0,0 @@
|
||||
const e="error",t="retval",r={get:function(e,t,n=null){return r._axiosCall(e,t,"get",n)},post:function(e,t,n=null){return r._axiosCall(e,t,"post",n)},isSuccess:function(r){return!("object"!=typeof r||!r.hasOwnProperty(e)||!r.hasOwnProperty(t)||0!=r.error)},isError:function(e){return!r.isSuccess(e)},hasData:function(e){return!(!r.isSuccess(e)||!("object"==typeof e[t]&&Object.keys(e[t]).length>0||"array"==typeof e[t]&&e[t].length>0||"string"==typeof e[t]&&""!=e[t].trim()||"number"==typeof e[t]))},getData:function(e){return r.hasData(e)?e[t]:null},getError:function(e){return"object"==typeof e&&Object.keys(e).length>0&&e.hasOwnProperty(t)?e[t]:"Generic error"},getErrorCode:function(t){return"object"==typeof t&&t.hasOwnProperty(e)?t[e]:1},_generateRouterURI:function(e){var t=null;return"undefined"!=typeof FHC_JS_DATA_STORAGE_OBJECT&&(t=FHC_JS_DATA_STORAGE_OBJECT.app_root+FHC_JS_DATA_STORAGE_OBJECT.ci_router+"/"+e),t},_printDebug:function(e,t,r){},_axiosCall:function(e,t,n,i){let o={method:n,url:r._generateRouterURI(e),timeout:5e3};if("get"==n?o.params=t:o.data=t,"object"==typeof i)for(var s in i)o[s]=i[s];return axios(o)}},n=2e3,i={getStudiensemester:function(){return r.get("codex/Bismeldestichtag/getStudiensemester",null,{timeout:n})},getBismeldestichtage:function(){return r.get("codex/Bismeldestichtag/getBismeldestichtage",null,{timeout:n})},addBismeldestichtag:function(e){return r.post("codex/Bismeldestichtag/addBismeldestichtag",{meldestichtag:e.meldestichtag,studiensemester_kurzbz:e.studiensemester_kurzbz},{timeout:n})},deleteBismeldestichtag:function(e){return r.post("codex/Bismeldestichtag/deleteBismeldestichtag",{meldestichtag_id:e.meldestichtag_id},{timeout:n})}};export{i as BismeldestichtagAPIs};
|
||||
//# sourceMappingURL=API.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
const t={formatDate:function(t){return t.replace(/(.*)-(.*)-(.*)/,"$3.$2.$1")}};export{t as BismeldestichtagHelper};
|
||||
//# sourceMappingURL=BismeldestichtagHelper.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"BismeldestichtagHelper.js","sources":["../../../../js/apps/Bismeldestichtag/BismeldestichtagHelper.js"],"sourcesContent":["/**\n * Copyright (C) 2022 fhcomplete.org\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <https://www.gnu.org/licenses/>.\n */\n\nexport const BismeldestichtagHelper = {\n\tformatDate: function(date) {\n\t\treturn date.replace(/(.*)-(.*)-(.*)/, '$3.$2.$1');\n\t}\n}\n"],"names":["BismeldestichtagHelper","formatDate","date","replace"],"mappings":"AAiBO,MAAMA,EAAyB,CACrCC,WAAY,SAASC,GACpB,OAAOA,EAAKC,QAAQ,iBAAkB,WACvC"}
|
||||
Vendored
-4
File diff suppressed because one or more lines are too long
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
-4
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-4
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
-6
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
-4
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
-4
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
const e={height:700,layout:"fitColumns",columns:[{title:"Log ID",field:"LogId",headerFilter:!0},{title:"Request ID",field:"RequestId",headerFilter:!0},{title:"Execution time",field:"ExecutionTime",headerFilter:!0},{title:"Executed by",field:"ExecutedBy",headerFilter:!0},{title:"Description",field:"Description",headerFilter:!0},{title:"Data",field:"Data",headerFilter:!0},{title:"Web service type",field:"WebserviceType",headerFilter:!0}],rowFormatter:function(e){let t=e.getData();if(null!=t&&t.hasOwnProperty("RequestId")&&null!=t.RequestId){let l=t.RequestId;l.includes("error")?e.getElement().style.color="red":l.includes("warning")&&(e.getElement().style.color="orange")}}},t=[{event:"rowClick",handler:function(e,t){alert(t.getData().Data)}}];export{t as LogsViewerTabulatorEventHandlers,e as LogsViewerTabulatorOptions};
|
||||
//# sourceMappingURL=TabulatorSetup.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"TabulatorSetup.js","sources":["../../../../js/apps/LogsViewer/TabulatorSetup.js"],"sourcesContent":["/**\n * Copyright (C) 2022 fhcomplete.org\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <https://www.gnu.org/licenses/>.\n */\n\n/**\n *\n */\nexport const LogsViewerTabulatorOptions = {\n\theight: 700,\n\tlayout: 'fitColumns',\n\tcolumns: [\n\t\t{title: 'Log ID', field: 'LogId', headerFilter: true},\n\t\t{title: 'Request ID', field: 'RequestId', headerFilter: true},\n\t\t{title: 'Execution time', field: 'ExecutionTime', headerFilter: true},\n\t\t{title: 'Executed by', field: 'ExecutedBy', headerFilter: true},\n\t\t{title: 'Description', field: 'Description', headerFilter: true},\n\t\t{title: 'Data', field: 'Data', headerFilter: true},\n\t\t{title: 'Web service type', field: 'WebserviceType', headerFilter: true}\n\t],\n\trowFormatter: function(row) {\n\n\t\tlet data = row.getData(); // get data for this row\n\n\t\t// If data is not null and provides the property RequestId and it is not null\n\t\tif (data != null && data.hasOwnProperty('RequestId') && data.RequestId != null)\n\t\t{\n\t\t\tlet requestId = data.RequestId;\n\n\t\t\tif (requestId.includes(\"error\"))\n\t\t\t{\n\t\t\t\trow.getElement().style.color = \"red\";\n\t\t\t}\n\t\t\telse if (requestId.includes(\"warning\"))\n\t\t\t{\n\t\t\t\trow.getElement().style.color = \"orange\";\n\t\t\t\n\t\t\t}\n\t\t}\n\t}\n};\n\n/**\n *\n */\nexport const LogsViewerTabulatorEventHandlers = [\n\t{\n\t\tevent: \"rowClick\",\n\t\thandler: function(e, row) {\n\t\t\talert(row.getData().Data);\n\t\t}\n\t}\n];\n\n"],"names":["LogsViewerTabulatorOptions","height","layout","columns","title","field","headerFilter","rowFormatter","row","data","getData","hasOwnProperty","RequestId","requestId","includes","getElement","style","color","LogsViewerTabulatorEventHandlers","event","handler","e","alert","Data"],"mappings":"AAoBO,MAAMA,EAA6B,CACzCC,OAAQ,IACRC,OAAQ,aACRC,QAAS,CACR,CAACC,MAAO,SAAUC,MAAO,QAASC,cAAc,GAChD,CAACF,MAAO,aAAcC,MAAO,YAAaC,cAAc,GACxD,CAACF,MAAO,iBAAkBC,MAAO,gBAAiBC,cAAc,GAChE,CAACF,MAAO,cAAeC,MAAO,aAAcC,cAAc,GAC1D,CAACF,MAAO,cAAeC,MAAO,cAAeC,cAAc,GAC3D,CAACF,MAAO,OAAQC,MAAO,OAAQC,cAAc,GAC7C,CAACF,MAAO,mBAAoBC,MAAO,iBAAkBC,cAAc,IAEpEC,aAAc,SAASC,GAEtB,IAAIC,EAAOD,EAAIE,UAGf,GAAY,MAARD,GAAgBA,EAAKE,eAAe,cAAkC,MAAlBF,EAAKG,UAC7D,CACC,IAAIC,EAAYJ,EAAKG,UAEjBC,EAAUC,SAAS,SAEtBN,EAAIO,aAAaC,MAAMC,MAAQ,MAEvBJ,EAAUC,SAAS,aAE3BN,EAAIO,aAAaC,MAAMC,MAAQ,SAGjC,CACD,GAMYC,EAAmC,CAC/C,CACCC,MAAO,WACPC,QAAS,SAASC,EAAGb,GACpBc,MAAMd,EAAIE,UAAUa,KACrB"}
|
||||
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
-4
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-13
@@ -1,13 +0,0 @@
|
||||
var Search = {
|
||||
search: function (searchsettings) {
|
||||
const url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/SearchBar/search';
|
||||
return axios.post(url, searchsettings);
|
||||
}
|
||||
};
|
||||
|
||||
var fhcapifactory = {
|
||||
"search": Search
|
||||
};
|
||||
|
||||
export { fhcapifactory as default };
|
||||
//# sourceMappingURL=fhcapifactory.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"fhcapifactory.js","sources":["../../../../js/apps/api/search.js","../../../../js/apps/api/fhcapifactory.js"],"sourcesContent":["export default {\n search: function(searchsettings) {\n const url = FHC_JS_DATA_STORAGE_OBJECT.app_root \n + FHC_JS_DATA_STORAGE_OBJECT.ci_router\n + '/components/SearchBar/search';\n return axios.post(url, searchsettings);\n }\n};\n","import Search from \"./search.js\";\n\nexport default {\n \"search\": Search,\n};\n"],"names":["search","searchsettings","url","FHC_JS_DATA_STORAGE_OBJECT","app_root","ci_router","axios","post","Search"],"mappings":"AAAA,aAAe;AACbA,EAAAA,MAAM,EAAE,UAASC,cAAc,EAAE;IAC7B,MAAMC,GAAG,GAAGC,0BAA0B,CAACC,QAAQ,GACnCD,0BAA0B,CAACE,SAAS,GACpC,8BAA8B;AAC1C,IAAA,OAAOC,KAAK,CAACC,IAAI,CAACL,GAAG,EAAED,cAAc,CAAC;AAC1C,EAAA;AACF,CAAC;;ACLD,oBAAe;AACX,EAAA,QAAQ,EAAEO;AACd,CAAC;;;;"}
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
var search = {
|
||||
search: function (searchsettings) {
|
||||
const url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/SearchBar/search';
|
||||
return axios.post(url, searchsettings);
|
||||
}
|
||||
};
|
||||
|
||||
export { search as default };
|
||||
//# sourceMappingURL=search.js.map
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"search.js","sources":["../../../../js/apps/api/search.js"],"sourcesContent":["export default {\n search: function(searchsettings) {\n const url = FHC_JS_DATA_STORAGE_OBJECT.app_root \n + FHC_JS_DATA_STORAGE_OBJECT.ci_router\n + '/components/SearchBar/search';\n return axios.post(url, searchsettings);\n }\n};\n"],"names":["search","searchsettings","url","FHC_JS_DATA_STORAGE_OBJECT","app_root","ci_router","axios","post"],"mappings":"AAAA,aAAe;AACbA,EAAAA,MAAM,EAAE,UAASC,cAAc,EAAE;IAC7B,MAAMC,GAAG,GAAGC,0BAA0B,CAACC,QAAQ,GACnCD,0BAA0B,CAACE,SAAS,GACpC,8BAA8B;AAC1C,IAAA,OAAOC,KAAK,CAACC,IAAI,CAACL,GAAG,EAAED,cAAc,CAAC;AAC1C,EAAA;AACF,CAAC;;;;"}
|
||||
Vendored
-4
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -180,7 +180,7 @@ export const AbgabetoolAssistenz = {
|
||||
// frozen: true,
|
||||
// width: 40
|
||||
// },
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', headerFilter: false, headerSort: false, formatter: this.formAction, tooltip:false, minWidth: 150, cssClass: 'sticky-col'},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', headerFilter: false, headerSort: false, formatter: this.formAction, tooltip:false, minWidth: 100, cssClass: 'sticky-col'},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4personenkennzeichen'))), headerFilter: true, field: 'pkz', formatter: this.pkzTextFormatter, widthGrow: 1, tooltip: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'student_vorname', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'student_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
|
||||
@@ -226,7 +226,7 @@ export const AbgabetoolAssistenz = {
|
||||
field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false},
|
||||
],
|
||||
persistence: false,
|
||||
persistenceID: "abgabetool_2026_02_26"
|
||||
persistenceID: "abgabetool_2026_03_16"
|
||||
},
|
||||
abgabeTableEventHandlers: [
|
||||
{
|
||||
@@ -645,7 +645,7 @@ export const AbgabetoolAssistenz = {
|
||||
actionButtons.className = "d-flex gap-3"; // you can keep Bootstrap gap if loaded
|
||||
actionButtons.style.display = "flex";
|
||||
actionButtons.style.alignItems = "stretch"; // buttons stretch to full height
|
||||
actionButtons.style.justifyContent = "center";
|
||||
actionButtons.style.justifyContent = "start";
|
||||
actionButtons.style.height = "100%"; // full grid cell height
|
||||
|
||||
const val = cell.getValue();
|
||||
@@ -675,8 +675,20 @@ export const AbgabetoolAssistenz = {
|
||||
createButton('fa fa-timeline', 'abgabetool/c4termineTimeLine', () => this.openTimeline(val))
|
||||
);
|
||||
|
||||
if(val.latestTerminWithUpload) {
|
||||
actionButtons.append(
|
||||
createButton('fa fa-download', 'abgabetool/c4downloadLatestAbgabe', () => this.downloadAbgabe(val.latestTerminWithUpload.paabgabe_id, val.student_uid, val.projektarbeit_id))
|
||||
)
|
||||
}
|
||||
|
||||
return actionButtons;
|
||||
},
|
||||
downloadAbgabe(paabgabe_id, student_uid, projektarbeit_id) {
|
||||
const url = `/api/frontend/v1/Abgabe/getStudentProjektarbeitAbgabeFile?paabgabe_id=${paabgabe_id}&student_uid=${student_uid}&projektarbeit_id=${projektarbeit_id}`;
|
||||
|
||||
window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url)
|
||||
// this.$api.call(ApiAbgabe.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid))
|
||||
},
|
||||
|
||||
undoSelection(cell) {
|
||||
// checks if cells row is selected and unselects -> imitates columns which dont trigger row selection
|
||||
@@ -780,6 +792,8 @@ export const AbgabetoolAssistenz = {
|
||||
// TODO: mehrsprachig englisch
|
||||
projekt.note_bez = opt.bezeichnung
|
||||
}
|
||||
|
||||
const latestTerminWithUpload = this.findLatestTerminWithUpload(projekt)
|
||||
|
||||
return {
|
||||
...projekt,
|
||||
@@ -787,6 +801,7 @@ export const AbgabetoolAssistenz = {
|
||||
details: {
|
||||
student_uid: projekt.student_uid,
|
||||
projektarbeit_id: projekt.projektarbeit_id,
|
||||
latestTerminWithUpload: latestTerminWithUpload ?? null
|
||||
},
|
||||
pkz: this.buildPKZ(projekt),
|
||||
beurteilung: projekt.beurteilungLink ?? null,
|
||||
@@ -800,6 +815,15 @@ export const AbgabetoolAssistenz = {
|
||||
}
|
||||
})
|
||||
},
|
||||
findLatestTerminWithUpload(projekt) {
|
||||
const withAbgabedatumSorted = projekt?.abgabetermine?.filter(t => t.abgabedatum != null)?.sort((a,b) => a < b)
|
||||
|
||||
if(withAbgabedatumSorted.length) {
|
||||
return withAbgabedatumSorted[0]
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
createInfoString(data) {
|
||||
let str = '';
|
||||
|
||||
@@ -1413,9 +1437,12 @@ export const AbgabetoolAssistenz = {
|
||||
|
||||
<div id="abgabetable" style="max-height:40vw;">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<div class="col-auto me-auto">
|
||||
<h2 tabindex="1">{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<label class="col-form-label">{{$capitalize($p.t('lehre/studiengang'))}}:</label>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<Dropdown
|
||||
:placeholder="$capitalize($p.t('lehre/studiengang'))"
|
||||
@@ -1430,6 +1457,9 @@ export const AbgabetoolAssistenz = {
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<label class="col-form-label">{{$capitalize($p.t('lehre/note'))}}:</label>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<Dropdown
|
||||
:placeholder="$p.t('lehre/note')"
|
||||
|
||||
@@ -667,8 +667,10 @@ export const AbgabetoolMitarbeiter = {
|
||||
setDetailComponent(details){
|
||||
this.loading=true
|
||||
|
||||
const pa = this.projektarbeiten?.retval?.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id)
|
||||
const projektarbeiten = this.projektarbeiten?.retval ?? this.projektarbeiten
|
||||
|
||||
const pa = projektarbeiten.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id)
|
||||
|
||||
let paIsBenotet = false
|
||||
if(pa.note !== undefined && pa.note !== null) {
|
||||
// check if the note is not defined as a non final projektarbeit note
|
||||
|
||||
@@ -2,8 +2,6 @@ import BsModal from "../Bootstrap/Modal.js";
|
||||
import CachedWidgetLoader from "../../composables/Dashboard/CachedWidgetLoader.js";
|
||||
import HeightTransition from "../Tranistion/HeightTransition.js";
|
||||
|
||||
import {absoluteJsImportUrl} from "../../helpers/UrlHelpers.js";
|
||||
|
||||
export default {
|
||||
name: 'Item',
|
||||
components: {
|
||||
|
||||
@@ -170,6 +170,7 @@ export default {
|
||||
return this.$attrs.modelValue;
|
||||
},
|
||||
set(v) {
|
||||
this.clearValidationForThisName()
|
||||
if (!this.$attrs.hasOwnProperty('modelValue'))
|
||||
this.modelValueDummy = v;
|
||||
this.$emit('update:modelValue', v);
|
||||
@@ -242,9 +243,9 @@ export default {
|
||||
template: `
|
||||
<component :is="!hasContainer ? 'FhcFragment' : 'div'" class="position-relative" :class="autoContainerClass">
|
||||
<label v-if="label && lcType != 'radio' && lcType != 'checkbox'" :class="!noAutoClass && 'form-label'" :for="idCmp">{{label}}</label>
|
||||
<input v-if="tag == 'input'" :type="lcType" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)">
|
||||
<textarea v-else-if="tag == 'textarea'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)"></textarea>
|
||||
<select v-else-if="tag == 'select'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)">
|
||||
<input v-if="tag == 'input'" :type="lcType" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="$emit('input', $event)">
|
||||
<textarea v-else-if="tag == 'textarea'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="$emit('input', $event)"></textarea>
|
||||
<select v-else-if="tag == 'select'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="$emit('input', $event)">
|
||||
<slot></slot>
|
||||
</select>
|
||||
<component
|
||||
|
||||
@@ -508,7 +508,7 @@ export default {
|
||||
this.handlePersonUrl();
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="stv" :class="{ 'sidebar-collapsed': sidebarCollapsed }">
|
||||
<div class="stv" :class="{ 'sidebar-collapsed': sidebarCollapsed }" data-cy="studentenverwaltung">
|
||||
<header class="navbar navbar-expand-lg navbar-dark bg-dark flex-md-nowrap p-0 shadow">
|
||||
<div class="col-md-4 col-lg-3 col-xl-2 d-flex align-items-center">
|
||||
<button
|
||||
@@ -632,14 +632,14 @@ export default {
|
||||
</app-menu>
|
||||
</div>
|
||||
</aside>
|
||||
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100">
|
||||
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100" data-cy="stv-sidebar">
|
||||
<div class="offcanvas-header justify-content-end px-1 d-md-none">
|
||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
|
||||
</div>
|
||||
<stv-verband :preselectedKey="studiengangKz ? '' + studiengangKz : null" :endpoint="verbandEndpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
|
||||
<stv-studiensemester v-model:studiensemester-kurzbz="studiensemesterKurzbz" @update:studiensemester-kurzbz="studiensemesterChanged"></stv-studiensemester>
|
||||
</nav>
|
||||
<main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10">
|
||||
<main class="col-md-8 ms-sm-auto col-lg-9 col-xl-10" data-cy="stv-main">
|
||||
<vertical-split>
|
||||
<template #top>
|
||||
<stv-list ref="stvList" v-model:selected="selected" :studiengang-kz="studiengangKz" :studiensemester-kurzbz="studiensemesterKurzbz" @filterActive="handleCustomFilter"></stv-list>
|
||||
|
||||
@@ -86,7 +86,7 @@ export default {
|
||||
this.loadConfig();
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details h-100 d-flex flex-column">
|
||||
<div class="stv-details h-100 d-flex flex-column" data-cy="stv-details">
|
||||
<div v-if="!students?.length" class="justify-content-center d-flex h-100 align-items-center">
|
||||
{{$p.t('ui', 'chooseStudent')}}
|
||||
</div>
|
||||
@@ -108,6 +108,7 @@ export default {
|
||||
<fhc-tabs
|
||||
v-if="students.length == 1"
|
||||
ref="tabs"
|
||||
data-cy="stv-details-tabs"
|
||||
:useprimevue="true"
|
||||
:modelValue="students[0]"
|
||||
:config="config"
|
||||
@@ -116,7 +117,17 @@ export default {
|
||||
@changed="reload"
|
||||
>
|
||||
</fhc-tabs>
|
||||
<fhc-tabs v-else ref="tabs" :useprimevue="true" :modelValue="students" :config="config" :default="$route.params.tab" style="flex: 1 1 0%; height: 0%" @changed="reload"></fhc-tabs>
|
||||
<fhc-tabs
|
||||
v-else
|
||||
ref="tabs"
|
||||
data-cy="stv-details-tabs"
|
||||
:useprimevue="true"
|
||||
:modelValue="students"
|
||||
:config="config"
|
||||
:default="$route.params.tab"
|
||||
style="flex: 1 1 0%; height: 0%"
|
||||
@changed="reload">
|
||||
</fhc-tabs>
|
||||
</div>
|
||||
<div v-else>
|
||||
Loading...
|
||||
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details-multistatus h-100">
|
||||
<div class="stv-details-multistatus h-100" data-cy="stv-tab-multistatus">
|
||||
<tbl-multi-status :model-value="modelValue" :config="config"></tbl-multi-status>
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -152,6 +152,7 @@ export default{
|
||||
button.className = 'btn btn-outline-secondary btn-action';
|
||||
button.innerHTML = '<i class="fa fa-forward"></i>';
|
||||
button.title = this.$p.t('ui', 'btn_statusVorruecken');
|
||||
button.setAttribute('data-cy', 'status-btn-advance');
|
||||
button.addEventListener('click', () =>
|
||||
this.actionAdvanceStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
|
||||
);
|
||||
@@ -164,6 +165,7 @@ export default{
|
||||
button.className = 'btn btn-outline-secondary btn-action';
|
||||
button.innerHTML = '<i class="fa fa-check"></i>';
|
||||
button.title = this.$p.t('ui', 'btn_confirmStatus');
|
||||
button.setAttribute('data-cy', 'status-btn-confirm');
|
||||
button.addEventListener('click', () =>
|
||||
this.actionConfirmStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
|
||||
);
|
||||
@@ -175,6 +177,7 @@ export default{
|
||||
button.className = 'btn btn-outline-secondary btn-action';
|
||||
button.innerHTML = '<i class="fa fa-edit"></i>';
|
||||
button.title = this.$p.t('ui', 'btn_editStatus');
|
||||
button.setAttribute('data-cy', 'status-btn-edit');
|
||||
button.addEventListener('click', () =>
|
||||
this.actionEditStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
|
||||
);
|
||||
@@ -186,6 +189,7 @@ export default{
|
||||
button.className = 'btn btn-outline-secondary btn-action';
|
||||
button.innerHTML = '<i class="fa fa-xmark"></i>';
|
||||
button.title = this.$p.t('ui', 'btn_deleteStatus');
|
||||
button.setAttribute('data-cy', 'status-btn-delete');
|
||||
button.addEventListener('click', () =>
|
||||
this.actionDeleteStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester)
|
||||
);
|
||||
@@ -204,6 +208,11 @@ export default{
|
||||
{
|
||||
row.getElement().classList.add('text-black','text-opacity-50','fst-italic');
|
||||
}
|
||||
// data-cy: unique per status entry for Cypress assertions
|
||||
const stdsem = rowData.studiensemester_kurzbz ?? 'unknown';
|
||||
const status = rowData.status_kurzbz ?? 'unknown';
|
||||
const sem = rowData.ausbildungssemester ?? '0';
|
||||
row.getElement().setAttribute('data-cy', `status-row-${stdsem}-${status}-${sem}`);
|
||||
},
|
||||
layout: 'fitDataStretchFrozen',
|
||||
layoutColumnsOnNewData: false,
|
||||
@@ -393,7 +402,7 @@ export default{
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
template: `
|
||||
<div class="stv-multistatus h-100 pt-3">
|
||||
<div class="stv-multistatus h-100 pt-3" data-cy="stv-multistatus">
|
||||
<status-modal
|
||||
ref="test"
|
||||
:meldestichtag="new Date(dataMeldestichtag)"
|
||||
@@ -405,6 +414,7 @@ export default{
|
||||
<core-filter-cmpt
|
||||
v-if="!this.modelValue.length"
|
||||
ref="table"
|
||||
data-cy="stv-multistatus-table"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
:tabulator-events="tabulatorEvents"
|
||||
table-only
|
||||
|
||||
@@ -14,6 +14,9 @@ export default {
|
||||
inject: {
|
||||
defaultSemester: {
|
||||
from: 'defaultSemester'
|
||||
},
|
||||
currentSemester: {
|
||||
from: 'currentSemester'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -95,8 +98,9 @@ export default {
|
||||
this.formData.themenbereich = null;
|
||||
this.formData.projekttyp_kurzbz = null;
|
||||
this.formData.firma = null;
|
||||
this.formData.lehrveranstaltung_id = null;
|
||||
this.formData.lehreinheit_id = null;
|
||||
// dont reset these form fields for UX reasons
|
||||
// this.formData.lehrveranstaltung_id = null;
|
||||
// this.formData.lehreinheit_id = null;
|
||||
this.formData.beginn = null;
|
||||
this.formData.ende = null;
|
||||
this.formData.freigegeben = true;
|
||||
@@ -109,7 +113,7 @@ export default {
|
||||
getFormData(newProjektarbeit, studiensemester_kurzbz, additional_lehrveranstaltung_id) {
|
||||
|
||||
this.additional_lehrveranstaltung_id = additional_lehrveranstaltung_id;
|
||||
this.studiensemester = studiensemester_kurzbz || this.defaultSemester;
|
||||
this.studiensemester = studiensemester_kurzbz || this.currentSemester;
|
||||
this.newProjektarbeit = newProjektarbeit;
|
||||
|
||||
this.$api
|
||||
|
||||
@@ -121,7 +121,6 @@ export default {
|
||||
height: 'auto',
|
||||
minHeight: '100',
|
||||
selectableRows: true,
|
||||
selectableRows: 1,
|
||||
index: 'betreuer_id',
|
||||
persistence:{
|
||||
columns: true, //persist column layout
|
||||
|
||||
@@ -142,6 +142,10 @@ export default {
|
||||
row.getElement().classList.add('text-black','text-opacity-50','fst-italic');
|
||||
}
|
||||
row.getElement().draggable = true
|
||||
// data-cy for Cypress e2e: prefer prestudent_id, fall back to uid or person_id
|
||||
const d = row.getData();
|
||||
const id = d.prestudent_id ?? d.uid ?? d.person_id ?? 'unknown';
|
||||
row.getElement().setAttribute('data-cy', 'student-row-' + id);
|
||||
},
|
||||
|
||||
ajaxRequestFunc: (url, config, params) => {
|
||||
@@ -600,11 +604,12 @@ export default {
|
||||
// TODO(chris): focusin, focusout, keydown and tabindex should be in the filter component
|
||||
// TODO(chris): filter component column chooser has no accessibilty features
|
||||
template: `
|
||||
<div class="stv-list h-100 pt-3">
|
||||
<div class="stv-list h-100 pt-3" data-cy="stv-list">
|
||||
<div
|
||||
class="tabulator-container d-flex flex-column h-100"
|
||||
:class="{'has-filter': filter.length}"
|
||||
tabindex="0"
|
||||
data-cy="stv-list-table-container"
|
||||
@focusin="onFocus"
|
||||
@keydown="onKeydown"
|
||||
v-draggable:copyLink.capture="selectedDragObject"
|
||||
|
||||
@@ -61,6 +61,15 @@ export default {
|
||||
},
|
||||
noSemReloadNodes() {
|
||||
return this.nodes.reduce(this.mapNodesToNoSemReloadNodes, []);
|
||||
},
|
||||
colPt() {
|
||||
return {
|
||||
rowToggler: ( options ) => {
|
||||
return {
|
||||
'data-cy': `tree-toggle-${options?.parent?.props?.node?.key ?? 'unknown'}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -319,7 +328,7 @@ export default {
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="overflow-auto" tabindex="-1">
|
||||
<div class="overflow-auto" tabindex="-1" data-cy="stv-verband-tree">
|
||||
<pv-treetable
|
||||
ref="tree"
|
||||
class="stv-verband p-treetable-sm"
|
||||
@@ -339,6 +348,7 @@ export default {
|
||||
field="name"
|
||||
expander
|
||||
class="text-break"
|
||||
:pt="colPt"
|
||||
>
|
||||
<template #header>
|
||||
<div class="text-right">
|
||||
@@ -349,6 +359,7 @@ export default {
|
||||
v-model="filters['global']"
|
||||
class="form-control ps-5"
|
||||
placeholder="Search"
|
||||
data-cy="verband-search"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -358,6 +369,7 @@ export default {
|
||||
v-if="['semester', 'verband', 'gruppe', 'gruppe_kurzbz'].some(key => node.data.hasOwnProperty(key))"
|
||||
:data-tree-item-key="node.key"
|
||||
:title="node.data.studiengang_kz"
|
||||
:data-cy="'student-collection-'+node.key"
|
||||
v-drag-click="() => toggleTreeNode(node)"
|
||||
v-drop:link-strict.student-collection="(evt, students) => dropStudents(node, students)"
|
||||
>
|
||||
@@ -367,6 +379,7 @@ export default {
|
||||
v-else
|
||||
:data-tree-item-key="node.key"
|
||||
:title="node.data.studiengang_kz"
|
||||
:data-cy="'stg-node-label-'+node.key"
|
||||
v-drag-click="() => toggleTreeNode(node)"
|
||||
>
|
||||
{{ node.data.name }}
|
||||
@@ -383,6 +396,7 @@ export default {
|
||||
v-if="favorites.on || favorites.list.length"
|
||||
href="#"
|
||||
@click.prevent="filterFav"
|
||||
data-cy="favorite-icon-header"
|
||||
>
|
||||
<i
|
||||
:class="favorites.on ? 'fa-solid' : 'fa-regular'"
|
||||
@@ -398,6 +412,7 @@ export default {
|
||||
data-link-fav-add
|
||||
@click.prevent="markFav(node)"
|
||||
@keydown.enter.stop.prevent="markFav(node)"
|
||||
:data-cy="'favorite-icon-'+node.data.studiengang_kz"
|
||||
>
|
||||
<i
|
||||
:class="favorites.list.includes(node.data.link + '') ? 'fa-solid' : 'fa-regular'"
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
const absoluteJsImportUrl = function(relativeurl)
|
||||
{
|
||||
if(true === FHC_JS_DATA_STORAGE_OBJECT.use_fhcomplete_build_version_in_path)
|
||||
{
|
||||
const absoluteurl = FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ relativeurl.replace(
|
||||
/^public\//,
|
||||
'public/' + FHC_JS_DATA_STORAGE_OBJECT.fhcomplete_build_version + '/'
|
||||
);
|
||||
return absoluteurl;
|
||||
}
|
||||
else
|
||||
{
|
||||
const absoluteurl = FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ relativeurl
|
||||
+ '?'
|
||||
+ FHC_JS_DATA_STORAGE_OBJECT.fhcomplete_build_version;
|
||||
return absoluteurl;
|
||||
}
|
||||
};
|
||||
|
||||
export { absoluteJsImportUrl };
|
||||
@@ -1,29 +0,0 @@
|
||||
***NVM installieren***
|
||||
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
||||
|
||||
oder
|
||||
|
||||
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
||||
|
||||
***Node.js installieren***
|
||||
|
||||
nvm install --lts
|
||||
|
||||
***package.json***
|
||||
|
||||
npm install
|
||||
|
||||
***Rollup build***
|
||||
|
||||
einmalig:
|
||||
|
||||
npm run build
|
||||
|
||||
mit debug ausgaben:
|
||||
|
||||
DEBUG=true npm run build
|
||||
|
||||
als watch bei Änderungen:
|
||||
|
||||
npm run watch
|
||||
@@ -1,99 +0,0 @@
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import vue from "rollup-plugin-vue";
|
||||
import { globSync } from 'glob';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import alias from '@rollup/plugin-alias';
|
||||
import { existsSync } from 'node:fs';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import json from '@rollup/plugin-json';
|
||||
|
||||
function FhcResolver () {
|
||||
return {
|
||||
name: 'fhc-resolver', // this name will show up in logs and errors
|
||||
resolveId ( source, importer, options ) {
|
||||
if( source.includes('.php') ) {
|
||||
return false;
|
||||
}
|
||||
//console.log('source: ' + source + ' options.isEntry: ' + options.isEntry + ' importer: ' + importer);
|
||||
if(importer !== undefined && !options.isEntry && !path.isAbsolute(source)) {
|
||||
let tmp = path.dirname(importer);
|
||||
if( importer.includes('/application/') ) {
|
||||
tmp = tmp.replace(/public\/js\//, 'js/').replace(/\/application\//, '/public/');
|
||||
}
|
||||
const resolved = path.resolve(tmp, source);
|
||||
//console.log(resolved);
|
||||
if( existsSync(resolved) ) {
|
||||
return resolved
|
||||
}
|
||||
}
|
||||
return null; // other ids should be handled as usually
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
input: Object.fromEntries(
|
||||
globSync('public/**/js/apps/**/*.js', {follow: true, realpath: true}).map(file => {
|
||||
if( path.dirname(file).includes('/dist/') || path.dirname(file).includes('/apps/vbform') ) {
|
||||
return null;
|
||||
}
|
||||
// This remove `src/` as well as the file extension from each
|
||||
// file, so e.g. src/nested/foo.js becomes nested/foo
|
||||
return [path.relative(
|
||||
'',
|
||||
file.slice(0, file.length - path.extname(file).length)
|
||||
).replace(/public\//, 'public/dist/'),
|
||||
// This expands the relative paths to absolute paths, so e.g.
|
||||
// src/nested/foo becomes /project/src/nested/foo.js
|
||||
fileURLToPath(new URL(file, import.meta.url))]
|
||||
}).filter(Boolean)
|
||||
),
|
||||
plugins: [
|
||||
alias({
|
||||
entries: {
|
||||
vue: 'vue/dist/vue.esm-bundler.js'
|
||||
}
|
||||
}),
|
||||
nodeResolve({
|
||||
preferBuiltins: true,
|
||||
moduleDirectories: ['node_modules'],
|
||||
modulePaths: globSync('application/extensions/*/node_modules', {follow: true, realpath: true}).map(file =>
|
||||
fileURLToPath(new URL(file, import.meta.url))
|
||||
),
|
||||
}),
|
||||
FhcResolver(),
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
'process.env.NODE_ENV': JSON.stringify( 'production' ),
|
||||
}),
|
||||
commonjs(),
|
||||
vue(),
|
||||
json(),
|
||||
babel({
|
||||
babelHelpers: 'bundled',
|
||||
plugins: ['transform-class-properties']
|
||||
}),
|
||||
postcss({
|
||||
extract: false,
|
||||
modules: true,
|
||||
use: ['sass'],
|
||||
}),
|
||||
terser()
|
||||
],
|
||||
watch: {
|
||||
buildDelay: 500
|
||||
},
|
||||
output: {
|
||||
preserveModules: false,
|
||||
sourcemap: true,
|
||||
format: 'es',
|
||||
dir: './',
|
||||
//manualChunks: {}
|
||||
chunkFileNames: 'public/dist/js/includes/[name]-[hash].js'
|
||||
}
|
||||
};
|
||||
@@ -1,158 +0,0 @@
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import { globSync } from 'glob';
|
||||
import path from 'node:path';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import { existsSync } from 'node:fs';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import json from '@rollup/plugin-json';
|
||||
|
||||
const debug = (process.env.DEBUG !== undefined) && (process.env.DEBUG === "true");
|
||||
|
||||
const fhcbasepath = import.meta.dirname;
|
||||
|
||||
let apps = {};
|
||||
let curapp = null;
|
||||
|
||||
console.log(process.env.DEBUG + ' ' + debug);
|
||||
|
||||
function FhcResolver () {
|
||||
return {
|
||||
name: 'fhc-resolver', // this name will show up in logs and errors
|
||||
buildStart (options) {
|
||||
curapp = apps[options.input[0]];
|
||||
|
||||
if(debug)
|
||||
{
|
||||
console.log('--------------------------------');
|
||||
console.log('fhc-resolver buildStart');
|
||||
console.log('options: ' + JSON.stringify(options, null, "\t"));
|
||||
console.log('apps: ' + JSON.stringify(apps, null, "\t"));
|
||||
console.log('curapp: ' + curapp);
|
||||
console.log('--------------------------------');
|
||||
}
|
||||
},
|
||||
resolveId ( source, importer, options ) {
|
||||
debug && console.log('source: ' + source + ' curapp: ' + curapp + ' importer: ' + importer);
|
||||
|
||||
if(importer === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if( source.includes('index.ci.php') ) {
|
||||
let source_abs = fhcbasepath + '/' + source.replace(/(\.\.\/)+/, '');
|
||||
let source_rel = path.relative(path.dirname(curapp), source_abs);
|
||||
|
||||
debug && console.log('SOURCE_ABS:' + source_abs + 'APP: ' + curapp + 'SOURCE_REL: ' + source_rel);
|
||||
|
||||
return { id: source_rel, external: 'relative'};
|
||||
}
|
||||
|
||||
if( source.includes('.php') ) {
|
||||
let source_abs = path.resolve(path.dirname(importer), source);
|
||||
if(source_abs.match(/\/FHC-Core-[^\/]+\/public\//)) {
|
||||
source_abs = fhcbasepath + source_abs.replace(/^.+?\/(FHC-Core-[^\/]+)\/public\//, '/public/extensions/$1/');
|
||||
}
|
||||
let source_rel = path.relative(path.dirname(curapp), source_abs);
|
||||
|
||||
debug && console.log('SOURCE_ABS:' + source_abs + 'APP: ' + curapp + 'SOURCE_REL: ' + source_rel);
|
||||
|
||||
return { id: source_rel, external: 'relative'};
|
||||
}
|
||||
|
||||
let resolved = null;
|
||||
|
||||
if(!path.isAbsolute(source)) {
|
||||
let tmp = path.dirname(importer);
|
||||
|
||||
if( importer.includes('/application/') ) {
|
||||
tmp = tmp.replace(/public\/js\//, 'js/').replace(/\/application\//, '/public/');
|
||||
}
|
||||
else if( importer.includes('/FHC-Core-') && !importer.includes('/extensions/') ) {
|
||||
tmp = fhcbasepath + tmp.replace(/^.+?\/(FHC-Core-[^\/]+)\/public\//, '/public/extensions/$1/');
|
||||
}
|
||||
|
||||
resolved = path.resolve(tmp, source);
|
||||
} else {
|
||||
resolved = source;
|
||||
|
||||
if( source.includes('/FHC-Core-') && !source.includes('/extensions/') )
|
||||
{
|
||||
resolved = fhcbasepath + source.replace(/^.+?\/(FHC-Core-[^\/]+)\/public\//, '/public/extensions/$1/');
|
||||
}
|
||||
}
|
||||
|
||||
if( resolved !== null && !existsSync(resolved) ) {
|
||||
console.log('not existsSync: ' + resolved + ' source: ' + source + ' importer: ' + importer);
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const useplugins = [
|
||||
json({
|
||||
compact: true
|
||||
}),
|
||||
FhcResolver(),
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
'process.env.NODE_ENV': JSON.stringify( 'production' ),
|
||||
}),
|
||||
babel({
|
||||
babelHelpers: 'bundled',
|
||||
plugins: ['transform-class-properties'],
|
||||
}),
|
||||
terser()
|
||||
];
|
||||
|
||||
export default globSync('public/**/js/apps/**/*.js', {follow: false, realpath: false}).map(file => {
|
||||
if( path.dirname(file).includes('/dist/')
|
||||
|| path.dirname(file).includes('/apps/vbform')
|
||||
|| path.dirname(file).includes('/apps/api')
|
||||
|| path.basename(file) === 'common.js'
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const inputfile = fhcbasepath + '/' + file;
|
||||
const outputfile = inputfile.replace(/public\//, 'public/dist/');
|
||||
const cssfile = path.basename(inputfile.replace(/\.js/, '.css'));
|
||||
|
||||
apps[inputfile] = outputfile;
|
||||
|
||||
if(debug)
|
||||
{
|
||||
console.log('--------------------------------');
|
||||
console.log('fhcbasepath: ' + fhcbasepath);
|
||||
console.log('file: ' + file);
|
||||
console.log('inputfile: ' + inputfile);
|
||||
console.log('outputfile: ' + outputfile);
|
||||
console.log('cssfile: ' + cssfile);
|
||||
console.log('--------------------------------');
|
||||
}
|
||||
|
||||
const cssplugin = [
|
||||
postcss({
|
||||
extract: cssfile,
|
||||
minimize: true,
|
||||
sourceMap: true
|
||||
})
|
||||
];
|
||||
|
||||
return {
|
||||
input: inputfile,
|
||||
plugins: [...useplugins, ...cssplugin],
|
||||
watch: {
|
||||
buildDelay: 500
|
||||
},
|
||||
output: {
|
||||
preserveModules: false,
|
||||
inlineDynamicImports: true,
|
||||
sourcemap: true,
|
||||
format: 'es',
|
||||
file: outputfile,
|
||||
}
|
||||
}
|
||||
}).filter(Boolean);
|
||||
+252
-4
@@ -3903,6 +3903,172 @@ $phrases = array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'geplZeitraum',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'geplanter Zeitraum',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'planned Period',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'bitteAuswaehlen',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Bitte auswählen...',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Please select...',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'hinweisLehrende',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Hinweis für Lehrende',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Note for Lecturers',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'lehreinheiten',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Lehreinheiten',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Teaching Units',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'lead',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Leitung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Lead',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'teamlead',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Team / Leitung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Team / Lead',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'ausblick_lvplanung',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Ausblick auf Ihre mögliche LV-Planung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Preview of Your Potential Course Planning',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
'phrase' => 'detailselfoverview',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => '<b>Achtung:</b> die vorliegenden Informationen stellen eine Vorabplanung dar und sind als Anfrage an Sie gedacht. <br /><br />
|
||||
Die Beauftragung der tatsächlichen Lehrveranstaltungen erfolgt durch Ihre Kompetenzfeldleitung. <br /><br />
|
||||
Ihre aktuell gültigen Lehraufträge und den LV Plan des aktuellen Semesters (Termine) finden Sie wie gewohnt unter „mein CIS“ -> „LV-Plan Hauptmenü“ bzw. „Lehrauftragsverwaltung“.',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => '<b>Please note:</b> The information provided represents a preliminary planning and is intended as an inquiry to you.<br /><br />
|
||||
The official assignment of the actual courses will be carried out by your Competence Field Manager.<br /><br />
|
||||
Your currently valid teaching assignments and the course schedule for the current semester (dates) can be found as usual under “My CIS” → “Schedule Main Menu” or “Teaching Assignment Administration”',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
array(
|
||||
'app' => 'pep',
|
||||
'category' => 'ui',
|
||||
@@ -44726,9 +44892,9 @@ array(
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => "Für den gesamten Studiengang verbindlicher Termin.
|
||||
|
||||
Liegt ein Termin in der Vergangenheit, kann nichts mehr hochgeladen werden. Ist es dennoch erforderlich,
|
||||
'text' => "Für den gesamten Studiengang verbindlicher Termin.
|
||||
|
||||
Liegt ein Termin in der Vergangenheit, kann nichts mehr hochgeladen werden. Ist es dennoch erforderlich,
|
||||
haben Studierende bei der Studiengangsassistenz um eine Korrektur dieses Termins anzusuchen.",
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
@@ -44919,7 +45085,7 @@ array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => "Verspätete Projektabgabe ist bei Terminen, welche von der Studiengangsassistenz für den gesamten Studiengang fixiert wurden nicht erlaubt!
|
||||
|
||||
|
||||
Um einen Endupload durchführen zu können, müssen Sie ein positiv benotetes Quality Gate 1 & Quality Gate 2 in der relevanten Projektarbeit absolviert haben.",
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
@@ -45234,6 +45400,46 @@ array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'abgabetool',
|
||||
'phrase' => 'c4downloadLatestAbgabe',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => "Zuletzt getätigte Abgabe herunterladen",
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Download latest uploaded File',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'abgabetool',
|
||||
'phrase' => 'c4termineTimeLine',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Zeitstrahl Termine',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Timeline Deadlines',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'abgabetool',
|
||||
@@ -46695,6 +46901,26 @@ array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'abgabetool',
|
||||
'phrase' => 'c4noZuordnungBetreuerStudent',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Keine Zuordnung oder Berechtigung für die Projektarbeit gefunden!',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'No assignment or authorization found for the project!',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
// ABGABETOOL PHRASEN END
|
||||
array(
|
||||
'app' => 'core',
|
||||
@@ -56948,6 +57174,28 @@ I have been informed that I am under no obligation to consent to the transmissio
|
||||
)
|
||||
),
|
||||
// ### Refactor Messages END
|
||||
//
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'error_noLehrverbandAssigned',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'StudentIn ist in diesem Semester keinem Lehrverband zugeteilt',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Student has no assignment to any teaching association',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user