From f235bfb588993dfdc6713c1a44e7a2438f901ef8 Mon Sep 17 00:00:00 2001
From: simon987
Date: Tue, 19 Feb 2019 19:38:54 -0500
Subject: [PATCH] Add project secret & bug fix
---
api/main.go | 2 +
api/models.go | 12 ++
api/project.go | 156 +++++++++++++++++-
api/task.go | 10 ++
config.yml | 3 +-
main/main.go | 1 +
schema.sql | 30 ++--
storage/database.go | 2 +
storage/project.go | 33 ++++
storage/task.go | 7 +-
test/api_task_test.go | 37 +++++
test/main_test.go | 17 ++
test/schema.sql | 27 +--
web/angular/src/app/api.service.ts | 26 ++-
web/angular/src/app/app-routing.module.ts | 6 +-
web/angular/src/app/app.module.ts | 8 +-
.../manager-list/manager-list.component.ts | 1 +
.../project-dashboard.component.html | 8 +-
.../project-dashboard.component.ts | 2 +
.../project-list/project-list.component.html | 4 +
.../project-perms.component.html | 5 +-
.../project-secret.component.css | 3 +
.../project-secret.component.html | 22 +++
.../project-secret.component.ts | 46 ++++++
.../update-project.component.html | 1 +
web/angular/src/assets/i18n/en.json | 14 +-
web/angular/src/assets/i18n/fr.json | 14 +-
27 files changed, 443 insertions(+), 54 deletions(-)
create mode 100644 web/angular/src/app/project-secret/project-secret.component.css
create mode 100644 web/angular/src/app/project-secret/project-secret.component.html
create mode 100644 web/angular/src/app/project-secret/project-secret.component.ts
diff --git a/api/main.go b/api/main.go
index 1d1875c..5fbb8b6 100644
--- a/api/main.go
+++ b/api/main.go
@@ -91,6 +91,8 @@ func New() *WebAPI {
api.router.POST("/project/request_access", LogRequestMiddleware(api.CreateWorkerAccess))
api.router.POST("/project/accept_request/:id/:wid", LogRequestMiddleware(api.AcceptAccessRequest))
api.router.POST("/project/reject_request/:id/:wid", LogRequestMiddleware(api.RejectAccessRequest))
+ api.router.GET("/project/secret/:id", LogRequestMiddleware(api.GetSecret))
+ api.router.POST("/project/secret/:id", LogRequestMiddleware(api.SetSecret))
api.router.POST("/task/submit", LogRequestMiddleware(api.SubmitTask))
api.router.GET("/task/get/:project", LogRequestMiddleware(api.GetTaskFromProject))
diff --git a/api/models.go b/api/models.go
index f28686f..01d641c 100644
--- a/api/models.go
+++ b/api/models.go
@@ -214,6 +214,10 @@ type ReleaseTaskRequest struct {
Verification int64 `json:"verification"`
}
+func (r *ReleaseTaskRequest) IsValid() bool {
+ return r.TaskId != 0
+}
+
type ReleaseTaskResponse struct {
Updated bool `json:"updated"`
}
@@ -276,3 +280,11 @@ type Info struct {
Name string `json:"name"`
Version string `json:"version"`
}
+
+type SetSecretRequest struct {
+ Secret string `json:"secret"`
+}
+
+type GetSecretResponse struct {
+ Secret string `json:"secret"`
+}
diff --git a/api/project.go b/api/project.go
index e8e87be..6b7d598 100644
--- a/api/project.go
+++ b/api/project.go
@@ -10,7 +10,13 @@ import (
func (api *WebAPI) GetProject(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || id <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid worker id",
+ }, 400)
+ return
+ }
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
@@ -263,7 +269,13 @@ func (api *WebAPI) GetProjectList(r *Request) {
func (api *WebAPI) GetAssigneeStatsForProject(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || id <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid worker id",
+ }, 400)
+ return
+ }
stats := api.Database.GetAssigneeStats(id, 16)
@@ -281,7 +293,13 @@ func (api *WebAPI) GetWorkerAccessListForProject(r *Request) {
manager := sess.Get("manager")
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || id <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid worker id",
+ }, 400)
+ return
+ }
if !isActionOnProjectAuthorized(id, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
r.Json(JsonResponse{
@@ -352,10 +370,22 @@ func (api *WebAPI) CreateWorkerAccess(r *Request) {
func (api *WebAPI) AcceptAccessRequest(r *Request) {
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || pid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid worker id",
+ }, 400)
+ return
+ }
wid, err := strconv.ParseInt(r.Ctx.UserValue("wid").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || wid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid worker id",
+ }, 400)
+ return
+ }
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
@@ -385,10 +415,22 @@ func (api *WebAPI) AcceptAccessRequest(r *Request) {
func (api *WebAPI) RejectAccessRequest(r *Request) {
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || pid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid project id",
+ }, 400)
+ return
+ }
wid, err := strconv.ParseInt(r.Ctx.UserValue("wid").(string), 10, 64)
- handleErr(err, r) //todo handle invalid id
+ if err != nil || wid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid worker id",
+ }, 400)
+ return
+ }
ok := api.Database.RejectAccessRequest(wid, pid)
@@ -407,7 +449,13 @@ 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
+ if err != nil || pid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid project id",
+ }, 400)
+ return
+ }
req := &SetManagerRoleOnProjectRequest{}
err = json.Unmarshal(r.Ctx.Request.Body(), req)
@@ -435,3 +483,95 @@ func (api *WebAPI) SetManagerRoleOnProject(r *Request) {
Ok: true,
})
}
+
+func (api *WebAPI) SetSecret(r *Request) {
+
+ pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
+ handleErr(err, r) //todo handle invalid id
+ if err != nil || pid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid project id",
+ }, 400)
+ return
+ }
+
+ sess := api.Session.StartFasthttp(r.Ctx)
+ manager := sess.Get("manager")
+
+ if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_EDIT, api.Database) {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Unauthorized",
+ }, 403)
+ return
+ }
+
+ req := &SetSecretRequest{}
+ err = json.Unmarshal(r.Ctx.Request.Body(), req)
+ if err != nil {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Could not parse request",
+ }, 400)
+ return
+ }
+
+ api.Database.SetSecret(pid, req.Secret)
+
+ r.OkJson(JsonResponse{
+ Ok: true,
+ })
+}
+
+func (api *WebAPI) GetSecret(r *Request) {
+
+ pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
+ if err != nil || pid <= 0 {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid project id",
+ }, 400)
+ return
+ }
+
+ var secret string
+
+ worker, err := api.validateSignature(r)
+ if err == nil {
+ secret, err = api.Database.GetSecret(pid, worker.Id)
+ if err != nil {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Unauthorized",
+ }, 403)
+ return
+ }
+ r.OkJson(JsonResponse{
+ Ok: true,
+ Content: GetSecretResponse{
+ Secret: secret,
+ },
+ })
+ return
+ }
+
+ sess := api.Session.StartFasthttp(r.Ctx)
+ manager := sess.Get("manager")
+
+ if !isActionOnProjectAuthorized(pid, manager, storage.ROLE_EDIT, api.Database) {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Unauthorized",
+ }, 403)
+ return
+ }
+
+ secret, _ = api.Database.GetSecret(pid, 0)
+ r.OkJson(JsonResponse{
+ Ok: true,
+ Content: GetSecretResponse{
+ Secret: secret,
+ },
+ })
+}
diff --git a/api/task.go b/api/task.go
index 4a6c8b1..ad1e34d 100644
--- a/api/task.go
+++ b/api/task.go
@@ -209,7 +209,17 @@ func (api *WebAPI) ReleaseTask(r *Request) {
Ok: false,
Message: "Could not parse request",
}, 400)
+ return
}
+
+ if !req.IsValid() {
+ r.Json(JsonResponse{
+ Ok: false,
+ Message: "Invalid request",
+ }, 400)
+ return
+ }
+
res := api.Database.ReleaseTask(req.TaskId, worker.Id, req.Result, req.Verification)
response := JsonResponse{
diff --git a/config.yml b/config.yml
index 56629c3..2a4100c 100755
--- a/config.yml
+++ b/config.yml
@@ -3,7 +3,8 @@ server:
database:
conn_str: "user=task_tracker dbname=task_tracker_test sslmode=disable"
- log_levels: ["debug", "error", "trace", "info", "warn"]
+ # log_levels: ["debug", "error", "trace", "info", "warn"]
+ log_levels: ["error", "info", "warn"]
git:
webhook_secret: "very_secret_secret"
diff --git a/main/main.go b/main/main.go
index a9c3500..2be616d 100644
--- a/main/main.go
+++ b/main/main.go
@@ -3,6 +3,7 @@ package main
import (
"github.com/simon987/task_tracker/api"
"github.com/simon987/task_tracker/config"
+ //"github.com/simon987/task_tracker/storage"
"math/rand"
"time"
)
diff --git a/schema.sql b/schema.sql
index 669298c..f5e7581 100755
--- a/schema.sql
+++ b/schema.sql
@@ -1,8 +1,6 @@
DROP TABLE IF EXISTS worker, project, task, log_entry,
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task;
-DROP TYPE IF EXISTS status;
-DROP TYPE IF EXISTS log_level;
CREATE TABLE worker
(
@@ -25,7 +23,8 @@ CREATE TABLE project
clone_url TEXT NOT NULL,
git_repo TEXT UNIQUE NOT NULL,
version TEXT NOT NULL,
- motd TEXT NOT NULL
+ motd TEXT NOT NULL,
+ secret TEXT NOT NULL DEFAULT '{}'
);
CREATE TABLE worker_access
@@ -83,7 +82,8 @@ CREATE TABLE manager_has_role_on_project
(
manager INTEGER REFERENCES manager (id) NOT NULL,
role SMALLINT NOT NULL,
- project INTEGER REFERENCES project (id) NOT NULL
+ project INTEGER REFERENCES project (id) NOT NULL,
+ PRIMARY KEY (manager, project)
);
CREATE TABLE project_monitoring_snapshot
@@ -102,14 +102,18 @@ $$
DECLARE
chain INTEGER;
BEGIN
- UPDATE project SET closed_task_count=closed_task_count + 1 WHERE id = OLD.project returning project.chain into chain;
- UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
- IF chain != 0 THEN
- INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
- priority, retries, max_retries, status, recipe)
- VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
- old.verification_count, old.priority, 0, old.max_retries, 1,
- old.recipe);
+ if OLD.assignee IS NOT NULL THEN
+ UPDATE project
+ SET closed_task_count=closed_task_count + 1
+ WHERE id = OLD.project returning project.chain into chain;
+ UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
+ IF chain != 0 THEN
+ INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
+ priority, retries, max_retries, status, recipe)
+ VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
+ old.verification_count, old.priority, 0, old.max_retries, 1,
+ old.recipe);
+ end if;
end if;
RETURN OLD;
END;
@@ -135,7 +139,7 @@ CREATE TRIGGER on_manager_insert
FOR EACH ROW
EXECUTE PROCEDURE on_manager_insert();
-CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver INT) RETURNS BOOLEAN AS
+CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
$$
DECLARE
res INT = NULL;
diff --git a/storage/database.go b/storage/database.go
index ba14894..aaba528 100644
--- a/storage/database.go
+++ b/storage/database.go
@@ -39,6 +39,8 @@ func (database *Database) getDB() *sql.DB {
logrus.Fatal(err)
}
+ db.SetMaxOpenConns(50)
+
database.db = db
} else {
err := database.db.Ping()
diff --git a/storage/project.go b/storage/project.go
index b35d600..4e80ed2 100644
--- a/storage/project.go
+++ b/storage/project.go
@@ -192,3 +192,36 @@ func (database *Database) GetAssigneeStats(pid int64, count int64) *[]AssignedTa
return &assignees
}
+
+func (database *Database) GetSecret(pid int64, workerId int64) (secret string, err error) {
+
+ db := database.getDB()
+
+ var row *sql.Row
+ if workerId == 0 {
+ row = db.QueryRow(`SELECT secret FROM project WHERE id=$1`, pid)
+ } else {
+ row = db.QueryRow(`SELECT secret FROM project
+ WHERE id =$1 AND (
+ SELECT a.role_assign FROM worker_access a WHERE a.worker=$2 AND a.project=$1
+ )`, pid, workerId)
+ }
+
+ err = row.Scan(&secret)
+ handleErr(err)
+ return
+}
+
+func (database *Database) SetSecret(pid int64, secret string) {
+
+ db := database.getDB()
+
+ res, err := db.Exec(`UPDATE project SET secret=$1 WHERE id=$2`, secret, pid)
+ handleErr(err)
+
+ rowsAffected, _ := res.RowsAffected()
+ logrus.WithFields(logrus.Fields{
+ "rowsAffected": rowsAffected,
+ "project": pid,
+ }).Info("Set secret")
+}
diff --git a/storage/task.go b/storage/task.go
index d932af2..6ebcfde 100644
--- a/storage/task.go
+++ b/storage/task.go
@@ -83,7 +83,7 @@ func (database *Database) GetTask(worker *Worker) *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
- AND (project.public OR EXISTS (
+ AND (project.public OR (
SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=project.id
))
AND wvt.task IS NULL
@@ -144,9 +144,10 @@ func (database Database) ReleaseTask(id int64, workerId int64, result TaskResult
var taskUpdated bool
if result == TR_OK {
- row := db.QueryRow(`SELECT release_task_ok($1,$2,$3)`, workerId, id, verification)
+ row := db.QueryRow(fmt.Sprintf(`SELECT release_task_ok(%d,%d,%d)`, workerId, id, verification))
- _ = row.Scan(&taskUpdated)
+ err := row.Scan(&taskUpdated)
+ handleErr(err)
} else if result == TR_FAIL {
res, err := db.Exec(`UPDATE task SET (status, assignee, retries) =
(CASE WHEN retries+1 >= max_retries THEN 2 ELSE 1 END, NULL, retries+1)
diff --git a/test/api_task_test.go b/test/api_task_test.go
index 21f8868..6357f62 100644
--- a/test/api_task_test.go
+++ b/test/api_task_test.go
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/simon987/task_tracker/api"
"github.com/simon987/task_tracker/storage"
+ "math"
"testing"
)
@@ -780,6 +781,42 @@ func TestTaskChain(t *testing.T) {
}
}
+func TestTaskReleaseBigInt(t *testing.T) {
+
+ createTask(api.SubmitTaskRequest{
+ Project: testProject,
+ VerificationCount: 1,
+ Recipe: "bigint",
+ }, testWorker)
+ createTask(api.SubmitTaskRequest{
+ Project: testProject,
+ VerificationCount: 1,
+ Recipe: "smallint",
+ }, testWorker)
+
+ tid := getTaskFromProject(testProject, testWorker).Content.Task.Id
+ tid2 := getTaskFromProject(testProject, testWorker).Content.Task.Id
+
+ r := releaseTask(api.ReleaseTaskRequest{
+ Verification: math.MaxInt64,
+ Result: storage.TR_OK,
+ TaskId: tid,
+ }, testWorker)
+
+ r2 := releaseTask(api.ReleaseTaskRequest{
+ Verification: math.MinInt64,
+ Result: storage.TR_OK,
+ TaskId: tid2,
+ }, testWorker)
+
+ if r.Content.Updated != true {
+ t.Error()
+ }
+ if r2.Content.Updated != true {
+ t.Error()
+ }
+}
+
func createTask(request api.SubmitTaskRequest, worker *storage.Worker) (ar api.JsonResponse) {
r := Post("/task/submit", request, worker, nil)
UnmarshalResponse(r, &ar)
diff --git a/test/main_test.go b/test/main_test.go
index c36c9d7..291883b 100644
--- a/test/main_test.go
+++ b/test/main_test.go
@@ -3,6 +3,7 @@ package test
import (
"github.com/simon987/task_tracker/api"
"github.com/simon987/task_tracker/config"
+ "github.com/simon987/task_tracker/storage"
"net/http"
"testing"
"time"
@@ -12,6 +13,9 @@ var testApi *api.WebAPI
var testAdminCtx *http.Client
var testUserCtx *http.Client
+var testProject int64
+var testWorker *storage.Worker
+
func TestMain(m *testing.M) {
config.SetupConfig()
@@ -25,6 +29,19 @@ func TestMain(m *testing.M) {
testAdminCtx = getSessionCtx("testadmin", "testadmin", true)
testUserCtx = getSessionCtx("testuser", "testuser", false)
+ testProject = createProjectAsAdmin(api.CreateProjectRequest{
+ Name: "generictestproject",
+ Public: false,
+ }).Content.Id
+ testWorker = createWorker(api.CreateWorkerRequest{
+ Alias: "generictestworker",
+ }).Content.Worker
+ requestAccess(api.CreateWorkerAccessRequest{
+ Project: testProject,
+ Assign: true,
+ Submit: true,
+ }, testWorker)
+ acceptAccessRequest(testProject, testWorker.Id, testAdminCtx)
m.Run()
}
diff --git a/test/schema.sql b/test/schema.sql
index 650492b..f5e7581 100755
--- a/test/schema.sql
+++ b/test/schema.sql
@@ -1,8 +1,6 @@
DROP TABLE IF EXISTS worker, project, task, log_entry,
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task;
-DROP TYPE IF EXISTS status;
-DROP TYPE IF EXISTS log_level;
CREATE TABLE worker
(
@@ -25,7 +23,8 @@ CREATE TABLE project
clone_url TEXT NOT NULL,
git_repo TEXT UNIQUE NOT NULL,
version TEXT NOT NULL,
- motd TEXT NOT NULL
+ motd TEXT NOT NULL,
+ secret TEXT NOT NULL DEFAULT '{}'
);
CREATE TABLE worker_access
@@ -103,14 +102,18 @@ $$
DECLARE
chain INTEGER;
BEGIN
- UPDATE project SET closed_task_count=closed_task_count + 1 WHERE id = OLD.project returning project.chain into chain;
- UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
- IF chain != 0 THEN
- INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
- priority, retries, max_retries, status, recipe)
- VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
- old.verification_count, old.priority, 0, old.max_retries, 1,
- old.recipe);
+ if OLD.assignee IS NOT NULL THEN
+ UPDATE project
+ SET closed_task_count=closed_task_count + 1
+ WHERE id = OLD.project returning project.chain into chain;
+ UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
+ IF chain != 0 THEN
+ INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
+ priority, retries, max_retries, status, recipe)
+ VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
+ old.verification_count, old.priority, 0, old.max_retries, 1,
+ old.recipe);
+ end if;
end if;
RETURN OLD;
END;
@@ -136,7 +139,7 @@ CREATE TRIGGER on_manager_insert
FOR EACH ROW
EXECUTE PROCEDURE on_manager_insert();
-CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver INT) RETURNS BOOLEAN AS
+CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
$$
DECLARE
res INT = NULL;
diff --git a/web/angular/src/app/api.service.ts b/web/angular/src/app/api.service.ts
index 236b47a..80c4f1a 100755
--- a/web/angular/src/app/api.service.ts
+++ b/web/angular/src/app/api.service.ts
@@ -6,7 +6,7 @@ import {Credentials} from "./models/credentials";
@Injectable()
export class ApiService {
- private url: string = "http://localhost/api";
+ public url: string = "http://localhost/api";
private options: {
withCredentials: true,
responseType: "json"
@@ -66,36 +66,44 @@ export class ApiService {
}
getProjectAccess(project: number) {
- return this.http.get(this.url + `/project/access_list/${project}`)
+ return this.http.get(this.url + `/project/access_list/${project}`, this.options)
}
getManagerList() {
- return this.http.get(this.url + "/manager/list")
+ return this.http.get(this.url + "/manager/list", this.options)
}
getManagerListWithRoleOn(project: number) {
- return this.http.get(this.url + "/manager/list_for_project/" + project)
+ return this.http.get(this.url + "/manager/list_for_project/" + project, this.options)
}
promote(managerId: number) {
- return this.http.get(this.url + `/manager/promote/${managerId}`)
+ return this.http.get(this.url + `/manager/promote/${managerId}`, this.options)
}
demote(managerId: number) {
- return this.http.get(this.url + `/manager/demote/${managerId}`)
+ return this.http.get(this.url + `/manager/demote/${managerId}`, this.options)
}
acceptWorkerAccessRequest(wid: number, pid: number) {
- return this.http.post(this.url + `/project/accept_request/${pid}/${wid}`, null)
+ return this.http.post(this.url + `/project/accept_request/${pid}/${wid}`, null, this.options)
}
rejectWorkerAccessRequest(wid: number, pid: number) {
- return this.http.post(this.url + `/project/reject_request/${pid}/${wid}`, null)
+ return this.http.post(this.url + `/project/reject_request/${pid}/${wid}`, null, this.options)
}
setManagerRoleOnProject(pid: number, role: number, manager: number) {
return this.http.post(this.url + `/manager/set_role_for_project/${pid}`,
- {"role": role, "manager": manager})
+ {"role": role, "manager": manager}, this.options)
+ }
+
+ getSecret(pid: number) {
+ return this.http.get(this.url + `/project/secret/${pid}`,)
+ }
+
+ setSecret(pid: number, secret: string) {
+ return this.http.post(this.url + `/project/secret/${pid}`, {"secret": secret})
}
}
diff --git a/web/angular/src/app/app-routing.module.ts b/web/angular/src/app/app-routing.module.ts
index 65f4b76..b8ebdc3 100755
--- a/web/angular/src/app/app-routing.module.ts
+++ b/web/angular/src/app/app-routing.module.ts
@@ -13,8 +13,11 @@ import {AccountDetailsComponent} from "./account-details/account-details.compone
import {WorkerDashboardComponent} from "./worker-dashboard/worker-dashboard.component";
import {ProjectPermsComponent} from "./project-perms/project-perms.component";
import {ManagerListComponent} from "./manager-list/manager-list.component";
+import {IndexComponent} from "./index/index.component";
+import {ProjectSecretComponent} from "./project-secret/project-secret.component";
const routes: Routes = [
+ {path: "", component: IndexComponent},
{path: "log", component: LogsComponent},
{path: "login", component: LoginComponent},
{path: "account", component: AccountDetailsComponent},
@@ -22,9 +25,10 @@ const routes: Routes = [
{path: "project/:id", component: ProjectDashboardComponent},
{path: "project/:id/update", component: UpdateProjectComponent},
{path: "project/:id/perms", component: ProjectPermsComponent},
+ {path: "project/:id/secret", component: ProjectSecretComponent},
{path: "new_project", component: CreateProjectComponent},
{path: "workers", component: WorkerDashboardComponent},
- {path: "manager_list", component: ManagerListComponent}
+ {path: "manager_list", component: ManagerListComponent},
];
@NgModule({
diff --git a/web/angular/src/app/app.module.ts b/web/angular/src/app/app.module.ts
index f9ebf6e..b888e25 100755
--- a/web/angular/src/app/app.module.ts
+++ b/web/angular/src/app/app.module.ts
@@ -27,6 +27,7 @@ import {
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
+ MatStepperModule,
MatTableModule,
MatTabsModule,
MatToolbarModule,
@@ -52,6 +53,8 @@ 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';
+import {IndexComponent} from './index/index.component';
+import {ProjectSecretComponent} from './project-secret/project-secret.component';
export function createTranslateLoader(http: HttpClient) {
@@ -76,6 +79,8 @@ export function createTranslateLoader(http: HttpClient) {
ProjectSelectComponent,
ManagerSelectComponent,
ProjectIconComponent,
+ IndexComponent,
+ ProjectSecretComponent,
],
imports: [
BrowserModule,
@@ -114,7 +119,8 @@ export function createTranslateLoader(http: HttpClient) {
MatProgressBarModule,
MatTabsModule,
MatListModule,
- MatButtonToggleModule
+ MatButtonToggleModule,
+ MatStepperModule
],
exports: [],
diff --git a/web/angular/src/app/manager-list/manager-list.component.ts b/web/angular/src/app/manager-list/manager-list.component.ts
index 989e8cf..dd95ba0 100644
--- a/web/angular/src/app/manager-list/manager-list.component.ts
+++ b/web/angular/src/app/manager-list/manager-list.component.ts
@@ -6,6 +6,7 @@ import {MatPaginator, MatSort, MatTableDataSource} from "@angular/material";
import * as moment from "moment"
import {AuthService} from "../auth.service";
+import {Manager} from "../models/manager";
@Component({
selector: 'app-manager-list',
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 cd73769..a037c13 100644
--- a/web/angular/src/app/project-dashboard/project-dashboard.component.html
+++ b/web/angular/src/app/project-dashboard/project-dashboard.component.html
@@ -56,11 +56,13 @@
-
-
+
-
+
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 bc29c98..fe460eb 100644
--- a/web/angular/src/app/project-dashboard/project-dashboard.component.ts
+++ b/web/angular/src/app/project-dashboard/project-dashboard.component.ts
@@ -7,6 +7,7 @@ import {Chart} from "chart.js";
import {AssignedTasks, MonitoringSnapshot} from "../models/monitoring";
import {TranslateService} from "@ngx-translate/core";
import {MessengerService} from "../messenger.service";
+import {AuthService} from "../auth.service";
@Component({
@@ -46,6 +47,7 @@ export class ProjectDashboardComponent implements OnInit {
constructor(private apiService: ApiService,
private route: ActivatedRoute,
private translate: TranslateService,
+ public auth: AuthService,
private messenger: MessengerService) {
}
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 8e3fffe..e97542a 100755
--- a/web/angular/src/app/project-list/project-list.component.html
+++ b/web/angular/src/app/project-list/project-list.component.html
@@ -29,6 +29,10 @@
*ngIf="authService.logged">
perm_identity
{{"project.perms" | translate}}
+
diff --git a/web/angular/src/app/project-perms/project-perms.component.html b/web/angular/src/app/project-perms/project-perms.component.html
index 44cc861..4cb384b 100644
--- a/web/angular/src/app/project-perms/project-perms.component.html
+++ b/web/angular/src/app/project-perms/project-perms.component.html
@@ -9,7 +9,7 @@
{{"perms.subtitle" | translate}}
-
+
{{"perms.workers" | translate}}
0">
@@ -65,5 +65,8 @@
+
+
+
diff --git a/web/angular/src/app/project-secret/project-secret.component.css b/web/angular/src/app/project-secret/project-secret.component.css
new file mode 100644
index 0000000..ef0ee71
--- /dev/null
+++ b/web/angular/src/app/project-secret/project-secret.component.css
@@ -0,0 +1,3 @@
+.mat-form-field {
+ width: 100%;
+}
diff --git a/web/angular/src/app/project-secret/project-secret.component.html b/web/angular/src/app/project-secret/project-secret.component.html
new file mode 100644
index 0000000..bae32f1
--- /dev/null
+++ b/web/angular/src/app/project-secret/project-secret.component.html
@@ -0,0 +1,22 @@
+
+
+
+ {{"secret.title" | translate}}
+ {{"secret.subtitle" | translate}}
+
+
+
+
+ {{"secret.secret" | translate}}
+
+
+
+
+
+
+
+
+
diff --git a/web/angular/src/app/project-secret/project-secret.component.ts b/web/angular/src/app/project-secret/project-secret.component.ts
new file mode 100644
index 0000000..d2ed4f4
--- /dev/null
+++ b/web/angular/src/app/project-secret/project-secret.component.ts
@@ -0,0 +1,46 @@
+import {Component, OnInit} from '@angular/core';
+import {AuthService} from "../auth.service";
+import {ApiService} from "../api.service";
+import {ActivatedRoute} from "@angular/router";
+import {TranslateService} from "@ngx-translate/core";
+import {MessengerService} from "../messenger.service";
+
+@Component({
+ selector: 'app-project-secret',
+ templateUrl: './project-secret.component.html',
+ styleUrls: ['./project-secret.component.css']
+})
+export class ProjectSecretComponent implements OnInit {
+
+ secret: string;
+ projectId: number;
+
+ constructor(private auth: AuthService,
+ private apiService: ApiService,
+ private translate: TranslateService,
+ private messenger: MessengerService,
+ private route: ActivatedRoute) {
+ }
+
+ ngOnInit() {
+ this.route.params.subscribe(params => {
+ this.projectId = params["id"];
+ this.getSecret();
+ });
+ }
+
+ getSecret() {
+ this.apiService.getSecret(this.projectId).subscribe(data => {
+ this.secret = data["content"]["secret"]
+ }, error => {
+ this.translate.get("messenger.unauthorized").subscribe(t => this.messenger.show(t))
+ })
+ }
+
+ onUpdate() {
+ this.apiService.setSecret(this.projectId, this.secret).subscribe(data => {
+ this.translate.get("secret.ok").subscribe(t => this.messenger.show(t))
+ })
+
+ }
+}
diff --git a/web/angular/src/app/update-project/update-project.component.html b/web/angular/src/app/update-project/update-project.component.html
index e1a6630..628c7ca 100644
--- a/web/angular/src/app/update-project/update-project.component.html
+++ b/web/angular/src/app/update-project/update-project.component.html
@@ -41,6 +41,7 @@
+
diff --git a/web/angular/src/assets/i18n/en.json b/web/angular/src/assets/i18n/en.json
index e4fa40b..dfdefbe 100644
--- a/web/angular/src/assets/i18n/en.json
+++ b/web/angular/src/assets/i18n/en.json
@@ -67,7 +67,8 @@
"perms": "Permissions",
"chain": "Chain tasks to",
"manager_select": "Give access to manager",
- "version": "Git version (commit hash)"
+ "version": "Git version (commit hash)",
+ "secret": "Secret"
},
"dashboard": {
"title": "Dashboard for",
@@ -137,5 +138,16 @@
"project_select": {
"list_loading": "Loading project list...",
"none": "None"
+ },
+ "index": {
+ "version": "Latest commit hash here",
+ "alias": "Relevent alias"
+ },
+ "secret": {
+ "title": "Project secret",
+ "subtitle": "You can set project configuration here. It is only accessible by workers with ASSIGN access to this project",
+ "secret": "Secret",
+ "update": "Update",
+ "ok": "Updated"
}
}
diff --git a/web/angular/src/assets/i18n/fr.json b/web/angular/src/assets/i18n/fr.json
index 827db1d..b9cad64 100644
--- a/web/angular/src/assets/i18n/fr.json
+++ b/web/angular/src/assets/i18n/fr.json
@@ -118,7 +118,8 @@
"set": "Changements enregistrés",
"workers": "Workers",
"no_workers": "Aucun Worker n'a explicitement accès à ce projet",
- "managers": "Managers"
+ "managers": "Managers",
+ "secret": "Secret"
},
"messenger": {
"close": "Fermer",
@@ -139,6 +140,17 @@
"project_select": {
"list_loading": "Chargement de la liste de projets...",
"none": "Aucun"
+ },
+ "index": {
+ "version": "Le dernier hash de commit",
+ "alias": "Alias pertinent"
+ },
+ "secret": {
+ "title": "Secret",
+ "subtitle": "Vous pouvez définir la configuration du projet ici. Ce n'est accessible que par les Workers ayant accès au projet",
+ "secret": "Secret",
+ "update": "Mettre à jour",
+ "ok": "Mis à jour"
}
}