rework worker permissions

This commit is contained in:
simon987 2019-02-16 16:18:28 -05:00
parent e079fc8497
commit 8784b536d3
20 changed files with 454 additions and 328 deletions

View File

@ -80,9 +80,6 @@ func New() *WebAPI {
api.router.GET("/worker/get/:id", LogRequestMiddleware(api.WorkerGet)) api.router.GET("/worker/get/:id", LogRequestMiddleware(api.WorkerGet))
api.router.GET("/worker/stats", LogRequestMiddleware(api.GetAllWorkerStats)) api.router.GET("/worker/stats", LogRequestMiddleware(api.GetAllWorkerStats))
api.router.POST("/access/grant", LogRequestMiddleware(api.WorkerGrantAccess))
api.router.POST("/access/remove", LogRequestMiddleware(api.WorkerRemoveAccess))
api.router.POST("/project/create", LogRequestMiddleware(api.ProjectCreate)) api.router.POST("/project/create", LogRequestMiddleware(api.ProjectCreate))
api.router.GET("/project/get/:id", LogRequestMiddleware(api.ProjectGet)) api.router.GET("/project/get/:id", LogRequestMiddleware(api.ProjectGet))
api.router.POST("/project/update/:id", LogRequestMiddleware(api.ProjectUpdate)) api.router.POST("/project/update/:id", LogRequestMiddleware(api.ProjectUpdate))
@ -90,8 +87,10 @@ func New() *WebAPI {
api.router.GET("/project/monitoring-between/:id", LogRequestMiddleware(api.GetSnapshotsBetween)) api.router.GET("/project/monitoring-between/:id", LogRequestMiddleware(api.GetSnapshotsBetween))
api.router.GET("/project/monitoring/:id", LogRequestMiddleware(api.GetNSnapshots)) api.router.GET("/project/monitoring/:id", LogRequestMiddleware(api.GetNSnapshots))
api.router.GET("/project/assignees/:id", LogRequestMiddleware(api.ProjectGetAssigneeStats)) api.router.GET("/project/assignees/:id", LogRequestMiddleware(api.ProjectGetAssigneeStats))
api.router.GET("/project/requests/:id", LogRequestMiddleware(api.ProjectGetAccessRequests)) api.router.GET("/project/accesses/:id", LogRequestMiddleware(api.ProjectGetWorkerAccesses))
api.router.GET("/project/request_access/:id", LogRequestMiddleware(api.WorkerRequestAccess)) api.router.POST("/project/request_access", LogRequestMiddleware(api.WorkerRequestAccess))
api.router.POST("/project/accept_request/:id/:wid", LogRequestMiddleware(api.AcceptAccessRequest))
api.router.POST("/project/reject_request/:id/:wid", LogRequestMiddleware(api.RejectAccessRequest))
api.router.POST("/task/create", LogRequestMiddleware(api.TaskCreate)) api.router.POST("/task/create", LogRequestMiddleware(api.TaskCreate))
api.router.GET("/task/get/:project", LogRequestMiddleware(api.TaskGetFromProject)) api.router.GET("/task/get/:project", LogRequestMiddleware(api.TaskGetFromProject))

View File

@ -59,7 +59,7 @@ type GetAssigneeStatsResponse struct {
Assignees *[]storage.AssignedTasks `json:"assignees"` Assignees *[]storage.AssignedTasks `json:"assignees"`
} }
type WorkerRequestAccessResponse struct { type WorkerAccessRequestResponse struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
} }
@ -67,7 +67,7 @@ type WorkerRequestAccessResponse struct {
type ProjectGetAccessRequestsResponse struct { type ProjectGetAccessRequestsResponse struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
Requests *[]storage.Worker `json:"requests,omitempty"` Accesses *[]storage.WorkerAccess `json:"accesses,omitempty"`
} }
func (api *WebAPI) ProjectCreate(r *Request) { func (api *WebAPI) ProjectCreate(r *Request) {
@ -187,7 +187,7 @@ func (api *WebAPI) ProjectUpdate(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx) sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager") manager := sess.Get("manager")
if !isProjectUpdateAuthorized(project, manager, api.Database) { if !isActionAuthorized(project.Id, manager, storage.ROLE_EDIT, api.Database) {
r.Json(CreateProjectResponse{ r.Json(CreateProjectResponse{
Ok: false, Ok: false,
Message: "Unauthorized", Message: "Unauthorized",
@ -245,7 +245,8 @@ func isProjectCreationAuthorized(project *storage.Project, manager interface{})
return true return true
} }
func isProjectUpdateAuthorized(project *storage.Project, manager interface{}, db *storage.Database) bool { func isActionAuthorized(project int64, manager interface{},
requiredRole storage.ManagerRole, db *storage.Database) bool {
if manager == nil { if manager == nil {
return false return false
@ -255,8 +256,8 @@ func isProjectUpdateAuthorized(project *storage.Project, manager interface{}, db
return true return true
} }
role := db.GetManagerRoleOn(manager.(*storage.Manager), project.Id) role := db.GetManagerRoleOn(manager.(*storage.Manager), project)
if role&storage.ROLE_EDIT == 1 { if role&requiredRole != 0 {
return true return true
} }
@ -347,7 +348,7 @@ func (api *WebAPI) ProjectGetAssigneeStats(r *Request) {
}) })
} }
func (api *WebAPI) ProjectGetAccessRequests(r *Request) { func (api *WebAPI) ProjectGetWorkerAccesses(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx) sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager") manager := sess.Get("manager")
@ -355,55 +356,120 @@ func (api *WebAPI) ProjectGetAccessRequests(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64) id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
handleErr(err, r) //todo handle invalid id handleErr(err, r) //todo handle invalid id
if manager == nil { if !isActionAuthorized(id, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
r.Json(ProjectGetAccessRequestsResponse{
Ok: false,
Message: "Unauthorized",
}, 401)
return
}
if !manager.(*storage.Manager).WebsiteAdmin &&
api.Database.GetManagerRoleOn(manager.(*storage.Manager), 1)&
storage.ROLE_MANAGE_ACCESS == 0 {
r.Json(ProjectGetAccessRequestsResponse{ r.Json(ProjectGetAccessRequestsResponse{
Ok: false, Ok: false,
Message: "Unauthorized", Message: "Unauthorized",
}, 403) }, 403)
return return
} }
requests := api.Database.GetAllAccessRequests(id) accesses := api.Database.GetAllAccesses(id)
r.OkJson(ProjectGetAccessRequestsResponse{ r.OkJson(ProjectGetAccessRequestsResponse{
Ok: true, Ok: true,
Requests: requests, Accesses: accesses,
}) })
} }
func (api *WebAPI) WorkerRequestAccess(r *Request) { func (api *WebAPI) WorkerRequestAccess(r *Request) {
id, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64) req := &WorkerAccessRequest{}
handleErr(err, r) //todo handle invalid id err := json.Unmarshal(r.Ctx.Request.Body(), req)
if err != nil {
r.Json(WorkerAccessRequestResponse{
Ok: false,
Message: "Could not parse request",
}, 400)
return
}
if !req.isValid() {
r.Json(WorkerAccessRequestResponse{
Ok: false,
Message: "Invalid request",
}, 400)
return
}
worker, err := api.validateSignature(r) worker, err := api.validateSignature(r)
if err != nil { if err != nil {
r.Json(WorkerRequestAccessResponse{ r.Json(WorkerAccessRequestResponse{
Ok: false, Ok: false,
Message: err.Error(), Message: err.Error(),
}, 401) }, 401)
} }
res := api.Database.SaveAccessRequest(worker, id) res := api.Database.SaveAccessRequest(&storage.WorkerAccess{
Worker: *worker,
Submit: req.Submit,
Assign: req.Assign,
Project: req.Project,
})
if res { if res {
r.OkJson(WorkerRequestAccessResponse{ r.OkJson(WorkerAccessRequestResponse{
Ok: true, Ok: true,
}) })
} else { } else {
r.Json(WorkerRequestAccessResponse{ r.Json(WorkerAccessRequestResponse{
Ok: false, Ok: false,
Message: "Project is public, you already have " + Message: "Project is public, you already have " +
"an active request or you already have access to this project", "an active request or you already have access to this project",
}, 400) }, 400)
} }
} }
func (api *WebAPI) AcceptAccessRequest(r *Request) {
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
handleErr(err, r) //todo handle invalid id
wid, err := strconv.ParseInt(r.Ctx.UserValue("wid").(string), 10, 64)
handleErr(err, r) //todo handle invalid id
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if !isActionAuthorized(pid, manager, storage.ROLE_MANAGE_ACCESS, api.Database) {
r.Json(WorkerAccessRequestResponse{
Message: "Unauthorized",
Ok: false,
}, 403)
return
}
ok := api.Database.AcceptAccessRequest(wid, pid)
if ok {
r.OkJson(WorkerAccessRequestResponse{
Ok: true,
})
} else {
r.OkJson(WorkerAccessRequestResponse{
Ok: false,
Message: "Worker did not have access to this project",
})
}
}
func (api *WebAPI) RejectAccessRequest(r *Request) {
pid, err := strconv.ParseInt(r.Ctx.UserValue("id").(string), 10, 64)
handleErr(err, r) //todo handle invalid id
wid, err := strconv.ParseInt(r.Ctx.UserValue("wid").(string), 10, 64)
handleErr(err, r) //todo handle invalid id
ok := api.Database.RejectAccessRequest(wid, pid)
if ok {
r.OkJson(WorkerAccessRequestResponse{
Ok: true,
})
} else {
r.OkJson(WorkerAccessRequestResponse{
Ok: false,
Message: "Worker did not have access to this project",
})
}
}

View File

@ -49,8 +49,17 @@ type GetTaskResponse struct {
func (api *WebAPI) TaskCreate(r *Request) { func (api *WebAPI) TaskCreate(r *Request) {
worker, err := api.validateSignature(r)
if worker == nil {
r.Json(CreateProjectResponse{
Ok: false,
Message: err.Error(),
}, 401)
return
}
createReq := &CreateTaskRequest{} createReq := &CreateTaskRequest{}
err := json.Unmarshal(r.Ctx.Request.Body(), createReq) err = json.Unmarshal(r.Ctx.Request.Body(), createReq)
if err != nil { if err != nil {
r.Json(CreateProjectResponse{ r.Json(CreateProjectResponse{
Ok: false, Ok: false,
@ -74,7 +83,7 @@ func (api *WebAPI) TaskCreate(r *Request) {
createReq.Hash64 = int64(siphash.Hash(1, 2, []byte(createReq.UniqueString))) createReq.Hash64 = int64(siphash.Hash(1, 2, []byte(createReq.UniqueString)))
} }
err := api.Database.SaveTask(task, createReq.Project, createReq.Hash64) err := api.Database.SaveTask(task, createReq.Project, createReq.Hash64, worker.Id)
if err != nil { if err != nil {
r.Json(CreateTaskResponse{ r.Json(CreateTaskResponse{

View File

@ -9,10 +9,6 @@ import (
"time" "time"
) )
type CreateWorkerRequest struct {
Alias string `json:"alias"`
}
type UpdateWorkerRequest struct { type UpdateWorkerRequest struct {
Alias string `json:"alias"` Alias string `json:"alias"`
} }
@ -22,6 +18,10 @@ type UpdateWorkerResponse struct {
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
} }
type CreateWorkerRequest struct {
Alias string `json:"alias"`
}
type CreateWorkerResponse struct { type CreateWorkerResponse struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
@ -34,22 +34,25 @@ type GetWorkerResponse struct {
Worker *storage.Worker `json:"worker,omitempty"` Worker *storage.Worker `json:"worker,omitempty"`
} }
type WorkerAccessRequest struct {
WorkerId int64 `json:"worker_id"`
ProjectId int64 `json:"project_id"`
}
type WorkerAccessResponse struct {
Ok bool `json:"ok"`
Message string `json:"message"`
}
type GetAllWorkerStatsResponse struct { type GetAllWorkerStatsResponse struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
Stats *[]storage.WorkerStats `json:"stats"` Stats *[]storage.WorkerStats `json:"stats"`
} }
type WorkerAccessRequest struct {
Assign bool `json:"assign"`
Submit bool `json:"submit"`
Project int64 `json:"project"`
}
func (w *WorkerAccessRequest) isValid() bool {
if !w.Assign && !w.Submit {
return false
}
return true
}
func (api *WebAPI) WorkerCreate(r *Request) { func (api *WebAPI) WorkerCreate(r *Request) {
workerReq := &CreateWorkerRequest{} workerReq := &CreateWorkerRequest{}
@ -125,57 +128,6 @@ func (api *WebAPI) WorkerGet(r *Request) {
} }
} }
func (api *WebAPI) WorkerGrantAccess(r *Request) {
req := &WorkerAccessRequest{}
err := json.Unmarshal(r.Ctx.Request.Body(), req)
if err != nil {
r.Json(GetTaskResponse{
Ok: false,
Message: "Could not parse request",
}, 400)
return
}
ok := api.Database.GrantAccess(req.WorkerId, req.ProjectId)
if ok {
r.OkJson(WorkerAccessResponse{
Ok: true,
})
} else {
r.OkJson(WorkerAccessResponse{
Ok: false,
Message: "Worker already has access to this project",
})
}
}
func (api *WebAPI) WorkerRemoveAccess(r *Request) {
req := &WorkerAccessRequest{}
err := json.Unmarshal(r.Ctx.Request.Body(), req)
if err != nil {
r.Json(GetTaskResponse{
Ok: false,
Message: "Could not parse request",
}, 400)
return
}
ok := api.Database.RemoveAccess(req.WorkerId, req.ProjectId)
if ok {
r.OkJson(WorkerAccessResponse{
Ok: true,
})
} else {
r.OkJson(WorkerAccessResponse{
Ok: false,
Message: "Worker did not have access to this project",
})
}
}
func (api *WebAPI) WorkerUpdate(r *Request) { func (api *WebAPI) WorkerUpdate(r *Request) {
worker, err := api.validateSignature(r) worker, err := api.validateSignature(r)

View File

@ -1,6 +1,6 @@
DROP TABLE IF EXISTS worker, project, task, log_entry, DROP TABLE IF EXISTS worker, project, task, log_entry,
worker_has_access_to_project, manager, manager_has_role_on_project, project_monitoring_snapshot, worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task, worker_requests_access_to_project; worker_verifies_task;
DROP TYPE IF EXISTS status; DROP TYPE IF EXISTS status;
DROP TYPE IF EXISTS log_level; DROP TYPE IF EXISTS log_level;
@ -28,10 +28,13 @@ CREATE TABLE project
motd TEXT NOT NULL motd TEXT NOT NULL
); );
CREATE TABLE worker_has_access_to_project CREATE TABLE worker_access
( (
worker INTEGER REFERENCES worker (id), worker INTEGER REFERENCES worker (id),
project INTEGER REFERENCES project (id), project INTEGER REFERENCES project (id),
role_assign boolean,
role_submit boolean,
request boolean,
primary key (worker, project) primary key (worker, project)
); );
@ -79,7 +82,7 @@ CREATE TABLE manager
CREATE TABLE manager_has_role_on_project CREATE TABLE manager_has_role_on_project
( (
manager INTEGER REFERENCES manager (id) NOT NULL, manager INTEGER REFERENCES manager (id) NOT NULL,
role SMALLINT NOT NULl, role SMALLINT NOT NULL,
project INTEGER REFERENCES project (id) NOT NULL project INTEGER REFERENCES project (id) NOT NULL
); );
@ -94,12 +97,6 @@ CREATE TABLE project_monitoring_snapshot
timestamp INT NOT NULL timestamp INT NOT NULL
); );
CREATE TABLE worker_requests_access_to_project
(
worker INT REFERENCES worker (id) NOT NULL,
project INT REFERENCES project (id) NOT NULL
);
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
$$ $$
DECLARE DECLARE

View File

@ -30,7 +30,7 @@ func (database *Database) MakeProjectSnapshots() {
WHERE task.project = project.id AND status = 1 AND wvt.task IS NULL), WHERE task.project = project.id AND status = 1 AND wvt.task IS NULL),
(SELECT COUNT(*) FROM task WHERE task.project = project.id AND status = 2), (SELECT COUNT(*) FROM task WHERE task.project = project.id AND status = 2),
closed_task_count, closed_task_count,
(SELECT COUNT(*) FROM worker_has_access_to_project wa WHERE wa.project = project.id), (SELECT COUNT(*) FROM worker_access wa WHERE wa.project = project.id),
(SELECT COUNT(*) FROM worker_verifies_task INNER JOIN task t on worker_verifies_task.task = t.id (SELECT COUNT(*) FROM worker_verifies_task INNER JOIN task t on worker_verifies_task.task = t.id
WHERE t.project = project.id), WHERE t.project = project.id),
extract(epoch from now() at time zone 'utc') extract(epoch from now() at time zone 'utc')

View File

@ -2,6 +2,7 @@ package storage
import ( import (
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
@ -35,15 +36,17 @@ const (
TR_SKIP TaskResult = 2 TR_SKIP TaskResult = 2
) )
func (database *Database) SaveTask(task *Task, project int64, hash64 int64) error { func (database *Database) SaveTask(task *Task, project int64, hash64 int64, wid int64) error {
db := database.getDB() db := database.getDB()
//TODO: For some reason it refuses to insert the 64-bit value unless I do that... //TODO: For some reason it refuses to insert the 64-bit value unless I do that...
res, err := db.Exec(fmt.Sprintf(` res, err := db.Exec(fmt.Sprintf(`
INSERT INTO task (project, max_retries, recipe, priority, max_assign_time, hash64,verification_count) INSERT INTO task (project, max_retries, recipe, priority, max_assign_time, hash64,verification_count)
VALUES ($1,$2,$3,$4,$5,NULLIF(%d, 0),$6)`, hash64), SELECT $1,$2,$3,$4,$5,NULLIF(%d, 0),$6 FROM worker_access
project, task.MaxRetries, task.Recipe, task.Priority, task.MaxAssignTime, task.VerificationCount) WHERE role_submit AND worker=$7 AND project=$1`, hash64),
project, task.MaxRetries, task.Recipe, task.Priority, task.MaxAssignTime, task.VerificationCount,
wid)
if err != nil { if err != nil {
logrus.WithError(err).WithFields(logrus.Fields{ logrus.WithError(err).WithFields(logrus.Fields{
"task": task, "task": task,
@ -59,6 +62,10 @@ func (database *Database) SaveTask(task *Task, project int64, hash64 int64) erro
"task": task, "task": task,
}).Trace("Database.saveTask INSERT task") }).Trace("Database.saveTask INSERT task")
if rowsAffected == 0 {
return errors.New("unauthorized task submit")
}
return nil return nil
} }
@ -77,7 +84,7 @@ func (database *Database) GetTask(worker *Worker) *Task {
LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1 LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1
WHERE assignee IS NULL AND task.status=1 WHERE assignee IS NULL AND task.status=1
AND (project.public OR EXISTS ( AND (project.public OR EXISTS (
SELECT 1 FROM worker_has_access_to_project a WHERE a.worker=$1 AND a.project=project.id SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=project.id
)) ))
AND wvt.task IS NULL AND wvt.task IS NULL
ORDER BY project.priority DESC, task.priority DESC ORDER BY project.priority DESC, task.priority DESC
@ -179,8 +186,8 @@ func (database *Database) GetTaskFromProject(worker *Worker, projectId int64) *T
INNER JOIN project project on task.project = project.id INNER JOIN project project on task.project = project.id
LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1 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 assignee IS NULL AND project.id=$2 AND status=1
AND (project.public OR EXISTS ( AND (project.public OR (
SELECT 1 FROM worker_has_access_to_project a WHERE a.worker=$1 AND a.project=$2 SELECT a.role_assign FROM worker_access a WHERE a.worker=$1 AND a.project=$2
)) ))
AND wvt.task IS NULL AND wvt.task IS NULL
ORDER BY task.priority DESC ORDER BY task.priority DESC

View File

@ -16,11 +16,20 @@ type WorkerStats struct {
ClosedTaskCount int64 `json:"closed_task_count"` ClosedTaskCount int64 `json:"closed_task_count"`
} }
type WorkerAccess struct {
Submit bool `json:"submit"`
Assign bool `json:"assign"`
Request bool `json:"request"`
Worker Worker `json:"worker"`
Project int64 `json:"project"`
}
func (database *Database) SaveWorker(worker *Worker) { func (database *Database) SaveWorker(worker *Worker) {
db := database.getDB() db := database.getDB()
row := db.QueryRow("INSERT INTO worker (created, secret, alias) VALUES ($1,$2,$3) RETURNING id", row := db.QueryRow(`INSERT INTO worker (created, secret, alias)
VALUES ($1,$2,$3) RETURNING id`,
worker.Created, worker.Secret, worker.Alias) worker.Created, worker.Secret, worker.Alias)
err := row.Scan(&worker.Id) err := row.Scan(&worker.Id)
@ -56,14 +65,14 @@ func (database *Database) GetWorker(id int64) *Worker {
func (database *Database) GrantAccess(workerId int64, projectId int64) bool { func (database *Database) GrantAccess(workerId int64, projectId int64) bool {
db := database.getDB() db := database.getDB()
res, err := db.Exec(`INSERT INTO worker_has_access_to_project (worker, project) VALUES ($1,$2) res, err := db.Exec(`UPDATE worker_access SET
ON CONFLICT DO NOTHING`, request=FALSE WHERE worker=$1 AND project=$2`,
workerId, projectId) workerId, projectId)
if err != nil { if err != nil {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"workerId": workerId, "workerId": workerId,
"projectId": projectId, "projectId": projectId,
}).WithError(err).Warn("Database.GrantAccess INSERT worker_hase_access_to_project") }).WithError(err).Warn("Database.GrantAccess INSERT")
return false return false
} }
@ -73,25 +82,7 @@ func (database *Database) GrantAccess(workerId int64, projectId int64) bool {
"rowsAffected": rowsAffected, "rowsAffected": rowsAffected,
"workerId": workerId, "workerId": workerId,
"projectId": projectId, "projectId": projectId,
}).Trace("Database.GrantAccess INSERT worker_has_access_to_project") }).Trace("Database.GrantAccess INSERT")
return rowsAffected == 1
}
func (database *Database) RemoveAccess(workerId int64, projectId int64) bool {
db := database.getDB()
res, err := db.Exec(`DELETE FROM worker_has_access_to_project WHERE worker=$1 AND project=$2`,
workerId, projectId)
handleErr(err)
rowsAffected, _ := res.RowsAffected()
logrus.WithFields(logrus.Fields{
"rowsAffected": rowsAffected,
"workerId": workerId,
"projectId": projectId,
}).Trace("Database.RemoveAccess DELETE worker_has_access_to_project")
return rowsAffected == 1 return rowsAffected == 1
} }
@ -113,14 +104,14 @@ func (database *Database) UpdateWorker(worker *Worker) bool {
return rowsAffected == 1 return rowsAffected == 1
} }
func (database *Database) SaveAccessRequest(worker *Worker, projectId int64) bool { func (database *Database) SaveAccessRequest(wa *WorkerAccess) bool {
db := database.getDB() db := database.getDB()
res, err := db.Exec(`INSERT INTO worker_requests_access_to_project res, err := db.Exec(`INSERT INTO worker_access(worker, project, role_assign,
SELECT $1, id FROM project WHERE id=$2 AND NOT project.public role_submit, request)
AND NOT EXISTS(SELECT * FROM worker_has_access_to_project WHERE worker=$1 AND project=$2)`, VALUES ($1,$2,$3,$4,TRUE)`,
worker.Id, projectId) wa.Worker.Id, wa.Project, wa.Assign, wa.Submit)
if err != nil { if err != nil {
return false return false
} }
@ -134,35 +125,12 @@ func (database *Database) SaveAccessRequest(worker *Worker, projectId int64) boo
return rowsAffected == 1 return rowsAffected == 1
} }
func (database *Database) AcceptAccessRequest(worker *Worker, projectId int64) bool { func (database *Database) AcceptAccessRequest(worker int64, projectId int64) bool {
db := database.getDB() db := database.getDB()
res, err := db.Exec(`DELETE FROM worker_requests_access_to_project res, err := db.Exec(`UPDATE worker_access SET request=FALSE
WHERE worker=$1 AND project=$2`) WHERE worker=$1 AND project=$2`, worker, projectId)
handleErr(err)
rowsAffected, _ := res.RowsAffected()
if rowsAffected == 1 {
_, err := db.Exec(`INSERT INTO worker_has_access_to_project
(worker, project) VALUES ($1,$2)`,
worker.Id, projectId)
handleErr(err)
}
logrus.WithFields(logrus.Fields{
"rowsAffected": rowsAffected,
}).Trace("Database.AcceptAccessRequest")
return rowsAffected == 1
}
func (database *Database) RejectAccessRequest(worker *Worker, projectId int64) bool {
db := database.getDB()
res, err := db.Exec(`DELETE FROM worker_requests_access_to_project
WHERE worker=$1 AND project=$2`, worker.Id, projectId)
handleErr(err) handleErr(err)
rowsAffected, _ := res.RowsAffected() rowsAffected, _ := res.RowsAffected()
@ -174,22 +142,44 @@ func (database *Database) RejectAccessRequest(worker *Worker, projectId int64) b
return rowsAffected == 1 return rowsAffected == 1
} }
func (database *Database) GetAllAccessRequests(projectId int64) *[]Worker { func (database *Database) RejectAccessRequest(workerId int64, projectId int64) bool {
db := database.getDB()
res, err := db.Exec(`DELETE FROM worker_access WHERE worker=$1 AND project=$2`,
workerId, projectId)
handleErr(err)
rowsAffected, _ := res.RowsAffected()
logrus.WithFields(logrus.Fields{
"rowsAffected": rowsAffected,
"workerId": workerId,
"projectId": projectId,
}).Trace("Database.RejectAccessRequest DELETE")
return rowsAffected == 1
}
func (database *Database) GetAllAccesses(projectId int64) *[]WorkerAccess {
db := database.getDB() db := database.getDB()
rows, err := db.Query(`SELECT id, alias, created FROM worker_requests_access_to_project rows, err := db.Query(`SELECT id, alias, created, role_assign, role_submit, request
INNER JOIN worker w on worker_requests_access_to_project.worker = w.id FROM worker_access
WHERE project=$1`, INNER JOIN worker w on worker_access.worker = w.id
WHERE project=$1 ORDER BY request, alias`,
projectId) projectId)
handleErr(err) handleErr(err)
requests := make([]Worker, 0) requests := make([]WorkerAccess, 0)
for rows.Next() { for rows.Next() {
w := Worker{} wa := WorkerAccess{
_ = rows.Scan(&w.Id, &w.Alias, &w.Created) Project: projectId,
requests = append(requests, w) }
_ = rows.Scan(&wa.Worker.Id, &wa.Worker.Alias, &wa.Worker.Created,
&wa.Assign, &wa.Submit, &wa.Request)
requests = append(requests, wa)
} }
return &requests return &requests

View File

@ -143,6 +143,40 @@ func TestInvalidCredentialsLogin(t *testing.T) {
} }
} }
func TestRequireManageAccessRole(t *testing.T) {
user := getSessionCtx("testreqmanrole", "testreqmanrole", false)
pid := createProject(api.CreateProjectRequest{
GitRepo: "testRequireManageAccessRole",
CloneUrl: "testRequireManageAccessRole",
Name: "testRequireManageAccessRole",
Version: "testRequireManageAccessRole",
}, user).Id
w := genWid()
requestAccess(api.WorkerAccessRequest{
Submit: true,
Assign: true,
Project: pid,
}, w)
rGuest := acceptAccessRequest(pid, w.Id, nil)
rOtherUser := acceptAccessRequest(pid, w.Id, testUserCtx)
rUser := acceptAccessRequest(pid, w.Id, user)
if rGuest.Ok != false {
t.Error()
}
if rOtherUser.Ok != false {
t.Error()
}
if rUser.Ok != true {
t.Error()
}
}
func register(request *api.RegisterRequest) *api.RegisterResponse { func register(request *api.RegisterRequest) *api.RegisterResponse {
r := Post("/register", request, nil, nil) r := Post("/register", request, nil, nil)

View File

@ -2,8 +2,6 @@ package test
import ( import (
"github.com/simon987/task_tracker/api" "github.com/simon987/task_tracker/api"
"github.com/simon987/task_tracker/config"
"github.com/simon987/task_tracker/storage"
"strconv" "strconv"
"testing" "testing"
) )
@ -29,24 +27,3 @@ func BenchmarkCreateTaskRemote(b *testing.B) {
}, worker) }, worker)
} }
} }
func BenchmarkCreateTask(b *testing.B) {
config.SetupConfig()
db := storage.Database{}
project, _ := db.SaveProject(&storage.Project{
Priority: 1,
Id: 1,
Version: "bmcreatetask",
Public: true,
Motd: "bmcreatetask",
Name: "BenchmarkCreateTask" + strconv.Itoa(b.N),
GitRepo: "benchmark_test" + strconv.Itoa(b.N),
})
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = db.SaveTask(&storage.Task{}, project, 0)
}
}

