From aeedfeee08b531a802985244bf5fe4f41074f3ea Mon Sep 17 00:00:00 2001 From: Ente Date: Wed, 22 Oct 2025 23:39:24 +0200 Subject: [PATCH 01/12] TT-201: Add link to documentation to the settings page --- api/v1/class/i18n/suite/users/settings/snippets_DE.json | 3 ++- api/v1/class/i18n/suite/users/settings/snippets_EN.json | 3 ++- api/v1/class/i18n/suite/users/settings/snippets_NL.json | 3 ++- suite/users/settings.php | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/v1/class/i18n/suite/users/settings/snippets_DE.json b/api/v1/class/i18n/suite/users/settings/snippets_DE.json index ff8b5b1..f3785ba 100644 --- a/api/v1/class/i18n/suite/users/settings/snippets_DE.json +++ b/api/v1/class/i18n/suite/users/settings/snippets_DE.json @@ -13,6 +13,7 @@ "note2_b": "hier", "note2_c": "um die Aktuellsten Änderungen der Webseite zu sehen.", "github_note": "Hilfe via GitHub", - "roadmap_note": "TimeTrack Roadmap" + "roadmap_note": "TimeTrack Roadmap", + "documentation": "TimeTrack Dokumentation" } \ No newline at end of file diff --git a/api/v1/class/i18n/suite/users/settings/snippets_EN.json b/api/v1/class/i18n/suite/users/settings/snippets_EN.json index 020505c..efe163d 100644 --- a/api/v1/class/i18n/suite/users/settings/snippets_EN.json +++ b/api/v1/class/i18n/suite/users/settings/snippets_EN.json @@ -13,6 +13,7 @@ "note2_b": "here", "note2_c": "to see the latest changes to the website.", "github_note": "Help via GitHub", - "roadmap_note": "TimeTrack Roadmap" + "roadmap_note": "TimeTrack Roadmap", + "documentation": "TimeTrack Documentation" } \ No newline at end of file diff --git a/api/v1/class/i18n/suite/users/settings/snippets_NL.json b/api/v1/class/i18n/suite/users/settings/snippets_NL.json index 4ee3f7f..839971e 100644 --- a/api/v1/class/i18n/suite/users/settings/snippets_NL.json +++ b/api/v1/class/i18n/suite/users/settings/snippets_NL.json @@ -13,6 +13,7 @@ "note2_b": "hier", "note2_c": "om de laatste wijzigingen aan de website te zien.", "github_note": "Hulp via GitHub", - "roadmap_note": "TimeTrack Roadmap" + "roadmap_note": "TimeTrack Roadmap", + "documentation": "TimeTrack Documentatie" } \ No newline at end of file diff --git a/suite/users/settings.php b/suite/users/settings.php index 792a67e..94d8e0a 100644 --- a/suite/users/settings.php +++ b/suite/users/settings.php @@ -85,7 +85,8 @@

| - + | +

TimeTrack Version: getTimeTrackVersion(); ?> | API Version: getToilVersion(); ?>

