diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index 34bfc34..e554d2b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -102,7 +102,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories) + $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)core\sharedmemory;$(ProjectDir)core\events;%(AdditionalIncludeDirectories) Console @@ -117,7 +117,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories) + $(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)core\sharedmemory;$(ProjectDir)core\events;%(AdditionalIncludeDirectories) Console @@ -126,10 +126,11 @@ + + - @@ -148,21 +149,23 @@ + + + + + + + + - - - - - - @@ -191,6 +194,7 @@ + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters index c13b320..ac65e97 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters @@ -64,11 +64,17 @@ {8057b93d-51a9-42df-b06e-01ce395f6308} - - {ec639004-44c6-4bd6-9963-077adde82b5f} + + {d9da9793-fe6f-4914-bee3-99d5934da228} - - {7aa8722e-adfa-466e-8211-de63f3b7892b} + + {0769afb6-f57d-4ae3-a1cf-ceca6e606af0} + + + {85029bdb-6941-41dc-a3a7-9e5841671d8c} + + + {1050aca7-6f2c-4ccb-a446-db9c898c3599} @@ -144,8 +150,14 @@ Source Files\Models - - Source Files\DataStores\SharedMemory + + Source Files\Core\SharedMemory + + + Source Files\Core\Events + + + Source Files\Views @@ -254,26 +266,32 @@ Header Files\Views - - Header Files\DataStores\SharedMemory - - - Header Files\DataStores\SharedMemory - - - Header Files\DataStores\SharedMemory - - - Header Files\DataStores\SharedMemory - - - Header Files\DataStores\SharedMemory - - - Header Files\DataStores\SharedMemory - Header Files\DataStores + + Header Files\Core\SharedMemory + + + Header Files\Core\SharedMemory + + + Header Files\Core\SharedMemory + + + Header Files\Core\SharedMemory + + + Header Files\Core\SharedMemory + + + Header Files\Core\SharedMemory + + + Header Files\Core\Events + + + Header Files\Views + \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index 487ecd5..d892e36 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -622,3 +622,16 @@ void Controller::shutdown() auto& dataStore = DataStore::getInstance(); dataStore.shutdown(); } + +/* +Function: registerEvents +Description: Registers menu event handles with the authentication + service. +Parameter: HANDLE accountDisabledEvent - account disabled event handle + HANDLE notificationAvailableEvent - notification event handle +Return type: void +*/ +void Controller::registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent) +{ + m_authenticationManagementService.registerEvents(accountDisabledEvent, notificationAvailableEvent); +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 7ec1c30..622c7b7 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -8,6 +8,7 @@ Date:19-May-2026 */ #pragma once +#include #include #include "AuthenticationManagementService.h" #include "Enums.h" @@ -72,4 +73,5 @@ public: void configureNotifications(bool paymentNotifications, bool serviceNotifications); bool initialize(); void shutdown(); + void registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.cpp new file mode 100644 index 0000000..568a0e6 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.cpp @@ -0,0 +1,225 @@ +/* +File: EventManager.cpp +Description: Implementation file containing the method definitions of the + EventManager class, including listener management and + interprocess event publishing. +Author: Trenser +Date:15-Jun-2026 +*/ + +#include +#include +#include "EventManager.h" + +namespace +{ + const std::string USER_DISABLED_EVENT = "userDisabled_"; + + const std::string NOTIFICATION_AVAILABLE_EVENT = "notificationAvailable_"; +} + +/* +Function: EventManager +Description: Constructs an EventManager instance with default values. +Parameter: None +Return type: None +*/ +EventManager::EventManager() + : + m_userDisabledEvent(NULL), + m_notificationAvailableEvent(NULL), + m_shutdownEvent(NULL), + m_running(false) {} + +/* +Function: ~EventManager +Description: Destroys the EventManager and performs final cleanup. +Parameter: None +Return type: None +*/ +EventManager::~EventManager() +{ + shutdown(); + if (m_listenerThread.joinable()) + { + m_listenerThread.join(); + } +} + +/* +Function: initialize +Description: Creates the user-specific events and starts the listener + thread. +Parameter: const std::string& userId - unique identifier of the user + std::function userDisabledCallback - callback for + user disable events + std::function notificationCallback - callback for + notification events +Return type: bool - true if initialization succeeds, false otherwise +*/ +bool EventManager::initialize(const std::string& userId, std::function userDisabledCallback, std::function notificationCallback) +{ + if (m_running.load()) + { + return false; + } + m_userDisabledCallback = userDisabledCallback; + m_notificationCallback = notificationCallback; + m_userDisabledEvent = CreateEventA(NULL, FALSE, FALSE, (USER_DISABLED_EVENT + userId).c_str()); + if (!m_userDisabledEvent) + { + return false; + } + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + CloseHandle(m_userDisabledEvent); + m_userDisabledEvent = NULL; + throw std::runtime_error("Only one session allowed per user."); + } + m_notificationAvailableEvent = CreateEventA(NULL, FALSE, FALSE, (NOTIFICATION_AVAILABLE_EVENT + userId).c_str()); + if (!m_notificationAvailableEvent) + { + CloseHandle(m_userDisabledEvent); + m_userDisabledEvent = NULL; + return false; + } + m_shutdownEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!m_shutdownEvent) + { + CloseHandle(m_userDisabledEvent); + CloseHandle(m_notificationAvailableEvent); + m_userDisabledEvent = NULL; + m_notificationAvailableEvent = NULL; + return false; + } + m_running.store(true); + m_listenerThread = std::thread(&EventManager::run, this); + return true; +} + +/* +Function: shutdown +Description: Stops the listener thread and releases event resources. +Parameter: None +Return type: None +*/ +void EventManager::shutdown() +{ + if (!m_running.load()) + { + return; + } + m_running.store(false); + if (m_shutdownEvent) + { + SetEvent(m_shutdownEvent); + } + if (m_listenerThread.joinable()) + { + if (std::this_thread::get_id() != m_listenerThread.get_id()) + { + m_listenerThread.join(); + } + } + if (m_userDisabledEvent) + { + CloseHandle(m_userDisabledEvent); + m_userDisabledEvent = NULL; + } + if (m_notificationAvailableEvent) + { + CloseHandle(m_notificationAvailableEvent); + m_notificationAvailableEvent = NULL; + } + if (m_shutdownEvent) + { + CloseHandle(m_shutdownEvent); + m_shutdownEvent = NULL; + } +} + +/* +Function: run +Description: Waits for and dispatches user-related events. +Parameter: None +Return type: void +*/ +void EventManager::run() +{ + HANDLE handles[3]; + handles[0] = m_userDisabledEvent; + handles[1] = m_notificationAvailableEvent; + handles[2] = m_shutdownEvent; + while (m_running.load()) + { + DWORD result = WaitForMultipleObjects(3, handles, FALSE, INFINITE); + switch (result) + { + case WAIT_OBJECT_0: + try + { + if (m_userDisabledCallback) + { + m_userDisabledCallback(); + } + } + catch (const std::exception& exception) + { + std::cout << exception.what() << std::endl; + } + break; + case WAIT_OBJECT_0 + 1: + try + { + if (m_notificationCallback) + { + m_notificationCallback(); + } + } + catch (const std::exception& exception) + { + std::cout << exception.what() << std::endl; + } + break; + case WAIT_OBJECT_0 + 2: + return; + default: + break; + } + } +} + +/* +Function: sendUserDisabledEvent +Description: Publishes a user disabled event for a specific user. +Parameter: const std::string& userId - target user identifier +Return type: void +*/ +void EventManager::sendUserDisabledEvent(const std::string& userId) +{ + HANDLE eventHandle = CreateEventA(NULL, FALSE, FALSE, (USER_DISABLED_EVENT + userId).c_str()); + if (!eventHandle) + { + return; + } + SetEvent(eventHandle); + CloseHandle(eventHandle); +} + +/* +Function: sendNotificationAvailableEvent +Description: Publishes a notification available event for a specific + user. +Parameter: const std::string& userId - target user identifier +Return type: void +*/ +void EventManager::sendNotificationAvailableEvent(const std::string& userId) +{ + HANDLE eventHandle = CreateEventA(NULL, FALSE, FALSE, (NOTIFICATION_AVAILABLE_EVENT + userId).c_str()); + if (!eventHandle) + { + return; + } + SetEvent(eventHandle); + CloseHandle(eventHandle); +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.h new file mode 100644 index 0000000..01de6c4 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/events/EventManager.h @@ -0,0 +1,37 @@ +/* +File: EventManager.h +Description: Header file declaring the EventManager class, which manages + user-specific interprocess events for user disable and + notification availability updates. +Author: Trenser +Date:15-Jun-2026 +*/ + +#pragma once + +#include +#include +#include +#include +#include + +class EventManager +{ +private: + HANDLE m_userDisabledEvent; + HANDLE m_notificationAvailableEvent; + HANDLE m_shutdownEvent; + std::atomic m_running; + std::thread m_listenerThread; + std::function m_userDisabledCallback; + std::function m_notificationCallback; + void run(); + +public: + EventManager(); + ~EventManager(); + bool initialize(const std::string& userId, std::function userDisabledCallback, std::function notificationCallback); + void shutdown(); + static void sendUserDisabledEvent(const std::string& userId); + static void sendNotificationAvailableEvent(const std::string& userId); +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/FileHeader.h similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/FileHeader.h rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/FileHeader.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/MappingInfo.h similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/MappingInfo.h rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/MappingInfo.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/RecordState.h similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/RecordState.h rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/RecordState.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SerializedRecords.h similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SerializedRecords.h rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SerializedRecords.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.cpp similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.cpp diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.h similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.h rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/SharedMemory.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/TrackedRecord.h similarity index 100% rename from Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/TrackedRecord.h rename to Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/sharedmemory/TrackedRecord.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp index 71d66b6..56137e5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp @@ -14,6 +14,9 @@ Date:19-May-2026 #include "DataStoreLockGuard.h" User* AuthenticationManagementService::m_authenticatedUser = nullptr; +EventManager AuthenticationManagementService::m_eventManager; +HANDLE AuthenticationManagementService::m_accountDisabledEvent = NULL; +HANDLE AuthenticationManagementService::m_notificationsAvailableEvent = NULL; /* Function: login @@ -37,6 +40,22 @@ bool AuthenticationManagementService::login(const std::string& username, const s if (password == user->getPassword()) { m_authenticatedUser = user; + m_eventManager.initialize( + user->getId(), + []() + { + if (m_accountDisabledEvent) + { + SetEvent(m_accountDisabledEvent); + } + }, + []() + { + if (m_notificationsAvailableEvent) + { + SetEvent(m_notificationsAvailableEvent); + } + }); return true; } return false; @@ -65,7 +84,10 @@ Return type: void */ void AuthenticationManagementService::logout() { + m_eventManager.shutdown(); m_authenticatedUser = nullptr; + m_accountDisabledEvent = NULL; + m_notificationsAvailableEvent = NULL; } /* @@ -92,3 +114,17 @@ void AuthenticationManagementService::changePassword(const std::string& newPassw trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED; m_dataStore.saveUsers(); } + +/* +Function: registerEvents +Description: Registers menu event handles used to notify the active + menu of account disable and notification events. +Parameter: HANDLE accountDisabledEvent - account disabled event handle + HANDLE notificationAvailableEvent - notification event handle +Return type: void +*/ +void AuthenticationManagementService::registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent) +{ + m_accountDisabledEvent = accountDisabledEvent; + m_notificationsAvailableEvent = notificationAvailableEvent; +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h index 47266a1..d512892 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h @@ -9,6 +9,8 @@ Date:19-May-2026 #pragma once #include +#include +#include "EventManager.h" #include "DataStore.h" class User; @@ -17,6 +19,9 @@ class AuthenticationManagementService { private: static User* m_authenticatedUser; + static EventManager m_eventManager; + static HANDLE m_accountDisabledEvent; + static HANDLE m_notificationsAvailableEvent; DataStore& m_dataStore; public: AuthenticationManagementService() : m_dataStore(DataStore::getInstance()) {} @@ -24,4 +29,5 @@ public: void logout(); void changePassword(const std::string& newPassword); User* getAuthenticatedUser(); + void registerEvents(HANDLE accountDisabledEvent, HANDLE notificationAvailableEvent); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp index 8e17739..a007ac1 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp @@ -19,6 +19,7 @@ Date: 22-May-2026 #include "Utility.h" #include "Vector.h" #include "DataStoreLockGuard.h" +#include "EventManager.h" util::Map InventoryManagementService::m_observers{}; @@ -281,5 +282,6 @@ void InventoryManagementService::sendNotification(User* user, const std::string& auto& trackedNotificationsMap = m_dataStore.getNotifications(); trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification)); m_dataStore.saveNotifications(); + EventManager::sendNotificationAvailableEvent(user->getId()); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index dc42a5b..09bf1da 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -22,6 +22,7 @@ Date: 20-May-2026 #include "User.h" #include "Utility.h" #include "DataStoreLockGuard.h" +#include "EventManager.h" util::Map PaymentManagementService::m_observers{}; @@ -109,6 +110,7 @@ void PaymentManagementService::sendNotification(User* user, const std::string& t auto& trackedNotificationsMap = m_dataStore.getNotifications(); trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification)); m_dataStore.saveNotifications(); + EventManager::sendNotificationAvailableEvent(user->getId()); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index ed59380..cf438d0 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -27,6 +27,7 @@ Date:19-May-2026 #include "DataStoreLockGuard.h" #include "Utility.h" #include "DataStoreLockGuard.h" +#include "EventManager.h" /* Function: purchaseService @@ -199,6 +200,7 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t auto& trackedNotificationsMap = m_dataStore.getNotifications(); trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification)); m_dataStore.saveNotifications(); + EventManager::sendNotificationAvailableEvent(user->getId()); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index e923e1c..ab85936 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -22,6 +22,7 @@ Date:19-May-2026 #include "Utility.h" #include "TrackedRecord.h" #include "DataStoreLockGuard.h" +#include "EventManager.h" /* Function: ensureAdminExists @@ -267,30 +268,38 @@ void UserManagementService::removeUser(const std::string& userID) InventoryManagementService inventoryManagementService; PaymentManagementService paymentManagementService; ServiceManagementService serviceManagementService; - DataStoreLockGuard lock(m_dataStore); - auto& trackedUsersMap = m_dataStore.getUsers(); - int index = trackedUsersMap.find(userID); - if (index != -1) + std::string removedUserID; { - User* user = trackedUsersMap.getValueAt(index).data; - if (user != nullptr) + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + int index = trackedUsersMap.find(userID); + if (index != -1) { - if (user->getUserType() == util::UserType::CUSTOMER) + User* user = trackedUsersMap.getValueAt(index).data; + if (user != nullptr) { - serviceManagementService.cancelCustomerServiceBookings(userID); + if (user->getUserType() == util::UserType::CUSTOMER) + { + serviceManagementService.cancelCustomerServiceBookings(userID); + } + if (user->getUserType() == util::UserType::TECHNICIAN) + { + serviceManagementService.cancelTechnicianJobs(userID); + } + inventoryManagementService.detach(user); + paymentManagementService.detach(user); + serviceManagementService.detach(user); + user->setState(util::State::INACTIVE); + trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED; + removedUserID = user->getId(); + m_dataStore.saveUsers(); } - if (user->getUserType() == util::UserType::TECHNICIAN) - { - serviceManagementService.cancelTechnicianJobs(userID); - } - inventoryManagementService.detach(user); - paymentManagementService.detach(user); - serviceManagementService.detach(user); - user->setState(util::State::INACTIVE); - trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED; - m_dataStore.saveUsers(); } } + if (!removedUserID.empty()) + { + EventManager::sendUserDisabledEvent(removedUserID); + } } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 76a1901..68ec663 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -30,10 +30,16 @@ Return type: void */ void AdminMenu::showMenu() { + startEventListener(); while (true) { try { + if (!m_isMenuActive) + { + logout(); + break; + } int choice; util::clear(); std::cout << "Admin Menu" @@ -68,6 +74,7 @@ void AdminMenu::showMenu() util::pressEnter(); } } + stopEventListener(); } /* @@ -78,6 +85,11 @@ Return type: bool - true if menu continues, false if logout */ bool AdminMenu::handleOperation(int choice) { + if (!m_isMenuActive) + { + logout(); + return false; + } switch (choice) { case 1: @@ -141,6 +153,19 @@ bool AdminMenu::handleOperation(int choice) return true; } +/* +Function: handleNotificationEvent +Description: Retrieves and displays the latest notification for the + currently logged in admin. +Parameter: None +Return type: void +*/ +void AdminMenu::handleNotificationEvent() +{ + auto notifications = m_controller.getNotifications(); + displayNewNotification(notifications); +} + /* Function: logout Description: Logs out the currently authenticated admin user. diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h index bdffcb6..f9aa415 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h @@ -9,12 +9,13 @@ Date:19-May-2026 #pragma once #include "Controller.h" +#include "Menu.h" -class AdminMenu +class AdminMenu : public Menu { private: - Controller m_controller; bool handleOperation(int choice); + void handleNotificationEvent() override; public: void showMenu(); void logout(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 0d60f97..3932fba 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -32,10 +32,17 @@ Return type: void */ void CustomerMenu::showMenu() { + + startEventListener(); while (true) { try { + if (!m_isMenuActive) + { + logout(); + break; + } int choice; util::clear(); std::cout << "Customer Menu" @@ -62,6 +69,7 @@ void CustomerMenu::showMenu() util::pressEnter(); } } + stopEventListener(); } /* @@ -72,6 +80,11 @@ Return type: bool - true if menu continues, false if logout */ bool CustomerMenu::handleOperation(int choice) { + if (!m_isMenuActive) + { + logout(); + return false; + } switch (choice) { case 1: @@ -111,6 +124,19 @@ bool CustomerMenu::handleOperation(int choice) return true; } +/* +Function: handleNotificationEvent +Description: Retrieves and displays the latest notification for the + currently logged in admin. +Parameter: None +Return type: void +*/ +void CustomerMenu::handleNotificationEvent() +{ + auto notifications = m_controller.getNotifications(); + displayNewNotification(notifications); +} + /* Function: logout Description: Logs out the currently authenticated customer user. diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h index d491720..c619107 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h @@ -9,13 +9,14 @@ Date:19-May-2026 */ #pragma once +#include "Menu.h" #include "Controller.h" -class CustomerMenu +class CustomerMenu : public Menu { private: - Controller m_controller; bool handleOperation(int choice); + void handleNotificationEvent(); public: void showMenu(); void logout(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp new file mode 100644 index 0000000..2573c0e --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp @@ -0,0 +1,144 @@ +/* +File: Menu.cpp +Description: Implementation file containing common menu event listener + functionality, account disable handling, and notification + event dispatching for all menu types. +Author: Trenser +Date:16-Jun-2026 +*/ + +#include "Menu.h" + +/* +Function: Menu +Description: Constructs a Menu object and initializes event handles + and menu state. +Parameter: None +Return type: None +*/ +Menu::Menu() + : + m_isMenuActive(false), + m_accountDisabledEvent(NULL), + m_notificationAvailableEvent(NULL), + m_shutdownEvent(NULL) {} + +/* +Function: ~Menu +Description: Destroys the Menu object and performs event listener + cleanup. +Parameter: None +Return type: None +*/ +Menu::~Menu() +{ + stopEventListener(); +} + +/* +Function: startEventListener +Description: Creates menu event handles, registers them with the + authentication service, and starts the event listener + thread. +Parameter: None +Return type: void +*/ +void Menu::startEventListener() +{ + if (m_isMenuActive.load()) + { + return; + } + m_isMenuActive.store(true); + m_accountDisabledEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + m_notificationAvailableEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + m_shutdownEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + m_controller.registerEvents(m_accountDisabledEvent, m_notificationAvailableEvent); + m_eventListenerThread = std::thread(&Menu::eventListenerLoop, this); +} + +/* +Function: eventListenerLoop +Description: Waits for account disabled, notification available, + and shutdown events and dispatches them to the + appropriate handlers. +Parameter: None +Return type: void +*/ +void Menu::eventListenerLoop() +{ + HANDLE handles[3]; + handles[0] = m_accountDisabledEvent; + handles[1] = m_notificationAvailableEvent; + handles[2] = m_shutdownEvent; + while (m_isMenuActive.load()) + { + DWORD result = WaitForMultipleObjects(3, handles, FALSE, INFINITE); + switch (result) + { + case WAIT_OBJECT_0: + handleAccountDisabledEvent(); + break; + case WAIT_OBJECT_0 + 1: + handleNotificationEvent(); + break; + case WAIT_OBJECT_0 + 2: + return; + } + } +} + +/* +Function: stopEventListener +Description: Stops the event listener thread and releases all + associated event handles. +Parameter: None +Return type: void +*/ +void Menu::stopEventListener() +{ + m_isMenuActive.store(false); + if (m_shutdownEvent) + { + SetEvent(m_shutdownEvent); + } + if (m_eventListenerThread.joinable()) + { + m_eventListenerThread.join(); + } + if (m_accountDisabledEvent) + { + CloseHandle(m_accountDisabledEvent); + } + if (m_notificationAvailableEvent) + { + CloseHandle(m_notificationAvailableEvent); + } + if (m_shutdownEvent) + { + CloseHandle(m_shutdownEvent); + } + m_accountDisabledEvent = NULL; + m_notificationAvailableEvent = NULL; + m_shutdownEvent = NULL; +} + +/* +Function: handleAccountDisabledEvent +Description: Handles an account disabled event by marking the menu + inactive and notifying the user. +Parameter: None +Return type: void +*/ +void Menu::handleAccountDisabledEvent() +{ + m_isMenuActive.store(false); + MessageBoxA( + GetConsoleWindow(), + "Your account has been disabled.", + "Account Disabled", + MB_OK | + MB_ICONWARNING | + MB_SETFOREGROUND | + MB_TOPMOST); +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.h new file mode 100644 index 0000000..146efa8 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.h @@ -0,0 +1,33 @@ +/* +File: Menu.h +Description: Base class providing common event listener functionality + for all menu implementations. +Author: Trenser +Date:16-Jun-2026 +*/ + +#pragma once + +#include +#include +#include +#include "Controller.h" + +class Menu +{ +protected: + Controller m_controller; + std::atomic m_isMenuActive; + HANDLE m_accountDisabledEvent; + HANDLE m_notificationAvailableEvent; + HANDLE m_shutdownEvent; + std::thread m_eventListenerThread; + void startEventListener(); + void stopEventListener(); + void eventListenerLoop(); + void handleAccountDisabledEvent(); + virtual void handleNotificationEvent() = 0; +public: + Menu(); + virtual ~Menu(); +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index c6ebaa6..0d0f695 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -1407,4 +1407,38 @@ inline std::string selectComboPackage(util::Map notifications - + collection of notifications +Return type: void +*/ +inline void displayNewNotification(util::Vector notifications) +{ + const Notification* notification = nullptr; + size_t numberOfNotifications = notifications.getSize(); + for (int index = 0; index < numberOfNotifications; index++) + { + if (!notification) + { + notification = notifications[index]; + } + else + { + if (notification->getId() < notifications[index]->getId()) + { + notification = notifications[index]; + } + } + } + MessageBoxA( + GetConsoleWindow(), + notification->getMessage().c_str(), + notification->getTitle().c_str(), + MB_OK | + MB_ICONINFORMATION); } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp index 8ff3e12..4b090d8 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp @@ -27,10 +27,16 @@ Returns: */ void TechnicianMenu::showMenu() { + startEventListener(); while (true) { try { + if (!m_isMenuActive) + { + logout(); + break; + } int choice; util::clear(); std::cout << "Technician Menu" @@ -52,6 +58,7 @@ void TechnicianMenu::showMenu() util::pressEnter(); } } + stopEventListener(); } /* @@ -62,6 +69,11 @@ Return type: bool - true if menu continues, false if logout */ bool TechnicianMenu::handleOperation(int choice) { + if (!m_isMenuActive) + { + logout(); + return false; + } switch (choice) { case 1: @@ -86,6 +98,19 @@ bool TechnicianMenu::handleOperation(int choice) return true; } +/* +Function: handleNotificationEvent +Description: Retrieves and displays the latest notification for the + currently logged in admin. +Parameter: None +Return type: void +*/ +void TechnicianMenu::handleNotificationEvent() +{ + auto notifications = m_controller.getNotifications(); + displayNewNotification(notifications); +} + /* Function: displayJobs Description: Displays all Jobs assigned to a Technician diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h index 2d118a0..b00c1f3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h @@ -9,12 +9,13 @@ Date:19-May-2026 #pragma once #include "Controller.h" +#include "Menu.h" -class TechnicianMenu +class TechnicianMenu : public Menu { private: - Controller m_controller; bool handleOperation(int choice); + void handleNotificationEvent(); public: void showMenu(); void displayJobs();