View File

@ -11,23 +11,29 @@ import (
func TestCreateTaskValid(t *testing.T) { func TestCreateTaskValid(t *testing.T) {
//Make sure there is always a project for id:1 pid := createProjectAsAdmin(api.CreateProjectRequest{
createProjectAsAdmin(api.CreateProjectRequest{
Name: "Some Test name", Name: "Some Test name",
Version: "Test Version", Version: "Test Version",
CloneUrl: "http://github.com/test/test", CloneUrl: "http://github.com/test/test",
}) GitRepo: "Some git repo",
}).Id
worker := genWid() worker := genWid()
requestAccess(api.WorkerAccessRequest{
Project: pid,
Submit: true,
Assign: false,
}, worker)
acceptAccessRequest(pid, worker.Id, testAdminCtx)
resp := createTask(api.CreateTaskRequest{ resp := createTask(api.CreateTaskRequest{
Project: 1, Project: pid,
Recipe: "{}", Recipe: "{}",
MaxRetries: 3, MaxRetries: 3,
}, worker) }, worker)
if resp.Ok != true { if resp.Ok != true {
t.Fail() t.Error()
} }
} }
@ -143,6 +149,12 @@ func TestCreateGetTask(t *testing.T) {
}) })
worker := genWid() worker := genWid()
requestAccess(api.WorkerAccessRequest{
Submit: true,
Assign: true,
Project: resp.Id,
}, worker)
acceptAccessRequest(resp.Id, worker.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
Project: resp.Id, Project: resp.Id,
@ -211,6 +223,19 @@ func createTasks(prefix string) (int64, int64) {
Public: true, Public: true,
}) })
worker := genWid() worker := genWid()
requestAccess(api.WorkerAccessRequest{
Submit: true,
Assign: false,
Project: highP.Id,
}, worker)
acceptAccessRequest(highP.Id, worker.Id, testAdminCtx)
requestAccess(api.WorkerAccessRequest{
Submit: true,
Assign: false,
Project: lowP.Id,
}, worker)
acceptAccessRequest(lowP.Id, worker.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
Project: lowP.Id, Project: lowP.Id,
Recipe: "low1", Recipe: "low1",
@ -303,6 +328,13 @@ func TestTaskNoAccess(t *testing.T) {
Public: false, Public: false,
}).Id }).Id
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, worker)
acceptAccessRequest(worker.Id, pid, testAdminCtx)
createResp := createTask(api.CreateTaskRequest{ createResp := createTask(api.CreateTaskRequest{
Project: pid, Project: pid,
Priority: 1, Priority: 1,
@ -315,8 +347,7 @@ func TestTaskNoAccess(t *testing.T) {
t.Error() t.Error()
} }
grantAccess(worker.Id, pid) rejectAccessRequest(pid, worker.Id, testAdminCtx)
removeAccess(worker.Id, pid)
tResp := getTaskFromProject(pid, worker) tResp := getTaskFromProject(pid, worker)
@ -345,6 +376,13 @@ func TestTaskHasAccess(t *testing.T) {
Public: false, Public: false,
}).Id }).Id
requestAccess(api.WorkerAccessRequest{
Submit: true,
Assign: true,
Project: pid,
}, worker)
acceptAccessRequest(worker.Id, pid, testAdminCtx)
createResp := createTask(api.CreateTaskRequest{ createResp := createTask(api.CreateTaskRequest{
Project: pid, Project: pid,
Priority: 1, Priority: 1,
@ -357,8 +395,6 @@ func TestTaskHasAccess(t *testing.T) {
t.Error() t.Error()
} }
grantAccess(worker.Id, pid)
tResp := getTaskFromProject(pid, worker) tResp := getTaskFromProject(pid, worker)
if tResp.Ok != true { if tResp.Ok != true {
@ -392,6 +428,13 @@ func TestReleaseTaskSuccess(t *testing.T) {
Public: true, Public: true,
}).Id }).Id
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, worker)
acceptAccessRequest(pid, worker.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
Priority: 0, Priority: 0,
Project: pid, Project: pid,
@ -431,6 +474,12 @@ func TestCreateIntCollision(t *testing.T) {
}).Id }).Id
w := genWid() w := genWid()
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w)
acceptAccessRequest(pid, w.Id, testAdminCtx)
if createTask(api.CreateTaskRequest{ if createTask(api.CreateTaskRequest{
Project: pid, Project: pid,
@ -471,6 +520,12 @@ func TestCreateStringCollision(t *testing.T) {
}).Id }).Id
w := genWid() w := genWid()
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w)
acceptAccessRequest(pid, w.Id, testAdminCtx)
if createTask(api.CreateTaskRequest{ if createTask(api.CreateTaskRequest{
Project: pid, Project: pid,
@ -520,6 +575,12 @@ func TestCannotVerifySameTaskTwice(t *testing.T) {
}).Id }).Id
w := genWid() w := genWid()
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w)
acceptAccessRequest(pid, w.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
VerificationCount: 2, VerificationCount: 2,
@ -560,6 +621,24 @@ func TestVerification2(t *testing.T) {
w := genWid() w := genWid()
w2 := genWid() w2 := genWid()
w3 := genWid() w3 := genWid()
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w)
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w2)
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w3)
acceptAccessRequest(pid, w.Id, testAdminCtx)
acceptAccessRequest(pid, w2.Id, testAdminCtx)
acceptAccessRequest(pid, w3.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
VerificationCount: 2, VerificationCount: 2,
@ -614,6 +693,12 @@ func TestReleaseTaskFail(t *testing.T) {
}).Id }).Id
w := genWid() w := genWid()
requestAccess(api.WorkerAccessRequest{
Project: pid,
Assign: true,
Submit: true,
}, w)
acceptAccessRequest(pid, w.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
MaxRetries: 0, MaxRetries: 0,
@ -657,6 +742,18 @@ func TestTaskChain(t *testing.T) {
CloneUrl: "testtaskchain2", CloneUrl: "testtaskchain2",
Chain: p1, Chain: p1,
}).Id }).Id
requestAccess(api.WorkerAccessRequest{
Project: p1,
Assign: true,
Submit: true,
}, w)
requestAccess(api.WorkerAccessRequest{
Project: p2,
Assign: true,
Submit: true,
}, w)
acceptAccessRequest(p1, w.Id, testAdminCtx)
acceptAccessRequest(p2, w.Id, testAdminCtx)
createTask(api.CreateTaskRequest{ createTask(api.CreateTaskRequest{
Project: p2, Project: p2,

View File

@ -64,79 +64,6 @@ func TestGetWorkerInvalid(t *testing.T) {
t.Error() t.Error()
} }
} }
func TestGrantAccessFailedProjectConstraint(t *testing.T) {
wid := genWid()
resp := grantAccess(wid.Id, 38274593)
if resp.Ok != false {
t.Error()
}
if len(resp.Message) <= 0 {
t.Error()
}
}
func TestRemoveAccessFailedProjectConstraint(t *testing.T) {
worker := genWid()
resp := removeAccess(worker.Id, 38274593)
if resp.Ok != false {
t.Error()
}
if len(resp.Message) <= 0 {
t.Error()
}
}
func TestRemoveAccessFailedWorkerConstraint(t *testing.T) {
pid := createProjectAsAdmin(api.CreateProjectRequest{
Priority: 1,
GitRepo: "dfffffffffff",
CloneUrl: "fffffffffff23r",
Version: "f83w9rw",
Motd: "ddddddddd",
Name: "removeaccessfailedworkerconstraint",
Public: true,
}).Id
resp := removeAccess(0, pid)
if resp.Ok != false {
t.Error()
}
if len(resp.Message) <= 0 {
t.Error()
}
}
func TestGrantAccessFailedWorkerConstraint(t *testing.T) {
pid := createProjectAsAdmin(api.CreateProjectRequest{
Priority: 1,
GitRepo: "dfffffffffff1",
CloneUrl: "fffffffffff23r1",
Version: "f83w9rw1",
Motd: "ddddddddd1",
Name: "grantaccessfailedworkerconstraint",
Public: true,
}).Id
resp := removeAccess(0, pid)
if resp.Ok != false {
t.Error()
}
if len(resp.Message) <= 0 {
t.Error()
}
}
func TestUpdateAliasValid(t *testing.T) { func TestUpdateAliasValid(t *testing.T) {
wid := genWid() wid := genWid()
@ -169,7 +96,30 @@ func TestCreateWorkerAliasInvalid(t *testing.T) {
if len(resp.Message) <= 0 { if len(resp.Message) <= 0 {
t.Error() t.Error()
} }
}
func TestInvalidAccessRequest(t *testing.T) {
w := genWid()
pid := createProjectAsAdmin(api.CreateProjectRequest{
Name: "testinvalidaccessreq",
CloneUrl: "testinvalidaccessreq",
GitRepo: "testinvalidaccessreq",
}).Id
r := requestAccess(api.WorkerAccessRequest{
Submit: false,
Assign: false,
Project: pid,
}, w)
if r.Ok != false {
t.Error()
}
if len(r.Message) <= 0 {
t.Error()
}
} }
func createWorker(req api.CreateWorkerRequest) (*api.CreateWorkerResponse, *http.Response) { func createWorker(req api.CreateWorkerRequest) (*api.CreateWorkerResponse, *http.Response) {
@ -201,14 +151,11 @@ func genWid() *storage.Worker {
return resp.Worker return resp.Worker
} }
func grantAccess(wid int64, project int64) *api.WorkerAccessResponse { func requestAccess(req api.WorkerAccessRequest, w *storage.Worker) *api.WorkerAccessRequestResponse {
r := Post("/access/grant", api.WorkerAccessRequest{ r := Post(fmt.Sprintf("/project/request_access"), req, w, nil)
WorkerId: wid,
ProjectId: project,
}, nil, nil)
var resp *api.WorkerAccessResponse var resp *api.WorkerAccessRequestResponse
data, _ := ioutil.ReadAll(r.Body) data, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(data, &resp) err := json.Unmarshal(data, &resp)
handleErr(err) handleErr(err)
@ -216,14 +163,25 @@ func grantAccess(wid int64, project int64) *api.WorkerAccessResponse {
return resp return resp
} }
func removeAccess(wid int64, project int64) *api.WorkerAccessResponse { func acceptAccessRequest(pid int64, wid int64, s *http.Client) *api.WorkerAccessRequestResponse {
r := Post("/access/remove", api.WorkerAccessRequest{ r := Post(fmt.Sprintf("/project/accept_request/%d/%d", pid, wid), nil,
WorkerId: wid, nil, s)
ProjectId: project,
}, nil, nil)
var resp *api.WorkerAccessResponse var resp *api.WorkerAccessRequestResponse
data, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(data, &resp)
handleErr(err)
return resp
}
func rejectAccessRequest(pid int64, wid int64, s *http.Client) *api.WorkerAccessRequestResponse {
r := Post(fmt.Sprintf("/project/reject_request/%d/%d", pid, wid), nil,
nil, s)
var resp *api.WorkerAccessRequestResponse
data, _ := ioutil.ReadAll(r.Body) data, _ := ioutil.ReadAll(r.Body)
err := json.Unmarshal(data, &resp) err := json.Unmarshal(data, &resp)
handleErr(err) handleErr(err)

View File

@ -1,6 +1,6 @@
DROP TABLE IF EXISTS worker, project, task, log_entry, DROP TABLE IF EXISTS worker, project, task, log_entry,
worker_has_access_to_project, manager, manager_has_role_on_project, project_monitoring_snapshot, worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task, worker_requests_access_to_project; worker_verifies_task;
DROP TYPE IF EXISTS status; DROP TYPE IF EXISTS status;
DROP TYPE IF EXISTS log_level; DROP TYPE IF EXISTS log_level;
@ -28,10 +28,13 @@ CREATE TABLE project
motd TEXT NOT NULL motd TEXT NOT NULL
); );
CREATE TABLE worker_has_access_to_project CREATE TABLE worker_access
( (
worker INTEGER REFERENCES worker (id), worker INTEGER REFERENCES worker (id),
project INTEGER REFERENCES project (id), project INTEGER REFERENCES project (id),
role_assign boolean,
role_submit boolean,
request boolean,
primary key (worker, project) primary key (worker, project)
); );
@ -81,7 +84,7 @@ CREATE TABLE manager_has_role_on_project
manager INTEGER REFERENCES manager (id) NOT NULL, manager INTEGER REFERENCES manager (id) NOT NULL,
role SMALLINT NOT NULL, role SMALLINT NOT NULL,
project INTEGER REFERENCES project (id) NOT NULL, project INTEGER REFERENCES project (id) NOT NULL,
primary key (manager, project) PRIMARY KEY (manager, project)
); );
CREATE TABLE project_monitoring_snapshot CREATE TABLE project_monitoring_snapshot
@ -95,12 +98,6 @@ CREATE TABLE project_monitoring_snapshot
timestamp INT NOT NULL timestamp INT NOT NULL
); );
CREATE TABLE worker_requests_access_to_project
(
worker INT REFERENCES worker (id) NOT NULL,
project INT REFERENCES project (id) NOT NULL
);
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
$$ $$
DECLARE DECLARE

