├── tmp
└── .placeholder
├── lib
├── .htaccess
├── fpdf
│ ├── .htaccess
│ ├── license.txt
│ ├── font
│ │ ├── courier.php
│ │ ├── courierb.php
│ │ ├── courieri.php
│ │ └── courierbi.php
│ └── install.txt
├── phplot
│ ├── .htaccess
│ ├── fonts
│ │ ├── Khula-Bold.ttf
│ │ ├── Khula-Light.ttf
│ │ ├── Khula-Regular.ttf
│ │ ├── Khula-SemiBold.ttf
│ │ └── Khula-ExtraBold.ttf
│ └── contrib
│ │ ├── data_table.example2.php
│ │ ├── prune_labels.example.php
│ │ ├── data_table.example3.php
│ │ ├── color_range.example.php
│ │ ├── prune_labels.test.php
│ │ ├── prune_labels.php
│ │ ├── color_range.test1.php
│ │ ├── README.txt
│ │ ├── data_table.example1.php
│ │ └── color_range.test2.php
├── htmlinput.php
├── const.php
├── texttemplate.php
├── tools.php
├── lang.php
├── api.php
├── permissions.php
├── md5sums.txt
├── roles.php
├── loader.php
├── color.php
├── mailer.php
├── browser.php
├── plan.php
└── boxes.php
├── index.php
├── .gitignore
├── frontend
├── img
│ ├── bg.png
│ ├── logo.png
│ ├── vendor.png
│ ├── favicon.png
│ ├── vendor-logo.png
│ ├── resource_types
│ │ ├── Room.svg
│ │ ├── Phone.svg
│ │ ├── General.svg
│ │ ├── Car.svg
│ │ └── Computer.svg
│ ├── add.svg
│ ├── ok.svg
│ ├── warning.svg
│ ├── home.svg
│ ├── swap.svg
│ ├── delete.svg
│ ├── code.svg
│ ├── file.svg
│ ├── flash-auto.svg
│ ├── info-gray.svg
│ ├── user.svg
│ ├── clean.svg
│ ├── check.svg
│ ├── book.svg
│ ├── email.svg
│ ├── free.svg
│ ├── month.svg
│ ├── calendar.svg
│ ├── export.svg
│ ├── edit.svg
│ ├── roster.svg
│ ├── uncheck.svg
│ ├── copy.svg
│ ├── info-white.svg
│ ├── chart.svg
│ ├── info.svg
│ ├── key.svg
│ ├── anniversary.svg
│ ├── note.svg
│ ├── cancel.svg
│ ├── ldap-directory.svg
│ ├── refresh.svg
│ ├── resources.svg
│ ├── image.svg
│ ├── lock.svg
│ ├── sync.svg
│ ├── grid.svg
│ ├── template.svg
│ ├── attach-file.svg
│ ├── users.svg
│ ├── checklist.svg
│ ├── loader.svg
│ ├── birthday.svg
│ ├── roles.svg
│ ├── absent.svg
│ ├── ok1.svg
│ ├── ok2.svg
│ ├── absent-last-minute.svg
│ ├── absent-approve.svg
│ └── holiday.svg
├── manual
│ └── de.pdf
├── css
│ ├── mobile.css
│ └── tux.css
├── board.inc.php
├── session.php
├── head.inc.php
├── fileprovider.php
├── views
│ ├── start.php
│ ├── about.php
│ ├── changePassword.php
│ ├── viewIcsUrl.php
│ ├── holidays.php
│ ├── userBirthdays.php
│ ├── deployFile.php
│ ├── deployNote.php
│ ├── userAnniversaries.php
│ ├── resources.php
│ ├── editTextTemplates.php
│ ├── dbMaintenance.php
│ ├── roles.php
│ ├── assignUsersToRoster.php
│ └── copyServices.php
├── js
│ └── main.js
├── ajaxHandler.php
├── export.php
└── setup.php
├── template
├── icsmail_text.txt
├── mail_absence_approved1.txt
├── mail_absence_approved2.txt
├── mail_absence_declined.txt
├── icsmail_text_cancel.txt
├── mail_new_absence.txt
└── mail_new_swap_service.txt
├── .github
├── screenshots
│ ├── 0start.png
│ ├── 1users.png
│ ├── 2plan.png
│ ├── 3swap.png
│ ├── 1services.png
│ ├── 3absence.png
│ ├── 1birthdays.png
│ ├── 2planfilled.png
│ ├── 3myservices.png
│ ├── 1usersettings.png
│ ├── 2useroverview.png
│ └── 1userconstraints.png
└── FUNDING.yml
├── UPGRADE.md
├── api
├── html.php
├── pdf.php
└── ics.php
└── conf.php.example
/tmp/.placeholder:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/.htaccess:
--------------------------------------------------------------------------------
1 | Deny from all
2 |
--------------------------------------------------------------------------------
/lib/fpdf/.htaccess:
--------------------------------------------------------------------------------
1 | Allow from all
2 |
--------------------------------------------------------------------------------
/lib/phplot/.htaccess:
--------------------------------------------------------------------------------
1 | Allow from all
2 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | 'example.org'.
5 |
--------------------------------------------------------------------------------
/frontend/board.inc.php:
--------------------------------------------------------------------------------
1 |
2 |
9 |

