File tree Expand file tree Collapse file tree 6 files changed +101
-0
lines changed
AdminDashboard/src/Pages/Settings/Authentication
Infrastructure/Postgres/SchemaMigrations Expand file tree Collapse file tree 6 files changed +101
-0
lines changed Original file line number Diff line number Diff line change @@ -73,6 +73,46 @@ const Settings: FunctionComponent = (): ReactElement => {
7373 modelId : ObjectID . getZeroObjectID ( ) ,
7474 } }
7575 />
76+
77+ < CardModelDetail
78+ name = "Project Creation Settings"
79+ cardProps = { {
80+ title : "Project Creation" ,
81+ description :
82+ "Control who can create new projects on this OneUptime Server." ,
83+ } }
84+ isEditable = { true }
85+ editButtonText = "Edit Settings"
86+ formFields = { [
87+ {
88+ field : {
89+ disableUserProjectCreation : true ,
90+ } ,
91+ title : "Restrict Project Creation to Admins Only" ,
92+ fieldType : FormFieldSchemaType . Toggle ,
93+ required : false ,
94+ description :
95+ "When enabled, only master admin users can create new projects." ,
96+ } ,
97+ ] }
98+ modelDetailProps = { {
99+ modelType : GlobalConfig ,
100+ id : "model-detail-project-creation" ,
101+ fields : [
102+ {
103+ field : {
104+ disableUserProjectCreation : true ,
105+ } ,
106+ fieldType : FieldType . Boolean ,
107+ title : "Restrict Project Creation to Admins Only" ,
108+ placeholder : "No" ,
109+ description :
110+ "When enabled, only master admin users can create new projects." ,
111+ } ,
112+ ] ,
113+ modelId : ObjectID . getZeroObjectID ( ) ,
114+ } }
115+ />
76116 </ Page >
77117 ) ;
78118} ;
Original file line number Diff line number Diff line change @@ -58,6 +58,25 @@ export default class GlobalConfig extends GlobalConfigModel {
5858 } )
5959 public disableSignup ?: boolean = undefined ;
6060
61+ @ColumnAccessControl ( {
62+ create : [ ] ,
63+ read : [ ] ,
64+ update : [ ] ,
65+ } )
66+ @TableColumn ( {
67+ type : TableColumnType . Boolean ,
68+ title : "Disable User Project Creation" ,
69+ description : "Only master admins can create projects when enabled." ,
70+ defaultValue : false ,
71+ } )
72+ @Column ( {
73+ type : ColumnType . Boolean ,
74+ nullable : true ,
75+ default : false ,
76+ unique : true ,
77+ } )
78+ public disableUserProjectCreation ?: boolean = undefined ;
79+
6180 // SMTP Settings.
6281
6382 @ColumnAccessControl ( {
Original file line number Diff line number Diff line change @@ -80,4 +80,11 @@ export default class DatabaseConfig {
8080 "disableSignup" ,
8181 ) ) as boolean ;
8282 }
83+
84+ @CaptureSpan ( )
85+ public static async shouldDisableUserProjectCreation ( ) : Promise < boolean > {
86+ return ( await DatabaseConfig . getFromGlobalConfig (
87+ "disableUserProjectCreation" ,
88+ ) ) as boolean ;
89+ }
8390}
Original file line number Diff line number Diff line change 1+ import { MigrationInterface , QueryRunner } from "typeorm" ;
2+
3+ export class MigrationName1770834237091 implements MigrationInterface {
4+ public name = "MigrationName1770834237091" ;
5+
6+ public async up ( queryRunner : QueryRunner ) : Promise < void > {
7+ await queryRunner . query (
8+ `ALTER TABLE "GlobalConfig" ADD "disableUserProjectCreation" boolean DEFAULT false` ,
9+ ) ;
10+ await queryRunner . query (
11+ `ALTER TABLE "GlobalConfig" ADD CONSTRAINT "UQ_disableUserProjectCreation" UNIQUE ("disableUserProjectCreation")` ,
12+ ) ;
13+ }
14+
15+ public async down ( queryRunner : QueryRunner ) : Promise < void > {
16+ await queryRunner . query (
17+ `ALTER TABLE "GlobalConfig" DROP CONSTRAINT "UQ_disableUserProjectCreation"` ,
18+ ) ;
19+ await queryRunner . query (
20+ `ALTER TABLE "GlobalConfig" DROP COLUMN "disableUserProjectCreation"` ,
21+ ) ;
22+ }
23+ }
Original file line number Diff line number Diff line change @@ -258,6 +258,7 @@ import { MigrationName1770728946893 } from "./1770728946893-MigrationName";
258258import { MigrationName1770732721195 } from "./1770732721195-MigrationName" ;
259259import { MigrationName1770833704656 } from "./1770833704656-MigrationName" ;
260260import { MigrationName1770834237090 } from "./1770834237090-MigrationName" ;
261+ import { MigrationName1770834237091 } from "./1770834237091-MigrationName" ;
261262
262263export default [
263264 InitialMigration ,
@@ -520,4 +521,5 @@ export default [
520521 MigrationName1770732721195 ,
521522 MigrationName1770833704656 ,
522523 MigrationName1770834237090 ,
524+ MigrationName1770834237091 ,
523525] ;
Original file line number Diff line number Diff line change @@ -124,6 +124,7 @@ export class ProjectService extends DatabaseService<Model> {
124124 select : {
125125 name : true ,
126126 email : true ,
127+ isMasterAdmin : true ,
127128 companyPhoneNumber : true ,
128129 companyName : true ,
129130 utmCampaign : true ,
@@ -142,6 +143,15 @@ export class ProjectService extends DatabaseService<Model> {
142143 throw new BadDataException ( "User not found." ) ;
143144 }
144145
146+ // Check if project creation is restricted to admins only
147+ const shouldDisableProjectCreation : boolean =
148+ await DatabaseConfig . shouldDisableUserProjectCreation ( ) ;
149+ if ( shouldDisableProjectCreation && ! user . isMasterAdmin ) {
150+ throw new NotAuthorizedException (
151+ "Project creation is restricted to admin users only on this OneUptime Server. Please contact your server admin." ,
152+ ) ;
153+ }
154+
145155 if ( IsBillingEnabled ) {
146156 if ( ! data . data . paymentProviderPlanId ) {
147157 throw new BadDataException ( "Plan required to create the project." ) ;
You can’t perform that action at this time.
0 commit comments