From d44b9924e7e73beca025b836c1dd738898f628cd Mon Sep 17 00:00:00 2001 From: simon987 Date: Fri, 22 Feb 2019 20:44:27 -0500 Subject: [PATCH] Some work on project actions --- api/models.go | 4 ++ api/project.go | 1 + config.yml | 6 +-- schema.sql | 1 + storage/project.go | 27 +++++++------ storage/task.go | 4 +- test/api_project_test.go | 40 +++++++++++++++++++ test/config.yml | 2 +- test/schema.sql | 1 + .../app/admin-panel/admin-panel.component.css | 0 .../admin-panel/admin-panel.component.html | 13 ++++++ .../app/admin-panel/admin-panel.component.ts | 16 ++++++++ web/angular/src/app/app.module.ts | 9 ++++- .../are-you-sure/are-you-sure.component.css | 3 ++ .../are-you-sure/are-you-sure.component.html | 8 ++++ .../are-you-sure/are-you-sure.component.ts | 25 ++++++++++++ web/angular/src/app/models/project.ts | 1 + .../project-dashboard.component.css | 8 ++++ .../project-dashboard.component.html | 22 ++++++++++ .../project-dashboard.component.ts | 31 ++++++++++++++ .../project-icon/project-icon.component.html | 8 ++-- .../project-list/project-list.component.css | 8 ++++ .../project-list/project-list.component.html | 7 ++-- web/angular/src/assets/i18n/en.json | 16 +++++++- web/angular/src/assets/i18n/fr.json | 6 ++- 25 files changed, 237 insertions(+), 30 deletions(-) create mode 100644 web/angular/src/app/admin-panel/admin-panel.component.css create mode 100644 web/angular/src/app/admin-panel/admin-panel.component.html create mode 100644 web/angular/src/app/admin-panel/admin-panel.component.ts create mode 100644 web/angular/src/app/are-you-sure/are-you-sure.component.css create mode 100644 web/angular/src/app/are-you-sure/are-you-sure.component.html create mode 100644 web/angular/src/app/are-you-sure/are-you-sure.component.ts diff --git a/api/models.go b/api/models.go index 01d641c..d86bb9b 100644 --- a/api/models.go +++ b/api/models.go @@ -148,6 +148,7 @@ type UpdateProjectRequest struct { Public bool `json:"public"` Hidden bool `json:"hidden"` Chain int64 `json:"chain"` + Paused bool `json:"paused"` } func (req *UpdateProjectRequest) isValid() bool { @@ -204,6 +205,9 @@ func (req *SubmitTaskRequest) IsValid() bool { if req.Hash64 != 0 && req.UniqueString != "" { return false } + if req.Project == 0 { + return false + } return true } diff --git a/api/project.go b/api/project.go index 6b7d598..56ef278 100644 --- a/api/project.go +++ b/api/project.go @@ -158,6 +158,7 @@ func (api *WebAPI) UpdateProject(r *Request) { Public: updateReq.Public, Hidden: updateReq.Hidden, Chain: updateReq.Chain, + Paused: updateReq.Paused, } sess := api.Session.StartFasthttp(r.Ctx) manager := sess.Get("manager") diff --git a/config.yml b/config.yml index b12fccd..867ca8b 100755 --- a/config.yml +++ b/config.yml @@ -2,7 +2,7 @@ server: address: "0.0.0.0:42901" database: - conn_str: "user=task_tracker dbname=task_tracker sslmode=disable" + conn_str: "user=task_tracker password=task_tracker dbname=task_tracker sslmode=disable" # log_levels: ["debug", "error", "trace", "info", "warn"] log_levels: ["error", "info", "warn"] @@ -19,8 +19,8 @@ log: session: cookie_name: "tt" - expiration: "25m" + expiration: "8h" monitoring: - snapshot_interval: "60s" + snapshot_interval: "120s" history_length: "400h" diff --git a/schema.sql b/schema.sql index f5e7581..807ecc9 100755 --- a/schema.sql +++ b/schema.sql @@ -19,6 +19,7 @@ CREATE TABLE project chain INT DEFAULT NULL REFERENCES project (id), public boolean NOT NULL, hidden boolean NOT NULL, + paused boolean NOT NULL, name TEXT UNIQUE NOT NULL, clone_url TEXT NOT NULL, git_repo TEXT UNIQUE NOT NULL, diff --git a/storage/project.go b/storage/project.go index 4e80ed2..01e3713 100644 --- a/storage/project.go +++ b/storage/project.go @@ -17,6 +17,7 @@ type Project struct { Public bool `json:"public"` Hidden bool `json:"hidden"` Chain int64 `json:"chain"` + Paused bool `json:"paused"` } type AssignedTasks struct { @@ -28,10 +29,10 @@ func (database *Database) SaveProject(project *Project) (int64, error) { db := database.getDB() row := db.QueryRow(`INSERT INTO project (name, git_repo, clone_url, version, priority, - motd, public, hidden, chain) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0)) RETURNING id`, + motd, public, hidden, chain, paused) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0),$10) RETURNING id`, project.Name, project.GitRepo, project.CloneUrl, project.Version, project.Priority, project.Motd, - project.Public, project.Hidden, project.Chain) + project.Public, project.Hidden, project.Chain, project.Paused) var id int64 err := row.Scan(&id) @@ -57,7 +58,7 @@ func (database *Database) GetProject(id int64) *Project { db := database.getDB() row := db.QueryRow(`SELECT id, priority, name, clone_url, git_repo, version, - motd, public, hidden, COALESCE(chain, 0) + motd, public, hidden, COALESCE(chain, 0), paused FROM project WHERE id=$1`, id) project, err := scanProject(row) @@ -80,7 +81,7 @@ func scanProject(row *sql.Row) (*Project, error) { p := &Project{} err := row.Scan(&p.Id, &p.Priority, &p.Name, &p.CloneUrl, &p.GitRepo, &p.Version, - &p.Motd, &p.Public, &p.Hidden, &p.Chain) + &p.Motd, &p.Public, &p.Hidden, &p.Chain, &p.Paused) return p, err } @@ -89,7 +90,7 @@ func (database *Database) GetProjectWithRepoName(repoName string) *Project { db := database.getDB() row := db.QueryRow(`SELECT id, priority, name, clone_url, git_repo, version, - motd, public, hidden, COALESCE(chain, 0) FROM project WHERE LOWER(git_repo)=$1`, + motd, public, hidden, COALESCE(chain, 0), paused FROM project WHERE LOWER(git_repo)=$1`, strings.ToLower(repoName)) project, err := scanProject(row) @@ -108,11 +109,11 @@ func (database *Database) UpdateProject(project *Project) error { db := database.getDB() res, err := db.Exec(`UPDATE project - SET (priority, name, clone_url, git_repo, version, motd, public, hidden, chain) = - ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0)) - WHERE id=$10`, + SET (priority, name, clone_url, git_repo, version, motd, public, hidden, chain, paused) = + ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0), $10) + WHERE id=$11`, project.Priority, project.Name, project.CloneUrl, project.GitRepo, project.Version, project.Motd, - project.Public, project.Hidden, project.Chain, project.Id) + project.Public, project.Hidden, project.Chain, project.Paused, project.Id) if err != nil { return err } @@ -135,13 +136,13 @@ func (database Database) GetAllProjects(managerId int64) *[]Project { var err error if managerId == 0 { rows, err = db.Query(`SELECT - Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0) + Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0), paused FROM project WHERE NOT hidden ORDER BY name`) } else { rows, err = db.Query(`SELECT - Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0) + Id, priority, name, clone_url, git_repo, version, motd, public, hidden, COALESCE(chain,0), paused FROM project LEFT JOIN manager_has_role_on_project mhrop ON mhrop.project = id AND mhrop.manager=$1 WHERE NOT hidden OR mhrop.role & 1 = 1 OR (SELECT tracker_admin FROM manager WHERE id=$1) @@ -153,7 +154,7 @@ func (database Database) GetAllProjects(managerId int64) *[]Project { p := Project{} err := rows.Scan(&p.Id, &p.Priority, &p.Name, &p.CloneUrl, &p.GitRepo, &p.Version, &p.Motd, &p.Public, &p.Hidden, - &p.Chain) + &p.Chain, &p.Paused) handleErr(err) projects = append(projects, p) } diff --git a/storage/task.go b/storage/task.go index 6ebcfde..1466f77 100644 --- a/storage/task.go +++ b/storage/task.go @@ -82,7 +82,7 @@ func (database *Database) GetTask(worker *Worker) *Task { FROM task INNER JOIN project project on task.project = project.id LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1 - WHERE assignee IS NULL AND task.status=1 + WHERE NOT project.paused AND assignee IS NULL AND task.status=1 AND (project.public OR ( SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=project.id )) @@ -186,7 +186,7 @@ func (database *Database) GetTaskFromProject(worker *Worker, projectId int64) *T FROM task INNER JOIN project project on task.project = project.id LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1 - WHERE assignee IS NULL AND project.id=$2 AND status=1 + WHERE NOT project.paused AND assignee IS NULL AND project.id=$2 AND status=1 AND (project.public OR ( SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=$2 )) diff --git a/test/api_project_test.go b/test/api_project_test.go index c5f2a44..e37456d 100644 --- a/test/api_project_test.go +++ b/test/api_project_test.go @@ -142,6 +142,7 @@ func TestUpdateProjectValid(t *testing.T) { Motd: "MotdB", Public: false, Hidden: true, + Paused: true, }, pid, testAdminCtx) if updateResp.Ok != true { @@ -168,6 +169,9 @@ func TestUpdateProjectValid(t *testing.T) { if proj.Project.Hidden != true { t.Error() } + if proj.Project.Paused != true { + t.Error() + } } func TestUpdateProjectInvalid(t *testing.T) { @@ -444,6 +448,42 @@ func TestAdminShouldSeeHiddenProjectInList(t *testing.T) { } } +func TestPausedProjectShouldNotDispatchTasks(t *testing.T) { + + createTask(api.SubmitTaskRequest{ + Project: testProject, + Recipe: "...", + }, testWorker) + createTask(api.SubmitTaskRequest{ + Project: testProject, + Recipe: "...", + }, testWorker) + createTask(api.SubmitTaskRequest{ + Project: testProject, + Recipe: "...", + }, testWorker) + + task1 := getTaskFromProject(testProject, testWorker).Content.Task + if task1 == nil { + t.Error() + } + + updateProject(api.UpdateProjectRequest{ + Paused: true, + Name: "generictestproject", + }, testProject, testAdminCtx) + + task2 := getTaskFromProject(testProject, testWorker).Content.Task + if task2 != nil { + t.Error() + } + + updateProject(api.UpdateProjectRequest{ + Paused: false, + Name: "generictestproject", + }, testProject, testAdminCtx) +} + func createProjectAsAdmin(req api.CreateProjectRequest) CreateProjectAR { return createProject(req, testAdminCtx) } diff --git a/test/config.yml b/test/config.yml index c5c0edc..ae65cb8 100644 --- a/test/config.yml +++ b/test/config.yml @@ -2,7 +2,7 @@ server: address: "127.0.0.1:5001" database: - conn_str: "user=task_tracker dbname=task_tracker_test sslmode=disable" + conn_str: "user=task_tracker password=task_tracker dbname=task_tracker sslmode=disable" log_levels: ["debug", "error", "trace", "info", "warn"] git: diff --git a/test/schema.sql b/test/schema.sql index f5e7581..807ecc9 100755 --- a/test/schema.sql +++ b/test/schema.sql @@ -19,6 +19,7 @@ CREATE TABLE project chain INT DEFAULT NULL REFERENCES project (id), public boolean NOT NULL, hidden boolean NOT NULL, + paused boolean NOT NULL, name TEXT UNIQUE NOT NULL, clone_url TEXT NOT NULL, git_repo TEXT UNIQUE NOT NULL, diff --git a/web/angular/src/app/admin-panel/admin-panel.component.css b/web/angular/src/app/admin-panel/admin-panel.component.css new file mode 100644 index 0000000..e69de29 diff --git a/web/angular/src/app/admin-panel/admin-panel.component.html b/web/angular/src/app/admin-panel/admin-panel.component.html new file mode 100644 index 0000000..e52e6df --- /dev/null +++ b/web/angular/src/app/admin-panel/admin-panel.component.html @@ -0,0 +1,13 @@ +
+ + + {{"admin_panel.title"|translate}} + {{"admin_panel.subtitle"|translate}} + + + + + + + +
diff --git a/web/angular/src/app/admin-panel/admin-panel.component.ts b/web/angular/src/app/admin-panel/admin-panel.component.ts new file mode 100644 index 0000000..1a9a949 --- /dev/null +++ b/web/angular/src/app/admin-panel/admin-panel.component.ts @@ -0,0 +1,16 @@ +import {Component, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-admin-panel', + templateUrl: './admin-panel.component.html', + styleUrls: ['./admin-panel.component.css'] +}) +export class AdminPanelComponent implements OnInit { + + constructor() { + } + + ngOnInit() { + } + +} diff --git a/web/angular/src/app/app.module.ts b/web/angular/src/app/app.module.ts index b888e25..4c99976 100755 --- a/web/angular/src/app/app.module.ts +++ b/web/angular/src/app/app.module.ts @@ -12,6 +12,7 @@ import { MatButtonToggleModule, MatCardModule, MatCheckboxModule, + MatDialogModule, MatDividerModule, MatExpansionModule, MatFormFieldModule, @@ -55,6 +56,8 @@ import {ManagerSelectComponent} from './manager-select/manager-select.component' import {ProjectIconComponent} from './project-icon/project-icon.component'; import {IndexComponent} from './index/index.component'; import {ProjectSecretComponent} from './project-secret/project-secret.component'; +import {AdminPanelComponent} from './admin-panel/admin-panel.component'; +import {AreYouSureComponent} from './are-you-sure/are-you-sure.component'; export function createTranslateLoader(http: HttpClient) { @@ -81,6 +84,8 @@ export function createTranslateLoader(http: HttpClient) { ProjectIconComponent, IndexComponent, ProjectSecretComponent, + AdminPanelComponent, + AreYouSureComponent, ], imports: [ BrowserModule, @@ -120,7 +125,8 @@ export function createTranslateLoader(http: HttpClient) { MatTabsModule, MatListModule, MatButtonToggleModule, - MatStepperModule + MatStepperModule, + MatDialogModule, ], exports: [], @@ -131,6 +137,7 @@ export function createTranslateLoader(http: HttpClient) { ], entryComponents: [ SnackBarComponent, + AreYouSureComponent ], bootstrap: [AppComponent] }) diff --git a/web/angular/src/app/are-you-sure/are-you-sure.component.css b/web/angular/src/app/are-you-sure/are-you-sure.component.css new file mode 100644 index 0000000..d7bb0bf --- /dev/null +++ b/web/angular/src/app/are-you-sure/are-you-sure.component.css @@ -0,0 +1,3 @@ +.mat-dialog-actions { + justify-content: end; +} diff --git a/web/angular/src/app/are-you-sure/are-you-sure.component.html b/web/angular/src/app/are-you-sure/are-you-sure.component.html new file mode 100644 index 0000000..1bdb067 --- /dev/null +++ b/web/angular/src/app/are-you-sure/are-you-sure.component.html @@ -0,0 +1,8 @@ +

{{"dialog.confirmation"|translate}}

+
+

{{"dialog.are_you_sure"|translate}}

+
+
+ + +
diff --git a/web/angular/src/app/are-you-sure/are-you-sure.component.ts b/web/angular/src/app/are-you-sure/are-you-sure.component.ts new file mode 100644 index 0000000..bd6db00 --- /dev/null +++ b/web/angular/src/app/are-you-sure/are-you-sure.component.ts @@ -0,0 +1,25 @@ +import {Component, OnInit} from '@angular/core'; +import {MatDialogRef} from "@angular/material"; + +@Component({ + selector: 'app-are-you-sure', + templateUrl: './are-you-sure.component.html', + styleUrls: ['./are-you-sure.component.css'] +}) +export class AreYouSureComponent implements OnInit { + + constructor(public dialogRef: MatDialogRef) { + } + + ngOnInit() { + + } + + onNoClick() { + this.dialogRef.close(false) + } + + onYesClick() { + this.dialogRef.close(true) + } +} diff --git a/web/angular/src/app/models/project.ts b/web/angular/src/app/models/project.ts index 4d77415..3ce77bf 100644 --- a/web/angular/src/app/models/project.ts +++ b/web/angular/src/app/models/project.ts @@ -9,4 +9,5 @@ export interface Project { public: boolean; chain: number; hidden: boolean; + paused: boolean; } diff --git a/web/angular/src/app/project-dashboard/project-dashboard.component.css b/web/angular/src/app/project-dashboard/project-dashboard.component.css index 9611819..b229487 100644 --- a/web/angular/src/app/project-dashboard/project-dashboard.component.css +++ b/web/angular/src/app/project-dashboard/project-dashboard.component.css @@ -38,3 +38,11 @@ display: none; } } + +.project-actions { + margin-top: 1em; +} + +.project-actions button { + margin-right: 1em; +} diff --git a/web/angular/src/app/project-dashboard/project-dashboard.component.html b/web/angular/src/app/project-dashboard/project-dashboard.component.html index e64d4d0..937a39f 100644 --- a/web/angular/src/app/project-dashboard/project-dashboard.component.html +++ b/web/angular/src/app/project-dashboard/project-dashboard.component.html @@ -52,6 +52,28 @@
{{project | json}}
+ + + {{"dashboard.actions" | translate}} + + + + + + + diff --git a/web/angular/src/app/project-dashboard/project-dashboard.component.ts b/web/angular/src/app/project-dashboard/project-dashboard.component.ts index fe460eb..3159b6f 100644 --- a/web/angular/src/app/project-dashboard/project-dashboard.component.ts +++ b/web/angular/src/app/project-dashboard/project-dashboard.component.ts @@ -8,6 +8,8 @@ import {AssignedTasks, MonitoringSnapshot} from "../models/monitoring"; import {TranslateService} from "@ngx-translate/core"; import {MessengerService} from "../messenger.service"; import {AuthService} from "../auth.service"; +import {MatDialog} from "@angular/material"; +import {AreYouSureComponent} from "../are-you-sure/are-you-sure.component"; @Component({ @@ -48,6 +50,7 @@ export class ProjectDashboardComponent implements OnInit { private route: ActivatedRoute, private translate: TranslateService, public auth: AuthService, + public dialog: MatDialog, private messenger: MessengerService) { } @@ -340,4 +343,32 @@ export class ProjectDashboardComponent implements OnInit { this.messenger.show(t)) }) } + + resetFailedTasks() { + this.dialog.open(AreYouSureComponent, { + width: '250px', + }).afterClosed().subscribe(result => { + if (result) { + alert("yes") + } + }); + } + + pauseProject() { + this.dialog.open(AreYouSureComponent, { + width: '250px', + }).afterClosed().subscribe(result => { + if (result) { + this.project.paused = true; + this.apiService.updateProject(this.project).subscribe(() => { + this.translate.get("messenger.acknowledged").subscribe(t => + this.messenger.show(t)) + }) + } + }); + } + + hardReset() { + + } } diff --git a/web/angular/src/app/project-icon/project-icon.component.html b/web/angular/src/app/project-icon/project-icon.component.html index 4bde839..d6e04bf 100644 --- a/web/angular/src/app/project-icon/project-icon.component.html +++ b/web/angular/src/app/project-icon/project-icon.component.html @@ -1,3 +1,5 @@ -public -lock -visibility_off +public +lock + +visibility_off +pause diff --git a/web/angular/src/app/project-list/project-list.component.css b/web/angular/src/app/project-list/project-list.component.css index 99e25a2..3ef3c83 100755 --- a/web/angular/src/app/project-list/project-list.component.css +++ b/web/angular/src/app/project-list/project-list.component.css @@ -5,3 +5,11 @@ button { mat-panel-title > project-icon { margin-right: 1em; } + +.paused { + color: #9a9a9a; +} + +.mat-expansion-panel-header-description { + flex-grow: 0; +} diff --git a/web/angular/src/app/project-list/project-list.component.html b/web/angular/src/app/project-list/project-list.component.html index e97542a..270edfc 100755 --- a/web/angular/src/app/project-list/project-list.component.html +++ b/web/angular/src/app/project-list/project-list.component.html @@ -12,11 +12,12 @@ - + - {{project.id}}{{project.name}} + {{project.id}} + {{project.name}} - {{project.motd}} + {{project.motd}}
{{project | json}}
diff --git a/web/angular/src/assets/i18n/en.json b/web/angular/src/assets/i18n/en.json index dfdefbe..434072f 100644 --- a/web/angular/src/assets/i18n/en.json +++ b/web/angular/src/assets/i18n/en.json @@ -74,7 +74,12 @@ "title": "Dashboard for", "metadata": "Project metadata", "empty": "No tasks", - "refresh": "Refresh" + "refresh": "Refresh", + "actions": "Actions", + "reset_failed": "Reset failed tasks", + "pause": "Pause", + "resume": "Resume", + "hard_reset": "Hard_reset" }, "login": { "title": "Login", @@ -121,7 +126,8 @@ }, "messenger": { "close": "Close", - "unauthorized": "Unauthorized" + "unauthorized": "Unauthorized", + "acknowledged": "Changes saved" }, "manager_list": { "title": "Manager list", @@ -149,5 +155,11 @@ "secret": "Secret", "update": "Update", "ok": "Updated" + }, + "dialog": { + "confirmation": "Confirmation", + "are_you_sure": "Are you sure?", + "no": "No", + "ok": "Ok" } } diff --git a/web/angular/src/assets/i18n/fr.json b/web/angular/src/assets/i18n/fr.json index b9cad64..ead804d 100644 --- a/web/angular/src/assets/i18n/fr.json +++ b/web/angular/src/assets/i18n/fr.json @@ -74,7 +74,8 @@ "title": "Tableau de bord pour ", "metadata": "Métadonnés du projet", "empty": "Aucune tâche", - "refresh": "Rafraîchir" + "refresh": "Rafraîchir", + "actions": "Actions" }, "login": { "title": "Ouvrir un session", @@ -123,7 +124,8 @@ }, "messenger": { "close": "Fermer", - "unauthorized": "Non autorisé" + "unauthorized": "Non autorisé", + "acknowledged": "Changements enregistrés" }, "manager_list": { "title": "Liste ",