From 86abe1e5e9e80fa9c5905bc9b78e286ef38bfe2e Mon Sep 17 00:00:00 2001 From: Ente Date: Thu, 23 Oct 2025 00:58:24 +0200 Subject: [PATCH 02/12] Changelog and version update --- CHANGELOG.md | 6 ++++++ VERSION | 2 +- composer.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 268af8e..f58d44b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v8.2.1 + +* Added events for worktime correction proposals: `WorktimeCorrectionProposed` +* Sanitized outputs to prevent XSS attacks +* Added a link to the documentation within the settings page + ## v8.2 * Users are now able to propose corrections to worktimes when they have been marked as for "in review". diff --git a/VERSION b/VERSION index 0dc0f32..797ed2e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.2 \ No newline at end of file +8.2.1 \ No newline at end of file diff --git a/composer.json b/composer.json index 15b8cb9..bf85a3b 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "TimeTrack is a PHP-written time recording tool for small businesses", "type": "software", "license": "GNU GPL", - "version": "8.2", + "version": "8.2.1", "authors": [ { "name": "Bryan Boehnke-Avan", From f85272e5391ec964c16d75e7b10fd4b933c98bf2 Mon Sep 17 00:00:00 2001 From: Ente Date: Fri, 24 Oct 2025 00:13:20 +0200 Subject: [PATCH 03/12] TT-71: Dockerized version --- .dockerignore | 9 ++++++++ CHANGELOG.md | 8 +++++++ README.md | 14 +++++++++++ .../events/worktimes/WorktimeAddedEvent.php | 2 +- api/v1/class/projects/projects.arbeit.inc.php | 2 +- api/v1/inc/app.json.sample | 6 ++--- docker/apache2.conf | 11 +++++++++ docker/entrypoint.sh | 23 +++++++++++++++++++ 8 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 .dockerignore create mode 100644 docker/apache2.conf create mode 100644 docker/entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..63370ee --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.git +.gitignore +vendor +node_modules +Dockerfile +docker-compose.yml +*.md +*.log +tests diff --git a/CHANGELOG.md b/CHANGELOG.md index f58d44b..4d34958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## v8.2.2 + +* Fixed deprecation warning for `WorktimeAddedEvent` event +* Dockerized TimeTrack: + * Added `Dockerfile` and `docker-compose.yml` to run TimeTrack within Docker + * Added `entrypoint.sh` to handle database migrations and start Apache + * Updated `README.md` with Docker instructions + ## v8.2.1 * Added events for worktime correction proposals: `WorktimeCorrectionProposed` diff --git a/README.md b/README.md index 4ee7138..0352ef3 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,20 @@ TimeTrack aims to be an easy-to-use time recording software for small enterprise ## Installation +### Quick Install with Docker + +You can quickly get started with TimeTrack using Docker. Follow these steps: + +* Ensure you have Docker and Docker Compose installed on your system. +* Clone the TimeTrack repository: `git clone https://github.com/Ente/timetrack.git` & `cd timetrack` +* Build the Docker image: `docker build -t openducks/timetrack .` +* Create a `app.json` configuration file based on the provided sample below: `cp api/v1/inc/app.json.sample api/v1/inc/app.json` and edit it to fit your needs. + * Adjust the database settings if needed (at least `db_password`) + * Change the base_url to match your setup (e.g. `localhost:8080`) + * **Change the DB password before using in production within the `docker-compose.yml` and `app.json` file!** +* Start the services using Docker Compose: `docker-compose up -d` +* Access TimeTrack in your web browser at `http://localhost:8080` + ### Requirements - PHP 8.2 (`curl|gd|gmp|intl|mbstring|mysqli|openssl|xsl|gettext|dom|ldap`) - tested with PHP 8.2.26 diff --git a/api/v1/class/events/worktimes/WorktimeAddedEvent.php b/api/v1/class/events/worktimes/WorktimeAddedEvent.php index 80f9543..4b615f7 100644 --- a/api/v1/class/events/worktimes/WorktimeAddedEvent.php +++ b/api/v1/class/events/worktimes/WorktimeAddedEvent.php @@ -12,7 +12,7 @@ class WorktimeAddedEvent extends Event private string $Wtype; - public function __construct(string $username, array $dates = [], int $Wtype){ + public function __construct(string $username, int $Wtype, array $dates = []){ $this->username = $username; $this->dates = $dates; $this->Wtype = $Wtype; diff --git a/api/v1/class/projects/projects.arbeit.inc.php b/api/v1/class/projects/projects.arbeit.inc.php index d6b5282..c9aa17e 100644 --- a/api/v1/class/projects/projects.arbeit.inc.php +++ b/api/v1/class/projects/projects.arbeit.inc.php @@ -9,7 +9,7 @@ public function __construct() $this->db = new DB; } - public function addProject($name, $description = null, $items_assoc, $deadline = null, $owner = null) + public function addProject($name, $items_assoc, $description = null, $deadline = null, $owner = null) { Exceptions::error_rep("[PROJECTS] Adding project..."); if ($items_assoc == null) { diff --git a/api/v1/inc/app.json.sample b/api/v1/inc/app.json.sample index 1303b7c..4df2133 100644 --- a/api/v1/inc/app.json.sample +++ b/api/v1/inc/app.json.sample @@ -11,9 +11,9 @@ "force_theme": "false" }, "mysql": { - "db_host": "localhost", - "db_user": "root", - "db_password": "", + "db_host": "db", + "db_user": "timetool", + "db_password": "yourpassword", "db": "ab" }, "smtp": { diff --git a/docker/apache2.conf b/docker/apache2.conf new file mode 100644 index 0000000..4cccfe4 --- /dev/null +++ b/docker/apache2.conf @@ -0,0 +1,11 @@ + + DocumentRoot /var/www/html + + Options Indexes FollowSymLinks + AllowOverride All + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..c76b41e --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +# Waiting for the database to be ready +echo "Waiting for database to be ready..." +sleep 10 + +# Run Phinx migrations +echo "Running database migrations..." +if [ -f /var/www/html/vendor/bin/phinx ]; then + php /var/www/html/vendor/bin/phinx migrate || true +else + echo "Phinx not found — skipping migration." +fi + +# Start PC/SC daemon for smartcard/NFC +echo "Starting pcscd..." +pcscd --daemon & + + +# Start Apache +echo "Starting Apache..." +exec apache2-foreground From 7be914f25973f53cf33afe53152002ffe52a46e6 Mon Sep 17 00:00:00 2001 From: Ente Date: Fri, 24 Oct 2025 00:14:03 +0200 Subject: [PATCH 04/12] TT-71: README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0352ef3..1ed211b 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ You can quickly get started with TimeTrack using Docker. Follow these steps: * Start the services using Docker Compose: `docker-compose up -d` * Access TimeTrack in your web browser at `http://localhost:8080` +Certain features, like the NFC login may require additional setup for parsing the USB device. + ### Requirements - PHP 8.2 (`curl|gd|gmp|intl|mbstring|mysqli|openssl|xsl|gettext|dom|ldap`) - tested with PHP 8.2.26 From 6c33224d2238fe8159bf13aa34e16ce59e1ab554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bryan=20B=C3=B6hnke-Avan?= Date: Fri, 24 Oct 2025 13:09:57 +0200 Subject: [PATCH 05/12] Add login information for TimeTrack Added login credentials information to the README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1ed211b..33cd199 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ You can quickly get started with TimeTrack using Docker. Follow these steps: * **Change the DB password before using in production within the `docker-compose.yml` and `app.json` file!** * Start the services using Docker Compose: `docker-compose up -d` * Access TimeTrack in your web browser at `http://localhost:8080` +* Login with username `admin` and password `admin` Certain features, like the NFC login may require additional setup for parsing the USB device. From 4eb34dd0f13f0a761044438c45e34552b57a6298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bryan=20B=C3=B6hnke-Avan?= Date: Sat, 25 Oct 2025 17:23:51 +0200 Subject: [PATCH 06/12] Remove hardcoded file path from plugin.yml Removed hardcoded path from plugin configuration. --- api/v1/class/plugins/plugins/utility/plugin.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/api/v1/class/plugins/plugins/utility/plugin.yml b/api/v1/class/plugins/plugins/utility/plugin.yml index 19c0fa4..26d0e15 100644 --- a/api/v1/class/plugins/plugins/utility/plugin.yml +++ b/api/v1/class/plugins/plugins/utility/plugin.yml @@ -12,4 +12,3 @@ custom.values: license: LIC nav_links: 'Open Utility Plugin': views/overview.php -path: 'C:\Users\diege\Documents\GitHub\timetrack/api/v1/class/plugins/plugins/utility/plugin.yml' From 8c9af3bf66b2e9341bb23c9e79b21388527d59dd Mon Sep 17 00:00:00 2001 From: Ente Date: Sat, 25 Oct 2025 18:52:55 +0200 Subject: [PATCH 07/12] Update to version 8.2.3 with various enhancements and fixes - Added 'active' column to users table with migration - Implemented user activation/deactivation functionality - Updated changelog for version 8.2.3 - Removed outdated index.css file - Improved error handling for inactive users - Added footer to multiple project-related pages - Updated German, English, and Dutch language snippets --- CHANGELOG.md | 10 + VERSION | 2 +- api/v1/class/auth/auth.arbeit.inc.php | 24 +- api/v1/class/benutzer/benutzer.arbeit.inc.php | 19 +- .../class/i18n/suite/status/snippets_DE.json | 16 +- .../class/i18n/suite/status/snippets_EN.json | 12 +- .../class/i18n/suite/status/snippets_NL.json | 24 +- .../plugins/plugins/userdetail/views/user.php | 12 + assets/css/index.css | 239 ------------------ composer.json | 2 +- errors/500.php | 2 +- ...20251025162511_add_active_users_column.php | 25 ++ suite/admin/projects/addUser.php | 1 + suite/admin/projects/admin.php | 1 + suite/admin/projects/edit.php | 1 + suite/projects/createItem.php | 1 + suite/projects/item.php | 1 + suite/projects/mapWorktimeToItem.php | 1 + suite/projects/overview.php | 1 + suite/projects/view.php | 2 +- suite/worktime/correction.php | 1 + 21 files changed, 145 insertions(+), 252 deletions(-) delete mode 100644 assets/css/index.css create mode 100644 migrations/migrations/20251025162511_add_active_users_column.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d34958..39b507c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # CHANGELOG +## v8.2.3 + +**This update requires DB migration** - see `README.md` section `Database` + +* Fixed missing `status` i18n entries +* Fixed incorrect theme loading within error pages +* Removed outdated `index.css` file +* Added missing footer to project management pages +* Admins can now enable or disable users within the `userdetail` plugin + ## v8.2.2 * Fixed deprecation warning for `WorktimeAddedEvent` event diff --git a/VERSION b/VERSION index 797ed2e..85ce942 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.2.1 \ No newline at end of file +8.2.3 \ No newline at end of file diff --git a/api/v1/class/auth/auth.arbeit.inc.php b/api/v1/class/auth/auth.arbeit.inc.php index e56169d..d5a287f 100644 --- a/api/v1/class/auth/auth.arbeit.inc.php +++ b/api/v1/class/auth/auth.arbeit.inc.php @@ -71,7 +71,12 @@ public static function login($username, $password, $option){ # "option"-> array $_SESSION["username"] = $username; $_SESSION["time"] = date("d.m.Y H:i:s", $ts); self::store_state($username); - + # check if user active + if(!$data["active"]) { + EventDispatcherService::get()->dispatch(new LoggedInUserEvent($username, "failed")); + Exceptions::error_rep("Login failed for username '$username' - User inactive. Redirecting..."); + die(header("Location: http://{$base_url}/suite/login.php?" . $sM->URIBuilder("userinactive"))); + } if(@isset($option["remember"])){ if($ini["general"]["app"] == "true"){ EventDispatcherService::get()->dispatch(new LoggedInUserEvent($username, "success")); @@ -103,6 +108,12 @@ public static function login($username, $password, $option){ # "option"-> array nfclogin: Exceptions::error_rep("Authenticated user via NFC login '" . $username . "'"); } + # check if user active + if(!$data["active"]) { + EventDispatcherService::get()->dispatch(new LoggedInUserEvent($username, "failed")); + Exceptions::error_rep("Login failed for username '$username' - User inactive. Redirecting..."); + die(header("Location: http://{$base_url}/suite/login.php?" . $sM->URIBuilder("userinactive"))); + } Exceptions::error_rep("Successfully authenticated user '" . $username . "'"); $ini = Arbeitszeit::get_app_ini(); $ts = time(); @@ -162,6 +173,13 @@ public function login_validation(){ Exceptions::error_rep("State mismatch on user {$_SESSION["username"]}. Removing state and redirecting..."); header("Location: http://{$baseurl}/suite/login.php?" . $this->statusMessages()->URIBuilder("statemismatch")); } + # is active user + if(!$this->benutzer()->user_active($_SESSION["username"])) { + EventDispatcherService::get()->dispatch(new ValidatedLoginEvent($_SESSION["username"] ?? "N/A", "failed")); + $this->remove_state($_SESSION["username"]); + Exceptions::error_rep("User {$_SESSION["username"]} is inactive. Removing state and redirecting..."); + header("Location: http://{$baseurl}/suite/login.php?" . $this->statusMessages()->URIBuilder("userinactive")); + } } /** @@ -205,10 +223,10 @@ public static function store_state($user){ if($ini["general"]["app"] == "true"){ @ini_set("session.cookie_samesite", "None"); @session_set_cookie_params(["path" => "/", "domain" => $ini["general"]["base_url"], "secure" => true, "samesite" => "None"]); - setcookie("state", $state, null, "/"); + setcookie("state", $state, time()+(60*60*24*30), "/"); session_regenerate_id(true); } else { - setcookie("state", $state, null, "/"); + setcookie("state", $state, time()+(60*60*24*30), "/"); $_SESSION["state"] = $state; } $sql = "UPDATE `users` SET `state` = ? WHERE `username` = ?;"; diff --git a/api/v1/class/benutzer/benutzer.arbeit.inc.php b/api/v1/class/benutzer/benutzer.arbeit.inc.php index 3a7a05b..36b62eb 100644 --- a/api/v1/class/benutzer/benutzer.arbeit.inc.php +++ b/api/v1/class/benutzer/benutzer.arbeit.inc.php @@ -47,6 +47,23 @@ public function create_user($username, $name, $email, $password, $isAdmin = 0) } } + public function user_active($username){ + $user = $this->get_user($username); + if($user["active"] == true || $user["active"] == 1){ + return true; + } else { + return false; + } + } + + public function activate_user($username){ + return $this->editUserProperties($username, "active", 1); + } + + public function deactivate_user($username){ + return $this->editUserProperties($username, "active", 0); + } + /** * delete_user() - Deletes a user from the database * @@ -326,7 +343,7 @@ public function editUserProperties(mixed $username_or_id, string $name, mixed $v return false; } - $allowed_types = ["username", "email", "isAdmin", "name"]; + $allowed_types = ["username", "email", "isAdmin", "name", "active"]; if (!in_array($name, $allowed_types)) { Exceptions::error_rep("Could not update user entry – invalid property '{$name}'"); return false; diff --git a/api/v1/class/i18n/suite/status/snippets_DE.json b/api/v1/class/i18n/suite/status/snippets_DE.json index 293e834..bd74878 100644 --- a/api/v1/class/i18n/suite/status/snippets_DE.json +++ b/api/v1/class/i18n/suite/status/snippets_DE.json @@ -15,8 +15,8 @@ "password_reset": "Hinweis: Es wurde eine E-Mail verschickt, damit du dein Passwort zurücksetzen kannst.", "nodata": "Fehler: Es wurde kein Benutzername oder Passwort eingegeben.", "wrongdata": "Fehler: Falsche Anmeldedaten.", - "worktime_review": "Hinweis: Arbeitszeit erfolgreich auf Prüfung gestellt!", - "worktime_review_unlock": "Hinweis: Prüfung erfolgreich aufgehoben für Arbeitszeit!", + "worktime_reviewed": "Hinweis: Arbeitszeit erfolgreich auf Prüfung gestellt!", + "worktime_review_unlocked": "Hinweis: Prüfung erfolgreich aufgehoben für Arbeitszeit!", "worktime_easymode_start": "Hinweis: Deine Schicht wurde erfolgreich gestartet!", "worktime_easymode_end": "Hinweis: Deine Schicht wurde erfolgreich beendet!", "worktime_easymode_pause_start": "Hinweis: Deine Pause wurde erfolgreich gestartet!", @@ -38,5 +38,15 @@ "projects_item_added": "Hinweis: Projektaufgabe hinzugefügt.", "projects_item_failed": "Fehler: Die Projektaufgabe konnte nicht hinzugefügt werden. Bitte wende dich an deinen Administrator.", "mapWorktimeToItem_success": "Hinweis: Arbeitszeit erfolgreich mit der Projektaufgabe verbunden.", - "mapWorktimeToItem_failed": "Fehler: Die Arbeitszeit konnte nicht mit der Projektaufgabe verbunden werden. Bitte wende dich an deinen Administrator." + "mapWorktimeToItem_failed": "Fehler: Die Arbeitszeit konnte nicht mit der Projektaufgabe verbunden werden. Bitte wende dich an deinen Administrator.", + "notloggedin": "Fehler: Du bist nicht eingeloggt.", + "loggedout": "Hinweis: Du wurdest ausgeloggt.", + "worktime_updated": "Hinweis: Arbeitszeit erfolgreich aktualisiert!", + "error_worktime_update": "Fehler: Deine Arbeitszeit konnte nicht aktualisiert werden. Bitte kontaktiere deinen Administrator!", + "notifications_entry_added": "Hinweis: Benachrichtigungeneintrag hinzugefügt!", + "notifications_entry_edited": "Hinweis: Benachrichtigungeneintrag aktualisiert!", + "user_added": "Hinweis: Neuer Benutzer erfolgreich hinzugefügt!", + "changed_sickness": "Hinweis: Die Krankheit wurde erfolgreich aktualisiert!", + "changed_vacation": "Hinweis: Der Urlaub wurde erfolgreich aktualisiert!", + "userinactive": "Fehler: Dein Konto wurde deaktiviert. Bitte wende dich an deinen Administrator!" } diff --git a/api/v1/class/i18n/suite/status/snippets_EN.json b/api/v1/class/i18n/suite/status/snippets_EN.json index d89396f..173de41 100644 --- a/api/v1/class/i18n/suite/status/snippets_EN.json +++ b/api/v1/class/i18n/suite/status/snippets_EN.json @@ -38,5 +38,15 @@ "projects_item_added": "Note: The item has been added to the project.", "projects_item_failed": "Error: An error occurred while creating the item. Please contact your administrator.", "mapWorktimeToItem_success": "Note: Worktime successfully mapped to project item.", - "mapWorktimeToItem_failed": "Error: An error occurred while mapping the worktime to the project itme. Please contact your administrator." + "mapWorktimeToItem_failed": "Error: An error occurred while mapping the worktime to the project itme. Please contact your administrator.", + "notloggedin": "Error: You are not logged in.", + "loggedout": "Note: You have been logged out.", + "worktime_updated": "Note: Work time successfully updated!", + "error_worktime_update": "Error: Your work time could not be updated. Please contact your administrator!", + "notifications_entry_added": "Note: Notification entry added!", + "notifications_entry_edited": "Note: Notification entry updated!", + "user_added": "Note: New user successfully added!", + "changed_sickness": "Note: Sickness successfully updated!", + "changed_vacation": "Note: Vacation successfully updated!", + "userinactive": "Error: Your account has been disabled. Please contact your administrator!" } diff --git a/api/v1/class/i18n/suite/status/snippets_NL.json b/api/v1/class/i18n/suite/status/snippets_NL.json index 8dee092..31c9a21 100644 --- a/api/v1/class/i18n/suite/status/snippets_NL.json +++ b/api/v1/class/i18n/suite/status/snippets_NL.json @@ -26,5 +26,27 @@ "statemismatch": "Fout: Beveiligingsfout", "ldapauth": "Fout: LDAP-authenticatie mislukt.", "ldapcreated": "Opmerking: Log opnieuw in. Je account is nu aangemaakt. (LDAP self-login toegestaan)", - "notification_not_found": "Fout: Notificatie niet gevonden." + "notification_not_found": "Fout: Notificatie niet gevonden.", + "project_deleted": "Opmerking: Project succesvol verwijderd.", + "project_deleted_failed": "Fout: Het project kon niet worden verwijderd. Neem contact op met je beheerder.", + "project_edited": "Opmerking: Wijzigingen aan het project zijn doorgevoerd.", + "project_edited_error": "Fout: Er is een fout opgetreden bij het doorvoeren van de wijzigingen aan het project. Neem contact op met je beheerder.", + "project_added": "Opmerking: Het project is succesvol toegevoegd.", + "project_added_error": "Fout: Er is een fout opgetreden bij het aanmaken van het nieuwe project. Neem contact op met je beheerder.", + "project_userAdded": "Opmerking: De gebruiker is succesvol toegevoegd aan het project.", + "project_userAdded_failed": "Fout: Er is een fout opgetreden bij het toewijzen van de rechten aan de gebruiker. Neem contact op met je beheerder.", + "projects_item_added": "Opmerking: Het item is toegevoegd aan het project.", + "projects_item_failed": "Fout: Er is een fout opgetreden bij het aanmaken van het item. Neem contact op met je beheerder.", + "mapWorktimeToItem_success": "Opmerking: Werkuren succesvol gekoppeld aan projectitem.", + "mapWorktimeToItem_failed": "Fout: Er is een fout opgetreden bij het koppelen van de werkuren aan het projectitem. Neem contact op met je beheerder.", + "notloggedin": "Fout: Je bent niet ingelogd.", + "loggedout": "Opmerking: Je bent uitgelogd.", + "worktime_updated": "Opmerking: Werkuren succesvol bijgewerkt!", + "error_worktime_update": "Fout: Je werkuren konden niet worden bijgewerkt. Neem contact op met je beheerder!", + "notifications_entry_added": "Opmerking: Notificatie-item toegevoegd!", + "notifications_entry_edited": "Opmerking: Notificatie-item bijgewerkt!", + "user_added": "Opmerking: Nieuwe gebruiker succesvol toegevoegd!", + "changed_sickness": "Opmerking: Ziekte succesvol bijgewerkt!", + "changed_vacation": "Opmerking: Vakantie succesvol bijgewerkt!", + "userinactive": "Fout: Je account is uitgeschakeld. Neem contact op met je beheerder!" } diff --git a/api/v1/class/plugins/plugins/userdetail/views/user.php b/api/v1/class/plugins/plugins/userdetail/views/user.php index 231d449..296aad1 100644 --- a/api/v1/class/plugins/plugins/userdetail/views/user.php +++ b/api/v1/class/plugins/plugins/userdetail/views/user.php @@ -26,6 +26,7 @@ $username = $_POST["username"]; $email = $_POST["email"]; $name = $_POST["name"]; + @$active = $_POST["active"]; if (!empty($username)) { if ($benutzer->editUserProperties($id, "username", $username)) { @@ -50,6 +51,16 @@ } } + if (!empty($_POST["active"])) { + if ($benutzer->editUserProperties($id, "active", 1)) { + echo "Enabled user account for ID {$id}.
"; + } + } elseif(empty($_POST["active"])){ + if($benutzer->editUserProperties($id, "active", 0)) { + echo "Disabled user account for ID {$id}.
"; + } + } + $payload = [ "id" => $id, "username" => $username, @@ -83,6 +94,7 @@