View File

@ -65,8 +65,8 @@ export class ApiService {
return this.http.get(this.url + `/worker/stats`, this.options) return this.http.get(this.url + `/worker/stats`, this.options)
} }
getProjectAccessRequests(project: number) { getProjectAccess(project: number) {
return this.http.get(this.url + `/project/requests/${project}`) return this.http.get(this.url + `/project/accesses/${project}`)
} }
getAllManagers() { getAllManagers() {
@ -81,4 +81,12 @@ export class ApiService {
return this.http.get(this.url + `/manager/demote/${managerId}`) return this.http.get(this.url + `/manager/demote/${managerId}`)
} }
acceptWorkerAccessRequest(wid: number, pid: number) {
return this.http.post(this.url + `/project/accept_request/${pid}/${wid}`, null)
}
rejectWorkerAccessRequest(wid: number, pid: number) {
return this.http.post(this.url + `/project/reject_request/${pid}/${wid}`, null)
}
} }

View File

@ -0,0 +1,9 @@
import {Worker} from "./worker"
export interface WorkerAccess {
submit: boolean
assign: boolean
request: boolean
worker: Worker
project: number
}

View File

@ -2,3 +2,7 @@
button { button {
margin-left: 15px; margin-left: 15px;
} }
.request {
color: #757575;
}

