From 0a427bfe9bead091b23b5686f5df8430fa3a976f Mon Sep 17 00:00:00 2001 From: Richard LT Date: Thu, 5 Jan 2023 15:40:28 +0100 Subject: [PATCH] feat(api,ui): allow to disable vcs management on project (#6408) --- engine/api/api.go | 5 ++- engine/api/config.go | 7 ++-- engine/api/repositories_manager.go | 16 ++++++++ sdk/config.go | 7 ++-- ui/src/app/model/config.service.ts | 1 + .../show/admin/project.admin.component.ts | 19 +++++++-- .../project/show/admin/project.admin.html | 40 +++++++++---------- .../project.repomanager.list.component.ts | 23 ++++++++--- .../list/project.repomanager.list.html | 38 ++++++++++-------- 9 files changed, 101 insertions(+), 55 deletions(-) diff --git a/engine/api/api.go b/engine/api/api.go index 98191b4936..1cc136567c 100644 --- a/engine/api/api.go +++ b/engine/api/api.go @@ -221,8 +221,9 @@ type Configuration struct { TemplateBulkRunnerCount int64 `toml:"templateBulkRunnerCount" comment:"The count of runner that will execute the workflow template bulk operation." json:"templateBulkRunnerCount" default:"10"` } `toml:"workflow" comment:"######################\n 'Workflow' global configuration \n######################" json:"workflow"` Project struct { - CreationDisabled bool `toml:"creationDisabled" comment:"Disable project creation for CDS non admin users." json:"creationDisabled" default:"false" commented:"true"` - InfoCreationDisabled string `toml:"infoCreationDisabled" comment:"Optional message to display if project creation is disabled." json:"infoCreationDisabled" default:"" commented:"true"` + CreationDisabled bool `toml:"creationDisabled" comment:"Disable project creation for CDS non admin users." json:"creationDisabled" default:"false" commented:"true"` + InfoCreationDisabled string `toml:"infoCreationDisabled" comment:"Optional message to display if project creation is disabled." json:"infoCreationDisabled" default:"" commented:"true"` + VCSManagementDisabled bool `toml:"vcsManagementDisabled" comment:"Disable VCS management on project for CDS non admin users." json:"vcsManagementDisabled" default:"false" commented:"true"` } `toml:"project" comment:"######################\n 'Project' global configuration \n######################" json:"project"` EventBus event.Config `toml:"events" comment:"######################\n Event bus configuration \n######################" json:"events" mapstructure:"events"` } diff --git a/engine/api/config.go b/engine/api/config.go index 3767b7010b..abf5efb995 100644 --- a/engine/api/config.go +++ b/engine/api/config.go @@ -91,9 +91,10 @@ func (api *API) configCDNHandler() service.Handler { func (api *API) configAPIHandler() service.Handler { return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error { return service.WriteJSON(w, sdk.APIConfig{ - DefaultRunRetentionPolicy: api.Config.Workflow.DefaultRetentionPolicy, - ProjectCreationDisabled: api.Config.Project.CreationDisabled, - ProjectInfoCreationDisabled: api.Config.Project.InfoCreationDisabled, + DefaultRunRetentionPolicy: api.Config.Workflow.DefaultRetentionPolicy, + ProjectCreationDisabled: api.Config.Project.CreationDisabled, + ProjectInfoCreationDisabled: api.Config.Project.InfoCreationDisabled, + ProjectVCSManagementDisabled: api.Config.Project.VCSManagementDisabled, }, http.StatusOK) } } diff --git a/engine/api/repositories_manager.go b/engine/api/repositories_manager.go index 0cfe8ab2e4..6ad6a426b7 100644 --- a/engine/api/repositories_manager.go +++ b/engine/api/repositories_manager.go @@ -55,6 +55,10 @@ func (api *API) repositoriesManagerAuthorizeHandler() service.Handler { key := vars[permProjectKey] rmName := vars["name"] + if api.Config.Project.VCSManagementDisabled && !isAdmin(ctx) { + return sdk.NewErrorFrom(sdk.ErrForbidden, "vcs management is disabled") + } + proj, err := project.Load(ctx, api.mustDB(), key) if err != nil { return sdk.WrapError(err, "cannot load project") @@ -206,6 +210,10 @@ func (api *API) repositoriesManagerAuthorizeBasicHandler() service.Handler { projectKey := vars["permProjectKey"] rmName := vars["name"] + if api.Config.Project.VCSManagementDisabled && !isAdmin(ctx) { + return sdk.NewErrorFrom(sdk.ErrForbidden, "vcs management is disabled") + } + var tv map[string]interface{} if err := service.UnmarshalBody(r, &tv); err != nil { return err @@ -272,6 +280,10 @@ func (api *API) repositoriesManagerAuthorizeCallbackHandler() service.Handler { projectKey := vars[permProjectKey] rmName := vars["name"] + if api.Config.Project.VCSManagementDisabled && !isAdmin(ctx) { + return sdk.NewErrorFrom(sdk.ErrForbidden, "vcs management is disabled") + } + var tv map[string]interface{} if err := service.UnmarshalBody(r, &tv); err != nil { return err @@ -346,6 +358,10 @@ func (api *API) deleteRepositoriesManagerHandler() service.Handler { projectKey := vars[permProjectKey] rmName := vars["name"] + if api.Config.Project.VCSManagementDisabled && !isAdmin(ctx) { + return sdk.NewErrorFrom(sdk.ErrForbidden, "vcs management is disabled") + } + force := service.FormBool(r, "force") p, err := project.Load(ctx, api.mustDB(), projectKey) diff --git a/sdk/config.go b/sdk/config.go index 5ba972152d..0d4700f3e2 100644 --- a/sdk/config.go +++ b/sdk/config.go @@ -12,9 +12,10 @@ type ConfigUser struct { } type APIConfig struct { - DefaultRunRetentionPolicy string `json:"default_run_retention_policy"` - ProjectCreationDisabled bool `json:"project_creation_disabled"` - ProjectInfoCreationDisabled string `json:"project_info_creation_disabled,omitempty"` + DefaultRunRetentionPolicy string `json:"default_run_retention_policy"` + ProjectCreationDisabled bool `json:"project_creation_disabled"` + ProjectInfoCreationDisabled string `json:"project_info_creation_disabled,omitempty"` + ProjectVCSManagementDisabled bool `json:"project_vcs_management_disabled,omitempty"` } type TCPServer struct { diff --git a/ui/src/app/model/config.service.ts b/ui/src/app/model/config.service.ts index ad1624edfe..72bc909e85 100644 --- a/ui/src/app/model/config.service.ts +++ b/ui/src/app/model/config.service.ts @@ -2,4 +2,5 @@ export class APIConfig { default_run_retention_policy: string; project_creation_disabled: boolean; project_info_creation_disabled: string; + project_vcs_management_disabled: boolean; } diff --git a/ui/src/app/views/project/show/admin/project.admin.component.ts b/ui/src/app/views/project/show/admin/project.admin.component.ts index d3d6faf855..81663e3750 100644 --- a/ui/src/app/views/project/show/admin/project.admin.component.ts +++ b/ui/src/app/views/project/show/admin/project.admin.component.ts @@ -2,9 +2,13 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Store } from '@ngxs/store'; +import { APIConfig } from 'app/model/config.service'; import { Project } from 'app/model/project.model'; +import { AutoUnsubscribe } from 'app/shared/decorator/autoUnsubscribe'; import { ToastService } from 'app/shared/toast/ToastService'; +import { ConfigState } from 'app/store/config.state'; import { DeleteProject, UpdateProject } from 'app/store/project.action'; +import { Subscription } from 'rxjs'; import { finalize } from 'rxjs/operators'; @Component({ @@ -13,12 +17,15 @@ import { finalize } from 'rxjs/operators'; styleUrls: ['./project.admin.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) +@AutoUnsubscribe() export class ProjectAdminComponent implements OnInit { @Input() project: Project; loading = false; fileTooLarge = false; + configSubscription: Subscription; + apiConfig: APIConfig; constructor( private _toast: ToastService, @@ -26,13 +33,17 @@ export class ProjectAdminComponent implements OnInit { private _router: Router, private _store: Store, private _cd: ChangeDetectorRef - ) { - } + ) { } ngOnInit(): void { if (!this.project.permissions.writable) { - this._router.navigate(['/project', this.project.key], {queryParams: {tab: 'applications'}}); + this._router.navigate(['/project', this.project.key], { queryParams: { tab: 'applications' } }); } + + this.configSubscription = this._store.select(ConfigState.api).subscribe(c => { + this.apiConfig = c; + this._cd.markForCheck(); + }); } onSubmitProjectUpdate() { @@ -47,7 +58,7 @@ export class ProjectAdminComponent implements OnInit { deleteProject(): void { this.loading = true; - this._store.dispatch(new DeleteProject({projectKey: this.project.key})) + this._store.dispatch(new DeleteProject({ projectKey: this.project.key })) .pipe(finalize(() => { this.loading = false; this._cd.markForCheck(); diff --git a/ui/src/app/views/project/show/admin/project.admin.html b/ui/src/app/views/project/show/admin/project.admin.html index 503f7a4fc4..57e95d1242 100644 --- a/ui/src/app/views/project/show/admin/project.admin.html +++ b/ui/src/app/views/project/show/admin/project.admin.html @@ -4,24 +4,17 @@ Project name - + - + Description - @@ -31,20 +24,23 @@
project icon
- - + + - + - - + + @@ -53,8 +49,8 @@
Once you delete a project, there is no going back. Please be certain.
-
diff --git a/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.component.ts b/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.component.ts index 7393100a85..19e752f59b 100644 --- a/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.component.ts +++ b/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.component.ts @@ -1,11 +1,15 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Store } from '@ngxs/store'; +import { APIConfig } from 'app/model/config.service'; import { Project } from 'app/model/project.model'; import { RepositoriesManager } from 'app/model/repositories.model'; import { RepoManagerService } from 'app/service/repomanager/project.repomanager.service'; +import { AutoUnsubscribe } from 'app/shared/decorator/autoUnsubscribe'; import { ToastService } from 'app/shared/toast/ToastService'; +import { ConfigState } from 'app/store/config.state'; import { DisconnectRepositoryManagerInProject } from 'app/store/project.action'; +import { Subscription } from 'rxjs'; import { finalize } from 'rxjs/operators'; @Component({ @@ -14,7 +18,8 @@ import { finalize } from 'rxjs/operators'; styleUrls: ['./project.repomanager.list.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class ProjectRepoManagerComponent { +@AutoUnsubscribe() +export class ProjectRepoManagerComponent implements OnInit { @Input() project: Project; @Input() reposmanagers: RepositoriesManager[]; @@ -24,14 +29,22 @@ export class ProjectRepoManagerComponent { repoNameToDelete: string; confirmationMessage: string; deleteModal: boolean; + apiConfig: APIConfig; + configSubscription: Subscription; constructor( private _toast: ToastService, public _translate: TranslateService, private repoManagerService: RepoManagerService, - private store: Store, + private _store: Store, private _cd: ChangeDetectorRef - ) { + ) { } + + ngOnInit(): void { + this.configSubscription = this._store.select(ConfigState.api).subscribe(c => { + this.apiConfig = c; + this._cd.markForCheck(); + }); } clickDeleteButton(repoName: string): void { @@ -59,7 +72,7 @@ export class ProjectRepoManagerComponent { return; } this.deleteLoading = true; - this.store.dispatch(new DisconnectRepositoryManagerInProject({ + this._store.dispatch(new DisconnectRepositoryManagerInProject({ projectKey: this.project.key, repoManager: this.repoNameToDelete })) diff --git a/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.html b/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.html index dc7a681fec..fcf75fcf6c 100644 --- a/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.html +++ b/ui/src/app/views/project/show/admin/repomanager/list/project.repomanager.list.html @@ -1,24 +1,30 @@
- - Name - - + + Name + + - - - {{r.name}} - -{{ 'project_repoman_created_by' | translate }}{{r.created_by}} - - User: {{r.auth.username}} - - SSH User: {{r.auth.sshUsername}} - - SSH Key: {{r.auth.sshKeyName}} - - - - - + + + {{r.name}} + -{{ 'project_repoman_created_by' | translate + }}{{r.created_by}} + - User: + {{r.auth.username}} + - SSH User: + {{r.auth.sshUsername}} + - SSH Key: + {{r.auth.sshKeyName}} + + + + +