diff --git a/App/FeatureSet/BaseAPI/Index.ts b/App/FeatureSet/BaseAPI/Index.ts index 12876e9daa..d8ac3410c8 100644 --- a/App/FeatureSet/BaseAPI/Index.ts +++ b/App/FeatureSet/BaseAPI/Index.ts @@ -286,6 +286,16 @@ import WorkflowService, { import WorkflowVariableService, { Service as WorkflowVariableServiceType, } from "CommonServer/Services/WorkflowVariableService"; + +import ProbeOwnerTeamService, { + Service as ProbeOwnerTeamServiceType, +} from "CommonServer/Services/ProbeOwnerTeamService"; + +import ProbeOwnerUserService, { + Service as ProbeOwnerUserServiceType, +} from "CommonServer/Services/ProbeOwnerUserService"; + + import FeatureSet from "CommonServer/Types/FeatureSet"; import Express, { ExpressApplication } from "CommonServer/Utils/Express"; import Log from "Model/AnalyticsModels/Log"; @@ -377,6 +387,8 @@ import UserOnCallLog from "Model/Models/UserOnCallLog"; import Workflow from "Model/Models/Workflow"; import WorkflowLog from "Model/Models/WorkflowLog"; import WorkflowVariable from "Model/Models/WorkflowVariable"; +import ProbeOwnerTeam from "Model/Models/ProbeOwnerTeam"; +import ProbeOwnerUser from "Model/Models/ProbeOwnerUser"; const BaseAPIFeatureSet: FeatureSet = { init: async (): Promise => { @@ -448,6 +460,22 @@ const BaseAPIFeatureSet: FeatureSet = { ).getRouter(), ); + app.use( + `/${APP_NAME.toLocaleLowerCase()}`, + new BaseAPI( + ProbeOwnerUser, + ProbeOwnerUserService, + ).getRouter(), + ); + + app.use( + `/${APP_NAME.toLocaleLowerCase()}`, + new BaseAPI( + ProbeOwnerTeam, + ProbeOwnerTeamService, + ).getRouter(), + ); + app.use( `/${APP_NAME.toLocaleLowerCase()}`, new BaseAPI( diff --git a/App/FeatureSet/Workers/Jobs/Probe/UpdateConnectionStatus.ts b/App/FeatureSet/Workers/Jobs/Probe/UpdateConnectionStatus.ts index b32553a5e1..2b5775d0b0 100644 --- a/App/FeatureSet/Workers/Jobs/Probe/UpdateConnectionStatus.ts +++ b/App/FeatureSet/Workers/Jobs/Probe/UpdateConnectionStatus.ts @@ -5,7 +5,6 @@ import { EVERY_MINUTE } from "Common/Utils/CronTime"; import ProbeService from "CommonServer/Services/ProbeService"; import logger from "CommonServer/Utils/Logger"; import Probe, { ProbeStatus } from "Model/Models/Probe"; -import User from "Model/Models/User"; import MonitorProbe from "Model/Models/MonitorProbe"; import MonitorProbeService from "CommonServer/Services/MonitorProbeService"; @@ -41,7 +40,7 @@ RunCron( continue; } - let connectionStatus = ProbeStatus.Connected; + let connectionStatus: ProbeStatus = ProbeStatus.Connected; if (!probe.lastAlive) { connectionStatus = ProbeStatus.Disconnected; @@ -59,8 +58,8 @@ RunCron( connectionStatus = ProbeStatus.Connected; } - let shouldNotifyProbeOwner = false; - let shouldUpdateConnectionStatus = false; + let shouldNotifyProbeOwner: boolean = false; + let shouldUpdateConnectionStatus: boolean = false; if ( probe.connectionStatus && @@ -114,7 +113,3 @@ RunCron( } }, ); - -const getProbeOwners = async (probe: Probe): Promise => {}; - -const updateMonitors = async (probe: Probe): Promise => {}; diff --git a/CommonServer/Infrastructure/Postgres/SchemaMigrations/1719838746775-MigrationName.ts b/CommonServer/Infrastructure/Postgres/SchemaMigrations/1719838746775-MigrationName.ts new file mode 100644 index 0000000000..9ccd5bd78c --- /dev/null +++ b/CommonServer/Infrastructure/Postgres/SchemaMigrations/1719838746775-MigrationName.ts @@ -0,0 +1,62 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class MigrationName1719838746775 implements MigrationInterface { + public name = 'MigrationName1719838746775' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "ProbeOwnerTeam" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "version" integer NOT NULL, "projectId" uuid NOT NULL, "teamId" uuid NOT NULL, "probeId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "isOwnerNotified" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_b33e4c1d912b244680e0bace977" PRIMARY KEY ("_id"))`); + await queryRunner.query(`CREATE INDEX "IDX_6ffffa98ea1d05063733f36e55" ON "ProbeOwnerTeam" ("projectId") `); + await queryRunner.query(`CREATE INDEX "IDX_90007d943ad04dbef87aefcb6b" ON "ProbeOwnerTeam" ("teamId") `); + await queryRunner.query(`CREATE INDEX "IDX_d9a4b1d48b2eaefefb8f5dceb7" ON "ProbeOwnerTeam" ("probeId") `); + await queryRunner.query(`CREATE INDEX "IDX_b0a43c04a374168e90b5fe63e7" ON "ProbeOwnerTeam" ("isOwnerNotified") `); + await queryRunner.query(`CREATE TABLE "ProbeOwnerUser" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "version" integer NOT NULL, "projectId" uuid NOT NULL, "userId" uuid NOT NULL, "probeId" uuid NOT NULL, "createdByUserId" uuid, "deletedByUserId" uuid, "isOwnerNotified" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_6dfa74aadf4e90010fc1e86c76b" PRIMARY KEY ("_id"))`); + await queryRunner.query(`CREATE INDEX "IDX_e94247bb495236a2931d974cf0" ON "ProbeOwnerUser" ("projectId") `); + await queryRunner.query(`CREATE INDEX "IDX_3fbca1f838f73adbba73e81de7" ON "ProbeOwnerUser" ("userId") `); + await queryRunner.query(`CREATE INDEX "IDX_5d293a0a28ae8b189814761e9b" ON "ProbeOwnerUser" ("probeId") `); + await queryRunner.query(`CREATE INDEX "IDX_da7e9e3e1f350f3f99f0271d85" ON "ProbeOwnerUser" ("isOwnerNotified") `); + await queryRunner.query(`CREATE TABLE "ProbeLabel" ("probeId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_4564a1667bf06e98f36c266e986" PRIMARY KEY ("probeId", "labelId"))`); + await queryRunner.query(`CREATE INDEX "IDX_171fad9149ab82a7e83d12286b" ON "ProbeLabel" ("probeId") `); + await queryRunner.query(`CREATE INDEX "IDX_ab7fd85397d8c70c77c761004d" ON "ProbeLabel" ("labelId") `); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" ADD CONSTRAINT "FK_6ffffa98ea1d05063733f36e557" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" ADD CONSTRAINT "FK_90007d943ad04dbef87aefcb6b7" FOREIGN KEY ("teamId") REFERENCES "Team"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" ADD CONSTRAINT "FK_d9a4b1d48b2eaefefb8f5dceb73" FOREIGN KEY ("probeId") REFERENCES "Probe"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" ADD CONSTRAINT "FK_5f7e1a1dfc8380824e10d83f124" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" ADD CONSTRAINT "FK_e72250699a438e22153d9c32ea3" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" ADD CONSTRAINT "FK_e94247bb495236a2931d974cf0a" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" ADD CONSTRAINT "FK_3fbca1f838f73adbba73e81de7a" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" ADD CONSTRAINT "FK_5d293a0a28ae8b189814761e9b7" FOREIGN KEY ("probeId") REFERENCES "Probe"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" ADD CONSTRAINT "FK_011c2a132409253ceb1234695c6" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" ADD CONSTRAINT "FK_248df6f39557f114b03dd815bcf" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "ProbeLabel" ADD CONSTRAINT "FK_171fad9149ab82a7e83d12286b3" FOREIGN KEY ("probeId") REFERENCES "Probe"("_id") ON DELETE CASCADE ON UPDATE CASCADE`); + await queryRunner.query(`ALTER TABLE "ProbeLabel" ADD CONSTRAINT "FK_ab7fd85397d8c70c77c761004d2" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "ProbeLabel" DROP CONSTRAINT "FK_ab7fd85397d8c70c77c761004d2"`); + await queryRunner.query(`ALTER TABLE "ProbeLabel" DROP CONSTRAINT "FK_171fad9149ab82a7e83d12286b3"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" DROP CONSTRAINT "FK_248df6f39557f114b03dd815bcf"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" DROP CONSTRAINT "FK_011c2a132409253ceb1234695c6"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" DROP CONSTRAINT "FK_5d293a0a28ae8b189814761e9b7"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" DROP CONSTRAINT "FK_3fbca1f838f73adbba73e81de7a"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerUser" DROP CONSTRAINT "FK_e94247bb495236a2931d974cf0a"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" DROP CONSTRAINT "FK_e72250699a438e22153d9c32ea3"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" DROP CONSTRAINT "FK_5f7e1a1dfc8380824e10d83f124"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" DROP CONSTRAINT "FK_d9a4b1d48b2eaefefb8f5dceb73"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" DROP CONSTRAINT "FK_90007d943ad04dbef87aefcb6b7"`); + await queryRunner.query(`ALTER TABLE "ProbeOwnerTeam" DROP CONSTRAINT "FK_6ffffa98ea1d05063733f36e557"`); + await queryRunner.query(`DROP INDEX "public"."IDX_ab7fd85397d8c70c77c761004d"`); + await queryRunner.query(`DROP INDEX "public"."IDX_171fad9149ab82a7e83d12286b"`); + await queryRunner.query(`DROP TABLE "ProbeLabel"`); + await queryRunner.query(`DROP INDEX "public"."IDX_da7e9e3e1f350f3f99f0271d85"`); + await queryRunner.query(`DROP INDEX "public"."IDX_5d293a0a28ae8b189814761e9b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_3fbca1f838f73adbba73e81de7"`); + await queryRunner.query(`DROP INDEX "public"."IDX_e94247bb495236a2931d974cf0"`); + await queryRunner.query(`DROP TABLE "ProbeOwnerUser"`); + await queryRunner.query(`DROP INDEX "public"."IDX_b0a43c04a374168e90b5fe63e7"`); + await queryRunner.query(`DROP INDEX "public"."IDX_d9a4b1d48b2eaefefb8f5dceb7"`); + await queryRunner.query(`DROP INDEX "public"."IDX_90007d943ad04dbef87aefcb6b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_6ffffa98ea1d05063733f36e55"`); + await queryRunner.query(`DROP TABLE "ProbeOwnerTeam"`); + } + +} diff --git a/CommonServer/Infrastructure/Postgres/SchemaMigrations/Index.ts b/CommonServer/Infrastructure/Postgres/SchemaMigrations/Index.ts index b5ccbfa65d..8b865d5fb5 100644 --- a/CommonServer/Infrastructure/Postgres/SchemaMigrations/Index.ts +++ b/CommonServer/Infrastructure/Postgres/SchemaMigrations/Index.ts @@ -21,6 +21,7 @@ import { MigrationName1719247426296 } from "./1719247426296-MigrationName"; import { MigrationName1719348009053 } from "./1719348009053-MigrationName"; import { MigrationName1719827175832 } from "./1719827175832-MigrationName"; import { MigrationName1719831213463 } from "./1719831213463-MigrationName"; +import { MigrationName1719838746775 } from "./1719838746775-MigrationName"; export default [ InitialMigration, @@ -46,4 +47,5 @@ export default [ MigrationName1719348009053, MigrationName1719827175832, MigrationName1719831213463, + MigrationName1719838746775 ]; diff --git a/Model/Models/Probe.ts b/Model/Models/Probe.ts index bbe88c7ce3..579953c3ea 100755 --- a/Model/Models/Probe.ts +++ b/Model/Models/Probe.ts @@ -7,6 +7,7 @@ import { PlanType } from "Common/Types/Billing/SubscriptionPlan"; import ColumnAccessControl from "Common/Types/Database/AccessControl/ColumnAccessControl"; import TableAccessControl from "Common/Types/Database/AccessControl/TableAccessControl"; import TableBillingAccessControl from "Common/Types/Database/AccessControl/TableBillingAccessControl"; +import AccessControlColumn from "Common/Types/Database/AccessControlColumn"; import ColumnLength from "Common/Types/Database/ColumnLength"; import ColumnType from "Common/Types/Database/ColumnType"; import CrudApiEndpoint from "Common/Types/Database/CrudApiEndpoint"; @@ -20,7 +21,8 @@ import IconProp from "Common/Types/Icon/IconProp"; import ObjectID from "Common/Types/ObjectID"; import Permission from "Common/Types/Permission"; import Version from "Common/Types/Version"; -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne } from "typeorm"; +import Label from "./Label"; export enum ProbeStatus { Connected = "connected", @@ -36,6 +38,7 @@ export enum ProbeStatus { @IsPermissionsIf(Permission.Public, "projectId", null) @TenantColumn("projectId") @CrudApiEndpoint(new Route("/probe")) +@AccessControlColumn("labels") @SlugifyColumn("name", "slug") @Entity({ name: "Probe", @@ -501,4 +504,52 @@ export default class Probe extends BaseModel { unique: false, }) public connectionStatus?: ProbeStatus = undefined; -} + + + @ColumnAccessControl({ + create: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CreateProjectStatusPage, + ], + read: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.ReadProjectStatusPage, + ], + update: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.EditProjectStatusPage, + ], + }) + @TableColumn({ + required: false, + type: TableColumnType.EntityArray, + modelType: Label, + title: "Labels", + description: + "Relation to Labels Array where this object is categorized in.", + }) + @ManyToMany( + () => { + return Label; + }, + { eager: false }, + ) + @JoinTable({ + name: "ProbeLabel", + inverseJoinColumn: { + name: "labelId", + referencedColumnName: "_id", + }, + joinColumn: { + name: "probeId", + referencedColumnName: "_id", + }, + }) + public labels?: Array