View File

@ -11,19 +11,23 @@
<mat-card-content> <mat-card-content>
<mat-list *ngIf="!unauthorized"> <mat-list *ngIf="!unauthorized">
<mat-list-item *ngFor="let w of requests"> <mat-list-item *ngFor="let wa of accesses" [class.request]="wa.request">
<mat-icon mat-list-icon>person_add</mat-icon> <mat-icon mat-list-icon *ngIf="wa.submit" [title]="'perms.assign'|translate">library_add</mat-icon>
<h4 mat-line>{{w.alias}}</h4> <mat-icon mat-list-icon *ngIf="wa.assign" [title]="'perms.submit'|translate">get_app</mat-icon>
<h4 mat-line>{{wa.worker.alias}} {{wa.request ? ('perms.pending' | translate) : ''}}</h4>
<div mat-line> <div mat-line>
Id=<span class="text-mono">{{w.id}}</span>, {{"perms.created" | translate}} Id=<span class="text-mono">{{wa.worker.id}}</span>, {{"perms.created" | translate}}
<span <span
class="text-mono">{{moment.unix(w.created).utc().format("UTC YYYY-MM-DD HH:mm:ss")}}</span> class="text-mono">{{moment.unix(wa.worker.created).utc().format("UTC YYYY-MM-DD HH:mm:ss")}}</span>
</div> </div>
<span style="flex: 1 1 auto;"></span> <span style="flex: 1 1 auto;"></span>
<button mat-raised-button color="primary" [title]="'perms.grant' | translate"> <button mat-raised-button color="primary" [title]="'perms.grant' | translate"
*ngIf="wa.request" (click)="acceptRequest(wa)">
<mat-icon>check</mat-icon> <mat-icon>check</mat-icon>
</button> </button>
<button mat-raised-button color="warn" [title]="'perms.reject' | translate"> <button mat-raised-button color="warn"
[title]="wa.request ? ('perms.reject'|translate) : ('perms.remove'|translate)"
(click)="rejectRequest(wa)">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
</mat-list-item> </mat-list-item>