" placeholder="box@mail.com">
+ >
" hidden>

HR

diff --git a/assets/css/index.css b/assets/css/index.css deleted file mode 100644 index 118b15a..0000000 --- a/assets/css/index.css +++ /dev/null @@ -1,239 +0,0 @@ -span { - color: red; -} - -* { - text-align: center; - - @import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Rubik:ital,wght@0,300..900;1,300..900&display=swap'); - font-family:"Roboto", sans-serif; - color: white; - background-color: black; -} -.progress-bar { - width: 100%; - background-color: #ddd; - padding: 3px; - border-radius: 5px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); -} - -.progress-bar-inner { - height: 20px; - background-color: #4caf50; - border-radius: 2px; - animation: progressAnimation 2s linear infinite; -} - -@keyframes progressAnimation { - 0% { - transform: translateX(100%); - } - 100% { - transform: translateX(-100%); - } -} - -.box { - width: auto; - max-width: 800px; - height: auto; - border: 5px solid; - padding: 2px; - margin: auto; - border-radius: 5px; - margin-left: auto; - margin-right: auto; - opacity: 1; - border-color: rgba(255, 255, 255, 0.64); - transition: all 0.5s; -} - -/*.button { - background: #258cd1; - position: relative; - color: white; - top: 100px; - font-size: 23px; - border-radius: 10px; - border-width: 10px; - border-color: rgba(0, 0, 0, 0); - box-shadow: 0px 15px 0px 0px rgba(102, 104, 111, 0.3), 0px 0px 20px 0px rgba(102, 104, 111, 0.3); - transition: all 0.1s; - } - - .button:hover { - top: 108px; - box-shadow: 0px 7px 0px 0px rgba(102, 104, 111, 0.7); - background-color: rgb(66, 67, 71, 0.7); - }*/ - -.button { - background-color: #4caf50; /* Grüne Hintergrundfarbe */ - border: none; - color: white; /* Weiße Schrift */ - padding: 15px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - cursor: pointer; - border-radius: 8px; /* Abgerundete Ecken */ - transition: background-color 0.5s ease; /* Transition für'n sanften Farbwechsel */ -} - -.button:hover { - animation: hoverAnimation 0.5s ease forwards; -} - -@keyframes hoverAnimation { - from { - background-color: #4caf50; - } - to { - background-color: #45a049; - } -} - -.button { - background-color: rgb(66, 67, 71, 0.3); -} - -.input { - color: white; - height: 40px; - text-align: center; - width: auto; - border-color: rgba(133, 133, 133, 0.2); - background-color: rgba(102, 104, 111); - opacity: 0.5; - border-radius: 10px; - transition: all 0.5s; - font-size: 20px; -} - -.input:hover { - opacity: 1; - transition: 0s; - font-size: 23px; -} - -ul { - list-style-type: none; - margin: 0; - padding: 0; - overflow: hidden; - background-color: rgb(0, 0, 0); - opacity: 0.6; - position: sticky; - color: rgb(255, 255, 255); -} - -li { - float: left; -} - -li a { - display: block; - padding: 14px; - color: white; - opacity: 0.6; -} - -li a:hover { - background-color: grey; - color: white; -} - -li.b { - float: right; -} - -li.active { - background-color: grey; -} - -/* CSS für den Blur-Effekt */ -.blur { - filter: blur(8px); /* Du kannst die Stärke des Blur-Effekts ändern */ - transition: filter 0.5s; /* Für einen sanften Übergang */ -} - -/* CSS für den "Freigeben"-Button */ -.button-blur { - background-color: #0074d9; /* Eine passende Farbe für den Button */ - color: #fff; /* Textfarbe für den Button */ - padding: 10px 20px; - border: none; - cursor: pointer; -} - -/* CSS für den "Freigeben"-Button bei Hover */ -.button-blur:hover { - background-color: #0056b3; /* Ändert sich, wenn du mit der Maus darüber fährst */ -} - -.bottom-link { - text-align: left !important; - position: absolute !important; - bottom: 0 !important; - left: 0 !important; -} - -hr { - color: white; - margin: auto; - margin-top: 5px; - margin-bottom: 5px; - width: 75%; - text-align: center; -} - -.text-red { color: red; font-weight: bold;} -.text-green { color: green; font-weight: bold;} -.text-yellow { color: yellow; font-weight: bold;} -.text-blue { color: blue; font-weight: bold;} - -.status-message { - font-family: "Rubik", sans-serif; - font-size: 16px; - padding: 15px 20px; - margin: 20px auto; - border-radius: 10px; - max-width: 700px; - border: 2px solid rgba(255, 255, 255, 0.3); - box-shadow: 0 0 10px rgba(255, 255, 255, 0.1); - background: rgba(255, 255, 255, 0.05); - backdrop-filter: blur(6px); - color: white; - text-align: center; - position: relative; - transition: all 0.3s ease-in-out; - cursor: default; -} - -.status-message .dismiss-button { - position: absolute; - top: 8px; - right: 12px; - font-size: 20px; - color: white; - cursor: pointer; - transition: color 0.3s; -} - -.status-message .dismiss-button:hover { - color: red; -} - -.status-message.dismissed { - opacity: 0; - transform: scale(0.95); - height: 0; - margin: 0; - padding: 0; - border: 0; - pointer-events: none; -} - diff --git a/composer.json b/composer.json index bf85a3b..b8fe4b6 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "TimeTrack is a PHP-written time recording tool for small businesses", "type": "software", "license": "GNU GPL", - "version": "8.2.1", + "version": "8.2.3", "authors": [ { "name": "Bryan Boehnke-Avan", diff --git a/errors/500.php b/errors/500.php index c76512d..3a6c977 100644 --- a/errors/500.php +++ b/errors/500.php @@ -15,7 +15,7 @@ 500 | Internal Server Error - + ?v=1">
diff --git a/migrations/migrations/20251025162511_add_active_users_column.php b/migrations/migrations/20251025162511_add_active_users_column.php new file mode 100644 index 0000000..5a1a72d --- /dev/null +++ b/migrations/migrations/20251025162511_add_active_users_column.php @@ -0,0 +1,25 @@ +table('users')->hasColumn('active')) { + $this->table('users') + ->addColumn('active', 'boolean', [ + 'default' => true, + 'null' => false, + 'after' => 'password' + ]) + ->update(); + $this->execute('UPDATE users SET active = 1 WHERE active IS NULL'); + echo "Added active column to users table\n"; + } else { + echo "active column already exists in users table\n"; + } + } +} diff --git a/suite/admin/projects/addUser.php b/suite/admin/projects/addUser.php index f29795d..bbcf30f 100644 --- a/suite/admin/projects/addUser.php +++ b/suite/admin/projects/addUser.php @@ -45,5 +45,6 @@ + diff --git a/suite/admin/projects/admin.php b/suite/admin/projects/admin.php index fbda32c..fbf2089 100644 --- a/suite/admin/projects/admin.php +++ b/suite/admin/projects/admin.php @@ -107,6 +107,7 @@ function confirmDelete(e, projectId) { + \ No newline at end of file diff --git a/suite/admin/projects/edit.php b/suite/admin/projects/edit.php index dd776bc..92cfea3 100644 --- a/suite/admin/projects/edit.php +++ b/suite/admin/projects/edit.php @@ -58,5 +58,6 @@ + diff --git a/suite/projects/createItem.php b/suite/projects/createItem.php index 687454a..2dae3ac 100644 --- a/suite/projects/createItem.php +++ b/suite/projects/createItem.php @@ -40,5 +40,6 @@ + diff --git a/suite/projects/item.php b/suite/projects/item.php index 1daf28d..14b1a7d 100644 --- a/suite/projects/item.php +++ b/suite/projects/item.php @@ -73,5 +73,6 @@ + diff --git a/suite/projects/mapWorktimeToItem.php b/suite/projects/mapWorktimeToItem.php index ee4421d..03d90c9 100644 --- a/suite/projects/mapWorktimeToItem.php +++ b/suite/projects/mapWorktimeToItem.php @@ -39,5 +39,6 @@ Cancel + diff --git a/suite/projects/overview.php b/suite/projects/overview.php index 8147062..3613024 100644 --- a/suite/projects/overview.php +++ b/suite/projects/overview.php @@ -95,5 +95,6 @@ + diff --git a/suite/projects/view.php b/suite/projects/view.php index 05abe17..91d9301 100644 --- a/suite/projects/view.php +++ b/suite/projects/view.php @@ -132,7 +132,7 @@ - +