Merge pull request #3433 from bluewave-labs/fix/controllers
fix/controllers
This commit is contained in:
26 files changed
+168
-48
No files matched your search
@@ -23,7 +23,24 @@ import { IUserService } from "@/service/index.js";
|
||||
|
||||
const SERVICE_NAME = "authController";
|
||||
|
||||
class AuthController {
|
||||
export interface IAuthController {
|
||||
registerUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
createUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
loginUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
editUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
checkSuperadminExists(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
requestRecovery(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
validateRecovery(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
resetPassword(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
deleteUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
deleteUserById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
getAllUsers(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
getUserById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
editUserById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
editUserPasswordById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
}
|
||||
|
||||
class AuthController implements IAuthController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private userService: IUserService;
|
||||
|
||||
@@ -12,7 +12,16 @@ import { requireTeamId } from "@/controllers/controllerUtils.js";
|
||||
|
||||
const SERVICE_NAME = "checkController";
|
||||
|
||||
class CheckController {
|
||||
export interface ICheckController {
|
||||
serviceName: string;
|
||||
getChecksByMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getChecksByTeam: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getChecksSummaryByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
deleteChecks: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
deleteChecksByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
|
||||
class CheckController implements ICheckController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private checkService: ICheckService;
|
||||
|
||||
@@ -2,7 +2,12 @@ import { IDiagnosticService } from "@/service/index.js";
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
|
||||
const SERVICE_NAME = "diagnosticController";
|
||||
class DiagnosticController {
|
||||
|
||||
export interface IDiagnosticController {
|
||||
getSystemStats: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
|
||||
class DiagnosticController implements IDiagnosticController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private diagnosticService: IDiagnosticService;
|
||||
|
||||
@@ -6,7 +6,10 @@ import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
const SERVICE_NAME = "geoCheckController";
|
||||
|
||||
class GeoCheckController {
|
||||
export interface IGeoCheckController {
|
||||
getGeoChecksByMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
class GeoCheckController implements IGeoCheckController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private geoChecksService: IGeoChecksService;
|
||||
|
||||
@@ -5,7 +5,14 @@ import { IIncidentService } from "@/service/index.js";
|
||||
import { getIncidentsByTeamQueryValidation, getIncidentSummaryQueryValidation } from "@/validation/incidentValidation.js";
|
||||
|
||||
const SERVICE_NAME = "IncidentController";
|
||||
class IncidentController {
|
||||
|
||||
export interface IIncidentController {
|
||||
getIncidentsByTeam: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getIncidentSummary: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getIncidentById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
resolveIncidentManually: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
class IncidentController implements IIncidentController {
|
||||
private incidentService: IIncidentService;
|
||||
constructor(incidentService: IIncidentService) {
|
||||
this.incidentService = incidentService;
|
||||
|
||||
@@ -4,7 +4,13 @@ import { requireFirstName, requireTeamId, requireUserRoles } from "@/controllers
|
||||
import { IInviteService } from "@/service/index.js";
|
||||
const SERVICE_NAME = "inviteController";
|
||||
|
||||
class InviteController {
|
||||
export interface IInviteController {
|
||||
getInviteToken: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
sendInviteEmail: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
verifyInviteToken: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
|
||||
class InviteController implements IInviteController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private inviteService: IInviteService;
|
||||
constructor(inviteService: IInviteService) {
|
||||
|
||||
@@ -3,6 +3,10 @@ import { Request, Response, NextFunction } from "express";
|
||||
|
||||
const SERVICE_NAME = "LogController";
|
||||
|
||||
export interface ILogController {
|
||||
getLogs: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
||||
}
|
||||
|
||||
class LogController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private logger: ILogger;
|
||||
|
||||
@@ -11,7 +11,15 @@ import {
|
||||
import { requireTeamId } from "@/controllers/controllerUtils.js";
|
||||
import { IMaintenanceWindowService } from "@/service/index.js";
|
||||
|
||||
class MaintenanceWindowController {
|
||||
export interface IMaintenanceWindowController {
|
||||
createMaintenanceWindows: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getMaintenanceWindowById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getMaintenanceWindowsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getMaintenanceWindowsByMonitorId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
deleteMaintenanceWindow: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
editMaintenanceWindow: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
class MaintenanceWindowController implements IMaintenanceWindowController {
|
||||
private maintenanceWindowService: IMaintenanceWindowService;
|
||||
constructor(maintenanceWindowService: IMaintenanceWindowService) {
|
||||
this.maintenanceWindowService = maintenanceWindowService;
|
||||
|
||||
@@ -16,11 +16,32 @@ import {
|
||||
importMonitorsBodyValidation,
|
||||
} from "@/validation/monitorValidation.js";
|
||||
import sslChecker from "ssl-checker";
|
||||
import { fetchMonitorCertificate, requireTeamId, requireUserId } from "./controllerUtils.js";
|
||||
import { fetchMonitorCertificate, requireTeamId, requireUserId } from "@/controllers/controllerUtils.js";
|
||||
import { IMonitorService } from "@/service/index.js";
|
||||
|
||||
const SERVICE_NAME = "monitorController";
|
||||
class MonitorController {
|
||||
|
||||
export interface IMonitorController {
|
||||
getMonitorCertificate: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getUptimeDetailsById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getHardwareDetailsById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getPageSpeedDetailsById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getGeoChecksByMonitorId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getMonitorById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
createMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
importMonitorsFromJSON: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
deleteMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
deleteAllMonitors: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
editMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
pauseMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
addDemoMonitors: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getMonitorsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getMonitorsWithChecksByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
exportMonitorsToJSON: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getAllGames: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getGroupsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
class MonitorController implements IMonitorController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private monitorService: IMonitorService;
|
||||
|
||||
@@ -15,7 +15,16 @@ import { requireTeamId, requireUserId } from "./controllerUtils.js";
|
||||
|
||||
const SERVICE_NAME = "NotificationController";
|
||||
|
||||
class NotificationController {
|
||||
export interface INotificationController {
|
||||
testNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
createNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getNotificationsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
deleteNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
getNotificationById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
editNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
testAllNotifications: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;
|
||||
}
|
||||
class NotificationController implements INotificationController {
|
||||
private notificationsService: INotificationsService;
|
||||
private monitorsRepository: IMonitorsRepository;
|
||||
constructor(notificationsService: INotificationsService, monitorsRepository: IMonitorsRepository) {
|
||||
|
||||
@@ -3,7 +3,14 @@ import { Request, Response, NextFunction } from "express";
|
||||
|
||||
const SERVICE_NAME = "JobQueueController";
|
||||
|
||||
class JobQueueController {
|
||||
export interface IJobQueueController {
|
||||
getMetrics(req: Request, res: Response, next: NextFunction): Promise<void>;
|
||||
getJobs(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
getAllMetrics(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
flushQueue(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
}
|
||||
|
||||
class JobQueueController implements IJobQueueController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private jobQueue: ISuperSimpleQueue;
|
||||
constructor(jobQueue: ISuperSimpleQueue) {
|
||||
|
||||
@@ -6,7 +6,14 @@ import { IEmailService, ISettingsService } from "@/service/index.js";
|
||||
|
||||
const SERVICE_NAME = "SettingsController";
|
||||
|
||||
class SettingsController {
|
||||
export interface ISettingsController {
|
||||
serviceName: string;
|
||||
getAppSettings(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
updateAppSettings(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
sendTestEmail(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
}
|
||||
|
||||
class SettingsController implements ISettingsController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private settingsService: ISettingsService;
|
||||
private emailService: IEmailService;
|
||||
|
||||
@@ -15,7 +15,16 @@ import { NormalizeData } from "@/utils/dataUtils.js";
|
||||
|
||||
const SERVICE_NAME = "statusPageController";
|
||||
|
||||
class StatusPageController {
|
||||
export interface IStatusPageController {
|
||||
readonly serviceName: string;
|
||||
createStatusPage(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
updateStatusPage(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
getStatusPageByUrl(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
getStatusPagesByTeamId(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
deleteStatusPage(req: Request, res: Response, next: NextFunction): Promise<Response | void>;
|
||||
}
|
||||
|
||||
class StatusPageController implements IStatusPageController {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
private statusPageService: IStatusPageService;
|
||||
private monitorsRepository: IMonitorsRepository;
|
||||
@@ -66,7 +75,7 @@ class StatusPageController {
|
||||
if (statusPage === null) {
|
||||
throw new AppError({ message: "Status page not found", status: 404 });
|
||||
}
|
||||
return res.status(200).json({
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
msg: "Status page updated successfully",
|
||||
data: statusPage,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Router, RequestHandler } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import multer from "multer";
|
||||
import { IAuthController } from "@/controllers/authController.js";
|
||||
|
||||
const upload = multer();
|
||||
|
||||
class AuthRoutes {
|
||||
private router: Router;
|
||||
private authController: any;
|
||||
private authController: IAuthController;
|
||||
|
||||
constructor(authController: any, verifyJWT: RequestHandler) {
|
||||
constructor(authController: IAuthController, verifyJWT: RequestHandler) {
|
||||
this.router = Router();
|
||||
this.authController = authController;
|
||||
this.initRoutes(verifyJWT);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Router } from "express";
|
||||
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { ICheckController } from "@/controllers/checkController.js";
|
||||
|
||||
class CheckRoutes {
|
||||
private router: Router;
|
||||
private checkController: any;
|
||||
private checkController: ICheckController;
|
||||
|
||||
constructor(checkController: any) {
|
||||
constructor(checkController: ICheckController) {
|
||||
this.router = Router();
|
||||
this.checkController = checkController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { RequestHandler, Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { IDiagnosticController } from "@/controllers/diagnosticController.js";
|
||||
|
||||
class DiagnosticRoutes {
|
||||
private router: Router;
|
||||
private diagnosticController: any;
|
||||
private diagnosticController: IDiagnosticController;
|
||||
|
||||
constructor(diagnosticController: any, verifyJWT: RequestHandler) {
|
||||
constructor(diagnosticController: IDiagnosticController, verifyJWT: RequestHandler) {
|
||||
this.router = Router();
|
||||
this.diagnosticController = diagnosticController;
|
||||
this.initRoutes(verifyJWT);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { IGeoCheckController } from "@/controllers/geoCheckController.js";
|
||||
import { Router } from "express";
|
||||
|
||||
class GeoCheckRoutes {
|
||||
private router: Router;
|
||||
private geoCheckController: any;
|
||||
private geoCheckController: IGeoCheckController;
|
||||
|
||||
constructor(geoCheckController: any) {
|
||||
constructor(geoCheckController: IGeoCheckController) {
|
||||
this.router = Router();
|
||||
this.geoCheckController = geoCheckController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { IIncidentController } from "@/controllers/incidentController.js";
|
||||
|
||||
class IncidentRoutes {
|
||||
private router: Router;
|
||||
private incidentController: any;
|
||||
private incidentController: IIncidentController;
|
||||
|
||||
constructor(incidentController: any) {
|
||||
constructor(incidentController: IIncidentController) {
|
||||
this.router = Router();
|
||||
this.incidentController = incidentController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { RequestHandler, Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { IInviteController } from "@/controllers/inviteController.js";
|
||||
|
||||
class InviteRoutes {
|
||||
private router: Router;
|
||||
private inviteController: any;
|
||||
private inviteController: IInviteController;
|
||||
|
||||
constructor(inviteController: any, verifyJWT: RequestHandler) {
|
||||
constructor(inviteController: IInviteController, verifyJWT: RequestHandler) {
|
||||
this.router = Router();
|
||||
this.inviteController = inviteController;
|
||||
this.initRoutes(verifyJWT);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { isAllowed } from "@/middleware/isAllowed.js";
|
||||
import { ILogController } from "@/controllers/logController.js";
|
||||
class LogRoutes {
|
||||
private router: Router;
|
||||
private logController: any;
|
||||
private logController: ILogController;
|
||||
|
||||
constructor(logController: any) {
|
||||
constructor(logController: ILogController) {
|
||||
this.router = Router();
|
||||
this.logController = logController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { IMaintenanceWindowController } from "@/controllers/maintenanceWindowController.js";
|
||||
import { Router } from "express";
|
||||
|
||||
class MaintenanceWindowRoutes {
|
||||
private router: Router;
|
||||
private mwController: any;
|
||||
private mwController: IMaintenanceWindowController;
|
||||
|
||||
constructor(maintenanceWindowController: any) {
|
||||
constructor(maintenanceWindowController: IMaintenanceWindowController) {
|
||||
this.router = Router();
|
||||
this.mwController = maintenanceWindowController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { Router } from "express";
|
||||
import { isAllowed } from "@/middleware/isAllowed.js";
|
||||
import multer from "multer";
|
||||
import { fetchMonitorCertificate } from "@/controllers/controllerUtils.js";
|
||||
const upload = multer({
|
||||
storage: multer.memoryStorage(), // Store file in memory as Buffer
|
||||
});
|
||||
import { IMonitorController } from "@/controllers/monitorController.js";
|
||||
|
||||
class MonitorRoutes {
|
||||
private router: Router;
|
||||
private monitorController: any;
|
||||
constructor(monitorController: any) {
|
||||
private monitorController: IMonitorController;
|
||||
constructor(monitorController: IMonitorController) {
|
||||
this.router = Router();
|
||||
this.monitorController = monitorController;
|
||||
this.initRoutes();
|
||||
@@ -38,7 +34,7 @@ class MonitorRoutes {
|
||||
|
||||
// Util routes
|
||||
this.router.get("/certificate/:monitorId", (req, res, next) => {
|
||||
this.monitorController.getMonitorCertificate(req, res, next, fetchMonitorCertificate);
|
||||
this.monitorController.getMonitorCertificate(req, res, next);
|
||||
});
|
||||
|
||||
// General monitor CRUD routes
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { INotificationController } from "@/controllers/notificationController.js";
|
||||
import { Router } from "express";
|
||||
class NotificationRoutes {
|
||||
private router: Router;
|
||||
private notificationController: any;
|
||||
private notificationController: INotificationController;
|
||||
|
||||
constructor(notificationController: any) {
|
||||
constructor(notificationController: INotificationController) {
|
||||
this.router = Router();
|
||||
this.notificationController = notificationController;
|
||||
this.initializeRoutes();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { isAllowed } from "@/middleware/isAllowed.js";
|
||||
import { IJobQueueController } from "@/controllers/queueController.js";
|
||||
class QueueRoutes {
|
||||
private router: Router;
|
||||
private queueController: any;
|
||||
private queueController: IJobQueueController;
|
||||
|
||||
constructor(queueController: any) {
|
||||
constructor(queueController: IJobQueueController) {
|
||||
this.router = Router();
|
||||
this.queueController = queueController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import { ISettingsController } from "@/controllers/settingsController.js";
|
||||
|
||||
class SettingsRoutes {
|
||||
private router: Router;
|
||||
private settingsController: any;
|
||||
private settingsController: ISettingsController;
|
||||
|
||||
constructor(settingsController: any) {
|
||||
constructor(settingsController: ISettingsController) {
|
||||
this.router = Router();
|
||||
this.settingsController = settingsController;
|
||||
this.initRoutes();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { IStatusPageController } from "@/controllers/statusPageController.js";
|
||||
import { RequestHandler, Router } from "express";
|
||||
import multer from "multer";
|
||||
const upload = multer();
|
||||
|
||||
class StatusPageRoutes {
|
||||
private router: Router;
|
||||
private statusPageController: any;
|
||||
private statusPageController: IStatusPageController;
|
||||
|
||||
constructor(statusPageController: any, verifyJWT: RequestHandler, verifyStatusPageAccess: RequestHandler) {
|
||||
constructor(statusPageController: IStatusPageController, verifyJWT: RequestHandler, verifyStatusPageAccess: RequestHandler) {
|
||||
this.router = Router();
|
||||
this.statusPageController = statusPageController;
|
||||
this.initRoutes(verifyJWT, verifyStatusPageAccess);
|
||||
|
||||
Reference in new issue
Block a user