mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-19 10:16:41 +00:00
More work on perms page
This commit is contained in:
parent
b936513eb9
commit
94c3ce3267
26
api/auth.go
26
api/auth.go
@ -155,6 +155,32 @@ func (api *WebAPI) GetManagerList(r *Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func (api *WebAPI) GetManagerListWithRoleOn(r *Request) {
|
||||
|
||||
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
|
||||
handleErr(err, r) //todo handle invalid id
|
||||
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if manager == nil {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Unauthorized",
|
||||
}, 401)
|
||||
return
|
||||
}
|
||||
|
||||
managers := api.Database.GetManagerListWithRoleOn(pid)
|
||||
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: true,
|
||||
Content: GetManagerListWithRoleOnResponse{
|
||||
Managers: managers,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (api *WebAPI) PromoteManager(r *Request) {
|
||||
|
||||
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
|
||||
|
@ -106,8 +106,10 @@ func New() *WebAPI {
|
||||
api.router.GET("/logout", LogRequestMiddleware(api.Logout))
|
||||
api.router.GET("/account", LogRequestMiddleware(api.GetAccountDetails))
|
||||
api.router.GET("/manager/list", LogRequestMiddleware(api.GetManagerList))
|
||||
api.router.GET("/manager/list_for_project/:id", LogRequestMiddleware(api.GetManagerListWithRoleOn))
|
||||
api.router.GET("/manager/promote/:id", LogRequestMiddleware(api.PromoteManager))
|
||||
api.router.GET("/manager/demote/:id", LogRequestMiddleware(api.DemoteManager))
|
||||
api.router.POST("/manager/set_role_for_project/:id", LogRequestMiddleware(api.SetManagerRoleOnProject))
|
||||
|
||||
api.router.NotFound = func(ctx *fasthttp.RequestCtx) {
|
||||
|
||||
|
@ -81,6 +81,10 @@ type GetManagerListResponse struct {
|
||||
Managers *[]storage.Manager `json:"managers"`
|
||||
}
|
||||
|
||||
type GetManagerListWithRoleOnResponse struct {
|
||||
Managers *[]storage.ManagerRoleOn `json:"managers"`
|
||||
}
|
||||
|
||||
type GetLogRequest struct {
|
||||
Level storage.LogLevel `json:"level"`
|
||||
Since int64 `json:"since"`
|
||||
@ -263,6 +267,11 @@ func (w *CreateWorkerAccessRequest) isValid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type SetManagerRoleOnProjectRequest struct {
|
||||
Manager int64 `json:"manager"`
|
||||
Role storage.ManagerRole `json:"role"`
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
|
@ -100,7 +100,7 @@ func (api *WebAPI) CreateProject(r *Request) {
|
||||
return
|
||||
}
|
||||
|
||||
api.Database.SetManagerRoleOn(manager.(*storage.Manager), id,
|
||||
api.Database.SetManagerRoleOn(manager.(*storage.Manager).Id, id,
|
||||
storage.ROLE_MANAGE_ACCESS|storage.ROLE_READ|storage.ROLE_EDIT)
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: true,
|
||||
@ -403,3 +403,35 @@ func (api *WebAPI) RejectAccessRequest(r *Request) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (api *WebAPI) SetManagerRoleOnProject(r *Request) {
|
||||
|
||||
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
|
||||
handleErr(err, r) //todo handle invalid id
|
||||
|
||||
req := &SetManagerRoleOnProjectRequest{}
|
||||
err = json.Unmarshal(r.Ctx.Request.Body(), req)
|
||||
if err != nil {
|
||||
r.Json(JsonResponse{
|
||||
Ok: false,
|
||||
Message: "Could not parse request",
|
||||
}, 400)
|
||||
return
|
||||
}
|
||||
|
||||
sess := api.Session.StartFasthttp(r.Ctx)
|
||||
manager := sess.Get("manager")
|
||||
|
||||
if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
|
||||
r.Json(JsonResponse{
|
||||
Message: "Unauthorized",
|
||||
Ok: false,
|
||||
}, 403)
|
||||
return
|
||||
}
|
||||
|
||||
api.Database.SetManagerRoleOn(req.Manager, pid, req.Role)
|
||||
r.OkJson(JsonResponse{
|
||||
Ok: true,
|
||||
})
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package storage
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
@ -23,6 +24,11 @@ type Manager struct {
|
||||
RegisterTime int64 `json:"register_time"`
|
||||
}
|
||||
|
||||
type ManagerRoleOn struct {
|
||||
Manager Manager `json:"manager"`
|
||||
Role ManagerRole `json:"role"`
|
||||
}
|
||||
|
||||
func (database *Database) ValidateCredentials(username []byte, password []byte) (*Manager, error) {
|
||||
|
||||
db := database.getDB()
|
||||
@ -142,20 +148,28 @@ func (database *Database) GetManagerRoleOn(manager *Manager, projectId int64) Ma
|
||||
return role
|
||||
}
|
||||
|
||||
func (database *Database) SetManagerRoleOn(manager *Manager, projectId int64, role ManagerRole) {
|
||||
func (database *Database) SetManagerRoleOn(manager int64, projectId int64, role ManagerRole) {
|
||||
|
||||
db := database.getDB()
|
||||
|
||||
res, err := db.Exec(`INSERT INTO manager_has_role_on_project (manager, role, project)
|
||||
VALUES ($1,$2,$3) ON CONFLICT (manager, project) DO UPDATE SET role=$2`,
|
||||
manager.Id, role, projectId)
|
||||
handleErr(err)
|
||||
var res sql.Result
|
||||
var err error
|
||||
|
||||
if role == 0 {
|
||||
res, err = db.Exec(`DELETE FROM manager_has_role_on_project WHERE manager=$1 AND project=$2`,
|
||||
manager, projectId)
|
||||
} else {
|
||||
res, err = db.Exec(`INSERT INTO manager_has_role_on_project (manager, role, project)
|
||||
VALUES ($1,$2,$3) ON CONFLICT (manager, project) DO UPDATE SET role=$2`,
|
||||
manager, role, projectId)
|
||||
}
|
||||
|
||||
handleErr(err)
|
||||
rowsAffected, _ := res.RowsAffected()
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"role": role,
|
||||
"manager": manager.Username,
|
||||
"manager": manager,
|
||||
"rowsAffected": rowsAffected,
|
||||
"project": projectId,
|
||||
}).Info("Set manager role on project")
|
||||
@ -177,3 +191,29 @@ func (database *Database) GetManagerList() *[]Manager {
|
||||
|
||||
return &managers
|
||||
}
|
||||
|
||||
func (database *Database) GetManagerListWithRoleOn(project int64) *[]ManagerRoleOn {
|
||||
|
||||
db := database.getDB()
|
||||
|
||||
rows, err := db.Query(`SELECT id, register_time, tracker_admin, username, role
|
||||
FROM manager
|
||||
LEFT JOIN manager_has_role_on_project mhrop on
|
||||
manager.id = mhrop.manager
|
||||
WHERE project=$1 ORDER BY id`, project)
|
||||
handleErr(err)
|
||||
|
||||
managers := make([]ManagerRoleOn, 0)
|
||||
|
||||
for rows.Next() {
|
||||
m := Manager{}
|
||||
var role ManagerRole
|
||||
_ = rows.Scan(&m.Id, &m.RegisterTime, &m.WebsiteAdmin, &m.Username, &role)
|
||||
managers = append(managers, ManagerRoleOn{
|
||||
Manager: m,
|
||||
Role: role,
|
||||
})
|
||||
}
|
||||
|
||||
return &managers
|
||||
}
|
||||
|
@ -69,10 +69,14 @@ export class ApiService {
|
||||
return this.http.get(this.url + `/project/access_list/${project}`)
|
||||
}
|
||||
|
||||
getAllManagers() {
|
||||
getManagerList() {
|
||||
return this.http.get(this.url + "/manager/list")
|
||||
}
|
||||
|
||||
getManagerListWithRoleOn(project: number) {
|
||||
return this.http.get(this.url + "/manager/list_for_project/" + project)
|
||||
}
|
||||
|
||||
promote(managerId: number) {
|
||||
return this.http.get(this.url + `/manager/promote/${managerId}`)
|
||||
}
|
||||
@ -89,4 +93,9 @@ export class ApiService {
|
||||
return this.http.post(this.url + `/project/reject_request/${pid}/${wid}`, null)
|
||||
}
|
||||
|
||||
setManagerRoleOnProject(pid: number, role: number, manager: number) {
|
||||
return this.http.post(this.url + `/manager/set_role_for_project/${pid}`,
|
||||
{"role": role, "manager": manager})
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,3 @@
|
||||
.nav-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
>{{"nav.manager_list" | translate}}</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
<span class="nav-spacer"></span>
|
||||
<span class="spacer"></span>
|
||||
<button mat-button [class.mat-accent]="router.url == '/login'"
|
||||
class="nav-link" *ngIf="!authService.account"
|
||||
[routerLink]="'login'">{{"nav.login" | translate}}</button>
|
||||
|
@ -50,6 +50,8 @@ import {WorkerDashboardComponent} from './worker-dashboard/worker-dashboard.comp
|
||||
import {ProjectPermsComponent} from './project-perms/project-perms.component';
|
||||
import {ManagerListComponent} from './manager-list/manager-list.component';
|
||||
import {ProjectSelectComponent} from './project-select/project-select.component';
|
||||
import {ManagerSelectComponent} from './manager-select/manager-select.component';
|
||||
import {ProjectIconComponent} from './project-icon/project-icon.component';
|
||||
|
||||
|
||||
export function createTranslateLoader(http: HttpClient) {
|
||||
@ -72,6 +74,8 @@ export function createTranslateLoader(http: HttpClient) {
|
||||
ProjectPermsComponent,
|
||||
ManagerListComponent,
|
||||
ProjectSelectComponent,
|
||||
ManagerSelectComponent,
|
||||
ProjectIconComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -3,6 +3,7 @@ import {ApiService} from "./api.service";
|
||||
import {Credentials} from "./models/credentials";
|
||||
import {MessengerService} from "./messenger.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {Manager} from "./models/manager";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -6,13 +6,20 @@
|
||||
<mat-card-content>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{"project.name" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.name" [placeholder]="'project.name' | translate">
|
||||
<input type="text" matInput [(ngModel)]="project.name" [placeholder]="'project.name' | translate"
|
||||
required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{ "project.clone_url" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.clone_url" (change)="cloneUrlChange()"
|
||||
[placeholder]="'project.clone_url_placeholder' | translate">
|
||||
[placeholder]="'project.clone_url_placeholder' | translate" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{"project.version" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.version" name="version"
|
||||
[placeholder]="'project.version'|translate"
|
||||
>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{ "project.git_repo" | translate }}</mat-label>
|
||||
|
@ -55,7 +55,7 @@ export class ManagerListComponent implements OnInit {
|
||||
}
|
||||
|
||||
private getManagers() {
|
||||
this.apiService.getAllManagers()
|
||||
this.apiService.getManagerList()
|
||||
.subscribe(data => {
|
||||
this.data.data = data["content"]["managers"]
|
||||
},
|
||||
|
@ -0,0 +1,3 @@
|
||||
.mat-form-field {
|
||||
width: 100%;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<mat-form-field appearance="outline" style="margin-top: 1em">
|
||||
<mat-label>{{"project.manager_select" | translate}}</mat-label>
|
||||
<mat-select [(ngModel)]="manager" (selectionChange)="managerChange.emit($event.value)"
|
||||
[placeholder]="'perms.manager_select' | translate"
|
||||
(opened)="loadManagerList()">
|
||||
<mat-select-trigger></mat-select-trigger>
|
||||
<mat-option disabled *ngIf="managerList == undefined">
|
||||
{{"project_select.loading" | translate}}
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let m of managerList" [value]="m">
|
||||
<mat-icon *ngIf="m.tracker_admin">supervisor_account</mat-icon>
|
||||
<mat-icon *ngIf="!m.tracker_admin">person</mat-icon>
|
||||
{{m.username}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
@ -0,0 +1,30 @@
|
||||
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
|
||||
import {ApiService} from "../api.service";
|
||||
import {Manager} from "../models/manager";
|
||||
|
||||
@Component({
|
||||
selector: 'manager-select',
|
||||
templateUrl: './manager-select.component.html',
|
||||
styleUrls: ['./manager-select.component.css']
|
||||
})
|
||||
export class ManagerSelectComponent implements OnInit {
|
||||
|
||||
manager: Manager;
|
||||
managerList: Manager[];
|
||||
|
||||
@Output()
|
||||
managerChange = new EventEmitter<Manager>();
|
||||
|
||||
constructor(private apiService: ApiService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
loadManagerList() {
|
||||
this.apiService.getManagerList()
|
||||
.subscribe(data => this.managerList = data["content"]["managers"])
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,6 +1,54 @@
|
||||
interface Manager {
|
||||
export interface Manager {
|
||||
id: number;
|
||||
username: string
|
||||
tracker_admin: boolean
|
||||
register_time: number
|
||||
}
|
||||
|
||||
export class ManagerRoleOnProject {
|
||||
manager: Manager;
|
||||
role: number;
|
||||
|
||||
public static fromEntity(data: { role: number, manager: Manager }): ManagerRoleOnProject {
|
||||
let m = new ManagerRoleOnProject();
|
||||
m.role = data.role;
|
||||
m.manager = data.manager;
|
||||
return m;
|
||||
}
|
||||
|
||||
get readRole(): boolean {
|
||||
return (this.role & 1) != 0
|
||||
}
|
||||
|
||||
set readRole(role: boolean) {
|
||||
if (role) {
|
||||
this.role |= 1
|
||||
} else {
|
||||
this.role &= ~1
|
||||
}
|
||||
}
|
||||
|
||||
get editRole(): boolean {
|
||||
return (this.role & 2) != 0
|
||||
}
|
||||
|
||||
set editRole(role: boolean) {
|
||||
if (role) {
|
||||
this.role |= 2
|
||||
} else {
|
||||
this.role &= ~2
|
||||
}
|
||||
}
|
||||
|
||||
get manageRole(): boolean {
|
||||
return (this.role & 4) != 0
|
||||
}
|
||||
|
||||
set manageRole(role: boolean) {
|
||||
if (role) {
|
||||
this.role |= 4
|
||||
} else {
|
||||
this.role &= ~4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import {ActivatedRoute} from "@angular/router";
|
||||
|
||||
import {Chart} from "chart.js";
|
||||
import {AssignedTasks, MonitoringSnapshot} from "../models/monitoring";
|
||||
import {TranslateService} from "@ngx-translate/core";
|
||||
import {MessengerService} from "../messenger.service";
|
||||
|
||||
|
||||
@Component({
|
||||
@ -41,7 +43,10 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
lastSnapshot: MonitoringSnapshot;
|
||||
assignees: AssignedTasks[];
|
||||
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute) {
|
||||
constructor(private apiService: ApiService,
|
||||
private route: ActivatedRoute,
|
||||
private translate: TranslateService,
|
||||
private messenger: MessengerService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -305,28 +310,32 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
|
||||
private getProject() {
|
||||
this.apiService.getProject(this.projectId).subscribe((data: any) => {
|
||||
this.project = data.content.project;
|
||||
this.project = data.content.project;
|
||||
|
||||
this.apiService.getMonitoringSnapshots(60, this.projectId)
|
||||
.subscribe((data: any) => {
|
||||
this.snapshots = data.content.snapshots;
|
||||
this.lastSnapshot = this.snapshots ? this.snapshots.sort((a, b) => {
|
||||
return b.time_stamp - a.time_stamp
|
||||
})[0] : null;
|
||||
this.apiService.getMonitoringSnapshots(60, this.projectId)
|
||||
.subscribe((data: any) => {
|
||||
this.snapshots = data.content.snapshots;
|
||||
this.lastSnapshot = this.snapshots ? this.snapshots.sort((a, b) => {
|
||||
return b.time_stamp - a.time_stamp
|
||||
})[0] : null;
|
||||
|
||||
this.setupTimeline();
|
||||
this.setupStatusPie();
|
||||
this.setupTimeline();
|
||||
this.setupStatusPie();
|
||||
|
||||
if (!this.snapshots) {
|
||||
return
|
||||
}
|
||||
if (!this.snapshots) {
|
||||
return
|
||||
}
|
||||
|
||||
this.apiService.getAssigneeStats(this.projectId)
|
||||
.subscribe((data: any) => {
|
||||
this.assignees = data.content.assignees;
|
||||
this.setupAssigneesPie();
|
||||
});
|
||||
})
|
||||
})
|
||||
this.apiService.getAssigneeStats(this.projectId)
|
||||
.subscribe((data: any) => {
|
||||
this.assignees = data.content.assignees;
|
||||
this.setupAssigneesPie();
|
||||
});
|
||||
})
|
||||
},
|
||||
error => {
|
||||
this.translate.get("messenger.unauthorized").subscribe(t =>
|
||||
this.messenger.show(t))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
<mat-icon *ngIf="project.public" [title]="'project.public' | translate">public</mat-icon>
|
||||
<mat-icon *ngIf="!project.public && !project.hidden" [title]="'project.private'|translate">lock</mat-icon>
|
||||
<mat-icon *ngIf="project.hidden" [title]="'project.hidden'|translate">visibility_off</mat-icon>
|
21
web/angular/src/app/project-icon/project-icon.component.ts
Normal file
21
web/angular/src/app/project-icon/project-icon.component.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {Project} from "../models/project";
|
||||
|
||||
@Component({
|
||||
selector: 'project-icon',
|
||||
templateUrl: './project-icon.component.html',
|
||||
styleUrls: ['./project-icon.component.css']
|
||||
})
|
||||
export class ProjectIconComponent implements OnInit {
|
||||
|
||||
|
||||
@Input()
|
||||
project: Project;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,6 @@ button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
mat-panel-title > mat-icon {
|
||||
mat-panel-title > project-icon {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
@ -13,11 +13,7 @@
|
||||
<mat-expansion-panel *ngFor="let project of projects" style="margin-top: 1em">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<mat-icon *ngIf="project.public" [title]="'project.public' | translate">public</mat-icon>
|
||||
<mat-icon *ngIf="!project.public && !project.hidden" [title]="'project.private'|translate">
|
||||
lock
|
||||
</mat-icon>
|
||||
<mat-icon *ngIf="project.hidden" [title]="'project.hidden'|translate">block</mat-icon>
|
||||
<project-icon [project]="project"></project-icon>
|
||||
<span style="width: 3em">{{project.id}}</span>{{project.name}}
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>{{project.motd}}</mat-panel-description>
|
||||
|
@ -6,3 +6,7 @@ button {
|
||||
.request {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
mat-checkbox {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
@ -9,8 +9,9 @@
|
||||
<mat-card-subtitle>{{"perms.subtitle" | translate}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<mat-list *ngIf="!unauthorized">
|
||||
<mat-card-content *ngIf="!unauthorized || !auth.account">
|
||||
<h3>{{"perms.workers" | translate}}</h3>
|
||||
<mat-list *ngIf="accesses && accesses.length>0">
|
||||
<mat-list-item *ngFor="let wa of accesses" [class.request]="wa.request">
|
||||
<mat-icon mat-list-icon *ngIf="wa.submit" [title]="'perms.assign'|translate">library_add</mat-icon>
|
||||
<mat-icon mat-list-icon *ngIf="wa.assign" [title]="'perms.submit'|translate">get_app</mat-icon>
|
||||
@ -32,7 +33,33 @@
|
||||
</button>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
<p *ngIf="unauthorized" class="unauthorized">
|
||||
<p *ngIf="!accesses || accesses.length == 0">{{"perms.no_workers"|translate}}</p>
|
||||
|
||||
<h3>{{"perms.managers" | translate}}</h3>
|
||||
<manager-select (managerChange)="onSelectManager($event)"></manager-select>
|
||||
<mat-list>
|
||||
<mat-list-item *ngFor="let m of managerRoles">
|
||||
<mat-icon *ngIf="m.manager.tracker_admin">supervisor_account</mat-icon>
|
||||
<mat-icon *ngIf="!m.manager.tracker_admin">person</mat-icon>
|
||||
{{m.manager.username}}
|
||||
<span class="spacer"></span>
|
||||
<mat-checkbox [(ngModel)]="m.readRole"
|
||||
(change)="onRoleChange(m)"
|
||||
[disabled]="m.manager.id==auth.account.id"
|
||||
>{{"perms.read"|translate}}</mat-checkbox>
|
||||
<mat-checkbox [(ngModel)]="m.editRole"
|
||||
(change)="onRoleChange(m)"
|
||||
[disabled]="m.manager.id==auth.account.id"
|
||||
>{{"perms.edit"|translate}}</mat-checkbox>
|
||||
<mat-checkbox [(ngModel)]="m.manageRole"
|
||||
(change)="onRoleChange(m)"
|
||||
[disabled]="m.manager.id==auth.account.id"
|
||||
>{{"perms.manage"|translate}}</mat-checkbox>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
<mat-card-content *ngIf="unauthorized">
|
||||
<p class="unauthorized">
|
||||
<mat-icon>block</mat-icon>
|
||||
{{"perms.unauthorized" | translate}}
|
||||
</p>
|
||||
|
@ -1,12 +1,14 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ApiService} from "../api.service";
|
||||
import {Project} from "../models/project";
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {MessengerService} from "../messenger.service";
|
||||
import {TranslateService} from "@ngx-translate/core";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
|
||||
import * as moment from "moment"
|
||||
import {WorkerAccess} from "../models/worker-access";
|
||||
import {AuthService} from "../auth.service";
|
||||
import {Manager, ManagerRoleOnProject} from "../models/manager";
|
||||
import {MessengerService} from "../messenger.service";
|
||||
import {TranslateService} from "@ngx-translate/core";
|
||||
|
||||
@Component({
|
||||
selector: 'app-project-perms',
|
||||
@ -17,14 +19,15 @@ export class ProjectPermsComponent implements OnInit {
|
||||
|
||||
constructor(private apiService: ApiService,
|
||||
private route: ActivatedRoute,
|
||||
private messengerService: MessengerService,
|
||||
private translate: TranslateService,
|
||||
private router: Router) {
|
||||
private messenger: MessengerService,
|
||||
public auth: AuthService) {
|
||||
}
|
||||
|
||||
project: Project;
|
||||
private projectId: number;
|
||||
accesses: WorkerAccess[];
|
||||
managerRoles: ManagerRoleOnProject;
|
||||
unauthorized: boolean = false;
|
||||
moment = moment;
|
||||
|
||||
@ -33,17 +36,24 @@ export class ProjectPermsComponent implements OnInit {
|
||||
this.projectId = params["id"];
|
||||
this.getProject();
|
||||
this.getProjectAccesses();
|
||||
this.getProjectManagers();
|
||||
})
|
||||
}
|
||||
|
||||
public acceptRequest(wa: WorkerAccess) {
|
||||
this.apiService.acceptWorkerAccessRequest(wa.worker.id, this.projectId)
|
||||
.subscribe(() => this.getProjectAccesses())
|
||||
.subscribe(() => {
|
||||
this.getProjectAccesses();
|
||||
this.translate.get("perms.set").subscribe(t => this.messenger.show(t));
|
||||
})
|
||||
}
|
||||
|
||||
public rejectRequest(wa: WorkerAccess) {
|
||||
this.apiService.rejectWorkerAccessRequest(wa.worker.id, this.projectId)
|
||||
.subscribe(() => this.getProjectAccesses())
|
||||
.subscribe(() => {
|
||||
this.getProjectAccesses();
|
||||
this.translate.get("perms.set").subscribe(t => this.messenger.show(t));
|
||||
})
|
||||
}
|
||||
|
||||
private getProject() {
|
||||
@ -64,7 +74,31 @@ export class ProjectPermsComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
private getProjectManagers() {
|
||||
this.apiService.getManagerListWithRoleOn(this.projectId)
|
||||
.subscribe(data => {
|
||||
this.managerRoles = data["content"]["managers"].map(d =>
|
||||
ManagerRoleOnProject.fromEntity(d))
|
||||
})
|
||||
}
|
||||
|
||||
public refresh() {
|
||||
this.getProjectAccesses()
|
||||
this.getProjectAccesses();
|
||||
this.getProjectManagers();
|
||||
}
|
||||
|
||||
public onSelectManager(manager: Manager) {
|
||||
if (manager.id != this.auth.account.id) {
|
||||
this.apiService.setManagerRoleOnProject(this.projectId, 1, manager.id)
|
||||
.subscribe(() => this.refresh())
|
||||
}
|
||||
}
|
||||
|
||||
public onRoleChange(manager: ManagerRoleOnProject) {
|
||||
this.apiService.setManagerRoleOnProject(this.projectId, manager.role, manager.manager.id)
|
||||
.subscribe(() => {
|
||||
this.refresh();
|
||||
this.translate.get("perms.set").subscribe(t => this.messenger.show(t));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,7 @@
|
||||
{{"project_select.none" | translate}}
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let p of projectList" [value]="p">
|
||||
<mat-icon *ngIf="p.public">public</mat-icon>
|
||||
<mat-icon *ngIf="!p.public">lock</mat-icon>
|
||||
<project-icon [project]="p"></project-icon>
|
||||
<span style="width: 3em; display: inline-block">{{p.id}}</span>
|
||||
{{p.name}}
|
||||
</mat-option>
|
||||
|
@ -5,25 +5,37 @@
|
||||
<mat-card-content>
|
||||
<form (ngSubmit)="onSubmit()" *ngIf="project != undefined" id="uf">
|
||||
<mat-form-field appearance="outline">
|
||||
<input type="text" matInput [(ngModel)]="project.name" name="name" placeholder="Name">
|
||||
<mat-label>{{"project.name" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.name" name="name"
|
||||
[placeholder]="'project.name'|translate"
|
||||
>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<textarea matInput [(ngModel)]="project.motd" placeholder="Message of the day"
|
||||
<mat-label>{{"project.motd" | translate}}</mat-label>
|
||||
<textarea matInput [(ngModel)]="project.motd"
|
||||
[placeholder]="'project.motd'|translate"
|
||||
name="motd"></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{"project.clone_url" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.clone_url" name="clone_url"
|
||||
placeholder="Git clone url">
|
||||
[placeholder]="'project.clone_url'|translate"
|
||||
>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{"project.version" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.version" name="version"
|
||||
[placeholder]="'project.version'|translate"
|
||||
>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{"project.git_repo" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.git_repo" name="git_repo"
|
||||
placeholder='Full repository name (e.g. "simon987/task_tracker")'>
|
||||
<mat-hint align="start">Changes on the <strong>master</strong> branch will be tracked if webhooks
|
||||
are
|
||||
enabled
|
||||
</mat-hint>
|
||||
[placeholder]="'project.git_repo_placeholder'|translate"
|
||||
>
|
||||
<mat-hint align="start">{{'project.git_repo_hint'|translate}}</mat-hint>
|
||||
</mat-form-field>
|
||||
<project-select [(project)]="selectedProject"></project-select>
|
||||
</form>
|
||||
|
@ -51,7 +51,7 @@
|
||||
},
|
||||
"project": {
|
||||
"name": "Project name",
|
||||
"clone_url": "Clone url",
|
||||
"clone_url": "Git clone url",
|
||||
"clone_url_placeholder": "Example: \"https://github.com/simon987/task_tracker\"",
|
||||
"git_repo_placeholder": "Example: \"simon987/task_tracker\"",
|
||||
"git_repo_hint": "Changes in the master branch will be tracked if webhooks are enabled",
|
||||
@ -65,7 +65,9 @@
|
||||
"motd": "Message of the day",
|
||||
"update": "Edit",
|
||||
"perms": "Permissions",
|
||||
"chain": "Chain tasks to"
|
||||
"chain": "Chain tasks to",
|
||||
"manager_select": "Give access to manager",
|
||||
"version": "Git version (commit hash)"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard for",
|
||||
@ -107,7 +109,14 @@
|
||||
"refresh": "Refresh",
|
||||
"pending": "(Pending)",
|
||||
"assign": "Assign",
|
||||
"submit": "Submit"
|
||||
"submit": "Submit",
|
||||
"read": "Read",
|
||||
"edit": "Edit",
|
||||
"manage": "Manage permissions",
|
||||
"set": "Changes saved",
|
||||
"workers": "Workers",
|
||||
"no_workers": "No workers have explicit access to this project",
|
||||
"managers": "Managers"
|
||||
},
|
||||
"messenger": {
|
||||
"close": "Close",
|
||||
|
@ -66,7 +66,9 @@
|
||||
"motd": "Message du jour",
|
||||
"update": "Mettre à jour",
|
||||
"perms": "Permissions",
|
||||
"chain": "Enchainer les tâches vers"
|
||||
"chain": "Enchainer les tâches vers",
|
||||
"manager_select": "Donner accès à",
|
||||
"version": "Version git (hash du commit)"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Tableau de bord pour ",
|
||||
@ -100,7 +102,7 @@
|
||||
},
|
||||
"perms": {
|
||||
"title": "Permissions du projet",
|
||||
"subtitle": "Les Workers doivent faire un requête d'acces pour pouvoir travailler sur les projets privés",
|
||||
"subtitle": "Les Workers doivent faire une requête d'acces pour pouvoir travailler sur les projets privés",
|
||||
"unauthorized": "Vous devez avoir ROLE_GESTION_ACCES sur ce project pour accéder à cette page",
|
||||
"created": "Créé le",
|
||||
"grant": "Accepter la requête",
|
||||
@ -109,7 +111,14 @@
|
||||
"refresh": "Refraichir",
|
||||
"pending": "(En attente)",
|
||||
"assign": "Assigner",
|
||||
"submit": "Soumettre"
|
||||
"submit": "Soumettre",
|
||||
"read": "Lecture",
|
||||
"edit": "Modification",
|
||||
"manage": "Gestion des permissions",
|
||||
"set": "Changements enregistrés",
|
||||
"workers": "Workers",
|
||||
"no_workers": "Aucun Worker n'a explicitement accès à ce projet",
|
||||
"managers": "Managers"
|
||||
},
|
||||
"messenger": {
|
||||
"close": "Fermer",
|
||||
|
@ -99,3 +99,12 @@ pre {
|
||||
color: #ff4081;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.mat-list-item-content > mat-icon {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user