refactor auth service
This commit is contained in:
1 parent
3611aee468
commit
a3e24b5420
16 files changed
+180
-32
No files matched your search
@@ -43,6 +43,7 @@ import {
|
||||
MongoTeamRepository,
|
||||
MongoInviteRepository,
|
||||
MongoTeamMembershipRepository,
|
||||
MongoOrgRepository,
|
||||
} from "@/repositories/index.js";
|
||||
|
||||
export const initServices = async () => {
|
||||
@@ -55,6 +56,7 @@ export const initServices = async () => {
|
||||
const teamRepository = new MongoTeamRepository();
|
||||
const inviteRepository = new MongoInviteRepository();
|
||||
const teamMembershipRepository = new MongoTeamMembershipRepository();
|
||||
const mongoOrgRepository = new MongoOrgRepository();
|
||||
|
||||
const checkService = new CheckService(checksRepository, monitorRepository);
|
||||
const inviteService = new InviteService(
|
||||
@@ -108,7 +110,11 @@ export const initServices = async () => {
|
||||
const authService = new AuthService(
|
||||
jobQueue,
|
||||
entitlementsProvider,
|
||||
monitorRepository
|
||||
monitorRepository,
|
||||
userRepository,
|
||||
mongoOrgRepository,
|
||||
teamRepository,
|
||||
teamMembershipRepository
|
||||
);
|
||||
const meService = new MeService(entitlementsProvider);
|
||||
const monitorService = new MonitorService(
|
||||
|
||||
@@ -27,3 +27,9 @@ export { default as MongoTeamRepository } from "@/repositories/team/MongoTeamRep
|
||||
|
||||
export type { ITeamMembershipRepository } from "@/repositories/team-membership/ITeamMembershipRepository.js";
|
||||
export { default as MongoTeamMembershipRepository } from "@/repositories/team-membership/MongoTeamMembershipRepository.js";
|
||||
|
||||
export type { IOrgRepository } from "@/repositories/org/IOrgRepository.js";
|
||||
export { default as MongoOrgRepository } from "@/repositories/org/MongoOrgRepository.js";
|
||||
|
||||
export type { IOrgMembershipRepository } from "@/repositories/org-membership/IOrgMembershopRepository.js";
|
||||
export { default as MongoOrgMembershipRepository } from "@/repositories/org-membership/MongoOrgMembershipRepository.js";
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface IOrgMembershipRepository {
|
||||
// create
|
||||
// single fetch
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { type IOrgMembership, OrgMembership } from "@/db/models/index.js";
|
||||
import { IOrgMembershipRepository } from "@/repositories/index.js";
|
||||
import { OrgMembership as OrgMembershipEntity } from "@/types/domain/index.js";
|
||||
|
||||
class MongoOrgMembershipRepository implements IOrgMembershipRepository {
|
||||
private toEntity = (doc: IOrgMembership): OrgMembershipEntity => {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
orgId: doc.orgId.toString(),
|
||||
userId: doc.userId.toString(),
|
||||
roleId: doc.roleId?.toString(),
|
||||
role: doc.roleId?.toString() || "",
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoOrgMembershipRepository;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Org } from "@/types/domain/index.js";
|
||||
|
||||
export interface IOrgRepository {
|
||||
// create
|
||||
create(orgData: Partial<Org>): Promise<Org>;
|
||||
// single fetch
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { type IOrg, Org } from "@/db/models/index.js";
|
||||
import type { IOrgRepository } from "@/repositories/index.js";
|
||||
import { Org as OrgEntity } from "@/types/domain/index.js";
|
||||
|
||||
class MongoOrgRepository implements IOrgRepository {
|
||||
toEntity = (doc: IOrg): OrgEntity => {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
name: doc.name.toString(),
|
||||
ownerId: doc.ownerId.toString(),
|
||||
planKey: doc.planKey,
|
||||
|
||||
// Billing
|
||||
billingCustomerId: doc.billingCustomerId,
|
||||
subscriptionId: doc.subscriptionId,
|
||||
priceId: doc.priceId,
|
||||
priceIds: doc.priceIds,
|
||||
subscriptionStatus: doc.subscriptionStatus,
|
||||
currentPeriodStart: doc.currentPeriodStart,
|
||||
currentPeriodEnd: doc.currentPeriodEnd,
|
||||
|
||||
entitlements: doc.entitlements,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
create = async (orgData: Partial<OrgEntity>) => {
|
||||
const org = await Org.create(orgData);
|
||||
return this.toEntity(org);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoOrgRepository;
|
||||
@@ -2,6 +2,7 @@ import { Role } from "@/types/domain/index.js";
|
||||
|
||||
export interface IRoleRepository {
|
||||
// create
|
||||
createMany(rolesData: Role[]): Promise<Role[]>;
|
||||
// single fetch
|
||||
findById(roleId: string, orgId: string): Promise<Role | null>;
|
||||
// collection fetch
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Types } from "mongoose";
|
||||
import type { IRoleRepository } from "./IRoleRepository.js";
|
||||
import { Role } from "@/db/models/index.js";
|
||||
import type { IRole } from "@/db/models/index.js";
|
||||
import { Role as RoleEntity } from "@/types/domain/index.js";
|
||||
import type { Role as RoleEntity } from "@/types/domain/index.js";
|
||||
|
||||
class MongoRoleRepository implements IRoleRepository {
|
||||
private toEntity = (doc: IRole): RoleEntity => {
|
||||
return {
|
||||
@@ -14,11 +16,37 @@ class MongoRoleRepository implements IRoleRepository {
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
createMany = async (rolesData: RoleEntity[]): Promise<RoleEntity[]> => {
|
||||
const docs = rolesData.map((role) => ({
|
||||
...role,
|
||||
organizationId: role.organizationId
|
||||
? new Types.ObjectId(role.organizationId)
|
||||
: undefined,
|
||||
}));
|
||||
|
||||
const insertedRoles = await Role.insertMany(docs);
|
||||
return insertedRoles.map((r) => {
|
||||
return this.toEntity({
|
||||
_id: r._id,
|
||||
organizationId: r.organizationId || new Types.ObjectId(),
|
||||
name: r.name,
|
||||
scope: r.scope,
|
||||
permissions: r.permissions,
|
||||
createdAt: r.createdAt,
|
||||
updatedAt: r.updatedAt,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
findById = async (roleId: string, orgId: string) => {
|
||||
const role = await Role.findOne({
|
||||
_id: roleId,
|
||||
organizationId: orgId,
|
||||
});
|
||||
})
|
||||
.lean<IRole>()
|
||||
.exec();
|
||||
|
||||
if (!role) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { TeamMembership } from "@/types/domain/index.js";
|
||||
export interface ITeamMembershipRepository {
|
||||
// create
|
||||
create(membership: Partial<TeamMembership>): Promise<TeamMembership>;
|
||||
// single fetch
|
||||
findByUserId(userId: string, teamId: string): Promise<TeamMembership | null>;
|
||||
// collection fetch
|
||||
|
||||
@@ -13,6 +13,11 @@ class MongoTeamMembershipRepository implements ITeamMembershipRepository {
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
create = async (membership: Partial<TeamMembershipEntity>) => {
|
||||
const created = await TeamMembership.create(membership);
|
||||
return this.toEntity(created);
|
||||
};
|
||||
|
||||
findByUserId = async (userId: string, teamId: string) => {
|
||||
const membership = await TeamMembership.findOne({
|
||||
userId,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Team } from "@/types/domain/index.js";
|
||||
|
||||
export interface ITeamRepository {
|
||||
// create
|
||||
create(team: Partial<Team>): Promise<Team>;
|
||||
// single fetch
|
||||
findById(teamId: string, orgId: string): Promise<Team | null>;
|
||||
// collection fetch
|
||||
|
||||
@@ -14,6 +14,11 @@ class MongoTeamRepository implements ITeamRepository {
|
||||
};
|
||||
};
|
||||
|
||||
create = async (team: Partial<TeamEntity>) => {
|
||||
const created = await Team.create(team);
|
||||
return this.toEntity(created);
|
||||
};
|
||||
|
||||
findById = async (teamId: string, orgId: string) => {
|
||||
const team = await Team.findOne({
|
||||
_id: teamId,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { User } from "@/types/domain/index.js";
|
||||
export interface IUserRepository {
|
||||
// create
|
||||
create(userData: Partial<User>): Promise<User>;
|
||||
// single fetch
|
||||
findByEmail: (email: string) => Promise<User | null>;
|
||||
// collection fetch
|
||||
|
||||
@@ -17,6 +17,11 @@ class MongoUserRepository implements IUserRepository {
|
||||
};
|
||||
};
|
||||
|
||||
create = async (userData: Partial<UserEntity>) => {
|
||||
const user = await User.create(userData);
|
||||
return this.toEntity(user);
|
||||
};
|
||||
|
||||
findByEmail = async (email: string) => {
|
||||
const user = await User.findOne({ email });
|
||||
if (!user) return null;
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
ITokenizedUser,
|
||||
Check,
|
||||
NotificationChannel,
|
||||
IInvite,
|
||||
} from "@/db/models/index.js";
|
||||
import { Types } from "mongoose";
|
||||
import ApiError from "@/utils/ApiError.js";
|
||||
@@ -23,7 +22,13 @@ import { Plans } from "@/types/entitlements.js";
|
||||
import { PERMISSIONS } from "@/types/permissions.js";
|
||||
import type { Entitlements } from "@/types/entitlements.js";
|
||||
import type { IEntitlementsProvider } from "@/services/system/EntitlementsService.js";
|
||||
import type { IMonitorRepository } from "@/repositories/index.js";
|
||||
import type {
|
||||
IMonitorRepository,
|
||||
IUserRepository,
|
||||
IOrgRepository,
|
||||
ITeamRepository,
|
||||
ITeamMembershipRepository,
|
||||
} from "@/repositories/index.js";
|
||||
import type { Invite } from "@/types/domain/index.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
@@ -71,15 +76,28 @@ class AuthService implements IAuthService {
|
||||
private jobQueue: IJobQueue;
|
||||
private entitlementsProvider: IEntitlementsProvider;
|
||||
private monitorRepository: IMonitorRepository;
|
||||
private userRepository: IUserRepository;
|
||||
private orgRepository: IOrgRepository;
|
||||
private teamRepository: ITeamRepository;
|
||||
private teamMembershipRepository: ITeamMembershipRepository;
|
||||
|
||||
constructor(
|
||||
jobQueue: IJobQueue,
|
||||
entitlementsProvider: IEntitlementsProvider,
|
||||
monitorRepository: IMonitorRepository
|
||||
monitorRepository: IMonitorRepository,
|
||||
userRepository: IUserRepository,
|
||||
orgRepository: IOrgRepository,
|
||||
teamRepository: ITeamRepository,
|
||||
teamMembershipRepository: ITeamMembershipRepository
|
||||
) {
|
||||
this.SERVICE_NAME = SERVICE_NAME;
|
||||
this.jobQueue = jobQueue;
|
||||
this.entitlementsProvider = entitlementsProvider;
|
||||
this.monitorRepository = monitorRepository;
|
||||
this.userRepository = userRepository;
|
||||
this.orgRepository = orgRepository;
|
||||
this.teamRepository = teamRepository;
|
||||
this.teamMembershipRepository = teamMembershipRepository;
|
||||
}
|
||||
|
||||
async register(signupData: RegisterData) {
|
||||
@@ -102,26 +120,27 @@ class AuthService implements IAuthService {
|
||||
passwordHash,
|
||||
};
|
||||
|
||||
const user = await User.create(newUserData);
|
||||
created.user = user._id;
|
||||
const user = await this.userRepository.create(newUserData);
|
||||
created.user = user.id;
|
||||
|
||||
const org = await Org.create({
|
||||
const org = await this.orgRepository.create({
|
||||
name: `${user.firstName}'s Org`,
|
||||
ownerId: user._id,
|
||||
ownerId: user.id,
|
||||
planKey: "free",
|
||||
entitlements: Plans["free"],
|
||||
});
|
||||
created.org = org._id;
|
||||
|
||||
created.org = org.id;
|
||||
|
||||
const roles = await Role.insertMany([
|
||||
{
|
||||
organizationId: org._id,
|
||||
organizationId: org.id,
|
||||
name: "Org Admin",
|
||||
scope: "organization",
|
||||
permissions: ["*"],
|
||||
},
|
||||
{
|
||||
organizationId: org._id,
|
||||
organizationId: org.id,
|
||||
name: "Org Member",
|
||||
scope: "organization",
|
||||
permissions: [
|
||||
@@ -142,7 +161,7 @@ class AuthService implements IAuthService {
|
||||
],
|
||||
},
|
||||
{
|
||||
organizationId: org._id,
|
||||
organizationId: org.id,
|
||||
name: "Team Admin",
|
||||
permissions: [
|
||||
PERMISSIONS.monitors.all,
|
||||
@@ -153,7 +172,7 @@ class AuthService implements IAuthService {
|
||||
scope: "team",
|
||||
},
|
||||
{
|
||||
organizationId: org._id,
|
||||
organizationId: org.id,
|
||||
name: "Team Member",
|
||||
permissions: [
|
||||
PERMISSIONS.monitors.read,
|
||||
@@ -168,45 +187,45 @@ class AuthService implements IAuthService {
|
||||
created.roles = roles.map((r) => r._id);
|
||||
|
||||
const membership = await OrgMembership.create({
|
||||
userId: user._id,
|
||||
orgId: org._id,
|
||||
userId: user.id,
|
||||
orgId: org.id,
|
||||
roleId: roles[0]?._id,
|
||||
});
|
||||
created.orgMembership = membership._id;
|
||||
|
||||
const team = await Team.create({
|
||||
const team = await this.teamRepository.create({
|
||||
name: "Default Team",
|
||||
orgId: org._id,
|
||||
orgId: org.id,
|
||||
description: "This is your default team",
|
||||
isSystem: true,
|
||||
});
|
||||
created.team = team._id;
|
||||
created.team = team.id;
|
||||
|
||||
const teamMembership = await TeamMembership.create({
|
||||
orgId: org._id,
|
||||
userId: user._id,
|
||||
teamId: team._id,
|
||||
roleId: roles[2]?._id,
|
||||
const teamMembership = await this.teamMembershipRepository.create({
|
||||
orgId: org.id,
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
roleId: roles[2]?._id.toString(),
|
||||
});
|
||||
created.teamMembership = teamMembership._id;
|
||||
created.teamMembership = teamMembership.id;
|
||||
|
||||
const tokenizedUser: ITokenizedUser = {
|
||||
sub: user._id.toString(),
|
||||
sub: user.id,
|
||||
email: user.email,
|
||||
orgId: org._id.toString(),
|
||||
orgId: org.id,
|
||||
};
|
||||
|
||||
const returnableTeam = {
|
||||
id: team._id.toString(),
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
permissions: roles[2]?.permissions || [],
|
||||
};
|
||||
|
||||
const entitlements: Entitlements =
|
||||
await this.entitlementsProvider.getForOrg(org._id.toString());
|
||||
await this.entitlementsProvider.getForOrg(org.id);
|
||||
|
||||
const returnableUser: IUserReturnable = {
|
||||
id: user._id.toString(),
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface OrgMembership extends Document {
|
||||
export interface OrgMembership {
|
||||
id: string;
|
||||
orgId: string;
|
||||
userId: string;
|
||||
|
||||
Reference in new issue
Block a user