Implement Service Refactoring

<UserStory> 1954: Implement Service Refactoring </UserStory>

UserStory #1954

<Changes>
1. Refactored notification handling to persist notifications directly in the datastore instead of maintaining notification collections within User objects.
2. Removed recipient User pointer dependencies from Notification and retained recipient user identification through recipientUserId.
3. Implemented generic observer persistence support in DataStore with shared helper methods for loading and saving observer subscriptions.
4. Added datastore-backed observer management for ServiceManagementService, PaymentManagementService, and InventoryManagementService.
5. Updated attach() and detach() operations to load, modify, and persist observer subscriptions using shared memory mappings.
6. Refactored sendNotification() implementations to create and persist Notification records directly to the datastore for subscribed observers.
7. Updated UserManagementService notification retrieval and deletion logic to operate on datastore notification records filtered by recipient user ID.
8. Removed notification ownership and observer-specific notification APIs from User and Observer classes.
9. Added configurable shared memory growth factor support and updated mapping expansion logic to use centralized configuration values.
10. Removed obsolete NotificationManagementService implementation and updated project configuration references.
11. Added DataStoreLockGuard integration for observer and notification persistence operations to ensure synchronized datastore access.
</Changes>

<Test>
N/A
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
This commit is contained in:
2026-06-12 19:23:56 +05:30
parent 5f4ee72ffe
commit 67ac7f6625
17 changed files with 186 additions and 210 deletions
@@ -140,7 +140,6 @@
<ClCompile Include="models\User.cpp" /> <ClCompile Include="models\User.cpp" />
<ClCompile Include="services\AuthenticationManagementService.cpp" /> <ClCompile Include="services\AuthenticationManagementService.cpp" />
<ClCompile Include="services\InventoryManagementService.cpp" /> <ClCompile Include="services\InventoryManagementService.cpp" />
<ClCompile Include="services\NotificationManagementService.cpp" />
<ClCompile Include="services\PaymentManagementService.cpp" /> <ClCompile Include="services\PaymentManagementService.cpp" />
<ClCompile Include="services\ServiceManagementService.cpp" /> <ClCompile Include="services\ServiceManagementService.cpp" />
<ClCompile Include="services\UserManagementService.cpp" /> <ClCompile Include="services\UserManagementService.cpp" />
@@ -114,9 +114,6 @@
<ClCompile Include="datastores\DataStore.cpp"> <ClCompile Include="datastores\DataStore.cpp">
<Filter>Source Files\DataStores</Filter> <Filter>Source Files\DataStores</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="services\NotificationManagementService.cpp">
<Filter>Source Files\Services</Filter>
</ClCompile>
<ClCompile Include="core\patterns\Observer.cpp"> <ClCompile Include="core\patterns\Observer.cpp">
<Filter>Source Files\Core\Patterns</Filter> <Filter>Source Files\Core\Patterns</Filter>
</ClCompile> </ClCompile>
@@ -278,5 +275,8 @@
<ClInclude Include="datastores\sharedmemory\SharedMemory.h"> <ClInclude Include="datastores\sharedmemory\SharedMemory.h">
<Filter>Header Files\DataStores\SharedMemory</Filter> <Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="datastores\DataStoreLockGuard.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -13,5 +13,4 @@ class Observer
{ {
public: public:
virtual ~Observer() = default; virtual ~Observer() = default;
virtual void addNotification(Notification* notification) = 0;
}; };
@@ -230,20 +230,6 @@ util::Map<std::string, TrackedRecord<User>>& DataStore::getUsers()
{ {
auto users = loadRecords<User, SerializedUser>(m_users); auto users = loadRecords<User, SerializedUser>(m_users);
refreshCache(m_userCache, users); refreshCache(m_userCache, users);
auto& notifications = getNotifications();
int numberOfNotifications = m_notificationCache.getSize();
for (int index = 0; index < numberOfNotifications; index++)
{
Notification* notification = notifications.getValueAt(index).data;
const std::string& recipientUserId = notification->getRecipientUserId();
int userIndex = m_userCache.find(recipientUserId);
if (userIndex == -1)
{
throw std::runtime_error("Invalid recipient user ID");
}
User* user = m_userCache.getValueAt(userIndex).data;
user->addNotification(notification);
}
return m_userCache; return m_userCache;
} }
@@ -340,6 +326,37 @@ util::Map<std::string, TrackedRecord<Invoice>>& DataStore::getInvoices()
return m_invoiceCache; return m_invoiceCache;
} }
/*
Function: getObservers
Description: Retrieves observer records from the specified observer mapping
and resolves them to User objects.
Parameters:
- mapping: Observer mapping to read from
Returns:
- util::Map<std::string, User*>: Collection of observer records
Throws:
- std::runtime_error if an observer references an invalid user ID
*/
util::Map<std::string, User*> DataStore::getObservers(MappingInfo& mapping)
{
auto& users = getUsers();
util::Map<std::string, User*> observers;
SharedMemory::ensureLatestMapping(mapping);
size_t recordCount = SharedMemory::getRecordCount(mapping);
for (size_t index = 0; index < recordCount; index++)
{
const SerializedObserver* observer = static_cast<SerializedObserver*>(SharedMemory::getRecordAddress(mapping, index));
int userIndex = users.find(observer->id);
if (userIndex == -1)
{
throw std::runtime_error("Invalid observer user ID");
}
User* user = users.getValueAt(userIndex).data;
observers.insert(user->getId(), user);
}
return observers;
}
/* /*
Function: getServiceManagementObservers Function: getServiceManagementObservers
Description: Retrieves all service management observer records from the datastore. Description: Retrieves all service management observer records from the datastore.
@@ -350,7 +367,7 @@ Returns:
*/ */
util::Map<std::string, User*> DataStore::getServiceManagementObservers() util::Map<std::string, User*> DataStore::getServiceManagementObservers()
{ {
return util::Map<std::string, User*>(); return getObservers(m_serviceManagementObservers);
} }
/* /*
@@ -363,7 +380,7 @@ Returns:
*/ */
util::Map<std::string, User*> DataStore::getPaymentManagementObservers() util::Map<std::string, User*> DataStore::getPaymentManagementObservers()
{ {
return util::Map<std::string, User*>(); return getObservers(m_paymentManagementObservers);
} }
/* /*
@@ -376,7 +393,7 @@ Returns:
*/ */
util::Map<std::string, User*> DataStore::getInventoryManagementObservers() util::Map<std::string, User*> DataStore::getInventoryManagementObservers()
{ {
return util::Map<std::string, User*>(); return getObservers(m_inventoryManagementObservers);
} }
/* /*
@@ -390,7 +407,6 @@ Returns:
void DataStore::saveUsers() void DataStore::saveUsers()
{ {
saveRecords<User, SerializedUser>(m_users, m_userCache); saveRecords<User, SerializedUser>(m_users, m_userCache);
saveNotifications();
} }
/* /*
@@ -478,16 +494,49 @@ void DataStore::saveInvoices()
{ {
} }
/*
Function: saveObservers
Description: Persists observer records to the specified observer mapping.
Parameters:
- mapping: MappingInfo&, observer mapping to save to
- observers: util::Map<std::string, User*>&, collection of observer records
Returns:
- None
*/
void DataStore::saveObservers(MappingInfo& mapping, util::Map<std::string, User*>& observers)
{
size_t observerCount = static_cast<size_t>(observers.getSize());
size_t capacity = config::file::INITIAL_CAPACITY;
while (capacity < observerCount)
{
capacity *= config::file::GROWTH_FACTOR;
}
if (!SharedMemory::resizeMapping(mapping, capacity))
{
throw std::runtime_error("Failed to resize observer mapping");
}
SharedMemory::setRecordCount(mapping, observerCount);
for (size_t index = 0; index < observerCount; index++)
{
SerializedObserver serializedObserver;
User* user = observers.getValueAt(static_cast<int>(index));
strcpy_s(serializedObserver.id, sizeof(serializedObserver.id), user->getId().c_str());
SerializedObserver* destination = static_cast<SerializedObserver*>(SharedMemory::getRecordAddress(mapping, index));
*destination = serializedObserver;
}
}
/* /*
Function: saveServiceManagementObservers Function: saveServiceManagementObservers
Description: Persists all service management observer records to the datastore. Description: Persists all service management observer records to the datastore.
Parameters: Parameters:
- observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records - observers: util::Map<std::string, User*>&, collection of observer records
Returns: Returns:
- None - None
*/ */
void DataStore::saveServiceManagementObservers(util::Map<std::string, User*>& observers) void DataStore::saveServiceManagementObservers(util::Map<std::string, User*>& observers)
{ {
saveObservers(m_serviceManagementObservers, observers);
} }
/* /*
@@ -500,6 +549,7 @@ Returns:
*/ */
void DataStore::savePaymentManagementObservers(util::Map<std::string, User*>& observers) void DataStore::savePaymentManagementObservers(util::Map<std::string, User*>& observers)
{ {
saveObservers(m_paymentManagementObservers, observers);
} }
/* /*
@@ -512,6 +562,7 @@ Returns:
*/ */
void DataStore::saveInventoryManagementObservers(util::Map<std::string, User*>& observers) void DataStore::saveInventoryManagementObservers(util::Map<std::string, User*>& observers)
{ {
saveObservers(m_inventoryManagementObservers, observers);
} }
/* /*
@@ -86,6 +86,8 @@ private:
void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records); void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records);
template<typename TObject> void clearCache(util::Map<std::string, TrackedRecord<TObject>>&cache); template<typename TObject> void clearCache(util::Map<std::string, TrackedRecord<TObject>>&cache);
template<typename TObject> void refreshCache(util::Map<std::string, TrackedRecord<TObject>>&cache, util::Map<std::string, TrackedRecord<TObject>>&refreshedCache); template<typename TObject> void refreshCache(util::Map<std::string, TrackedRecord<TObject>>&cache, util::Map<std::string, TrackedRecord<TObject>>&refreshedCache);
util::Map<std::string, User*> getObservers(MappingInfo& mapping);
void saveObservers(MappingInfo& mapping, util::Map<std::string, User*>& observers);
}; };
/* /*
@@ -320,7 +320,7 @@ bool SharedMemory::ensureCapacityForInsert(MappingInfo& mapping)
{ {
return true; return true;
} }
return resizeMapping(mapping, capacity * 2); return resizeMapping(mapping, capacity * config::file::GROWTH_FACTOR);
} }
/* /*
@@ -1,7 +1,7 @@
/* /*
File: Notification.cpp File: Notification.cpp
Description: Implements the Notification class which represents system notifications in the Vehicle Service Management System. Description: Implements the Notification class which represents system notifications in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for notification details such as ID, recipient, title, message, and timestamp. Provides constructors, accessors, and mutators for notification details such as ID, recipientID, title, message, and timestamp.
Author: Trenser Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
@@ -24,8 +24,7 @@ Returns:
*/ */
Notification::Notification() Notification::Notification()
: m_id("NOT" + std::to_string(++m_uid)), : m_id("NOT" + std::to_string(++m_uid)),
m_recipient(nullptr), m_state(util::State::ACTIVE) { m_state(util::State::ACTIVE) {}
}
/* /*
Function: Notification Function: Notification
@@ -39,10 +38,9 @@ Parameters:
Returns: Returns:
- A new Notification object. - A new Notification object.
*/ */
Notification::Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt) Notification::Notification(const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt)
: m_id("NOT" + std::to_string(++m_uid)), : m_id("NOT" + std::to_string(++m_uid)),
m_recipientUserId(recipientUserId), m_recipientUserId(recipientUserId),
m_recipient(recipient),
m_title(title), m_title(title),
m_message(message), m_message(message),
m_state(util::State::ACTIVE), m_state(util::State::ACTIVE),
@@ -65,7 +63,6 @@ Returns:
Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state) Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state)
: m_id(id), : m_id(id),
m_recipientUserId(recipientUserId), m_recipientUserId(recipientUserId),
m_recipient(nullptr),
m_title(title), m_title(title),
m_message(message), m_message(message),
m_createdAt(createdAt), m_createdAt(createdAt),
@@ -100,17 +97,6 @@ const std::string& Notification::getRecipientUserId() const
return m_recipientUserId; return m_recipientUserId;
} }
/*
Function: getRecipient
Description: Retrieves the pointer to the recipient user.
Returns:
- User* representing the recipient.
*/
User* Notification::getRecipient() const
{
return m_recipient;
}
/* /*
Function: getTitle Function: getTitle
Description: Retrieves the title of the notification. Description: Retrieves the title of the notification.
@@ -181,19 +167,6 @@ void Notification::setRecipientUserId(const std::string& recipientUserId)
m_recipientUserId = recipientUserId; m_recipientUserId = recipientUserId;
} }
/*
Function: setRecipient
Description: Sets the recipient user pointer for the notification.
Parameters:
- recipient: Pointer to the User object.
Returns:
- void
*/
void Notification::setRecipient(User* recipient)
{
m_recipient = recipient;
}
/* /*
Function: setTitle Function: setTitle
Description: Sets the title of the notification. Description: Sets the title of the notification.
@@ -20,24 +20,21 @@ private:
static int m_uid; static int m_uid;
std::string m_id; std::string m_id;
std::string m_recipientUserId; std::string m_recipientUserId;
User* m_recipient;
std::string m_title; std::string m_title;
std::string m_message; std::string m_message;
util::Timestamp m_createdAt; util::Timestamp m_createdAt;
util::State m_state; util::State m_state;
public: public:
Notification(); Notification();
Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt); Notification(const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt);
Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state); Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state);
const std::string& getId() const; const std::string& getId() const;
const std::string& getRecipientUserId() const; const std::string& getRecipientUserId() const;
User* getRecipient() const;
const std::string& getTitle() const; const std::string& getTitle() const;
const std::string& getMessage() const; const std::string& getMessage() const;
const util::Timestamp& getCreatedAt() const; const util::Timestamp& getCreatedAt() const;
void setId(const std::string& id); void setId(const std::string& id);
void setRecipientUserId(const std::string& recipientUserId); void setRecipientUserId(const std::string& recipientUserId);
void setRecipient(User* recipient);
void setTitle(const std::string& title); void setTitle(const std::string& title);
void setMessage(const std::string& message); void setMessage(const std::string& message);
void setCreatedAt(const util::Timestamp& createdAt); void setCreatedAt(const util::Timestamp& createdAt);
@@ -89,23 +89,6 @@ User::User(const std::string& userId, const std::string& userName, const std::st
} }
} }
/*
Function: ~User
Description: Destructor that cleans up dynamically allocated notifications associated with the user.
Parameters:
- None
Returns:
- void
*/
User::~User()
{
auto values = m_notifications.getValues();
for (int index = 0; index < values.getSize(); index++)
{
delete values[index];
}
}
/* /*
Function: getId Function: getId
Description: Retrieves the unique ID of the user. Description: Retrieves the unique ID of the user.
@@ -172,17 +155,6 @@ const std::string& User::getEmail() const
return m_email; return m_email;
} }
/*
Function: getNotifications
Description: Retrieves the map of notifications associated with the user.
Returns:
- util::Map<std::string, Notification*>& representing the notifications.
*/
util::Map<std::string, Notification*>& User::getNotifications()
{
return m_notifications;
}
/* /*
Function: getUserType Function: getUserType
Description: Retrieves the role of the user. Description: Retrieves the role of the user.
@@ -283,22 +255,6 @@ void User::setEmail(const std::string& email)
m_email = email; m_email = email;
} }
/*
Function: addNotification
Description: Adds a new notification to the users notification map.
Parameters:
- notification: Pointer to the Notification object.
Returns:
- void
*/
void User::addNotification(Notification* notification)
{
if (notification)
{
m_notifications.insert(notification->getId(), notification);
}
}
/* /*
Function: setRole Function: setRole
Description: Sets the role of the user. Description: Sets the role of the user.
@@ -26,21 +26,19 @@ private:
std::string m_name; std::string m_name;
std::string m_phone; std::string m_phone;
std::string m_email; std::string m_email;
util::Map<std::string, Notification*> m_notifications;
util::UserType m_type; util::UserType m_type;
util::State m_status; util::State m_status;
public: public:
User(); User();
User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role); User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role);
User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status); User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status);
~User(); ~User() = default;
const std::string& getId() const; const std::string& getId() const;
const std::string& getUserName() const; const std::string& getUserName() const;
const std::string& getPassword() const; const std::string& getPassword() const;
const std::string& getName() const; const std::string& getName() const;
const std::string& getPhone() const; const std::string& getPhone() const;
const std::string& getEmail() const; const std::string& getEmail() const;
util::Map<std::string, Notification*>& getNotifications();
util::UserType getUserType() const; util::UserType getUserType() const;
util::State getState() const; util::State getState() const;
void setId(const std::string& id); void setId(const std::string& id);
@@ -49,7 +47,6 @@ public:
void setName(const std::string& name); void setName(const std::string& name);
void setPhone(const std::string& phone); void setPhone(const std::string& phone);
void setEmail(const std::string& email); void setEmail(const std::string& email);
void addNotification(Notification* notification) override;
void setRole(util::UserType role); void setRole(util::UserType role);
void setState(util::State status); void setState(util::State status);
SerializedUser serialize() const; SerializedUser serialize() const;
@@ -19,7 +19,7 @@ Date: 22-May-2026
#include "User.h" #include "User.h"
#include "Utility.h" #include "Utility.h"
#include "Vector.h" #include "Vector.h"
#include "DataStoreLockGuard.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{}; util::Map<std::string, User*> InventoryManagementService::m_observers{};
@@ -271,6 +271,9 @@ Returns:
*/ */
void InventoryManagementService::attach(User* user) void InventoryManagementService::attach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getInventoryManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -279,6 +282,7 @@ void InventoryManagementService::attach(User* user)
m_observers[userID] = user; m_observers[userID] = user;
} }
} }
m_dataStore.saveInventoryManagementObservers(m_observers);
} }
/* /*
@@ -291,6 +295,9 @@ Returns:
*/ */
void InventoryManagementService::detach(User* user) void InventoryManagementService::detach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getInventoryManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -299,6 +306,7 @@ void InventoryManagementService::detach(User* user)
m_observers.remove(userID); m_observers.remove(userID);
} }
} }
m_dataStore.saveInventoryManagementObservers(m_observers);
} }
/* /*
@@ -315,27 +323,27 @@ Throws:
*/ */
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message) void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{ {
if (user) if (!user)
{ {
if (m_observers.find(user->getId()) != -1) return;
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
} }
DataStoreLockGuard lock(m_dataStore);
m_observers = m_dataStore.getInventoryManagementObservers();
if (m_observers.find(user->getId()) == -1)
{
return;
}
Notification* notification = Factory::getObject<Notification>(
user->getId(),
title,
message,
util::Timestamp());
if (!notification)
{
throw std::runtime_error("Failed to create notification");
}
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
} }
@@ -1 +0,0 @@
#include "NotificationManagementService.h"
@@ -21,6 +21,7 @@ Date: 20-May-2026
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
#include "Utility.h" #include "Utility.h"
#include "DataStoreLockGuard.h"
util::Map<std::string, User*> PaymentManagementService::m_observers{}; util::Map<std::string, User*> PaymentManagementService::m_observers{};
@@ -34,6 +35,9 @@ Returns:
*/ */
void PaymentManagementService::attach(User* user) void PaymentManagementService::attach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getPaymentManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -42,6 +46,7 @@ void PaymentManagementService::attach(User* user)
m_observers[userID] = user; m_observers[userID] = user;
} }
} }
m_dataStore.savePaymentManagementObservers(m_observers);
} }
/* /*
@@ -54,6 +59,9 @@ Returns:
*/ */
void PaymentManagementService::detach(User* user) void PaymentManagementService::detach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getPaymentManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -62,6 +70,7 @@ void PaymentManagementService::detach(User* user)
m_observers.remove(userID); m_observers.remove(userID);
} }
} }
m_dataStore.savePaymentManagementObservers(m_observers);
} }
/* /*
@@ -78,28 +87,28 @@ Throws:
*/ */
void PaymentManagementService::sendNotification(User* user, const std::string& title, const std::string& message) void PaymentManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{ {
if (user) if (!user)
{ {
if (m_observers.find(user->getId()) != -1) return;
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
} }
DataStoreLockGuard lock(m_dataStore);
m_observers = m_dataStore.getPaymentManagementObservers();
if (m_observers.find(user->getId()) == -1)
{
return;
}
Notification* notification = Factory::getObject<Notification>(
user->getId(),
title,
message,
util::Timestamp());
if (!notification)
{
throw std::runtime_error("Failed to create notification");
}
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
} }
/* /*
@@ -26,6 +26,7 @@ Date:19-May-2026
#include "User.h" #include "User.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "Utility.h" #include "Utility.h"
#include "DataStoreLockGuard.h"
/* /*
Function: purchaseService Function: purchaseService
@@ -122,6 +123,9 @@ Returns:
*/ */
void ServiceManagementService::attach(User* user) void ServiceManagementService::attach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getServiceManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -130,6 +134,7 @@ void ServiceManagementService::attach(User* user)
m_observers[userID] = user; m_observers[userID] = user;
} }
} }
m_dataStore.saveServiceManagementObservers(m_observers);
} }
/* /*
@@ -142,6 +147,9 @@ Returns:
*/ */
void ServiceManagementService::detach(User* user) void ServiceManagementService::detach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getServiceManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -150,6 +158,7 @@ void ServiceManagementService::detach(User* user)
m_observers.remove(userID); m_observers.remove(userID);
} }
} }
m_dataStore.saveServiceManagementObservers(m_observers);
} }
/* /*
@@ -166,52 +175,28 @@ Throws:
*/ */
void ServiceManagementService::sendNotification(User* user, const std::string& title, const std::string& message) void ServiceManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{ {
if (user) if (!user)
{ {
if (m_observers.find(user->getId()) != -1) return;
{ }
Notification* notification = DataStoreLockGuard lock(m_dataStore);
Factory::getObject<Notification>( m_observers = m_dataStore.getServiceManagementObservers();
user->getId(), if (m_observers.find(user->getId()) == -1)
user, {
title, return;
message, }
util::Timestamp() Notification* notification = Factory::getObject<Notification>(
); user->getId(),
if (notification) title,
{ message,
user->addNotification(notification); util::Timestamp());
} if (!notification)
else {
{ throw std::runtime_error("Failed to create notification");
throw std::runtime_error("Failed to create notification"); }
} auto& trackedNotificationsMap = m_dataStore.getNotifications();
} trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
} m_dataStore.saveNotifications();
}
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
ServiceManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> ServiceManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
} }
/* /*
@@ -53,6 +53,4 @@ public:
void saveServiceBookings(); void saveServiceBookings();
void loadJobCards(); void loadJobCards();
void saveJobCards(); void saveJobCards();
void loadObservers();
void saveObservers();
}; };
@@ -170,12 +170,16 @@ util::Vector<Notification*> UserManagementService::getUserNotifications(const st
User* user = trackedUsersMap[userID].data; User* user = trackedUsersMap[userID].data;
if (user) if (user)
{ {
auto& notifications = user->getNotifications(); auto& trackedNotificationMap = m_dataStore.getNotifications();
int numberOfNotifications = notifications.getSize(); int numberOfNotifications = trackedNotificationMap.getSize();
util::Vector<Notification*> notificationsVector; util::Vector<Notification*> notificationsVector;
for (int index = 0; index < numberOfNotifications; index++) for (int index = 0; index < numberOfNotifications; index++)
{ {
notificationsVector.push_back(notifications.getValueAt(index)); Notification* notification = trackedNotificationMap.getValueAt(index).data;
if (notification->getRecipientUserId() == userID && notification->getState() == util::State::ACTIVE)
{
notificationsVector.push_back(notification);
}
} }
return notificationsVector; return notificationsVector;
} }
@@ -208,20 +212,18 @@ void UserManagementService::deleteNotification(const std::string& notificationID
{ {
throw std::runtime_error("No user found with given UserID"); throw std::runtime_error("No user found with given UserID");
} }
User* user = trackedUsersMap.getValueAt(userIndex).data;
auto& notifications = user->getNotifications();
if (notifications.find(notificationID) == -1)
{
throw std::runtime_error("No notification found with given NotificationID");
}
int notificationIndex = trackedNotificationsMap.find(notificationID); int notificationIndex = trackedNotificationsMap.find(notificationID);
if (notificationIndex == -1) if (notificationIndex == -1)
{ {
throw std::runtime_error("No notification found with given NotificationID"); throw std::runtime_error("No notification found with given NotificationID");
} }
notifications[notificationID]->setState(util::State::INACTIVE); Notification* notification = trackedNotificationsMap.getValueAt(notificationIndex).data;
trackedNotificationsMap.getValueAt(notificationIndex).state = RecordState::MODIFIED; if (notification->getRecipientUserId() == userID)
m_dataStore.saveNotifications(); {
notification->setState(util::State::INACTIVE);
trackedNotificationsMap.getValueAt(notificationIndex).state = RecordState::MODIFIED;
m_dataStore.saveNotifications();
}
} }
/* /*
@@ -29,6 +29,7 @@ namespace config
namespace file namespace file
{ {
const size_t INITIAL_CAPACITY = 100; const size_t INITIAL_CAPACITY = 100;
const size_t GROWTH_FACTOR = 2;
constexpr const char* DIRECTORY = "files/"; constexpr const char* DIRECTORY = "files/";
constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat"; constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat";
constexpr const char* USER_FILE = "files/User.dat"; constexpr const char* USER_FILE = "files/User.dat";