10 |
11 |
12 |
13 | licenseUsers <= license::FREE_USERS) { ?>
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | superadmin > 0 || count($adminRosters) > 0 || count($userRosters) > 0) { ?>
22 |
23 |
24 |
25 | licenseValid) { ?>
26 |
licenseCompany); ?>
27 |
28 |
29 | superadmin > 0) { ?>
30 |
31 |
32 |
33 | 0) { ?>
34 |
35 |
36 |
37 |
38 | '.htmlspecialchars($ar->roster_title).'';
40 | } ?>
41 |
42 |
43 |
44 |
45 |
46 | 0) { ?>
47 |
48 |
49 |
50 |
51 | '.htmlspecialchars($ar->roster_title).'';
53 | } ?>
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/frontend/img/ok.svg:
--------------------------------------------------------------------------------
1 |
2 |
37 | ldap > 0) {
9 | die(''.LANG['unable_to_change_password_ldap'].'
');
10 | }
11 |
12 | if(isset($_POST['old_pw']) && isset($_POST['new_pw']) && isset($_POST['confirm_pw'])) {
13 | $error = false;
14 |
15 | if(!$error) if(!password_verify($_POST['old_pw'], $currentUser->password)) {
16 | $info = LANG['old_password_not_correct'];
17 | $infoclass = 'red';
18 | $error = true;
19 | }
20 | if(!$error) if($_POST['new_pw'] != $_POST['confirm_pw']) {
21 | $info = LANG['passwords_do_not_match'];
22 | $infoclass = 'red';
23 | $error = true;
24 | }
25 |
26 | if(!$error) if($db->updateUserPassword(
27 | $currentUser->id,
28 | password_hash($_POST['new_pw'], PASSWORD_DEFAULT)
29 | )) {
30 | $info = LANG['password_changed'];
31 | $infoclass = 'green';
32 | } else {
33 | $info = LANG['password_could_not_be_changed'].' '.$db->getLastStatement()->error;
34 | $infoclass = 'red';
35 | }
36 | }
37 | ?>
38 |
69 |
--------------------------------------------------------------------------------
/frontend/img/resource_types/General.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/img/sync.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/ajaxHandler.php:
--------------------------------------------------------------------------------
1 | getUser($_SESSION['mp_userid']);
6 |
7 |
8 | if(isset($_POST['action'])) {
9 | if($_POST['action'] == 'remove_assignment' && !empty($_POST['id'])) {
10 |
11 | $ps = $db->getPlannedService($_POST['id']);
12 | if(!$perm->isUserAdminForRoster($currentUser, $ps->service_roster_id)) {
13 | die(LANG['no_admin_rights_for_this_roster']);
14 | }
15 |
16 | $plan = new plan($db);
17 | if($plan->removeAssignment($ps->id)) {
18 | die('OK');
19 | } else {
20 | die(LANG['error'].': '.$db->getLastStatement()->error);
21 | }
22 |
23 | }
24 | elseif($_POST['action'] == 'remove_file' && !empty($_POST['id'])) {
25 |
26 | $plannedServiceFile = $db->getPlannedServiceFile($_POST['id']);
27 | if($plannedServiceFile != null) {
28 | $service = $db->getService($plannedServiceFile->service_id);
29 | if(!$perm->isUserAdminForRoster($currentUser, $service->roster_id)) {
30 | die(LANG['no_admin_rights_for_this_roster']);
31 | }
32 |
33 | if($db->removePlannedServiceFile($plannedServiceFile->id)) {
34 | die('OK');
35 | } else {
36 | die(LANG['error'].': '.$db->getLastStatement()->error);
37 | }
38 | }
39 |
40 | }
41 | elseif($_POST['action'] == 'remove_resource' && !empty($_POST['id'])) {
42 |
43 | $plannedServiceResource = $db->getPlannedServiceResource($_POST['id']);
44 | if($plannedServiceResource != null) {
45 | $service = $db->getService($plannedServiceResource->service_id);
46 | if(!$perm->isUserAdminForRoster($currentUser, $service->roster_id)) {
47 | die(LANG['no_admin_rights_for_this_roster']);
48 | }
49 |
50 | if($db->removePlannedServiceResource($plannedServiceResource->id)) {
51 | die('OK');
52 | } else {
53 | die(LANG['error'].': '.$db->getLastStatement()->error);
54 | }
55 | }
56 |
57 | }
58 | elseif($_POST['action'] == 'set_scroll' && !empty($_POST['scroll'])) {
59 |
60 | $_SESSION['scroll'] = $_POST['scroll'];
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/frontend/img/grid.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/img/template.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/img/attach-file.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/lib/mailer.php:
--------------------------------------------------------------------------------
1 | dbhandle = $db;
8 | }
9 |
10 | function mailNewSwap($roster_id) {
11 | // send mail to all roster users
12 | foreach($this->dbhandle->getRosterUsers($roster_id) as $u) {
13 | if(!tools::isValidEmail($u->user_email)) continue;
14 | $body = texttemplate::processTemplate('mail_new_swap_service.txt', null);
15 | mail($u->user_email, LANG['new_service_swap_request'], $body);
16 | }
17 | }
18 |
19 | function mailNewAbsence($userid) {
20 | // send mail to all roster admins for approval
21 | foreach($this->dbhandle->getUserRosters($userid) as $ur) {
22 | foreach($this->dbhandle->getRosterAdmins($ur->roster_id) as $u) {
23 | if(!tools::isValidEmail($u->user_email)) continue;
24 | $body = texttemplate::processTemplate('mail_new_absence.txt', null);
25 | mail($u->user_email, LANG['new_absence_request'], $body);
26 | }
27 | }
28 | }
29 |
30 | function mailAbsenceApproved1($absence_id) {
31 | $absence = $this->dbhandle->getAbsence($absence_id);
32 | $user = $this->dbhandle->getUser($absence->user_id);
33 | if(tools::isValidEmail($user->email)) {
34 | $body = texttemplate::processTemplate('mail_absence_approved1.txt', null);
35 | mail($user->email, LANG['absence_request_confirmed'], $body);
36 | }
37 | }
38 |
39 | function mailAbsenceApproved2($absence_id) {
40 | $absence = $this->dbhandle->getAbsence($absence_id);
41 | $user = $this->dbhandle->getUser($absence->user_id);
42 | if(tools::isValidEmail($user->email)) {
43 | $body = texttemplate::processTemplate('mail_absence_approved2.txt', null);
44 | mail($user->email, LANG['absence_request_approved'], $body);
45 | }
46 | }
47 |
48 | function mailAbsenceDeclined($absence_id) {
49 | $absence = $this->dbhandle->getAbsence($absence_id);
50 | $user = $this->dbhandle->getUser($absence->user_id);
51 | if(tools::isValidEmail($user->email)) {
52 | $body = texttemplate::processTemplate('mail_absence_declined.txt', null);
53 | mail($user->email, LANG['absence_request_declined'], $body);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/img/users.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/img/checklist.svg:
--------------------------------------------------------------------------------
1 |
2 |
68 |
--------------------------------------------------------------------------------
/frontend/img/resource_types/Car.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/img/resource_types/Computer.svg:
--------------------------------------------------------------------------------
1 |
2 |
68 |
--------------------------------------------------------------------------------
/frontend/views/viewIcsUrl.php:
--------------------------------------------------------------------------------
1 | id.'&auth='.md5($currentUser->password).'&view='.$view;
9 | if($roster_id != -1) $param .= '&roster='.$roster_id;
10 | $server = $_SERVER['HTTP_HOST'];
11 | $link = "$protocol://$server$path$param";
12 | return $link;
13 | }
14 | ?>
15 |
16 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | getUserRosters($currentUser->id) as $r) { ?>
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/frontend/export.php:
--------------------------------------------------------------------------------
1 | getUser($_SESSION['mp_userid']);
8 |
9 | if(isset($_GET['export']) && isset($_GET['type'])) {
10 | if($_GET['export'] == 'plan' && !empty($_GET['roster']) && !empty($_GET['week'])) {
11 | // check user rights
12 | if($perm->isUserAdminForRoster($currentUser, $_GET['roster'])
13 | || $perm->isUserAssignedToRoster($currentUser, $_GET['roster'])) {
14 | if($_GET['type'] == 'pdf') {
15 | $pdf = new genpdf($db);
16 | $pdf->createPlanPdf($_GET['roster'], $_GET['week']);
17 | $pdf->getPdfHandle()->Output('I', 'MASTERPLAN');
18 | die();
19 | }
20 | } else {
21 | die(LANG['permission_error']);
22 | }
23 | }
24 | elseif($_GET['export'] == 'userServices' && !empty($_GET['roster']) && !empty($_GET['week'])) {
25 | // check user rights
26 | if($perm->isUserAdminForRoster($currentUser, $_GET['roster'])) {
27 | if($_GET['type'] == 'pdf') {
28 | $pdf = new genpdf($db);
29 | $pdf->createUserServicesPdf($_GET['roster'], $_GET['week']);
30 | $pdf->getPdfHandle()->Output('I', 'MASTERPLAN');
31 | die();
32 | }
33 | } else {
34 | die(LANG['permission_error']);
35 | }
36 | }
37 | elseif($_GET['export'] == 'freeUsers' && !empty($_GET['roster']) && !empty($_GET['week'])) {
38 | // check user rights
39 | if($perm->isUserAdminForRoster($currentUser, $_GET['roster'])) {
40 | if($_GET['type'] == 'pdf') {
41 | $pdf = new genpdf($db);
42 | $pdf->createFreeUsersPdf($_GET['roster'], $_GET['week']);
43 | $pdf->getPdfHandle()->Output('I', 'MASTERPLAN');
44 | die();
45 | }
46 | } else {
47 | die(LANG['permission_error']);
48 | }
49 | }
50 | elseif($_GET['export'] == 'absence' && !empty($_GET['user'])) {
51 | // check user rights
52 | if($perm->isUserSuperadmin($currentUser) || $currentUser->id == $_GET['user']) {
53 | if($_GET['type'] == 'pdf') {
54 | $pdf = new genpdf($db);
55 | $pdf->createAbsencePdf($_GET['user']);
56 | $pdf->getPdfHandle()->Output('I', 'MASTERPLAN');
57 | die();
58 | }
59 | } else {
60 | die(LANG['permission_error']);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/phplot/contrib/data_table.example1.php:
--------------------------------------------------------------------------------
1 | array("Label", 'Y1', 'Y2', 'Y3'),
32 | 'column_widths' => array(3, 1, 2, 3),
33 | 'column_formats' => array('%s', '%d', '%5.2f', '%6g'),
34 | 'width' => $tbl_width,
35 | 'height' => $tbl_height,
36 | 'data' => $data,
37 | 'column_alignments' => array('C', 'R', 'R', 'R'),
38 | );
39 |
40 | $img = imagecreate($img_width, $img_height);
41 | $white = imagecolorresolve($img, 255, 255, 255);
42 | $red = imagecolorresolve($img, 255, 0, 0);
43 | imageline($img, 0, $cy, $img_width-1, $cy, $red);
44 | imageline($img, $cx, 0, $cx, $img_height-1, $red);
45 |
46 | draw_data_table($img, array_merge($base_settings, array(
47 | 'position' => array(10, 10),
48 | )));
49 | draw_data_table($img, array_merge($base_settings, array(
50 | 'position' => array($cx + 10, 10),
51 | 'cellpadding' => 12,
52 | 'column_alignments' => array('R', 'L', 'R', 'R'),
53 | )));
54 | draw_data_table($img, array_merge($base_settings, array(
55 | 'position' => array(10, $cy + 10),
56 | 'color' => array(0x66, 0x66, 0xcc),
57 | )));
58 | draw_data_table($img, array_merge($base_settings, array(
59 | 'position' => array($cx + 10, $cy + 10),
60 | 'font' => 4,
61 | )));
62 |
63 | imagepng($img);
64 |
--------------------------------------------------------------------------------
/frontend/img/loader.svg:
--------------------------------------------------------------------------------
1 |
57 |
--------------------------------------------------------------------------------
/frontend/img/birthday.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/views/holidays.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | if(!empty($_POST['action'])) {
12 | if($_POST['action'] == 'removeHoliday' && !empty($_POST['id'])) {
13 | if($db->removeHoliday($_POST['id'])) {
14 | $info = LANG['holiday_removed'];
15 | $infoclass = 'green';
16 | } else {
17 | $info = LANG['holiday_could_not_be_removed'];
18 | $infoclass = 'red';
19 | }
20 | }
21 | }
22 | ?>
23 |
24 |
25 |
(getHolidays()); ?>)
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 | | | | |
40 |
41 | getHolidays() as $h) {
43 | $service_title = ''.LANG['all'].'';
44 | if($h->service_id != null) {
45 | $service_title = htmlspecialchars($h->service_shortname." ".$h->service_title);
46 | }
47 |
48 | echo '';
49 | echo '| '.htmlspecialchars($h->title).' | ';
50 | echo ''.htmlspecialchars($h->day).' | ';
51 | echo ''.$service_title.' | ';
52 | echo ''
53 | .' '
54 | .''
59 | .' | ';
60 | echo '
';
61 | }
62 | ?>
63 |
64 |
65 |
--------------------------------------------------------------------------------
/frontend/img/roles.svg:
--------------------------------------------------------------------------------
1 |
2 |
59 |
--------------------------------------------------------------------------------
/frontend/views/userBirthdays.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die('Sie benötigen Superadmin-Berechtigungen um diese Seite aufzurufen
');
9 | }
10 |
11 | $birthdayUsers = [];
12 | foreach($db->getUsers() as $u) {
13 | if(trim($u->birthday) != '')
14 | $birthdayUsers[] = $u;
15 | }
16 | usort($birthdayUsers, 'sortBirthdays');
17 |
18 | function sortBirthdays($a, $b) {
19 | $currentYearA = date('Y');
20 | $timeBirthdayA = strtotime($a->birthday);
21 | $timeNextBirthdayA = strtotime($currentYearA.'-'.date('m',$timeBirthdayA).'-'.date('d',$timeBirthdayA));
22 | if($timeNextBirthdayA < strtotime(date('Y-m-d')))
23 | $timeNextBirthdayA = strtotime('+ 1 year', $timeNextBirthdayA);
24 |
25 | $currentYearB = date('Y');
26 | $timeBirthdayB = strtotime($b->birthday);
27 | $timeNextBirthdayB = strtotime($currentYearB.'-'.date('m',$timeBirthdayB).'-'.date('d',$timeBirthdayB));
28 | if($timeNextBirthdayB < strtotime(date('Y-m-d')))
29 | $timeNextBirthdayB = strtotime('+ 1 year', $timeNextBirthdayB);
30 |
31 | if($timeNextBirthdayA == $timeNextBirthdayB) {
32 | return 0;
33 | }
34 | return ($timeNextBirthdayA < $timeNextBirthdayB) ? -1 : 1;
35 | }
36 | ?>
37 |
38 |
39 |
Kommende Geburtstage
40 |
41 |
42 |
43 | | Mitarbeiter | E-Mail | Geburtstag | Alter |
44 |
45 | birthday);
48 | $isToday = (date('m-d',$timeBirthday) == date('m-d'));
49 |
50 | $timeNextBirthday = strtotime(date('Y').'-'.date('m',$timeBirthday).'-'.date('d',$timeBirthday));
51 | if($timeNextBirthday < strtotime(date('Y-m-d')))
52 | $timeNextBirthday = strtotime('+ 1 year', $timeNextBirthday);
53 |
54 | echo '';
55 | echo '| '; boxes::echoUser($u); echo ' | ';
56 | echo ''.htmlspecialchars($u->email).' | ';
57 | echo ''.htmlspecialchars(strftime(DATE_FORMAT, $timeBirthday)).' | ';
58 | echo ''.(date('Y', $timeNextBirthday)-date('Y', $timeBirthday)).' | ';
59 | echo '
';
60 | }
61 | ?>
62 |
63 |
64 |
--------------------------------------------------------------------------------
/frontend/views/deployFile.php:
--------------------------------------------------------------------------------
1 | getService($_GET['service']);
17 | } else {
18 | die(''.LANG['service_not_found'].'
');
19 | }
20 |
21 | if(isset($_POST['service']) && isset($_POST['day']) && isset($_FILES['file'])) {
22 | // check user rights
23 | if($perm->isUserAdminForRoster($currentUser, $service->roster_id)) {
24 |
25 | if($db->createPlannedServiceFile($_POST['service'], $_POST['day'], $_FILES['file']['name'], file_get_contents($_FILES['file']['tmp_name']))) {
26 | echo "";
27 | die();
28 | } else {
29 | $info = LANG['error'].': '.$db->getLastStatement()->error;
30 | $infoclass = 'red';
31 | }
32 |
33 | } else {
34 | $info = LANG['no_admin_rights_for_this_roster'];
35 | $infoclass = 'yellow';
36 | }
37 | }
38 | ?>
39 |
40 |
41 |
42 |
43 |
44 |
72 |
73 |
--------------------------------------------------------------------------------
/frontend/img/absent.svg:
--------------------------------------------------------------------------------
1 |
2 |
73 |
--------------------------------------------------------------------------------
/frontend/views/deployNote.php:
--------------------------------------------------------------------------------
1 | getService($_GET['service']);
17 | } else {
18 | die(''.LANG['service_not_found'].'
');
19 | }
20 |
21 | $notes = $db->getPlannedServiceNotes($service->id, $day);
22 |
23 | if(isset($_POST['service']) && isset($_POST['day']) && isset($_POST['note'])) {
24 | // check user rights
25 | if($perm->isUserAdminForRoster($currentUser, $service->roster_id)) {
26 |
27 | if($db->updatePlannedServiceNote($_POST['service'], $_POST['day'], $_POST['note'])) {
28 | echo "";
29 | die();
30 | } else {
31 | $info = LANG['error'].': '.$db->getLastStatement()->error;
32 | $infoclass = 'red';
33 | }
34 |
35 | } else {
36 | $info = LANG['no_admin_rights_for_this_roster'];
37 | $infoclass = 'yellow';
38 | }
39 | }
40 | ?>
41 |
42 |
43 |
44 |
45 |
46 |
74 |
75 |
--------------------------------------------------------------------------------
/frontend/views/userAnniversaries.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | $users = [];
12 | foreach($db->getUsers() as $u) {
13 | if(trim($u->start_date) != '')
14 | $users[] = $u;
15 | }
16 | usort($users, 'sortAnniversaries');
17 |
18 | function sortAnniversaries($a, $b) {
19 | $currentYearA = date('Y');
20 | $timeBirthdayA = strtotime($a->start_date);
21 | $timeNextBirthdayA = strtotime($currentYearA.'-'.date('m',$timeBirthdayA).'-'.date('d',$timeBirthdayA));
22 | if($timeNextBirthdayA < strtotime(date('Y-m-d')))
23 | $timeNextBirthdayA = strtotime('+ 1 year', $timeNextBirthdayA);
24 |
25 | $currentYearB = date('Y');
26 | $timeBirthdayB = strtotime($b->start_date);
27 | $timeNextBirthdayB = strtotime($currentYearB.'-'.date('m',$timeBirthdayB).'-'.date('d',$timeBirthdayB));
28 | if($timeNextBirthdayB < strtotime(date('Y-m-d')))
29 | $timeNextBirthdayB = strtotime('+ 1 year', $timeNextBirthdayB);
30 |
31 | if($timeNextBirthdayA == $timeNextBirthdayB) {
32 | return 0;
33 | }
34 | return ($timeNextBirthdayA < $timeNextBirthdayB) ? -1 : 1;
35 | }
36 | ?>
37 |
38 |
39 |
40 |
41 |
42 |
43 | | | | |
44 |
45 | start_date);
48 | $isToday = (date('m-d',$timeStart) == date('m-d'));
49 |
50 | $timeNext = strtotime(date('Y').'-'.date('m',$timeStart).'-'.date('d',$timeStart));
51 | if($timeNext < strtotime(date('Y-m-d')))
52 | $timeNext = strtotime('+ 1 year', $timeNext);
53 |
54 | echo '';
55 | echo '| '; boxes::echoUser($u); echo ' | ';
56 | echo ''.htmlspecialchars($u->email).' | ';
57 | echo ''.htmlspecialchars(strftime(DATE_FORMAT, $timeStart)).' | ';
58 | echo ''.htmlspecialchars(strftime(DATE_FORMAT, $timeNext)).': '.(date('Y', $timeNext)-date('Y', $timeStart)).' Jahr(en) | ';
59 | echo '
';
60 | }
61 | ?>
62 |
63 |
64 |
--------------------------------------------------------------------------------
/frontend/img/ok1.svg:
--------------------------------------------------------------------------------
1 |
2 |
71 |
--------------------------------------------------------------------------------
/frontend/img/ok2.svg:
--------------------------------------------------------------------------------
1 |
2 |
71 |
--------------------------------------------------------------------------------
/lib/browser.php:
--------------------------------------------------------------------------------
1 | checkBrowser();
10 | }
11 |
12 | private function checkBrowser() {
13 | if($this->isInternetExplorer()) {
14 | $this->valid = false;
15 | $this->message = LANG['browser_not_supported'];
16 | }
17 | elseif($this->isFirefox()) {
18 | $this->valid = false;
19 | $this->message = LANG['browser_not_supported_calendar_field'];
20 | }
21 | elseif($this->isSafari()) {
22 | $this->valid = false;
23 | $this->message = LANG['browser_not_supported_calendar_field'];
24 | }
25 | else {
26 | $this->valid = true;
27 | }
28 | }
29 |
30 | private function isInternetExplorer() {
31 | $ua = $_SERVER["HTTP_USER_AGENT"];
32 | return (preg_match('~MSIE|Internet Explorer~i', $ua) || (strpos($ua, 'Trident/7.0; rv:11.0') !== false));
33 | }
34 |
35 | private function isFirefox() {
36 | $ua = $_SERVER["HTTP_USER_AGENT"];
37 | return boolval(strpos($ua, 'Firefox'));
38 | }
39 |
40 | private function isSafari() {
41 | $ua = $_SERVER["HTTP_USER_AGENT"];
42 | return (strpos($ua, 'Safari') && !strpos($ua, 'Chrome'));
43 | }
44 |
45 | /* functions for detecting browsers and operating systems */
46 | public static function getOperatingSystem() {
47 | $ua = $_SERVER["HTTP_USER_AGENT"];
48 | if(strpos($ua, 'Android'))
49 | return "Android";
50 | elseif(strpos($ua, 'iPhone') || strpos($ua, 'iPad'))
51 | return "iPhone";
52 | elseif(strpos($ua, 'Palm'))
53 | return "Palm";
54 | elseif(strpos($ua, 'Linux'))
55 | return "Linux";
56 | elseif(strpos($ua, 'Macintosh'))
57 | return "Macintosh";
58 | elseif(strpos($ua, 'Windows'))
59 | return "Windows";
60 | else
61 | return "Unknown";
62 | }
63 |
64 | /*** for detecting different versions
65 | $msie_7 = strpos($ua, 'MSIE 7.0') ? true : false;
66 | $msie_8 = strpos($ua, 'MSIE 8.0') ? true : false;
67 | $firefox_2 = strpos($ua, 'Firefox/2.0') ? true : false;
68 | $firefox_3 = strpos($ua, 'Firefox/3.0') ? true : false;
69 | $firefox_3_6 = strpos($ua, 'Firefox/3.6') ? true : false;
70 | $safari_2 = strpos($ua, 'Safari/419') ? true : false; // Safari 2
71 | $safari_3 = strpos($ua, 'Safari/525') ? true : false; // Safari 3
72 | $safari_3_1 = strpos($ua, 'Safari/528') ? true : false; // Safari 3.1
73 | $safari_4 = strpos($ua, 'Safari/531') ? true : false; // Safari 4
74 | */
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/frontend/views/resources.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | if(!empty($_POST['action'])) {
12 | if($_POST['action'] == 'removeResource' && !empty($_POST['id'])) {
13 | if($db->removeResource($_POST['id'])) {
14 | $info = LANG['resource_removed'];
15 | $infoclass = 'green';
16 | } else {
17 | $info = LANG['error'].': '.$db->getLastStatement()->error;
18 | $infoclass = 'red';
19 | }
20 | }
21 | }
22 | ?>
23 |
24 |
25 |
(getResources()); ?>)
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 | | / | | | | |
40 |
41 | getResources() as $r) {
43 | echo '';
44 | echo ''
45 | .(($r->icon != null && $r->icon != '') ? ' ' : '')
46 | .' '
47 | .' | ';
48 | echo ''.htmlspecialchars($r->type).' | ';
49 | echo ''.htmlspecialchars($r->title).' | ';
50 | echo ''.htmlspecialchars(tools::shortText($r->description)).' | ';
51 | echo ''
52 | .' '
53 | .''
58 | .' | ';
59 | echo '
';
60 | }
61 | ?>
62 |
63 |
64 |
--------------------------------------------------------------------------------
/lib/plan.php:
--------------------------------------------------------------------------------
1 | dbhandle = $dbhandle;
8 | }
9 |
10 | public function getConsolidatedServicesByRosterAndDay($roster_id, $day) {
11 | // check if service is canceled because of a defined holiday
12 | $services = [];
13 | $holidays = $this->dbhandle->getHolidays();
14 | foreach($this->dbhandle->getServicesByRosterAndDay($roster_id, $day) as $s) {
15 | if(count($holidays) == 0) {
16 | $services[] = $s;
17 | } else {
18 | foreach($holidays as $holiday) {
19 | if(!($holiday->day == $day && ($holiday->service_id == null || $holiday->service_id == $s->id))) {
20 | $services[] = $s;
21 | break;
22 | }
23 | }
24 | }
25 | }
26 | return $services;
27 | }
28 |
29 | public function removeAssignment($id) {
30 | $ps = $this->dbhandle->getPlannedService($id);
31 | if($ps == null) return false;
32 |
33 | $sendCancelMail = false;
34 | if($ps->icsmail_sent != null && $ps->icsmail_sent != 0) $sendCancelMail = true;
35 |
36 | if(!$this->dbhandle->removePlannedService($ps->id)) {
37 | return false;
38 | } else {
39 | if($sendCancelMail) {
40 | $this->sendIcsMail($ps, true);
41 | }
42 | return true;
43 | }
44 | }
45 |
46 | public function sendIcsMail($ps, $cancel) {
47 | if(tools::isValidEmail($ps->user_email)) {
48 | $icsDomain = $this->dbhandle->getSetting('ics_domain');
49 | $icsRoster = $this->dbhandle->getRoster($ps->service_roster_id);
50 |
51 | $body = texttemplate::processTemplate('icsmail_text.txt', null);
52 | if($cancel) $body = texttemplate::processTemplate('icsmail_text_cancel.txt', null);
53 |
54 | $ics = ics::compileIcsBody(
55 | $ps->id,
56 | $icsDomain,
57 | $icsRoster->icsmail_sender_name,
58 | $icsRoster->icsmail_sender_address,
59 | $ps->user_fullname, $ps->user_email,
60 | strtotime($ps->day.' '.$ps->service_start),
61 | strtotime($ps->day.' '.$ps->service_end),
62 | $ps->service_shortname,
63 | $ps->service_title,
64 | $ps->service_location,
65 | $cancel
66 | );
67 | $success = ics::sendIcsMail(
68 | $icsRoster->icsmail_sender_name,
69 | $icsRoster->icsmail_sender_address,
70 | $ps->user_email,
71 | $ps->service_shortname,
72 | $body, $ics
73 | );
74 | if($cancel) {
75 | $this->dbhandle->setPlannedServiceSent($ps->id, 0);
76 | } else {
77 | $this->dbhandle->setPlannedServiceSent($ps->id, 1);
78 | }
79 | return $success;
80 | } else {
81 | return false;
82 | }
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/frontend/img/absent-last-minute.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/frontend/views/editTextTemplates.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | // update
12 | if(isset($_POST['writefile']) && isset($_POST['text'])) {
13 | $escapedFilename = str_replace('/','',$_POST['writefile']);
14 | if(file_exists(TEMPLATE_FILES.'/'.$escapedFilename) && file_put_contents(TEMPLATE_FILES.'/'.$escapedFilename, $_POST['text'])) {
15 | $info = LANG['template_saved'];
16 | $infoclass = 'green';
17 | } else {
18 | $info = LANG['template_could_not_be_saved'];
19 | $infoclass = 'red';
20 | }
21 | }
22 | ?>
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |

31 |
46 |
47 |
48 |
53 |
54 |
55 |

56 |
67 |
68 |
71 |
74 |
78 |
--------------------------------------------------------------------------------
/api/ics.php:
--------------------------------------------------------------------------------
1 | checkActive();
6 |
7 | if(!empty($_GET['user'])
8 | && !empty($_GET['auth'])
9 | && !empty($_GET['view'])) {
10 |
11 | $user = $db->getUser($_GET['user']);
12 | if(md5($user->password) != $_GET['auth']) die('authentication failed');
13 |
14 | $icsDomain = $db->getSetting('ics_domain', '');
15 |
16 | if($_GET['view'] == 'userServices') {
17 |
18 | // query planned services
19 | $allPlannedServices = $db->getPlannedServicesByUser($user->id);
20 | foreach($allPlannedServices as $ps) {
21 | // check if roster is released
22 | $released = false;
23 | foreach($db->getReleasedPlansByRoster($ps->service_roster_id) as $rp) {
24 | if($rp->day == $ps->day) {
25 | $released = true;
26 | break;
27 | }
28 | }
29 | if($released) {
30 | $icsRoster = $db->getRoster($ps->service_roster_id);
31 | $ics = ics::compileIcsBody(
32 | $ps->id,
33 | $icsDomain,
34 | $icsRoster->icsmail_sender_name,
35 | $icsRoster->icsmail_sender_address,
36 | $ps->user_fullname, $ps->user_email,
37 | strtotime($ps->day.' '.$ps->service_start),
38 | strtotime($ps->day.' '.$ps->service_end),
39 | $ps->service_shortname,
40 | $ps->service_title,
41 | $ps->service_location,
42 | false
43 | );
44 | echo $ics."\n\n";
45 | }
46 | }
47 |
48 | }
49 | elseif($_GET['view'] == 'roster' && !empty($_GET['roster'])) {
50 |
51 | // check permissions
52 | if(!
53 | ($perm->isUserAdminForRoster($user, $_GET['roster'])
54 | || $perm->isUserAssignedToRoster($user, $_GET['roster']))
55 | ) {
56 | die('permission violation');
57 | }
58 | // query planned services
59 | $allPlannedServices = $db->getPlannedServicesWithUserByRoster($_GET['roster']);
60 | foreach($allPlannedServices as $ps) {
61 | // check if roster is released
62 | $released = false;
63 | foreach($db->getReleasedPlansByRoster($ps->service_roster_id) as $rp) {
64 | if($rp->day == $ps->day) {
65 | $released = true;
66 | break;
67 | }
68 | }
69 | if($released) {
70 | $icsRoster = $db->getRoster($ps->service_roster_id);
71 | $ics = ics::compileIcsBody(
72 | $ps->id,
73 | $icsDomain,
74 | $icsRoster->icsmail_sender_name,
75 | $icsRoster->icsmail_sender_address,
76 | $ps->user_fullname, $ps->user_email,
77 | strtotime($ps->day.' '.$ps->service_start),
78 | strtotime($ps->day.' '.$ps->service_end),
79 | $ps->service_shortname,
80 | $ps->service_title,
81 | $ps->service_location,
82 | false
83 | );
84 | echo $ics."\n\n";
85 | }
86 | }
87 |
88 | }
89 | else {
90 | die('invalid api call');
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/frontend/views/dbMaintenance.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | // cleanup selected items
12 | if(isset($_POST['date'])) {
13 | $success = null;
14 | if($success !== false && isset($_POST['clear_old_assignments']) && $_POST['clear_old_assignments'] == 1) {
15 | $success = $db->removePlannedServicesOlderThan($_POST['date']);
16 | }
17 | if($success !== false && isset($_POST['clear_old_absences']) && $_POST['clear_old_absences'] == 1) {
18 | $success = $db->removeAbsencesOlderThan($_POST['date']);
19 | }
20 | if($success !== false && isset($_POST['clear_old_swaps']) && $_POST['clear_old_swaps'] == 1) {
21 | $success = $db->removeSwapServicesOlderThan($_POST['date']);
22 | }
23 | if($success !== false && isset($_POST['clear_old_services']) && $_POST['clear_old_services'] == 1) {
24 | $success = $db->removeExpiredServices();
25 | }
26 | if($success === true) {
27 | $info = LANG['database_cleaned'];
28 | $infoclass = 'green';
29 | } elseif($success === null) {
30 | $info = LANG['no_action_selected'];
31 | $infoclass = 'yellow';
32 | } else {
33 | $info = LANG['error'].': '.$db->getLastStatement()->error;
34 | $infoclass = 'red';
35 | }
36 | }
37 | ?>
38 |
76 |
--------------------------------------------------------------------------------
/frontend/views/roles.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | if(!empty($_POST['action'])) {
12 | if($_POST['action'] == 'removeRole' && !empty($_POST['id'])) {
13 | if($db->removeRole($_POST['id'])) {
14 | $info = LANG['role_removed'];
15 | $infoclass = 'green';
16 | } else {
17 | $info = LANG['error'].': '.$db->getLastStatement()->error;
18 | $infoclass = 'red';
19 | }
20 | }
21 | }
22 | ?>
23 |
24 |
25 |
(getRoles()); ?>)
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 | | | | | | | |
40 |
41 | getRoles() as $r) {
43 | // count assigned users
44 | $amount_users = 0;
45 | foreach($db->getUsers() as $u) {
46 | if($r != null) foreach($db->getUserRoles($u->id) as $role) {
47 | if($r->id == $role->role_id) {
48 | $amount_users ++;
49 | }
50 | }
51 | }
52 |
53 | echo '';
54 | echo '| '.htmlspecialchars($r->title).' | ';
55 | echo ''.htmlspecialchars($r->max_hours_per_day).' | ';
56 | echo ''.htmlspecialchars($r->max_services_per_week).' | ';
57 | echo ''.htmlspecialchars($r->max_hours_per_week).' | ';
58 | echo ''.htmlspecialchars($r->max_hours_per_month).' | ';
59 | echo ''.$amount_users.' | ';
60 | echo ''
61 | .' '
62 | .''
67 | .' | ';
68 | echo '
';
69 | }
70 | ?>
71 |
72 |
73 |
--------------------------------------------------------------------------------
/frontend/views/assignUsersToRoster.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | $roster = null;
12 |
13 | if(isset($_GET['roster'])) {
14 | $roster = $db->getRoster($_GET['roster']);
15 | } else {
16 | die(''.LANG['roster_not_found'].'
');
17 | }
18 |
19 | if(!empty($_POST['roster']) && !empty($_POST['users'])) {
20 | $success = null;
21 |
22 | $db->beginTransaction();
23 | $success = $db->removeUserToRosterByRoster($_POST['roster']);
24 | foreach($_POST['users'] as $uid) {
25 | if($success == null || $success == true)
26 | $success = $db->insertUserToRoster($uid, $_POST['roster']);
27 | }
28 |
29 | if($success) {
30 | $db->commitTransaction();
31 | header('Location: index.php?view=rosters');
32 | die();
33 | } else {
34 | $db->rollbackTransaction();
35 | $info = LANG['employee_could_not_be_assigned'].' '.$db->getLastStatement()->error;
36 | $infoclass = 'red';
37 | }
38 | }
39 | ?>
40 |
41 |
42 |
43 |
44 |
45 |
87 |
88 |
--------------------------------------------------------------------------------
/frontend/setup.php:
--------------------------------------------------------------------------------
1 | existsSchema();
8 |
9 | if($schemaExists && count($db->getUsers()) > 0) die();
10 |
11 | if(isset($_POST['username']) && isset($_POST['password']) && isset($_POST['password2'])) {
12 | if($_POST['password'] == $_POST['password2']) {
13 | $id = $db->createUser(
14 | 1, // superadmin-flag
15 | $_POST['username'], // login
16 | '', // firstname
17 | '', // lastname
18 | 'Administrator', // fullname
19 | '', // email
20 | '', // phone
21 | '', // mobile
22 | null, // birthday
23 | date('Y-m-d'), // start date
24 | '', // id_no
25 | 'initial admin user', // description
26 | 0, // ldap-flag
27 | 0, // locked-flag
28 | -1, // max hours per day
29 | -1, // may services per week
30 | -1, // may hours per week
31 | -1, // max hours per month
32 | '#fff' // color
33 | );
34 | $db->updateUserPassword(
35 | $id, password_hash($_POST['password'], PASSWORD_DEFAULT)
36 | );
37 | header('Location: index.php');
38 | die();
39 | } else {
40 | $info = LANG['passwords_do_not_match'];
41 | $infoclass = 'yellow';
42 | }
43 | }
44 | ?>
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
style="background-image:url('img/cdtitle.jpg')">
56 |
57 |

58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |

85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/phplot/contrib/color_range.test2.php:
--------------------------------------------------------------------------------
1 | superadmin == 0) {
8 | die(''.LANG['page_superadmin_right_needed'].'
');
9 | }
10 |
11 | $services = [];
12 | $preselectRoster = -1;
13 | foreach(explode(',',$_GET['services']) as $service_id) {
14 | $service = $db->getService($service_id);
15 | if($service != null) {
16 | $services[] = $service;
17 | $preselectRoster = $service->roster_id;
18 | }
19 | }
20 | if(count($services) == 0)
21 | die(''.LANG['no_services_selected'].'
');
22 |
23 | if(!empty($_POST['roster'])) {
24 | $success = null;
25 |
26 | $db->beginTransaction();
27 | foreach($services as $s) {
28 | if($success == null || $success == true)
29 | $success = $db->createService(
30 | $_POST['roster'], $s->shortname.$_POST['suffix'], $s->title.$_POST['suffix'], $s->location, $s->employees, $s->start, $s->end,
31 | $_POST['date_start'], $_POST['date_end'], $s->color, $s->wd1, $s->wd2, $s->wd3, $s->wd4, $s->wd5, $s->wd6, $s->wd7
32 | );
33 | }
34 |
35 | if($success) {
36 | $db->commitTransaction();
37 | header('Location: index.php?view=rosters');
38 | die();
39 | } else {
40 | $db->rollbackTransaction();
41 | $info = LANG['services_could_not_be_copied'].' '.$db->getLastStatement()->error;
42 | $infoclass = 'red';
43 | }
44 | }
45 | ?>
46 |
47 |
48 |
49 |
50 |
51 |
87 |
88 |
--------------------------------------------------------------------------------
/frontend/img/absent-approve.svg:
--------------------------------------------------------------------------------
1 |
2 |
92 |
--------------------------------------------------------------------------------
/frontend/img/holiday.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/lib/boxes.php:
--------------------------------------------------------------------------------
1 | color)) $extraClass = 'darkbg';
8 | echo '';
45 | }
46 |
47 | public static function echoAbsence($absence, $db) {
48 | $aplan = new autoplan($db);
49 | $approved = $aplan->isAbsenceApproved($absence);
50 |
51 | $extraClass = '';
52 | if(color::isDarkBg($absence->absent_type_color)) $extraClass .= ' darkbg';
53 | if(!$approved) $extraClass .= ' pending';
54 |
55 | echo '';
62 | }
63 |
64 | public static function echoUser($user) {
65 | $extraClass = ''; if(color::isDarkBg($user->color)) $extraClass = 'darkbg';
66 | echo '';
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------