Skip to content

Commit 236b0f0

Browse files
authored
Merge pull request #280 from SCVApp/master
api so user can have multiple lockers
2 parents 1de2ad7 + 24abe89 commit 236b0f0

File tree

3 files changed

+88
-25
lines changed

3 files changed

+88
-25
lines changed

db_migrations/locker_function.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ BEGIN
77
END IF;
88
END IF;
99

10+
-- Check if user has reached the maximum number of lockers
11+
IF (TG_OP IN ('INSERT', 'UPDATE') AND (OLD.user_id IS NULL OR NEW.user_id != OLD.user_id OR OLD.locker_id IS NULL OR NEW.locker_id != OLD.locker_id)) THEN
12+
IF (SELECT COUNT(*) FROM lockers_users WHERE user_id = NEW.user_id AND start_time < NOW() AND (end_time IS NULL OR end_time > NOW())) >= 2 THEN
13+
RAISE EXCEPTION 'The user have reached the maximum number of lockers';
14+
END IF;
15+
END IF;
1016
RETURN NEW;
1117
END;
1218
$$ LANGUAGE plpgsql;

src/lockers/lockers.controller.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class LockersController {
3333
async getUserLocker(@Req() req: Request, @Res() res: Response) {
3434
const userAzureId: string = req.body.azure_id;
3535
const userAccessToken: string = req.body.access_token;
36-
const locker = await this.lockersService.getUserLocker(
36+
const locker = await this.lockersService.getUserLockers(
3737
userAzureId,
3838
userAccessToken,
3939
);
@@ -94,11 +94,15 @@ export class LockersController {
9494
User requests to end locker session if user currently has a locker assigned to him it will be opened and end the session so locker can be used by other users
9595
*/
9696
@Post('end')
97-
async endLocker(@Req() req: Request, @Res() res: Response) {
98-
const userAzureId = req.body.azure_id;
99-
const userAccessToken = req.body.access_token;
97+
async endLocker(@Body() data: OpenLockerDto, @Res() res: Response) {
98+
const userAzureId = data.azure_id;
99+
const userAccessToken = data.access_token;
100100

101-
await this.lockersService.endLocker(userAzureId, userAccessToken);
101+
await this.lockersService.endLocker(
102+
userAzureId,
103+
userAccessToken,
104+
data.lockerId,
105+
);
102106

103107
return res.status(200).json({ message: 'Locker session ended' });
104108
}

src/lockers/lockers.service.ts

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,71 @@ export class LockersService {
8181
return await this.lockerRepository.findOne({ where: { id } });
8282
}
8383

84-
async getUserLocker(userAzureId: string, userAccessToken: string) {
84+
async getUserLockers(userAzureId: string, userAccessToken: string) {
8585
const user: UserPassEntity = await this.passService.getUserFromAzureId(
8686
userAzureId,
8787
userAccessToken,
8888
);
8989
if (!user) {
9090
throw new NotFoundException('User not found');
9191
}
92-
return await this.getUsersActiveLocker(user);
92+
return await this.getUsersActiveLockers(user, false);
9393
}
9494

95-
async getUsersActiveLocker(
95+
async getUsersActiveLockers(
9696
user: UserPassEntity,
97-
): Promise<LockerEntity | null> {
98-
const locker = await this.lockersUsersRepository
97+
countOnly: true,
98+
): Promise<number>;
99+
async getUsersActiveLockers(
100+
user: UserPassEntity,
101+
countOnly: false,
102+
): Promise<LockerEntity[]>;
103+
104+
async getUsersActiveLockers(
105+
user: UserPassEntity,
106+
countOnly: boolean,
107+
): Promise<LockerEntity[] | number> {
108+
const data = this.lockersUsersRepository
99109
.createQueryBuilder('lockers_users')
100110
.select('locker_id')
101111
.where('user_id = :user_id', { user_id: user.id })
102112
.andWhere('start_time < NOW()')
103113
.andWhere('(end_time > NOW() OR end_time IS NULL)')
104-
.orderBy('start_time', 'DESC')
105-
.limit(1)
106-
.getRawOne();
114+
.orderBy('start_time', 'DESC');
107115

108-
if (!locker || !locker.locker_id) {
109-
return null;
116+
if (countOnly) {
117+
return await data.getCount();
110118
}
111119

112-
return await this.getLockerById(locker.locker_id);
120+
const lockers = await data.getRawMany();
121+
const promises = lockers.map((locker) =>
122+
this.getLockerById(locker.locker_id),
123+
);
124+
const result = await Promise.allSettled(promises);
125+
126+
return result
127+
.map((r) => {
128+
if (r.status === 'fulfilled') {
129+
return r.value;
130+
}
131+
return null;
132+
})
133+
.filter((r): r is LockerEntity => r !== null);
134+
}
135+
136+
async isUserUsingLocker(
137+
user: UserPassEntity,
138+
lockerId: number,
139+
): Promise<boolean> {
140+
const result: number = await this.lockersUsersRepository
141+
.createQueryBuilder('lu')
142+
.where('lu.user_id = :user_id', { user_id: user.id })
143+
.andWhere('lu.locker_id = :locker_id', { locker_id: lockerId })
144+
.andWhere('lu.start_time < NOW()')
145+
.andWhere('(lu.end_time > NOW() OR lu.end_time IS NULL)')
146+
.getCount();
147+
148+
return result > 0;
113149
}
114150

115151
// Open locker or assign locker to
@@ -125,14 +161,20 @@ export class LockersService {
125161
if (!user) {
126162
throw new NotFoundException('User not found');
127163
}
128-
const activeLocker = await this.getUsersActiveLocker(user);
129-
if (activeLocker) {
130-
const success = await this.openLocker(activeLocker);
131-
if (!success) {
132-
throw new InternalServerErrorException('Failed to open locker');
133-
}
164+
165+
// Check if user is already using locker
166+
const isUserUsingLocker = await this.isUserUsingLocker(user, lockerId);
167+
if (isUserUsingLocker) {
168+
await this.openLockerById(lockerId);
134169
return;
135170
}
171+
172+
// Check if user lockers limit is reached
173+
const userLockersCount = await this.getUsersActiveLockers(user, true);
174+
if (userLockersCount >= 2) {
175+
throw new NotFoundException('You have reached the limit of lockers');
176+
}
177+
136178
const selectedLocker = await this.getLockerById(lockerId);
137179
if (!selectedLocker) {
138180
throw new NotFoundException('Locker not found');
@@ -163,18 +205,29 @@ export class LockersService {
163205
}
164206

165207
// End locker session
166-
async endLocker(userAzureId: string, userAccessToken: string) {
208+
async endLocker(
209+
userAzureId: string,
210+
userAccessToken: string,
211+
lockerId: number,
212+
) {
167213
const user: UserPassEntity = await this.passService.getUserFromAzureId(
168214
userAzureId,
169215
userAccessToken,
170216
);
171217
if (!user) {
172218
throw new NotFoundException('User not found');
173219
}
174-
const activeLocker = await this.getUsersActiveLocker(user);
220+
221+
const isUserUsingLocker = await this.isUserUsingLocker(user, lockerId);
222+
if (!isUserUsingLocker) {
223+
throw new NotFoundException('User is not using this locker');
224+
}
225+
226+
const activeLocker = await this.getLockerById(lockerId);
175227
if (!activeLocker) {
176-
throw new NotFoundException('User does not have an active locker');
228+
throw new NotFoundException('Locker not found');
177229
}
230+
178231
const success = await this.openLocker(activeLocker);
179232
if (!success) {
180233
throw new InternalServerErrorException('Failed to open locker');

0 commit comments

Comments
 (0)