12 files changed
+111
-120
No files matched your search
Whitespace-only changes.
@@ -1,4 +1,3 @@
|
||||
import TranslationService from "../service/system/translationService.js";
|
||||
import MongoDB from "../db/MongoDB.js";
|
||||
import NetworkService from "../service/infrastructure/networkService.js";
|
||||
import EmailService from "../service/infrastructure/emailService.js";
|
||||
@@ -81,6 +80,7 @@ import {
|
||||
MongoSettingsRepository,
|
||||
MongoNotificationsRepository,
|
||||
MongoIncidentRepository,
|
||||
MongoTeamsRepository,
|
||||
IMonitorsRepository,
|
||||
IChecksRepository,
|
||||
IMonitorStatsRepository,
|
||||
@@ -91,14 +91,13 @@ import {
|
||||
ISettingsRepository,
|
||||
INotificationsRepository,
|
||||
IIncidentsRepository,
|
||||
ITeamsRepository,
|
||||
} from "@/repositories/index.js";
|
||||
import { ILogger } from "@/utils/logger.js";
|
||||
import { EnvConfig } from "@/service/system/settingsService.js";
|
||||
|
||||
export type InitializedServices = {
|
||||
//v1
|
||||
settingsService: any;
|
||||
translationService: any;
|
||||
db: any;
|
||||
networkService: any;
|
||||
emailService: any;
|
||||
@@ -127,6 +126,7 @@ export type InitializedServices = {
|
||||
settingsRepository: ISettingsRepository;
|
||||
notificationsRepository: INotificationsRepository;
|
||||
incidentsRepository: IIncidentsRepository;
|
||||
teamsRepository: ITeamsRepository;
|
||||
};
|
||||
|
||||
export const initializeServices = async ({
|
||||
@@ -138,9 +138,6 @@ export const initializeServices = async ({
|
||||
envSettings: EnvConfig;
|
||||
settingsService: any;
|
||||
}): Promise<InitializedServices> => {
|
||||
const translationService = new TranslationService(logger);
|
||||
await translationService.initialize();
|
||||
|
||||
// Create DB
|
||||
const inviteModule = new InviteModule({ InviteToken, crypto });
|
||||
const statusPageModule = new StatusPageModule({ StatusPage, NormalizeData, AppSettings });
|
||||
@@ -177,6 +174,8 @@ export const initializeServices = async ({
|
||||
const settingsRepository = new MongoSettingsRepository();
|
||||
const notificationsRepository = new MongoNotificationsRepository();
|
||||
const incidentsRepository = new MongoIncidentRepository();
|
||||
const teamsRepository = new MongoTeamsRepository();
|
||||
|
||||
const networkService = new NetworkService({
|
||||
axios,
|
||||
got,
|
||||
@@ -260,6 +259,7 @@ export const initializeServices = async ({
|
||||
invitesRepository,
|
||||
recoveryTokensRepository,
|
||||
settingsRepository,
|
||||
teamsRepository,
|
||||
});
|
||||
|
||||
const diagnosticService = new DiagnosticService();
|
||||
@@ -289,7 +289,6 @@ export const initializeServices = async ({
|
||||
const services = {
|
||||
//v1
|
||||
settingsService,
|
||||
translationService,
|
||||
db,
|
||||
networkService,
|
||||
emailService,
|
||||
@@ -318,6 +317,7 @@ export const initializeServices = async ({
|
||||
settingsRepository,
|
||||
notificationsRepository,
|
||||
incidentsRepository,
|
||||
teamsRepository,
|
||||
};
|
||||
|
||||
return services;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import mongoose from "mongoose";
|
||||
const TeamSchema = mongoose.Schema(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
export default mongoose.model("Team", TeamSchema);
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
import { Schema, model, type Types } from "mongoose";
|
||||
|
||||
import type { Team } from "@/types/index.js";
|
||||
|
||||
type TeamDocumentBase = Omit<Team, "id" | "createdAt" | "updatedAt"> & {};
|
||||
interface TeamDocument extends TeamDocumentBase {
|
||||
_id: Types.ObjectId;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const TeamSchema = new Schema<TeamDocument>(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
const TeamModel = model<TeamDocument>("Team", TeamSchema);
|
||||
|
||||
export type { TeamDocument };
|
||||
export { TeamModel };
|
||||
export default TeamModel;
|
||||
@@ -27,3 +27,6 @@ export { default as NotificationModel } from "@/db/models/Notification.js";
|
||||
|
||||
export * from "@/db/models/Incident.js";
|
||||
export { default as IncidentModel } from "@/db/models/Incident.js";
|
||||
|
||||
export * from "@/db/models/Team.js";
|
||||
export { default as TeamModel } from "@/db/models/Team.js";
|
||||
@@ -27,3 +27,6 @@ export { default as MongoNotificationsRepository } from "@/repositories/notifica
|
||||
|
||||
export * from "@/repositories/incidents/IIncidentsRepository.js";
|
||||
export { default as MongoIncidentRepository } from "@/repositories/incidents/MongoIncidentRepository.js";
|
||||
|
||||
export * from "@/repositories/teams/ITeamsRepository.js";
|
||||
export { default as MongoTeamsRepository } from "@/repositories/teams/MongoTeamsRepository.js";
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Team } from "@/types/index.js";
|
||||
export interface ITeamsRepository {
|
||||
// create
|
||||
create(email: string): Promise<Team>;
|
||||
// fetch
|
||||
// update
|
||||
// delete
|
||||
// other
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Team } from "@/types/index.js";
|
||||
import { TeamDocument, TeamModel } from "@/db/models/index.js";
|
||||
import { ITeamsRepository } from "@/repositories/index.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
class MongoTeamsRepository implements ITeamsRepository {
|
||||
private toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
return value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);
|
||||
};
|
||||
|
||||
private toDateString = (value?: Date | string | null): string => {
|
||||
if (!value) {
|
||||
return new Date(0).toISOString();
|
||||
}
|
||||
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
||||
};
|
||||
|
||||
private toEntity = (doc: TeamDocument): Team => {
|
||||
return {
|
||||
id: this.toStringId(doc._id),
|
||||
email: doc.email,
|
||||
createdAt: this.toDateString(doc.createdAt),
|
||||
updatedAt: this.toDateString(doc.updatedAt),
|
||||
};
|
||||
};
|
||||
|
||||
create = async (email: string) => {
|
||||
const team = await TeamModel.create({ email });
|
||||
return this.toEntity(team);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoTeamsRepository;
|
||||
@@ -1,9 +1,15 @@
|
||||
import { IInvitesRepository, IMonitorsRepository, IRecoveryTokensRepository, IUsersRepository, ISettingsRepository } from "@/repositories/index.js";
|
||||
import Team from "@/db/models/Team.js";
|
||||
import {
|
||||
IInvitesRepository,
|
||||
IMonitorsRepository,
|
||||
IRecoveryTokensRepository,
|
||||
IUsersRepository,
|
||||
ISettingsRepository,
|
||||
ITeamsRepository,
|
||||
} from "@/repositories/index.js";
|
||||
import type { User } from "@/types/index.js";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
import { ISuperSimpleQueue } from "../infrastructure/SuperSimpleQueue/SuperSimpleQueue.js";
|
||||
import { ISuperSimpleQueue } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js";
|
||||
|
||||
const SERVICE_NAME = "userService";
|
||||
|
||||
@@ -21,6 +27,7 @@ class UserService {
|
||||
private invitesRepository: IInvitesRepository;
|
||||
private recoveryTokensRepository: IRecoveryTokensRepository;
|
||||
private settingsRepository: ISettingsRepository;
|
||||
private teamsRepository: ITeamsRepository;
|
||||
|
||||
constructor({
|
||||
crypto,
|
||||
@@ -34,6 +41,7 @@ class UserService {
|
||||
invitesRepository,
|
||||
recoveryTokensRepository,
|
||||
settingsRepository,
|
||||
teamsRepository,
|
||||
}: {
|
||||
crypto: any;
|
||||
emailService: any;
|
||||
@@ -47,6 +55,7 @@ class UserService {
|
||||
invitesRepository: IInvitesRepository;
|
||||
recoveryTokensRepository: IRecoveryTokensRepository;
|
||||
settingsRepository: ISettingsRepository;
|
||||
teamsRepository: ITeamsRepository;
|
||||
}) {
|
||||
this.emailService = emailService;
|
||||
this.settingsService = settingsService;
|
||||
@@ -59,6 +68,7 @@ class UserService {
|
||||
this.invitesRepository = invitesRepository;
|
||||
this.recoveryTokensRepository = recoveryTokensRepository;
|
||||
this.settingsRepository = settingsRepository;
|
||||
this.teamsRepository = teamsRepository;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
@@ -85,10 +95,11 @@ class UserService {
|
||||
const jwtSecret = this.crypto.randomBytes(64).toString("hex");
|
||||
await this.settingsRepository.update({ jwtSecret });
|
||||
// Create a new team
|
||||
const team = new Team({
|
||||
email: user.email,
|
||||
});
|
||||
user.teamId = team._id;
|
||||
if (!user.email) {
|
||||
throw new AppError({ message: "Email is required for first user", service: SERVICE_NAME, method: "registerUser", status: 400 });
|
||||
}
|
||||
const team = await this.teamsRepository.create(user.email);
|
||||
user.teamId = team.id;
|
||||
}
|
||||
|
||||
const newUser = await this.usersRepository.create({ ...user }, file);
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
class TranslationService {
|
||||
static SERVICE_NAME = "TranslationService";
|
||||
constructor(logger) {
|
||||
this.logger = logger;
|
||||
this.translations = {};
|
||||
this._language = "en";
|
||||
this.localesDir = path.join(process.cwd(), "src/locales");
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return TranslationService.SERVICE_NAME;
|
||||
}
|
||||
|
||||
setLanguage(language) {
|
||||
this._language = language;
|
||||
}
|
||||
|
||||
get language() {
|
||||
return this._language;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
try {
|
||||
await this.loadFromFiles();
|
||||
} catch (error) {
|
||||
this.logger.error({
|
||||
message: error.message,
|
||||
service: "TranslationService",
|
||||
method: "initialize",
|
||||
stack: error.stack,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async loadFromFiles() {
|
||||
try {
|
||||
if (!fs.existsSync(this.localesDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(this.localesDir).filter((file) => file.endsWith(".json"));
|
||||
|
||||
if (files.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
const language = file.replace(".json", "");
|
||||
const filePath = path.join(this.localesDir, file);
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
this.translations[language] = JSON.parse(content);
|
||||
}
|
||||
|
||||
this.logger.info({
|
||||
message: "Translations loaded from files successfully",
|
||||
service: "TranslationService",
|
||||
method: "loadFromFiles",
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.logger.error({
|
||||
message: error.message,
|
||||
service: "TranslationService",
|
||||
method: "loadFromFiles",
|
||||
stack: error.stack,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getTranslation(key) {
|
||||
let language = this._language;
|
||||
|
||||
try {
|
||||
return this.translations[language]?.[key] || this.translations["en"]?.[key] || key;
|
||||
} catch (error) {
|
||||
this.logger.error({
|
||||
message: error.message,
|
||||
service: "TranslationService",
|
||||
method: "getTranslation",
|
||||
stack: error.stack,
|
||||
});
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default TranslationService;
|
||||
@@ -11,3 +11,4 @@ export * from "@/types/notification.js";
|
||||
export * from "@/types/alert.js";
|
||||
export * from "@/types/incident.js";
|
||||
export * from "@/types/email.js";
|
||||
export * from "@/types/team.js";
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface Team {
|
||||
id: string;
|
||||
email: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
Reference in new issue
Block a user