mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 23:14:02 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98ceeb862d | ||
|
|
2050f5ae65 | ||
|
|
587e523990 | ||
|
|
5ec1a1c54c | ||
|
|
2c65ccc8da | ||
|
|
787308aad4 | ||
|
|
ba92eea7eb | ||
|
|
50951dfdcf | ||
|
|
be7527e994 | ||
|
|
d5c1721ab1 | ||
|
|
8eb27b194f | ||
|
|
579a55a00d | ||
|
|
0a00caa1e4 | ||
|
|
c53040ed5c | ||
|
|
f7465047cb | ||
|
|
0dadaece08 | ||
|
|
69fd223358 | ||
|
|
9c43374267 | ||
|
|
ea7c0cccde | ||
|
|
6dfe292776 | ||
|
|
c90f7a31bb | ||
|
|
073160dde4 | ||
|
|
56fe8c9d09 | ||
|
|
9a3532265f | ||
|
|
4abe6f0d24 | ||
|
|
9fbbd6b855 | ||
|
|
1bf2b707ef | ||
|
|
e32691994c | ||
|
|
46f8d0d07d | ||
|
|
9274743df3 | ||
|
|
66e400013a | ||
|
|
3f95bfd82f | ||
|
|
dc22ac6b06 | ||
|
|
f4cc311806 | ||
|
|
df46b8ebdd | ||
|
|
870c36e76b | ||
|
|
96b2d88d39 | ||
|
|
474fc1fc57 | ||
|
|
3825e2fb38 | ||
|
|
4c0635be7c | ||
|
|
67b863f9db | ||
|
|
7628ebc9ca | ||
|
|
deb6dad7ad | ||
|
|
077f052112 | ||
|
|
e7f57c9ddd | ||
|
|
095e2bf581 | ||
|
|
25345a0522 | ||
|
|
e2b5201b5a | ||
|
|
5c80a382bf | ||
|
|
aa940683d6 | ||
|
|
843c65d52b | ||
|
|
e26f4262df | ||
|
|
dde586e004 | ||
|
|
506c23ae89 | ||
|
|
e90e03e0cc | ||
|
|
335671b46a | ||
|
|
19b8c16057 | ||
|
|
dea3aac222 | ||
|
|
5d7281e470 | ||
|
|
a7d925a177 | ||
|
|
4ef4a06a7e | ||
|
|
29515491a2 | ||
|
|
6cb8d0a9d1 | ||
|
|
2c4574d93b | ||
|
|
2fde630971 | ||
|
|
fce5ee7a16 | ||
|
|
8ccb9cd892 | ||
|
|
d1af44bcdc | ||
|
|
efc67d14a5 |
@@ -33,25 +33,5 @@ Events::on('loadRenderers', function ($renderers) {
|
||||
);
|
||||
});
|
||||
|
||||
Events::on('loadRenderers', function ($renderers) {
|
||||
$fhc_core_renderers =& $renderers();
|
||||
$fhc_core_renderers["coodle"] = array(
|
||||
'calendarEvent' => absoluteJsImportUrl('public/js/components/Cis/Renderer/Coodle/calendarEvent.js'),
|
||||
'modalTitle' => absoluteJsImportUrl('public/js/components/Cis/Renderer/Coodle/modalTitle.js'),
|
||||
'modalContent' => absoluteJsImportUrl('public/js/components/Cis/Renderer/Coodle/modalContent.js'),
|
||||
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
|
||||
);
|
||||
});
|
||||
|
||||
Events::on('loadRenderers', function ($renderers) {
|
||||
$fhc_core_renderers =& $renderers();
|
||||
$fhc_core_renderers["freeBusy"] = array(
|
||||
'calendarEvent' => absoluteJsImportUrl('public/js/components/Cis/Renderer/FreeBusy/calendarEvent.js'),
|
||||
'modalTitle' => absoluteJsImportUrl('public/js/components/Cis/Renderer/FreeBusy/modalTitle.js'),
|
||||
'modalContent' => absoluteJsImportUrl('public/js/components/Cis/Renderer/FreeBusy/modalContent.js'),
|
||||
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
$config['infocenter_studiengang_kz'] = '10021, 10027, 10002';
|
||||
$config['infocenter_qualifikationskurs_kz'] = '10002';
|
||||
|
||||
@@ -68,12 +68,6 @@ $route['Cis/OtherLvPlan/.*'] = 'Cis/OtherLvPlan/index/$1';
|
||||
//Route for LV Plan Stg/Semester/Verband/Gruppe
|
||||
$route['Cis/StgOrgLvPlan/.*'] = 'Cis/StgOrgLvPlan/index/$1';
|
||||
|
||||
$route['Cis/CoodleExternal/(:any)/(:any)'] = 'Cis/CoodleExternal/index/$1/$2';
|
||||
|
||||
$route['CoodleFreeBusy/(:any)'] = 'api/frontend/v1/coodle/FreeBusy/getCoodleFreeBusy/$1';
|
||||
$route['CoodleIcal/encrypted/(:any)'] = 'api/frontend/v1/coodle/CoodleSurvey/getCoodleIcalEncrypted/$1';
|
||||
$route['CoodleIcal/(:any)'] = 'api/frontend/v1/coodle/CoodleSurvey/getCoodleIcal/$1';
|
||||
|
||||
$route['Abgabetool/Assistenz'] = 'Cis/Abgabetool/Assistenz';
|
||||
$route['Abgabetool/Assistenz/(:any)'] = 'Cis/Abgabetool/Assistenz/$1';
|
||||
$route['Abgabetool/Mitarbeiter'] = 'Cis/Abgabetool/Mitarbeiter';
|
||||
|
||||
@@ -872,19 +872,3 @@ $config['dms'] = [
|
||||
)
|
||||
)"
|
||||
];
|
||||
|
||||
$config['group'] = [
|
||||
'primarykey' => 'gruppe_kurzbz',
|
||||
'table' => 'public.tbl_gruppe',
|
||||
'searchfields' => [
|
||||
'gruppe_kurzbz' => [
|
||||
'comparison' => 'similar',
|
||||
'field' => 'gruppe_kurzbz',
|
||||
],
|
||||
],
|
||||
'resultfields' => [
|
||||
"g.gruppe_kurzbz as name",
|
||||
],
|
||||
'resultjoin' => "
|
||||
JOIN public.tbl_gruppe g USING (gruppe_kurzbz)"
|
||||
];
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
|
||||
$CI =& get_instance();
|
||||
|
||||
|
||||
$config['employee'] = $CI->config->item('employee', 'search');
|
||||
unset($config['student']['searchfields']['email']);
|
||||
unset($config['student']['searchfields']['tel']);
|
||||
$config['employee']['resultfields'] = [
|
||||
"m.mitarbeiter_uid AS uid",
|
||||
"(p.vorname || ' ' || p.nachname) AS name",
|
||||
];
|
||||
$config['employee']['resultjoin'] = "
|
||||
JOIN public.tbl_mitarbeiter m USING (mitarbeiter_uid)
|
||||
JOIN public.tbl_benutzer b ON (b.uid = m.mitarbeiter_uid AND b.aktiv = true)
|
||||
JOIN public.tbl_person p USING(person_id)
|
||||
LEFT JOIN (
|
||||
SELECT kontakt, standort_id
|
||||
FROM public.tbl_kontakt
|
||||
WHERE kontakttyp = 'telefon'
|
||||
) k ON (k.standort_id = m.standort_id)";
|
||||
|
||||
$config['student'] = $CI->config->item('student', 'search');
|
||||
unset($config['student']['searchfields']['email']);
|
||||
unset($config['student']['searchfields']['tel']);
|
||||
$config['student']['resultfields'] = [
|
||||
"s.student_uid AS uid",
|
||||
"(p.vorname || ' ' || p.nachname) AS name",
|
||||
];
|
||||
$config['student']['resultjoin'] = "
|
||||
JOIN public.tbl_student s USING (student_uid)
|
||||
JOIN public.tbl_benutzer b ON(b.uid = s.student_uid AND b.aktiv = true)
|
||||
JOIN public.tbl_person p USING(person_id)";
|
||||
|
||||
$config['group'] = $CI->config->item('group', 'search');
|
||||
$config['group']['resultfields'] = [
|
||||
"g.gruppe_kurzbz as name",
|
||||
"ARRAY(
|
||||
SELECT bg.uid as uid
|
||||
FROM public.tbl_benutzergruppe bg
|
||||
WHERE bg.gruppe_kurzbz = g.gruppe_kurzbz
|
||||
ORDER BY bg.uid
|
||||
) AS user_uids",
|
||||
"ARRAY(
|
||||
SELECT p.vorname || ' ' || p.nachname AS name
|
||||
FROM public.tbl_benutzergruppe bg
|
||||
JOIN public.tbl_benutzer b ON(b.uid = bg.uid)
|
||||
JOIN public.tbl_person p ON(p.person_id = b.person_id)
|
||||
WHERE bg.gruppe_kurzbz = g.gruppe_kurzbz
|
||||
ORDER BY bg.uid
|
||||
) AS user_names",
|
||||
];
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Coodle extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'index' => [self::PERM_LOGGED],
|
||||
]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ["viewData" => [], 'route' => 'Coodle']);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class CoodleExternal extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'index' => [self::PERM_ANONYMOUS],
|
||||
]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'CoodleExternal', 'isExternal' => true]);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class AuthInfo extends FHCAPI_Controller
|
||||
{
|
||||
@@ -38,7 +37,6 @@ class AuthInfo extends FHCAPI_Controller
|
||||
|
||||
$this->load->model('crm/Student_model', 'StudentModel');
|
||||
$this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
|
||||
$this->uid = getAuthUID();
|
||||
$this->pid = getAuthPersonID();
|
||||
@@ -56,16 +54,15 @@ class AuthInfo extends FHCAPI_Controller
|
||||
*/
|
||||
public function getAuthUID()
|
||||
{
|
||||
$this->terminateWithSuccess(['uid' => $this->uid]);
|
||||
$this->terminateWithSuccess(['uid'=>$this->uid]);
|
||||
}
|
||||
|
||||
|
||||
public function getAuthInfo()
|
||||
{
|
||||
$data = (object) array(
|
||||
'uid' => $this->uid,
|
||||
'isMitarbeiter' => $this->isMitarbeiter,
|
||||
'isStudent' => $this->isStudent,
|
||||
'name' => getData($this->PersonModel->getFullName($this->uid)),
|
||||
'uid' => $this->uid,
|
||||
'isMitarbeiter' => $this->isMitarbeiter,
|
||||
'isStudent' => $this->isStudent
|
||||
);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ class CisMenu extends FHCAPI_Controller
|
||||
$doc->loadXML($menuItem->content);
|
||||
$urlElem = $doc->getElementsByTagName('url')->item(0);
|
||||
|
||||
$this->menuItemUrlTargetHelper($menuItem, $doc);
|
||||
|
||||
if (!$urlElem) {
|
||||
return '';
|
||||
}
|
||||
@@ -122,5 +124,18 @@ class CisMenu extends FHCAPI_Controller
|
||||
return $url;
|
||||
}
|
||||
|
||||
private function menuItemUrlTargetHelper($menuItem, $xmldoc)
|
||||
{
|
||||
if($menuItem->template_kurzbz === 'redirect')
|
||||
{
|
||||
$targetElem = $xmldoc->getElementsByTagName('target')->item(0);
|
||||
$target = ($targetElem) ? $targetElem->textContent : '';
|
||||
if(!in_array($target, array('_self', '_top', '_blank')))
|
||||
{
|
||||
$target = '_self';
|
||||
}
|
||||
$menuItem->target = $target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class Lehrveranstaltung extends FHCAPI_Controller
|
||||
{
|
||||
$studiengang_kz = $this->getStudiengangKz($stg_kz);
|
||||
|
||||
if (is_null($studiengang_kz) || !preg_match("/^-?[1-9][0-9]*$/", (string)$studiengang_kz))
|
||||
if (is_null($studiengang_kz) || !preg_match("/^(-?[1-9][0-9]*|0)$/", (string)$studiengang_kz))
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$verband = null;
|
||||
|
||||
@@ -47,7 +47,7 @@ class LvPlan extends FHCAPI_Controller
|
||||
'fetchFerienEvents' => self::PERM_LOGGED,
|
||||
'getStudiengaenge' => self::PERM_LOGGED,
|
||||
'getLehrverband' => self::PERM_LOGGED,
|
||||
'permissionOtherLvPlan' => self::PERM_ANONYMOUS,
|
||||
'permissionOtherLvPlan' => self::PERM_LOGGED,
|
||||
'compactibleEventTypes' => self::PERM_LOGGED,
|
||||
'getLeEvents' => self::PERM_LOGGED,
|
||||
'getLvEvents' => self::PERM_LOGGED,
|
||||
@@ -62,7 +62,6 @@ class LvPlan extends FHCAPI_Controller
|
||||
'dbExecuteUser' => 'RESTful API'
|
||||
));
|
||||
|
||||
$this->load->library('PermissionLib');
|
||||
$this->load->library('form_validation');
|
||||
$this->load->library('PhrasesLib');
|
||||
$this->loadPhrases(
|
||||
@@ -438,7 +437,7 @@ class LvPlan extends FHCAPI_Controller
|
||||
*/
|
||||
public function permissionOtherLvPlan()
|
||||
{
|
||||
$this->terminateWithSuccess(getAuthUID() && $this->permissionlib->isBerechtigt('basis/other_lv_plan'));
|
||||
$this->terminateWithSuccess($this->permissionlib->isBerechtigt('basis/other_lv_plan'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,7 @@ class RouteInfo extends FHCAPI_Controller
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'info' => self::PERM_ANONYMOUS,
|
||||
'info' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
$this->load->model('system/Webservicelog_model', 'WebservicelogModel');
|
||||
@@ -33,8 +33,6 @@ class RouteInfo extends FHCAPI_Controller
|
||||
|
||||
public function info()
|
||||
{
|
||||
if (!getAuthUID()) $this->terminateWithSuccess(null);
|
||||
|
||||
$payload = json_decode($this->input->raw_input_stream);
|
||||
|
||||
if (isset($payload->app) && isset($payload->path) && $this->isValidApp($payload->app) && $this->isValidPath($payload->path))
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2024 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class RoomPlan extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'addRoomReservation' => self::PERM_LOGGED,
|
||||
'deleteRoomReservation' => self::PERM_LOGGED,
|
||||
'getRoomCreationInfo' => self::PERM_LOGGED,
|
||||
'getGruppen' => self::PERM_LOGGED,
|
||||
'getLektor' => self::PERM_LOGGED,
|
||||
'getReservableMap' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
$this->load->library('LogLib');
|
||||
$this->loglib->setConfigs(array(
|
||||
'classIndex' => 5,
|
||||
'functionIndex' => 5,
|
||||
'lineIndex' => 4,
|
||||
'dbLogType' => 'API',
|
||||
'dbExecuteUser' => 'RESTful API'
|
||||
));
|
||||
|
||||
$this->load->library('form_validation');
|
||||
$this->load->library('PermissionLib');
|
||||
$this->load->library('StundenplanLib');
|
||||
|
||||
$this->loadPhrases(['ui']);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
|
||||
|
||||
public function addRoomReservation()
|
||||
{
|
||||
$this->form_validation->set_rules('selectedStart', "Start", "required");
|
||||
$this->form_validation->set_rules('selectedEnd', "End", "required");
|
||||
$this->form_validation->set_rules('title', "Title", "required|max_length[10]");
|
||||
$this->form_validation->set_rules('beschreibung', "Beschreibung", "required|max_length[32]");
|
||||
$this->form_validation->set_rules('ort_kurzbz', "Ort", "required|max_length[16]");
|
||||
$this->form_validation->set_rules('studiengang', 'Studiengang', 'numeric');
|
||||
$this->form_validation->set_rules('semester', 'Semester', 'integer|greater_than_equal_to[0]');
|
||||
$this->form_validation->set_rules('verband', 'Verband', 'trim');
|
||||
$this->form_validation->set_rules('gruppe', 'Gruppe', 'trim');
|
||||
$this->form_validation->set_rules('spezialgruppe', 'Spezialgruppe', 'max_length[32]');
|
||||
$this->form_validation->set_rules('lektoren', 'Lektoren');
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$start = $this->input->post('selectedStart');
|
||||
$end = $this->input->post('selectedEnd');
|
||||
$title = $this->input->post('title');
|
||||
$beschreibung = $this->input->post('beschreibung');
|
||||
$ort_kurzbz = $this->input->post('ort_kurzbz');
|
||||
|
||||
$studiengang_kz = $this->input->post('studiengang');
|
||||
$semester = $this->input->post('semester');
|
||||
$verband = $this->input->post('verband');
|
||||
$gruppe = $this->input->post('gruppe');
|
||||
$spezialgruppe = $this->input->post('spezialgruppe');
|
||||
$lektoren = $this->input->post('lektoren');
|
||||
|
||||
|
||||
$result = $this->stundenplanlib->addReservation($start, $end, $title, $beschreibung, $ort_kurzbz, $lektoren, $studiengang_kz, $semester, $verband, $gruppe, $spezialgruppe);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
public function deleteRoomReservation()
|
||||
{
|
||||
$reservierung_id = $this->input->post('reservierung_id');
|
||||
|
||||
$result = $this->stundenplanlib->deleteReservation($reservierung_id);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
public function getRoomCreationInfo()
|
||||
{
|
||||
$return_array = array('berechtigt' => false, 'studiengaenge' => []);
|
||||
if (!$this->permissionlib->isBerechtigt('lehre/reservierung'))
|
||||
$this->terminateWithSuccess($return_array);
|
||||
|
||||
$stg_berechtigungen = $this->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
|
||||
if (isEmptyArray($stg_berechtigungen))
|
||||
$this->terminateWithSuccess($return_array);
|
||||
|
||||
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
$this->StudiengangModel->addSelect('studiengang_kz, UPPER(CONCAT(typ, kurzbz)) as kuerzel, kurzbzlang');
|
||||
$this->StudiengangModel->addOrder('typ, kurzbz');
|
||||
$this->StudiengangModel->db->where_in('studiengang_kz', $stg_berechtigungen);
|
||||
$studiengaenge = $this->StudiengangModel->loadWhere(array('aktiv' => true));
|
||||
|
||||
if (isError($studiengaenge))
|
||||
$this->terminateWithError($studiengaenge);
|
||||
|
||||
$return_array['studiengaenge'] = hasData($studiengaenge) ? getData($studiengaenge) : [];
|
||||
$return_array['berechtigt'] = true;
|
||||
|
||||
$this->terminateWithSuccess($return_array);
|
||||
}
|
||||
|
||||
public function getGruppen()
|
||||
{
|
||||
$query = $this->input->get('query');
|
||||
if (is_null($query))
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$stg_berechtigungen = $this->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
|
||||
|
||||
if (isEmptyArray($stg_berechtigungen))
|
||||
$this->terminateWithSuccess([]);
|
||||
|
||||
$this->load->model('organisation/gruppe_model', 'GruppeModel');
|
||||
|
||||
$query_words = explode(' ', urldecode($query));
|
||||
|
||||
$this->GruppeModel->addOrder('gruppe_kurzbz');
|
||||
$this->GruppeModel->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->GruppeModel->db->group_start();
|
||||
$this->GruppeModel->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
|
||||
$this->GruppeModel->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
|
||||
$this->GruppeModel->db->or_where('beschreibung ILIKE', "%" . $word . "%");
|
||||
$this->GruppeModel->db->or_where('orgform_kurzbz ILIKE', "%" . $word . "%");
|
||||
|
||||
if (is_numeric($word))
|
||||
{
|
||||
$this->GruppeModel->db->or_where('studiengang_kz', $word);
|
||||
}
|
||||
$this->GruppeModel->db->group_end();
|
||||
}
|
||||
$this->GruppeModel->db->group_end();
|
||||
$this->GruppeModel->db->where_in('studiengang_kz', $stg_berechtigungen);
|
||||
$gruppen = $this->GruppeModel->loadWhere(array('sichtbar' => true, 'lehre' => true));
|
||||
if (isError($gruppen))
|
||||
$this->terminateWithError($gruppen);
|
||||
|
||||
$this->terminateWithSuccess(hasData($gruppen) ? getData($gruppen) : []);
|
||||
}
|
||||
|
||||
public function getLektor()
|
||||
{
|
||||
|
||||
$query = $this->input->get('query');
|
||||
if (is_null($query))
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$stg_berechtigungen = $this->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
|
||||
|
||||
if (isEmptyArray($stg_berechtigungen))
|
||||
$this->terminateWithSuccess([]);
|
||||
|
||||
$this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
|
||||
|
||||
$query_words = explode(' ', urldecode($query));
|
||||
|
||||
$this->MitarbeiterModel->addSelect('uid, person_id, vorname, nachname');
|
||||
$this->MitarbeiterModel->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid');
|
||||
$this->MitarbeiterModel->addJoin('public.tbl_person', 'person_id');
|
||||
$this->MitarbeiterModel->db->where('public.tbl_benutzer.aktiv', true);
|
||||
$this->MitarbeiterModel->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->MitarbeiterModel->db->group_start();
|
||||
$this->MitarbeiterModel->db->where('tbl_person.vorname ILIKE', "%" . $word . "%");
|
||||
$this->MitarbeiterModel->db->or_where('tbl_person.nachname ILIKE', "%" . $word . "%");
|
||||
$this->MitarbeiterModel->db->or_where('uid ILIKE', "%" . $word . "%");
|
||||
$this->MitarbeiterModel->db->group_end();
|
||||
}
|
||||
$this->MitarbeiterModel->db->group_end();
|
||||
|
||||
$this->MitarbeiterModel->addOrder('nachname');
|
||||
$this->MitarbeiterModel->addOrder('vorname');
|
||||
$mitarbeiter = $this->MitarbeiterModel->load();
|
||||
if (isError($mitarbeiter))
|
||||
$this->terminateWithError($mitarbeiter);
|
||||
|
||||
$this->terminateWithSuccess(hasData($mitarbeiter) ? getData($mitarbeiter) : []);
|
||||
}
|
||||
|
||||
public function getReservableMap($ort_kurzbz = null)
|
||||
{
|
||||
$this->form_validation->set_rules('start_date', "StartDate", "required");
|
||||
$this->form_validation->set_rules('end_date', "EndDate", "required");
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
// storing the post parameter in local variables
|
||||
$start_date = $this->input->post('start_date', true);
|
||||
$end_date = $this->input->post('end_date', true);
|
||||
|
||||
$result = $this->stundenplanlib->getReservableMap($ort_kurzbz, $start_date, $end_date);
|
||||
|
||||
$this->terminateWithSuccess(array('reservierbarMap' => hasData($result) ? getData($result) : []));
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,322 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2026 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
class FreeBusy extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getFreeBusyTypes' => self::PERM_LOGGED,
|
||||
'getFreeBusyEntries' => self::PERM_LOGGED,
|
||||
'createFreeBusyEntry' => self::PERM_LOGGED,
|
||||
'updateFreeBusyEntry' => self::PERM_LOGGED,
|
||||
'deleteFreeBusyEntry' => self::PERM_LOGGED,
|
||||
'getFreeBusySchedule' => self::PERM_LOGGED,
|
||||
'getCoodleFreeBusy' => self::PERM_ANONYMOUS,
|
||||
]);
|
||||
|
||||
$this->load->model('person/Freebusy_model', 'FreeBusyModel');
|
||||
$this->load->model('person/Freebusytyp_model', 'FreeBusyTypeModel');
|
||||
|
||||
$this->load->library('FreeBusyLib');
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->load->model("ressource/CoodleSurvey_model", "CoodleSurveyModel");
|
||||
$this->load->model("ressource/CoodleSurveyTimeslot_model", "CoodleSurveyTimeslotModel");
|
||||
$this->load->model("ressource/CoodleSurveyParticipant_model", "CoodleSurveyParticipantModel");
|
||||
|
||||
$this->loadPhrases([
|
||||
'coodle'
|
||||
]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
public function getFreeBusyTypes()
|
||||
{
|
||||
$freeBusyTypesResult = $this->FreeBusyTypeModel->getActiveFreeBusyTypes();
|
||||
$freeBusyTypes = $this->getDataOrTerminateWithError($freeBusyTypesResult);
|
||||
$freeBusyTypes = $this->formatDefaultUrlsInFreeBusyTypes($freeBusyTypes);
|
||||
$this->terminateWithSuccess($freeBusyTypes);
|
||||
|
||||
}
|
||||
|
||||
public function getFreeBusyEntries()
|
||||
{
|
||||
$this->FreeBusyModel->addOrder("freebusy_id");
|
||||
$freeBusyEntries = $this->FreeBusyModel->loadWhere(["uid" => getAuthUID()]);
|
||||
$freeBusyEntries = $this->getDataOrTerminateWithError($freeBusyEntries);
|
||||
$this->terminateWithSuccess($freeBusyEntries);
|
||||
}
|
||||
|
||||
public function createFreeBusyEntry()
|
||||
{
|
||||
$description = $this->input->post("description");
|
||||
$type = $this->input->post("type") ?? "Sonstiges";
|
||||
$url = $this->input->post("url");
|
||||
$isActive = $this->input->post("isActive");
|
||||
|
||||
$this->form_validation->set_data([
|
||||
"url" => $url,
|
||||
"description" => $description,
|
||||
]);
|
||||
$this->form_validation->set_rules("url", "URL", "required|max_length[255]");
|
||||
$this->form_validation->set_rules("description", "Description", "max_length[255]");
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
if (!$this->isUrlValid($url)) {
|
||||
$this->terminateWithError($this->p->t("coodle", "url_not_working"));
|
||||
}
|
||||
|
||||
$this->FreeBusyModel->insert(
|
||||
[
|
||||
"uid" => getAuthUID(),
|
||||
"freebusytyp_kurzbz" => $type,
|
||||
"url" => $url,
|
||||
"aktiv" => $isActive,
|
||||
"bezeichnung" => $description,
|
||||
]
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
public function updateFreeBusyEntry()
|
||||
{
|
||||
$id = $this->input->post("id");
|
||||
$description = $this->input->post("description");
|
||||
$type = $this->input->post("type") ?? "Sonstiges";
|
||||
$url = $this->input->post("url");
|
||||
$isActive = $this->input->post("isActive");
|
||||
|
||||
$this->form_validation->set_data([
|
||||
"url" => $url,
|
||||
"description" => $description,
|
||||
]);
|
||||
$this->form_validation->set_rules("url", "URL", "required|max_length[255]");
|
||||
$this->form_validation->set_rules("description", "Description", "max_length[255]");
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
if (!$this->isUrlValid($url)) {
|
||||
$this->terminateWithError($this->p->t("coodle", "url_not_working"));
|
||||
}
|
||||
|
||||
$existingFreeBusyEntryResult = $this->FreeBusyModel->load($id);
|
||||
$existingFreeBusyEntry = $this->getDataOrTerminateWithError($existingFreeBusyEntryResult);
|
||||
$existingFreeBusyEntry = $existingFreeBusyEntry && count($existingFreeBusyEntry) ? $existingFreeBusyEntry[0] : null;
|
||||
if (!$existingFreeBusyEntry) {
|
||||
$this->terminateWithError("FreeBusy entry not found!");
|
||||
} else if ($existingFreeBusyEntry->uid !== getAuthUID()) {
|
||||
$this->terminateWithError("You are not authorized to modify this FreeBusy entry!");
|
||||
}
|
||||
|
||||
$this->FreeBusyModel->update(
|
||||
$id,
|
||||
[
|
||||
"uid" => getAuthUID(),
|
||||
"freebusytyp_kurzbz" => $type,
|
||||
"url" => $url,
|
||||
"aktiv" => $isActive,
|
||||
"bezeichnung" => $description,
|
||||
]
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
public function deleteFreeBusyEntry()
|
||||
{
|
||||
$id = $this->input->post("id");
|
||||
|
||||
$existingFreeBusyEntryResult = $this->FreeBusyModel->load($id);
|
||||
$existingFreeBusyEntry = $this->getDataOrTerminateWithError($existingFreeBusyEntryResult);
|
||||
$existingFreeBusyEntry = $existingFreeBusyEntry && count($existingFreeBusyEntry) ? $existingFreeBusyEntry[0] : null;
|
||||
if (!$existingFreeBusyEntry) {
|
||||
$this->terminateWithError("FreeBusy entry not found!");
|
||||
} else if ($existingFreeBusyEntry->uid !== getAuthUID()) {
|
||||
$this->terminateWithError("You are not authorized to delete this FreeBusy entry!");
|
||||
}
|
||||
|
||||
$this->FreeBusyModel->delete($id);
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
public function getFreeBusySchedule()
|
||||
{
|
||||
$uid = $this->input->post("uid");
|
||||
$coodleSurveyIdToExclude = $this->input->post("coodleSurveyIdToExclude");
|
||||
$freeBusyEntries = $this->FreeBusyModel->loadWhere(["uid" => $uid, "aktiv" => true]);
|
||||
$freeBusyEntries = $this->getDataOrTerminateWithError($freeBusyEntries);
|
||||
|
||||
$cumulativeFreeBusyEvents = $this->freebusylib->getDefaultInternalFreeBusy($uid);
|
||||
|
||||
foreach ($freeBusyEntries as $freeBusyEntry) {
|
||||
// todo: following workaround is to use new coodle freebusy endpoint, remove once actual redirect is set up
|
||||
// keep query param with excluded survey id, only remove url replacement
|
||||
$freeBusyUrl = $freeBusyEntry->url;
|
||||
if ($freeBusyEntry->freebusytyp_kurzbz === "Coodle") {
|
||||
$freeBusyUrl = APP_ROOT . "cis.php/CoodleFreeBusy/" . $uid;
|
||||
if ($coodleSurveyIdToExclude) {
|
||||
$freeBusyUrl .= "?excludeSurvey=" . $coodleSurveyIdToExclude;
|
||||
}
|
||||
}
|
||||
|
||||
$freeBusyEvents = $this->freebusylib->getFreeBusy($freeBusyUrl);
|
||||
$cumulativeFreeBusyEvents = array_merge(
|
||||
$cumulativeFreeBusyEvents,
|
||||
$freeBusyEvents
|
||||
);
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess($cumulativeFreeBusyEvents);
|
||||
}
|
||||
|
||||
public function getCoodleFreeBusy($uid)
|
||||
{
|
||||
$participantEntries = $this->CoodleSurveyParticipantModel->getParticipantEntriesByUid($uid);
|
||||
|
||||
$surveys = [];
|
||||
if (count($participantEntries)) {
|
||||
$surveyIds = array_map(
|
||||
function ($participantEntry) {
|
||||
return $participantEntry->survey_id;
|
||||
},
|
||||
$participantEntries
|
||||
);
|
||||
$surveys = $this->CoodleSurveyModel->getSurveys($surveyIds);
|
||||
}
|
||||
|
||||
$surveyIdToBeExcluded = $this->input->get("excludeSurvey");
|
||||
if ($surveyIdToBeExcluded) {
|
||||
$surveyIdToBeExcluded = intval($surveyIdToBeExcluded);
|
||||
$surveys = array_filter(
|
||||
$surveys,
|
||||
function ($survey) use ($surveyIdToBeExcluded) {
|
||||
return $survey->id !== $surveyIdToBeExcluded;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$activeSurveys = array_filter(
|
||||
$surveys,
|
||||
function ($survey) {
|
||||
return !$survey->completed_at && !$survey->canceled_at;
|
||||
}
|
||||
);
|
||||
|
||||
$timeslots = [];
|
||||
if (count($activeSurveys)) {
|
||||
$activeSurveyIds = array_map(
|
||||
function ($activeSurvey) {
|
||||
return $activeSurvey->id;
|
||||
},
|
||||
$activeSurveys
|
||||
);
|
||||
$timeslots = $this->CoodleSurveyTimeslotModel->getTimeslotsForMultipleSurveys($activeSurveyIds);
|
||||
}
|
||||
|
||||
$formattedTimeslots = [];
|
||||
if (count($timeslots)) {
|
||||
$localTimezone = new DateTimeZone("Europe/Vienna");
|
||||
$utcTimezone = new DateTimeZone("UTC");
|
||||
|
||||
foreach ($activeSurveys as $activeSurvey) {
|
||||
$correspondingTimeslots = array_filter(
|
||||
$timeslots,
|
||||
function ($timeslot) use ($activeSurvey) {
|
||||
return $timeslot->survey_id === $activeSurvey->id;
|
||||
}
|
||||
);
|
||||
$formattedCorrespondingTimeslots = array_map(
|
||||
function ($timeslot) use ($activeSurvey, $utcTimezone, $localTimezone) {
|
||||
$startTime = new DateTime($timeslot->starts_at, $localTimezone);
|
||||
$endTime = new DateTime($timeslot->starts_at, $localTimezone);
|
||||
$endTime->modify("+$activeSurvey->timeslot_duration minutes");
|
||||
|
||||
$startTime->setTimezone($utcTimezone);
|
||||
$endTime->setTimezone($utcTimezone);
|
||||
|
||||
$formattedStartTime = $startTime->format("Ymd\THis\Z");
|
||||
$formattedEndTime = $endTime->format("Ymd\THis\Z");
|
||||
return [
|
||||
"start" => $formattedStartTime,
|
||||
"end" => $formattedEndTime,
|
||||
];
|
||||
},
|
||||
$correspondingTimeslots
|
||||
);
|
||||
$formattedTimeslots = array_merge($formattedTimeslots, $formattedCorrespondingTimeslots);
|
||||
}
|
||||
}
|
||||
|
||||
$coodleFreeBusyIcsFilePath = tempnam(sys_get_temp_dir(), "coodle_freebusy_");
|
||||
|
||||
$coodleFreeBusyIcsFile = fopen($coodleFreeBusyIcsFilePath, "w");
|
||||
fwrite($coodleFreeBusyIcsFile, "BEGIN:VCALENDAR" . PHP_EOL);
|
||||
fwrite($coodleFreeBusyIcsFile, "VERSION:2.0" . PHP_EOL);
|
||||
fwrite($coodleFreeBusyIcsFile, "PRDODID:" . CAMPUS_NAME . PHP_EOL);
|
||||
fwrite($coodleFreeBusyIcsFile, "ATTENDEE:mailto:" . $uid . "@" . DOMAIN . PHP_EOL);
|
||||
fwrite($coodleFreeBusyIcsFile, "BEGIN:VFREEBUSY" . PHP_EOL);
|
||||
|
||||
foreach ($formattedTimeslots as $timeslot) {
|
||||
fwrite($coodleFreeBusyIcsFile, "FREEBUSY;FBTYPE=BUSY:" . $timeslot["start"] . "/" . $timeslot["end"] . PHP_EOL);
|
||||
}
|
||||
|
||||
fwrite($coodleFreeBusyIcsFile, "END:VFREEBUSY" . PHP_EOL);
|
||||
fwrite($coodleFreeBusyIcsFile, "END:VCALENDAR");
|
||||
|
||||
$this->terminateWithFileOutput("text/calendar", file_get_contents($coodleFreeBusyIcsFilePath), "coodle_freebusy_$uid.ics");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
private function isUrlValid($url)
|
||||
{
|
||||
return !!@fopen($url, "r");
|
||||
}
|
||||
|
||||
private function formatDefaultUrlsInFreeBusyTypes($freeBusyTypes)
|
||||
{
|
||||
$uid = getAuthUID();
|
||||
return array_map(function ($freeBusyType) use ($uid) {
|
||||
if (!$freeBusyType->url_vorlage || !strlen($freeBusyType->url_vorlage)) {
|
||||
$freeBusyType->url_default = null;
|
||||
unset($freeBusyType->url_vorlage);
|
||||
return $freeBusyType;
|
||||
}
|
||||
|
||||
$freeBusyType->url_default = str_replace('$uid', $uid, $freeBusyType->url_vorlage);
|
||||
unset($freeBusyType->url_vorlage);
|
||||
return $freeBusyType;
|
||||
}, $freeBusyTypes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -370,6 +370,7 @@ class LvTermine extends FHCAPI_Controller
|
||||
$result->semester = $item->semester;
|
||||
$result->verband = $item->verband;
|
||||
$result->gruppe = $item->gruppe;
|
||||
$result->studiensemester_kurzbz = $item->studiensemester_kurzbz;
|
||||
return $result;
|
||||
},
|
||||
$lehrverband_query_result));
|
||||
|
||||
@@ -42,6 +42,8 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
$this->load->model('education/Note_model', 'NoteModel');
|
||||
$this->load->model('education/Projektbetreuer_model', 'BetreuerModel');
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
$this->load->model('crm/Student_model', 'StudentModel');
|
||||
$this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel');
|
||||
|
||||
// load libraries
|
||||
$this->load->library('PermissionLib');
|
||||
@@ -100,16 +102,16 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
private function fetchProjektarbeitById($projektarbeit_id) {
|
||||
$this->ProjektarbeitModel->resetQuery();
|
||||
$this->ProjektarbeitModel->addSelect(
|
||||
'lehre.tbl_projektarbeit.projektarbeit_id, titel, titel_english, themenbereich, projekttyp_kurzbz, lehrveranstaltung_id, lehreinheit_id,
|
||||
firma_id, beginn, ende, gesperrtbis, note, final, freigegeben, tbl_projektarbeit.anmerkung, fa.name AS firma_name'
|
||||
'lehre.tbl_projektarbeit.projektarbeit_id, titel, titel_english, themenbereich, projekttyp_kurzbz, lehrveranstaltung_id, lehreinheit_id,
|
||||
tbl_projektarbeit.studiensemester_kurzbz, firma_id, beginn, ende, gesperrtbis, note, final, freigegeben, tbl_projektarbeit.anmerkung, fa.name AS firma_name'
|
||||
);
|
||||
$this->ProjektarbeitModel->addJoin('lehre.tbl_lehreinheit le', 'lehreinheit_id');
|
||||
$this->ProjektarbeitModel->addJoin('lehre.tbl_lehrveranstaltung lv', 'lehrveranstaltung_id');
|
||||
$this->ProjektarbeitModel->addJoin('public.tbl_firma fa', 'firma_id', 'LEFT');
|
||||
|
||||
|
||||
return $this->ProjektarbeitModel->loadWhere(
|
||||
array('projektarbeit_id' => $projektarbeit_id)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,14 +248,38 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
$additional_lehrveranstaltung_id = $this->input->get('additional_lehrveranstaltung_id');
|
||||
|
||||
if (!isset($student_uid)) $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL);
|
||||
if (!isset($studiensemester_kurzbz)) $this->terminateWithError('Studiensemster missing', self::ERROR_TYPE_GENERAL);
|
||||
if (!isset($studiensemester_kurzbz)) $this->terminateWithError('Studiensemester missing', self::ERROR_TYPE_GENERAL);
|
||||
|
||||
// get Lvs
|
||||
// get prestudent_id from student model
|
||||
$studentRes = $this->StudentModel->load(['student_uid' => $student_uid]);
|
||||
if(hasData($studentRes)) {
|
||||
$student = getData($studentRes);
|
||||
} else {
|
||||
$this->terminateWithError($studentRes, self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
// to get prestudent_status history
|
||||
$historyRes = $this->PrestudentstatusModel->getHistoryPrestudent($student[0]->prestudent_id);
|
||||
if(hasData($historyRes)) {
|
||||
$history = getData($historyRes);
|
||||
} else {
|
||||
$this->terminateWithError($historyRes, self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
// query for every lva of a studiengang that has projektarbeit flag true
|
||||
$lvsResult = $this->LehrveranstaltungModel->getLvsForProjektarbeit($student_uid, $studiengang_kz, $additional_lehrveranstaltung_id);
|
||||
|
||||
if (isError($lvsResult)) return $this->terminateWithError($lvsResult, self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$lvs = hasData($lvsResult) ? getData($lvsResult) : [];
|
||||
|
||||
$lvsIDs = array_column($lvs, 'lehrveranstaltung_id');
|
||||
|
||||
// get current studienplan_id from status history to find out which lva options are actually assigned to the students studienplan
|
||||
// important so the projektarbeit has the correct lva assigned to be able to find and print the thesis title on the degree documents!
|
||||
$currentStatus = $history[0];
|
||||
$lvByStudienPlanRes = $this->LehrveranstaltungModel->getLvsByStudienplanByLvaIDs($currentStatus->studienplan_id, $lvsIDs);
|
||||
if(hasData($lvByStudienPlanRes)) {
|
||||
$lvs = getData($lvByStudienPlanRes);
|
||||
}
|
||||
|
||||
foreach ($lvs as $lv)
|
||||
{
|
||||
@@ -320,11 +346,18 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp'])
|
||||
]);
|
||||
|
||||
$this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'required|is_natural', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehreinheit']),
|
||||
$this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'is_natural', [
|
||||
'is_natural' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit'])
|
||||
]);
|
||||
|
||||
$this->form_validation->set_rules('lehrveranstaltung_id', 'Lehrveranstaltung', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehrveranstaltung'])
|
||||
]);
|
||||
|
||||
$this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required', [
|
||||
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Studiensemester'])
|
||||
]);
|
||||
|
||||
$this->form_validation->set_rules('beginn', 'Beginn', 'is_valid_date', [
|
||||
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Beginn'])
|
||||
]);
|
||||
@@ -354,6 +387,8 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
'projekttyp_kurzbz' => $formData['projekttyp_kurzbz'],
|
||||
'firma_id' => $formData['firma_id'] ?? null,
|
||||
'lehreinheit_id' => $formData['lehreinheit_id'],
|
||||
'lehrveranstaltung_id' => $formData['lehrveranstaltung_id'],
|
||||
'studiensemester_kurzbz' => $formData['studiensemester_kurzbz'],
|
||||
'beginn' => isset($formData['beginn']) && !isEmptyString($formData['beginn']) ? $formData['beginn'] : null,
|
||||
'ende' => isset($formData['ende']) && !isEmptyString($formData['ende']) ? $formData['ende'] : null,
|
||||
'note' => $formData['note'] ?? null,
|
||||
|
||||
@@ -803,7 +803,7 @@ class ReihungstestJob extends JOB_Controller
|
||||
{
|
||||
if (!isset($studiensemester) || isEmptyString($studiensemester))
|
||||
{
|
||||
$this->logError("Studiensemster not passed as parameter");
|
||||
$this->logError("Studiensemester not passed as parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ class InfoCenter extends Auth_Controller
|
||||
const PREV_FILTER_ID = 'prev_filter_id';
|
||||
const KEEP_TABLESORTER_FILTER = 'keepTsFilter';
|
||||
|
||||
const ONBOARDING_INSERTVON = 'onboarding';
|
||||
const ONBOARDING_KENNZEICHENTYP = 'eobRegistrierungsId';
|
||||
|
||||
private $_uid; // contains the UID of the logged user
|
||||
|
||||
// Used to log with PersonLogLib
|
||||
@@ -175,6 +178,7 @@ class InfoCenter extends Auth_Controller
|
||||
$this->load->model('person/Kontakt_model', 'KontaktModel');
|
||||
$this->load->model('person/Geschlecht_model', 'GeschlechtModel');
|
||||
$this->load->model('person/adresse_model', 'AdresseModel');
|
||||
$this->load->model('person/Kennzeichen_model', 'KennzeichenModel');
|
||||
|
||||
// Loads libraries
|
||||
$this->load->library('PersonLogLib');
|
||||
@@ -1452,6 +1456,100 @@ class InfoCenter extends Auth_Controller
|
||||
|
||||
$this->outputJsonSuccess("Done!");
|
||||
}
|
||||
|
||||
public function getAbsageData()
|
||||
{
|
||||
$stg_typ = $this->getStudienArtBerechtigung(['b', 'm']);
|
||||
|
||||
if (!is_null($stg_typ))
|
||||
{
|
||||
$statusgruende = $this->StatusgrundModel->getStatus(self::ABGEWIESENERSTATUS, true)->retval;
|
||||
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
|
||||
$studiengaenge = $this->StudiengangModel->getStudiengaengeWithOrgForm(array_column($stg_typ, 'typ'), $studienSemester);
|
||||
|
||||
$data = array (
|
||||
'statusgruende' => $statusgruende,
|
||||
'studiengaenge' => $studiengaenge->retval
|
||||
);
|
||||
|
||||
$this->outputJsonSuccess($data);
|
||||
}
|
||||
else
|
||||
$this->outputJsonSuccess(null);
|
||||
}
|
||||
|
||||
public function getStudienArtBerechtigung($typ = null)
|
||||
{
|
||||
$studiengang_kz_all = $this->permissionlib->getSTG_isEntitledFor('infocenter');
|
||||
$stg_typ = $this->StudiengangModel->getStudiengangTyp($studiengang_kz_all, $typ);
|
||||
return getData($stg_typ);
|
||||
}
|
||||
|
||||
public function getStudienartData()
|
||||
{
|
||||
$this->outputJsonSuccess($this->getStudienArtBerechtigung(['b', 'm', 'l']));
|
||||
}
|
||||
|
||||
public function saveAbsageForAll()
|
||||
{
|
||||
$statusgrund = $this->input->post('statusgrund');
|
||||
$studiengang = $this->input->post('studiengang');
|
||||
$abgeschickt = $this->input->post('abgeschickt');
|
||||
$personen = $this->input->post('personen');
|
||||
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
|
||||
|
||||
if ($statusgrund === 'null' || $studiengang === 'null' || $abgeschickt === 'null' || empty($personen))
|
||||
$this->terminateWithJsonError("Bitte füllen Sie alle Felder aus");
|
||||
|
||||
if ($studiengang === 'all' && $abgeschickt === 'all')
|
||||
{
|
||||
foreach($personen as $person)
|
||||
{
|
||||
$prestudenten = $this->PrestudentModel->getByPersonWithoutLehrgang($person, $studienSemester);
|
||||
|
||||
if (!hasData($prestudenten))
|
||||
continue;
|
||||
|
||||
$prestudentenData = getData($prestudenten);
|
||||
|
||||
foreach ($prestudentenData as $prestudent)
|
||||
{
|
||||
$this->saveAbsage($prestudent->prestudent_id, $statusgrund);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
|
||||
|
||||
$this->StudienplanModel->addSelect('1');
|
||||
$this->StudienplanModel->addJoin('lehre.tbl_studienordnung so', 'studienordnung_id');
|
||||
$escaped = $this->StudienplanModel->db->escape(strtoupper($studiengang));
|
||||
$this->StudienplanModel->db->where("UPPER(so.studiengangkurzbzlang || ':' || tbl_studienplan.orgform_kurzbz) = $escaped");
|
||||
$this->StudienplanModel->addLimit(1);
|
||||
$studiengangResult = $this->StudienplanModel->load();
|
||||
|
||||
if (hasData($studiengangResult))
|
||||
{
|
||||
foreach($personen as $person)
|
||||
{
|
||||
$prestudent = $this->PrestudentModel->getPrestudentByStudiengangAndPerson($studiengang, $person, $studienSemester, $abgeschickt, $abgeschickt === 'all');
|
||||
|
||||
if (!hasData($prestudent))
|
||||
continue;
|
||||
|
||||
$prestudentData = getData($prestudent);
|
||||
$this->saveAbsage($prestudentData[0]->prestudent_id, $statusgrund);
|
||||
}
|
||||
}
|
||||
else
|
||||
$this->terminateWithJsonError("Falschen Studiengang übergeben!");
|
||||
|
||||
}
|
||||
|
||||
$this->outputJsonSuccess("Success");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
@@ -1946,6 +2044,17 @@ class InfoCenter extends Auth_Controller
|
||||
show_error(getError($user_person));
|
||||
}
|
||||
|
||||
// add info about first electronig onboarding login
|
||||
$this->KennzeichenModel->addSelect('insertamum');
|
||||
$onboarding_first_login = $this->KennzeichenModel->loadWhere(
|
||||
array('person_id' => $person_id, 'kennzeichentyp_kurzbz' => self::ONBOARDING_KENNZEICHENTYP)
|
||||
);
|
||||
|
||||
if (isError($onboarding_first_login))
|
||||
{
|
||||
show_error(getError($onboarding_first_login));
|
||||
}
|
||||
|
||||
$data = array (
|
||||
'lockedby' => $lockedby,
|
||||
'lockedbyother' => $lockedbyother,
|
||||
@@ -1955,7 +2064,9 @@ class InfoCenter extends Auth_Controller
|
||||
'messages' => $messages->retval,
|
||||
'logs' => $logs,
|
||||
'notizen' => $notizen->retval,
|
||||
'notizenbewerbung' => $notizen_bewerbung->retval
|
||||
'notizenbewerbung' => $notizen_bewerbung->retval,
|
||||
'created_by_onboarding' => $stammdaten->retval->insertvon == self::ONBOARDING_INSERTVON,
|
||||
'onboarding_first_login' => hasData($onboarding_first_login) ? getData($onboarding_first_login)[0]->insertamum : null
|
||||
);
|
||||
|
||||
return $data;
|
||||
@@ -2375,97 +2486,4 @@ class InfoCenter extends Auth_Controller
|
||||
$this->loglib->logError('Studiengang has no mail for sending Freigabe mail');
|
||||
}
|
||||
}
|
||||
|
||||
public function getAbsageData()
|
||||
{
|
||||
$stg_typ = $this->getStudienArtBerechtigung(['b', 'm']);
|
||||
|
||||
if (!is_null($stg_typ))
|
||||
{
|
||||
$statusgruende = $this->StatusgrundModel->getStatus(self::ABGEWIESENERSTATUS, true)->retval;
|
||||
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
|
||||
$studiengaenge = $this->StudiengangModel->getStudiengaengeWithOrgForm(array_column($stg_typ, 'typ'), $studienSemester);
|
||||
|
||||
$data = array (
|
||||
'statusgruende' => $statusgruende,
|
||||
'studiengaenge' => $studiengaenge->retval
|
||||
);
|
||||
|
||||
$this->outputJsonSuccess($data);
|
||||
}
|
||||
else
|
||||
$this->outputJsonSuccess(null);
|
||||
}
|
||||
|
||||
public function getStudienArtBerechtigung($typ = null)
|
||||
{
|
||||
$studiengang_kz_all = $this->permissionlib->getSTG_isEntitledFor('infocenter');
|
||||
$stg_typ = $this->StudiengangModel->getStudiengangTyp($studiengang_kz_all, $typ);
|
||||
return getData($stg_typ);
|
||||
}
|
||||
|
||||
public function getStudienartData()
|
||||
{
|
||||
$this->outputJsonSuccess($this->getStudienArtBerechtigung(['b', 'm', 'l']));
|
||||
}
|
||||
|
||||
public function saveAbsageForAll()
|
||||
{
|
||||
$statusgrund = $this->input->post('statusgrund');
|
||||
$studiengang = $this->input->post('studiengang');
|
||||
$abgeschickt = $this->input->post('abgeschickt');
|
||||
$personen = $this->input->post('personen');
|
||||
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
|
||||
|
||||
if ($statusgrund === 'null' || $studiengang === 'null' || $abgeschickt === 'null' || empty($personen))
|
||||
$this->terminateWithJsonError("Bitte füllen Sie alle Felder aus");
|
||||
|
||||
if ($studiengang === 'all' && $abgeschickt === 'all')
|
||||
{
|
||||
foreach($personen as $person)
|
||||
{
|
||||
$prestudenten = $this->PrestudentModel->getByPersonWithoutLehrgang($person, $studienSemester);
|
||||
|
||||
if (!hasData($prestudenten))
|
||||
continue;
|
||||
|
||||
$prestudentenData = getData($prestudenten);
|
||||
|
||||
foreach ($prestudentenData as $prestudent)
|
||||
{
|
||||
$this->saveAbsage($prestudent->prestudent_id, $statusgrund);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
|
||||
|
||||
$this->StudienplanModel->addSelect('1');
|
||||
$this->StudienplanModel->addJoin('lehre.tbl_studienordnung so', 'studienordnung_id');
|
||||
$escaped = $this->StudienplanModel->db->escape(strtoupper($studiengang));
|
||||
$this->StudienplanModel->db->where("UPPER(so.studiengangkurzbzlang || ':' || tbl_studienplan.orgform_kurzbz) = $escaped");
|
||||
$this->StudienplanModel->addLimit(1);
|
||||
$studiengangResult = $this->StudienplanModel->load();
|
||||
|
||||
if (hasData($studiengangResult))
|
||||
{
|
||||
foreach($personen as $person)
|
||||
{
|
||||
$prestudent = $this->PrestudentModel->getPrestudentByStudiengangAndPerson($studiengang, $person, $studienSemester, $abgeschickt, $abgeschickt === 'all');
|
||||
|
||||
if (!hasData($prestudent))
|
||||
continue;
|
||||
|
||||
$prestudentData = getData($prestudent);
|
||||
$this->saveAbsage($prestudentData[0]->prestudent_id, $statusgrund);
|
||||
}
|
||||
}
|
||||
else
|
||||
$this->terminateWithJsonError("Falschen Studiengang übergeben!");
|
||||
|
||||
}
|
||||
|
||||
$this->outputJsonSuccess("Success");
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ class Rueckstellung extends Auth_Controller
|
||||
private $_ci; // Code igniter instance
|
||||
private $_uid;
|
||||
|
||||
const ZGV_UEBERPRUEFUNG_MAIL_VORLAGE = 'ZGVUEP';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(
|
||||
@@ -23,6 +25,7 @@ class Rueckstellung extends Auth_Controller
|
||||
$this->load->model('crm/RueckstellungStatus_model', 'RueckstellungStatusModel');
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
$this->load->library('PersonLogLib');
|
||||
$this->load->library('MessageLib');
|
||||
|
||||
$this->_setAuthUID(); // sets property uid
|
||||
|
||||
@@ -78,6 +81,8 @@ class Rueckstellung extends Auth_Controller
|
||||
|
||||
$this->_log($person_id, $status_kurzbz);
|
||||
|
||||
if ($status_kurzbz === 'onhold_zgv')
|
||||
$this->sendRueckstellungMessage($person_id);
|
||||
$this->outputJson($result);
|
||||
}
|
||||
|
||||
@@ -104,6 +109,10 @@ class Rueckstellung extends Auth_Controller
|
||||
if (isError($result))
|
||||
$this->terminateWithJsonError(getError($result));
|
||||
$this->_log($person, $status_kurzbz);
|
||||
|
||||
if ($status_kurzbz === 'onhold_zgv')
|
||||
$this->sendRueckstellungMessage($person);
|
||||
|
||||
}
|
||||
$this->outputJsonSuccess("Erfolgreich gespeichert!");
|
||||
}
|
||||
@@ -160,4 +169,26 @@ class Rueckstellung extends Auth_Controller
|
||||
$this->_uid
|
||||
);
|
||||
}
|
||||
|
||||
private function sendRueckstellungMessage($person_id)
|
||||
{
|
||||
$person = $this->_ci->PersonModel->load($person_id);
|
||||
|
||||
if (hasData($person))
|
||||
{
|
||||
$person = getData($person)[0];
|
||||
|
||||
return $this->messagelib->sendMessageUserTemplate(
|
||||
$person_id,
|
||||
self::ZGV_UEBERPRUEFUNG_MAIL_VORLAGE,
|
||||
array(
|
||||
'anrede' => $person->anrede,
|
||||
'nachname' => $person->nachname
|
||||
),
|
||||
null,
|
||||
getAuthPersonId(),
|
||||
'infocenter'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
* @param string $headerImg Filename of the specific Sancho header image.
|
||||
* @param string $cc Sets CC of mail.
|
||||
* @param string $bcc Sets BCC of mail.
|
||||
* @param array $attachments array of arrays with 'filePath' and (optional) 'altName' keys
|
||||
* @return void
|
||||
*/
|
||||
function sendSanchoMail(
|
||||
@@ -45,8 +44,7 @@ function sendSanchoMail(
|
||||
$footerImg = '',
|
||||
$from = null,
|
||||
$cc = null,
|
||||
$bcc = null,
|
||||
$attachments = []
|
||||
$bcc = null
|
||||
)
|
||||
{
|
||||
$ci =& get_instance();
|
||||
@@ -118,18 +116,6 @@ function sendSanchoMail(
|
||||
$ci->email->attach($sanchoFooter_img, 'inline');
|
||||
$cid_header = $ci->email->attachment_cid($sanchoHeader_img); // sets unique content id for embedding
|
||||
$cid_footer = $ci->email->attachment_cid($sanchoFooter_img); // sets unique content id for embedding
|
||||
|
||||
// attach files
|
||||
if (count($attachments)) {
|
||||
foreach ($attachments as $attachment) {
|
||||
if (isset($attachment["altName"])) {
|
||||
$ci->email->attach($attachment["filePath"], 'attachment', $attachment["altName"]);
|
||||
} else {
|
||||
$ci->email->attach($attachment["filePath"], 'attachment');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set specific mail content into specific content template
|
||||
|
||||
@@ -741,7 +741,7 @@ class AnrechnungLib
|
||||
$fullname = hasData($result) ? $result->retval[0]->vorname. $result->retval[0]->nachname : '';
|
||||
|
||||
// Return filename
|
||||
return 'Anrechnungsantrag'. $orgform_kurzbz .'_LV-'. $lehrveranstaltung_id. '_'. $fullname;
|
||||
return 'Anrechnungsantrag'. $orgform_kurzbz .'_LV-'. $lehrveranstaltung_id. '_'. $fullname . '.pdf';
|
||||
}
|
||||
|
||||
public function LVhasLector($anrechnung_id)
|
||||
|
||||
@@ -25,17 +25,4 @@ class CryptLib
|
||||
|
||||
return $cipher->encrypt($value);
|
||||
}
|
||||
|
||||
public static function RIJNDAEL_256_ECB_DECRYPT($value, $key, $paddingDisabled = false)
|
||||
{
|
||||
if (isEmptyString($value) || isEmptyString($key)) return null;
|
||||
|
||||
$cipher = new Rijndael(Rijndael::MODE_ECB);
|
||||
$cipher->setBlockLength(256);
|
||||
$cipher->setKey($key);
|
||||
|
||||
if ($paddingDisabled === true) $cipher->disablePadding();
|
||||
|
||||
return $cipher->decrypt($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2026 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
// require_once('../../include/ical.class.php');
|
||||
|
||||
class FreeBusyLib
|
||||
{
|
||||
private $_ci; // Code igniter instance
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->model("ressource/Zeitsperre_model", "ZeitsperreModel");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
public function getFreeBusy($url)
|
||||
{
|
||||
$fileStream = @fopen($url, "r");
|
||||
if (!$fileStream)
|
||||
return [];
|
||||
|
||||
$busyTimeslots = [];
|
||||
$fileContent = file_get_contents($url);
|
||||
if (mb_strpos($fileContent, "BEGIN:VFREEBUSY") !== false) {
|
||||
$busyTimeslots = $this->parseFreeBusyFormat($fileContent);
|
||||
} else {
|
||||
$busyTimeslots = $this->parseConventionalFormat($fileContent);
|
||||
}
|
||||
|
||||
return $busyTimeslots;
|
||||
}
|
||||
|
||||
public function getDefaultInternalFreeBusy($uid)
|
||||
{
|
||||
$events = [];
|
||||
|
||||
$this->_ci->load->library('StundenplanLib');
|
||||
|
||||
$startDate = new DateTime();
|
||||
$startDate = $startDate->format("Y-m-d");
|
||||
$endDate = new DateTime();
|
||||
$endDate->modify("+1 year");
|
||||
$endDate = $endDate->format("Y-m-d");
|
||||
|
||||
$userEvents = getData($this->_ci->stundenplanlib->getEventsUser($startDate, $endDate, $uid));
|
||||
if ($userEvents && count($userEvents)) {
|
||||
$userEvents = array_map(
|
||||
function ($event) {
|
||||
return [
|
||||
"start" => $event->datum . " " . $event->beginn,
|
||||
"end" => $event->datum . " " . $event->ende,
|
||||
];
|
||||
},
|
||||
$userEvents
|
||||
);
|
||||
$events = array_merge($events, $userEvents);
|
||||
}
|
||||
|
||||
$userAbsences = getData($this->_ci->ZeitsperreModel->getZeitsperre($uid));
|
||||
if ($userAbsences && count($userAbsences)) {
|
||||
$today = new DateTime();
|
||||
$today = $today->format("Y-m-d");
|
||||
$userAbsences = array_filter(
|
||||
$userAbsences,
|
||||
function ($absence) use ($today) {
|
||||
return $absence->bisdatum >= $today;
|
||||
}
|
||||
);
|
||||
$userAbsences = array_map(
|
||||
function ($absence) {
|
||||
return [
|
||||
"start" => $absence->vondatum . " 00:00:00",
|
||||
"end" => $absence->bisdatum . " 23:59:00",
|
||||
];
|
||||
},
|
||||
$userAbsences
|
||||
);
|
||||
$events = array_merge($events, $userAbsences);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
private function parseConventionalFormat($fileContent)
|
||||
{
|
||||
$fileContentRows = explode("\n", $fileContent);
|
||||
$fileContentRows = array_map(function ($row) {
|
||||
return trim($row);
|
||||
}, $fileContentRows);
|
||||
|
||||
$busyTimeslots = [];
|
||||
$isParsingEvent = false;
|
||||
$parsedEvent = ["start" => null, "end" => null];
|
||||
$currentDateTime = new DateTime();
|
||||
$currentDateTime = $currentDateTime->format("Y-m-d H:i:s");
|
||||
|
||||
foreach ($fileContentRows as $row) {
|
||||
if (mb_strpos($row, "BEGIN:VEVENT") !== false) {
|
||||
$isParsingEvent = true;
|
||||
} else if (mb_strpos($row, "END:VEVENT") !== false) {
|
||||
if (
|
||||
$isParsingEvent &&
|
||||
$parsedEvent["start"] &&
|
||||
$parsedEvent["end"] &&
|
||||
$parsedEvent["end"] > $currentDateTime
|
||||
) {
|
||||
$busyTimeslots[] = $parsedEvent;
|
||||
}
|
||||
|
||||
$isParsingEvent = false;
|
||||
$parsedEvent["start"] = null;
|
||||
$parsedEvent["end"] = null;
|
||||
} else if (mb_strpos($row, "DTSTART;VALUE=DATE") !== false) {
|
||||
$startDateString = explode(":", $row)[1];
|
||||
$start = substr($startDateString, 0, 4) . "-" . substr($startDateString, 4, 2) . "-" . substr($startDateString, 6, 2) . " 00:00:00";
|
||||
$parsedEvent["start"] = $start;
|
||||
} else if (mb_strpos($row, "DTSTART") !== false) {
|
||||
$timestamp = explode(":", $row)[1];
|
||||
|
||||
if (mb_substr($timestamp, -1) === "Z") {
|
||||
$timestamp = $this->convertTimestampToLocalTimezone($timestamp);
|
||||
} else if (mb_strpos($row, "TZID=") !== false) {
|
||||
$remainingString = explode("TZID=", $row)[1];
|
||||
$remainingString = explode(":", $remainingString)[0];
|
||||
$timezoneIdentifier = explode(";", $remainingString)[0];
|
||||
$timestamp = $this->convertTimestampToLocalTimezone($timestamp, $timezoneIdentifier);
|
||||
}
|
||||
|
||||
$startDate = substr($timestamp, 0, 4) . "-" . substr($timestamp, 4, 2) . "-" . substr($timestamp, 6, 2);
|
||||
$startTime = substr($timestamp, 9, 2) . ":" . substr($timestamp, 11, 2) . ":" . substr($timestamp, 13, 2);
|
||||
$parsedEvent["start"] = $startDate . " " . $startTime;
|
||||
} else if (mb_strpos($row, "DTEND;VALUE=DATE") !== false) {
|
||||
$endDateString = explode(":", $row)[1];
|
||||
$end = substr($endDateString, 0, 4) . "-" . substr($endDateString, 4, 2) . "-" . substr($endDateString, 6, 2) . " 00:00:00";
|
||||
$parsedEvent["end"] = $end;
|
||||
} else if (mb_strpos($row, "DTEND") !== false) {
|
||||
$timestamp = explode(":", $row)[1];
|
||||
if (mb_substr($timestamp, -1) === "Z") {
|
||||
$timestamp = $this->convertTimestampToLocalTimezone($timestamp);
|
||||
} else if (mb_strpos($row, "TZID=") !== false) {
|
||||
$remainingString = explode("TZID=", $row)[1];
|
||||
$remainingString = explode(":", $remainingString)[0];
|
||||
$timezoneIdentifier = explode(";", $remainingString)[0];
|
||||
$timestamp = $this->convertTimestampToLocalTimezone($timestamp, $timezoneIdentifier);
|
||||
}
|
||||
|
||||
$endDate = substr($timestamp, 0, 4) . "-" . substr($timestamp, 4, 2) . "-" . substr($timestamp, 6, 2);
|
||||
$endTime = substr($timestamp, 9, 2) . ":" . substr($timestamp, 11, 2) . ":" . substr($timestamp, 13, 2);
|
||||
$parsedEvent["end"] = $endDate . " " . $endTime;
|
||||
}
|
||||
}
|
||||
|
||||
return $busyTimeslots;
|
||||
}
|
||||
|
||||
private function parseFreeBusyFormat($fileContent)
|
||||
{
|
||||
$fileContentRows = explode("\n", $fileContent);
|
||||
$fileContentRows = array_map(function ($row) {
|
||||
return trim($row);
|
||||
}, $fileContentRows);
|
||||
|
||||
$busyTimeslots = [];
|
||||
$currentDateTime = new DateTime();
|
||||
$currentDateTime = $currentDateTime->format("Y-m-d H:i:s");
|
||||
|
||||
foreach ($fileContentRows as $row) {
|
||||
if (
|
||||
mb_strpos($row, "VFREEBUSY") !== false ||
|
||||
mb_strpos($row, "FREEBUSY") === false ||
|
||||
mb_strpos($row, "FBTYPE=FREE") !== false
|
||||
)
|
||||
continue;
|
||||
|
||||
$timestamps = explode(":", $row)[1];
|
||||
$timestamps = explode(",", $timestamps);
|
||||
foreach ($timestamps as $timestamp) {
|
||||
$startEndTimestamps = explode("/", $timestamp);
|
||||
|
||||
$startTimestamp = $startEndTimestamps[0];
|
||||
$endTimestamp = $startEndTimestamps[1];
|
||||
|
||||
if (mb_substr($startTimestamp, -1) === "Z") {
|
||||
$startTimestamp = $this->convertTimestampToLocalTimezone($startTimestamp);
|
||||
}
|
||||
if (mb_substr($endTimestamp, -1) === "Z") {
|
||||
$endTimestamp = $this->convertTimestampToLocalTimezone($endTimestamp);
|
||||
}
|
||||
|
||||
$startDate = substr($startTimestamp, 0, 4) . "-" . substr($startTimestamp, 4, 2) . "-" . substr($startTimestamp, 6, 2);
|
||||
$startTime = substr($startTimestamp, 9, 2) . ":" . substr($startTimestamp, 11, 2) . ":" . substr($startTimestamp, 13, 2);
|
||||
$start = $startDate . " " . $startTime;
|
||||
|
||||
$endDate = substr($endTimestamp, 0, 4) . "-" . substr($endTimestamp, 4, 2) . "-" . substr($endTimestamp, 6, 2);
|
||||
$endTime = substr($endTimestamp, 9, 2) . ":" . substr($endTimestamp, 11, 2) . ":" . substr($endTimestamp, 13, 2);
|
||||
$end = $endDate . " " . $endTime;
|
||||
|
||||
if ($end < $currentDateTime)
|
||||
continue;
|
||||
|
||||
$busyTimeslots[] = ["start" => $start, "end" => $end];
|
||||
}
|
||||
}
|
||||
|
||||
return $busyTimeslots;
|
||||
}
|
||||
|
||||
private function convertTimestampToLocalTimezone($timestamp, $originalTimezoneIdentifier = "UTC")
|
||||
{
|
||||
$originalTimezone = new DateTimeZone($originalTimezoneIdentifier);
|
||||
$localTimezone = new DateTimeZone("Europe/Vienna");
|
||||
|
||||
$date = new DateTime($timestamp, $originalTimezone);
|
||||
$date->setTimezone($localTimezone);
|
||||
return $date->format("Ymd\THis");
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,6 @@ class StundenplanLib
|
||||
return $stundenplan_data;
|
||||
$stundenplan_data = getData($stundenplan_data) ?? [];
|
||||
|
||||
$this->_ci->addMeta("stundenplanData", $stundenplan_data);
|
||||
$function_error = $this->expandObjectInformation($stundenplan_data);
|
||||
if ($function_error)
|
||||
return $function_error;
|
||||
@@ -392,39 +391,6 @@ class StundenplanLib
|
||||
$item->gruppe = $gruppe_obj_array;
|
||||
$item->lektor = $lektor_obj_array;
|
||||
|
||||
$this->_ci->load->library('PermissionLib');
|
||||
$berechtigt_begrenzt = $this->_ci->permissionlib->isBerechtigt('lehre/reservierung:begrenzt', 'sui');
|
||||
|
||||
$now = time();
|
||||
$res_lektor_start = $this->jump_day($now, RES_TAGE_LEKTOR_MIN - 1);
|
||||
$res_lektor_ende = mktime(0, 0, 0, date('m', $now), date('d', $now) + RES_TAGE_LEKTOR_BIS, date('Y', $now));
|
||||
|
||||
$start_date = is_numeric($item->beginn) ? $item->beginn : strtotime($item->beginn);
|
||||
if (!date('w', $start_date)) {
|
||||
$start_date = $this->jump_day($start_date, 1);
|
||||
}
|
||||
|
||||
$start_date_str = date('Y-m-d', $start_date);
|
||||
$res_lektor_start_str = date('Y-m-d', $res_lektor_start);
|
||||
$res_lektor_ende_str = date('Y-m-d', $res_lektor_ende);
|
||||
|
||||
$show_delete = (
|
||||
(
|
||||
$berechtigt_begrenzt &&
|
||||
(
|
||||
(isset($item->insertvon) && $item->insertvon == getAuthUID()) ||
|
||||
(isset($item->uids) && in_array(getAuthUID(), $item->uids))
|
||||
)
|
||||
) &&
|
||||
$start_date_str >= $res_lektor_start_str &&
|
||||
$start_date_str <= $res_lektor_ende_str
|
||||
);
|
||||
|
||||
if ($show_delete)
|
||||
$item->deletable = true;
|
||||
else
|
||||
$item->deletable = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,212 +486,6 @@ class StundenplanLib
|
||||
return success($stundenplan_data);
|
||||
}
|
||||
|
||||
public function addReservation($start, $end, $title, $beschreibung, $ort_kurzbz, $lektoren = null, $studiengang = null, $semester = null, $verband = null, $gruppe = null, $spezialgruppe = null)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
$this->_ci->load->model('ressource/Stunde_model', 'StundeModel');
|
||||
$this->_ci->load->model('ressource/Reservierung_model', 'ReservierungModel');
|
||||
$this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel');
|
||||
$this->_ci->load->model('ressource/stundenplan_model', 'StundenplanModel');
|
||||
$this->_ci->load->library('PermissionLib');
|
||||
|
||||
$startTime = new DateTime($start);
|
||||
$endTime = new DateTime($end);
|
||||
|
||||
$stunden = $this->_ci->StundeModel->loadWhere(array(
|
||||
'beginn <' => $endTime->format('H:i:s'),
|
||||
'ende >' => $startTime->format('H:i:s')
|
||||
));
|
||||
|
||||
if (!hasData($stunden))
|
||||
{
|
||||
return error("Keine Stunden vorhanden");
|
||||
}
|
||||
|
||||
$stunden = array_column(getData($stunden), 'stunde');
|
||||
|
||||
$this->_ci->StundenplandevModel->db->select('1');
|
||||
$this->_ci->StundenplandevModel->db->where('datum', $startTime->format('Y-m-d'));
|
||||
$this->_ci->StundenplandevModel->db->where('ort_kurzbz', $ort_kurzbz);
|
||||
$this->_ci->StundenplandevModel->db->where_in('stunde', $stunden);
|
||||
$stundenplandev_belegung = $this->_ci->StundenplandevModel->load();
|
||||
|
||||
$this->_ci->StundenplanModel->db->select('1');
|
||||
$this->_ci->StundenplanModel->db->where('ort_kurzbz', $ort_kurzbz);
|
||||
$this->_ci->StundenplanModel->db->where('datum', $startTime->format('Y-m-d'));
|
||||
$this->_ci->StundenplanModel->db->where_in('stunde', $stunden);
|
||||
$stundenplan_belegung = $this->_ci->StundenplanModel->load();
|
||||
|
||||
if ((hasData($stundenplandev_belegung) || hasData($stundenplan_belegung))
|
||||
&& !$this->_ci->permissionlib->isBerechtigt('lehre/reservierungAdvanced'))
|
||||
return error ('lvplan/bereitsReserviert');
|
||||
|
||||
$this->_ci->ReservierungModel->addSelect('stunde');
|
||||
$reservation_hours = $this->_ci->ReservierungModel->loadWhere(array('datum' => $startTime->format('Y-m-d'), 'ort_kurzbz' => $ort_kurzbz));
|
||||
|
||||
|
||||
if (isError($reservation_hours))
|
||||
return $reservation_hours;
|
||||
|
||||
$reservation_hours = hasData($reservation_hours) ? array_column(getData($reservation_hours), 'stunde') : array();
|
||||
|
||||
if (!empty(array_intersect($stunden, $reservation_hours))
|
||||
&& !$this->_ci->permissionlib->isBerechtigt('lehre/reservierungAdvanced'))
|
||||
return error("lvplan/bereitsReserviert");
|
||||
|
||||
|
||||
if (!empty($lektoren))
|
||||
{
|
||||
foreach ($lektoren as $lektor)
|
||||
{
|
||||
$insert = array('ort_kurzbz' => $ort_kurzbz,
|
||||
'datum' => $startTime->format('Y-m-d'),
|
||||
'titel' => $title,
|
||||
'studiengang_kz' => is_null($studiengang) ? 0 : $studiengang,
|
||||
'beschreibung' => $beschreibung,
|
||||
'insertvon' => getAuthUID(),
|
||||
'uid' => $lektor,
|
||||
'semester' => is_null($semester) ? null : $semester,
|
||||
'verband' => is_null($verband) ? null : $verband,
|
||||
'gruppe' => is_null($gruppe) ? null : $gruppe,
|
||||
'gruppe_kurzbz' => is_null($spezialgruppe) ? null : $spezialgruppe,
|
||||
);
|
||||
|
||||
foreach ($stunden as $stunde)
|
||||
{
|
||||
$insert['stunde'] = $stunde;
|
||||
$check_insert = $this->_ci->ReservierungModel->insert($insert);
|
||||
if (isError($check_insert))
|
||||
return $check_insert;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($stunden as $stunde)
|
||||
{
|
||||
$check_insert = $this->_ci->ReservierungModel->insert(array(
|
||||
'ort_kurzbz' => $ort_kurzbz,
|
||||
'uid' => getAuthUID(),
|
||||
'stunde' => $stunde,
|
||||
'datum' => $startTime->format('Y-m-d'),
|
||||
'titel' => $title,
|
||||
'studiengang_kz' => is_null($studiengang) ? 0 : $studiengang,
|
||||
'beschreibung' => $beschreibung,
|
||||
'insertvon' => getAuthUID()
|
||||
));
|
||||
if (isError($check_insert))
|
||||
return $check_insert;
|
||||
}
|
||||
}
|
||||
|
||||
return success("Erfolgreich");
|
||||
}
|
||||
|
||||
public function deleteReservation($reservierung_id)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
$this->_ci->load->model('ressource/Reservierung_model', 'ReservierungModel');
|
||||
$this->_ci->load->model('ressource/Stunde_model', 'StundeModel');
|
||||
$this->_ci->load->library('PermissionLib');
|
||||
|
||||
|
||||
$this->_ci->ReservierungModel->db->where_in('reservierung_id', $reservierung_id);
|
||||
$reservation = $this->_ci->ReservierungModel->load();
|
||||
if (isError($reservation))
|
||||
return $reservation;
|
||||
|
||||
if (!hasData($reservation))
|
||||
return error("Reservierungen nicht gefunden");
|
||||
|
||||
$reservations = getData($reservation);
|
||||
|
||||
$today = new DateTime();
|
||||
foreach ($reservations as $reservierung)
|
||||
{
|
||||
if ($today->format('Y-m-d') > $reservierung->datum)
|
||||
return error("Vergangene Reservierungen können nicht gelöscht werden");
|
||||
|
||||
if (($this->_ci->permissionlib->isBerechtigt('lehre/reservierung:begrenzt')) && ($reservierung->insertvon == getAuthUID() || $reservierung->uid === getAuthUID()))
|
||||
{
|
||||
$delete_result = $this->_ci->ReservierungModel->delete($reservierung->reservierung_id);
|
||||
|
||||
if (isError($delete_result))
|
||||
return $delete_result;
|
||||
}
|
||||
}
|
||||
return success("Erfolgreich");
|
||||
}
|
||||
|
||||
|
||||
public function getReservableMap($ort_kurzbz, $start_date, $end_date)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
|
||||
$this->_ci->load->library('PermissionLib');
|
||||
|
||||
$berechtigt_begrenzt = $this->_ci->permissionlib->isBerechtigt('lehre/reservierung:begrenzt', 'suid');
|
||||
$berechtigt_erweitert = $this->_ci->permissionlib->isBerechtigt('lehre/reservierung', 'suid');
|
||||
|
||||
$ort_data = $this->_ci->OrtModel->load($ort_kurzbz);
|
||||
if (isError($ort_data) || !hasData($ort_data))
|
||||
return [];
|
||||
|
||||
$ort_data = getData($ort_data)[0];
|
||||
|
||||
if (!$ort_data->reservieren)
|
||||
return [];
|
||||
|
||||
if (!$berechtigt_begrenzt && !$berechtigt_erweitert)
|
||||
return [];
|
||||
|
||||
$start_ts = is_numeric($start_date) ? (int)$start_date : strtotime($start_date);
|
||||
$end_ts = is_numeric($end_date) ? (int)$end_date : strtotime($end_date);
|
||||
|
||||
if (!$start_ts || !$end_ts)
|
||||
return [];
|
||||
|
||||
if ($end_ts < $start_ts)
|
||||
{
|
||||
$tmp = $start_ts;
|
||||
$start_ts = $end_ts;
|
||||
$end_ts = $tmp;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$tage_min = defined('RES_TAGE_LEKTOR_MIN') ? (int)RES_TAGE_LEKTOR_MIN : 0;
|
||||
$tage_bis = defined('RES_TAGE_LEKTOR_BIS') ? (int)RES_TAGE_LEKTOR_BIS : 0;
|
||||
|
||||
$datum_res_lektor_start = $this->jump_day($now, $tage_min - 1);
|
||||
$datum_res_lektor_ende = $this->jump_day($now, $tage_bis);
|
||||
|
||||
$start_ymd_allowed = date('Y-m-d', $datum_res_lektor_start);
|
||||
$end_ymd_allowed = date('Y-m-d', $datum_res_lektor_ende);
|
||||
|
||||
$result = [];
|
||||
|
||||
$current = strtotime(date('Y-m-d', $start_ts) . ' 00:00:00');
|
||||
$end_day = strtotime(date('Y-m-d', $end_ts) . ' 00:00:00');
|
||||
|
||||
while ($current <= $end_day)
|
||||
{
|
||||
$ymd = date('Y-m-d', $current);
|
||||
|
||||
$result[$ymd] = ($ymd >= $start_ymd_allowed && $ymd <= $end_ymd_allowed) ? true : false;
|
||||
|
||||
$current = $this->jump_day($current, 1);
|
||||
}
|
||||
|
||||
return success($result);
|
||||
}
|
||||
|
||||
private function jump_day($timestamp, $days)
|
||||
{
|
||||
$days = (int)$days;
|
||||
$prefix = ($days >= 0 ? '+' : '');
|
||||
return strtotime($prefix . $days . ' days', $timestamp);
|
||||
}
|
||||
|
||||
// start of the private functions ########################################################################################################
|
||||
|
||||
// function used to sort an array of studiensemester strings
|
||||
|
||||
@@ -31,18 +31,20 @@ class Vertrag_model extends DB_Model
|
||||
*/
|
||||
public function save($person_id, $mitarbeiter_uid, $lehrveranstaltung_id, $lehreinheit_id, $projektarbeit_id = null, $vertragsstunden, $betrag, $studiensemester_kurzbz)
|
||||
{
|
||||
$person_id = (isset($person_id) && is_numeric($person_id))
|
||||
$vertragstyp_kurzbz = (is_null($projektarbeit_id)) ? 'Lehrauftrag' : 'Betreuung';
|
||||
|
||||
$person_id = (isset($person_id) && is_numeric($person_id))
|
||||
? $person_id
|
||||
: show_error('peron_id must be set and numeric.');
|
||||
$lehreinheit_id = (isset($lehreinheit_id) && is_numeric($lehreinheit_id))
|
||||
? $lehreinheit_id
|
||||
: show_error('lehreinheit_id must be set and numeric.');
|
||||
$lehrveranstaltung_id = (isset($lehrveranstaltung_id) && is_numeric($lehrveranstaltung_id))
|
||||
? $lehrveranstaltung_id
|
||||
: show_error('lehrveranstaltung_id must be set and numeric.');
|
||||
$projektarbeit_id = (isset($projektarbeit_id) && is_numeric($projektarbeit_id))
|
||||
? $projektarbeit_id
|
||||
: null;
|
||||
$lehreinheit_id = (isset($lehreinheit_id) && is_numeric($lehreinheit_id))
|
||||
? $lehreinheit_id
|
||||
: (($vertragstyp_kurzbz == 'Betreuung') ? null : show_error('lehreinheit_id must be set and numeric.'));
|
||||
$vertragsstunden = (isset($vertragsstunden) && is_numeric($vertragsstunden))
|
||||
? $vertragsstunden
|
||||
: 0;
|
||||
@@ -53,7 +55,7 @@ class Vertrag_model extends DB_Model
|
||||
? $mitarbeiter_uid
|
||||
: show_error('mitarbeiter_uid must be set and a string value.');;
|
||||
|
||||
$vertragstyp_kurzbz = (is_null($projektarbeit_id)) ? 'Lehrauftrag' : 'Betreuung';
|
||||
|
||||
|
||||
// First check if Vertrag already exists for that Lehrauftrag or for that Projektbetreuerauftrag
|
||||
if ($vertragstyp_kurzbz == 'Lehrauftrag')
|
||||
@@ -257,7 +259,7 @@ class Vertrag_model extends DB_Model
|
||||
}
|
||||
elseif ($vertragstyp_kurzbz == 'Betreuung')
|
||||
{
|
||||
$this->addSelect('lehreinheit_id');
|
||||
$this->addSelect('lehreinheit_id, lehre.tbl_projektarbeit.lehrveranstaltung_id, lehre.tbl_projektarbeit.studiensemester_kurzbz');
|
||||
$this->addJoin('lehre.tbl_projektbetreuer', 'vertrag_id');
|
||||
$this->addJoin('lehre.tbl_projektarbeit', 'projektarbeit_id');
|
||||
if ($result = $this->loadWhere(array('vertrag_id' => $vertrag_id)))
|
||||
@@ -281,17 +283,22 @@ class Vertrag_model extends DB_Model
|
||||
{
|
||||
if ($result = getData($this->getLehreinheitID($vertrag_id)))
|
||||
{
|
||||
$this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
|
||||
$this->LehreinheitModel->addSelect($select);
|
||||
if (!empty($result[0]->lehreinheit_id))
|
||||
{
|
||||
$this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
|
||||
$this->LehreinheitModel->addSelect($select);
|
||||
|
||||
if($result = $this->LehreinheitModel->load($result[0]->lehreinheit_id))
|
||||
{
|
||||
return success($result->retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
return error('Fehler beim Laden der Lehreinheit');
|
||||
if ($result = $this->LehreinheitModel->load($result[0]->lehreinheit_id))
|
||||
{
|
||||
return success($result->retval);
|
||||
}
|
||||
else
|
||||
{
|
||||
return error('Fehler beim Laden der Lehreinheit');
|
||||
}
|
||||
}
|
||||
|
||||
return success($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -563,14 +570,13 @@ SELECT
|
||||
null::integer as pruefung_id,
|
||||
projektarbeit_id,
|
||||
(tbl_projektbetreuer.stunden*tbl_projektbetreuer.stundensatz) as betrag1,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
tbl_projektarbeit.studiensemester_kurzbz,
|
||||
tbl_projektbetreuer.betreuerart_kurzbz,
|
||||
(SELECT nachname || ' ' || vorname FROM public.tbl_person JOIN public.tbl_benutzer USING(person_id) WHERE uid=tbl_projektarbeit.student_uid)
|
||||
as bezeichnung
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
tbl_projektbetreuer.person_id=?
|
||||
AND vertrag_id IS NULL
|
||||
@@ -619,14 +625,13 @@ SELECT
|
||||
null::integer as pruefung_id,
|
||||
projektarbeit_id,
|
||||
(tbl_projektbetreuer.stunden * tbl_projektbetreuer.stundensatz) as betrag,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
tbl_projektarbeit.studiensemester_kurzbz,
|
||||
tbl_projektbetreuer.betreuerart_kurzbz,
|
||||
(SELECT nachname || ' ' || vorname FROM public.tbl_person JOIN public.tbl_benutzer USING(person_id) WHERE uid=tbl_projektarbeit.student_uid)
|
||||
as bezeichnung, vertrag_id
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
tbl_projektbetreuer.person_id=?
|
||||
AND vertrag_id = ?
|
||||
|
||||
@@ -177,7 +177,7 @@ class Prestudentstatus_model extends DB_Model
|
||||
* @param prestudent_id ID of the Prestudent.
|
||||
* @param $status_kurzbz kurzbz of the status.
|
||||
* @param $ausbildungssemester ausbildungssemester of the status.
|
||||
* @param $studiensemester_kurzbz studiensemster of the status.
|
||||
* @param $studiensemester_kurzbz studiensemester of the status.
|
||||
*
|
||||
* @return result object with all the status entries
|
||||
*/
|
||||
|
||||
@@ -85,9 +85,18 @@ class Lehreinheitmitarbeiter_model extends DB_Model
|
||||
|
||||
public function getLektorenByLe($lehreinheit_id)
|
||||
{
|
||||
$this->addSelect('vorname, nachname, tbl_lehreinheitmitarbeiter.*, stundenplan.verplant');
|
||||
$this->addSelect('tbl_person.vorname, tbl_person.nachname, tbl_lehreinheitmitarbeiter.*, stundenplan.verplant,
|
||||
COALESCE(insertvonperson.vorname || \' \' || insertvonperson.nachname, tbl_lehreinheitmitarbeiter.insertvon) as insertvon,
|
||||
COALESCE(updatevonperson.vorname || \' \' || updatevonperson.nachname, tbl_lehreinheitmitarbeiter.updatevon) as updatevon');
|
||||
$this->addJoin('tbl_benutzer', 'uid = mitarbeiter_uid');
|
||||
$this->addJoin('tbl_person', 'person_id');
|
||||
$this->addJoin('tbl_benutzer insertvonbenutzer', 'insertvonbenutzer.uid = tbl_lehreinheitmitarbeiter.insertvon', 'LEFT');
|
||||
$this->addJoin('tbl_person insertvonperson', 'insertvonperson.person_id = insertvonbenutzer.person_id', 'LEFT');
|
||||
|
||||
$this->addJoin('tbl_benutzer updatevonbenutzer', 'updatevonbenutzer.uid = tbl_lehreinheitmitarbeiter.updatevon', 'LEFT');
|
||||
$this->addJoin('tbl_person updatevonperson', 'updatevonperson.person_id = updatevonbenutzer.person_id', 'LEFT');
|
||||
|
||||
|
||||
|
||||
$this->addJoin('(
|
||||
SELECT 1 as verplant, lehreinheit_id, mitarbeiter_uid
|
||||
|
||||
@@ -1263,6 +1263,39 @@ class Lehrveranstaltung_model extends DB_Model
|
||||
";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets lehrveranstaltungen of Studienplan of a certain lva_id set
|
||||
* used if a bigger set of lva id is already available and it needs to be checked against a certain studienplan aswell
|
||||
* @param $studienplan_id ID des Studienplans
|
||||
* @param $lva_ids LVA_ID welche abgegleicht werden sollen
|
||||
* @return array|null
|
||||
*/
|
||||
public function getLvsByStudienplanByLvaIDs($studienplan_id, $lva_ids)
|
||||
{
|
||||
$params = array($studienplan_id, $lva_ids);
|
||||
|
||||
$qry = "SELECT tbl_lehrveranstaltung.*,
|
||||
tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id,
|
||||
tbl_studienplan_lehrveranstaltung.semester as stpllv_semester,
|
||||
tbl_studienplan_lehrveranstaltung.pflicht as stpllv_pflicht,
|
||||
tbl_studienplan_lehrveranstaltung.koordinator as stpllv_koordinator,
|
||||
tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id_parent,
|
||||
tbl_studienplan_lehrveranstaltung.sort stpllv_sort,
|
||||
tbl_studienplan_lehrveranstaltung.curriculum,
|
||||
tbl_studienplan_lehrveranstaltung.export,
|
||||
tbl_studienplan_lehrveranstaltung.genehmigung
|
||||
FROM lehre.tbl_lehrveranstaltung
|
||||
JOIN lehre.tbl_studienplan_lehrveranstaltung
|
||||
USING(lehrveranstaltung_id)
|
||||
WHERE tbl_studienplan_lehrveranstaltung.studienplan_id = ?
|
||||
AND tbl_studienplan_lehrveranstaltung.lehrveranstaltung_id IN ?
|
||||
";
|
||||
|
||||
$qry .= " ORDER BY stpllv_sort, semester, sort";
|
||||
|
||||
return $this->execQuery($qry, $params);
|
||||
}
|
||||
|
||||
public function getAllOe($lv_id)
|
||||
{
|
||||
$qry = "SELECT DISTINCT oe_kurzbz
|
||||
|
||||
@@ -50,8 +50,7 @@ class Paabgabe_model extends DB_Model
|
||||
JOIN lehre.tbl_projektbetreuer USING(projektarbeit_id)
|
||||
JOIN public.tbl_benutzer bn_student ON(tbl_projektarbeit.student_uid=bn_student.uid)
|
||||
JOIN public.tbl_person person_student ON(bn_student.person_id=person_student.person_id)
|
||||
JOIN lehre.tbl_lehreinheit ON(tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung ON(tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
JOIN public.tbl_studiengang ON(tbl_lehrveranstaltung.studiengang_kz=tbl_studiengang.studiengang_kz)
|
||||
JOIN campus.tbl_paabgabetyp USING(paabgabetyp_kurzbz)
|
||||
WHERE
|
||||
@@ -68,14 +67,13 @@ class Paabgabe_model extends DB_Model
|
||||
campus.tbl_paabgabe.insertvon, campus.tbl_paabgabe.insertamum, campus.tbl_paabgabe.updatevon, campus.tbl_paabgabe.updateamum,
|
||||
campus.tbl_paabgabe.note, upload_allowed, beurteilungsnotiz, student_uid, tbl_projektarbeit.note, lehre.tbl_projektarbeit.titel,
|
||||
UPPER(tbl_studiengang.typ) as stgtyp, UPPER(tbl_studiengang.kurzbz) as stgkz, public.tbl_studiengang.studiengang_kz,
|
||||
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_lehreinheit.studiensemester_kurzbz,
|
||||
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_projektarbeit.studiensemester_kurzbz,
|
||||
public.tbl_person.anrede, public.tbl_person.titelpre, public.tbl_person.vorname, public.tbl_person.nachname, public.tbl_person.titelpost
|
||||
FROM campus.tbl_paabgabe
|
||||
JOIN campus.tbl_paabgabetyp USING (paabgabetyp_kurzbz)
|
||||
JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit using(lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
|
||||
JOIN public.tbl_studiengang on(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
|
||||
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
JOIN public.tbl_studiengang ON(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
|
||||
JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
|
||||
JOIN public.tbl_person USING (person_id)
|
||||
|
||||
@@ -93,7 +91,7 @@ class Paabgabe_model extends DB_Model
|
||||
campus.tbl_paabgabe.insertvon, campus.tbl_paabgabe.insertamum, campus.tbl_paabgabe.updatevon, campus.tbl_paabgabe.updateamum,
|
||||
campus.tbl_paabgabe.note, upload_allowed, beurteilungsnotiz, student_uid, tbl_projektarbeit.note, lehre.tbl_projektarbeit.titel,
|
||||
UPPER(tbl_studiengang.typ) as stgtyp, UPPER(tbl_studiengang.kurzbz) as stgkz, public.tbl_studiengang.studiengang_kz,
|
||||
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_lehreinheit.studiensemester_kurzbz,
|
||||
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_projektarbeit.studiensemester_kurzbz,
|
||||
lehre.tbl_projektbetreuer.betreuerart_kurzbz, lehre.tbl_projektbetreuer.person_id,
|
||||
public.tbl_person.anrede, public.tbl_person.titelpre, public.tbl_person.vorname, public.tbl_person.nachname, public.tbl_person.titelpost
|
||||
|
||||
@@ -101,8 +99,7 @@ class Paabgabe_model extends DB_Model
|
||||
JOIN campus.tbl_paabgabetyp USING (paabgabetyp_kurzbz)
|
||||
JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_projektbetreuer USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit using(lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
JOIN public.tbl_studiengang on(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
|
||||
JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
|
||||
JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
|
||||
|
||||
@@ -25,7 +25,7 @@ class Projektarbeit_model extends DB_Model
|
||||
{
|
||||
$qry = "SELECT
|
||||
pa.*, tbl_projekttyp.bezeichnung,
|
||||
tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.lehrveranstaltung_id,
|
||||
pa.studiensemester_kurzbz, pa.lehrveranstaltung_id,
|
||||
tbl_firma.name AS firma_name,
|
||||
(
|
||||
SELECT
|
||||
@@ -41,7 +41,6 @@ class Projektarbeit_model extends DB_Model
|
||||
FROM
|
||||
lehre.tbl_projektarbeit pa
|
||||
JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_firma USING (firma_id)
|
||||
WHERE
|
||||
@@ -57,7 +56,7 @@ class Projektarbeit_model extends DB_Model
|
||||
|
||||
if (isset($studiensemester_kurzbz))
|
||||
{
|
||||
$qry .= ' AND tbl_lehreinheit.studiensemester_kurzbz=?';
|
||||
$qry .= ' AND tbl_projektarbeit.studiensemester_kurzbz=?';
|
||||
$params[] = $studiensemester_kurzbz;
|
||||
}
|
||||
|
||||
@@ -134,7 +133,7 @@ class Projektarbeit_model extends DB_Model
|
||||
projektarbeit_id,
|
||||
lehre.tbl_projekttyp.bezeichnung as projekttypbezeichnung,
|
||||
lehre.tbl_projekttyp.projekttyp_kurzbz as projekttypkurzbz,
|
||||
lehre.tbl_lehreinheit.studiensemester_kurzbz,
|
||||
lehre.tbl_projektarbeit.studiensemester_kurzbz,
|
||||
lehre.tbl_lehrveranstaltung.studiengang_kz,
|
||||
public.tbl_studiengang.kurzbzlang,
|
||||
lehre.tbl_projektarbeit.note as note,
|
||||
@@ -157,7 +156,6 @@ class Projektarbeit_model extends DB_Model
|
||||
LEFT JOIN public.tbl_benutzer USING(person_id)
|
||||
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
LEFT JOIN lehre.tbl_betreuerart USING(betreuerart_kurzbz)
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON(public.tbl_mitarbeiter.mitarbeiter_uid = public.tbl_benutzer.uid)
|
||||
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
|
||||
@@ -366,7 +364,7 @@ class Projektarbeit_model extends DB_Model
|
||||
tbl_studiengang.typ, tbl_studiengang.kurzbz,
|
||||
tbl_projektarbeit.projekttyp_kurzbz, tbl_projekttyp.bezeichnung,
|
||||
tbl_projektarbeit.titel, tbl_projektarbeit.projektarbeit_id, tbl_projektarbeit.note,
|
||||
student_benutzer.uid, tbl_student.matrikelnr, tbl_lehreinheit.studiensemester_kurzbz, public.tbl_student.student_uid,
|
||||
student_benutzer.uid, tbl_student.matrikelnr, tbl_projektarbeit.studiensemester_kurzbz, public.tbl_student.student_uid,
|
||||
|
||||
lehre.tbl_projektarbeit.sprache,
|
||||
lehre.tbl_projektarbeit.seitenanzahl,
|
||||
@@ -430,7 +428,6 @@ class Projektarbeit_model extends DB_Model
|
||||
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
|
||||
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
|
||||
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
|
||||
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
@@ -503,7 +500,7 @@ class Projektarbeit_model extends DB_Model
|
||||
student_person.vorname AS student_vorname,
|
||||
student_person.nachname AS student_nachname,
|
||||
public.tbl_student.matrikelnr,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
tbl_projektarbeit.studiensemester_kurzbz,
|
||||
betreuer_benutzer.uid AS betreuer_benutzer_uid,
|
||||
betreuer_person.titelpre AS betreuer_titelpre,
|
||||
betreuer_person.vorname AS betreuer_vorname,
|
||||
@@ -565,7 +562,6 @@ class Projektarbeit_model extends DB_Model
|
||||
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
|
||||
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
|
||||
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
|
||||
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
@@ -633,7 +629,7 @@ class Projektarbeit_model extends DB_Model
|
||||
student_person.vorname AS student_vorname,
|
||||
student_person.nachname AS student_nachname,
|
||||
public.tbl_student.matrikelnr,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
tbl_projektarbeit.studiensemester_kurzbz,
|
||||
betreuer_benutzer.uid AS betreuer_benutzer_uid,
|
||||
betreuer_person.titelpre AS betreuer_titelpre,
|
||||
betreuer_person.vorname AS betreuer_vorname,
|
||||
@@ -695,7 +691,6 @@ class Projektarbeit_model extends DB_Model
|
||||
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
|
||||
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
|
||||
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
|
||||
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
|
||||
@@ -218,7 +218,7 @@ class Studiensemester_model extends DB_Model
|
||||
*/
|
||||
public function getByDate($date)
|
||||
{
|
||||
// gets the studiensemster of a date or the next closest previous studiensemester if a date is not within a studiensemester
|
||||
// gets the studiensemester of a date or the next closest previous studiensemester if a date is not within a studiensemester
|
||||
$query = "
|
||||
SELECT studiensemester_kurzbz, start, ende
|
||||
FROM public.tbl_studiensemester
|
||||
|
||||
@@ -11,14 +11,4 @@ class Freebusytyp_model extends DB_Model
|
||||
$this->dbTable = 'campus.tbl_freebusytyp';
|
||||
$this->pk = 'freebusytyp_kurzbz';
|
||||
}
|
||||
|
||||
public function getAllFreeBusyTypes()
|
||||
{
|
||||
return $this->execReadOnlyQuery("SELECT * FROM " . $this->dbTable);
|
||||
}
|
||||
|
||||
public function getActiveFreeBusyTypes()
|
||||
{
|
||||
return $this->execReadOnlyQuery("SELECT * FROM " . $this->dbTable . " WHERE is_active");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ class Notiz_model extends DB_Model
|
||||
/**
|
||||
* Add a Notiz for a given person
|
||||
*/
|
||||
public function addNotizForPerson($person_id, $titel, $text, $erledigt, $verfasser_uid)
|
||||
public function addNotizForPerson($person_id, $titel, $text, $erledigt, $verfasser_uid, $insertvon = null)
|
||||
{
|
||||
// Loads model Notizzuordnung_model
|
||||
$this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel');
|
||||
@@ -106,8 +106,15 @@ class Notiz_model extends DB_Model
|
||||
// Start DB transaction
|
||||
$this->db->trans_start(false);
|
||||
|
||||
$result = $this->insert(array('titel' => $titel, 'text' => $text, 'erledigt' => $erledigt, 'verfasser_uid' => $verfasser_uid,
|
||||
"insertvon" => $verfasser_uid));
|
||||
$result = $this->insert(
|
||||
array(
|
||||
'titel' => $titel,
|
||||
'text' => $text,
|
||||
'erledigt' => $erledigt,
|
||||
'verfasser_uid' => $verfasser_uid,
|
||||
'insertvon' => $insertvon ?? $verfasser_uid
|
||||
)
|
||||
);
|
||||
|
||||
if (isSuccess($result))
|
||||
{
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
<?php
|
||||
class CoodleSurveyExternalParticipant_model extends DB_Model
|
||||
{
|
||||
|
||||
private $_ci; // Code igniter instance
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'campus.tbl_coodle_survey_external_participants';
|
||||
$this->pk = 'id';
|
||||
|
||||
$this->_ci =& get_instance();
|
||||
}
|
||||
|
||||
public function getExternalParticipants($surveyId, $includeAccessKeys = false)
|
||||
{
|
||||
$selectedColumns = $includeAccessKeys ? "*" : "id, survey_id, name, email, selection";
|
||||
$query = "SELECT $selectedColumns
|
||||
FROM $this->dbTable
|
||||
WHERE survey_id = $surveyId
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getExternalParticipant($externalParticipantId, $includeAccessKey = false)
|
||||
{
|
||||
$selectedColumns = $includeAccessKey ? "*" : "id, survey_id, name, email, selection";
|
||||
$query = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE id = $externalParticipantId
|
||||
LIMIT 1
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getExternalParticipantByAccessKey($surveyId, $accessKey)
|
||||
{
|
||||
$query = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE survey_id = $surveyId AND access_key = '$accessKey'
|
||||
LIMIT 1
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function updateExternalParticipants($surveyId, $externalParticipants, $timeslots)
|
||||
{
|
||||
$participantsQuery = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE survey_id = $surveyId
|
||||
";
|
||||
$oldExternalParticipants = getData($this->execQuery($participantsQuery));
|
||||
$oldExternalParticipantIds = array_map(
|
||||
function ($oldExternalParticipant) {
|
||||
return $oldExternalParticipant->id;
|
||||
},
|
||||
$oldExternalParticipants
|
||||
);
|
||||
|
||||
$persistingExternalParticipants = array_filter(
|
||||
$externalParticipants,
|
||||
function ($externalParticipant) {
|
||||
return isset($externalParticipant["id"]) && $externalParticipant["id"];
|
||||
}
|
||||
);
|
||||
$persistingExternalParticipantIds = array_map(
|
||||
function ($persistingExternalParticipant) {
|
||||
return $persistingExternalParticipant["id"];
|
||||
},
|
||||
$persistingExternalParticipants
|
||||
);
|
||||
|
||||
$redundantExternalParticipantIds = array_diff(
|
||||
$oldExternalParticipantIds,
|
||||
$persistingExternalParticipantIds
|
||||
);
|
||||
|
||||
$newExternalParticipants = array_filter(
|
||||
$externalParticipants,
|
||||
function ($externalParticipant) {
|
||||
return !isset($externalParticipant["id"]) || !$externalParticipant["id"];
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
if (count($redundantExternalParticipantIds)) {
|
||||
$idsToBeDeleted = "(" . implode(", ", $redundantExternalParticipantIds) . ")";
|
||||
$deleteQuery = "DELETE FROM $this->dbTable WHERE id IN $idsToBeDeleted";
|
||||
$this->execQuery($deleteQuery);
|
||||
}
|
||||
|
||||
if (count($newExternalParticipants)) {
|
||||
$insertValues = array_map(
|
||||
function ($newExternalParticipant) use ($surveyId) {
|
||||
$name = $newExternalParticipant["name"];
|
||||
$email = $newExternalParticipant["email"];
|
||||
$accessKey = uniqid();
|
||||
return "($surveyId, '$name', '$email', '$accessKey', NULL)";
|
||||
},
|
||||
$newExternalParticipants
|
||||
);
|
||||
$insertValues = implode(", ", $insertValues);
|
||||
$insertQuery = "INSERT INTO $this->dbTable (survey_id, name, email, access_key, selection) VALUES $insertValues";
|
||||
$this->execQuery($insertQuery);
|
||||
}
|
||||
|
||||
$updatedExternalParticipants = getData($this->execQuery($participantsQuery));
|
||||
$timeslotIds = array_map(
|
||||
function ($timeslot) {
|
||||
return $timeslot->id;
|
||||
},
|
||||
$timeslots
|
||||
);
|
||||
|
||||
foreach ($updatedExternalParticipants as $externalParticipant) {
|
||||
if (!$externalParticipant->selection)
|
||||
continue;
|
||||
|
||||
$selection = json_decode($externalParticipant->selection, true);
|
||||
if (!count($selection))
|
||||
continue;
|
||||
|
||||
$obsoleteSelectedTimeslotIds = array_diff($selection, $timeslotIds);
|
||||
if (!count($obsoleteSelectedTimeslotIds))
|
||||
continue;
|
||||
|
||||
$updatedSelection = null;
|
||||
if (count($obsoleteSelectedTimeslotIds) !== count($selection)) {
|
||||
$updatedSelection = array_filter(
|
||||
$selection,
|
||||
function ($timeslotId) use ($obsoleteSelectedTimeslotIds) {
|
||||
return !in_array($timeslotId, $obsoleteSelectedTimeslotIds);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$this->updateSelection($externalParticipant->id, $updatedSelection);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSelection($externalParticipantId, $selection)
|
||||
{
|
||||
$selection = $selection !== null ? "'" . json_encode($selection) . "'" : "NULL";
|
||||
$selectionUpdateQuery = "UPDATE $this->dbTable SET selection = $selection WHERE id = $externalParticipantId";
|
||||
$this->execQuery($selectionUpdateQuery);
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
<?php
|
||||
class CoodleSurveyParticipant_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'campus.tbl_coodle_survey_participants';
|
||||
}
|
||||
|
||||
public function getParticipants($surveyId)
|
||||
{
|
||||
$query = "
|
||||
SELECT
|
||||
surveyParticipant.participant_uid as uid,
|
||||
surveyParticipant.selection as selection,
|
||||
person.vorname || ' ' || person.nachname AS name
|
||||
FROM $this->dbTable surveyParticipant
|
||||
JOIN public.tbl_benutzer benutzer ON(benutzer.uid = surveyParticipant.participant_uid)
|
||||
JOIN public.tbl_person person ON(person.person_id = benutzer.person_id)
|
||||
WHERE survey_id = $surveyId
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getParticipantEntriesByUid($uid)
|
||||
{
|
||||
$query = "SELECT * FROM $this->dbTable WHERE participant_uid = '$uid'";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getActiveParticipantEntriesByUid($uid)
|
||||
{
|
||||
$query = "SELECT
|
||||
surveyParticipant.survey_id as survey_id,
|
||||
surveyParticipant.participant_uid as participant_uid,
|
||||
surveyParticipant.selection as selection
|
||||
FROM $this->dbTable surveyParticipant
|
||||
JOIN campus.tbl_coodle_surveys survey ON(survey.id = surveyParticipant.survey_id)
|
||||
WHERE surveyParticipant.participant_uid = '$uid'
|
||||
AND survey.completed_at IS NULL
|
||||
AND survey.canceled_at IS NULL";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function updateParticipants($surveyId, $participants, $timeslots)
|
||||
{
|
||||
$participantUids = array_map(function ($participant) {
|
||||
return $participant["uid"];
|
||||
}, $participants);
|
||||
|
||||
$existingParticipantsQuery = "SELECT * FROM " . $this->dbTable . " WHERE survey_id = " . $surveyId;
|
||||
$existingParticipants = getData($this->execQuery($existingParticipantsQuery));
|
||||
$existingParticipantUids = array_map(
|
||||
function ($existingParticipant) {
|
||||
return $existingParticipant->participant_uid;
|
||||
},
|
||||
$existingParticipants
|
||||
);
|
||||
|
||||
$newParticipantUids = array_filter(
|
||||
$participantUids,
|
||||
function ($participantUid) use ($existingParticipantUids) {
|
||||
return !in_array($participantUid, $existingParticipantUids);
|
||||
}
|
||||
);
|
||||
$redundantParticipantUids = array_filter(
|
||||
$existingParticipantUids,
|
||||
function ($existingParticipantUid) use ($participantUids) {
|
||||
return !in_array($existingParticipantUid, $participantUids);
|
||||
}
|
||||
);
|
||||
|
||||
if (count($newParticipantUids)) {
|
||||
$insertQuery = "INSERT INTO $this->dbTable VALUES ";
|
||||
$newParticipantInsertValues = array_map(
|
||||
function ($newParticipantUid) use ($surveyId) {
|
||||
return "('$surveyId', '$newParticipantUid', NULL)";
|
||||
},
|
||||
$newParticipantUids
|
||||
);
|
||||
$newParticipantInsertValues = implode(", ", $newParticipantInsertValues);
|
||||
$insertQuery .= $newParticipantInsertValues;
|
||||
$insertQuery .= ";";
|
||||
|
||||
$this->execQuery($insertQuery);
|
||||
}
|
||||
|
||||
if (count($redundantParticipantUids)) {
|
||||
$deleteQuery = "DELETE FROM $this->dbTable WHERE survey_id = $surveyId AND participant_uid IN ('" . implode("', '", $redundantParticipantUids) . "');";
|
||||
$this->execQuery($deleteQuery);
|
||||
}
|
||||
|
||||
$timeslotIds = array_map(
|
||||
function ($timeslot) {
|
||||
return $timeslot->id;
|
||||
},
|
||||
$timeslots
|
||||
);
|
||||
|
||||
$updatedExistingParticipants = getData($this->execQuery($existingParticipantsQuery));
|
||||
foreach ($updatedExistingParticipants as $participant) {
|
||||
if (!$participant->selection)
|
||||
continue;
|
||||
|
||||
$selection = json_decode($participant->selection, true);
|
||||
if (!count($selection))
|
||||
continue;
|
||||
|
||||
$obsoleteSelectedTimeslotIds = array_diff($selection, $timeslotIds);
|
||||
if (!count($obsoleteSelectedTimeslotIds))
|
||||
continue;
|
||||
|
||||
$updatedSelection = null;
|
||||
if (count($obsoleteSelectedTimeslotIds) !== count($selection)) {
|
||||
$updatedSelection = array_filter(
|
||||
$selection,
|
||||
function ($timeslotId) use ($obsoleteSelectedTimeslotIds) {
|
||||
return !in_array($timeslotId, $obsoleteSelectedTimeslotIds);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$this->updateSelection($surveyId, $participant->participant_uid, $updatedSelection);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateSelection($surveyId, $participantUid, $selection)
|
||||
{
|
||||
$selection = $selection !== null ? "'" . json_encode($selection) . "'" : "NULL";
|
||||
$selectionUpdateQuery = "UPDATE $this->dbTable SET selection = $selection WHERE survey_id = $surveyId AND participant_uid = '$participantUid'";
|
||||
$this->execQuery($selectionUpdateQuery);
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
class CoodleSurveyTimeslot_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'campus.tbl_coodle_survey_timeslots';
|
||||
$this->pk = 'id';
|
||||
}
|
||||
|
||||
public function getTimeslots($surveyId)
|
||||
{
|
||||
$query = "SELECT id, starts_at
|
||||
FROM $this->dbTable
|
||||
WHERE survey_id = $surveyId
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getTimeslotsForMultipleSurveys($surveyIds)
|
||||
{
|
||||
if (!count($surveyIds)) return [];
|
||||
|
||||
$surveyIds = "(" . implode(", ", $surveyIds) . ")";
|
||||
$query = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE survey_id IN $surveyIds
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getTimeslot($timeslotId)
|
||||
{
|
||||
$query = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE id = $timeslotId
|
||||
LIMIT 1
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function updateTimeslots($surveyId, $timeslots)
|
||||
{
|
||||
$newTimeslots = array_filter(
|
||||
$timeslots,
|
||||
function ($timeslot) {
|
||||
return !$timeslot["id"];
|
||||
}
|
||||
);
|
||||
$persistedTimeslots = array_filter(
|
||||
$timeslots,
|
||||
function ($timeslot) {
|
||||
return $timeslot["id"];
|
||||
}
|
||||
);
|
||||
$persistedTimeslotIds = array_map(
|
||||
function ($persistedTimeslot) {
|
||||
return $persistedTimeslot["id"];
|
||||
},
|
||||
$persistedTimeslots
|
||||
);
|
||||
|
||||
$existingTimeslotsQuery = "SELECT id, starts_at
|
||||
FROM $this->dbTable
|
||||
WHERE survey_id = $surveyId
|
||||
";
|
||||
$existingTimeslots = getData($this->execQuery($existingTimeslotsQuery));
|
||||
$existingTimeslotIds = array_map(
|
||||
function ($existingTimeslot) {
|
||||
return $existingTimeslot->id;
|
||||
},
|
||||
$existingTimeslots
|
||||
);
|
||||
|
||||
$obsoleteTimeslotIds = array_diff($existingTimeslotIds, $persistedTimeslotIds);
|
||||
if (count($obsoleteTimeslotIds)) {
|
||||
$deleteQuery = "DELETE FROM $this->dbTable WHERE id IN ('" . implode("', '", $obsoleteTimeslotIds) . "');";
|
||||
$this->execQuery($deleteQuery);
|
||||
}
|
||||
|
||||
if (count($newTimeslots)) {
|
||||
$insertQuery = "INSERT INTO $this->dbTable (survey_id, starts_at) VALUES ";
|
||||
$newTimeslotInsertValues = array_map(
|
||||
function ($newTimeslot) use ($surveyId) {
|
||||
return "('$surveyId', '" . $newTimeslot["startsAt"] . "')";
|
||||
},
|
||||
$newTimeslots
|
||||
);
|
||||
$newTimeslotInsertValues = implode(", ", $newTimeslotInsertValues);
|
||||
$insertQuery .= $newTimeslotInsertValues;
|
||||
$insertQuery .= ";";
|
||||
|
||||
$this->execQuery($insertQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
<?php
|
||||
class CoodleSurvey_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'campus.tbl_coodle_surveys';
|
||||
$this->pk = 'id';
|
||||
|
||||
$this->load->model('ressource/CoodleSurveyParticipant_model', 'CoodleSurveyParticipantModel');
|
||||
}
|
||||
|
||||
public function getSurvey($surveyId)
|
||||
{
|
||||
$query = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE id = $surveyId
|
||||
LIMIT 1
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getSurveys($surveyIds)
|
||||
{
|
||||
if (!count($surveyIds)) return [];
|
||||
|
||||
$surveyIds = "(" . implode(", ", $surveyIds) . ")";
|
||||
$query = "SELECT *
|
||||
FROM $this->dbTable
|
||||
WHERE id IN $surveyIds
|
||||
";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getActiveSurveys($uid)
|
||||
{
|
||||
$userParticipantEntries = getData($this->CoodleSurveyParticipantModel->getParticipantEntriesByUid($uid));
|
||||
$surveyIdsWhereUserIsParticipant = array_map(
|
||||
function ($userParticipantEntry) {
|
||||
return $userParticipantEntry->survey_id;
|
||||
},
|
||||
$userParticipantEntries
|
||||
);
|
||||
$surveyIdsWhereUserIsParticipantValue = implode(", ", $surveyIdsWhereUserIsParticipant);
|
||||
|
||||
$query = "SELECT
|
||||
survey.id as id,
|
||||
survey.creator_uid as creator_uid,
|
||||
survey.title as title,
|
||||
survey.ends_at as ends_at,
|
||||
survey.created_at as created_at,
|
||||
person.vorname || ' ' || person.nachname AS creator_name
|
||||
FROM $this->dbTable as survey
|
||||
JOIN public.tbl_benutzer benutzer ON(benutzer.uid = survey.creator_uid)
|
||||
JOIN public.tbl_person person ON(person.person_id = benutzer.person_id)
|
||||
WHERE (";
|
||||
if (strlen($surveyIdsWhereUserIsParticipantValue)) {
|
||||
$query .= "id IN ($surveyIdsWhereUserIsParticipantValue) OR ";
|
||||
}
|
||||
$query .= "creator_uid = '$uid')
|
||||
AND completed_at IS NULL
|
||||
AND canceled_at IS NULL";
|
||||
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function getInactiveSurveys($uid)
|
||||
{
|
||||
$userParticipantEntries = getData($this->CoodleSurveyParticipantModel->getParticipantEntriesByUid($uid));
|
||||
$surveyIdsWhereUserIsParticipant = array_map(
|
||||
function ($userParticipantEntry) {
|
||||
return $userParticipantEntry->survey_id;
|
||||
},
|
||||
$userParticipantEntries
|
||||
);
|
||||
$surveyIdsWhereUserIsParticipantValue = implode(", ", $surveyIdsWhereUserIsParticipant);
|
||||
|
||||
$query = "SELECT
|
||||
survey.id as id,
|
||||
survey.creator_uid as creator_uid,
|
||||
survey.title as title,
|
||||
survey.created_at as created_at,
|
||||
survey.completed_at as completed_at,
|
||||
survey.canceled_at as canceled_at,
|
||||
person.vorname || ' ' || person.nachname AS creator_name
|
||||
FROM $this->dbTable as survey
|
||||
JOIN public.tbl_benutzer benutzer ON(benutzer.uid = survey.creator_uid)
|
||||
JOIN public.tbl_person person ON(person.person_id = benutzer.person_id)
|
||||
WHERE (";
|
||||
if (strlen($surveyIdsWhereUserIsParticipantValue)) {
|
||||
$query .= "id IN ($surveyIdsWhereUserIsParticipantValue) OR ";
|
||||
}
|
||||
$query .= "creator_uid = '$uid')
|
||||
AND (completed_at IS NOT NULL OR canceled_at IS NOT NULL)";
|
||||
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
public function createSurvey($surveyData, $creatorUid)
|
||||
{
|
||||
$surveyCreationResult = $this->insert([
|
||||
"creator_uid" => $creatorUid,
|
||||
"title" => $surveyData["title"],
|
||||
"description" => $surveyData["description"] ?? "",
|
||||
"timeslot_duration" => $surveyData["timeslotDuration"],
|
||||
"are_selections_anonymized" => !!$surveyData["areSelectionsAnonymized"],
|
||||
"are_participants_anonymized" => !!$surveyData["areParticipantsAnonymized"],
|
||||
"max_selections" => $surveyData["maxSelections"] ?? 1,
|
||||
"selected_timeslot_id" => null,
|
||||
"ends_at" => $surveyData["endsAt"],
|
||||
"completed_at" => null,
|
||||
"canceled_at" => null,
|
||||
"created_at" => "NOW()",
|
||||
"updated_at" => "NOW()",
|
||||
]);
|
||||
|
||||
if (isError($surveyCreationResult)) {
|
||||
return error('Something went wrong during survey creation!');
|
||||
}
|
||||
|
||||
return $surveyCreationResult;
|
||||
}
|
||||
|
||||
public function updateSurvey($surveyId, $surveyData)
|
||||
{
|
||||
$surveyUpdateResult = $this->update($surveyId, [
|
||||
"title" => $surveyData["title"],
|
||||
"description" => $surveyData["description"],
|
||||
"timeslot_duration" => $surveyData["timeslotDuration"],
|
||||
"are_selections_anonymized" => $surveyData["areSelectionsAnonymized"],
|
||||
"are_participants_anonymized" => $surveyData["areParticipantsAnonymized"],
|
||||
"max_selections" => $surveyData["maxSelections"],
|
||||
"ends_at" => $surveyData["endsAt"],
|
||||
"updated_at" => "NOW()",
|
||||
]);
|
||||
|
||||
if (isError($surveyUpdateResult)) {
|
||||
return error('Something went wrong during survey update!');
|
||||
}
|
||||
|
||||
return $surveyUpdateResult;
|
||||
}
|
||||
|
||||
public function cancelSurvey($surveyId)
|
||||
{
|
||||
$this->update($surveyId, [
|
||||
"canceled_at" => "NOW()",
|
||||
"updated_at" => "NOW()",
|
||||
]);
|
||||
}
|
||||
|
||||
public function completeSurvey($surveyId, $timeslotId)
|
||||
{
|
||||
$this->update($surveyId, [
|
||||
"selected_timeslot_id" => $timeslotId,
|
||||
"completed_at" => "NOW()",
|
||||
"updated_at" => "NOW()",
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,6 @@ class Zeitsperre_model extends DB_Model
|
||||
$this->pk = 'zeitsperre_id';
|
||||
}
|
||||
|
||||
public function getZeitsperre($uid)
|
||||
{
|
||||
$query = "SELECT * from campus.tbl_zeitsperre WHERE mitarbeiter_uid = '$uid'";
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save or update Zeitsperre.
|
||||
*
|
||||
|
||||
@@ -232,8 +232,8 @@ FROM
|
||||
SELECT
|
||||
pa.lehreinheit_id,
|
||||
lv.lehrveranstaltung_id,
|
||||
pa.projektarbeit_id::text AS "projektarbeit_id",
|
||||
le.studiensemester_kurzbz,
|
||||
pa.projektarbeit_id::text AS "projektarbeit_id",
|
||||
pa.studiensemester_kurzbz,
|
||||
stg.studiengang_kz,
|
||||
upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz",
|
||||
lv.orgform_kurzbz,
|
||||
@@ -268,8 +268,7 @@ FROM
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer pb
|
||||
JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv ON (pa.lehrveranstaltung_id = lv.lehrveranstaltung_id)
|
||||
JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz)
|
||||
JOIN PUBLIC.tbl_person person USING (person_id)
|
||||
LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id)
|
||||
@@ -280,7 +279,7 @@ FROM
|
||||
/* filter projektbetreuuer */
|
||||
pb.person_id = \'' . $PERSON_ID . '\'
|
||||
/* filter studiensemester */
|
||||
AND le.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
|
||||
AND pa.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
|
||||
/* filter active lehrveranstaltungen */
|
||||
AND lv.aktiv = TRUE
|
||||
/* filter active organisationseinheiten */
|
||||
|
||||
@@ -242,8 +242,8 @@ FROM
|
||||
pa.lehreinheit_id,
|
||||
lv.lehrveranstaltung_id,
|
||||
lv.bezeichnung AS "lv_bezeichnung",
|
||||
(pa.projektarbeit_id::text) AS "projektarbeit_id",
|
||||
le.studiensemester_kurzbz,
|
||||
(pa.projektarbeit_id::text) AS "projektarbeit_id",
|
||||
pa.studiensemester_kurzbz,
|
||||
stg.studiengang_kz,
|
||||
upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz",
|
||||
lv.orgform_kurzbz,
|
||||
@@ -270,7 +270,7 @@ FROM
|
||||
ELSE (oe.organisationseinheittyp_kurzbz ||
|
||||
\' \' || oe.bezeichnung)
|
||||
END AS "lv_oe_kurzbz",
|
||||
(nachname || \' \' || vorname) AS "lektor",
|
||||
(nachname || \' \' || vorname) AS "lektor",
|
||||
TRUNC(pb.stunden, 1) AS "stunden",
|
||||
pb.stundensatz,
|
||||
TRUNC((pb.stunden * pb.stundensatz), 2) AS "betrag",
|
||||
@@ -280,8 +280,7 @@ FROM
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer pb
|
||||
JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv ON (pa.lehrveranstaltung_id = lv.lehrveranstaltung_id)
|
||||
JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz)
|
||||
JOIN PUBLIC.tbl_person person USING (person_id)
|
||||
LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id)
|
||||
@@ -291,7 +290,7 @@ FROM
|
||||
/* filter organisationseinheit */
|
||||
lv.oe_kurzbz IN (\'' . implode('\',\'', $ORGANISATIONSEINHEIT) . '\')
|
||||
/* filter studiensemester */
|
||||
AND le.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
|
||||
AND pa.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
|
||||
/* filter active lehrveranstaltungen */
|
||||
AND lv.aktiv = TRUE
|
||||
/* filter active organisationseinheiten */
|
||||
|
||||
@@ -272,8 +272,8 @@ FROM
|
||||
pa.lehreinheit_id,
|
||||
lv.lehrveranstaltung_id,
|
||||
lv.bezeichnung AS "lv_bezeichnung",
|
||||
pa.projektarbeit_id::text AS "projektarbeit_id",
|
||||
le.studiensemester_kurzbz,
|
||||
pa.projektarbeit_id::text AS "projektarbeit_id",
|
||||
pa.studiensemester_kurzbz,
|
||||
stg.studiengang_kz,
|
||||
upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz",
|
||||
lv.orgform_kurzbz,
|
||||
@@ -310,8 +310,7 @@ FROM
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer pb
|
||||
JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv ON (pa.lehrveranstaltung_id = lv.lehrveranstaltung_id)
|
||||
JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz)
|
||||
JOIN PUBLIC.tbl_person person USING (person_id)
|
||||
LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id)
|
||||
@@ -321,7 +320,7 @@ FROM
|
||||
/* filter studiengang */
|
||||
lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ')
|
||||
/* filter studiensemester */
|
||||
AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\'
|
||||
AND pa.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\'
|
||||
/* filter active lehrveranstaltungen */
|
||||
AND lv.aktiv = TRUE
|
||||
/* filter ausbildungssemester */
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
$LOGDATA_NAME = '\'Login with code\', \'Login with user\', \'Attempt to register with existing mailadress\', \'Access code sent\', \'Personal data saved\'';
|
||||
$REJECTED_STATUS = '\'Abgewiesener\'';
|
||||
$ADDITIONAL_STG = $this->config->item('infocenter_studiengang_kz');
|
||||
$QUALIFIKATIONSKURS = $this->config->item('infocenter_qualifikationskurs_kz');
|
||||
$STATUS_KURZBZ = '\'Wartender\', \'Bewerber\', \'Aufgenommener\', \'Student\'';
|
||||
$STUDIENSEMESTER = '\''.$this->variablelib->getVar('infocenter_studiensemester').'\'';
|
||||
$ORG_NAME = '\'InfoCenter\'';
|
||||
@@ -277,7 +278,26 @@ $query = '
|
||||
WHERE konto.person_id = p.person_id
|
||||
AND konto.studiensemester_kurzbz = '. $STUDIENSEMESTER .'
|
||||
AND konto.buchungstyp_kurzbz = '. $KAUTION_DRITT_STAAT .'
|
||||
) AS "Kaution"
|
||||
) AS "Kaution",
|
||||
(
|
||||
SELECT 1
|
||||
FROM public.tbl_prestudentstatus pss
|
||||
JOIN public.tbl_prestudent ps USING(prestudent_id)
|
||||
JOIN public.tbl_studiengang sg USING(studiengang_kz)
|
||||
JOIN lehre.tbl_studienplan sp USING(studienplan_id)
|
||||
JOIN lehre.tbl_studienordnung so USING(studienordnung_id)
|
||||
WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.'
|
||||
AND pss.bewerbung_abgeschicktamum IS NOT NULL
|
||||
AND ps.person_id = p.person_id
|
||||
AND sg.studiengang_kz in('.$QUALIFIKATIONSKURS.')
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM tbl_prestudentstatus spss
|
||||
WHERE spss.prestudent_id = ps.prestudent_id
|
||||
AND spss.status_kurzbz = '.$REJECTED_STATUS.'
|
||||
)
|
||||
LIMIT 1
|
||||
) AS "Qualikurs"
|
||||
FROM public.tbl_person p
|
||||
LEFT JOIN (
|
||||
SELECT tpl.person_id,
|
||||
@@ -351,7 +371,8 @@ $query = '
|
||||
'ZGV Nation MA',
|
||||
'InfoCenter Mitarbeiter',
|
||||
'Identitätsnachweis',
|
||||
ucfirst($this->p->t('infocenter', 'kaution'))
|
||||
ucfirst($this->p->t('infocenter', 'kaution')),
|
||||
'Qualikurs'
|
||||
),
|
||||
'formatRow' => function($datasetRaw) {
|
||||
|
||||
@@ -480,6 +501,14 @@ $query = '
|
||||
$datasetRaw->{'Kaution'} = 'Offen';
|
||||
}
|
||||
|
||||
if ($datasetRaw->{'Qualikurs'} === null)
|
||||
{
|
||||
$datasetRaw->{'Qualikurs'} = 'Nein';
|
||||
}
|
||||
else
|
||||
{
|
||||
$datasetRaw->{'Qualikurs'} = 'Ja';
|
||||
}
|
||||
return $datasetRaw;
|
||||
},
|
||||
'markRow' => function($datasetRaw) {
|
||||
|
||||
@@ -92,6 +92,14 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-6 table-responsive">
|
||||
<?php if ($onboarding_first_login): ?>
|
||||
<div class="row" id="onboardingRow">
|
||||
<?php if ($created_by_onboarding): ?>
|
||||
<div class="col-xs-5"><strong><?php echo $this->p->t('infocenter','onboardingRegistriert') ?></strong></div>
|
||||
<?php endif; ?>
|
||||
<div class="col-xs-7<?php echo $created_by_onboarding ? ' text-right' : '' ?>"><strong><?php echo $this->p->t('infocenter','ersterOnboardingLogin').': '.date_format(date_create($onboarding_first_login), 'd.m.Y') ?></strong></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<table class="table table-bordered stammdaten_form">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -191,12 +199,12 @@
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-xs-6">
|
||||
<a class="editStammdaten">
|
||||
<a class="editStammdaten" href="javascript:void(0);">
|
||||
<i class="fa fa-edit"></i> <?php echo $this->p->t('ui','bearbeiten'); ?></a>
|
||||
<div class="editActionStammdaten" style="display:none">
|
||||
<a class="cancelStammdaten">
|
||||
<a class="cancelStammdaten" href="javascript:void(0);">
|
||||
<i class="fa fa-trash"></i> <?php echo $this->p->t('ui','abbrechen');?></a>
|
||||
<a class="saveStammdaten">
|
||||
<a class="saveStammdaten" href="javascript:void(0);">
|
||||
<i class="fa fa-save"></i> <?php echo $this->p->t('ui','speichern'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,11 +29,10 @@ $this->load->view('templates/FHC-Header', $includesArray);
|
||||
<cis-menu
|
||||
root-url="<?= site_url(''); ?>"
|
||||
logo-url="<?= base_url($this->config->item('theme_logo')); ?>"
|
||||
avatar-url="<?= isset($isExternal) && $isExternal ? '' : site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
|
||||
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
|
||||
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
|
||||
:searchbaroptions="searchbaroptions"
|
||||
:searchfunction="searchfunction"
|
||||
:is-external="<?= isset($isExternal) && $isExternal ? 1 : 0 ?>"
|
||||
></cis-menu>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -345,11 +345,10 @@ $qry = "SELECT
|
||||
WHERE uid=student_uid) as student, tbl_lehrveranstaltung.studiengang_kz, tbl_lehrveranstaltung.semester,
|
||||
tbl_studiengang.email, tbl_betreuerart.beschreibung AS beutreuerart_beschreibung, tbl_projektbetreuer.stunden
|
||||
FROM
|
||||
lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, lehre.tbl_projektarbeit, lehre.tbl_projektbetreuer, public.tbl_studiengang, lehre.tbl_betreuerart
|
||||
lehre.tbl_lehrveranstaltung, lehre.tbl_projektarbeit, lehre.tbl_projektbetreuer, public.tbl_studiengang, lehre.tbl_betreuerart
|
||||
WHERE
|
||||
tbl_lehreinheit.lehreinheit_id=tbl_projektarbeit.lehreinheit_id AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($stdsem)." AND
|
||||
tbl_lehrveranstaltung.lehrveranstaltung_id=tbl_projektarbeit.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($stdsem)." AND
|
||||
tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id AND
|
||||
tbl_lehrveranstaltung.studiengang_kz=tbl_studiengang.studiengang_kz AND
|
||||
tbl_projektbetreuer.betreuerart_kurzbz=tbl_betreuerart.betreuerart_kurzbz AND
|
||||
|
||||
@@ -143,7 +143,6 @@ if($aktion!='zip')
|
||||
JOIN campus.tbl_paabgabe USING(projektarbeit_id)
|
||||
LEFT JOIN public.tbl_benutzer ON(uid=student_uid)
|
||||
LEFT JOIN public.tbl_person ON(tbl_benutzer.person_id=tbl_person.person_id)
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
|
||||
WHERE (projekttyp_kurzbz='Bachelor' OR projekttyp_kurzbz='Diplom')
|
||||
@@ -214,7 +213,6 @@ if(isset($_REQUEST['ok']) || (isset($_REQUEST['aktion']) && $_REQUEST['aktion']=
|
||||
JOIN campus.tbl_paabgabe USING(projektarbeit_id)
|
||||
LEFT JOIN public.tbl_benutzer ON(uid=student_uid)
|
||||
LEFT JOIN public.tbl_person ON(tbl_benutzer.person_id=tbl_person.person_id)
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
|
||||
WHERE (projekttyp_kurzbz='Bachelor' OR projekttyp_kurzbz='Diplom')
|
||||
|
||||
@@ -87,7 +87,6 @@ cellSeparator (default value: "|")
|
||||
JOIN campus.tbl_paabgabe USING(projektarbeit_id)
|
||||
LEFT JOIN public.tbl_benutzer ON(uid=student_uid)
|
||||
LEFT JOIN public.tbl_person ON(tbl_benutzer.person_id=tbl_person.person_id)
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
|
||||
WHERE (projekttyp_kurzbz='Bachelor' OR projekttyp_kurzbz='Diplom')
|
||||
|
||||
+1145
-21
File diff suppressed because it is too large
Load Diff
@@ -25,10 +25,77 @@
|
||||
* http://www.example.com/cis/public/freebusy_coodle.php/oesi
|
||||
*/
|
||||
require_once('../../config/cis.config.inc.php');
|
||||
require_once('../../include/benutzer.class.php');
|
||||
require_once('../../include/functions.inc.php');
|
||||
require_once('../../include/coodle.class.php');
|
||||
require_once('../../include/ical.class.php');
|
||||
|
||||
$uid = mb_substr($_SERVER['PATH_INFO'], 1);
|
||||
$excludeSurveyQueryParam = isset($_GET['excludeSurvey']) ? '?excludeSurvey=' . $_GET['excludeSurvey'] : '';
|
||||
$uid = mb_substr($_SERVER['PATH_INFO'],1);
|
||||
|
||||
header('Location: ' . APP_ROOT . 'cis.php/CoodleFreeBusy/' . $uid . $excludeSurveyQueryParam);
|
||||
exit;
|
||||
$bn = new benutzer();
|
||||
if(!$bn->load($uid))
|
||||
die('User invalid');
|
||||
|
||||
header("Content-Type: text/calendar; charset=UTF-8");
|
||||
|
||||
echo "BEGIN:VCALENDAR\n";
|
||||
echo "VERSION:2.0\n";
|
||||
echo "PRODID:-//FH TECHNIKUM WIEN//EN\n";
|
||||
echo "METHOD:PUBLISH\n";
|
||||
echo 'ORGANIZER;CN=',$bn->vorname,' ',$bn->nachname,':mailto:',$uid,'@',DOMAIN,"\n";
|
||||
echo 'DTSTAMP;TZID=Europe/Vienna:',date('Ymd', mktime(date('H'),date('i'),date('s'),date('m'),date('d')-5,date('Y'))),'T',date('Hms'),"\n";
|
||||
echo 'DTSTART;TZID=Europe/Vienna:',date('Ymd', mktime(0,0,0,date('m'),date('d')-5,date('Y'))),"T000000\n";
|
||||
echo 'DTEND;TZID=Europe/Vienna:',date('Ymd', mktime(0,0,0,date('m'),date('d')+30,date('Y'))),"T000000\n";
|
||||
echo 'URL:',APP_ROOT,'cis/public/freebusy_coodle.php/',$uid,"\n";
|
||||
echo "BEGIN:VFREEBUSY";
|
||||
|
||||
// Alle Umfragen holen an denen der User beteiligt ist
|
||||
$umfragen = new coodle();
|
||||
$umfragen->getCoodleFromUser($uid);
|
||||
foreach($umfragen->result as $umfrage)
|
||||
{
|
||||
if($umfrage->coodle_status_kurzbz=='laufend')
|
||||
{
|
||||
// Bei laufenden Umfragen werden alle angekreuzten Vorschlaege zur FreeBusy hinzugefuegt
|
||||
$ressource = new coodle();
|
||||
if($ressource_id = $ressource->RessourceExists($umfrage->coodle_id, $uid))
|
||||
{
|
||||
// Terminvorschlaege laden die angekreuzt wurden
|
||||
$termine = new coodle();
|
||||
$termine->getRessourceTermin($umfrage->coodle_id, $ressource_id);
|
||||
foreach($termine->result as $termin)
|
||||
{
|
||||
//Start und Ende berechnen
|
||||
$date = new DateTime($termin->datum.' '.$termin->uhrzeit);
|
||||
$dtstart = $date->format('Ymd\THis');
|
||||
$interval =new DateInterval('PT'.$umfrage->dauer.'M');
|
||||
$date->add($interval);
|
||||
$uhrzeit_ende = $date->format('H:i:s');
|
||||
$dtende = $date->format('Ymd\THis');
|
||||
echo "\nFREEBUSY;TZID=Europe/Vienna: $dtstart/$dtende";
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($umfrage->coodle_status_kurzbz=='abgeschlossen')
|
||||
{
|
||||
// Bei abgeschlossenen Umfragen wird nur mehr der ausgewaehlte Termin zur FreeBusy hinzugefuegt
|
||||
$termin = new coodle();
|
||||
$coodle_termin_id=$termin->getTerminAuswahl($umfrage->coodle_id);
|
||||
if($termin->loadTermin($coodle_termin_id))
|
||||
{
|
||||
//Start und Ende berechnen
|
||||
$date = new DateTime($termin->datum.' '.$termin->uhrzeit);
|
||||
$dtstart = $date->format('Ymd\THis');
|
||||
$interval =new DateInterval('PT'.$umfrage->dauer.'M');
|
||||
$date->add($interval);
|
||||
$uhrzeit_ende = $date->format('H:i:s');
|
||||
$dtende = $date->format('Ymd\THis');
|
||||
echo "\nFREEBUSY;TZID=Europe/Vienna: $dtstart/$dtende";
|
||||
}
|
||||
}
|
||||
// stornierte Umfragen werden nicht beruecksichtigt
|
||||
}
|
||||
|
||||
echo "\nEND:VFREEBUSY";
|
||||
echo "\nEND:VCALENDAR";
|
||||
?>
|
||||
+125
-6
@@ -23,21 +23,140 @@
|
||||
* Aufruf: http://www.example.com/cis/public/ical_coodle.php/[uid]
|
||||
*/
|
||||
require_once('../../config/cis.config.inc.php');
|
||||
require_once('../../include/benutzer.class.php');
|
||||
require_once('../../include/functions.inc.php');
|
||||
require_once('../../include/coodle.class.php');
|
||||
require_once('../../include/ical.class.php');
|
||||
|
||||
|
||||
$params = mb_substr($_SERVER['PATH_INFO'],1);
|
||||
$paramsArray = explode('/',$params);
|
||||
$private = false;
|
||||
|
||||
// redirect to new coodle ical
|
||||
if ($paramsArray[0] == 'cipher_encryption')
|
||||
{
|
||||
$encryptedKey = $paramsArray[1];
|
||||
header('Location: '.APP_ROOT.'cis.php/CoodleIcal/encrypted/' . $encryptedKey);
|
||||
exit;
|
||||
$uid = decryptData($paramsArray[1],LVPLAN_CYPHER_KEY);
|
||||
$private = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$uid = $paramsArray[0];
|
||||
header('Location: '.APP_ROOT.'cis.php/CoodleIcal/' . $uid);
|
||||
exit;
|
||||
}
|
||||
|
||||
$bn = new benutzer();
|
||||
if(!$bn->load($uid))
|
||||
die('User invalid');
|
||||
|
||||
header("Content-Type: text/calendar; charset=UTF-8");
|
||||
header("Content-disposition: filename=Coodle Terminzusagen.ics");
|
||||
|
||||
echo "BEGIN:VCALENDAR\n";
|
||||
echo "VERSION:2.0\n";
|
||||
echo "PRODID:-//FH TECHNIKUM WIEN//EN\n";
|
||||
//echo "METHOD:PUBLISH\n";
|
||||
//echo 'ORGANIZER;CN=',$bn->vorname,' ',$bn->nachname,':mailto:',$uid,'@',DOMAIN,"\n";
|
||||
//echo 'DTSTAMP;TZID=Europe/Vienna:',date('Ymd', mktime(date('H'),date('i'),date('s'),date('m'),date('d')-5,date('Y'))),'T',date('Hms'),"\n";
|
||||
echo 'DTSTART;TZID=Europe/Vienna:',date('Ymd', mktime(0,0,0,date('m'),date('d')-5,date('Y'))),"T000000\n";
|
||||
echo 'DTEND;TZID=Europe/Vienna:',date('Ymd', mktime(0,0,0,date('m'),date('d')+30,date('Y'))),"T000000\n";
|
||||
echo "BEGIN:VTIMEZONE
|
||||
TZID:Europe/Vienna
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:+0100
|
||||
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||
DTSTART:19810329T020000
|
||||
TZNAME:GMT+02:00
|
||||
TZOFFSETTO:+0200
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:+0200
|
||||
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||
DTSTART:19961027T030000
|
||||
TZNAME:GMT+01:00
|
||||
TZOFFSETTO:+0100
|
||||
END:STANDARD
|
||||
END:VTIMEZONE\n";
|
||||
//echo 'URL:',APP_ROOT,'cis/public/ical_coodle.php/',$uid,"\n";
|
||||
|
||||
// Alle Umfragen holen an denen der User beteiligt ist
|
||||
$umfragen = new coodle();
|
||||
$umfragen->getCoodleFromUser($uid);
|
||||
$i = 0;
|
||||
if (count($umfragen->result) > 0)
|
||||
{
|
||||
//echo "BEGIN:VEVENT";
|
||||
}
|
||||
foreach($umfragen->result as $umfrage)
|
||||
{
|
||||
if($umfrage->coodle_status_kurzbz=='laufend')
|
||||
{
|
||||
// Bei laufenden Umfragen werden alle angekreuzten Vorschlaege zur FreeBusy hinzugefuegt
|
||||
$ressource = new coodle();
|
||||
if($ressource_id = $ressource->RessourceExists($umfrage->coodle_id, $uid))
|
||||
{
|
||||
// Terminvorschlaege laden die angekreuzt wurden
|
||||
$termine = new coodle($umfrage->coodle_id);
|
||||
$termine->getRessourceTermin($umfrage->coodle_id, $ressource_id);
|
||||
foreach($termine->result as $termin)
|
||||
{
|
||||
//Start und Ende berechnen
|
||||
$date = new DateTime($termin->datum.' '.$termin->uhrzeit);
|
||||
$dtstart = $date->format('Ymd\THis');
|
||||
$interval =new DateInterval('PT'.$umfrage->dauer.'M');
|
||||
$date->add($interval);
|
||||
$uhrzeit_ende = $date->format('H:i:s');
|
||||
$dtende = $date->format('Ymd\THis');
|
||||
$ersteller = new benutzer($termine->ersteller_uid);
|
||||
if ($private == true)
|
||||
{
|
||||
$summary = 'Coodle Terminoption '.strip_tags($termine->titel);
|
||||
$description = 'Erstellt von '.$ersteller->vorname.' '.$ersteller->nachname;
|
||||
}
|
||||
else
|
||||
{
|
||||
$summary = 'Coodle Terminoption';
|
||||
$description = '';
|
||||
}
|
||||
|
||||
echo "\nBEGIN:VEVENT";
|
||||
echo "\nUID:Coodle_Terminoption".$dtstart."_".$dtende;
|
||||
echo "\nSUMMARY:".$summary;
|
||||
echo "\nDESCRIPTION:".$description;
|
||||
echo "\nDTSTART;TZID=Europe/Vienna:$dtstart";
|
||||
echo "\nDTEND;TZID=Europe/Vienna:$dtende";
|
||||
echo "\nTRANSP:OPAQUE";
|
||||
echo "\nEND:VEVENT";
|
||||
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bei abgeschlossene Umfragen wird ein iCal File mitgeschickt,
|
||||
// deshalb müssen diese Termine nicht berücksichtigt werden
|
||||
/*elseif($umfrage->coodle_status_kurzbz=='abgeschlossen')
|
||||
{
|
||||
// Bei abgeschlossenen Umfragen wird nur mehr der ausgewaehlte Termin zur FreeBusy hinzugefuegt
|
||||
$termin = new coodle();
|
||||
$coodle_termin_id=$termin->getTerminAuswahl($umfrage->coodle_id);
|
||||
if($termin->loadTermin($coodle_termin_id))
|
||||
{
|
||||
//Start und Ende berechnen
|
||||
$date = new DateTime($termin->datum.' '.$termin->uhrzeit);
|
||||
$dtstart = $date->format('Ymd\THis');
|
||||
$interval =new DateInterval('PT'.$umfrage->dauer.'M');
|
||||
$date->add($interval);
|
||||
$uhrzeit_ende = $date->format('H:i:s');
|
||||
$dtende = $date->format('Ymd\THis');
|
||||
|
||||
echo "\nBEGIN:VEVENT";
|
||||
echo "\nSUMMARY:Coodle Terminzusage";
|
||||
echo "\nDTSTART;TZID=Europe/Vienna: $dtstart";
|
||||
echo "\nDTEND;TZID=Europe/Vienna: $dtende";
|
||||
echo "\nTRANSP:OPAQUE";
|
||||
echo "\nEND:VEVENT";
|
||||
}
|
||||
}*/
|
||||
// stornierte Umfragen werden nicht beruecksichtigt
|
||||
}
|
||||
|
||||
echo "\nEND:VCALENDAR";
|
||||
?>
|
||||
@@ -122,8 +122,7 @@ foreach ($project_arr as $project)
|
||||
|
||||
// * get studiensemester
|
||||
$pa = new Projektarbeit($pa_id);
|
||||
$le = new Lehreinheit($pa->lehreinheit_id);
|
||||
$studiensemester_kurzbz = $le->studiensemester_kurzbz;
|
||||
$studiensemester_kurzbz = $pa->studiensemester_kurzbz;
|
||||
|
||||
// * get begin- and end date of studiensemester
|
||||
$ss = new Studiensemester($studiensemester_kurzbz);
|
||||
|
||||
@@ -107,16 +107,14 @@ SELECT
|
||||
FROM
|
||||
lehre.tbl_projektarbeit,
|
||||
lehre.tbl_lehrveranstaltung,
|
||||
lehre.tbl_lehreinheit,
|
||||
lehre.tbl_projektbetreuer,
|
||||
public.tbl_person
|
||||
WHERE
|
||||
tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id AND
|
||||
tbl_lehreinheit.lehreinheit_id=tbl_projektarbeit.lehreinheit_id AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektbetreuer.person_id=tbl_person.person_id AND
|
||||
tbl_projektbetreuer.stunden<>0 AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($stsem)."
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($stsem)."
|
||||
GROUP BY studiengang_kz,geschlecht";
|
||||
|
||||
if(!$result = $db->db_query($qry))
|
||||
@@ -231,7 +229,7 @@ if($format=='xls')
|
||||
if(!isset($stunden['w']))
|
||||
$stunden['w']=0;
|
||||
$summe_w+=$stunden['w'];
|
||||
if(!isset($summe_oe[$oe]['w']))
|
||||
if(!isset($summe_oe[$oe]['w']))
|
||||
$summe_oe[$oe]['w']=0;
|
||||
$summe_oe[$oe]['w']+=$stunden['w'];
|
||||
$worksheet->write($zeile,$organisationseinheiten_idx[$oe]+1,$stunden['w'],$format_data);
|
||||
|
||||
@@ -85,7 +85,7 @@ $db = new basis_db();
|
||||
//Daten holen
|
||||
$qry = "SELECT * FROM (
|
||||
SELECT
|
||||
tbl_lehreinheit.*, tbl_person.vorname, tbl_person.nachname, tbl_person.titelpre,
|
||||
tbl_person.vorname, tbl_person.nachname, tbl_person.titelpre,
|
||||
tbl_mitarbeiter.personalnummer, tbl_person.person_id, tbl_mitarbeiter.mitarbeiter_uid,
|
||||
tbl_mitarbeiter.fixangestellt,
|
||||
tbl_lehreinheitmitarbeiter.stundensatz as stundensatz,
|
||||
@@ -109,21 +109,20 @@ if($semester!='')
|
||||
//Projektsbetreuungen
|
||||
$qry.= " UNION
|
||||
SELECT
|
||||
tbl_lehreinheit.*, tbl_person.vorname, tbl_person.nachname, tbl_person.titelpre,
|
||||
tbl_person.vorname, tbl_person.nachname, tbl_person.titelpre,
|
||||
tbl_mitarbeiter.personalnummer, tbl_person.person_id, tbl_mitarbeiter.mitarbeiter_uid,
|
||||
tbl_mitarbeiter.fixangestellt,
|
||||
0 as stundensatz,
|
||||
0 as semesterstunden
|
||||
FROM
|
||||
lehre.tbl_lehreinheit, lehre.tbl_projektarbeit, lehre.tbl_projektbetreuer,
|
||||
lehre.tbl_projektarbeit, lehre.tbl_projektbetreuer,
|
||||
public.tbl_mitarbeiter, public.tbl_benutzer, lehre.tbl_lehrveranstaltung, public.tbl_person
|
||||
WHERE
|
||||
tbl_mitarbeiter.mitarbeiter_uid = tbl_benutzer.uid AND
|
||||
tbl_benutzer.person_id = tbl_projektbetreuer.person_id AND
|
||||
tbl_projektarbeit.projektarbeit_id = tbl_projektbetreuer.projektarbeit_id AND
|
||||
tbl_projektarbeit.lehreinheit_id = tbl_lehreinheit.lehreinheit_id AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)." AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)." AND
|
||||
tbl_lehrveranstaltung.studiengang_kz = ".$db->db_add_param($studiengang_kz, FHC_INTEGER)." AND
|
||||
tbl_person.person_id = tbl_projektbetreuer.person_id";
|
||||
if($semester!='')
|
||||
@@ -164,16 +163,15 @@ if($result = $db->db_query($qry))
|
||||
$qry = "
|
||||
SELECT
|
||||
tbl_projektbetreuer.stunden, tbl_projektbetreuer.stundensatz
|
||||
FROM lehre.tbl_projektbetreuer, lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung,
|
||||
FROM lehre.tbl_projektbetreuer, lehre.tbl_lehrveranstaltung,
|
||||
public.tbl_benutzer, lehre.tbl_projektarbeit, campus.vw_student
|
||||
WHERE
|
||||
tbl_projektbetreuer.person_id=tbl_benutzer.person_id
|
||||
AND tbl_benutzer.uid=".$db->db_add_param($uid)."
|
||||
AND tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id
|
||||
AND student_uid=vw_student.uid
|
||||
AND tbl_lehreinheit.lehreinheit_id=tbl_projektarbeit.lehreinheit_id
|
||||
AND tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
AND tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id
|
||||
AND tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
AND tbl_projektarbeit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id
|
||||
AND tbl_lehrveranstaltung.studiengang_kz=".$db->db_add_param($studiengang_kz, FHC_INTEGER);
|
||||
if($semester!='')
|
||||
$qry.=" AND tbl_lehrveranstaltung.semester=".$db->db_add_param($semester, FHC_INTEGER);
|
||||
|
||||
@@ -99,10 +99,9 @@ $qry_stg = "SELECT distinct studiengang_kz, typ, kurzbz
|
||||
studiengang_kz
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer JOIN lehre.tbl_projektarbeit ON tbl_projektbetreuer.projektarbeit_id=tbl_projektarbeit.projektarbeit_id
|
||||
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_projektarbeit.lehreinheit_id
|
||||
JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_lehreinheit.lehrveranstaltung_id
|
||||
JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_projektarbeit.lehrveranstaltung_id
|
||||
WHERE
|
||||
lehre.tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
lehre.tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
) as foo
|
||||
JOIN public.tbl_studiengang USING (studiengang_kz)
|
||||
";
|
||||
@@ -506,10 +505,9 @@ if ($result_stg = $db->db_query($qry_stg))
|
||||
JOIN public.tbl_benutzer ON tbl_benutzer.person_id=tbl_person.person_id
|
||||
JOIN public.tbl_mitarbeiter ON tbl_mitarbeiter.mitarbeiter_uid=tbl_benutzer.uid
|
||||
JOIN lehre.tbl_projektarbeit ON tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id
|
||||
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id=tbl_projektarbeit.lehreinheit_id
|
||||
JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_lehreinheit.lehrveranstaltung_id
|
||||
JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_projektarbeit.lehrveranstaltung_id
|
||||
WHERE
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND
|
||||
tbl_lehrveranstaltung.studiengang_kz=".$db->db_add_param($studiengang_kz, FHC_INTEGER)." AND
|
||||
NOT EXISTS (SELECT
|
||||
mitarbeiter_uid
|
||||
@@ -589,12 +587,11 @@ if ($result_stg = $db->db_query($qry_stg))
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer JOIN public.tbl_benutzer ON tbl_projektbetreuer.person_id = tbl_benutzer.person_id
|
||||
JOIN lehre.tbl_projektarbeit ON tbl_projektarbeit.projektarbeit_id = tbl_projektbetreuer.projektarbeit_id
|
||||
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_projektarbeit.lehreinheit_id
|
||||
JOIN lehre.tbl_lehrveranstaltung ON tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id
|
||||
JOIN lehre.tbl_lehrveranstaltung ON tbl_projektarbeit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id
|
||||
JOIN campus.vw_student ON vw_student.uid = student_uid
|
||||
WHERE
|
||||
tbl_benutzer.uid = ".$db->db_add_param($uid)."
|
||||
AND tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
AND tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
AND tbl_lehrveranstaltung.studiengang_kz=".$db->db_add_param($studiengang_kz, FHC_INTEGER);
|
||||
|
||||
if ($result = $db->db_query($qry))
|
||||
@@ -825,15 +822,14 @@ if ($result_stg = $db->db_query($qry_stg))
|
||||
$worksheet =& $workbook->addWorksheet('Betreuerstunden');
|
||||
$worksheet->setInputEncoding('utf-8');
|
||||
$qry = "SELECT
|
||||
studiensemester_kurzbz, nachname, vorname, sum(stunden) AS stunden, titelpre,
|
||||
lehre.tbl_projektarbeit.studiensemester_kurzbz, nachname, vorname, sum(stunden) AS stunden, titelpre,
|
||||
sum(tbl_projektbetreuer.stundensatz*tbl_projektbetreuer.stunden)::numeric(8, 2) AS euro, person_id
|
||||
FROM
|
||||
public.tbl_person JOIN lehre.tbl_projektbetreuer USING (person_id)
|
||||
JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
WHERE
|
||||
studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)." AND
|
||||
lehre.tbl_projektarbeit.studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)." AND
|
||||
stunden > 0";
|
||||
|
||||
if (count($stg_arr) > 0)
|
||||
@@ -841,7 +837,7 @@ if ($result_stg = $db->db_query($qry_stg))
|
||||
|
||||
$qry .= "
|
||||
GROUP BY
|
||||
studiensemester_kurzbz, person_id, nachname, vorname, titelpre
|
||||
lehre.tbl_projektarbeit.studiensemester_kurzbz, person_id, nachname, vorname, titelpre
|
||||
ORDER BY
|
||||
nachname, vorname
|
||||
";
|
||||
|
||||
@@ -304,15 +304,14 @@ if($studiengang_kz!='')
|
||||
$qry = "SELECT
|
||||
*
|
||||
FROM
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung,
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehrveranstaltung,
|
||||
lehre.tbl_projektbetreuer, public.tbl_person
|
||||
WHERE
|
||||
tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id AND
|
||||
tbl_person.person_id=tbl_projektbetreuer.person_id AND
|
||||
tbl_lehrveranstaltung.studiengang_kz=".$db->db_add_param($studiengang_kz, FHC_INTEGER)." AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
";
|
||||
|
||||
if($semester!='')
|
||||
@@ -323,14 +322,13 @@ elseif($mitarbeiter_uid!='')
|
||||
$qry = "SELECT
|
||||
*
|
||||
FROM
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, lehre.tbl_projektbetreuer, public.tbl_person
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehrveranstaltung, lehre.tbl_projektbetreuer, public.tbl_person
|
||||
WHERE
|
||||
tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id AND
|
||||
tbl_person.person_id=tbl_projektbetreuer.person_id AND
|
||||
tbl_projektbetreuer.person_id=".$db->db_add_param($mitarbeiter->person_id, FHC_INTEGER)." AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
";
|
||||
}
|
||||
elseif($oe_kurzbz!='')
|
||||
@@ -338,15 +336,14 @@ elseif($oe_kurzbz!='')
|
||||
$qry = "SELECT
|
||||
*
|
||||
FROM
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung, lehre.tbl_projektbetreuer,
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehrveranstaltung, lehre.tbl_projektbetreuer,
|
||||
public.tbl_person, lehre.tbl_lehrveranstaltung as lehrfach
|
||||
WHERE
|
||||
tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.projektarbeit_id=tbl_projektbetreuer.projektarbeit_id AND
|
||||
tbl_lehreinheit.lehrfach_id=lehrfach.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id=lehrfach.lehrveranstaltung_id AND
|
||||
tbl_person.person_id=tbl_projektbetreuer.person_id AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND
|
||||
lehrfach.oe_kurzbz=".$db->db_add_param($oe_kurzbz)."
|
||||
";
|
||||
}
|
||||
|
||||
@@ -490,15 +490,13 @@ if($result = $db->db_query($qry))
|
||||
tbl_projektbetreuer.person_id,
|
||||
tbl_lehrveranstaltung.orgform_kurzbz
|
||||
FROM lehre.tbl_projektarbeit,
|
||||
lehre.tbl_lehreinheit,
|
||||
lehre.tbl_lehrveranstaltung,
|
||||
lehre.tbl_projektbetreuer,
|
||||
PUBLIC.tbl_person
|
||||
WHERE tbl_projektarbeit.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
|
||||
AND tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id
|
||||
WHERE tbl_projektarbeit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id
|
||||
AND tbl_projektarbeit.projektarbeit_id = tbl_projektbetreuer.projektarbeit_id
|
||||
AND tbl_person.person_id = tbl_projektbetreuer.person_id
|
||||
AND tbl_lehreinheit.studiensemester_kurzbz = ".$db->db_add_param($studiensemester_kurzbz);
|
||||
AND tbl_projektarbeit.studiensemester_kurzbz = ".$db->db_add_param($studiensemester_kurzbz);
|
||||
|
||||
if($uid!=='')
|
||||
{
|
||||
|
||||
@@ -84,15 +84,14 @@ $qry = "SELECT
|
||||
ende, CASE WHEN freigegeben THEN 'Ja' ELSE 'Nein' END, gesperrtbis, themenbereich,
|
||||
tbl_projektarbeit.anmerkung, projektarbeit_id
|
||||
FROM
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung,
|
||||
lehre.tbl_projektarbeit, lehre.tbl_lehrveranstaltung,
|
||||
public.tbl_benutzer, public.tbl_person, lehre.tbl_projekttyp
|
||||
WHERE
|
||||
tbl_projektarbeit.lehreinheit_id = tbl_lehreinheit.lehreinheit_id AND
|
||||
tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_lehreinheit.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.student_uid = tbl_benutzer.uid AND
|
||||
tbl_benutzer.person_id = tbl_person.person_id AND
|
||||
tbl_projektarbeit.projekttyp_kurzbz = tbl_projekttyp.projekttyp_kurzbz AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz = ".$db->db_add_param($studiensemester_kurzbz)." AND
|
||||
tbl_projektarbeit.studiensemester_kurzbz = ".$db->db_add_param($studiensemester_kurzbz)." AND
|
||||
tbl_lehrveranstaltung.studiengang_kz = ".$db->db_add_param($studiengang_kz)." AND
|
||||
tbl_projektarbeit.projekttyp_kurzbz IN ('Bachelor','Diplom','Projekt')";
|
||||
|
||||
|
||||
@@ -4374,6 +4374,8 @@ if(!$error)
|
||||
$projektarbeit->titel = $_POST['titel'];
|
||||
$projektarbeit->titel_english = $_POST['titel_english'];
|
||||
$projektarbeit->lehreinheit_id = $_POST['lehreinheit_id'];
|
||||
$projektarbeit->lehrveranstaltung_id = $_POST['lehrveranstaltung_id'];
|
||||
$projektarbeit->studiensemester_kurzbz = $_POST['studiensemester_kurzbz'];
|
||||
$projektarbeit->student_uid = $_POST['student_uid'];
|
||||
$projektarbeit->firma_id = $_POST['firma_id'];
|
||||
$projektarbeit->note = $_POST['note'];
|
||||
|
||||
@@ -239,6 +239,7 @@ function StudentProjektarbeitDetailDisableFields(val)
|
||||
document.getElementById('student-projektarbeit-button-speichern').disabled=val;
|
||||
document.getElementById('student-projektarbeit-menulist-projekttyp').disabled=val;
|
||||
document.getElementById('student-projektarbeit-menulist-lehrveranstaltung').disabled=val;
|
||||
document.getElementById('student-projektarbeit-menulist-studiensemester').disabled=val;
|
||||
document.getElementById('student-projektarbeit-menulist-lehreinheit').disabled=val;
|
||||
document.getElementById('student-projektarbeit-menulist-firma').disabled=val;
|
||||
document.getElementById('student-projektarbeit-menulist-note').disabled=val;
|
||||
@@ -290,6 +291,7 @@ function StudentProjektarbeitResetFields()
|
||||
document.getElementById('student-projektarbeit-menulist-firma').value='';
|
||||
document.getElementById('student-projektarbeit-menulist-note').value='';
|
||||
document.getElementById('student-projektarbeit-checkbox-final').checked=true;
|
||||
document.getElementById('student-projektarbeit-menulist-studiensemester').value=getStudiensemester();
|
||||
|
||||
var stg_kz = document.getElementById('student-detail-menulist-studiengang_kz').value;
|
||||
|
||||
@@ -379,6 +381,7 @@ function StudentProjektarbeitAuswahl()
|
||||
lehreinheit_id = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#lehreinheit_id" ));
|
||||
lehrveranstaltung_id = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#lehrveranstaltung_id" ));
|
||||
lehreinheit_stsem = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#lehreinheit_stsem" ));
|
||||
projektarbeit_stsem = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#projektarbeit_stsem" ));
|
||||
student_uid = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#student_uid" ));
|
||||
firma_id = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#firma_id" ));
|
||||
note = getTargetHelper(dsource,subject,rdfService.GetResource( predicateNS + "#note" ));
|
||||
@@ -399,7 +402,7 @@ function StudentProjektarbeitAuswahl()
|
||||
|
||||
//Lehrveranstaltung DropDown laden
|
||||
var LvDropDown = document.getElementById('student-projektarbeit-menulist-lehrveranstaltung');
|
||||
url='<?php echo APP_ROOT;?>rdf/lehrveranstaltung.rdf.php?uid='+student_uid+"&projektarbeit=true&withlv="+lehrveranstaltung_id+"&"+gettimestamp();
|
||||
url='<?php echo APP_ROOT;?>rdf/lehrveranstaltung.rdf.php?uid='+student_uid+"&stg_kz="+stg_kz+"&projektarbeit=true&withlv="+lehrveranstaltung_id+"&"+gettimestamp();
|
||||
|
||||
//Alte DS entfernen
|
||||
var oldDatasources = LvDropDown.database.GetDataSources();
|
||||
@@ -420,7 +423,7 @@ function StudentProjektarbeitAuswahl()
|
||||
|
||||
// Lehreinheit Drop Down laden
|
||||
var LeDropDown = document.getElementById('student-projektarbeit-menulist-lehreinheit');
|
||||
url='<?php echo APP_ROOT;?>rdf/lehreinheit.rdf.php?lehrveranstaltung_id='+lehrveranstaltung_id+"&studiensemester_kurzbz="+lehreinheit_stsem+"&"+gettimestamp();
|
||||
url='<?php echo APP_ROOT;?>rdf/lehreinheit.rdf.php?lehrveranstaltung_id='+lehrveranstaltung_id+"&studiensemester_kurzbz="+projektarbeit_stsem+"&"+gettimestamp();
|
||||
|
||||
//Alte DS entfernen
|
||||
var oldDatasources = LeDropDown.database.GetDataSources();
|
||||
@@ -442,6 +445,7 @@ function StudentProjektarbeitAuswahl()
|
||||
//Werte setzen
|
||||
document.getElementById('student-projektarbeit-textbox-projektarbeit_id').value=projektarbeit_id;
|
||||
document.getElementById('student-projektarbeit-textbox-lehreinheit_stsem').value=lehreinheit_stsem;
|
||||
document.getElementById('student-projektarbeit-menulist-studiensemester').value=projektarbeit_stsem;
|
||||
document.getElementById('student-projektarbeit-menulist-projekttyp').value=projekttyp_kurzbz;
|
||||
document.getElementById('student-projektarbeit-menulist-lehrveranstaltung').value=lehrveranstaltung_id;
|
||||
document.getElementById('student-projektarbeit-menulist-lehreinheit').value=lehreinheit_id;
|
||||
@@ -539,6 +543,7 @@ function StudentProjektarbeitSpeichern()
|
||||
projektarbeit_id = document.getElementById('student-projektarbeit-textbox-projektarbeit_id').value;
|
||||
projekttyp_kurzbz = document.getElementById('student-projektarbeit-menulist-projekttyp').value;
|
||||
lehrveranstaltung_id = document.getElementById('student-projektarbeit-menulist-lehrveranstaltung').value;
|
||||
studiensemester_kurzbz = document.getElementById('student-projektarbeit-menulist-studiensemester').value;
|
||||
lehreinheit_id = document.getElementById('student-projektarbeit-menulist-lehreinheit').value;
|
||||
titel = document.getElementById('student-projektarbeit-textbox-titel').value;
|
||||
titel_english = document.getElementById('student-projektarbeit-textbox-titel_english').value;
|
||||
@@ -585,12 +590,18 @@ function StudentProjektarbeitSpeichern()
|
||||
return false;
|
||||
}
|
||||
|
||||
if(lehreinheit_id=='')
|
||||
if(lehrveranstaltung_id=='')
|
||||
{
|
||||
alert('Bitte einen LV-Teil auswaehlen');
|
||||
alert('Bitte eine Lehrveranstaltung auswaehlen');
|
||||
return false;
|
||||
}
|
||||
|
||||
if(studiensemester_kurzbz=='')
|
||||
{
|
||||
alert('Bitte ein Studiensemester auswaehlen');
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isNaN(gesamtstunden))
|
||||
gesamtstunden=0;
|
||||
|
||||
@@ -603,6 +614,8 @@ function StudentProjektarbeitSpeichern()
|
||||
req.add('projekttyp_kurzbz', projekttyp_kurzbz );
|
||||
req.add('titel', titel);
|
||||
req.add('titel_english', titel_english);
|
||||
req.add('lehrveranstaltung_id', lehrveranstaltung_id);
|
||||
req.add('studiensemester_kurzbz', studiensemester_kurzbz);
|
||||
req.add('lehreinheit_id', lehreinheit_id);
|
||||
req.add('student_uid', student_uid);
|
||||
req.add('firma_id', firma_id);
|
||||
@@ -738,7 +751,7 @@ function StudentProjektarbeitLVAChange()
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
lehrveranstaltung_id = document.getElementById('student-projektarbeit-menulist-lehrveranstaltung').value;
|
||||
studiensemester_kurzbz = getStudiensemester();
|
||||
studiensemester_kurzbz = document.getElementById('student-projektarbeit-menulist-studiensemester').value;
|
||||
|
||||
// Lehreinheit Drop Down laden
|
||||
var LeDropDown = document.getElementById('student-projektarbeit-menulist-lehreinheit');
|
||||
@@ -897,8 +910,8 @@ function StudentProjektbetreuerAuswahl()
|
||||
document.getElementById('student-projektbetreuer-textbox-person_id').value=person_id;
|
||||
document.getElementById('student-projektbetreuer-checkbox-neu').checked=false;
|
||||
|
||||
var lehreinheitstsem = document.getElementById('student-projektarbeit-textbox-lehreinheit_stsem').value;
|
||||
var default_stundensatz = StudentProjektbetreuerLoadStundensatz(person_id, lehreinheitstsem);
|
||||
var projektarbeitstsem = document.getElementById('student-projektarbeit-menulist-studiensemester').value;
|
||||
var default_stundensatz = StudentProjektbetreuerLoadStundensatz(person_id, projektarbeitstsem);
|
||||
|
||||
if (default_stundensatz != '')
|
||||
default_stundensatz = 'Stundensatz (Default '+default_stundensatz+'):';
|
||||
@@ -1410,9 +1423,10 @@ function StudentProjektbetreuerLoadStundensatz(person_id, studiensemester)
|
||||
function StudentProjektbetreuerLoadMitarbeiterDaten()
|
||||
{
|
||||
var person_id = MenulistGetSelectedValue('student-projektbetreuer-menulist-person');
|
||||
var lehreinheitstsem = document.getElementById('student-projektarbeit-textbox-lehreinheit_stsem').value;
|
||||
var projektarbeitstsem = document.getElementById('student-projektarbeit-menulist-studiensemester').value;
|
||||
|
||||
var stundensatz = StudentProjektbetreuerLoadStundensatz(person_id, lehreinheitstsem);
|
||||
|
||||
var stundensatz = StudentProjektbetreuerLoadStundensatz(person_id, projektarbeitstsem);
|
||||
|
||||
if (stundensatz != '')
|
||||
default_stundensatz = 'Stundensatz (Default '+stundensatz+'):';
|
||||
|
||||
@@ -104,6 +104,10 @@ $is_hidden = (!defined('FAS_STUDIERENDE_PROJEKTARBEIT_VERTRAGSDETAILS_ANZEIGEN')
|
||||
class="sortDirectionIndicator"
|
||||
sort="rdf:http://www.technikum-wien.at/projektarbeit/rdf#projektarbeit_id" />
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="student-projektarbeit-tree-lehrveranstaltung_id" label="LehrveranstaltungID" flex="2" hidden="true"
|
||||
class="sortDirectionIndicator"
|
||||
sort="rdf:http://www.technikum-wien.at/projektarbeit/rdf#lehrveranstaltung_id" />
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="student-projektarbeit-tree-lehreinheit_id" label="LehreinheitID" flex="2" hidden="true"
|
||||
class="sortDirectionIndicator"
|
||||
sort="rdf:http://www.technikum-wien.at/projektarbeit/rdf#lehreinheit_id" />
|
||||
@@ -131,7 +135,7 @@ $is_hidden = (!defined('FAS_STUDIERENDE_PROJEKTARBEIT_VERTRAGSDETAILS_ANZEIGEN')
|
||||
<treeitem uri="rdf:*">
|
||||
<treerow>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#bezeichnung"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#lehreinheit_stsem"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#projektarbeit_stsem"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#titel"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#note"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#beginn"/>
|
||||
@@ -141,6 +145,7 @@ $is_hidden = (!defined('FAS_STUDIERENDE_PROJEKTARBEIT_VERTRAGSDETAILS_ANZEIGEN')
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#themenbereich"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#anmerkung"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#projektarbeit_id"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#lehrveranstaltung_id"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#lehreinheit_id"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#student_uid"/>
|
||||
<treecell label="rdf:http://www.technikum-wien.at/projektarbeit/rdf#firma_id"/>
|
||||
@@ -249,6 +254,20 @@ $is_hidden = (!defined('FAS_STUDIERENDE_PROJEKTARBEIT_VERTRAGSDETAILS_ANZEIGEN')
|
||||
</template>
|
||||
</menulist>
|
||||
</row>
|
||||
<row>
|
||||
<label value="Studiensemester" control="student-projektarbeit-menulist-studiensemester"/>
|
||||
<menulist id="student-projektarbeit-menulist-studiensemester" disabled="true"
|
||||
datasources="<?php echo APP_ROOT ?>rdf/studiensemester.rdf.php?order=desc" flex="1"
|
||||
ref="http://www.technikum-wien.at/studiensemester/liste">
|
||||
<template>
|
||||
<menupopup>
|
||||
<menuitem value="rdf:http://www.technikum-wien.at/studiensemester/rdf#kurzbz"
|
||||
label="rdf:http://www.technikum-wien.at/studiensemester/rdf#kurzbz"
|
||||
uri="rdf:*"/>
|
||||
</menupopup>
|
||||
</template>
|
||||
</menulist>
|
||||
</row>
|
||||
<row>
|
||||
<label value="LV-Teil" control="student-projektarbeit-menulist-lehreinheit"/>
|
||||
<menulist id="student-projektarbeit-menulist-lehreinheit" disabled="true"
|
||||
|
||||
@@ -271,7 +271,8 @@ foreach ($uid_arr as $uid)
|
||||
'matr_nr' => $person->matr_nr,
|
||||
'ausstellungsdatum' => date('M.Y'),
|
||||
'gueltigbis' => $datum_obj->formatDatum($gueltigbis, 'd.m.Y'),
|
||||
'gueltigbis_3jahre' => date('d.m.Y', strtotime('+3 years'))
|
||||
'gueltigbis_3jahre' => date('d.m.Y', strtotime('+3 years')),
|
||||
'gueltigbis_2jahre' => date('d.m.Y', strtotime('+2 years'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,5 +521,63 @@ class adresse extends basis_db
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Laedt die österreichische Zustell Adresse einer Person
|
||||
* @param $person_id ID der Person
|
||||
* @return true wenn ok, false im Fehlerfall
|
||||
*/
|
||||
public function loadOesterreichischeZustellAdresse($person_id, $typ = null)
|
||||
{
|
||||
//Pruefen ob person_id eine gueltige Zahl ist
|
||||
if(!is_numeric($person_id) || $person_id == '')
|
||||
{
|
||||
$this->errormsg = 'PersonID muss eine Zahl sein';
|
||||
return false;
|
||||
}
|
||||
$typ_clause = '';
|
||||
if (isset($typ)) $typ_clause = "AND typ=".$this->db_add_param($typ);
|
||||
|
||||
//Daten aus der Datenbank lesen
|
||||
$qry = "SELECT * FROM public.tbl_adresse WHERE person_id=".$this->db_add_param($person_id, FHC_INTEGER, false)."
|
||||
AND nation = 'A'
|
||||
{$typ_clause}
|
||||
ORDER BY zustelladresse DESC, adresse_id DESC LIMIT 1";
|
||||
|
||||
if(!$this->db_query($qry))
|
||||
{
|
||||
$this->errormsg = 'Fehler bei einer Datenbankabfrage';
|
||||
return false;
|
||||
}
|
||||
|
||||
if($row = $this->db_fetch_object())
|
||||
{
|
||||
$this->adresse_id = $row->adresse_id;
|
||||
$this->heimatadresse = $this->db_parse_bool($row->heimatadresse);
|
||||
$this->zustelladresse = $this->db_parse_bool($row->zustelladresse);
|
||||
$this->gemeinde = $row->gemeinde;
|
||||
$this->name = $row->name;
|
||||
$this->nation = $row->nation;
|
||||
$this->ort = $row->ort;
|
||||
$this->person_id = $row->person_id;
|
||||
$this->plz = $row->plz;
|
||||
$this->strasse = $row->strasse;
|
||||
$this->typ = $row->typ;
|
||||
$this->updateamum = $row->updateamum;
|
||||
$this->updatevon = $row->updatevon;
|
||||
$this->insertamum = $row->insertamum;
|
||||
$this->insertvon = $row->insertvon;
|
||||
$this->firma_id = $row->firma_id;
|
||||
$this->rechnungsadresse = $this->db_parse_bool($row->rechnungsadresse);
|
||||
$this->anmerkung = $row->anmerkung;
|
||||
$this->co_name = $row->co_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg = 'Es ist kein Datensatz mit dieser ID vorhanden';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -48,7 +48,7 @@ class bisarchiv extends basis_db
|
||||
*/
|
||||
protected function validate()
|
||||
{
|
||||
if($this->studiensemster_kurzbz == null || mb_strlen($this->studiensemster_kurzbz) > 6)
|
||||
if($this->studiensemester_kurzbz == null || mb_strlen($this->studiensemester_kurzbz) > 6)
|
||||
{
|
||||
$this->errormsg = "Studiensemester ist ungueltig";
|
||||
return false;
|
||||
@@ -107,7 +107,7 @@ class bisarchiv extends basis_db
|
||||
return false;
|
||||
|
||||
$qry = "INSERT INTO bis.tbl_archiv (studiensemester_kurzbz, meldung, html, studiengang_kz, insertamum, insertvon, typ) VALUES ("
|
||||
. $this->db_add_param($this->studiensemster_kurzbz) . ","
|
||||
. $this->db_add_param($this->studiensemester_kurzbz) . ","
|
||||
. $this->db_add_param($this->meldung) . ","
|
||||
. $this->db_add_param($this->html) . ","
|
||||
. $this->db_add_param($this->studiengang_kz) . ","
|
||||
|
||||
@@ -2088,7 +2088,7 @@ class lehrveranstaltung extends basis_db
|
||||
/**
|
||||
* lädt die Lehrveranstaltungen zum zugehörigen Mitarbeiter
|
||||
* @param String $uid User ID des Mitarbeiters
|
||||
* @param String $studiensemster_kurzbz Kurzbezeichnung des Studiensemesters
|
||||
* @param String $studiensemester_kurzbz Kurzbezeichnung des Studiensemesters
|
||||
*/
|
||||
public function getLVByMitarbeiter($uid, $studiensemester_kurzbz = null)
|
||||
{
|
||||
@@ -2911,5 +2911,176 @@ class lehrveranstaltung extends basis_db
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert die geladenen Lehrveranstaltungen gegen den aktuellen Studienplan des Studenten.
|
||||
* Ermittelt den Studienplan über den Prestudent-Status (aktuellster Eintrag) und gleicht
|
||||
* die vorhandenen IDs mit der Tabelle tbl_studienplan_lehrveranstaltung ab.
|
||||
* Die interne Liste wird nur bei gefundenen Treffern aktualisiert.
|
||||
*
|
||||
* @param string $student_uid Student uid.
|
||||
* @return bool True bei erfolgreicher Abwicklung oder leeren Ausgangsdaten, False bei Datenbankfehlern.
|
||||
*/
|
||||
public function checkLvaAgainstStudentCurrentStudienplan($student_uid) {
|
||||
$qryStudent = "SELECT prestudent_id FROM tbl_student WHERE student_uid = ".$this->db_add_param($student_uid)."";
|
||||
|
||||
if($result = $this->db_query($qryStudent))
|
||||
{
|
||||
if($row = $this->db_fetch_object($result))
|
||||
{
|
||||
$prestudent_id = $row->prestudent_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg = 'Fehler beim Ermitteln der des aktuellen studienplan für studenten über prestudent';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg='Fehler bei Datenbankabfrage ' .$this->db_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
$qryHistory = "SELECT studienplan_id
|
||||
FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id = ".$this->db_add_param($prestudent_id)."
|
||||
ORDER BY public.tbl_prestudentstatus.datum DESC";
|
||||
if($result = $this->db_query($qryHistory))
|
||||
{
|
||||
if($row = $this->db_fetch_object($result))
|
||||
{
|
||||
$studienplan_id = $row->studienplan_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg = 'Fehler beim Ermitteln der des aktuellen studienplan für studenten über prestudentstatus';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg='Fehler bei Datenbankabfrage ' .$this->db_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
// needs to have lva_ids from previous query in this context
|
||||
$lvsIDs = array_column($this->lehrveranstaltungen, 'lehrveranstaltung_id');
|
||||
|
||||
if (empty($lvsIDs)) {
|
||||
// exit without modifying object state if no lva_id to query by are found
|
||||
return true;
|
||||
}
|
||||
|
||||
$ids = $this->db_implode4SQL($lvsIDs);
|
||||
|
||||
$qry = "SELECT tbl_lehrveranstaltung.*,
|
||||
tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id,
|
||||
tbl_studienplan_lehrveranstaltung.semester as stpllv_semester,
|
||||
tbl_studienplan_lehrveranstaltung.pflicht as stpllv_pflicht,
|
||||
tbl_studienplan_lehrveranstaltung.koordinator as stpllv_koordinator,
|
||||
tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id_parent,
|
||||
tbl_studienplan_lehrveranstaltung.sort stpllv_sort,
|
||||
tbl_studienplan_lehrveranstaltung.curriculum,
|
||||
tbl_studienplan_lehrveranstaltung.export,
|
||||
tbl_studienplan_lehrveranstaltung.genehmigung
|
||||
FROM lehre.tbl_lehrveranstaltung
|
||||
JOIN lehre.tbl_studienplan_lehrveranstaltung
|
||||
USING(lehrveranstaltung_id)
|
||||
WHERE tbl_studienplan_lehrveranstaltung.studienplan_id = ".$this->db_add_param($studienplan_id)."
|
||||
AND tbl_studienplan_lehrveranstaltung.lehrveranstaltung_id IN (".$ids.");";
|
||||
|
||||
if($result = $this->db_query($qry))
|
||||
{
|
||||
// reset the lva array and fill it with the new set
|
||||
$temp_lvas = array();
|
||||
while($row = $this->db_fetch_object($result))
|
||||
{
|
||||
$obj = new lehrveranstaltung();
|
||||
|
||||
$obj->lehrveranstaltung_id = $row->lehrveranstaltung_id;
|
||||
$obj->studiengang_kz = $row->studiengang_kz;
|
||||
$obj->bezeichnung = $row->bezeichnung;
|
||||
$obj->kurzbz = $row->kurzbz;
|
||||
$obj->lehrform_kurzbz = $row->lehrform_kurzbz;
|
||||
$obj->semester = $row->semester;
|
||||
$obj->ects = $row->ects;
|
||||
$obj->semesterstunden = $row->semesterstunden;
|
||||
$obj->anmerkung = $row->anmerkung;
|
||||
$obj->lehre = $this->db_parse_bool($row->lehre);
|
||||
$obj->lehreverzeichnis = $row->lehreverzeichnis;
|
||||
$obj->aktiv = $this->db_parse_bool($row->aktiv);
|
||||
$obj->ext_id = $row->ext_id;
|
||||
$obj->insertamum = $row->insertamum;
|
||||
$obj->insertvon = $row->insertvon;
|
||||
$obj->planfaktor = $row->planfaktor;
|
||||
$obj->planlektoren = $row->planlektoren;
|
||||
$obj->planpersonalkosten = $row->planpersonalkosten;
|
||||
$obj->plankostenprolektor = $row->plankostenprolektor;
|
||||
$obj->updateamum = $row->updateamum;
|
||||
$obj->updatevon = $row->updatevon;
|
||||
$obj->sprache = $row->sprache;
|
||||
$obj->sort = $row->sort;
|
||||
$obj->incoming = $row->incoming;
|
||||
$obj->zeugnis = $this->db_parse_bool($row->zeugnis);
|
||||
$obj->projektarbeit = $this->db_parse_bool($row->projektarbeit);
|
||||
$obj->koordinator = $row->koordinator;
|
||||
$obj->bezeichnung_english = $row->bezeichnung_english;
|
||||
$obj->orgform_kurzbz = $row->orgform_kurzbz;
|
||||
$obj->lehrtyp_kurzbz = $row->lehrtyp_kurzbz;
|
||||
$obj->lehrmodus_kurzbz = $row->lehrmodus_kurzbz;
|
||||
$obj->oe_kurzbz = $row->oe_kurzbz;
|
||||
$obj->raumtyp_kurzbz = $row->raumtyp_kurzbz;
|
||||
$obj->anzahlsemester = $row->anzahlsemester;
|
||||
$obj->semesterwochen = $row->semesterwochen;
|
||||
$obj->lvnr = $row->lvnr;
|
||||
$obj->semester_alternativ = $row->semester_alternativ;
|
||||
$obj->farbe = $row->farbe;
|
||||
$obj->lehrveranstaltung_template_id = $row->lehrveranstaltung_template_id;
|
||||
$obj->stpllv_sort = $row->stpllv_sort;
|
||||
$obj->benotung = $this->db_parse_bool($row->benotung);
|
||||
$obj->lvinfo = $this->db_parse_bool($row->lvinfo);
|
||||
$obj->lehrauftrag = $this->db_parse_bool($row->lehrauftrag);
|
||||
$obj->evaluierung = $this->db_parse_bool($row->evaluierung);
|
||||
|
||||
$obj->bezeichnung_arr['German'] = $row->bezeichnung;
|
||||
$obj->bezeichnung_arr['English'] = $row->bezeichnung_english;
|
||||
if ($obj->bezeichnung_arr['English'] == '')
|
||||
$obj->bezeichnung_arr['English'] = $obj->bezeichnung_arr['German'];
|
||||
|
||||
$obj->sws = $row->sws;
|
||||
$obj->lvs = $row->lvs;
|
||||
$obj->alvs = $row->alvs;
|
||||
$obj->lvps = $row->lvps;
|
||||
$obj->las = $row->las;
|
||||
|
||||
$obj->stpllv_semester = $row->stpllv_semester;
|
||||
$obj->stpllv_pflicht = $this->db_parse_bool($row->stpllv_pflicht);
|
||||
$obj->stpllv_koordinator = $row->stpllv_koordinator;
|
||||
$obj->studienplan_lehrveranstaltung_id = $row->studienplan_lehrveranstaltung_id;
|
||||
$obj->studienplan_lehrveranstaltung_id_parent = $row->studienplan_lehrveranstaltung_id_parent;
|
||||
$obj->curriculum = $this->db_parse_bool($row->curriculum);
|
||||
$obj->export = $this->db_parse_bool($row->export);
|
||||
$obj->genehmigung = $this->db_parse_bool($row->genehmigung);
|
||||
$obj->new = false;
|
||||
|
||||
$temp_lvas[] = $obj;
|
||||
}
|
||||
|
||||
// Only update the class property if we actually found matching records.
|
||||
// If $temp_lvas is empty, $this->lehrveranstaltungen remains unchanged.
|
||||
if (!empty($temp_lvas)) {
|
||||
$this->lehrveranstaltungen = $temp_lvas;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg='Fehler bei Datenbankabfrage ' .$this->db_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -37,6 +37,8 @@ class projektarbeit extends basis_db
|
||||
public $titel; // string
|
||||
public $titel_english; // string
|
||||
public $lehreinheit_id; // integer
|
||||
public $lehrveranstaltung_id; // integer
|
||||
public $studiensemester_kurzbz; // string
|
||||
public $student_uid; // integer
|
||||
public $firma_id; // integer
|
||||
public $note; // integer
|
||||
@@ -129,6 +131,8 @@ class projektarbeit extends basis_db
|
||||
$this->titel = $row->titel;
|
||||
$this->titel_english = $row->titel_english;
|
||||
$this->lehreinheit_id = $row->lehreinheit_id;
|
||||
$this->lehrveranstaltung_id = $row->lehrveranstaltung_id;
|
||||
$this->studiensemester_kurzbz = $row->studiensemester_kurzbz;
|
||||
$this->student_uid = $row->student_uid;
|
||||
$this->firma_id = $row->firma_id;
|
||||
$this->note = $row->note;
|
||||
@@ -178,9 +182,13 @@ class projektarbeit extends basis_db
|
||||
{
|
||||
$this->errormsg='Projekttyp_kurzbz darf nicht NULL sein!';
|
||||
}
|
||||
if ($this->lehreinheit_id==null)
|
||||
if ($this->lehrveranstaltung_id==null)
|
||||
{
|
||||
$this->errormsg='Lehreinheit_id darf nicht NULL sein!';
|
||||
$this->errormsg='Lehrveranstaltung_id darf nicht NULL sein!';
|
||||
}
|
||||
if ($this->studiensemester_kurzbz==null)
|
||||
{
|
||||
$this->errormsg='Studiensemester_kurzbz darf nicht NULL sein!';
|
||||
}
|
||||
if(mb_strlen($this->projekttyp_kurzbz)>16)
|
||||
{
|
||||
@@ -261,12 +269,15 @@ class projektarbeit extends basis_db
|
||||
{
|
||||
//Neuen Datensatz einfuegen
|
||||
|
||||
$qry='BEGIN; INSERT INTO lehre.tbl_projektarbeit (projekttyp_kurzbz, titel, lehreinheit_id, student_uid, firma_id, note, punkte,
|
||||
$qry='BEGIN; INSERT INTO lehre.tbl_projektarbeit (projekttyp_kurzbz, titel, lehreinheit_id,
|
||||
lehrveranstaltung_id, studiensemester_kurzbz, student_uid, firma_id, note, punkte,
|
||||
beginn, ende, faktor, freigegeben, gesperrtbis, stundensatz, gesamtstunden, themenbereich, anmerkung,
|
||||
insertamum, insertvon, updateamum, updatevon, titel_english, final) VALUES('.
|
||||
$this->db_add_param($this->projekttyp_kurzbz).', '.
|
||||
$this->db_add_param($this->titel).', '.
|
||||
$this->db_add_param($this->lehreinheit_id, FHC_INTEGER).', '.
|
||||
$this->db_add_param($this->lehrveranstaltung_id, FHC_INTEGER).', '.
|
||||
$this->db_add_param($this->studiensemester_kurzbz).', '.
|
||||
$this->db_add_param($this->student_uid).', '.
|
||||
$this->db_add_param($this->firma_id, FHC_INTEGER).', '.
|
||||
$this->db_add_param($this->note).', '.
|
||||
@@ -301,6 +312,8 @@ class projektarbeit extends basis_db
|
||||
'titel='.$this->db_add_param($this->titel).', '.
|
||||
'titel_english='.$this->db_add_param($this->titel_english).', '.
|
||||
'lehreinheit_id='.$this->db_add_param($this->lehreinheit_id, FHC_INTEGER).', '.
|
||||
'lehrveranstaltung_id='.$this->db_add_param($this->lehrveranstaltung_id, FHC_INTEGER).', '.
|
||||
'studiensemester_kurzbz='.$this->db_add_param($this->studiensemester_kurzbz).', '.
|
||||
'student_uid='.$this->db_add_param($this->student_uid).', '.
|
||||
'firma_id='.$this->db_add_param($this->firma_id, FHC_INTEGER).', '.
|
||||
'note='.$this->db_add_param($this->note).', '.
|
||||
@@ -406,6 +419,8 @@ class projektarbeit extends basis_db
|
||||
$obj->titel = $row->titel;
|
||||
$obj->titel_english = $row->titel_english;
|
||||
$obj->lehreinheit_id = $row->lehreinheit_id;
|
||||
$obj->lehrveranstaltung_id = $row->lehrveranstaltung_id;
|
||||
$obj->studiensemester_kurzbz = $row->studiensemester_kurzbz;
|
||||
$obj->student_uid = $row->student_uid;
|
||||
$obj->firma_id = $row->firma_id;
|
||||
$obj->note = $row->note;
|
||||
@@ -449,14 +464,13 @@ class projektarbeit extends basis_db
|
||||
tbl_projektarbeit.* , tbl_projekttyp.bezeichnung
|
||||
FROM
|
||||
lehre.tbl_projektarbeit
|
||||
JOIN
|
||||
lehre.tbl_projekttyp USING (projekttyp_kurzbz), lehre.tbl_lehreinheit, lehre.tbl_lehrveranstaltung
|
||||
JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
JOIN lehre.tbl_lehrveranstaltung ON (lehre.tbl_projektarbeit.lehrveranstaltung_id = lehre.tbl_lehrveranstaltung.lehrveranstaltung_id)
|
||||
|
||||
WHERE
|
||||
tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id AND
|
||||
tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_projektarbeit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id AND
|
||||
tbl_lehrveranstaltung.studiengang_kz=".$this->db_add_param($studiengang_kz, FHC_INTEGER)." AND
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$this->db_add_param($studiensemester_kurzbz);
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$this->db_add_param($studiensemester_kurzbz);
|
||||
|
||||
if($this->db_query($qry))
|
||||
{
|
||||
@@ -470,6 +484,8 @@ class projektarbeit extends basis_db
|
||||
$obj->titel = $row->titel;
|
||||
$obj->titel_english = $row->titel_english;
|
||||
$obj->lehreinheit_id = $row->lehreinheit_id;
|
||||
$obj->lehrveranstaltung_id = $row->lehrveranstaltung_id;
|
||||
$obj->studiensemester_kurzbz = $row->studiensemester_kurzbz;
|
||||
$obj->student_uid = $row->student_uid;
|
||||
$obj->firma_id = $row->firma_id;
|
||||
$obj->note = $row->note;
|
||||
@@ -534,7 +550,6 @@ class projektarbeit extends basis_db
|
||||
pa.projekttyp_kurzbz
|
||||
FROM
|
||||
lehre.tbl_projektarbeit pa
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
JOIN public.tbl_studiensemester sem USING(studiensemester_kurzbz)
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
|
||||
+10
-14
@@ -371,14 +371,14 @@ class vertrag extends basis_db
|
||||
null::integer as pruefung_id,
|
||||
projektarbeit_id,
|
||||
(tbl_projektbetreuer.stunden*tbl_projektbetreuer.stundensatz) as betrag,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
tbl_projektarbeit.studiensemester_kurzbz,
|
||||
tbl_projektbetreuer.betreuerart_kurzbz,
|
||||
(SELECT nachname || ' ' || vorname FROM public.tbl_person JOIN public.tbl_benutzer USING(person_id) WHERE uid=tbl_projektarbeit.student_uid)
|
||||
as bezeichnung
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
|
||||
WHERE
|
||||
tbl_projektbetreuer.person_id=".$this->db_add_param($person_id, FHC_INTEGER)."
|
||||
AND vertrag_id IS NULL";
|
||||
@@ -461,9 +461,8 @@ class vertrag extends basis_db
|
||||
OR
|
||||
EXISTS (SELECT 1 FROM lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
tbl_lehreinheit.studiensemester_kurzbz=".$db->db_add_param($studiensemester_kurzbz)."
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$db->db_add_param($studiensemester_kurzbz)."
|
||||
AND tbl_projektbetreuer.person_id=tbl_person.person_id
|
||||
AND tbl_projektbetreuer.vertrag_id IS NULL
|
||||
)
|
||||
@@ -535,12 +534,12 @@ class vertrag extends basis_db
|
||||
UNION
|
||||
SELECT
|
||||
'Betreuung' as type,
|
||||
tbl_projektarbeit.lehreinheit_id as lehreinheit_id,
|
||||
NULL as lehreinheit_id,
|
||||
null as mitarbeiter_uid,
|
||||
null::integer as pruefung_id,
|
||||
projektarbeit_id,
|
||||
(tbl_projektbetreuer.stunden*tbl_projektbetreuer.stundensatz) as betrag,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
tbl_projektarbeit.studiensemester_kurzbz,
|
||||
tbl_projektbetreuer.betreuerart_kurzbz,
|
||||
(SELECT nachname || ' ' || vorname FROM public.tbl_person JOIN public.tbl_benutzer USING(person_id) WHERE uid=tbl_projektarbeit.student_uid)
|
||||
as bezeichnung,
|
||||
@@ -549,7 +548,6 @@ class vertrag extends basis_db
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
JOIN lehre.tbl_vertrag USING (vertrag_id)
|
||||
WHERE
|
||||
vertrag_id=".$this->db_add_param($vertrag_id, FHC_INTEGER).";";
|
||||
@@ -942,17 +940,16 @@ class vertrag extends basis_db
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
vertrag_id=tbl_vertrag.vertrag_id
|
||||
AND studiensemester_kurzbz=".$this->db_add_param($stsem).")
|
||||
AND lehre.tbl_lehreinheit.studiensemester_kurzbz=".$this->db_add_param($stsem).")
|
||||
OR
|
||||
EXISTS (SELECT
|
||||
1
|
||||
FROM
|
||||
lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
vertrag_id=tbl_vertrag.vertrag_id
|
||||
AND studiensemester_kurzbz=".$this->db_add_param($stsem).")
|
||||
AND lehre.tbl_projektarbeit.studiensemester_kurzbz=".$this->db_add_param($stsem).")
|
||||
OR
|
||||
(NOT EXISTS (SELECT
|
||||
1
|
||||
@@ -980,7 +977,7 @@ class vertrag extends basis_db
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
vertrag_id=tbl_vertrag.vertrag_id
|
||||
AND studiensemester_kurzbz=".$this->db_add_param($stsem).")
|
||||
AND lehre.tbl_lehreinheit.studiensemester_kurzbz=".$this->db_add_param($stsem).")
|
||||
)
|
||||
AND tbl_benutzer.uid=".$this->db_add_param($mitarbeiter_uid);
|
||||
|
||||
@@ -1077,7 +1074,7 @@ class vertrag extends basis_db
|
||||
JOIN lehre.tbl_lehreinheitmitarbeiter USING(vertrag_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
studiensemester_kurzbz=".$this->db_add_param($studiensemester_kurzbz)."
|
||||
lehre.tbl_lehreinheit.studiensemester_kurzbz=".$this->db_add_param($studiensemester_kurzbz)."
|
||||
AND tbl_lehreinheitmitarbeiter.mitarbeiter_uid NOT IN(SELECT uid FROM public.tbl_benutzer WHERE person_id=tbl_vertrag.person_id)
|
||||
UNION
|
||||
SELECT
|
||||
@@ -1086,9 +1083,8 @@ class vertrag extends basis_db
|
||||
lehre.tbl_vertrag
|
||||
JOIN lehre.tbl_projektbetreuer USING(vertrag_id)
|
||||
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
|
||||
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
WHERE
|
||||
studiensemester_kurzbz=".$this->db_add_param($studiensemester_kurzbz)."
|
||||
tbl_projektarbeit.studiensemester_kurzbz=".$this->db_add_param($studiensemester_kurzbz)."
|
||||
AND tbl_projektbetreuer.person_id!=tbl_vertrag.person_id";
|
||||
|
||||
if($result = $this->db_query($qry))
|
||||
|
||||
@@ -748,17 +748,14 @@ or not exists
|
||||
UNION
|
||||
SELECT sum(pb.stunden) AS semstunden
|
||||
FROM
|
||||
lehre.tbl_projektarbeit pa,
|
||||
lehre.tbl_projektbetreuer pb,
|
||||
public.tbl_benutzer b,
|
||||
lehre.tbl_lehreinheit l
|
||||
JOIN
|
||||
lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id)
|
||||
JOIN
|
||||
public.tbl_studiengang s using (studiengang_kz)
|
||||
lehre.tbl_projektarbeit pa
|
||||
JOIN lehre.tbl_projektbetreuer pb ON(pa.projektarbeit_id = pb.projektarbeit_id)
|
||||
JOIN public.tbl_benutzer b ON(pb.person_id = b.person_id)
|
||||
JOIN lehre.tbl_lehreinheit l ON(pa.lehrveranstaltung_id = l.lehrveranstaltung_id AND pa.studiensemester_kurzbz = l.studiensemester_kurzbz)
|
||||
JOIN lehre.tbl_lehrveranstaltung lv ON (l.lehrveranstaltung_id = lv.lehrveranstaltung_id)
|
||||
JOIN public.tbl_studiengang s USING (studiengang_kz)
|
||||
|
||||
WHERE
|
||||
pa.lehreinheit_id = l.lehreinheit_id AND
|
||||
pb.projektarbeit_id = pa.projektarbeit_id AND
|
||||
pb.person_id = b.person_id AND
|
||||
b.uid = ".$this->db_add_param($user)." AND
|
||||
|
||||
@@ -33,10 +33,6 @@ html {
|
||||
background-color: var(--fhc-primary) !important;
|
||||
}
|
||||
|
||||
.fhc-primary-border-color {
|
||||
border-color: var(--fhc-primary) !important;
|
||||
}
|
||||
|
||||
.fhc-primary-highlight-bg {
|
||||
background-color: var(--fhc-primary-highlight) !important;
|
||||
}
|
||||
@@ -857,67 +853,4 @@ html {
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
#coodleParticipantsSearchResults {
|
||||
background-color: var(--fhc-background);
|
||||
border: 1px solid var(--fhc-border);
|
||||
}
|
||||
.coodleParticipantSearchResult:hover {
|
||||
opacity: 80%;
|
||||
}
|
||||
|
||||
.coodleCalendarTimeslotCard:hover {
|
||||
background-color: var(--fhc-background);
|
||||
}
|
||||
|
||||
.coodlePrimaryHover:hover {
|
||||
color: var(--fhc-primary);
|
||||
}
|
||||
|
||||
#coodleCalendar .fhc-calendar-base .part-body {
|
||||
z-index: 1 !important;
|
||||
}
|
||||
|
||||
#coodleCalendar .fhc-calendar-base .fhc-calendar-base-grid-line-background {
|
||||
z-index: 1 !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#coodleCalendar .fhc-calendar-base-grid-line-event {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#coodleCalendar .coodle-calendar-event-clear {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#freeBusyTable th {
|
||||
background-color: var(--fhc-primary) !important;
|
||||
color: var(--fhc-light) !important;
|
||||
}
|
||||
|
||||
#freeBusyTable .action:hover {
|
||||
opacity:80%;
|
||||
}
|
||||
|
||||
.fhcPrimaryHover:hover {
|
||||
color: var(--fhc-primary);
|
||||
}
|
||||
|
||||
.fhcPrimaryBorderHover:hover {
|
||||
border-color: var(--fhc-primary) !important;
|
||||
}
|
||||
|
||||
button.tabulator-page {
|
||||
background-color: var(--fhc-primary) !important;
|
||||
color: var(--fhc-light) !important;
|
||||
}
|
||||
|
||||
button.tabulator-page:hover {
|
||||
opacity: 90%;
|
||||
}
|
||||
|
||||
button.tabulator-page.active {
|
||||
border: solid 2px var(--fhc-primary) !important;
|
||||
}
|
||||
@@ -107,4 +107,9 @@
|
||||
|
||||
.gesperrtoption {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
#onboardingRow
|
||||
{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2026 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
searchParticipants(searchString) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/searchParticipants",
|
||||
params: {
|
||||
searchString,
|
||||
},
|
||||
};
|
||||
},
|
||||
createSurvey(surveyData) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/createSurvey",
|
||||
params: {
|
||||
surveyData,
|
||||
},
|
||||
};
|
||||
},
|
||||
updateSurvey(surveyId, surveyData, shouldInformParticipants) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/updateSurvey",
|
||||
params: {
|
||||
surveyId,
|
||||
surveyData,
|
||||
shouldInformParticipants,
|
||||
},
|
||||
};
|
||||
},
|
||||
getSurvey(surveyId) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/getSurvey",
|
||||
params: {
|
||||
surveyId,
|
||||
},
|
||||
};
|
||||
},
|
||||
getSurveyForExternalParticipant(surveyId, accessKey) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/getSurveyForExternalParticipant",
|
||||
params: {
|
||||
surveyId,
|
||||
accessKey,
|
||||
},
|
||||
};
|
||||
},
|
||||
getActiveSurveys() {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/getActiveSurveys",
|
||||
};
|
||||
},
|
||||
getInactiveSurveys() {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/getInactiveSurveys",
|
||||
};
|
||||
},
|
||||
submitParticipantSelection(surveyId, selection) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/submitParticipantSelection",
|
||||
params: {
|
||||
surveyId,
|
||||
selection,
|
||||
},
|
||||
};
|
||||
},
|
||||
submitExternalParticipantSelection(surveyId, accessKey, selection) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/submitExternalParticipantSelection",
|
||||
params: {
|
||||
surveyId,
|
||||
accessKey,
|
||||
selection,
|
||||
},
|
||||
};
|
||||
},
|
||||
cancelSurvey(surveyId) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/cancelSurvey",
|
||||
params: {
|
||||
surveyId,
|
||||
},
|
||||
};
|
||||
},
|
||||
completeSurvey(surveyId, selectedTimeslotId, selectedRoomId) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/completeSurvey",
|
||||
params: {
|
||||
surveyId,
|
||||
selectedTimeslotId,
|
||||
selectedRoomId,
|
||||
},
|
||||
};
|
||||
},
|
||||
sendReminders(surveyId) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/sendVotingReminders",
|
||||
params: {
|
||||
surveyId,
|
||||
},
|
||||
};
|
||||
},
|
||||
getCoodleIcalLink() {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/getCoodleIcalUrl",
|
||||
};
|
||||
},
|
||||
emailParticipants(surveyId, emailType, additionalData = null) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/emailParticipants",
|
||||
params: {
|
||||
surveyId,
|
||||
emailType,
|
||||
additionalData,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2026 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
getFreeBusyEntries() {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/coodle/FreeBusy/getFreeBusyEntries",
|
||||
};
|
||||
},
|
||||
createFreeBusyEntry(params) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/FreeBusy/createFreeBusyEntry",
|
||||
params,
|
||||
};
|
||||
},
|
||||
updateFreeBusyEntry(params) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/FreeBusy/updateFreeBusyEntry",
|
||||
params,
|
||||
};
|
||||
},
|
||||
deleteFreeBusyEntry(id) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/FreeBusy/deleteFreeBusyEntry",
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
};
|
||||
},
|
||||
getFreeBusyTypes() {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/coodle/FreeBusy/getFreeBusyTypes",
|
||||
};
|
||||
},
|
||||
getFreeBusySchedule(uid, coodleSurveyIdToExclude) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/coodle/FreeBusy/getFreeBusySchedule",
|
||||
params: {
|
||||
uid,
|
||||
coodleSurveyIdToExclude
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -10,8 +10,6 @@ import Profil from "../../components/Cis/Profil/Profil.js";
|
||||
import Raumsuche from "../../components/Cis/Raumsuche/Raumsuche.js";
|
||||
import CmsNews from "../../components/Cis/Cms/News.js";
|
||||
import CmsContent from "../../components/Cis/Cms/Content.js";
|
||||
import Coodle from "../../components/Cis/Coodle/Coodle.js";
|
||||
import CoodleExternal from "../../components/Cis/Coodle/CoodleExternal.js";
|
||||
import Info from "../../components/Cis/Mylv/Semester/Studiengang/Lv/Info.js";
|
||||
import RoomInformation, {DEFAULT_MODE_RAUMINFO_DESKTOP, DEFAULT_MODE_RAUMINFO_MOBILE} from "../../components/Cis/Mylv/RoomInformation.js";
|
||||
import AbgabetoolStudent from "../../components/Cis/Abgabetool/AbgabetoolStudent.js";
|
||||
@@ -221,18 +219,6 @@ const router = VueRouter.createRouter({
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
path: `/Cis/Coodle`,
|
||||
name: 'Coodle',
|
||||
component: Coodle,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: `/Cis/CoodleExternal/:surveyId/:accessKey`,
|
||||
name: 'CoodleExternal',
|
||||
component: CoodleExternal,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: `/Cis4`,
|
||||
name: 'Cis4',
|
||||
|
||||
@@ -9,7 +9,7 @@ const app = Vue.createApp({
|
||||
name: 'CisMenuApp',
|
||||
components: {
|
||||
FhcSearchbar,
|
||||
CisMenu,
|
||||
CisMenu
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
|
||||
@@ -44,10 +44,7 @@ export default {
|
||||
return () => true;
|
||||
}),
|
||||
hasDragoverFunc: Vue.computed(() => this.onDragover),
|
||||
mode: Vue.computed(() => this.mode),
|
||||
isAutoScrollEnabled: Vue.computed(
|
||||
() => this.$props.isAutoScrollEnabled,
|
||||
),
|
||||
mode: Vue.computed(() => this.mode)
|
||||
};
|
||||
},
|
||||
props: {
|
||||
@@ -100,11 +97,7 @@ export default {
|
||||
draggableEvents: [Boolean, Array, Function],
|
||||
dropableEvents: [Boolean, Array, Function],
|
||||
onDragover: Function,
|
||||
onDrop: Function,
|
||||
isAutoScrollEnabled: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
onDrop: Function
|
||||
},
|
||||
emits: [
|
||||
"click:next",
|
||||
@@ -116,8 +109,7 @@ export default {
|
||||
"update:date",
|
||||
"update:mode",
|
||||
"update:range",
|
||||
"drop",
|
||||
"emptyClicked",
|
||||
"drop"
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
@@ -301,7 +293,6 @@ export default {
|
||||
@update:range="$emit('update:range', $event)"
|
||||
@request-modal-open="showEventModal"
|
||||
@request-modal-close="hideEventModal"
|
||||
@emptyClicked="$emit('emptyClicked', $event)"
|
||||
v-bind="modeOptions ? modeOptions[cMode] : null || {}"
|
||||
>
|
||||
<template v-slot="slot"><slot v-bind="slot" /></template>
|
||||
|
||||
@@ -2,7 +2,6 @@ import GridLine from './Grid/Line.js';
|
||||
import GridLineEvent from './Grid/Line/Event.js';
|
||||
|
||||
import CalDnd from '../../../directives/Calendar/DragAndDrop.js';
|
||||
import CalClick from '../../../directives/Calendar/Click.js';
|
||||
|
||||
export default {
|
||||
name: "CalendarGrid",
|
||||
@@ -11,13 +10,12 @@ export default {
|
||||
GridLineEvent
|
||||
},
|
||||
directives: {
|
||||
CalDnd,
|
||||
CalDnd
|
||||
},
|
||||
inject: {
|
||||
originalEvents: "events",
|
||||
originalBackgrounds: "backgrounds",
|
||||
dropAllowed: "dropAllowed",
|
||||
isAutoScrollEnabled: "isAutoScrollEnabled",
|
||||
dropAllowed: "dropAllowed"
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
@@ -269,10 +267,6 @@ export default {
|
||||
|
||||
/* SCROLLING */
|
||||
enableAutoScroll() {
|
||||
if (!this.isAutoScrollEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.resizeObserver)
|
||||
this.resizeObserver = new ResizeObserver(this.scrollToEarliestEvent);
|
||||
this.resizeObserver.observe(this.$refs.body);
|
||||
@@ -405,7 +399,7 @@ export default {
|
||||
style="position:relative"
|
||||
:style="'grid-' + axisCol + ':' + (1+index) + ';grid-' + axisRow + ':ps_' + i + '/pe_' + i"
|
||||
>
|
||||
<slot name="part-body" v-bind="{ index, part, date }" />
|
||||
<slot name="part-body" v-bind="{ index, part }" />
|
||||
<div
|
||||
v-if="snapToGrid && dragging"
|
||||
style="position:absolute;inset:0;z-index:1"
|
||||
|
||||
@@ -144,13 +144,6 @@ export default {
|
||||
<template #part-header="{ part }">
|
||||
<label-time v-bind="{ part }" />
|
||||
</template>
|
||||
<template #part-body="params">
|
||||
<slot name="part-body">
|
||||
<div
|
||||
@click="$emit('emptyClicked', { event: $event, params })"
|
||||
class="position-absolute h-100 w-100"></div>
|
||||
</slot>
|
||||
</template>
|
||||
<template #event="slot">
|
||||
<div v-if="slot.event.type == 'loading'" class="placeholder-glow h-100 opacity-50">
|
||||
<span class="placeholder w-100 h-100" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import CalendarGrid from "../../Base/Grid.js";
|
||||
import LabelDay from "../../Base/Label/Day.js";
|
||||
import LabelDow from "../../Base/Label/Dow.js";
|
||||
import LabelTime from "../../Base/Label/Time.js";
|
||||
import CalendarGrid from '../../Base/Grid.js';
|
||||
import LabelDay from '../../Base/Label/Day.js';
|
||||
import LabelDow from '../../Base/Label/Dow.js';
|
||||
import LabelTime from '../../Base/Label/Time.js';
|
||||
|
||||
export default {
|
||||
name: "WeekView",
|
||||
@@ -9,54 +9,47 @@ export default {
|
||||
CalendarGrid,
|
||||
LabelDay,
|
||||
LabelDow,
|
||||
LabelTime,
|
||||
LabelTime
|
||||
},
|
||||
inject: {
|
||||
timeGrid: "timeGrid",
|
||||
timezone: "timezone",
|
||||
timezone: "timezone"
|
||||
},
|
||||
props: {
|
||||
day: {
|
||||
type: luxon.DateTime,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
collapseEmptyDays: Boolean,
|
||||
collapseEmptyDays: Boolean
|
||||
},
|
||||
computed: {
|
||||
start() {
|
||||
return this.day.startOf("week", { useLocaleWeeks: true });
|
||||
return this.day.startOf('week', { useLocaleWeeks: true });
|
||||
},
|
||||
axisMain() {
|
||||
return Array.from({ length: 7 }, (e, i) =>
|
||||
this.start.plus({ days: i }),
|
||||
);
|
||||
return Array.from({ length: 7 }, (e, i) => this.start.plus({ days: i }));
|
||||
},
|
||||
axisParts() {
|
||||
if (this.timeGrid) {
|
||||
// create {start, end} array
|
||||
return this.timeGrid.map((tu) => {
|
||||
return this.timeGrid.map(tu => {
|
||||
return {
|
||||
start: luxon.Duration.fromISOTime(tu.start),
|
||||
end: luxon.Duration.fromISOTime(tu.end),
|
||||
end: luxon.Duration.fromISOTime(tu.end)
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// create 07:00-23:00
|
||||
return Array.from({ length: 17 }, (e, i) =>
|
||||
luxon.Duration.fromObject({ hours: i + 7 }),
|
||||
);
|
||||
return Array.from({ length: 17 }, (e, i) => luxon.Duration.fromObject({ hours: i + 7 }));
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isToday(date) {
|
||||
return date.hasSame(
|
||||
luxon.DateTime.now().setZone(this.timezone),
|
||||
"day",
|
||||
);
|
||||
},
|
||||
return date.hasSame(luxon.DateTime.now().setZone(this.timezone), 'day');
|
||||
}
|
||||
},
|
||||
template: /* html */ `
|
||||
template: /* html */`
|
||||
<div class="fhc-calendar-mode-week-view h-100">
|
||||
<calendar-grid
|
||||
ref="grid"
|
||||
@@ -80,13 +73,6 @@ export default {
|
||||
<template #part-header="{ part }">
|
||||
<label-time v-bind="{ part }" />
|
||||
</template>
|
||||
<template #part-body="params">
|
||||
<slot name="part-body">
|
||||
<div
|
||||
@click="$emit('emptyClicked', { event: $event, params })"
|
||||
class="position-absolute h-100 w-100"></div>
|
||||
</slot>
|
||||
</template>
|
||||
<template #event="slot">
|
||||
<div v-if="slot.event.type == 'loading'" class="placeholder-glow h-100 opacity-50">
|
||||
<span class="placeholder w-100 h-100" />
|
||||
@@ -95,5 +81,5 @@ export default {
|
||||
</template>
|
||||
</calendar-grid>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
`
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
import { CoreFilterCmpt } from "../../../filter/Filter.js";
|
||||
|
||||
import { dateFilter } from "../../../../tabulator/filters/Dates.js";
|
||||
import CoodleApi from "../../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "ActiveCoodleSurveys",
|
||||
components: { CoreFilterCmpt },
|
||||
emits: ["showSurveyDetails"],
|
||||
data() {
|
||||
return {
|
||||
activeSurveys: [],
|
||||
activeSurveysTableConfig: {
|
||||
persistenceID: "activeSurveysTable",
|
||||
minHeight: 300,
|
||||
movableColumns: false,
|
||||
layout: "fitColumns",
|
||||
initialSort: [{ column: "createdAt", dir: "desc" }],
|
||||
locale: true,
|
||||
pagination: true,
|
||||
paginationSize: 25,
|
||||
paginationCounter: "rows",
|
||||
columns: [
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/title",
|
||||
field: "title",
|
||||
headerFilter: true,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/creator",
|
||||
field: "creatorName",
|
||||
headerFilter: true,
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/started_on",
|
||||
field: "createdAt",
|
||||
headerFilter: true,
|
||||
minWidth: 100,
|
||||
formatter: "datetime",
|
||||
formatterParams: this.datetimeFormatterParams(),
|
||||
headerFilterFunc: "dates",
|
||||
headerFilter: dateFilter,
|
||||
},
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/ends_on",
|
||||
field: "endsAt",
|
||||
headerFilter: true,
|
||||
minWidth: 100,
|
||||
formatter: "datetime",
|
||||
formatterParams: this.datetimeFormatterParams(),
|
||||
headerFilterFunc: "dates",
|
||||
headerFilter: dateFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
isFetchingSurveys: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async fetchActiveSurveys() {
|
||||
this.isFetchingSurveys = true;
|
||||
const surveysResponse = await this.$api.call(
|
||||
CoodleApi.getActiveSurveys(),
|
||||
);
|
||||
this.isFetchingSurveys = false;
|
||||
|
||||
if (surveysResponse.meta.status !== "success") return;
|
||||
|
||||
this.activeSurveys = surveysResponse.data.map((surveyData) => {
|
||||
return {
|
||||
id: surveyData.id,
|
||||
title: surveyData.title,
|
||||
endsAt: surveyData.ends_at.split(".")[0],
|
||||
createdAt: surveyData.created_at.split(".")[0],
|
||||
creator: {
|
||||
uid: surveyData.creator.uid,
|
||||
name: surveyData.creator.name,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
this.activeSurveysTableConfig.data = this.activeSurveys.map(
|
||||
(survey) => {
|
||||
return {
|
||||
id: survey.id,
|
||||
title: survey.title,
|
||||
creatorName: survey.creator.name,
|
||||
createdAt: survey.createdAt,
|
||||
endsAt: survey.endsAt,
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
afterActiveSurveysTableBuilt() {
|
||||
this.$refs.activeSurveysTable.tabulator.on(
|
||||
"rowClick",
|
||||
(event, row) => {
|
||||
this.$emit("showSurveyDetails", {
|
||||
surveyId: row._row.data.id,
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
datetimeFormatterParams: function () {
|
||||
const params = {
|
||||
inputFormat: "yyyy-MM-dd hh:mm:ss",
|
||||
outputFormat: "dd.MM.yyyy",
|
||||
invalidPlaceholder: "(invalid date)",
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
return params;
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.fetchActiveSurveys();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="card mb-4" style="height:100%">
|
||||
<div class="card-body">
|
||||
<div
|
||||
v-if="isFetchingSurveys"
|
||||
class="d-flex justify-content-center align-items-center mt-5"
|
||||
>
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">{{ $p.t("coodle/loading") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="!activeSurveys?.length"
|
||||
class="d-flex justify-content-center align-items-center mt-5"
|
||||
>
|
||||
<h3 class="fw-bold">{{ $p.t("coodle/no_active_surveys_found") }}</h3>
|
||||
</div>
|
||||
<div v-else class="d-flex flex-row overflow-x-auto">
|
||||
<div class="flex-shrink">
|
||||
<core-filter-cmpt
|
||||
@tableBuilt="afterActiveSurveysTableBuilt()"
|
||||
:noColumnFilter="true"
|
||||
:title="'Active surveys'"
|
||||
:ref="'activeSurveysTable'"
|
||||
:tabulatorOptions="activeSurveysTableConfig"
|
||||
:sideMenu="false"
|
||||
tableOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,213 +0,0 @@
|
||||
import CoodleFreeBusyTableFormRow from "./CoodleFreeBusy/CoodleFreeBusyTableFormRow.js";
|
||||
|
||||
import FreeBusyApi from "../../../../api/factory/freeBusy.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleFreeBusy",
|
||||
components: { CoodleFreeBusyTableFormRow },
|
||||
props: {
|
||||
authUid: Number | null,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columnHeaders: [],
|
||||
defaultSchedules: [
|
||||
{
|
||||
description: this.$p.t("coodle/freebusy_personal_schedule"),
|
||||
type: this.$p.t("coodle/schedule"),
|
||||
},
|
||||
{
|
||||
description: this.$p.t("coodle/freebusy_planned_absences"),
|
||||
type: this.$p.t("coodle/absences"),
|
||||
},
|
||||
],
|
||||
externalSchedules: [],
|
||||
scheduleEditIndex: null,
|
||||
scheduleFormData: null,
|
||||
scheduleTypes: [],
|
||||
isSubmittingScheduleForm: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getScheduleTypeText(value) {
|
||||
let type = this.scheduleTypes.find((type) => type.value === value);
|
||||
return type?.text ?? "Other";
|
||||
},
|
||||
openScheduleForm(index) {
|
||||
this.scheduleEditIndex = index;
|
||||
this.setScheduleFormData(
|
||||
index >= 0 ? this.externalSchedules[index] : null,
|
||||
);
|
||||
},
|
||||
closeScheduleForm() {
|
||||
this.scheduleEditIndex = null;
|
||||
},
|
||||
setScheduleFormData(schedule) {
|
||||
if (schedule) {
|
||||
this.scheduleFormData = { ...schedule };
|
||||
} else {
|
||||
this.scheduleFormData = {
|
||||
id: null,
|
||||
description: "",
|
||||
type: null,
|
||||
url: "",
|
||||
isActive: true,
|
||||
};
|
||||
}
|
||||
},
|
||||
async submitScheduleForm() {
|
||||
if (this.isSubmittingScheduleForm) return;
|
||||
|
||||
const response = await this.$api.call(
|
||||
this.scheduleFormData.id
|
||||
? FreeBusyApi.updateFreeBusyEntry(this.scheduleFormData)
|
||||
: FreeBusyApi.createFreeBusyEntry(this.scheduleFormData),
|
||||
);
|
||||
|
||||
if (response.meta.status === "success") {
|
||||
this.closeScheduleForm();
|
||||
this.getFreeBusySchedules();
|
||||
}
|
||||
},
|
||||
async deleteSchedule(schedule) {
|
||||
if (!schedule?.id) return;
|
||||
|
||||
const scheduleRemovalConfirmation = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/removal_confirmation"),
|
||||
message:
|
||||
this.$p.t("coodle/freebusy_removal_confirmation_message"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("ui/abbrechen"),
|
||||
});
|
||||
if (!scheduleRemovalConfirmation) return;
|
||||
|
||||
const scheduleDeletionResponse = await this.$api.call(
|
||||
FreeBusyApi.deleteFreeBusyEntry(schedule.id),
|
||||
);
|
||||
if (scheduleDeletionResponse.meta.status === "success") {
|
||||
this.getFreeBusySchedules();
|
||||
}
|
||||
},
|
||||
async getFreeBusyTypes() {
|
||||
const freeBusyTypesResponse = await this.$api.call(
|
||||
FreeBusyApi.getFreeBusyTypes(),
|
||||
);
|
||||
this.scheduleTypes = freeBusyTypesResponse.data.map((type) => {
|
||||
return {
|
||||
value: type.freebusytyp_kurzbz,
|
||||
text: type.bezeichnung,
|
||||
urlDefault: type.url_default,
|
||||
};
|
||||
});
|
||||
},
|
||||
async getFreeBusySchedules() {
|
||||
const freeBusyEntriesResponse = await this.$api.call(
|
||||
FreeBusyApi.getFreeBusyEntries(),
|
||||
);
|
||||
this.externalSchedules = freeBusyEntriesResponse.data.map(
|
||||
(freeBusySchedule) => {
|
||||
return {
|
||||
id: freeBusySchedule.freebusy_id,
|
||||
description: freeBusySchedule.bezeichnung,
|
||||
type: freeBusySchedule.freebusytyp_kurzbz,
|
||||
url: freeBusySchedule.url,
|
||||
isActive: freeBusySchedule.aktiv,
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.getFreeBusyTypes();
|
||||
await this.getFreeBusySchedules();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="card" style="min-height:100%">
|
||||
<div class="card-header">
|
||||
<h4>{{ $p.t("coodle/freebusy_settings") }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<span>
|
||||
{{ $p.t("coodle/freebusy_explainer") }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table id="freeBusyTable" style="min-width:100%;">
|
||||
<tr>
|
||||
<th class="border-1 py-1 px-2 fw-bold">{{ $p.t("coodle/description") }}</th>
|
||||
<th class="border-1 py-1 px-2 fw-bold">{{ $p.t("coodle/type") }}</th>
|
||||
<th class="border-1 py-1 px-2 fw-bold" style="width: 50%;">{{ "URL" }}</th>
|
||||
<th class="border-1 py-1 px-2 fw-bold">{{ $p.t("coodle/active") }}</th>
|
||||
<th class="border-1 py-1 px-2 fw-bold">{{ $p.t("coodle/actions") }}</th>
|
||||
</tr>
|
||||
<tr v-for="defaultSchedule in defaultSchedules">
|
||||
<td class="border-1 py-1 px-2">{{ defaultSchedule.description }}</td>
|
||||
<td class="border-1 py-1 px-2">{{ defaultSchedule.type }}</td>
|
||||
<td class="border-1 py-1 px-2"></td>
|
||||
<td class="border-1 py-1 px-2">{{ $p.t("coodle/yes") }}</td>
|
||||
<td class="border-1 py-1 px-2"></td>
|
||||
</tr>
|
||||
<template v-for="(schedule, index) in externalSchedules">
|
||||
<tr v-if="scheduleEditIndex !== index">
|
||||
<td class="border-1 py-1 px-2">{{ schedule.description }}</td>
|
||||
<td class="border-1 py-1 px-2">{{ getScheduleTypeText(schedule.type) }}</td>
|
||||
<td class="border-1 py-1 px-2">{{ schedule.url }}</td>
|
||||
<td class="border-1 py-1 px-2">{{ schedule.isActive ? $p.t("coodle/yes") : $p.t("coodle/no") }}</td>
|
||||
<td class="border-1 py-1 px-2">
|
||||
<div class="w-100 d-flex flex-row gap-1 align-items-center justify-content-evenly">
|
||||
<div
|
||||
@click="openScheduleForm(index)"
|
||||
:title="$p.t('coodle/edit')"
|
||||
type="button"
|
||||
class="action py-1 px-1"
|
||||
>
|
||||
<i class="fa-solid fa-pen-to-square"></i>
|
||||
</div>
|
||||
<div
|
||||
@click="deleteSchedule(schedule)"
|
||||
:title="$p.t('global/loeschen')"
|
||||
type="button"
|
||||
class="action py-1 px-1"
|
||||
>
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<coodle-free-busy-table-form-row
|
||||
v-else
|
||||
v-model:scheduleFormDataModelValue="scheduleFormData"
|
||||
@cancelForm="closeScheduleForm()"
|
||||
@submitForm="submitScheduleForm()"
|
||||
:scheduleTypes="scheduleTypes"
|
||||
/>
|
||||
</template>
|
||||
<tr v-if="scheduleEditIndex !== -1">
|
||||
<td colspan="5" class="border-1">
|
||||
<div
|
||||
@click="openScheduleForm(-1)"
|
||||
type="button"
|
||||
class="action w-100 d-flex flex-row align-items-center justify-content-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-circle-plus fa-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<coodle-free-busy-table-form-row
|
||||
v-else
|
||||
v-model:scheduleFormDataModelValue="scheduleFormData"
|
||||
@cancelForm="closeScheduleForm()"
|
||||
@submitForm="submitScheduleForm()"
|
||||
:scheduleTypes="scheduleTypes"
|
||||
/>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
export default {
|
||||
name: "CoodleFreeBusyTableFormRow",
|
||||
props: {
|
||||
scheduleFormDataModelValue: Object,
|
||||
scheduleTypes: Array,
|
||||
},
|
||||
emits: ["update:scheduleFormDataModelValue", "submitForm", "cancelForm"],
|
||||
computed: {
|
||||
scheduleFormData: {
|
||||
get() {
|
||||
return this.$props.scheduleFormDataModelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit("update:scheduleFormDataModelValue", newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"scheduleFormData.type": {
|
||||
handler(newValue) {
|
||||
const type = this.$props.scheduleTypes.find(
|
||||
(type) => type.value === newValue,
|
||||
);
|
||||
if (!type || !type.urlDefault?.length) return;
|
||||
|
||||
this.scheduleFormData.url = type.urlDefault;
|
||||
},
|
||||
},
|
||||
},
|
||||
template: /*html*/ `
|
||||
<tr>
|
||||
<td class="border-1 py-2 px-2">
|
||||
<input
|
||||
v-model="scheduleFormData.description"
|
||||
id="scheduleDescriptionInput"
|
||||
type="text"
|
||||
maxlength="255"
|
||||
class="w-100"
|
||||
/>
|
||||
</td>
|
||||
<td class="border-1 py-2 px-2">
|
||||
<select v-model="scheduleFormData.type" id="scheduleTypeInput" class="w-100 h-100">
|
||||
<option value="null">{{ "--" + $p.t("global/waehlen") + "--" }}</option>
|
||||
<option v-for="type in $props.scheduleTypes" :value="type.value">{{ type.text }}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="border-1 py-2 px-2">
|
||||
<input
|
||||
v-model="scheduleFormData.url"
|
||||
id="scheduleUrlInput"
|
||||
type="text"
|
||||
maxlength="255"
|
||||
class="w-100"
|
||||
/>
|
||||
</td>
|
||||
<td class="border-1 py-2 px-2">
|
||||
<div class="d-flex flex-row align-items-center justify-content-center">
|
||||
<input
|
||||
v-model="scheduleFormData.isActive"
|
||||
id="scheduleIsActiveInput"
|
||||
type="checkbox"
|
||||
style="height:15px; width:15px;"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-1 py-2 px-2">
|
||||
<div class="w-100 d-flex flex-row gap-1 align-items-center justify-content-evenly">
|
||||
<div @click="$emit('cancelForm')" :title="$p.t('ui/abbrechen')" type="button" class="action py-1 px-1">
|
||||
<i class="fa-solid fa-circle-left"></i>
|
||||
</div>
|
||||
<div @click="$emit('submitForm')" :title="$p.t('global/speichern')" type="button" class="action py-1 px-1">
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`,
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
import CoodleApi from "../../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleIcal",
|
||||
props: {
|
||||
authUid: String | null,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icalLink: "",
|
||||
encryptedIcalLink: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isDarkMode() {
|
||||
return this.$theme.theme_name.value == "dark";
|
||||
},
|
||||
link() {
|
||||
return this.icalLink;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getIcalLink() {
|
||||
const icalLinkResponse = await this.$api.call(CoodleApi.getCoodleIcalLink());
|
||||
if (icalLinkResponse.meta.status === "success") {
|
||||
this.icalLink = icalLinkResponse.data.unencryptedUrl;
|
||||
this.encryptedIcalLink = icalLinkResponse.data.encryptedUrl;
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.getIcalLink();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="card" style="min-height:100%">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<span>
|
||||
{{ $p.t("coodle/ical_explainer") }}
|
||||
</span>
|
||||
<span>
|
||||
{{ $p.t("coodle/ical_unencrypted") + ": " }}
|
||||
<a v-if="icalLink?.length" :href="icalLink" target="_blank">{{ icalLink }}</a>
|
||||
</span>
|
||||
<span>
|
||||
{{ $p.t("coodle/ical_encrypted") + ": " }}
|
||||
<a v-if="encryptedIcalLink?.length" :href="encryptedIcalLink" target="_blank">{{ encryptedIcalLink }}</a>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,441 +0,0 @@
|
||||
import CoodleSurveyVotingTable from "./CoodleSurvey/CoodleSurveyVotingTable.js";
|
||||
import CoodleSurveyCalendar from "./CoodleSurvey/CoodleSurveyCalendar.js";
|
||||
import CoodleSurveyParticipants from "./CoodleSurvey/CoodleSurveyParticipants.js";
|
||||
import CoodleSurveyDurationSelector from "./CoodleSurvey/CoodleSurveyDurationSelector.js";
|
||||
import CoodleSurveyBasicInfo from "./CoodleSurvey/CoodleSurveyBasicInfo.js";
|
||||
import CoodleSurveyHeader from "./CoodleSurvey/CoodleSurveyHeader.js";
|
||||
|
||||
import { formatDate, numberPadding } from "../../../../helpers/DateHelpers.js";
|
||||
|
||||
import CoodleApi from "../../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurvey",
|
||||
components: {
|
||||
CoodleSurveyVotingTable,
|
||||
CoodleSurveyCalendar,
|
||||
CoodleSurveyParticipants,
|
||||
CoodleSurveyDurationSelector,
|
||||
CoodleSurveyBasicInfo,
|
||||
CoodleSurveyHeader,
|
||||
},
|
||||
props: {
|
||||
survey: { type: Object | null },
|
||||
authInfo: { type: Object | null },
|
||||
authExternalParticipantId: { type: Number | null },
|
||||
isExternal: { type: Boolean, default: false },
|
||||
},
|
||||
emits: [
|
||||
"surveyCreationCanceled",
|
||||
"surveyCreated",
|
||||
"surveyUpdated",
|
||||
"surveyCanceled",
|
||||
"surveyCompleted",
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
surveyFormData: null,
|
||||
participantScheduleColors: [
|
||||
{
|
||||
uid: null,
|
||||
color: "#FF0000",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#00FF00",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#0000FF",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#FF00FF",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#00FFFF",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#FFFF00",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#FFA500",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#800080",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#228B22",
|
||||
},
|
||||
{
|
||||
uid: null,
|
||||
color: "#B87333",
|
||||
},
|
||||
],
|
||||
isEditInProgress: false,
|
||||
weekdayPhrases: [
|
||||
"global/monday",
|
||||
"global/tuesday",
|
||||
"global/wednesday",
|
||||
"global/thursday",
|
||||
"global/friday",
|
||||
"global/saturday",
|
||||
"global/sunday",
|
||||
],
|
||||
monthPhrases: [
|
||||
"global/january",
|
||||
"global/february",
|
||||
"global/march",
|
||||
"global/april",
|
||||
"global/may",
|
||||
"global/june",
|
||||
"global/july",
|
||||
"global/august",
|
||||
"global/september",
|
||||
"global/october",
|
||||
"global/november",
|
||||
"global/december",
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isDarkMode() {
|
||||
return this.$theme.theme_name.value == "dark";
|
||||
},
|
||||
parsedSelectedTimeslot() {
|
||||
if (!this.$props.survey?.selectedTimeslotId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const selectedTimeslot = this.$props.survey.timeslots.find(
|
||||
(timeslot) =>
|
||||
timeslot.id === this.$props.survey.selectedTimeslotId,
|
||||
);
|
||||
if (!selectedTimeslot) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.parseTimeslotForDisplay(selectedTimeslot);
|
||||
},
|
||||
parsedTimeslotsForVotingTable() {
|
||||
return (
|
||||
this.$props.survey?.timeslots
|
||||
.sort((timeslotA, timeslotB) => {
|
||||
return timeslotA.startsAt < timeslotB.startsAt ? -1 : 1;
|
||||
})
|
||||
.map((timeslot) =>
|
||||
this.parseTimeslotForDisplay(timeslot),
|
||||
) ?? []
|
||||
);
|
||||
},
|
||||
weekdays() {
|
||||
return this.weekdayPhrases.map((phrase) => this.$p.t(phrase));
|
||||
},
|
||||
months() {
|
||||
return this.monthPhrases.map((phrase) => this.$p.t(phrase));
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
survey: {
|
||||
async handler() {
|
||||
this.setSurveyFormData();
|
||||
if (!this.$props.survey?.id) {
|
||||
this.isEditInProgress = true;
|
||||
} else {
|
||||
this.isEditInProgress = false;
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
isEditInProgress() {
|
||||
if (!this.isEditInProgress) {
|
||||
this.setSurveyFormData();
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setSurveyFormData() {
|
||||
if (this.$props.survey) {
|
||||
this.surveyFormData = { ...this.$props.survey };
|
||||
} else {
|
||||
let defaultEndsAtDate = new Date();
|
||||
defaultEndsAtDate.setDate(defaultEndsAtDate.getDate() + 7);
|
||||
|
||||
this.surveyFormData = {
|
||||
id: null,
|
||||
creator: null,
|
||||
title: "",
|
||||
description: "",
|
||||
timeslotDuration: 60,
|
||||
maxSelections: 1,
|
||||
areParticipantsAnonymized: false,
|
||||
areSelectionsAnonymized: false,
|
||||
selectedTimeslot: null,
|
||||
endsAt: defaultEndsAtDate.toISOString().slice(0, 10),
|
||||
completedAt: null,
|
||||
canceledAt: null,
|
||||
updatedAt: null,
|
||||
createdAt: null,
|
||||
timeslots: [],
|
||||
participants: [],
|
||||
externalParticipants: [],
|
||||
};
|
||||
}
|
||||
|
||||
this.surveyFormData.participants.forEach((participant) => {
|
||||
participant.isCalendarShown = false;
|
||||
});
|
||||
|
||||
this.participantScheduleColors.forEach((participantColor) => {
|
||||
participantColor.uid = null;
|
||||
});
|
||||
},
|
||||
parseTimeslotForDisplay(timeslot) {
|
||||
const timeslotStartsAt = new Date(timeslot.startsAt);
|
||||
let timeslotEndsAt = new Date(timeslot.startsAt);
|
||||
timeslotEndsAt.setMinutes(
|
||||
timeslotEndsAt.getMinutes() +
|
||||
(this.$props.survey?.timeslotDuration ?? 0),
|
||||
);
|
||||
|
||||
return {
|
||||
id: timeslot.id,
|
||||
weekday: this.weekdays[timeslotStartsAt.getDay()],
|
||||
date: numberPadding(timeslotStartsAt.getDate()),
|
||||
month: this.months[timeslotStartsAt.getMonth()],
|
||||
year: timeslotStartsAt.getFullYear().toString(),
|
||||
fullDate: formatDate(timeslot.startsAt + " UTC"),
|
||||
startTime:
|
||||
numberPadding(timeslotStartsAt.getHours()) +
|
||||
":" +
|
||||
numberPadding(timeslotStartsAt.getMinutes()),
|
||||
endTime:
|
||||
numberPadding(timeslotEndsAt.getHours()) +
|
||||
":" +
|
||||
numberPadding(timeslotEndsAt.getMinutes()),
|
||||
startsAt: timeslotStartsAt,
|
||||
endsAt: timeslotEndsAt,
|
||||
};
|
||||
},
|
||||
cancelEditForm() {
|
||||
this.isEditInProgress = false;
|
||||
if (!this.$props.survey?.id) {
|
||||
this.$emit("surveyCreationCanceled");
|
||||
}
|
||||
},
|
||||
async submitForm() {
|
||||
if (
|
||||
!this.surveyFormData.participants.length &&
|
||||
!this.surveyFormData.externalParticipants.length
|
||||
) {
|
||||
const shouldProceedWithoutParticipants =
|
||||
await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/warning"),
|
||||
message: this.$p.t("coodle/no_participants_added"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("ui/abbrechen"),
|
||||
});
|
||||
if (!shouldProceedWithoutParticipants) return;
|
||||
}
|
||||
|
||||
if (!this.surveyFormData.timeslots.length) {
|
||||
const shouldProceedWithoutTimeslots =
|
||||
await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/warning"),
|
||||
message: this.$p.t("coodle/no_timeslots_added"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("ui/abbrechen"),
|
||||
});
|
||||
if (!shouldProceedWithoutTimeslots) return;
|
||||
}
|
||||
|
||||
let surveyData = this.formatOutgoingSurveyData(this.surveyFormData);
|
||||
if (this.surveyFormData.id) {
|
||||
this.updateSurvey(surveyData);
|
||||
} else {
|
||||
this.createSurvey(surveyData);
|
||||
}
|
||||
},
|
||||
formatOutgoingSurveyData(surveyFormData) {
|
||||
let timeslotDuration = surveyFormData.timeslotDuration;
|
||||
if (!timeslotDuration || timeslotDuration < 5) {
|
||||
timeslotDuration = 5;
|
||||
} else if (timeslotDuration % 5 !== 0) {
|
||||
timeslotDuration = timeslotDuration - (timeslotDuration % 5);
|
||||
}
|
||||
|
||||
let maxSelections = surveyFormData.maxSelections;
|
||||
if (maxSelections < 1) {
|
||||
maxSelections = 1;
|
||||
}
|
||||
|
||||
const participants = surveyFormData.participants.map(
|
||||
(participant) => {
|
||||
return {
|
||||
uid: participant.uid,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
id: surveyFormData.id,
|
||||
title: surveyFormData.title.trim(),
|
||||
description: surveyFormData.description.trim(),
|
||||
timeslotDuration,
|
||||
maxSelections,
|
||||
areParticipantsAnonymized:
|
||||
surveyFormData.areParticipantsAnonymized,
|
||||
areSelectionsAnonymized: surveyFormData.areSelectionsAnonymized,
|
||||
endsAt: surveyFormData.endsAt,
|
||||
timeslots: surveyFormData.timeslots,
|
||||
participants,
|
||||
externalParticipants: surveyFormData.externalParticipants,
|
||||
};
|
||||
},
|
||||
async createSurvey(surveyData) {
|
||||
const shouldInformParticipants = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/inform_participants"),
|
||||
message: this.$p.t("coodle/email_participants_created"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
|
||||
const surveyCreationResponse = await this.$api.call(
|
||||
CoodleApi.createSurvey(surveyData),
|
||||
);
|
||||
if (surveyCreationResponse.meta.status === "success") {
|
||||
this.$emit("surveyCreated", {
|
||||
surveyId: surveyCreationResponse.data,
|
||||
shouldInformParticipants,
|
||||
});
|
||||
}
|
||||
},
|
||||
async updateSurvey(surveyData) {
|
||||
const shouldInformParticipants = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/inform_participants"),
|
||||
message: this.$p.t("coodle/email_participants_updated"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
|
||||
const surveyUpdateResponse = await this.$api.call(
|
||||
CoodleApi.updateSurvey(surveyData.id, surveyData),
|
||||
);
|
||||
if (surveyUpdateResponse.meta.status === "success") {
|
||||
this.$emit("surveyUpdated", {
|
||||
surveyId: surveyData.id,
|
||||
shouldInformParticipants,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setSurveyFormData();
|
||||
if (!this.$props.survey?.id) {
|
||||
this.isEditInProgress = true;
|
||||
}
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="card mb-4" style="min-height:100%">
|
||||
<div class="card-header">
|
||||
<coodle-survey-header
|
||||
@editSurvey="isEditInProgress = true"
|
||||
@surveyCanceled="
|
||||
$emit('surveyCanceled', {
|
||||
surveyId: $props.survey.id,
|
||||
shouldInformParticipants: $event.shouldInformParticipants
|
||||
})
|
||||
"
|
||||
:survey="$props.survey"
|
||||
:isEditInProgress="isEditInProgress"
|
||||
:authUid="$props.authInfo?.uid"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<div v-if="isEditInProgress" class="d-flex flex-row justify-content-between">
|
||||
<span class="fst-italic">
|
||||
{{ $p.t("coodle/required_inputs") }}
|
||||
</span>
|
||||
<div class="d-flex flex-row gap-2 justify-content-end align-items-start px-0">
|
||||
<div>
|
||||
<div
|
||||
@click="cancelEditForm()"
|
||||
:class="isDarkMode ? 'btn-outline-light' : 'btn-outline-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("ui/abbrechen") }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
@click="submitForm()"
|
||||
:class="isDarkMode ? 'btn-light' : 'btn-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("global/speichern") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<coodle-survey-basic-info
|
||||
v-model:surveyFormDataModelValue="surveyFormData"
|
||||
:survey="$props.survey"
|
||||
:parsedSelectedTimeslot="parsedSelectedTimeslot"
|
||||
:isEditInProgress="isEditInProgress"
|
||||
/>
|
||||
<hr>
|
||||
<div v-if="!isEditInProgress && $props.survey" class="d-flex flex-column gap-2">
|
||||
<coodle-survey-voting-table
|
||||
@selectionSubmitted="$emit('surveyUpdated', {surveyId: $props.survey.id})"
|
||||
@surveyCompleted="
|
||||
$emit('surveyCompleted',{
|
||||
surveyId: $props.survey.id,
|
||||
shouldInformParticipants: $event.shouldInformParticipants,
|
||||
selectedRoomId: $event.selectedRoomId
|
||||
})
|
||||
"
|
||||
:authUid="$props.authInfo?.uid"
|
||||
:timeslots="parsedTimeslotsForVotingTable"
|
||||
:survey="$props.survey"
|
||||
:authExternalParticipantId="$props.authExternalParticipantId"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="!$props.isExternal" class="d-flex flex-column gap-3">
|
||||
<div class="row">
|
||||
<div class="col-12 col-xxl-4 pb-3">
|
||||
<coodle-survey-participants
|
||||
v-if="surveyFormData?.participants"
|
||||
v-model:participantsModelValue="surveyFormData.participants"
|
||||
v-model:externalParticipantsModelValue="surveyFormData.externalParticipants"
|
||||
v-model:participantScheduleColorsModelValue="participantScheduleColors"
|
||||
:authInfo="authInfo"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-xxl-8">
|
||||
<div class="d-flex flex-column gap-4">
|
||||
<coodle-survey-duration-selector
|
||||
v-if="surveyFormData?.timeslotDuration"
|
||||
v-model:durationModelValue="surveyFormData.timeslotDuration"
|
||||
:survey="$props.survey"
|
||||
/>
|
||||
<coodle-survey-calendar
|
||||
v-model:timeslotsModelValue="surveyFormData.timeslots"
|
||||
:survey="$props.survey"
|
||||
:timeslotDuration="surveyFormData.timeslotDuration"
|
||||
:surveyFormDataParticipants="surveyFormData.participants"
|
||||
:participantScheduleColors="participantScheduleColors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`,
|
||||
};
|
||||
@@ -1,277 +0,0 @@
|
||||
import { formatDate } from "../../../../../helpers/DateHelpers.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurveyBasicInfo",
|
||||
props: {
|
||||
survey: Object | null,
|
||||
surveyFormDataModelValue: Object | null,
|
||||
parsedSelectedTimeslot: Object | null,
|
||||
isEditInProgress: Boolean,
|
||||
},
|
||||
emits: ["update:surveyFormDataModelValue"],
|
||||
computed: {
|
||||
formattedSurveyDescription() {
|
||||
return this.$props.survey?.description?.replaceAll("\n", "<br>");
|
||||
},
|
||||
formattedSurveyTimeslotDuration() {
|
||||
if (this.isNewSurvey) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const minutes = this.$props.survey.timeslotDuration % 60;
|
||||
const hours = (this.$props.survey.timeslotDuration - minutes) / 60;
|
||||
let formattedDuration = hours ? hours + " hr " : "";
|
||||
formattedDuration += minutes + " min";
|
||||
return formattedDuration;
|
||||
},
|
||||
formattedSurveyEndsAt() {
|
||||
if (this.$props.survey?.endsAt) {
|
||||
return formatDate(this.$props.survey.endsAt);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
formattedSurveyCreatedAt() {
|
||||
if (this.$props.survey?.createdAt) {
|
||||
return formatDate(this.$props.survey.createdAt);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
formattedSurveyUpdatedAt() {
|
||||
if (this.$props.survey?.updatedAt) {
|
||||
return formatDate(this.$props.survey.updatedAt);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
formattedSurveyCanceledAt() {
|
||||
if (this.$props.survey?.canceledAt) {
|
||||
return formatDate(this.$props.survey.canceledAt);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
formattedSurveyCompletedAt() {
|
||||
if (this.$props.survey?.completedAt) {
|
||||
return formatDate(this.$props.survey.completedAt);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
isNewSurvey() {
|
||||
return !this.$props.survey?.id;
|
||||
},
|
||||
surveyFormData: {
|
||||
get() {
|
||||
return this.$props.surveyFormDataModelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit("update:surveyFormDataModelValue", newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showCreatorProfile() {
|
||||
if (this.isNewSurvey || !this.survey?.creator?.uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const creatorHref = this.$router.resolve({
|
||||
name: "ProfilView",
|
||||
params: { uid: this.survey?.creator?.uid },
|
||||
}).href;
|
||||
window.open(creatorHref, "_blank");
|
||||
},
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<template v-if="!$props.isEditInProgress">
|
||||
<span v-if="$props.survey?.completedAt" class="fst-italic">
|
||||
{{
|
||||
$p.t("coodle/survey_completed_info").replace(
|
||||
'(((completedAt)))',
|
||||
formattedSurveyCompletedAt
|
||||
)
|
||||
}}
|
||||
<span v-if="$props.survey?.selectedTimeslotId">
|
||||
{{
|
||||
$p.t("coodle/selected_timeslot_info").replace(
|
||||
"(((timeslot)))",
|
||||
parsedSelectedTimeslot?.weekday +
|
||||
" " +
|
||||
parsedSelectedTimeslot?.fullDate +
|
||||
" " +
|
||||
parsedSelectedTimeslot?.startTime +
|
||||
"-" +
|
||||
parsedSelectedTimeslot?.endTime
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span v-else>{{ $p.t("coodle/no_selected_timeslot_info") }}</span>
|
||||
</span>
|
||||
<span v-else-if="$props.survey?.canceledAt" class="fst-italic">
|
||||
{{
|
||||
$p.t("coodle/survey_canceled_info").replace(
|
||||
'(((canceledAt)))',
|
||||
formattedSurveyCanceledAt
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<div class="d-flex flex-row gap-3 flex-wrap">
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-row justify-content-center align-items-center" style="width: 30px;">
|
||||
<i class="fa-solid fa-user fa-lg"></i>
|
||||
</div>
|
||||
<span>
|
||||
<span class="fw-bold">{{ $p.t("coodle/created_by") + ": " }}</span>
|
||||
{{ this.$props.survey?.creator?.name }}
|
||||
<span
|
||||
v-if="this.$props.survey?.creator?.uid"
|
||||
@click="showCreatorProfile()"
|
||||
type="button"
|
||||
class="fhc-primary-color"
|
||||
>
|
||||
<i class="fa-solid fa-up-right-from-square"></i>
|
||||
</span>
|
||||
{{ " " + $p.t("ui/am") + " " + formattedSurveyCreatedAt}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-row justify-content-center align-items-center" style="width: 30px;">
|
||||
<i class="fa-solid fa-calendar fa-lg"></i>
|
||||
</div>
|
||||
<span>
|
||||
<span class="fw-bold">{{ $p.t("coodle/planned_end_date") + ": " }}</span>
|
||||
{{ formattedSurveyEndsAt }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-row justify-content-center align-items-center" style="width: 30px;">
|
||||
<i class="fa-solid fa-clock fa-lg"></i>
|
||||
</div>
|
||||
<span>
|
||||
<span class="fw-bold">{{ $p.t("coodle/timeslot_duration") + ": " }}</span>
|
||||
{{ formattedSurveyTimeslotDuration }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-row justify-content-center align-items-center" style="width: 30px;">
|
||||
<i class="fa-solid fa-calendar-check fa-lg"></i>
|
||||
</div>
|
||||
<span>
|
||||
<span class="fw-bold">{{ $p.t("coodle/max_selectable_timeslots") + ": " }}</span>
|
||||
{{ $props.survey?.maxSelections}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-row justify-content-center align-items-center" style="width: 30px;">
|
||||
<i class="fa-solid fa-user-secret fa-lg"></i>
|
||||
</div>
|
||||
<span>
|
||||
<span class="fw-bold">{{ $p.t("coodle/anon_participants") + ": " }}</span>
|
||||
{{ $props.survey?.areParticipantsAnonymized ? $p.t("coodle/yes") : $p.t("coodle/no")}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-row justify-content-center align-items-center" style="width: 30px;">
|
||||
<i class="fa-solid fa-eye-slash fa-lg"></i>
|
||||
</div>
|
||||
<span>
|
||||
<span class="fw-bold">{{ $p.t("coodle/anon_votes") + ": " }}</span>
|
||||
{{ $props.survey?.areSelectionsAnonymized ? $p.t("coodle/yes") : $p.t("coodle/no") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
v-if="$props.survey?.description?.length"
|
||||
class="text-wrap fst-italic"
|
||||
v-html="formattedSurveyDescription"
|
||||
></span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="row">
|
||||
<div class="d-flex flex-column gap-2 col-12 col-md-6 pb-2">
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<label for="surveyTitleInput" class="fw-bold">{{ "* " + $p.t("coodle/title") }}</label>
|
||||
<input v-model="surveyFormData.title" id="surveyTitleInput" type="text" maxlength="255" />
|
||||
</div>
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<label for="surveyDescriptionInput" class="fw-bold">{{ $p.t("coodle/description") }}</label>
|
||||
<textarea v-model="surveyFormData.description" rows="4" class="flex-grow-1" maxlength="1000" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="row">
|
||||
<div class="col-12 col-xxl-6 pb-2">
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<label
|
||||
for="surveyMaxSelectionsInput"
|
||||
class="fw-bold text-wrap"
|
||||
>
|
||||
{{ $p.t("coodle/max_selectable_timeslots") }}
|
||||
</label>
|
||||
<input
|
||||
v-model="surveyFormData.maxSelections"
|
||||
id="surveyMaxSelectionsInput"
|
||||
type="number"
|
||||
min="1"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-xxl-6 pb-2">
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<label
|
||||
for="surveyEndsAtInput"
|
||||
class="fw-bold text-wrap"
|
||||
>
|
||||
{{ "* " + $p.t("coodle/planned_end_date") }}
|
||||
</label>
|
||||
<input
|
||||
v-model="surveyFormData.endsAt"
|
||||
id="surveyEndsAtInput"
|
||||
type="date"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-6 d-flex flex-row align-items-center gap-2 pb-2">
|
||||
<label
|
||||
for="surveyAreParticipantsAnonymizedInput"
|
||||
class="fw-bold text-wrap"
|
||||
>
|
||||
{{ $p.t("coodle/anon_participants") + "?" }}
|
||||
</label>
|
||||
<input
|
||||
v-model="surveyFormData.areParticipantsAnonymized"
|
||||
id="surveyAreParticipantsAnonymizedInput"
|
||||
type="checkbox"
|
||||
style="min-height:15px;min-width:15px;"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 d-flex flex-row align-items-center gap-2 pb-2">
|
||||
<label
|
||||
for="surveyAreSelectionsAnonymizedInput"
|
||||
class="fw-bold text-wrap"
|
||||
>
|
||||
{{ $p.t("coodle/anon_votes") + "?" }}
|
||||
</label>
|
||||
<input
|
||||
v-model="surveyFormData.areSelectionsAnonymized"
|
||||
id="surveyAreSelectionsAnonymizedInput"
|
||||
type="checkbox"
|
||||
style="min-height:15px;min-width:15px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,426 +0,0 @@
|
||||
import CoodleSurveyCalendarTimeslotCard from "./CoodleSurveyCalendar/CoodleSurveyCalendarTimeslotCard.js";
|
||||
import FhcCalendar from "../../../../Calendar/Base.js";
|
||||
import ModeWeek from "../../../../Calendar/Mode/Week.js";
|
||||
import ModeDay from "../../../../Calendar/Mode/Day.js";
|
||||
|
||||
import FreeBusyApi from "../../../../../api/factory/freeBusy.js";
|
||||
import { useRenderers } from "../../../../../composables/Renderers.js";
|
||||
import { numberPadding } from "../../../../../helpers/DateHelpers.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurveyCalendar",
|
||||
components: { CoodleSurveyCalendarTimeslotCard, FhcCalendar },
|
||||
props: {
|
||||
timeslotsModelValue: Array | null,
|
||||
survey: Object | null,
|
||||
surveyFormDataParticipants: Array,
|
||||
participantScheduleColors: Array,
|
||||
timeslotDuration: Number | null,
|
||||
renderers: [],
|
||||
},
|
||||
emits: ["update:timeslotsModelValue"],
|
||||
setup() {
|
||||
const { renderers } = useRenderers();
|
||||
|
||||
return {
|
||||
renderers,
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
isMobile: "isMobile",
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mode: "Week",
|
||||
modeOptions: {
|
||||
week: {
|
||||
collapseEmptyDays: false,
|
||||
},
|
||||
},
|
||||
timeslotCalendarEvents: [],
|
||||
participantSchedules: {},
|
||||
isTimeslotCardEditInProgress: false,
|
||||
renderers: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
timezone() {
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.timezone;
|
||||
},
|
||||
backgrounds() {
|
||||
let now = luxon.DateTime.now().setZone(this.timezone);
|
||||
|
||||
return [
|
||||
{
|
||||
class: "background-past",
|
||||
end: now,
|
||||
label: now.startOf("minute").toISOTime({
|
||||
suppressSeconds: true,
|
||||
includeOffset: false,
|
||||
}),
|
||||
},
|
||||
];
|
||||
},
|
||||
events() {
|
||||
let events = this.timeslotCalendarEvents;
|
||||
|
||||
const participantsWithDisplayedSchedules =
|
||||
this.$props.surveyFormDataParticipants.filter(
|
||||
(participant) => participant.isCalendarShown,
|
||||
);
|
||||
participantsWithDisplayedSchedules.forEach((participant) => {
|
||||
let participantEvents =
|
||||
this.participantSchedules[participant.uid] ?? [];
|
||||
participantEvents = participantEvents.map((event) => {
|
||||
event.farbe =
|
||||
this.$props.participantScheduleColors
|
||||
.find(
|
||||
(participantColor) =>
|
||||
participantColor.uid === participant.uid,
|
||||
)
|
||||
?.color.slice(1) ?? "DDDDDD";
|
||||
return event;
|
||||
});
|
||||
events = events.concat(participantEvents);
|
||||
});
|
||||
|
||||
return events;
|
||||
},
|
||||
roundedTimeslotDuration() {
|
||||
if (!this.$props.timeslotDuration) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
return (
|
||||
this.$props.timeslotDuration -
|
||||
(this.$props.timeslotDuration % 5)
|
||||
);
|
||||
},
|
||||
timeslots: {
|
||||
get() {
|
||||
return this.timeslotsModelValue;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("update:timeslotsModelValue", value);
|
||||
},
|
||||
},
|
||||
sortedTimeslotCalendarEvents() {
|
||||
return this.timeslotCalendarEvents.sort(
|
||||
(timeslotCalendarEventA, timeslotCalendarEventB) => {
|
||||
let timeslotAStartsAt =
|
||||
timeslotCalendarEventA.datum +
|
||||
timeslotCalendarEventA.beginn;
|
||||
let timeslotBStartsAt =
|
||||
timeslotCalendarEventB.datum +
|
||||
timeslotCalendarEventB.beginn;
|
||||
if (timeslotAStartsAt > timeslotBStartsAt) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
modes() {
|
||||
let modes = {
|
||||
day: Vue.markRaw(ModeDay),
|
||||
};
|
||||
if (!this.isMobile) {
|
||||
modes.week = Vue.markRaw(ModeWeek);
|
||||
}
|
||||
return modes;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
timeslotDuration: {
|
||||
handler() {
|
||||
this.updateDurationOfExistingTimeslotCalendarEvents();
|
||||
},
|
||||
},
|
||||
timeslotCalendarEvents: {
|
||||
handler() {
|
||||
let oldTimeslotStartTimes =
|
||||
this.$props.survey?.timeslots.map(
|
||||
(timeslot) => timeslot.startsAt,
|
||||
) ?? [];
|
||||
let updatedTimeslotStartTimes = this.timeslotCalendarEvents.map(
|
||||
(timeslotCalendarEvent) =>
|
||||
timeslotCalendarEvent.datum +
|
||||
" " +
|
||||
timeslotCalendarEvent.beginn,
|
||||
);
|
||||
|
||||
let updatedTimeslots =
|
||||
this.$props.survey?.timeslots.filter((timeslot) =>
|
||||
updatedTimeslotStartTimes.includes(timeslot.startsAt),
|
||||
) ?? [];
|
||||
|
||||
updatedTimeslotStartTimes.forEach((startTime) => {
|
||||
if (
|
||||
!updatedTimeslots.some(
|
||||
(timeslot) => timeslot.startsAt === startTime,
|
||||
)
|
||||
) {
|
||||
updatedTimeslots.push({
|
||||
id: null,
|
||||
startsAt: startTime,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.timeslots = updatedTimeslots;
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
survey: {
|
||||
handler() {
|
||||
this.setTimeslotCalendarEvents();
|
||||
this.participantSchedules = {};
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
surveyFormDataParticipants: {
|
||||
handler() {
|
||||
this.updateDisplayedSchedules();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setTimeslotCalendarEvents() {
|
||||
this.timeslotCalendarEvents =
|
||||
this.$props.survey?.timeslots.map((timeslot) => {
|
||||
let startDate = new Date(timeslot.startsAt);
|
||||
return this.generateTimeslotCalendarEvent(startDate);
|
||||
}) ?? [];
|
||||
},
|
||||
addTimeslotOnCalendarClick(event) {
|
||||
if (this.timeslotCalendarEvents.length >= 50) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elementRectangle = event.event.target.getBoundingClientRect();
|
||||
const relativeClickLocation = event.event.y - elementRectangle.top;
|
||||
let minutes =
|
||||
Math.floor(
|
||||
(relativeClickLocation / elementRectangle.height) * 12,
|
||||
) * 5;
|
||||
if (minutes < 0 || minutes > 55) {
|
||||
minutes = 0;
|
||||
}
|
||||
|
||||
let hours = event.params?.part?.values?.hours ?? 12;
|
||||
if (hours < 7 || hours > 22) {
|
||||
hours = 12;
|
||||
}
|
||||
|
||||
let start = new Date(event.params.date.ts);
|
||||
start.setHours(hours);
|
||||
start.setMinutes(minutes);
|
||||
|
||||
let newTimeslotCalendarEvent =
|
||||
this.generateTimeslotCalendarEvent(start);
|
||||
|
||||
if (
|
||||
this.timeslotCalendarEvents.some(
|
||||
(timeslotCalendarEvent) =>
|
||||
timeslotCalendarEvent.isostart ===
|
||||
newTimeslotCalendarEvent.isostart,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.timeslotCalendarEvents.push(newTimeslotCalendarEvent);
|
||||
},
|
||||
generateTimeslotCalendarEvent(start) {
|
||||
let end = new Date(start.getTime());
|
||||
end.setMinutes(end.getMinutes() + this.roundedTimeslotDuration);
|
||||
|
||||
return {
|
||||
type: "coodle",
|
||||
datum: start.toISOString().slice(0, 10),
|
||||
beginn:
|
||||
numberPadding(start.getHours()) +
|
||||
":" +
|
||||
numberPadding(start.getMinutes()) +
|
||||
":00",
|
||||
ende:
|
||||
numberPadding(end.getHours()) +
|
||||
":" +
|
||||
numberPadding(end.getMinutes()) +
|
||||
":00",
|
||||
isostart: start.toISOString(),
|
||||
isoend: end.toISOString(),
|
||||
farbe: "DDDDDD",
|
||||
};
|
||||
},
|
||||
updateDurationOfExistingTimeslotCalendarEvents() {
|
||||
this.timeslotCalendarEvents = this.timeslotCalendarEvents.map(
|
||||
(timeslotCalendarEvent) => {
|
||||
let start = new Date(timeslotCalendarEvent.isostart);
|
||||
return this.generateTimeslotCalendarEvent(start);
|
||||
},
|
||||
);
|
||||
},
|
||||
createTimeslotFromCard(startDate) {
|
||||
if (
|
||||
this.timeslotCalendarEvents.some(
|
||||
(existingTimeslotCalendarEvent) =>
|
||||
existingTimeslotCalendarEvent.isostart ===
|
||||
startDate.toISOString(),
|
||||
)
|
||||
) {
|
||||
this.$fhcAlert.alertError(this.$p.t("coodle/duplicate_creation_not_allowed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.timeslotCalendarEvents.push(
|
||||
this.generateTimeslotCalendarEvent(startDate),
|
||||
);
|
||||
this.isTimeslotCardEditInProgress = false;
|
||||
},
|
||||
updateTimeslotFromCard(timeslotCalendarEvent, newStartDate) {
|
||||
if (
|
||||
this.timeslotCalendarEvents.some(
|
||||
(existingTimeslotCalendarEvent) =>
|
||||
existingTimeslotCalendarEvent.isostart ===
|
||||
newStartDate.toISOString(),
|
||||
)
|
||||
) {
|
||||
this.$fhcAlert.alertError(this.$p.t("coodle/duplicate_creation_not_allowed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.timeslotCalendarEvents = this.timeslotCalendarEvents.map(
|
||||
(existingTimeslotCalendarEvent) => {
|
||||
if (
|
||||
existingTimeslotCalendarEvent.isostart !==
|
||||
timeslotCalendarEvent.isostart
|
||||
) {
|
||||
return existingTimeslotCalendarEvent;
|
||||
}
|
||||
|
||||
return this.generateTimeslotCalendarEvent(newStartDate);
|
||||
},
|
||||
);
|
||||
|
||||
this.isTimeslotCardEditInProgress = false;
|
||||
},
|
||||
deleteTimeslot(timeslotCalendarEvent) {
|
||||
this.timeslotCalendarEvents = this.timeslotCalendarEvents.filter(
|
||||
(existingTimeslotCalendarEvent) => {
|
||||
return (
|
||||
existingTimeslotCalendarEvent.isostart !==
|
||||
timeslotCalendarEvent.isostart
|
||||
);
|
||||
},
|
||||
);
|
||||
this.isTimeslotCardEditInProgress = false;
|
||||
},
|
||||
getEventStyle(event) {
|
||||
if (!event.farbe) return undefined;
|
||||
return "--event-bg:#" + event.farbe;
|
||||
},
|
||||
updateDisplayedSchedules() {
|
||||
let participantsWithDisplayedSchedules =
|
||||
this.$props.surveyFormDataParticipants.filter(
|
||||
(participant) => participant.isCalendarShown,
|
||||
);
|
||||
participantsWithDisplayedSchedules.forEach((participant) => {
|
||||
if (!(participant.uid in this.participantSchedules)) {
|
||||
this.fetchFreeBusySchedule(participant.uid);
|
||||
}
|
||||
});
|
||||
},
|
||||
async fetchFreeBusySchedule(uid) {
|
||||
this.participantSchedules[uid] = null;
|
||||
const freeBusyScheduleResponse = await this.$api.call(
|
||||
FreeBusyApi.getFreeBusySchedule(uid, this.$props.survey?.id),
|
||||
);
|
||||
this.participantSchedules[uid] = freeBusyScheduleResponse.data.map(
|
||||
(event) => {
|
||||
const startDate = new Date(event.start);
|
||||
const endDate = new Date(event.end);
|
||||
return {
|
||||
datum: event.start.split(" ")[0],
|
||||
beginn: event.start.split(" ")[1],
|
||||
ende: event.end.split(" ")[1],
|
||||
isostart: startDate.toISOString(),
|
||||
isoend: endDate.toISOString(),
|
||||
type: "freeBusy",
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setTimeslotCalendarEvents();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div id="coodleCalendar" class="d-flex flex-column gap-3">
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-bold">{{ $p.t("coodle/timeslot_selection") }}</span>
|
||||
<span class="fst-italic">{{ $p.t("coodle/timeslot_adding_options") }}</span>
|
||||
</div>
|
||||
<div style="height:800px;">
|
||||
<fhc-calendar
|
||||
v-if="renderers"
|
||||
@emptyClicked="addTimeslotOnCalendarClick($event)"
|
||||
:ref="'coodleCalendar'"
|
||||
:timezone="timezone"
|
||||
:modes="modes"
|
||||
:modeOptions="modeOptions"
|
||||
:mode="!isMobile ? 'Week' : 'Day'"
|
||||
:timeGrid="null"
|
||||
:locale="$p.user_locale.value"
|
||||
:events="events"
|
||||
:backgrounds="backgrounds"
|
||||
:draggableEvents="true"
|
||||
:droppableEvents="true"
|
||||
:onDrop="true"
|
||||
:isAutoScrollEnabled="false"
|
||||
:showBtns="!isMobile"
|
||||
>
|
||||
<template v-slot="{ event, mode }">
|
||||
<div
|
||||
:class="'event-type-' + event.type + ' ' + mode + 'PageContainer'"
|
||||
:type="mode == 'day' ? 'button' : undefined"
|
||||
:style="getEventStyle(event)"
|
||||
>
|
||||
<component
|
||||
v-if="mode == 'event'"
|
||||
:is="renderers[event.type]?.modalContent"
|
||||
:event="event"
|
||||
></component>
|
||||
<component
|
||||
v-else-if="mode == 'eventheader'"
|
||||
:is="renderers[event.type]?.modalTitle"
|
||||
:event="event"
|
||||
></component>
|
||||
<component
|
||||
v-else
|
||||
@click.stop=""
|
||||
@deleteCoodleTimeslot="deleteTimeslot($event.timeslot)"
|
||||
:is="renderers[event.type]?.calendarEvent"
|
||||
:event="event"
|
||||
></component>
|
||||
</div>
|
||||
</template>
|
||||
</fhc-calendar>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div v-for="timeslot in sortedTimeslotCalendarEvents.concat([null])" class="col-12 col-md-6 col-xl-4">
|
||||
<coodle-survey-calendar-timeslot-card
|
||||
@createTimeslot="createTimeslotFromCard($event.startDate)"
|
||||
@updateTimeslot="updateTimeslotFromCard(timeslot, $event.newStartDate)"
|
||||
@deleteTimeslot="deleteTimeslot(timeslot)"
|
||||
@setIsTimeslotCardEditInProgress="isTimeslotCardEditInProgress = $event.value"
|
||||
:timeslot="timeslot"
|
||||
:isTimeslotCardEditInProgress="isTimeslotCardEditInProgress"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
-253
@@ -1,253 +0,0 @@
|
||||
import { numberPadding } from "../../../../../../helpers/DateHelpers.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurveyCalendarTimeslotCard",
|
||||
components: {
|
||||
VueDatePicker,
|
||||
},
|
||||
props: {
|
||||
timeslot: Object | null,
|
||||
isTimeslotCardEditInProgress: Boolean,
|
||||
},
|
||||
emits: [
|
||||
"deleteTimeslot",
|
||||
"updateTimeslot",
|
||||
"setIsTimeslotCardEditInProgress",
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
isEditInProgress: false,
|
||||
dateInput: null,
|
||||
startTimeInput: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
formattedDate() {
|
||||
let dateFragments = this.$props.timeslot.datum.split("-");
|
||||
return dateFragments[2] + "." + dateFragments[1] + ".";
|
||||
},
|
||||
formattedStartEnd() {
|
||||
return (
|
||||
this.$props.timeslot?.beginn?.slice(0, 5) +
|
||||
"-" +
|
||||
this.$props.timeslot?.ende?.slice(0, 5)
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
timeslot: {
|
||||
handler() {
|
||||
this.isEditInProgress = false;
|
||||
this.setInputs();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
isEditInProgress() {
|
||||
this.setInputs();
|
||||
},
|
||||
isTimeslotCardEditInProgress() {
|
||||
this.isEditInProgress = false;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setInputs() {
|
||||
const tomorrow = new Date(
|
||||
new Date().getTime() + 24 * 60 * 60 * 1000,
|
||||
);
|
||||
this.dateInput =
|
||||
this.$props.timeslot?.datum ??
|
||||
tomorrow.toISOString().slice(0, 10);
|
||||
this.startTimeInput =
|
||||
this.$props.timeslot?.beginn?.slice(0, 5) ?? "12:00";
|
||||
},
|
||||
async startEdit() {
|
||||
if (this.$props.isTimeslotCardEditInProgress) {
|
||||
this.$emit("setIsTimeslotCardEditInProgress", { value: false });
|
||||
}
|
||||
await this.$nextTick();
|
||||
this.$emit("setIsTimeslotCardEditInProgress", { value: true });
|
||||
await this.$nextTick();
|
||||
this.isEditInProgress = true;
|
||||
},
|
||||
cancelEdit() {
|
||||
this.isEditInProgress = false;
|
||||
this.$emit("setIsTimeslotCardEditInProgress", { value: false });
|
||||
},
|
||||
submitForm() {
|
||||
if (!this.dateInput || !this.startTimeInput) {
|
||||
this.$fhcAlert.alertError("Check your inputs!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.dateInput === this.$props.timeslot?.datum &&
|
||||
this.startTimeInput ===
|
||||
this.$props.timeslot?.beginn?.slice(0, 5)
|
||||
) {
|
||||
this.isEditInProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.startTimeInput < this.minStartTimeInput ||
|
||||
this.startTimeInput > this.maxStartTimeInput
|
||||
) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("coodle/timeslot_start_limits"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let minutes = parseInt(this.startTimeInput.slice(3));
|
||||
if (minutes % 5) {
|
||||
minutes = minutes - (minutes % 5);
|
||||
this.startTimeInput =
|
||||
this.startTimeInput.slice(0, 3) + numberPadding(minutes);
|
||||
}
|
||||
|
||||
let startDate = new Date(
|
||||
this.dateInput + " " + this.startTimeInput,
|
||||
);
|
||||
if (this.$props.timeslot) {
|
||||
this.$emit("updateTimeslot", { newStartDate: startDate });
|
||||
} else {
|
||||
this.$emit("createTimeslot", { startDate });
|
||||
}
|
||||
},
|
||||
updateDateInput(value) {
|
||||
let date = new Date(value);
|
||||
this.dateInput = date.toISOString().slice(0, 10);
|
||||
},
|
||||
getDateInputPreview() {
|
||||
if (!this.dateInput?.length) return "";
|
||||
|
||||
const day = this.dateInput.slice(8);
|
||||
const month = this.dateInput.slice(5, 7);
|
||||
const year = this.dateInput.slice(0, 4);
|
||||
|
||||
return day + "." + month + "." + year;
|
||||
},
|
||||
updateStartTimeInput(value) {
|
||||
this.startTimeInput =
|
||||
numberPadding(value.hours) + ":" + numberPadding(value.minutes);
|
||||
},
|
||||
getStartTimeInputPreview() {
|
||||
if (!this.startTimeInput?.length) return "";
|
||||
|
||||
const hours = this.startTimeInput.slice(0, 2);
|
||||
const minutes = this.startTimeInput.slice(3, 5);
|
||||
|
||||
return hours + ":" + minutes;
|
||||
},
|
||||
getInitialStartTimeValue() {
|
||||
if (!this.startTimeInput?.length) {
|
||||
return {
|
||||
hours: 12,
|
||||
minutes: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
hours: parseInt(this.startTimeInput.split(":")[0]),
|
||||
minutes: parseInt(this.startTimeInput.split(":")[1]),
|
||||
};
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setInputs();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="w-100 p-2" style="height: 120px;">
|
||||
<div class="coodleCalendarTimeslotCard h-100 d-flex flex-row justify-content-between px-3 py-2 border border-2 rounded-2">
|
||||
<template v-if="$props.timeslot || isEditInProgress">
|
||||
<div
|
||||
v-if="!isEditInProgress"
|
||||
class="d-flex flex-column gap-2 justify-content-center align-items-center flex-grow-1"
|
||||
>
|
||||
<span class="fs-5 fw-bold">{{ formattedDate }}</span>
|
||||
<span>{{ formattedStartEnd }}</span>
|
||||
</div>
|
||||
<div v-else class="d-flex flex-column gap-2 flex-grow-1 justify-content-center pe-3">
|
||||
<div class="d-flex flex-row align-items-center gap-2">
|
||||
<label :for="'dateInput-' + $props.timeslot?.isostart" class="fw-bold">{{ $p.t("coodle/date") + ": " }}</label>
|
||||
<vue-date-picker
|
||||
@update:model-value="updateDateInput($event)"
|
||||
:model-value="dateInput"
|
||||
:format="() => getDateInputPreview()"
|
||||
:text-input="true"
|
||||
:clearable="false"
|
||||
:enable-time-picker="false"
|
||||
:now-button-label="$p.t('calendar/today')"
|
||||
:week-num-name="$p.t('calendar/kw')"
|
||||
auto-apply
|
||||
six-weeks
|
||||
teleport
|
||||
/>
|
||||
</div>
|
||||
<div class="d-flex flex-row gap-2">
|
||||
<label :for="'startTimeInput-' + $props.timeslot?.isostart" class="fw-bold">{{ $p.t("coodle/starts_at") + ": " }}</label>
|
||||
<vue-date-picker
|
||||
@update:model-value="updateStartTimeInput($event)"
|
||||
:model-value="getInitialStartTimeValue()"
|
||||
:format="() => getStartTimeInputPreview()"
|
||||
:text-input="true"
|
||||
:clearable="false"
|
||||
:minutes-increment="5"
|
||||
:min-time="{ hours: 7, minutes: 0 }"
|
||||
:max-time="{ hours: 22, minutes: 55 }"
|
||||
time-picker
|
||||
teleport
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-row align-items-start justify-content-end">
|
||||
<template v-if="!isEditInProgress">
|
||||
<div
|
||||
@click="startEdit()"
|
||||
:title="$p.t('coodle/edit')"
|
||||
type="button"
|
||||
class="p-1 fhcPrimaryHover"
|
||||
>
|
||||
<i class="fa-solid fa-pen-to-square fa-lg"></i>
|
||||
</div>
|
||||
<div
|
||||
@click="$emit('deleteTimeslot')"
|
||||
:title="$p.t('ui/loeschen')"
|
||||
type="button"
|
||||
class="p-1 fhcPrimaryHover"
|
||||
>
|
||||
<i class="fa-solid fa-trash-can fa-lg"></i>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
@click="cancelEdit()"
|
||||
:title="$p.t('ui/abbrechen')"
|
||||
type="button"
|
||||
class="p-1 fhcPrimaryHover"
|
||||
>
|
||||
<i class="fa-regular fa-circle-left fa-lg"></i>
|
||||
</div>
|
||||
<div
|
||||
@click="submitForm()"
|
||||
:title="$p.t('global/speichern')"
|
||||
type="button"
|
||||
class="p-1 fhcPrimaryHover"
|
||||
>
|
||||
<i class="fa-solid fa-floppy-disk fa-lg"></i>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="flex-grow-1 d-flex flex-row justify-content-center align-items-center">
|
||||
<i
|
||||
@click="startEdit()"
|
||||
:title="$p.t('ui/hinzufugen')"
|
||||
type="button"
|
||||
class="fhcPrimaryHover fa-solid fa-circle-plus fa-2xl"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
export default {
|
||||
name: "CoodleSurveyDurationSelector",
|
||||
props: {
|
||||
durationModelValue: Number | null,
|
||||
survey: Object,
|
||||
},
|
||||
emits: ["update:durationModelValue"],
|
||||
data() {
|
||||
return {
|
||||
appointmentDurationPresets: [15, 30, 45, 60, 90, 120],
|
||||
selectedDurationPreset: null,
|
||||
durationCustomInput: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
duration: {
|
||||
get() {
|
||||
return this.$props.durationModelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit("update:durationModelValue", newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
durationCustomInput() {
|
||||
if (this.durationCustomInput) {
|
||||
this.duration = this.durationCustomInput;
|
||||
this.selectedDurationPreset = null;
|
||||
}
|
||||
},
|
||||
survey: {
|
||||
handler() {
|
||||
this.initializeInputs();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectAppointmentDurationPreset(preset) {
|
||||
this.selectedDurationPreset = preset;
|
||||
this.duration = preset;
|
||||
this.durationCustomInput = null;
|
||||
},
|
||||
initializeInputs() {
|
||||
this.selectedDurationPreset = null;
|
||||
this.durationCustomInput = null;
|
||||
if (this.appointmentDurationPresets.includes(this.duration)) {
|
||||
this.selectedDurationPreset = this.duration;
|
||||
} else {
|
||||
this.durationCustomInput = this.duration;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.initializeInputs();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<span class="fw-bold">{{ "* " + $p.t("coodle/timeslot_duration_in_minutes") }}</span>
|
||||
<div class="overflow-x-auto">
|
||||
<div class="d-flex flex-row align-items-center gap-2">
|
||||
<div
|
||||
v-for="durationPreset in appointmentDurationPresets"
|
||||
@click="selectAppointmentDurationPreset(durationPreset)"
|
||||
type="button"
|
||||
:class="{'fhc-primary-border-color': selectedDurationPreset === durationPreset}"
|
||||
class="border border-2 d-flex justify-content-center align-items-center"
|
||||
style="min-width:60px;height:40px;"
|
||||
>
|
||||
<span>{{ durationPreset }}</span>
|
||||
</div>
|
||||
<span class="text-nowrap ps-2">{{ $p.t("coodle/custom_duration") + ": " }}</span>
|
||||
<div
|
||||
:class="{'fhc-primary-border-color': durationCustomInput}"
|
||||
class="border border-2 d-flex justify-content-center align-items-center px-1"
|
||||
style="width:60px;height:40px;"
|
||||
>
|
||||
<input
|
||||
v-model="durationCustomInput"
|
||||
type="number"
|
||||
min="5"
|
||||
step="5"
|
||||
class="border-0"
|
||||
style="min-width:0; outline: none; background: none;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,146 +0,0 @@
|
||||
import CoodleApi from "../../../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurveyHeader",
|
||||
props: {
|
||||
survey: Object | null,
|
||||
isEditInProgress: Boolean,
|
||||
authUid: String | null,
|
||||
},
|
||||
emits: ["editSurvey", "surveyCanceled"],
|
||||
computed: {
|
||||
headerTitle() {
|
||||
if (this.$props.survey?.id && !this.$props.isEditInProgress) {
|
||||
return this.$props.survey.title;
|
||||
} else if (this.$props.survey?.id && this.$props.isEditInProgress) {
|
||||
return this.$p.t("coodle/edit_survey");
|
||||
} else {
|
||||
return this.$p.t("coodle/new_survey");
|
||||
}
|
||||
},
|
||||
isSurveyActive() {
|
||||
return (
|
||||
!this.$props.survey.completedAt &&
|
||||
!this.$props.survey.canceledAt
|
||||
);
|
||||
},
|
||||
isAuthUserSurveyCreator() {
|
||||
return (
|
||||
this.$props.authUid &&
|
||||
this.$props.authUid === this.$props.survey?.creator?.uid
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async cancelSurvey() {
|
||||
if (!this.$props.survey?.id) return;
|
||||
|
||||
const cancellationConfirmationMessage = this.$p
|
||||
.t("coodle/cancel_survey_confirmation_message")
|
||||
.replace("(((surveyTitle)))", this.$props.survey?.title);
|
||||
const cancellationConfirmation = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/cancellation_confirmation"),
|
||||
message: cancellationConfirmationMessage,
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
if (!cancellationConfirmation) return;
|
||||
|
||||
const shouldInformParticipants = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/inform_participants"),
|
||||
message: this.$p.t("coodle/email_participants_canceled"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
|
||||
const cancellationResponse = await this.$api.call(
|
||||
CoodleApi.cancelSurvey(
|
||||
this.$props.survey.id,
|
||||
),
|
||||
);
|
||||
if ((cancellationResponse.meta.status = "success")) {
|
||||
this.$emit("surveyCanceled", { shouldInformParticipants });
|
||||
}
|
||||
},
|
||||
async sendReminders() {
|
||||
if (!this.$props.survey?.id) return;
|
||||
|
||||
const numberOfParticipantsWithoutVote =
|
||||
this.$props.survey.participants.filter(
|
||||
(participant) => participant.selection === null,
|
||||
).length;
|
||||
|
||||
if (!numberOfParticipantsWithoutVote) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("coodle/all_participants_voted"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const reminderConfirmation = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/reminder_confirmation"),
|
||||
message: this.$p.t("coodle/email_participants_reminder"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
if (!reminderConfirmation) return;
|
||||
|
||||
const remindersResponse = await this.$api.call(
|
||||
CoodleApi.sendReminders(this.$props.survey.id),
|
||||
);
|
||||
if (remindersResponse.meta.status === "success") {
|
||||
this.$fhcAlert.alertSuccess(
|
||||
this.$p.t("coodle/reminders_success"),
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="d-flex flex-row align-items-center justify-content-between">
|
||||
<h4 class="text-wrap m-0">{{ headerTitle }}</h4>
|
||||
<div
|
||||
v-if="isAuthUserSurveyCreator && !isEditInProgress && isSurveyActive"
|
||||
class="dropdown"
|
||||
>
|
||||
<div
|
||||
role="button"
|
||||
class="px-2"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fa-solid fa-ellipsis-vertical fa-lg"></i>
|
||||
</div>
|
||||
<ul class="dropdown-menu dropdown-menu-end" style="min-width:0;'">
|
||||
<li>
|
||||
<div
|
||||
@click="sendReminders()"
|
||||
role="button"
|
||||
class="dropdown-item px-3 py-1"
|
||||
>
|
||||
{{ $p.t("coodle/send_reminders") }}
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div
|
||||
@click="$emit('editSurvey')"
|
||||
role="button"
|
||||
class="dropdown-item px-3 py-1"
|
||||
>
|
||||
{{ $p.t("coodle/edit_survey") }}
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div
|
||||
@click="cancelSurvey()"
|
||||
role="button"
|
||||
class="dropdown-item px-3 py-1"
|
||||
>
|
||||
{{ $p.t("coodle/cancel_survey") }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,448 +0,0 @@
|
||||
import CoodleApi from "../../../../../api/factory/coodle.js";
|
||||
|
||||
import { debounce } from "../../../../../helpers/DebounceHelper.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurveyParticipants",
|
||||
components: {},
|
||||
props: {
|
||||
participantsModelValue: Array,
|
||||
externalParticipantsModelValue: Array,
|
||||
participantScheduleColorsModelValue: Array,
|
||||
authInfo: { type: Object | null },
|
||||
},
|
||||
emits: [
|
||||
"update:participantsModelValue",
|
||||
"update:externalParticipantsModelValue",
|
||||
"update:participantScheduleColorsModelValue",
|
||||
],
|
||||
inject: {
|
||||
isMobile: "isMobile",
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchInput: "",
|
||||
isSearchingForParticipants: false,
|
||||
searchResults: [],
|
||||
areSearchResultsShown: false,
|
||||
warningGroupSize: 10,
|
||||
searchParticipantsAbortController: null,
|
||||
searchParticipants: debounce(async () => {
|
||||
if (this.searchInput.length < 2) return;
|
||||
|
||||
if (this.searchParticipantsAbortController)
|
||||
this.searchParticipantsAbortController.abort();
|
||||
this.searchParticipantsAbortController = new AbortController();
|
||||
|
||||
this.isSearchingForParticipants = true;
|
||||
|
||||
const participantsSearchResponse = await this.$api.call(
|
||||
CoodleApi.searchParticipants(this.searchInput),
|
||||
{ signal: this.searchParticipantsAbortController.signal },
|
||||
);
|
||||
this.isSearchingForParticipants = false;
|
||||
|
||||
this.parseParticipantSearchResults(
|
||||
participantsSearchResponse.data,
|
||||
);
|
||||
}, 300),
|
||||
hideSearchResults: debounce(async () => {
|
||||
this.areSearchResultsShown = false;
|
||||
}, 100),
|
||||
externalParticipantNameInput: "",
|
||||
externalParticipantEmailInput: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
participants: {
|
||||
get() {
|
||||
return this.$props.participantsModelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit("update:participantsModelValue", newValue);
|
||||
},
|
||||
},
|
||||
externalParticipants: {
|
||||
get() {
|
||||
return this.$props.externalParticipantsModelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit("update:externalParticipantsModelValue", newValue);
|
||||
},
|
||||
},
|
||||
participantScheduleColors: {
|
||||
get() {
|
||||
return this.$props.participantScheduleColorsModelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit(
|
||||
"update:participantScheduleColorsModelValue",
|
||||
newValue,
|
||||
);
|
||||
},
|
||||
},
|
||||
isMaxDisplayedParticipantSchedulesReached() {
|
||||
return (
|
||||
this.displayedParticipantSchedulesCount >=
|
||||
this.participantScheduleColors.length
|
||||
);
|
||||
},
|
||||
displayedParticipantSchedulesCount() {
|
||||
return this.participants.filter(
|
||||
(participant) => participant.isCalendarShown,
|
||||
).length;
|
||||
},
|
||||
hasAuthUserBeenAddedAsParticipant() {
|
||||
return this.participants.some(
|
||||
(participant) => participant.uid === this.$props.authInfo?.uid,
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
searchInput() {
|
||||
if (this.searchInput.length >= 2) {
|
||||
this.areSearchResultsShown = true;
|
||||
this.searchParticipants();
|
||||
} else {
|
||||
this.areSearchResultsShown = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseParticipantSearchResults(searchResults) {
|
||||
this.searchResults = searchResults
|
||||
.map((searchResult) => {
|
||||
let data = JSON.parse(searchResult.data);
|
||||
if (data.uid) {
|
||||
return {
|
||||
rank: searchResult.rank,
|
||||
type: "user",
|
||||
name: data.name,
|
||||
uid: data.uid,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
rank: searchResult.rank,
|
||||
type: "group",
|
||||
name: data.name,
|
||||
users: data.user_uids.map((userUid, index) => {
|
||||
return {
|
||||
uid: userUid,
|
||||
name: data.user_names[index],
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter((searchResult) => {
|
||||
return (
|
||||
searchResult.type === "group" ||
|
||||
!this.participants.some(
|
||||
(existingParticipant) =>
|
||||
existingParticipant.uid === searchResult.uid,
|
||||
)
|
||||
);
|
||||
})
|
||||
.toSorted(
|
||||
(searchResultA, searchResultB) =>
|
||||
searchResultB.rank - searchResultA.rank,
|
||||
);
|
||||
},
|
||||
async selectSearchResult(searchResult) {
|
||||
if (
|
||||
searchResult.type === "group" &&
|
||||
searchResult.users.length >= this.warningGroupSize
|
||||
) {
|
||||
let groupSizeWarningMessage = this.$p.t(
|
||||
"coodle/group_size_warning",
|
||||
);
|
||||
groupSizeWarningMessage = groupSizeWarningMessage.replace(
|
||||
"(((groupName)))",
|
||||
searchResult.name,
|
||||
);
|
||||
groupSizeWarningMessage = groupSizeWarningMessage.replaceAll(
|
||||
"(((n)))",
|
||||
searchResult.users.length,
|
||||
);
|
||||
const groupSizeConfirmation = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/warning"),
|
||||
message: groupSizeWarningMessage,
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("ui/abbrechen"),
|
||||
});
|
||||
|
||||
if (!groupSizeConfirmation) return;
|
||||
}
|
||||
|
||||
const addedParticipants =
|
||||
searchResult.type === "group"
|
||||
? searchResult.users
|
||||
: [searchResult];
|
||||
this.addParticipants(addedParticipants);
|
||||
this.searchInput = "";
|
||||
this.searchResults = [];
|
||||
},
|
||||
addParticipants(newParticipants) {
|
||||
newParticipants = newParticipants
|
||||
.filter((newParticipant) => {
|
||||
return !this.participants.some(
|
||||
(existingParticipant) =>
|
||||
existingParticipant.uid === newParticipant.uid,
|
||||
);
|
||||
})
|
||||
.map((newParticipant) => {
|
||||
return {
|
||||
uid: newParticipant.uid,
|
||||
name: newParticipant.name,
|
||||
isCalendarShown: false,
|
||||
};
|
||||
});
|
||||
|
||||
this.participants = this.participants.concat(newParticipants);
|
||||
},
|
||||
removeParticipant(participantToBeRemoved) {
|
||||
this.participants = this.participants.filter(
|
||||
(participant) => participant.uid !== participantToBeRemoved.uid,
|
||||
);
|
||||
|
||||
let occupiedParticipantColor = this.participantScheduleColors.find(
|
||||
(participantColor) =>
|
||||
participantColor.uid === participantToBeRemoved.uid,
|
||||
);
|
||||
if (!occupiedParticipantColor) return;
|
||||
occupiedParticipantColor.uid = null;
|
||||
},
|
||||
showSchedule(participantForCalendarToBeDisplayed) {
|
||||
if (this.isMaxDisplayedParticipantSchedulesReached) return;
|
||||
|
||||
this.participants = this.participants.map((participant) => {
|
||||
let updatedParticipant = { ...participant };
|
||||
if (
|
||||
participant.uid === participantForCalendarToBeDisplayed.uid
|
||||
) {
|
||||
updatedParticipant.isCalendarShown = true;
|
||||
}
|
||||
return updatedParticipant;
|
||||
});
|
||||
|
||||
this.participantScheduleColors.find(
|
||||
(participantColor) => !participantColor.uid,
|
||||
).uid = participantForCalendarToBeDisplayed.uid;
|
||||
},
|
||||
hideSchedule(participant) {
|
||||
participant.isCalendarShown = false;
|
||||
|
||||
let occupiedParticipantColor = this.participantScheduleColors.find(
|
||||
(participantColor) => participantColor.uid === participant.uid,
|
||||
);
|
||||
if (!occupiedParticipantColor) return;
|
||||
occupiedParticipantColor.uid = null;
|
||||
},
|
||||
hideAllSchedules() {
|
||||
this.participants.forEach((participant) => {
|
||||
participant.isCalendarShown = false;
|
||||
});
|
||||
this.participantScheduleColors.forEach((participantColor) => {
|
||||
participantColor.uid = null;
|
||||
});
|
||||
},
|
||||
getParticipantScheduleColor(participant) {
|
||||
return this.participantScheduleColors.find(
|
||||
(participantColor) => participantColor.uid === participant.uid,
|
||||
)?.color;
|
||||
},
|
||||
addExternalParticipant() {
|
||||
const nameInput = this.externalParticipantNameInput.trim();
|
||||
const emailInput = this.externalParticipantEmailInput.trim();
|
||||
|
||||
if (!nameInput.length || !emailInput.length) {
|
||||
this.$fhcAlert.alertError("Missing inputs!");
|
||||
return;
|
||||
}
|
||||
|
||||
const emailRegex =
|
||||
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
if (!emailRegex.test(emailInput)) {
|
||||
this.$fhcAlert.alertError("Invalid email format!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.externalParticipants.some(
|
||||
(externalParticipant) =>
|
||||
externalParticipant.email === emailInput,
|
||||
)
|
||||
) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("coodle/duplicates_not_allowed"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.externalParticipants = [
|
||||
...this.externalParticipants,
|
||||
{
|
||||
name: nameInput,
|
||||
email: emailInput,
|
||||
},
|
||||
];
|
||||
this.externalParticipantNameInput = "";
|
||||
this.externalParticipantEmailInput = "";
|
||||
},
|
||||
removeExternalParticipant(email) {
|
||||
this.externalParticipants = this.externalParticipants.filter(
|
||||
(externalParticipant) => externalParticipant.email !== email,
|
||||
);
|
||||
},
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-6 col-xxl-12 d-flex flex-column gap-1 mb-2">
|
||||
<label for="searchInput" class="fw-bold">{{ $p.t("coodle/int_participants") }}</label>
|
||||
<div class="position-relative mb-1">
|
||||
<input
|
||||
v-model="searchInput"
|
||||
@focus="areSearchResultsShown = searchInput.length >= 2"
|
||||
@blur="hideSearchResults()"
|
||||
:placeholder="'Search participants...'"
|
||||
id="searchInput"
|
||||
class="w-100"
|
||||
/>
|
||||
<div
|
||||
v-if="areSearchResultsShown"
|
||||
id="coodleParticipantsSearchResults"
|
||||
class="position-absolute w-100 d-flex flex-column overflow-y-auto"
|
||||
style="height:200px;"
|
||||
>
|
||||
<div
|
||||
v-if="isSearchingForParticipants"
|
||||
class="flex-grow-1 d-flex flex-row justify-content-center align-items-center"
|
||||
>
|
||||
<i class="fa-solid fa-spinner fa-spin fa-xl"></i>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="!searchResults.length"
|
||||
class="d-flex flex-row justify-content-center align-items-center py-3"
|
||||
>
|
||||
<span>{{ $p.t("coodle/no_results_found") }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
v-for="searchResult in searchResults"
|
||||
@click="selectSearchResult(searchResult)"
|
||||
type="button"
|
||||
class="coodleParticipantSearchResult d-flex flex-row gap-2 justify-content-start align-items-center py-1 px-2 border-bottom border-1"
|
||||
>
|
||||
<i v-if="searchResult.type === 'user'" class="fa-solid fa-user"></i>
|
||||
<i v-else-if="searchResult.type === 'group'" class="fa-solid fa-user-group"></i>
|
||||
<span>{{ searchResult.name + (searchResult.uid ? (" (" + searchResult.uid + ")") : "") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="participants.length" class="d-flex flex-row gap-2 flex-wrap">
|
||||
<div
|
||||
v-for="participant in participants"
|
||||
class="d-flex flex-row align-items-center gap-4 py-1 px-3 border border-1 rounded-pill"
|
||||
>
|
||||
<span>{{ participant.name }}</span>
|
||||
<div class="d-flex flex-row align-items-center gap-3">
|
||||
<i
|
||||
v-if="participant.isCalendarShown"
|
||||
@click="hideSchedule(participant)"
|
||||
type="button"
|
||||
class="fa-solid fa-calendar"
|
||||
:style="{color: getParticipantScheduleColor(participant)}"
|
||||
></i>
|
||||
<i
|
||||
v-else-if="isMaxDisplayedParticipantSchedulesReached"
|
||||
class="fa-regular fa-calendar-xmark"
|
||||
></i>
|
||||
<i
|
||||
v-else
|
||||
@click="showSchedule(participant)"
|
||||
type="button"
|
||||
class="fa-regular fa-calendar"
|
||||
></i>
|
||||
<i @click="removeParticipant(participant)" type="button" class="fa-solid fa-xmark"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!hasAuthUserBeenAddedAsParticipant && $props.authInfo" class="d-flex flex-row">
|
||||
<div
|
||||
@click="addParticipants([$props.authInfo])"
|
||||
type="button"
|
||||
class="py-1 px-3 border border-1 rounded-pill"
|
||||
>
|
||||
<span>{{ $p.t("coodle/add_yourself") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="isMaxDisplayedParticipantSchedulesReached" class="fst-italic">
|
||||
{{ $p.t("coodle/max_participant_schedules") }}
|
||||
</span>
|
||||
<div>
|
||||
<span
|
||||
v-if="displayedParticipantSchedulesCount"
|
||||
@click="hideAllSchedules()"
|
||||
type="button"
|
||||
class="text-decoration-underline"
|
||||
>
|
||||
{{ $p.t("coodle/hide_participant_schedules") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-xxl-12 d-flex flex-column gap-1 mb-2">
|
||||
<span class="fw-bold">{{ $p.t("coodle/ext_participants") }}</span>
|
||||
<div class="d-flex flex-row gap-2 mb-1">
|
||||
<div class="flex-grow-1 d-flex flex-column gap-2">
|
||||
<div >
|
||||
<input
|
||||
v-model="externalParticipantNameInput"
|
||||
:placeholder="'Name'"
|
||||
id="externalParticipantNameInput"
|
||||
maxlength="255"
|
||||
style="width:100%"
|
||||
/>
|
||||
</div>
|
||||
<div >
|
||||
<input
|
||||
v-model="externalParticipantEmailInput"
|
||||
:placeholder="'Email'"
|
||||
type="email"
|
||||
id="externalParticipantEmailInput"
|
||||
maxlength="255"
|
||||
style="width:100%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-row align-items-center justify-content-center">
|
||||
<div @click="addExternalParticipant()" type="button" class="p-1 fhcPrimaryHover">
|
||||
<i class="fa-solid fa-circle-plus fa-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="externalParticipants.length" class="d-flex flex-row gap-2 flex-wrap">
|
||||
<div
|
||||
v-for="externalParticipant in externalParticipants"
|
||||
:key="externalParticipant.email"
|
||||
class="d-flex flex-row align-items-center gap-4 py-1 px-3 border border-1 rounded-pill"
|
||||
>
|
||||
<div class="d-flex flex-row gap-2 flex-wrap">
|
||||
<span>{{ externalParticipant.name }}</span>
|
||||
<span>|</span>
|
||||
<span>{{ externalParticipant.email }}</span>
|
||||
</div>
|
||||
<i
|
||||
@click="removeExternalParticipant(externalParticipant.email)"
|
||||
type="button"
|
||||
class="fa-solid fa-xmark"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="!participants.length && !externalParticipants.length" class="fst-italic">
|
||||
{{ $p.t("coodle/no_participants_yet") }}
|
||||
</span>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,782 +0,0 @@
|
||||
import CoodleApi from "../../../../../api/factory/coodle.js";
|
||||
import OrtApi from "../../../../../api/factory/ort.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleSurveyVotingTable",
|
||||
props: {
|
||||
survey: { type: Object },
|
||||
authUid: { type: String | null },
|
||||
authExternalParticipantId: { type: Number | null },
|
||||
timeslots: { type: Array },
|
||||
},
|
||||
emits: ["selectionSubmitted", "surveyCompleted"],
|
||||
data() {
|
||||
return {
|
||||
isVotingInProgress: false,
|
||||
isFinalSelectionInProgress: false,
|
||||
participantsWithoutAuthUser: [],
|
||||
externalParticipantsWithoutAuthUser: [],
|
||||
authUserParticipant: null,
|
||||
editableAuthUserSelection: null,
|
||||
selectedTimeslotId: null,
|
||||
isRoomSelectionShown: false,
|
||||
selectedRoomIdentifier: null,
|
||||
isFetchingAvailableRooms: false,
|
||||
availableRooms: [],
|
||||
roomFilterText: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isDarkMode() {
|
||||
return this.$theme.theme_name.value == "dark";
|
||||
},
|
||||
isAuthUserSurveyCreator() {
|
||||
return (
|
||||
this.$props.authUid &&
|
||||
this.$props.authUid === this.$props.survey?.creator?.uid
|
||||
);
|
||||
},
|
||||
hasReachedMaxSelections() {
|
||||
if (!this.authUserParticipant || !this.editableAuthUserSelection)
|
||||
return false;
|
||||
|
||||
return (
|
||||
Object.values(this.editableAuthUserSelection).filter(
|
||||
(isSelected) => isSelected,
|
||||
).length >= this.$props.survey.maxSelections
|
||||
);
|
||||
},
|
||||
isSurveyActive() {
|
||||
return (
|
||||
!this.$props.survey.completedAt &&
|
||||
!this.$props.survey.canceledAt
|
||||
);
|
||||
},
|
||||
filteredAvailableRooms() {
|
||||
if (!this.roomFilterText?.length) {
|
||||
return this.availableRooms;
|
||||
}
|
||||
|
||||
const roomFilterText = this.roomFilterText.toLowerCase();
|
||||
return this.availableRooms.filter(
|
||||
(room) =>
|
||||
room.shortName.toLowerCase().includes(roomFilterText) ||
|
||||
room.longName.toLowerCase().includes(roomFilterText),
|
||||
);
|
||||
},
|
||||
timeslotDates() {
|
||||
if (!this.$props.timeslots.length) return [];
|
||||
|
||||
let groupedTimeslots = Object.groupBy(
|
||||
this.$props.timeslots,
|
||||
(timeslot) => {
|
||||
return timeslot.startsAt.toISOString().slice(0, 10);
|
||||
},
|
||||
);
|
||||
return Object.keys(groupedTimeslots)
|
||||
.sort()
|
||||
.map((dateKey) => {
|
||||
let timeslotDate = groupedTimeslots[dateKey];
|
||||
return {
|
||||
count: timeslotDate.length,
|
||||
date: timeslotDate[0].date,
|
||||
weekday: timeslotDate[0].weekday,
|
||||
month: timeslotDate[0].month,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
survey: {
|
||||
handler() {
|
||||
this.setData();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
timeslots: {
|
||||
handler() {
|
||||
this.setData();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
authUid() {
|
||||
this.setData();
|
||||
},
|
||||
authExternalParticipantId() {
|
||||
this.setData();
|
||||
},
|
||||
authUserParticipant: {
|
||||
handler() {
|
||||
this.setEditableAuthUserSelection();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
editableAuthUserSelection: {
|
||||
handler() {
|
||||
if (this.editableAuthUserSelection.none) {
|
||||
Object.keys(this.editableAuthUserSelection).forEach(
|
||||
(timeslotId) => {
|
||||
if (timeslotId !== "none") {
|
||||
this.editableAuthUserSelection[timeslotId] =
|
||||
false;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
isVotingInProgress() {
|
||||
this.setEditableAuthUserSelection();
|
||||
},
|
||||
isFinalSelectionInProgress() {
|
||||
this.setSelectedTimeslotId();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
parseParticipants() {
|
||||
const participants = this.$props.survey.participants.map(
|
||||
(participant) => {
|
||||
participant = { ...participant };
|
||||
const hasVotedWithoutSelection =
|
||||
participant.selection &&
|
||||
participant.selection.length === 0;
|
||||
|
||||
let selectionEntries = this.$props.timeslots.map(
|
||||
(timeslot) => [
|
||||
timeslot.id,
|
||||
participant.selection?.includes(timeslot.id),
|
||||
],
|
||||
);
|
||||
selectionEntries.push(["none", hasVotedWithoutSelection]);
|
||||
participant.selection =
|
||||
Object.fromEntries(selectionEntries);
|
||||
|
||||
return participant;
|
||||
},
|
||||
);
|
||||
|
||||
if (this.$props.authUid) {
|
||||
this.authUserParticipant =
|
||||
participants.find(
|
||||
(participant) =>
|
||||
participant.uid === this.$props.authUid,
|
||||
) ?? null;
|
||||
}
|
||||
|
||||
this.participantsWithoutAuthUser = this.$props.authUid
|
||||
? participants.filter(
|
||||
(participant) =>
|
||||
participant.uid !== this.$props.authUid,
|
||||
)
|
||||
: participants;
|
||||
},
|
||||
parseExternalParticipants() {
|
||||
const externalParticipants =
|
||||
this.$props.survey.externalParticipants.map(
|
||||
(externalParticipant) => {
|
||||
externalParticipant = { ...externalParticipant };
|
||||
const hasVotedWithoutSelection =
|
||||
externalParticipant.selection &&
|
||||
externalParticipant.selection.length === 0;
|
||||
|
||||
let selectionEntries = this.$props.timeslots.map(
|
||||
(timeslot) => [
|
||||
timeslot.id,
|
||||
externalParticipant.selection?.includes(
|
||||
timeslot.id,
|
||||
),
|
||||
],
|
||||
);
|
||||
selectionEntries.push([
|
||||
"none",
|
||||
hasVotedWithoutSelection,
|
||||
]);
|
||||
externalParticipant.selection =
|
||||
Object.fromEntries(selectionEntries);
|
||||
|
||||
return externalParticipant;
|
||||
},
|
||||
);
|
||||
|
||||
if (this.$props.authExternalParticipantId) {
|
||||
this.authUserParticipant = externalParticipants.find(
|
||||
(externalParticipant) =>
|
||||
externalParticipant.id ===
|
||||
this.$props.authExternalParticipantId,
|
||||
);
|
||||
}
|
||||
|
||||
this.externalParticipantsWithoutAuthUser = this.$props
|
||||
.authExternalParticipantId
|
||||
? externalParticipants.filter(
|
||||
(externalParticipant) =>
|
||||
externalParticipant.id !==
|
||||
this.$props.authExternalParticipantId,
|
||||
)
|
||||
: externalParticipants;
|
||||
},
|
||||
setData() {
|
||||
this.setForms();
|
||||
this.setSelectedTimeslotId();
|
||||
this.parseParticipants();
|
||||
this.parseExternalParticipants();
|
||||
},
|
||||
setForms() {
|
||||
this.isVotingInProgress = false;
|
||||
this.isFinalSelectionInProgress = false;
|
||||
this.isRoomSelectionShown = false;
|
||||
this.selectedRoomIdentifier = null;
|
||||
this.roomFilterText = "";
|
||||
},
|
||||
setEditableAuthUserSelection() {
|
||||
this.editableAuthUserSelection = this.authUserParticipant?.selection
|
||||
? { ...this.authUserParticipant.selection }
|
||||
: null;
|
||||
},
|
||||
setSelectedTimeslotId() {
|
||||
if (!this.$props.survey.completedAt) {
|
||||
this.selectedTimeslotId = null;
|
||||
} else if (this.$props.survey.selectedTimeslotId) {
|
||||
this.selectedTimeslotId = this.$props.survey.selectedTimeslotId;
|
||||
} else {
|
||||
this.selectedTimeslotId = "none";
|
||||
}
|
||||
},
|
||||
async submitParticipantSelection() {
|
||||
const selectedTimeslots = Object.entries(
|
||||
this.editableAuthUserSelection,
|
||||
)
|
||||
.filter((timeslotSelectionPair) => timeslotSelectionPair[1])
|
||||
.map((timeslotSelectionPair) => timeslotSelectionPair[0]);
|
||||
|
||||
let selection;
|
||||
if (!selectedTimeslots.length) {
|
||||
selection = null;
|
||||
} else if (selectedTimeslots.includes("none")) {
|
||||
selection = [];
|
||||
} else {
|
||||
selection = selectedTimeslots.map(Number);
|
||||
}
|
||||
|
||||
let selectionSubmissionResponse;
|
||||
if (this.$props.authExternalParticipantId) {
|
||||
selectionSubmissionResponse = await this.$api.call(
|
||||
CoodleApi.submitExternalParticipantSelection(
|
||||
this.$route.params.surveyId,
|
||||
this.$route.params.accessKey,
|
||||
selection,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
selectionSubmissionResponse = await this.$api.call(
|
||||
CoodleApi.submitParticipantSelection(
|
||||
this.survey.id,
|
||||
selection,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (selectionSubmissionResponse.meta.status === "success") {
|
||||
this.$emit("selectionSubmitted");
|
||||
}
|
||||
},
|
||||
async prepareFinalSelectionSubmission() {
|
||||
if (!this.$props.survey.id) return;
|
||||
|
||||
if (!this.selectedTimeslotId) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("coodle/no_selection_made"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let formattedSelectedTimeslot = "";
|
||||
let selectedTimeslot = null;
|
||||
|
||||
if (this.selectedTimeslotId === "none") {
|
||||
formattedSelectedTimeslot =
|
||||
'"' + this.$p.t("coodle/no_timeslot_possible") + '"';
|
||||
} else {
|
||||
selectedTimeslot = this.$props.timeslots.find(
|
||||
(timeslot) => timeslot.id === this.selectedTimeslotId,
|
||||
);
|
||||
if (!selectedTimeslot) return;
|
||||
formattedSelectedTimeslot =
|
||||
selectedTimeslot.weekday +
|
||||
" " +
|
||||
selectedTimeslot.fullDate +
|
||||
" " +
|
||||
selectedTimeslot.startTime +
|
||||
"-" +
|
||||
selectedTimeslot.endTime;
|
||||
}
|
||||
|
||||
const finalSelectionConfirmationMessage = this.$p
|
||||
.t("coodle/survey_completion_confirmation")
|
||||
.replace("(((timeslot)))", formattedSelectedTimeslot)
|
||||
.replace("(((surveyTitle)))", this.$props.survey?.title);
|
||||
const finalSelectionConfirmation = await this.$fhcAlert.confirm({
|
||||
header: "Final confirmation",
|
||||
message: finalSelectionConfirmationMessage,
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("ui/abbrechen"),
|
||||
});
|
||||
if (!finalSelectionConfirmation) return;
|
||||
|
||||
let participantsThatHaveNotVoted =
|
||||
this.participantsWithoutAuthUser.reduce((sum, participant) => {
|
||||
return (
|
||||
sum +
|
||||
(!Object.values(participant.selection).filter(
|
||||
(isSelected) => isSelected,
|
||||
).length
|
||||
? 1
|
||||
: 0)
|
||||
);
|
||||
}, 0);
|
||||
|
||||
if (
|
||||
this.authUserParticipant &&
|
||||
!Object.values(this.authUserParticipant.selection).filter(
|
||||
(isSelected) => isSelected,
|
||||
).length
|
||||
) {
|
||||
participantsThatHaveNotVoted++;
|
||||
}
|
||||
|
||||
if (participantsThatHaveNotVoted) {
|
||||
const shouldProceedWithoutAllVotes =
|
||||
await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/warning"),
|
||||
message: this.$p.t("coodle/continue_without_all_votes"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("ui/abbrechen"),
|
||||
});
|
||||
if (!shouldProceedWithoutAllVotes) return;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const isFutureTimeslot =
|
||||
selectedTimeslot && selectedTimeslot.startsAt > now;
|
||||
if (selectedTimeslot && isFutureTimeslot) {
|
||||
const shouldReserveARoom = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/room_reservation"),
|
||||
message: this.$p.t("coodle/reserve_room_confirmation"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
if (shouldReserveARoom) {
|
||||
this.isRoomSelectionShown = true;
|
||||
this.fetchAvailableRooms();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.submitFinalSelection();
|
||||
},
|
||||
submitWithRoomSelection() {
|
||||
if (this.availableRooms.length && !this.selectedRoomIdentifier) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("coodle/no_room_selection"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.submitFinalSelection();
|
||||
},
|
||||
async submitFinalSelection() {
|
||||
let shouldInformParticipants = false;
|
||||
const selectedTimeslotId =
|
||||
this.selectedTimeslotId === "none"
|
||||
? null
|
||||
: this.selectedTimeslotId;
|
||||
|
||||
if (!selectedTimeslotId) {
|
||||
shouldInformParticipants = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/inform_participants"),
|
||||
message: this.$p.t("coodle/email_participants_result"),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
} else {
|
||||
const selectedTimeslot = this.$props.timeslots.find(
|
||||
(timeslot) => timeslot.id === selectedTimeslotId,
|
||||
);
|
||||
const now = new Date();
|
||||
const isFutureTimeslot = selectedTimeslot.startsAt > now;
|
||||
if (isFutureTimeslot) {
|
||||
shouldInformParticipants = await this.$fhcAlert.confirm({
|
||||
header: this.$p.t("coodle/inform_participants"),
|
||||
message: this.$p.t(
|
||||
"coodle/email_participants_calendar_invite",
|
||||
),
|
||||
acceptLabel: this.$p.t("coodle/yes"),
|
||||
rejectLabel: this.$p.t("coodle/no"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const completionResponse = await this.$api.call(
|
||||
CoodleApi.completeSurvey(
|
||||
this.$props.survey.id,
|
||||
selectedTimeslotId,
|
||||
this.selectedRoomIdentifier,
|
||||
),
|
||||
);
|
||||
if (completionResponse.meta.status === "success") {
|
||||
this.$emit("surveyCompleted", {
|
||||
shouldInformParticipants,
|
||||
selectedRoomId: this.selectedRoomIdentifier,
|
||||
});
|
||||
}
|
||||
},
|
||||
async fetchAvailableRooms() {
|
||||
this.availableRooms = [];
|
||||
|
||||
const selectedTimeslotInfo = this.$props.timeslots.find(
|
||||
(timeslot) => timeslot.id === this.selectedTimeslotId,
|
||||
);
|
||||
|
||||
this.isFetchingAvailableRooms = true;
|
||||
const roomsResponse = await this.$api.call(
|
||||
OrtApi.getRooms(
|
||||
selectedTimeslotInfo.startsAt.toISOString(),
|
||||
selectedTimeslotInfo.startTime,
|
||||
selectedTimeslotInfo.endTime,
|
||||
"",
|
||||
this.$props.survey.participants.length,
|
||||
),
|
||||
);
|
||||
this.isFetchingAvailableRooms = false;
|
||||
|
||||
this.availableRooms = roomsResponse.data.retval
|
||||
.filter((room) => room.reservieren)
|
||||
.map((room) => {
|
||||
return {
|
||||
id: room.content_id,
|
||||
shortName: room.ort_kurzbz,
|
||||
longName: room.bezeichnung,
|
||||
};
|
||||
});
|
||||
},
|
||||
cancelRoomSelection() {
|
||||
this.isRoomSelectionShown = false;
|
||||
this.selectedRoomIdentifier = null;
|
||||
this.availableRooms = [];
|
||||
this.isFetchingAvailableRooms = false;
|
||||
this.roomFilterText = "";
|
||||
},
|
||||
showParticipantProfile(participant) {
|
||||
if (!participant?.uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const participantHref = this.$router.resolve({
|
||||
name: "ProfilView",
|
||||
params: { uid: participant.uid },
|
||||
}).href;
|
||||
|
||||
window.open(participantHref, "_blank");
|
||||
},
|
||||
showRoomDetails(room) {
|
||||
if (!room.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const roomHref =
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
"/CisVue/Cms/content/" +
|
||||
room.id;
|
||||
|
||||
window.open(roomHref, "_blank");
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setData();
|
||||
this.setEditableAuthUserSelection();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div>
|
||||
<span v-if="!isSurveyActive" class="fst-italic">
|
||||
{{ $p.t("coodle/voting_closed") }}
|
||||
</span>
|
||||
<span v-else-if="authUserParticipant" :class="{'opacity-0': !isVotingInProgress}" class="fst-italic">
|
||||
{{
|
||||
$props.survey?.maxSelections === 1 ?
|
||||
$p.t("coodle/max_one_selectable_timeslot") :
|
||||
$p.t("coodle/up_to_max_selectable_timeslots").replace("(((n)))", $props.survey?.maxSelections)
|
||||
}}
|
||||
</span>
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-column flex-shrink-1" style="max-width:100%;">
|
||||
<div class="overflow-x-auto">
|
||||
<table>
|
||||
<tr>
|
||||
<td rowspan="2" class="border-1"></td>
|
||||
<td v-for="timeslotDate in timeslotDates" :colspan="timeslotDate.count" class="border-1">
|
||||
<div class="px-1 d-flex flex-column align-items-center">
|
||||
<span>{{ timeslotDate.month.slice(0,3) }}</span>
|
||||
<span class="fs-5 fw-bold">{{ timeslotDate.date }}</span>
|
||||
<span>{{ timeslotDate.weekday.slice(0,3) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td rowspan="2" class="border-1">
|
||||
<div class="px-2 py-1 text-center">
|
||||
{{ $p.t("coodle/no_timeslot_possible") }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td v-for="timeslot in $props.timeslots" class="border-1">
|
||||
<div class="px-2 d-flex flex-column align-items-start text-nowrap">
|
||||
<span>{{ timeslot.startTime + " -" }}</span>
|
||||
<span>{{ timeslot.endTime }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="participant in participantsWithoutAuthUser">
|
||||
<td class="border-1 px-2 py-1">
|
||||
<div
|
||||
v-if="participant.name"
|
||||
class="d-flex flex-row gap-1 justify-content-between align-items-center"
|
||||
>
|
||||
<span>
|
||||
{{ participant.name }}
|
||||
</span>
|
||||
<span
|
||||
v-if="participant.uid"
|
||||
@click="showParticipantProfile(participant)"
|
||||
type="button"
|
||||
class="px-1 fhc-primary-color"
|
||||
>
|
||||
<i class="fa-solid fa-up-right-from-square"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="text-center">---</div>
|
||||
</td>
|
||||
<td v-for="timeslot in $props.timeslots" class="border-1">
|
||||
<div class="d-flex justify-content-center">
|
||||
<i v-if="participant.selection[timeslot.id]" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-1">
|
||||
<div class="d-flex justify-content-center">
|
||||
<i v-if="participant.selection.none" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="externalParticipant in externalParticipantsWithoutAuthUser">
|
||||
<td class="border-1 px-2 py-1">
|
||||
<div
|
||||
v-if="externalParticipant.name?.length"
|
||||
class="d-flex flex-row gap-1 justify-content-between align-items-center"
|
||||
>
|
||||
{{ externalParticipant.name }}
|
||||
</div>
|
||||
<div v-else class="text-center">---</div>
|
||||
</td>
|
||||
<td v-for="timeslot in $props.timeslots" class="border-1">
|
||||
<div class="d-flex justify-content-center">
|
||||
<i v-if="externalParticipant.selection[timeslot.id]" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-1">
|
||||
<div class="d-flex justify-content-center">
|
||||
<i v-if="externalParticipant.selection.none" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="authUserParticipant"
|
||||
:class="{'fhc-body-bg': isVotingInProgress}"
|
||||
>
|
||||
<td class="border-1 px-2 py-1">{{ authUserParticipant.name }}</td>
|
||||
<td v-for="timeslot in $props.timeslots" class="border-1">
|
||||
<div class="d-flex justify-content-center py-3">
|
||||
<input
|
||||
v-if="isSurveyActive"
|
||||
v-model="editableAuthUserSelection[timeslot.id]"
|
||||
:disabled="
|
||||
!isVotingInProgress ||
|
||||
(!editableAuthUserSelection[timeslot.id] && hasReachedMaxSelections) ||
|
||||
editableAuthUserSelection.none
|
||||
"
|
||||
:role="!isVotingInProgress ||
|
||||
(!editableAuthUserSelection[timeslot.id] && hasReachedMaxSelections) ||
|
||||
editableAuthUserSelection.none ? '' : 'button'"
|
||||
type="checkbox"
|
||||
style="width: 20px; height: 20px;"
|
||||
/>
|
||||
<i v-else-if="authUserParticipant.selection[timeslot.id]" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-1">
|
||||
<div class="d-flex justify-content-center py-3">
|
||||
<input
|
||||
v-if="isSurveyActive"
|
||||
v-model="editableAuthUserSelection.none"
|
||||
:disabled="!isVotingInProgress"
|
||||
:role="isVotingInProgress ? 'button' : ''"
|
||||
type="checkbox"
|
||||
style="width: 20px; height: 20px;"
|
||||
/>
|
||||
<i v-else-if="authUserParticipant.selection.none" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="$props.survey.voteTallies" class="fw-bold">
|
||||
<td class="border-1 px-2 py-1">{{ $p.t("coodle/vote_tally") }}</td>
|
||||
<td v-for="timeslot in $props.timeslots" class="border-1">
|
||||
<div class="d-flex flex-row justify-content-center">
|
||||
{{ $props.survey.voteTallies[timeslot.id] }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-1">
|
||||
<div class="d-flex flex-row justify-content-center">
|
||||
{{ $props.survey.voteTallies.none }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="isAuthUserSurveyCreator || $props.survey.completedAt"
|
||||
:class="{'fhc-body-bg': isFinalSelectionInProgress}"
|
||||
class="fw-bold"
|
||||
>
|
||||
<td class="border-1 px-2 py-1">{{ $p.t("coodle/final_selection") }}</td>
|
||||
<td v-for="timeslot in $props.timeslots" class="border-1">
|
||||
<div class="d-flex flex-row justify-content-center py-3">
|
||||
<input
|
||||
v-if="isSurveyActive"
|
||||
v-model="selectedTimeslotId"
|
||||
:value="timeslot.id"
|
||||
:disabled="!isFinalSelectionInProgress || isRoomSelectionShown"
|
||||
:role="isFinalSelectionInProgress ? 'button' : ''"
|
||||
type="radio"
|
||||
style="width: 20px; height: 20px;"
|
||||
/>
|
||||
<i v-else-if="selectedTimeslotId === timeslot.id" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-1">
|
||||
<div class="d-flex flex-row justify-content-center py-3">
|
||||
<input
|
||||
v-if="isSurveyActive"
|
||||
v-model="selectedTimeslotId"
|
||||
:value="'none'"
|
||||
:disabled="!isFinalSelectionInProgress || isRoomSelectionShown"
|
||||
:role="isFinalSelectionInProgress ? 'button' : ''"
|
||||
type="radio"
|
||||
style="width: 20px; height: 20px;"
|
||||
/>
|
||||
<i v-else-if="selectedTimeslotId === 'none'" class="fa-solid fa-check"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div v-if="isRoomSelectionShown" class="mt-3">
|
||||
<div v-if="isFetchingAvailableRooms" class="d-flex justify-content-center align-items-center py-3">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">{{ $p.t("coodle/loading") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!availableRooms.length" class="d-flex justify-content-center align-items-center py-4 px-1">
|
||||
<h5 class="flex-shrink fw-bold text-wrap m-0">
|
||||
{{ $p.t("coodle/no_rooms_available") }}
|
||||
</h5>
|
||||
</div>
|
||||
<div v-else class="d-flex flex-column gap-2">
|
||||
<div class="d-flex flex-row gap-1">
|
||||
<span class="fw-bold">{{ "Selected room: " }}</span>
|
||||
<span v-if="selectedRoomIdentifier?.length">{{ selectedRoomIdentifier }}</span>
|
||||
</div>
|
||||
<div class="d-flex flex-column gap-1 justify-content-start">
|
||||
<span class="fw-bold">{{ $p.t("coodle/available_rooms") + ":" }}</span>
|
||||
<div class="d-flex flex-row align-items-center gap-2">
|
||||
<input v-model="roomFilterText" :placeholder="'Filter rooms...'" id="roomFilterInput" />
|
||||
<div
|
||||
v-if="roomFilterText?.length"
|
||||
@click="roomFilterText = ''"
|
||||
type="button"
|
||||
class="px-1"
|
||||
>
|
||||
<i class="fa-solid fa-xmark fa-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!filteredAvailableRooms.length" class="d-flex flex-row align-items-center justify-content-center py-4 px-1">
|
||||
<h5 class="flex-shrink fw-bold text-wrap m-0">
|
||||
{{ $p.t("coodle/no_available_rooms_for_filter") }}
|
||||
</h5>
|
||||
</div>
|
||||
<div v-else class="d-flex flex-column overflow-y-auto" style="max-height:200px;">
|
||||
<div
|
||||
v-for="room in filteredAvailableRooms"
|
||||
@click="selectedRoomIdentifier = room.shortName"
|
||||
:key="room.shortName"
|
||||
:title="room.longName"
|
||||
type="button"
|
||||
:class="{'fhc-primary-color': selectedRoomIdentifier === room.shortName}"
|
||||
class="px-2 py-1 border border-x-2 border-y-1 d-flex flex-row align-items-center gap-1"
|
||||
>
|
||||
<span>{{ room.shortName }}</span>
|
||||
<span
|
||||
v-if="room.id"
|
||||
@click.stop="showRoomDetails(room)"
|
||||
type="button"
|
||||
class="px-1 fhc-primary-color"
|
||||
>
|
||||
<i class="fa-solid fa-up-right-from-square"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isSurveyActive" class="d-flex flex-row gap-2 mt-3 justify-content-end">
|
||||
<div
|
||||
v-if="authUserParticipant && !isVotingInProgress && !isFinalSelectionInProgress"
|
||||
@click="isVotingInProgress = true"
|
||||
:class="isDarkMode ? 'btn-outline-light' : 'btn-outline-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("coodle/vote") }}
|
||||
</div>
|
||||
<div
|
||||
v-if="isAuthUserSurveyCreator && !isVotingInProgress && !isFinalSelectionInProgress"
|
||||
@click="isFinalSelectionInProgress = true"
|
||||
:class="isDarkMode ? 'btn-outline-light' : 'btn-outline-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("coodle/finalize_survey") }}
|
||||
</div>
|
||||
<div
|
||||
v-if="isVotingInProgress || isFinalSelectionInProgress"
|
||||
@click="setForms()"
|
||||
:class="isDarkMode ? 'btn-outline-light' : 'btn-outline-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("ui/abbrechen") }}
|
||||
</div>
|
||||
<div
|
||||
v-if="isVotingInProgress"
|
||||
@click="submitParticipantSelection()"
|
||||
:class="isDarkMode ? 'btn-light' : 'btn-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("coodle/submit_vote") }}
|
||||
</div>
|
||||
<div
|
||||
v-if="isFinalSelectionInProgress"
|
||||
@click="isRoomSelectionShown ? submitWithRoomSelection() : prepareFinalSelectionSubmission()"
|
||||
:class="isDarkMode ? 'btn-light' : 'btn-dark'"
|
||||
class="btn text-nowrap"
|
||||
>
|
||||
{{ $p.t("coodle/submit_final_selection") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,157 +0,0 @@
|
||||
import { CoreFilterCmpt } from "../../../filter/Filter.js";
|
||||
|
||||
import { dateFilter } from "../../../../tabulator/filters/Dates.js";
|
||||
import CoodleApi from "../../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "InactiveCoodleSurveys",
|
||||
components: { CoreFilterCmpt },
|
||||
emits: ["showSurveyDetails"],
|
||||
data() {
|
||||
return {
|
||||
inactiveSurveys: [],
|
||||
inactiveSurveysTableConfig: {
|
||||
persistenceID: "inactiveSurveysTable",
|
||||
movableColumns: false,
|
||||
minHeight: 300,
|
||||
layout: "fitColumns",
|
||||
initialSort: [{ column: "endedAt", dir: "desc" }],
|
||||
pagination: true,
|
||||
paginationSize: 25,
|
||||
paginationCounter: "rows",
|
||||
locale: true,
|
||||
columns: [
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/title",
|
||||
field: "title",
|
||||
headerFilter: true,
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/creator",
|
||||
field: "creatorName",
|
||||
headerFilter: true,
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/started_on",
|
||||
field: "createdAt",
|
||||
headerFilter: true,
|
||||
minWidth: 100,
|
||||
formatter: "datetime",
|
||||
formatterParams: this.datetimeFormatterParams(),
|
||||
headerFilterFunc: "dates",
|
||||
headerFilter: dateFilter,
|
||||
},
|
||||
{
|
||||
title: "placeholder",
|
||||
titlePhrase: "coodle/ended_on",
|
||||
field: "endedAt",
|
||||
headerFilter: true,
|
||||
minWidth: 100,
|
||||
formatter: "datetime",
|
||||
formatterParams: this.datetimeFormatterParams(),
|
||||
headerFilterFunc: "dates",
|
||||
headerFilter: dateFilter,
|
||||
},
|
||||
],
|
||||
},
|
||||
isFetchingSurveys: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async fetchInactiveSurveys() {
|
||||
this.isFetchingSurveys = true;
|
||||
const surveysResponse = await this.$api.call(
|
||||
CoodleApi.getInactiveSurveys(),
|
||||
);
|
||||
this.isFetchingSurveys = false;
|
||||
|
||||
if (surveysResponse.meta.status !== "success") return;
|
||||
|
||||
this.inactiveSurveys = surveysResponse.data.map((surveyData) => {
|
||||
return {
|
||||
id: surveyData.id,
|
||||
title: surveyData.title,
|
||||
createdAt: surveyData.created_at.split(".")[0],
|
||||
completedAt: surveyData.completed_at?.split(".")[0],
|
||||
canceledAt: surveyData.canceled_at?.split(".")[0],
|
||||
creator: {
|
||||
uid: surveyData.creator.uid,
|
||||
name: surveyData.creator.name,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
this.inactiveSurveysTableConfig.data = this.inactiveSurveys.map(
|
||||
(survey) => {
|
||||
return {
|
||||
id: survey.id,
|
||||
title: survey.title,
|
||||
creatorName: survey.creator.name,
|
||||
createdAt: survey.createdAt,
|
||||
endedAt: survey.completedAt ?? survey.canceledAt,
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
afterInactiveSurveysTableBuilt() {
|
||||
this.$refs.inactiveSurveysTable.tabulator.on(
|
||||
"rowClick",
|
||||
(event, row) => {
|
||||
this.$emit("showSurveyDetails", {
|
||||
surveyId: row._row.data.id,
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
datetimeFormatterParams: function () {
|
||||
const params = {
|
||||
inputFormat: "yyyy-MM-dd hh:mm:ss",
|
||||
outputFormat: "dd.MM.yyyy",
|
||||
invalidPlaceholder: "(invalid date)",
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
return params;
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.fetchInactiveSurveys();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="card mb-4" style="height:100%">
|
||||
<div class="card-body">
|
||||
<div
|
||||
v-if="isFetchingSurveys"
|
||||
class="d-flex justify-content-center align-items-center mt-5"
|
||||
>
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">{{ $p.t("coodle/loading") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="!inactiveSurveys?.length"
|
||||
class="d-flex justify-content-center align-items-center mt-5"
|
||||
>
|
||||
<h3 class="fw-bold">{{$p.t("coodle/no_inactive_surveys_found") }}</h3>
|
||||
</div>
|
||||
<div v-else class="d-flex flex-row overflow-x-auto">
|
||||
<div class="flex-shrink">
|
||||
<core-filter-cmpt
|
||||
@tableBuilt="afterInactiveSurveysTableBuilt()"
|
||||
:noColumnFilter="true"
|
||||
:title="'Past surveys'"
|
||||
:ref="'inactiveSurveysTable'"
|
||||
:tabulatorOptions="inactiveSurveysTableConfig"
|
||||
:sideMenu="false"
|
||||
tableOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,226 +0,0 @@
|
||||
import ActiveCoodleSurveys from "./Components/ActiveCoodleSurveys.js";
|
||||
import InactiveCoodleSurveys from "./Components/InactiveCoodleSurveys.js";
|
||||
import CoodleSurvey from "./Components/CoodleSurvey.js";
|
||||
import CoodleFreeBusy from "./Components/CoodleFreeBusy.js";
|
||||
import CoodleIcal from "./Components/CoodleIcal.js";
|
||||
|
||||
import ApiAuthinfo from "../../../api/factory/authinfo.js";
|
||||
import CoodleApi from "../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "Coodle",
|
||||
components: {
|
||||
ActiveCoodleSurveys,
|
||||
InactiveCoodleSurveys,
|
||||
CoodleSurvey,
|
||||
CoodleFreeBusy,
|
||||
CoodleIcal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
authInfo: null,
|
||||
view: "activeSurveysTable",
|
||||
survey: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isDarkMode() {
|
||||
return this.$theme.theme_name.value == "dark";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getTabStylingClass(isSelected) {
|
||||
if (this.isDarkMode && isSelected) {
|
||||
return "btn-light";
|
||||
} else if (this.isDarkMode && !isSelected) {
|
||||
return "btn-outline-light";
|
||||
} else if (!this.isDarkMode && isSelected) {
|
||||
return "btn-dark";
|
||||
} else {
|
||||
return "btn-outline-dark";
|
||||
}
|
||||
},
|
||||
switchToTab(tab) {
|
||||
if (this.view === tab && tab !== "survey") return;
|
||||
|
||||
this.view = tab;
|
||||
this.survey = null;
|
||||
},
|
||||
async getAuthInfo() {
|
||||
const authInfoResponse = await this.$api.call(
|
||||
ApiAuthinfo.getAuthInfo(),
|
||||
);
|
||||
this.authInfo = {
|
||||
uid: authInfoResponse.data.uid,
|
||||
name: authInfoResponse.data.name,
|
||||
};
|
||||
},
|
||||
async showSurveyDetails(surveyId) {
|
||||
const surveyResponse = await this.$api.call(
|
||||
CoodleApi.getSurvey(surveyId),
|
||||
);
|
||||
if (surveyResponse.meta.status === "success") {
|
||||
this.survey = this.parseIncomingSurveyData(surveyResponse.data);
|
||||
this.view = "survey";
|
||||
} else {
|
||||
this.view = "activeSurveysTable";
|
||||
}
|
||||
},
|
||||
parseIncomingSurveyData(surveyData) {
|
||||
return {
|
||||
id: surveyData.id,
|
||||
creator: surveyData.creator,
|
||||
title: surveyData.title,
|
||||
description: surveyData.description,
|
||||
timeslotDuration: surveyData.timeslot_duration,
|
||||
maxSelections: surveyData.max_selections,
|
||||
areParticipantsAnonymized:
|
||||
surveyData.are_participants_anonymized,
|
||||
areSelectionsAnonymized: surveyData.are_selections_anonymized,
|
||||
selectedTimeslotId: surveyData.selected_timeslot_id,
|
||||
endsAt: surveyData.ends_at.split(" ")[0],
|
||||
completedAt: surveyData.completed_at,
|
||||
canceledAt: surveyData.canceled_at,
|
||||
createdAt: surveyData.created_at.split(" ")[0],
|
||||
updatedAt: surveyData.updated_at.split(" ")[0],
|
||||
timeslots: surveyData.timeslots.map((timeslot) => {
|
||||
return {
|
||||
id: timeslot.id,
|
||||
startsAt: timeslot.starts_at,
|
||||
};
|
||||
}),
|
||||
participants: surveyData.participants,
|
||||
externalParticipants: surveyData.external_participants,
|
||||
voteTallies: surveyData.vote_tallies,
|
||||
};
|
||||
},
|
||||
async afterSurveyCreated(surveyId, shouldInformParticipants) {
|
||||
await this.showSurveyDetails(surveyId);
|
||||
if (shouldInformParticipants) {
|
||||
this.$api.call(
|
||||
CoodleApi.emailParticipants(surveyId, "created"),
|
||||
);
|
||||
}
|
||||
},
|
||||
async afterSurveyUpdated(surveyId, shouldInformParticipants) {
|
||||
await this.showSurveyDetails(surveyId);
|
||||
if (shouldInformParticipants) {
|
||||
this.$api.call(
|
||||
CoodleApi.emailParticipants(surveyId, "updated"),
|
||||
);
|
||||
}
|
||||
},
|
||||
async afterSurveyCanceled(surveyId, shouldInformParticipants) {
|
||||
await this.showSurveyDetails(surveyId);
|
||||
if (shouldInformParticipants) {
|
||||
this.$api.call(
|
||||
CoodleApi.emailParticipants(surveyId, "canceled"),
|
||||
);
|
||||
}
|
||||
},
|
||||
async afterSurveyCompleted(
|
||||
surveyId,
|
||||
shouldInformParticipants,
|
||||
selectedRoomId,
|
||||
) {
|
||||
await this.showSurveyDetails(surveyId);
|
||||
if (shouldInformParticipants) {
|
||||
this.$api.call(
|
||||
CoodleApi.emailParticipants(surveyId, "completed", {
|
||||
selectedRoomId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.getAuthInfo();
|
||||
await this.$p.loadCategory(["coodle", "global", "ui"]);
|
||||
if (this.$route.query?.id?.length) {
|
||||
this.showSurveyDetails(this.$route.query.id);
|
||||
this.$router.replace({ query: null });
|
||||
}
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="h-100 d-flex flex-column gap-2">
|
||||
<h2 class="m-0">Coodle</h2>
|
||||
<div>
|
||||
<div class="d-flex flex-row gap-2 w-100 overflow-x-auto">
|
||||
<div
|
||||
@click="switchToTab('activeSurveysTable')"
|
||||
:class="getTabStylingClass(view === 'activeSurveysTable')"
|
||||
class="btn d-flex flex-row gap-2 align-items-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-person-booth fa-lg"></i>
|
||||
</div>
|
||||
<span class="text-nowrap">{{ $p.t("coodle/active_surveys") }}</span>
|
||||
</div>
|
||||
<div
|
||||
@click="switchToTab('pastSurveysTable')"
|
||||
:class="getTabStylingClass(view === 'pastSurveysTable')"
|
||||
class="btn d-flex flex-row gap-2 align-items-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-flag-checkered fa-lg"></i>
|
||||
</div>
|
||||
<span class="text-nowrap">{{ $p.t("coodle/inactive_surveys") }}</span>
|
||||
</div>
|
||||
<div
|
||||
@click="switchToTab('survey')"
|
||||
:class="getTabStylingClass(view === 'survey' && !survey?.id)"
|
||||
class="btn d-flex flex-row gap-2 align-items-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-circle-plus fa-lg"></i>
|
||||
</div>
|
||||
<span class="text-nowrap">{{ $p.t("coodle/create_survey") }}</span>
|
||||
</div>
|
||||
<div
|
||||
@click="switchToTab('freeBusySettings')"
|
||||
:class="getTabStylingClass(view === 'freeBusySettings')"
|
||||
class="btn d-flex flex-row gap-2 align-items-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-gear fa-lg"></i>
|
||||
</div>
|
||||
<span class="text-nowrap">{{ $p.t("coodle/freebusy_settings") }}</span>
|
||||
</div>
|
||||
<div
|
||||
@click="switchToTab('ical')"
|
||||
:class="getTabStylingClass(view === 'ical')"
|
||||
class="btn d-flex flex-row gap-2 align-items-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-calendar fa-lg"></i>
|
||||
</div>
|
||||
<span class="text-nowrap">{{ "Coodle iCal" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 mt-1">
|
||||
<active-coodle-surveys
|
||||
v-if="view === 'activeSurveysTable'"
|
||||
@showSurveyDetails="showSurveyDetails($event.surveyId)"
|
||||
/>
|
||||
<inactive-coodle-surveys
|
||||
v-else-if="view === 'pastSurveysTable'"
|
||||
@showSurveyDetails="showSurveyDetails($event.surveyId)"
|
||||
/>
|
||||
<coodle-survey
|
||||
v-else-if="view === 'survey'"
|
||||
@surveyCreationCanceled="switchToTab('activeSurveysTable')"
|
||||
@surveyCreated="afterSurveyCreated($event.surveyId, $event.shouldInformParticipants)"
|
||||
@surveyUpdated="afterSurveyUpdated($event.surveyId, $event.shouldInformParticipants)"
|
||||
@surveyCanceled="afterSurveyCanceled($event.surveyId, $event.shouldInformParticipants)"
|
||||
@surveyCompleted="
|
||||
afterSurveyCompleted($event.surveyId, $event.shouldInformParticipants, $event.selectedRoomId)
|
||||
"
|
||||
:survey="survey"
|
||||
:authInfo="authInfo"
|
||||
/>
|
||||
<coodle-free-busy v-else-if="view === 'freeBusySettings'" :authUid="authInfo?.uid" />
|
||||
<coodle-ical v-else-if="view === 'ical'" :authUid="authInfo?.uid" />
|
||||
</div>
|
||||
</div>`,
|
||||
};
|
||||
@@ -1,73 +0,0 @@
|
||||
import CoodleSurvey from "./Components/CoodleSurvey.js";
|
||||
|
||||
import CoodleApi from "../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleExternal",
|
||||
components: { CoodleSurvey },
|
||||
data() {
|
||||
return {
|
||||
survey: null,
|
||||
authExternalParticipantId: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async fetchSurvey() {
|
||||
const surveyResponse = await this.$api.call(
|
||||
CoodleApi.getSurveyForExternalParticipant(
|
||||
this.$route.params.surveyId,
|
||||
this.$route.params.accessKey,
|
||||
),
|
||||
);
|
||||
|
||||
if (surveyResponse.meta.status === "success") {
|
||||
this.survey = this.parseIncomingSurveyData(surveyResponse.data);
|
||||
this.authExternalParticipantId = this.survey.externalParticipants.find(
|
||||
(externalParticipant) => !!externalParticipant.id,
|
||||
).id;
|
||||
}
|
||||
},
|
||||
parseIncomingSurveyData(surveyData) {
|
||||
return {
|
||||
id: surveyData.id,
|
||||
creator: surveyData.creator,
|
||||
title: surveyData.title,
|
||||
description: surveyData.description,
|
||||
timeslotDuration: surveyData.timeslot_duration,
|
||||
maxSelections: surveyData.max_selections,
|
||||
areParticipantsAnonymized:
|
||||
surveyData.are_participants_anonymized,
|
||||
areSelectionsAnonymized: surveyData.are_selections_anonymized,
|
||||
selectedTimeslotId: surveyData.selected_timeslot_id,
|
||||
endsAt: surveyData.ends_at.split(" ")[0],
|
||||
completedAt: surveyData.completed_at,
|
||||
canceledAt: surveyData.canceled_at,
|
||||
createdAt: surveyData.created_at.split(" ")[0],
|
||||
updatedAt: surveyData.updated_at.split(" ")[0],
|
||||
timeslots: surveyData.timeslots.map((timeslot) => {
|
||||
return {
|
||||
id: timeslot.id,
|
||||
startsAt: timeslot.starts_at,
|
||||
};
|
||||
}),
|
||||
participants: surveyData.participants,
|
||||
externalParticipants: surveyData.external_participants,
|
||||
voteTallies: surveyData.vote_tallies,
|
||||
};
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.fetchSurvey();
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div>
|
||||
<coodle-survey
|
||||
@surveyUpdated="fetchSurvey()"
|
||||
:survey="survey"
|
||||
:authInfo="null"
|
||||
:authExternalParticipantId="authExternalParticipantId"
|
||||
:isExternal="true"
|
||||
/>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -18,8 +18,7 @@ export default {
|
||||
logoutUrl: String,
|
||||
selectedtypes: Array,
|
||||
searchbaroptions: Object,
|
||||
searchfunction: Function,
|
||||
isExternal: Boolean,
|
||||
searchfunction: Function
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
@@ -105,9 +104,7 @@ export default {
|
||||
},
|
||||
},
|
||||
created(){
|
||||
if (!this.$props.isExternal) {
|
||||
this.fetchMenu();
|
||||
}
|
||||
this.fetchMenu();
|
||||
},
|
||||
mounted(){
|
||||
this.$p.loadCategory(['ui', 'global', 'profilUpdate'])
|
||||
@@ -116,17 +113,17 @@ export default {
|
||||
});
|
||||
},
|
||||
template: /*html*/`
|
||||
<div id="cis-header-bar" :class="{'justify-content-between': $props.isExternal}" class="d-flex flex-row flex-grow-1">
|
||||
<div id="nav-logo" :class="{'d-none d-lg-block': !$props.isExternal}">
|
||||
<div id="cis-header-bar" class="d-flex flex-row flex-grow-1">
|
||||
<div id="nav-logo" class="d-none d-lg-block">
|
||||
<div class="d-flex h-100 justify-content-between">
|
||||
<a :href="rootUrl">
|
||||
<img :src="logoUrl" alt="Corporate Identity Logo">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
v-if="isNarrow && !$props.isExternal"
|
||||
v-if="isNarrow"
|
||||
:class="{'collapse multi-collapse collapse-horizontal show': isMobile}"
|
||||
id="navbar-toggler-collapsible"
|
||||
>
|
||||
@@ -138,7 +135,6 @@ export default {
|
||||
</div>
|
||||
|
||||
<fhc-searchbar
|
||||
v-if="!$props.isExternal"
|
||||
:searchoptions="searchbaroptions"
|
||||
:searchfunction="searchfunction"
|
||||
ref="searchbar"
|
||||
@@ -163,7 +159,6 @@ export default {
|
||||
</fhc-searchbar>
|
||||
|
||||
<div
|
||||
v-if="!$props.isExternal"
|
||||
id="options-collapsible"
|
||||
:class="{'collapse multi-collapse collapse-horizontal show': isMobile}"
|
||||
>
|
||||
@@ -189,40 +184,9 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="$props.isExternal" class="d-flex flex-row align-items-center justify-content-center gap-2 pe-2">
|
||||
<theme-switch></theme-switch>
|
||||
<div>
|
||||
<span
|
||||
id="externalPageLanguageDropdownToggler"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#externalPageLanguageDropdown"
|
||||
aria-expanded="false"
|
||||
aria-controls="externalPageLanguageDropdown"
|
||||
class="fhc-primary-highlight-bg align-self-center btn btn-secondary rounded-5"
|
||||
>
|
||||
<i class="fa-solid fa-language fa-2xl"></i>
|
||||
</span>
|
||||
<div
|
||||
id="externalPageLanguageDropdown"
|
||||
ref="externalPageLanguageDropdown"
|
||||
class="top-100 end-0 collapse position-absolute"
|
||||
aria-labelledby="externalPageLanguageDropdownToggler"
|
||||
>
|
||||
<cis-sprachen />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav
|
||||
v-if="!$props.isExternal"
|
||||
id="nav-main"
|
||||
class="offcanvas offcanvas-start"
|
||||
tabindex="-1"
|
||||
aria-labelledby="nav-main-btn"
|
||||
data-bs-backdrop="false"
|
||||
>
|
||||
<nav id="nav-main" class="offcanvas offcanvas-start" tabindex="-1" aria-labelledby="nav-main-btn" data-bs-backdrop="false">
|
||||
<div id="nav-main-sticky">
|
||||
<div class="d-flex flex-row h-100">
|
||||
<div class="offcanvas-body p-0">
|
||||
|
||||
@@ -72,20 +72,10 @@ export default {
|
||||
return this.entry.url.startsWith(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router)
|
||||
},
|
||||
target() {
|
||||
if (this.entry.template_kurzbz == 'redirect') {
|
||||
if (!this.entry.content)
|
||||
return '';
|
||||
let xmlDoc = (new DOMParser()).parseFromString(this.entry.content,"text/xml");
|
||||
let target = xmlDoc.getElementsByTagName('target')[0];
|
||||
if (!target)
|
||||
return '';
|
||||
|
||||
target = target.childNodes[0].nodeValue + "";
|
||||
if (target == 'content' || target == '_self')
|
||||
target = "";
|
||||
return target;
|
||||
if (this.entry?.target) {
|
||||
return this.entry.target;
|
||||
}
|
||||
return ''
|
||||
return '_self';
|
||||
},
|
||||
hasChilds() {
|
||||
return this.entry.childs && this.entry.childs.length !== 0;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
export default {
|
||||
props: {
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ["deleteCoodleTimeslot"],
|
||||
computed: {
|
||||
tooltipString() {
|
||||
const tooltipArray = [];
|
||||
|
||||
const dateFragments = this.$props.event.datum.split("-");
|
||||
tooltipArray.push(
|
||||
dateFragments[2] +
|
||||
"." +
|
||||
dateFragments[1] +
|
||||
"." +
|
||||
dateFragments[0] +
|
||||
".",
|
||||
);
|
||||
tooltipArray.push(this.start + "-" + this.end);
|
||||
|
||||
return tooltipArray.join("\n");
|
||||
},
|
||||
start() {
|
||||
return luxon.Duration.fromISOTime(this.event.beginn).toISOTime({
|
||||
suppressSeconds: true,
|
||||
});
|
||||
},
|
||||
end() {
|
||||
return luxon.Duration.fromISOTime(this.event.ende).toISOTime({
|
||||
suppressSeconds: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
template: /* html */ `
|
||||
<div
|
||||
class="coodle-calendar-event calendar-event-default h-100 w-100 p-1 d-flex flex-row"
|
||||
v-tooltip="tooltipString"
|
||||
>
|
||||
<div
|
||||
v-if="event?.beginn && event?.ende"
|
||||
class="d-flex flex-column justify-content-center align-items-center flex-grow-1"
|
||||
>
|
||||
<span>{{ start }}</span>
|
||||
<span>{{ end }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="d-flex justify-content-end align-items-start"
|
||||
>
|
||||
<div
|
||||
@click="$emit('deleteCoodleTimeslot', { timeslot: $props.event })"
|
||||
class="coodle-calendar-event-clear"
|
||||
>
|
||||
<i class="fa-solid fa-xmark fa-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
export default {
|
||||
props:{
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dateObject: null,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.dateObject = new Date(this.$props.event.isostart);
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<span>{{ $props.event.datum }}</span>
|
||||
<span>{{ $props.event.beginn.slice(0,5) }}</span>
|
||||
<span>{{ $props.event.end.slice(0,5) }}</span>
|
||||
</div>`,
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export default {
|
||||
props:{
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
template:`
|
||||
<div>Coodle</div>
|
||||
`
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
export default {
|
||||
props: {
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
template: /* html */ `
|
||||
<div
|
||||
class="coodle-calendar-event calendar-event-default h-100 w-100 p-1 d-flex flex-row"
|
||||
v-tooltip="tooltipString"
|
||||
></div>
|
||||
`,
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
export default {
|
||||
props:{
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dateObject: null,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.dateObject = new Date(this.$props.event.isostart);
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<span>{{ $props.event.datum }}</span>
|
||||
<span>{{ $props.event.beginn.slice(0,5) }}</span>
|
||||
<span>{{ $props.event.end.slice(0,5) }}</span>
|
||||
</div>`,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user