View File

@ -1,4 +1,3 @@
import {Worker} from "../models/worker"
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ApiService} from "../api.service"; import {ApiService} from "../api.service";
import {Project} from "../models/project"; import {Project} from "../models/project";
@ -7,6 +6,7 @@ import {MessengerService} from "../messenger.service";
import {TranslateService} from "@ngx-translate/core"; import {TranslateService} from "@ngx-translate/core";
import * as moment from "moment" import * as moment from "moment"
import {WorkerAccess} from "../models/worker-access";
@Component({ @Component({
selector: 'app-project-perms', selector: 'app-project-perms',
@ -24,7 +24,7 @@ export class ProjectPermsComponent implements OnInit {
project: Project; project: Project;
private projectId: number; private projectId: number;
requests: Worker[]; accesses: WorkerAccess[];
unauthorized: boolean = false; unauthorized: boolean = false;
moment = moment; moment = moment;
@ -32,20 +32,30 @@ export class ProjectPermsComponent implements OnInit {
this.route.params.subscribe(params => { this.route.params.subscribe(params => {
this.projectId = params["id"]; this.projectId = params["id"];
this.getProject(); this.getProject();
this.getProjectRequests(); this.getProjectAccesses();
}) })
} }
public acceptRequest(wa: WorkerAccess) {
this.apiService.acceptWorkerAccessRequest(wa.worker.id, this.projectId)
.subscribe(() => this.getProjectAccesses())
}
public rejectRequest(wa: WorkerAccess) {
this.apiService.rejectWorkerAccessRequest(wa.worker.id, this.projectId)
.subscribe(() => this.getProjectAccesses())
}
private getProject() { private getProject() {
this.apiService.getProject(this.projectId).subscribe(data => { this.apiService.getProject(this.projectId).subscribe(data => {
this.project = data["project"] this.project = data["project"]
}) })
} }
private getProjectRequests() { private getProjectAccesses() {
this.apiService.getProjectAccessRequests(this.projectId).subscribe( this.apiService.getProjectAccess(this.projectId).subscribe(
data => { data => {
this.requests = data["requests"] this.accesses = data["accesses"]
}, },
error => { error => {
if (error && (error.status == 401 || error.status == 403)) { if (error && (error.status == 401 || error.status == 403)) {
@ -55,6 +65,6 @@ export class ProjectPermsComponent implements OnInit {
} }
public refresh() { public refresh() {
this.getProjectRequests() this.getProjectAccesses()
} }
} }

View File

@ -103,7 +103,11 @@
"created": "Created on", "created": "Created on",
"grant": "Accept request", "grant": "Accept request",
"reject": "Deny request", "reject": "Deny request",
"refresh": "Refresh" "remove": "Remove access",
"refresh": "Refresh",
"pending": "(Pending)",
"assign": "Assign",
"submit": "Submit"
}, },
"messenger": { "messenger": {
"close": "Close", "close": "Close",

View File

@ -105,7 +105,11 @@
"created": "Créé le", "created": "Créé le",
"grant": "Accepter la requête", "grant": "Accepter la requête",
"reject": "Rejeter la requête", "reject": "Rejeter la requête",
"refresh": "Refraichir" "remove": "Enlever l'accès",
"refresh": "Refraichir",
"pending": "(En attente)",
"assign": "Assigner",
"submit": "Soumettre"
}, },
"messenger": { "messenger": {
"close": "Fermer", "close": "Fermer",