Add API endpoint to pause a worker

This commit is contained in:
simon987 2019-05-05 19:09:45 -04:00
parent 8f10567bd0
commit 72c8e18044
8 changed files with 378 additions and 231 deletions

View File

@ -86,6 +86,7 @@ func New() *WebAPI {
api.router.POST("/worker/create", LogRequestMiddleware(api.CreateWorker))
api.router.POST("/worker/update", LogRequestMiddleware(api.UpdateWorker))
api.router.POST("/worker/set_paused", LogRequestMiddleware(api.WorkerSetPaused))
api.router.GET("/worker/get/:id", LogRequestMiddleware(api.GetWorker))
api.router.GET("/worker/stats", LogRequestMiddleware(api.GetAllWorkerStats))

View File

@ -269,6 +269,11 @@ type UpdateWorkerRequest struct {
Alias string `json:"alias"`
}
type WorkerSetPausedRequest struct {
Worker int64 `json:"worker"`
Paused bool `json:"paused"`
}
type CreateWorkerRequest struct {
Alias string `json:"alias"`
}

View File

@ -200,6 +200,14 @@ func (api *WebAPI) GetTaskFromProject(r *Request) {
return
}
if worker.Paused {
r.Json(JsonResponse{
Ok: false,
Message: "A manager has paused you",
}, 400)
return
}
project, err := strconv.ParseInt(r.Ctx.UserValue("project").(string), 10, 64)
if err != nil || project <= 0 {
r.Json(JsonResponse{

View File

@ -126,6 +126,54 @@ func (api *WebAPI) UpdateWorker(r *Request) {
}
}
func (api *WebAPI) WorkerSetPaused(r *Request) {
sess := api.Session.StartFasthttp(r.Ctx)
manager := sess.Get("manager")
if manager == nil || !manager.(*storage.Manager).WebsiteAdmin {
r.Json(JsonResponse{
Ok: false,
Message: "Unauthorized",
}, 403)
return
}
req := &WorkerSetPausedRequest{}
err := json.Unmarshal(r.Ctx.Request.Body(), req)
if err != nil {
r.Json(JsonResponse{
Ok: false,
Message: "Could not parse request",
}, 400)
return
}
worker := api.Database.GetWorker(req.Worker)
if worker == nil {
r.Json(JsonResponse{
Ok: false,
Message: "Invalid worker",
}, 400)
return
}
worker.Paused = req.Paused
ok := api.Database.UpdateWorker(worker)
if ok {
r.OkJson(JsonResponse{
Ok: true,
})
} else {
r.OkJson(JsonResponse{
Ok: false,
Message: "Could not update worker",
})
}
}
func (api *WebAPI) GetAllWorkerStats(r *Request) {
stats := api.Database.GetAllWorkerStats()

View File

@ -1,179 +1,180 @@
DROP TABLE IF EXISTS worker, project, task, log_entry,
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task;
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task;
CREATE TABLE worker
(
id SERIAL PRIMARY KEY NOT NULL,
alias TEXT NOT NULL,
created INTEGER NOT NULL,
secret BYTEA NOT NULL,
closed_task_count INTEGER DEFAULT 0 NOT NULL
id SERIAL PRIMARY KEY NOT NULL,
alias TEXT NOT NULL,
created INTEGER NOT NULL,
secret BYTEA NOT NULL,
closed_task_count INTEGER DEFAULT 0 NOT NULL,
paused boolean NOT NULL DEFAULT false
);
CREATE TABLE project
(
id SERIAL PRIMARY KEY NOT NULL,
priority INTEGER DEFAULT 0 NOT NULL,
closed_task_count INT DEFAULT 0 NOT NULL,
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 NOT NULL,
version TEXT NOT NULL,
motd TEXT NOT NULL,
secret TEXT NOT NULL DEFAULT '{}',
webhook_secret TEXT NOT NULL,
assign_rate DOUBLE PRECISION NOT NULL,
submit_rate DOUBLE PRECISION NOT NULL
id SERIAL PRIMARY KEY NOT NULL,
priority INTEGER DEFAULT 0 NOT NULL,
closed_task_count INT DEFAULT 0 NOT NULL,
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 NOT NULL,
version TEXT NOT NULL,
motd TEXT NOT NULL,
secret TEXT NOT NULL DEFAULT '{}',
webhook_secret TEXT NOT NULL,
assign_rate DOUBLE PRECISION NOT NULL,
submit_rate DOUBLE PRECISION NOT NULL
);
CREATE TABLE worker_access
(
worker INTEGER REFERENCES worker (id),
project INTEGER REFERENCES project (id),
role_assign boolean,
role_submit boolean,
request boolean,
primary key (worker, project)
worker INTEGER REFERENCES worker (id),
project INTEGER REFERENCES project (id),
role_assign boolean,
role_submit boolean,
request boolean,
primary key (worker, project)
);
CREATE TABLE task
(
hash64 BIGINT DEFAULT NULL,
id SERIAL PRIMARY KEY,
project INTEGER REFERENCES project (id),
assignee INTEGER REFERENCES worker (id),
max_assign_time INTEGER DEFAULT 0,
assign_time INTEGER DEFAULT NULL,
verification_count INTEGER DEFAULT 0,
priority SMALLINT DEFAULT 0,
retries SMALLINT DEFAULT 0,
max_retries SMALLINT,
status SMALLINT DEFAULT 1,
recipe TEXT,
UNIQUE (project, hash64)
hash64 BIGINT DEFAULT NULL,
id SERIAL PRIMARY KEY,
project INTEGER REFERENCES project (id),
assignee INTEGER REFERENCES worker (id),
max_assign_time INTEGER DEFAULT 0,
assign_time INTEGER DEFAULT NULL,
verification_count INTEGER DEFAULT 0,
priority SMALLINT DEFAULT 0,
retries SMALLINT DEFAULT 0,
max_retries SMALLINT,
status SMALLINT DEFAULT 1,
recipe TEXT,
UNIQUE (project, hash64)
);
CREATE TABLE worker_verifies_task
(
verification_hash BIGINT NOT NULL,
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
worker INT REFERENCES worker (id) NOT NULL
verification_hash BIGINT NOT NULL,
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
worker INT REFERENCES worker (id) NOT NULL
);
CREATE TABLE log_entry
(
level INTEGER NOT NULL,
message TEXT NOT NULL,
message_data TEXT NOT NULL,
timestamp INTEGER NOT NULL
level INTEGER NOT NULL,
message TEXT NOT NULL,
message_data TEXT NOT NULL,
timestamp INTEGER NOT NULL
);
CREATE TABLE manager
(
id SERIAL PRIMARY KEY,
register_time INTEGER NOT NULL,
tracker_admin BOOLEAN NOT NULL,
username TEXT UNIQUE NOT NULL,
password BYTEA NOT NULL
id SERIAL PRIMARY KEY,
register_time INTEGER NOT NULL,
tracker_admin BOOLEAN NOT NULL,
username TEXT UNIQUE NOT NULL,
password BYTEA NOT NULL
);
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,
PRIMARY KEY (manager, project)
manager INTEGER REFERENCES manager (id) NOT NULL,
role SMALLINT NOT NULL,
project INTEGER REFERENCES project (id) NOT NULL,
PRIMARY KEY (manager, project)
);
CREATE TABLE project_monitoring_snapshot
(
project INT REFERENCES project (id) NOT NULL,
new_task_count INT NOT NULL,
failed_task_count INT NOT NULL,
closed_task_count INT NOT NULL,
awaiting_verification_task_count INT NOT NULL,
worker_access_count INT NOT NULL,
timestamp INT NOT NULL
project INT REFERENCES project (id) NOT NULL,
new_task_count INT NOT NULL,
failed_task_count INT NOT NULL,
closed_task_count INT NOT NULL,
awaiting_verification_task_count INT NOT NULL,
worker_access_count INT NOT NULL,
timestamp INT NOT NULL
);
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
$$
DECLARE
chain INTEGER;
chain INTEGER;
BEGIN
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)
ON CONFLICT DO NOTHING;
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)
ON CONFLICT DO NOTHING;
end if;
end if;
end if;
RETURN OLD;
RETURN OLD;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER on_task_delete
BEFORE DELETE
ON task
FOR EACH ROW
BEFORE DELETE
ON task
FOR EACH ROW
EXECUTE PROCEDURE on_task_delete_proc();
CREATE OR REPLACE FUNCTION on_manager_insert() RETURNS TRIGGER AS
$$
BEGIN
IF NEW.id = 1 THEN
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
end if;
RETURN NEW;
IF NEW.id = 1 THEN
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
end if;
RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER on_manager_insert
AFTER INSERT
ON manager
FOR EACH ROW
AFTER INSERT
ON manager
FOR EACH ROW
EXECUTE PROCEDURE on_manager_insert();
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
$$
DECLARE
res INT = NULL;
res INT = NULL;
BEGIN
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
IF res IS NULL THEN
INSERT INTO worker_verifies_task (worker, verification_hash, task)
SELECT wid, ver, task.id
FROM task
WHERE assignee = wid
AND task.id = tid;
DELETE
FROM task
WHERE id = tid
AND assignee = wid
AND (SELECT COUNT(*) as vcnt
FROM worker_verifies_task wvt
WHERE task = tid
GROUP BY wvt.verification_hash
ORDER BY vcnt DESC
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
IF res IS NULL THEN
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
end if;
end if;
INSERT INTO worker_verifies_task (worker, verification_hash, task)
SELECT wid, ver, task.id
FROM task
WHERE assignee = wid
AND task.id = tid;
RETURN res IS NOT NULL;
DELETE
FROM task
WHERE id = tid
AND assignee = wid
AND (SELECT COUNT(*) as vcnt
FROM worker_verifies_task wvt
WHERE task = tid
GROUP BY wvt.verification_hash
ORDER BY vcnt DESC
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
IF res IS NULL THEN
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
end if;
end if;
RETURN res IS NOT NULL;
END;
$$ LANGUAGE 'plpgsql';

View File

@ -9,6 +9,7 @@ type Worker struct {
Created int64 `json:"created"`
Alias string `json:"alias,omitempty"`
Secret []byte `json:"secret"`
Paused bool `json:"paused"`
}
type WorkerStats struct {
@ -96,8 +97,8 @@ func (database *Database) GrantAccess(workerId int64, projectId int64) bool {
func (database *Database) UpdateWorker(worker *Worker) bool {
db := database.getDB()
res, err := db.Exec(`UPDATE worker SET alias=$1 WHERE id=$2`,
worker.Alias, worker.Id)
res, err := db.Exec(`UPDATE worker SET alias=$1, paused=$2 WHERE id=$3`,
worker.Alias, worker.Paused, worker.Id)
handleErr(err)
rowsAffected, _ := res.RowsAffected()

View File

@ -6,6 +6,7 @@ import (
"github.com/simon987/task_tracker/client"
"github.com/simon987/task_tracker/storage"
"net/http"
"strings"
"testing"
)
@ -29,6 +30,10 @@ func TestCreateGetWorker(t *testing.T) {
if w.Alias != "my_worker_alias" {
t.Error()
}
if w.Paused != false {
t.Error()
}
}
func TestGetWorkerNotFound(t *testing.T) {
@ -68,6 +73,10 @@ func TestUpdateAliasValid(t *testing.T) {
if w.Alias != "new alias" {
t.Error()
}
if w.Paused != false {
t.Error()
}
}
func TestCreateWorkerAliasInvalid(t *testing.T) {
@ -109,6 +118,74 @@ func TestInvalidAccessRequest(t *testing.T) {
}
}
func TestAssignTaskWhenPaused(t *testing.T) {
w := genWid()
pid := createProjectAsAdmin(api.CreateProjectRequest{
Name: "testassigntaskwhenpaused",
CloneUrl: "testassigntaskwhenpaused",
GitRepo: "testassigntaskwhenpaused",
}).Content.Id
requestAccess(api.CreateWorkerAccessRequest{
Submit: true,
Assign: true,
Project: pid,
}, w)
acceptAccessRequest(pid, w.Id, testAdminCtx)
r := createTask(api.SubmitTaskRequest{
Project: pid,
Recipe: "a",
Hash64: 1,
}, w)
if r.Ok != true {
t.Error()
}
pauseWorker(&api.WorkerSetPausedRequest{
Paused: true,
Worker: w.Id,
}, testAdminCtx)
resp := getTaskFromProject(pid, w)
if resp.Ok != false {
t.Error()
}
if !strings.Contains(resp.Message, "paused") {
t.Error()
}
}
func TestPauseInvalidWorker(t *testing.T) {
r := pauseWorker(&api.WorkerSetPausedRequest{
Paused: true,
Worker: 9999111,
}, testAdminCtx)
if r.Ok != false {
t.Error()
}
}
func TestPauseUnauthorized(t *testing.T) {
w := genWid()
r := pauseWorker(&api.WorkerSetPausedRequest{
Paused: true,
Worker: w.Id,
}, testUserCtx)
if r.Ok != false {
t.Error()
}
}
func createWorker(req api.CreateWorkerRequest) (ar client.CreateWorkerResponse) {
r := Post("/worker/create", req, nil, nil)
UnmarshalResponse(r, &ar)
@ -147,8 +224,13 @@ func rejectAccessRequest(pid int64, wid int64, s *http.Client) (ar api.JsonRespo
}
func updateWorker(request api.UpdateWorkerRequest, w *storage.Worker) (ar api.JsonResponse) {
r := Post("/worker/update", request, w, nil)
UnmarshalResponse(r, &ar)
return
}
func pauseWorker(request *api.WorkerSetPausedRequest, s *http.Client) (ar api.JsonResponse) {
r := Post("/worker/set_paused", request, nil, s)
UnmarshalResponse(r, &ar)
return
}

View File

@ -1,180 +1,181 @@
DROP TABLE IF EXISTS worker, project, task, log_entry,
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task;
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
worker_verifies_task;
CREATE TABLE worker
(
id SERIAL PRIMARY KEY NOT NULL,
alias TEXT NOT NULL,
created INTEGER NOT NULL,
secret BYTEA NOT NULL,
closed_task_count INTEGER DEFAULT 0 NOT NULL
id SERIAL PRIMARY KEY NOT NULL,
alias TEXT NOT NULL,
created INTEGER NOT NULL,
secret BYTEA NOT NULL,
closed_task_count INTEGER DEFAULT 0 NOT NULL,
paused boolean NOT NULL DEFAULT false
);
CREATE TABLE project
(
id SERIAL PRIMARY KEY NOT NULL,
priority INTEGER DEFAULT 0 NOT NULL,
closed_task_count INT DEFAULT 0 NOT NULL,
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 NOT NULL,
version TEXT NOT NULL,
motd TEXT NOT NULL,
secret TEXT NOT NULL DEFAULT '{}',
webhook_secret TEXT NOT NULL,
assign_rate DOUBLE PRECISION NOT NULL,
submit_rate DOUBLE PRECISION NOT NULL
id SERIAL PRIMARY KEY NOT NULL,
priority INTEGER DEFAULT 0 NOT NULL,
closed_task_count INT DEFAULT 0 NOT NULL,
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 NOT NULL,
version TEXT NOT NULL,
motd TEXT NOT NULL,
secret TEXT NOT NULL DEFAULT '{}',
webhook_secret TEXT NOT NULL,
assign_rate DOUBLE PRECISION NOT NULL,
submit_rate DOUBLE PRECISION NOT NULL
);
CREATE TABLE worker_access
(
worker INTEGER REFERENCES worker (id),
project INTEGER REFERENCES project (id),
role_assign boolean,
role_submit boolean,
request boolean,
primary key (worker, project)
worker INTEGER REFERENCES worker (id),
project INTEGER REFERENCES project (id),
role_assign boolean,
role_submit boolean,
request boolean,
primary key (worker, project)
);
CREATE TABLE task
(
hash64 BIGINT DEFAULT NULL,
id SERIAL PRIMARY KEY,
project INTEGER REFERENCES project (id),
assignee INTEGER REFERENCES worker (id),
max_assign_time INTEGER DEFAULT 0,
assign_time INTEGER DEFAULT NULL,
verification_count INTEGER DEFAULT 0,
priority SMALLINT DEFAULT 0,
retries SMALLINT DEFAULT 0,
max_retries SMALLINT,
status SMALLINT DEFAULT 1,
recipe TEXT,
UNIQUE (project, hash64)
hash64 BIGINT DEFAULT NULL,
id SERIAL PRIMARY KEY,
project INTEGER REFERENCES project (id),
assignee INTEGER REFERENCES worker (id),
max_assign_time INTEGER DEFAULT 0,
assign_time INTEGER DEFAULT NULL,
verification_count INTEGER DEFAULT 0,
priority SMALLINT DEFAULT 0,
retries SMALLINT DEFAULT 0,
max_retries SMALLINT,
status SMALLINT DEFAULT 1,
recipe TEXT,
UNIQUE (project, hash64)
);
CREATE TABLE worker_verifies_task
(
verification_hash BIGINT NOT NULL,
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
worker INT REFERENCES worker (id) NOT NULL
verification_hash BIGINT NOT NULL,
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
worker INT REFERENCES worker (id) NOT NULL
);
CREATE TABLE log_entry
(
level INTEGER NOT NULL,
message TEXT NOT NULL,
message_data TEXT NOT NULL,
timestamp INTEGER NOT NULL
level INTEGER NOT NULL,
message TEXT NOT NULL,
message_data TEXT NOT NULL,
timestamp INTEGER NOT NULL
);
CREATE TABLE manager
(
id SERIAL PRIMARY KEY,
register_time INTEGER NOT NULL,
tracker_admin BOOLEAN NOT NULL,
username TEXT UNIQUE NOT NULL,
password BYTEA NOT NULL
id SERIAL PRIMARY KEY,
register_time INTEGER NOT NULL,
tracker_admin BOOLEAN NOT NULL,
username TEXT UNIQUE NOT NULL,
password BYTEA NOT NULL
);
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,
PRIMARY KEY (manager, project)
manager INTEGER REFERENCES manager (id) NOT NULL,
role SMALLINT NOT NULL,
project INTEGER REFERENCES project (id) NOT NULL,
PRIMARY KEY (manager, project)
);
CREATE TABLE project_monitoring_snapshot
(
project INT REFERENCES project (id) NOT NULL,
new_task_count INT NOT NULL,
failed_task_count INT NOT NULL,
closed_task_count INT NOT NULL,
awaiting_verification_task_count INT NOT NULL,
worker_access_count INT NOT NULL,
timestamp INT NOT NULL
project INT REFERENCES project (id) NOT NULL,
new_task_count INT NOT NULL,
failed_task_count INT NOT NULL,
closed_task_count INT NOT NULL,
awaiting_verification_task_count INT NOT NULL,
worker_access_count INT NOT NULL,
timestamp INT NOT NULL
);
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
$$
DECLARE
chain INTEGER;
chain INTEGER;
BEGIN
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)
ON CONFLICT DO NOTHING;
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)
ON CONFLICT DO NOTHING;
end if;
end if;
end if;
RETURN OLD;
RETURN OLD;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER on_task_delete
BEFORE DELETE
ON task
FOR EACH ROW
BEFORE DELETE
ON task
FOR EACH ROW
EXECUTE PROCEDURE on_task_delete_proc();
CREATE OR REPLACE FUNCTION on_manager_insert() RETURNS TRIGGER AS
$$
BEGIN
IF NEW.id = 1 THEN
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
end if;
RETURN NEW;
IF NEW.id = 1 THEN
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
end if;
RETURN NEW;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER on_manager_insert
AFTER INSERT
ON manager
FOR EACH ROW
AFTER INSERT
ON manager
FOR EACH ROW
EXECUTE PROCEDURE on_manager_insert();
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
$$
DECLARE
res INT = NULL;
res INT = NULL;
BEGIN
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
IF res IS NULL THEN
INSERT INTO worker_verifies_task (worker, verification_hash, task)
SELECT wid, ver, task.id
FROM task
WHERE assignee = wid
AND task.id = tid;
DELETE
FROM task
WHERE id = tid
AND assignee = wid
AND (SELECT COUNT(*) as vcnt
FROM worker_verifies_task wvt
WHERE task = tid
GROUP BY wvt.verification_hash
ORDER BY vcnt DESC
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
IF res IS NULL THEN
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
end if;
end if;
INSERT INTO worker_verifies_task (worker, verification_hash, task)
SELECT wid, ver, task.id
FROM task
WHERE assignee = wid
AND task.id = tid;
RETURN res IS NOT NULL;
DELETE
FROM task
WHERE id = tid
AND assignee = wid
AND (SELECT COUNT(*) as vcnt
FROM worker_verifies_task wvt
WHERE task = tid
GROUP BY wvt.verification_hash
ORDER BY vcnt DESC
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
IF res IS NULL THEN
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
end if;
end if;
RETURN res IS NOT NULL;
END;
$$ LANGUAGE 'plpgsql';