/* File: UserManagementService.cpp Description: Implementation file containing the method definitions of the UserManagementService class, including user creation, updates, and ensuring an admin account exists. Author: Trenser Date:19-May-2026 */ #include #include "Config.h" #include "Enums.h" #include "Factory.h" #include "InventoryManagementService.h" #include "Notification.h" #include "PaymentManagementService.h" #include "ServiceManagementService.h" #include "User.h" #include "UserManagementService.h" #include "Vector.h" #include "Validator.h" #include "Utility.h" #include "TrackedRecord.h" #include "DataStoreLockGuard.h" #include "EventManager.h" /* Function: ensureAdminExists Description: Ensures that at least one admin user exists in the system. If no admin is found, creates a default admin user using configuration constants. Parameter: None Return type: void */ void UserManagementService::ensureAdminExists() { DataStoreLockGuard lock(m_dataStore); auto& usersMap = m_dataStore.getUsers(); int usersMapSize = usersMap.getSize(); bool isAdminFound = false; for (int index = 0; index < usersMapSize; index++) { User* user = usersMap.getValueAt(index).data; if (user && user->getUserType() == util::UserType::ADMIN) { isAdminFound = true; break; } } if (!isAdminFound) { createUser( config::admin::DEFAULT_ADMIN_USERNAME, config::admin::DEFAULT_ADMIN_NAME, config::admin::DEFAULT_ADMIN_PASSWORD, config::admin::DEFAULT_ADMIN_EMAIL, config::admin::DEFAULT_ADMIN_PHONE, util::UserType::ADMIN); } } /* Function: createUser Description: Creates a new user with the provided details. Validates that the username is unique, then attaches the user to relevant management services (payment, service, inventory). Parameter: const std::string& username - user’s username const std::string& name - user’s name const std::string& password - user’s password const std::string& email - user’s email address const std::string& phone - user’s phone number util::UserType type - type of user (ADMIN, CUSTOMER, TECHNICIAN) Return type: void */ void UserManagementService::createUser(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone, util::UserType type) { InventoryManagementService inventoryManagementService; PaymentManagementService paymentManagementService; ServiceManagementService serviceManagementService; DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); auto usersMap = util::getObjects(trackedUsersMap); if (util::isUsernameDuplicate(username, usersMap)) { throw std::runtime_error("Username already exists"); } if (util::isEmailDuplicate(email, usersMap)) { throw std::runtime_error("Email already exists"); } if (util::isPhoneDuplicate(phone, usersMap)) { throw std::runtime_error("Phone already exists"); } User* newUser = Factory::getObject(username, password, name, phone, email, type); trackedUsersMap.insert(newUser->getId(), util::createNewRecord(newUser)); paymentManagementService.attach(newUser); serviceManagementService.attach(newUser); if (newUser->getUserType() == util::UserType::ADMIN) { inventoryManagementService.attach(newUser); } m_dataStore.saveUsers(); } /* Function: updateUserDetails Description: Updates the email and phone details of an existing user. Throws an exception if the user does not exist. Parameter: const std::string& userID - ID of the user to update const std::string& email - new email address const std::string& phone - new phone number Return type: void */ void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone) { DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); auto usersMap = util::getObjects(trackedUsersMap); int index = trackedUsersMap.find(userID); if (index == -1) { throw std::runtime_error("User does not exist!\n"); } User* user = trackedUsersMap.getValueAt(index).data; bool isModified = false; if (email != user->getEmail()) { if (util::isEmailDuplicate(email, usersMap)) { throw std::runtime_error("Email already exists!\n"); } user->setEmail(email); isModified = true; } if (phone != user->getPhone()) { if (util::isPhoneDuplicate(phone, usersMap)) { throw std::runtime_error("Phone number already exists!\n"); } user->setPhone(phone); isModified = true; } if (isModified) { trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED; m_dataStore.saveUsers(); } } /* Function: getUserNotifications Description: Retrieves all notifications associated with a given user ID. Parameters: - userID: The unique ID of the user whose notifications are to be retrieved. Returns: - util::Vector containing all notifications for the user. Throws: - std::runtime_error if no user is found with the given UserID or if the User object is invalid. */ util::Vector UserManagementService::getUserNotifications(const std::string& userID) { DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); if (trackedUsersMap.find(userID) == -1) { throw std::runtime_error("No user found with given UserID"); } User* user = trackedUsersMap[userID].data; if (user) { auto& trackedNotificationMap = m_dataStore.getNotifications(); int numberOfNotifications = trackedNotificationMap.getSize(); util::Vector notificationsVector; for (int index = 0; index < numberOfNotifications; index++) { Notification* notification = trackedNotificationMap.getValueAt(index).data; if (notification->getRecipientUserId() == userID && notification->getState() == util::State::ACTIVE) { notificationsVector.push_back(notification); } } return notificationsVector; } else { throw std::runtime_error("Invalid User object"); } } /* Function: deleteNotification Description: Marks a specific notification associated with a given user as inactive. Parameters: - notificationID: The unique ID of the notification to be deleted. - userID: The unique ID of the user whose notification is to be deleted. Returns: - void Throws: - std::runtime_error if no user is found with the given UserID or if no notification is found with the given NotificationID. */ void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID) { DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); auto& trackedNotificationsMap = m_dataStore.getNotifications(); int userIndex = trackedUsersMap.find(userID); if (userIndex == -1) { throw std::runtime_error("No user found with given UserID"); } int notificationIndex = trackedNotificationsMap.find(notificationID); if (notificationIndex == -1) { throw std::runtime_error("No notification found with given NotificationID"); } Notification* notification = trackedNotificationsMap.getValueAt(notificationIndex).data; if (notification->getRecipientUserId() == userID) { notification->setState(util::State::INACTIVE); trackedNotificationsMap.getValueAt(notificationIndex).state = RecordState::MODIFIED; m_dataStore.saveNotifications(); } } /* Function: getUsers Description: Retrieves all users stored in the DataStore. Parameter: None Return type: util::Map */ util::Map UserManagementService::getUsers() { DataStoreLockGuard lock(m_dataStore); auto users = util::getObjects(m_dataStore.getUsers()); return users; } /* Function: getUser Description: Retrieves a specific user by ID from the DataStore. Parameter: const std::string& userID - ID of the user Return type: User* */ User* UserManagementService::getUser(const std::string& userID) { DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); int index = trackedUsersMap.find(userID); if (index != -1) { return trackedUsersMap.getValueAt(index).data; } return nullptr; } /* Function: removeUser Description: Marks a user as inactive in the DataStore instead of deleting them. Parameter: const std::string& userID - ID of the user to remove Return type: void */ void UserManagementService::removeUser(const std::string& userID) { InventoryManagementService inventoryManagementService; PaymentManagementService paymentManagementService; ServiceManagementService serviceManagementService; std::string removedUserID; { DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); int index = trackedUsersMap.find(userID); if (index != -1) { User* user = trackedUsersMap.getValueAt(index).data; if (user != nullptr) { 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 (!removedUserID.empty()) { EventManager::sendUserDisabledEvent(removedUserID); } } /* Function: getUsers Description: Retrieves all active users of the specified type from the DataStore. Parameters: - type: The user type to filter by (ADMIN, CUSTOMER, or TECHNICIAN). Returns: - util::Map: Collection of active users matching the specified type, keyed by user ID. */ util::Map UserManagementService::getUsers(util::UserType type) { DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); util::Map currentUsers = util::getObjects(trackedUsersMap); util::Map filteredUsersMap; for (int index = 0; index < currentUsers.getSize(); index++) { User* currentUser = currentUsers.getValueAt(index); if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type) { filteredUsersMap.insert(currentUser->getId(), currentUser); } } return filteredUsersMap; }