Skip to content

Commit

Permalink
feat(api,ui): allow to disable vcs management on project (#6408)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardlt committed Jan 5, 2023
1 parent 7470a39 commit 0a427bf
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 55 deletions.
5 changes: 3 additions & 2 deletions engine/api/api.go
Expand Up @@ -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"`
}
Expand Down
7 changes: 4 additions & 3 deletions engine/api/config.go
Expand Up @@ -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)
}
}
16 changes: 16 additions & 0 deletions engine/api/repositories_manager.go
Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
7 changes: 4 additions & 3 deletions sdk/config.go
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions ui/src/app/model/config.service.ts
Expand Up @@ -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;
}
19 changes: 15 additions & 4 deletions ui/src/app/views/project/show/admin/project.admin.component.ts
Expand Up @@ -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({
Expand All @@ -13,26 +17,33 @@ 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,
public _translate: TranslateService,
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() {
Expand All @@ -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();
Expand Down
40 changes: 18 additions & 22 deletions ui/src/app/views/project/show/admin/project.admin.html
Expand Up @@ -4,24 +4,17 @@
<nz-form-item>
<nz-form-label [nzSpan]="3">Project name</nz-form-label>
<nz-form-control>
<input nz-input type="text" name="formProjectUpdateName"
placeholder="Project name"
[(ngModel)]="project.name"
[disabled]="loading"
required
#formProjectUpdateName="ngModel">
<input nz-input type="text" name="formProjectUpdateName" placeholder="Project name"
[(ngModel)]="project.name" [disabled]="loading" required #formProjectUpdateName="ngModel">
</nz-form-control>
<nz-alert *ngIf="formProjectUpdateName.invalid && !formProjectUpdateName.pristine"
nzType="error" nzMessage="Project name is mandatory and must respect the alphanumeric pattern ([a-zA-Z0-9]*)"></nz-alert>
<nz-alert *ngIf="formProjectUpdateName.invalid && !formProjectUpdateName.pristine" nzType="error"
nzMessage="Project name is mandatory and must respect the alphanumeric pattern ([a-zA-Z0-9]*)"></nz-alert>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="3">Description</nz-form-label>
<nz-form-control>
<textarea nz-input name="formProjectUpdateDescription"
placeholder="Description"
[(ngModel)]="project.description"
[disabled]="loading"
#formProjectUpdateDescription="ngModel">
<textarea nz-input name="formProjectUpdateDescription" placeholder="Description"
[(ngModel)]="project.description" [disabled]="loading" #formProjectUpdateDescription="ngModel">
</textarea>
</nz-form-control>
</nz-form-item>
Expand All @@ -31,20 +24,23 @@
<div>
<img class="proj-icon" [src]="project.icon" alt="project icon" *ngIf="project.icon">
</div>
<app-upload-button accept=".png,.jpg,.jpeg" image="true" (event)="fileEvent($event)"></app-upload-button>
<nz-alert *ngIf="fileTooLarge" nzType="error" nzMessage="Your file is too large (max 100Ko)"></nz-alert>
<app-upload-button accept=".png,.jpg,.jpeg" image="true"
(event)="fileEvent($event)"></app-upload-button>
<nz-alert *ngIf="fileTooLarge" nzType="error"
nzMessage="Your file is too large (max 100Ko)"></nz-alert>
</nz-form-control>
</nz-form-item>
<nz-form-item nzJustify="end">
<button nz-button nzType="primary" name="btnrename" [nzLoading]="loading" [disabled]="projectUpdateFrom.invalid">Rename</button>
<button nz-button nzType="primary" name="btnrename" [nzLoading]="loading"
[disabled]="projectUpdateFrom.invalid">Rename</button>
</nz-form-item>
</form>
</nz-card>
<nz-card nzTitle="Link to a repository manager" class="coloredTitle">
<app-repomanager-form [project]="project"></app-repomanager-form>
<app-project-repomanager-list *ngIf="project.vcs_servers && project.vcs_servers.length > 0"
[project]="project" [reposmanagers]="project.vcs_servers"
></app-project-repomanager-list>
<app-repomanager-form *ngIf="apiConfig && !apiConfig.project_vcs_management_disabled"
[project]="project"></app-repomanager-form>
<app-project-repomanager-list *ngIf="project.vcs_servers && project.vcs_servers.length > 0" [project]="project"
[reposmanagers]="project.vcs_servers"></app-project-repomanager-list>
</nz-card>
<nz-card nzTitle="Danger zone" class="redTitle">
<nz-row>
Expand All @@ -53,8 +49,8 @@
<div class="description">Once you delete a project, there is no going back. Please be certain.</div>
</nz-col>
<nz-col [nzSpan]="12" class="alignRight">
<button nz-button nzDanger nzType="primary" [nzLoading]="loading"
nz-popconfirm nzPopconfirmTitle="Are you sure you want to delete this project ?"
<button nz-button nzDanger nzType="primary" [nzLoading]="loading" nz-popconfirm
nzPopconfirmTitle="Are you sure you want to delete this project ?"
(nzOnConfirm)="deleteProject()">Delete</button>
</nz-col>
</nz-row>
Expand Down
@@ -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({
Expand All @@ -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[];
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}))
Expand Down
@@ -1,24 +1,30 @@
<div id="projectRepoManagers">
<nz-table [nzData]="reposmanagers" nzSize="small" #listrepos>
<thead>
<tr>
<th nzWidth="400px">Name</th>
<th nzWidth="50px"></th>
</tr>
<tr>
<th nzWidth="400px">Name</th>
<th nzWidth="50px"></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of listrepos.data">
<td>
{{r.name}}
<span *ngIf="r.created_by !== ''"> -{{ 'project_repoman_created_by' | translate }}{{r.created_by}}</span>
<span *ngIf="r.auth && r.auth.username && r.auth.username !== ''"> - User: {{r.auth.username}}</span>
<span *ngIf="r.auth && r.auth.sshUsername && r.auth.sshUsername !== ''"> - SSH User: {{r.auth.sshUsername}}</span>
<span *ngIf="r.auth && r.auth.sshKeyName && r.auth.sshKeyName !== ''"> - SSH Key: {{r.auth.sshKeyName}}</span>
</td>
<td class="rightAlign">
<button nz-button nzDanger nzType="primary" [nzLoading]="deleteLoading" *ngIf="r.type === ''" (click)="clickDeleteButton(r.name)">Remove</button>
</td>
</tr>
<tr *ngFor="let r of listrepos.data">
<td>
{{r.name}}
<span *ngIf="r.created_by !== ''"> -{{ 'project_repoman_created_by' | translate
}}{{r.created_by}}</span>
<span *ngIf="r.auth && r.auth.username && r.auth.username !== ''"> - User:
{{r.auth.username}}</span>
<span *ngIf="r.auth && r.auth.sshUsername && r.auth.sshUsername !== ''"> - SSH User:
{{r.auth.sshUsername}}</span>
<span *ngIf="r.auth && r.auth.sshKeyName && r.auth.sshKeyName !== ''"> - SSH Key:
{{r.auth.sshKeyName}}</span>
</td>
<td class="rightAlign">
<button *ngIf="r.type === '' && apiConfig && !apiConfig.project_vcs_management_disabled" nz-button
nzDanger nzType="primary" [nzLoading]="deleteLoading"
(click)="clickDeleteButton(r.name)">Remove</button>
</td>
</tr>
</tbody>
</nz-table>
</div>
Expand Down

0 comments on commit 0a427bf

Please sign in to comment.