Skip to content

Commit c1bb1fd

Browse files
committed
refactor me service
1 parent 03ce8f8 commit c1bb1fd

File tree

9 files changed

+89
-38
lines changed

9 files changed

+89
-38
lines changed

client/src/pages/maintenance/MaintenanceCreate.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import { useNavigate } from "react-router";
44
import { usePost, useGet } from "@/hooks/UseApi";
55
import type { ApiResponse } from "@/types/api";
66
import type { IMonitor } from "@/types/monitor";
7-
import type { IMaintenance } from "@/types/maintenance";
7+
import type { Maintenance } from "@/types/maintenance";
88
import type { FormValues } from "@/pages/maintenance/MaintenanceForm";
99

1010
const MaintenanceCreatePage = () => {
1111
const navigate = useNavigate();
12-
const { post, loading } = usePost<FormValues, IMaintenance>();
12+
const { post, loading } = usePost<FormValues, Maintenance>();
1313
const { response, loading: monitorsLoading } =
1414
useGet<ApiResponse<IMonitor[]>>("/monitors");
1515

server/src/init/services.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,15 @@ export const initServices = async () => {
125125
teamRepository,
126126
teamMembershipRepository
127127
);
128-
const meService = new MeService(entitlementsProvider);
128+
const meService = new MeService(
129+
entitlementsProvider,
130+
userRepository,
131+
orgRepository,
132+
orgMembershipRepository,
133+
teamRepository,
134+
teamMembershipRepository,
135+
roleRepository
136+
);
129137
const monitorService = new MonitorService(
130138
jobQueue,
131139
monitorRepository,

server/src/repositories/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ export { default as MongoTeamMembershipRepository } from "@/repositories/team-me
3131
export type { IOrgRepository } from "@/repositories/org/IOrgRepository.js";
3232
export { default as MongoOrgRepository } from "@/repositories/org/MongoOrgRepository.js";
3333

34-
export type { IOrgMembershipRepository } from "@/repositories/org-membership/IOrgMembershopRepository.js";
34+
export type { IOrgMembershipRepository } from "@/repositories/org-membership/IOrgMembershipRepository.js";
3535
export { default as MongoOrgMembershipRepository } from "@/repositories/org-membership/MongoOrgMembershipRepository.js";
3636

3737
export type { IMaintenanceRepository } from "@/repositories/maintenance/IMaintenanceRepository.js";
3838
export { default as MongoMaintenanceRepository } from "@/repositories/maintenance/MongoMaintenanceRepository.js";
39+
40+
export type { INotificationChannelRepository } from "@/repositories/notification-channels/INotificationChannelRepository.js";
41+
export { default as MongoNotificationChannelRepository } from "@/repositories/notification-channels/MongoNotificationChannelRepository.js";
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export interface INotificationChannelRepository {
2+
// create
3+
// single fetch
4+
// collection fetch
5+
// update
6+
// delete
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { INotificationChannelRepository } from "@/repositories/index.js";
2+
3+
class MongoNotificationRepository implements INotificationChannelRepository {}
4+
5+
export default MongoNotificationRepository;

server/src/repositories/org-membership/IOrgMembershopRepository.ts renamed to server/src/repositories/org-membership/IOrgMembershipRepository.ts

File renamed without changes.

server/src/repositories/user/IUserRepository.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export interface IUserRepository {
44
create(userData: Partial<User>): Promise<User>;
55
// single fetch
66
findByEmail: (email: string) => Promise<User | null>;
7+
findByUserId: (userId: string) => Promise<User | null>;
78
// collection fetch
89
// update
910
updateById: (

server/src/repositories/user/MongoUserRepository.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class MongoUserRepository implements IUserRepository {
2828
return this.toEntity(user);
2929
};
3030

31+
findByUserId = async (userId: string) => {
32+
const user = await User.findById(userId);
33+
if (!user) return null;
34+
return this.toEntity(user);
35+
};
36+
3137
updateById = async (userId: string, updateData: Partial<UserEntity>) => {
3238
const result = await User.findOneAndUpdate(
3339
{ _id: userId },

server/src/services/business/MeService.ts

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
import {
2-
User,
3-
Org,
4-
OrgMembership,
5-
Team,
6-
TeamMembership,
7-
Role,
8-
IRole,
9-
} from "@/db/models/index.js";
101
import ApiError from "@/utils/ApiError.js";
112
import type { IEntitlementsProvider } from "@/services/system/EntitlementsService.js";
123
import type { Entitlements } from "@/types/entitlements.js";
134
import type { UserReturnable } from "@/types/domain/index.js";
5+
import type {
6+
IUserRepository,
7+
IOrgRepository,
8+
IOrgMembershipRepository,
9+
ITeamRepository,
10+
ITeamMembershipRepository,
11+
IRoleRepository,
12+
} from "@/repositories/index.js";
1413

1514
export interface IMeService {
1615
me(userId: string): Promise<UserReturnable>;
@@ -26,73 +25,95 @@ const SERVICE_NAME = "MeService";
2625
class MeService implements IMeService {
2726
public SERVICE_NAME = SERVICE_NAME;
2827
private entitlementsProvider: IEntitlementsProvider;
29-
30-
constructor(entitlementsProvider: IEntitlementsProvider) {
28+
private userRepository: IUserRepository;
29+
private orgRepository: IOrgRepository;
30+
private orgMembershipRepository: IOrgMembershipRepository;
31+
private teamRepository: ITeamRepository;
32+
private teamMembershipRepository: ITeamMembershipRepository;
33+
private roleRepository: IRoleRepository;
34+
35+
constructor(
36+
entitlementsProvider: IEntitlementsProvider,
37+
userRepository: IUserRepository,
38+
orgRepository: IOrgRepository,
39+
orgMembershipRepository: IOrgMembershipRepository,
40+
teamRepository: ITeamRepository,
41+
teamMembershipRepository: ITeamMembershipRepository,
42+
roleRepository: IRoleRepository
43+
) {
3144
this.entitlementsProvider = entitlementsProvider;
45+
this.userRepository = userRepository;
46+
this.orgRepository = orgRepository;
47+
this.orgMembershipRepository = orgMembershipRepository;
48+
this.teamRepository = teamRepository;
49+
this.teamMembershipRepository = teamMembershipRepository;
50+
this.roleRepository = roleRepository;
3251
}
3352

3453
me = async (userId: string): Promise<UserReturnable> => {
3554
// Need to get teamIds
36-
const user = await User.findById(userId);
55+
const user = await this.userRepository.findByUserId(userId);
3756
if (!user) {
3857
throw new ApiError("User not found", 404);
3958
}
4059

4160
// Find OrgMembership
42-
const orgMembership = await OrgMembership.findOne({
43-
userId: user._id,
44-
}).lean();
61+
const orgMembership = await this.orgMembershipRepository.findByUserId(
62+
user.id
63+
);
4564
if (!orgMembership) {
4665
throw new ApiError("User is not part of any organization");
4766
}
4867

4968
// Find org and roles
50-
const org = await Org.findById(orgMembership.orgId).lean();
69+
const org = await this.orgRepository.findById(orgMembership.orgId);
5170

5271
if (!org) {
5372
throw new ApiError("Organization not found");
5473
}
5574

56-
const orgRoles = await Role.findById(orgMembership.roleId).lean();
75+
const orgRole = await this.roleRepository.findById(
76+
orgMembership.roleId || "",
77+
org.id
78+
);
5779

5880
// Get teams
59-
const teamMembershipWithRoles = await TeamMembership.find({
60-
userId: user._id,
61-
})
62-
.populate<{ roleId: IRole }>("roleId")
63-
.lean();
81+
const teamMembershipsWithRole =
82+
await this.teamMembershipRepository.findByUserIdWithRole(user.id);
6483

65-
const teamIds = teamMembershipWithRoles.map((tm) => tm.teamId.toString());
84+
if (!teamMembershipsWithRole) {
85+
throw new ApiError("Team memberships not found for user");
86+
}
6687

67-
const teams = await Team.find({ _id: { $in: teamIds } }).select(
68-
"_id, name"
69-
);
88+
const teamIds = teamMembershipsWithRole.map((tm) => tm.teamId);
89+
90+
const teams = await this.teamRepository.findManyById(teamIds);
7091

71-
const teamMap = new Map(teams.map((t) => [t._id.toString(), t]));
72-
const returnableTeams = teamMembershipWithRoles.map((tm) => {
73-
const team = teamMap.get(tm.teamId.toString());
92+
const teamMap = new Map(teams.map((t) => [t.id, t]));
93+
const returnableTeams = teamMembershipsWithRole.map((tm) => {
94+
const team = teamMap.get(tm.teamId);
7495
if (!team) {
7596
throw new ApiError("Team not found for membership");
7697
}
7798
return {
78-
id: team._id.toString(),
99+
id: team.id,
79100
name: team.name,
80-
permissions: tm.roleId?.permissions ?? [],
101+
permissions: tm.role?.permissions ?? [],
81102
};
82103
});
83104

84105
const entitlements: Entitlements =
85-
await this.entitlementsProvider.getForOrg(org._id.toString());
106+
await this.entitlementsProvider.getForOrg(org.id);
86107

87108
const returnableUser: UserReturnable = {
88-
id: user._id.toString(),
109+
id: user.id,
89110
email: user.email,
90111
firstName: user.firstName,
91112
lastName: user.lastName,
92113
org: {
93114
name: org.name,
94115
planKey: org.planKey,
95-
permissions: orgRoles?.permissions || [],
116+
permissions: orgRole?.permissions || [],
96117
},
97118
teams: returnableTeams,
98119
entitlements,

0 commit comments

Comments
 (0)