mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat: implement project creation restriction for non-admin users
This commit is contained in:
@@ -73,6 +73,46 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
modelId: ObjectID.getZeroObjectID(),
|
||||
}}
|
||||
/>
|
||||
|
||||
<CardModelDetail
|
||||
name="Project Creation Settings"
|
||||
cardProps={{
|
||||
title: "Project Creation",
|
||||
description:
|
||||
"Control who can create new projects on this OneUptime Server.",
|
||||
}}
|
||||
isEditable={true}
|
||||
editButtonText="Edit Settings"
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
disableUserProjectCreation: true,
|
||||
},
|
||||
title: "Restrict Project Creation to Admins Only",
|
||||
fieldType: FormFieldSchemaType.Toggle,
|
||||
required: false,
|
||||
description:
|
||||
"When enabled, only master admin users can create new projects.",
|
||||
},
|
||||
]}
|
||||
modelDetailProps={{
|
||||
modelType: GlobalConfig,
|
||||
id: "model-detail-project-creation",
|
||||
fields: [
|
||||
{
|
||||
field: {
|
||||
disableUserProjectCreation: true,
|
||||
},
|
||||
fieldType: FieldType.Boolean,
|
||||
title: "Restrict Project Creation to Admins Only",
|
||||
placeholder: "No",
|
||||
description:
|
||||
"When enabled, only master admin users can create new projects.",
|
||||
},
|
||||
],
|
||||
modelId: ObjectID.getZeroObjectID(),
|
||||
}}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -58,6 +58,25 @@ export default class GlobalConfig extends GlobalConfigModel {
|
||||
})
|
||||
public disableSignup?: boolean = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Boolean,
|
||||
title: "Disable User Project Creation",
|
||||
description: "Only master admins can create projects when enabled.",
|
||||
defaultValue: false,
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Boolean,
|
||||
nullable: true,
|
||||
default: false,
|
||||
unique: true,
|
||||
})
|
||||
public disableUserProjectCreation?: boolean = undefined;
|
||||
|
||||
// SMTP Settings.
|
||||
|
||||
@ColumnAccessControl({
|
||||
|
||||
@@ -80,4 +80,11 @@ export default class DatabaseConfig {
|
||||
"disableSignup",
|
||||
)) as boolean;
|
||||
}
|
||||
|
||||
@CaptureSpan()
|
||||
public static async shouldDisableUserProjectCreation(): Promise<boolean> {
|
||||
return (await DatabaseConfig.getFromGlobalConfig(
|
||||
"disableUserProjectCreation",
|
||||
)) as boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class MigrationName1770834237091 implements MigrationInterface {
|
||||
public name = "MigrationName1770834237091";
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "GlobalConfig" ADD "disableUserProjectCreation" boolean DEFAULT false`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "GlobalConfig" ADD CONSTRAINT "UQ_disableUserProjectCreation" UNIQUE ("disableUserProjectCreation")`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "GlobalConfig" DROP CONSTRAINT "UQ_disableUserProjectCreation"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "GlobalConfig" DROP COLUMN "disableUserProjectCreation"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -258,6 +258,7 @@ import { MigrationName1770728946893 } from "./1770728946893-MigrationName";
|
||||
import { MigrationName1770732721195 } from "./1770732721195-MigrationName";
|
||||
import { MigrationName1770833704656 } from "./1770833704656-MigrationName";
|
||||
import { MigrationName1770834237090 } from "./1770834237090-MigrationName";
|
||||
import { MigrationName1770834237091 } from "./1770834237091-MigrationName";
|
||||
|
||||
export default [
|
||||
InitialMigration,
|
||||
@@ -520,4 +521,5 @@ export default [
|
||||
MigrationName1770732721195,
|
||||
MigrationName1770833704656,
|
||||
MigrationName1770834237090,
|
||||
MigrationName1770834237091,
|
||||
];
|
||||
|
||||
@@ -124,6 +124,7 @@ export class ProjectService extends DatabaseService<Model> {
|
||||
select: {
|
||||
name: true,
|
||||
email: true,
|
||||
isMasterAdmin: true,
|
||||
companyPhoneNumber: true,
|
||||
companyName: true,
|
||||
utmCampaign: true,
|
||||
@@ -142,6 +143,15 @@ export class ProjectService extends DatabaseService<Model> {
|
||||
throw new BadDataException("User not found.");
|
||||
}
|
||||
|
||||
// Check if project creation is restricted to admins only
|
||||
const shouldDisableProjectCreation: boolean =
|
||||
await DatabaseConfig.shouldDisableUserProjectCreation();
|
||||
if (shouldDisableProjectCreation && !user.isMasterAdmin) {
|
||||
throw new NotAuthorizedException(
|
||||
"Project creation is restricted to admin users only on this OneUptime Server. Please contact your server admin.",
|
||||
);
|
||||
}
|
||||
|
||||
if (IsBillingEnabled) {
|
||||
if (!data.data.paymentProviderPlanId) {
|
||||
throw new BadDataException("Plan required to create the project.");
|
||||
|
||||
Reference in New Issue
Block a user