mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-16 08:56:45 +00:00
some bug fixes, some optimizations
This commit is contained in:
parent
51eb9ae6da
commit
4edf354f8d
@ -1,8 +1,8 @@
|
||||
|
||||
<a href='https://github.com/jpoles1/gopherbadger' target='_blank'></a>
|
||||
<a href='https://github.com/jpoles1/gopherbadger' target='_blank'></a>
|
||||
|
||||
### Running tests
|
||||
```bash
|
||||
cd test/
|
||||
go test -bench
|
||||
go test
|
||||
```
|
13
api/log.go
13
api/log.go
@ -30,6 +30,11 @@ type GetLogResponse struct {
|
||||
Logs *[]storage.LogEntry `json:"logs"`
|
||||
}
|
||||
|
||||
type LogResponse struct {
|
||||
Ok bool `json:"ok"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *LogRequest) Time() time.Time {
|
||||
|
||||
t := time.Unix(e.TimeStamp, 0)
|
||||
@ -89,7 +94,7 @@ func (api *WebAPI) LogTrace(r *Request) {
|
||||
|
||||
entry, err := api.parseLogEntry(r)
|
||||
if err != nil {
|
||||
r.Json(GetLogResponse{
|
||||
r.Json(LogResponse{
|
||||
Ok: false,
|
||||
Message: "Could not parse request",
|
||||
}, 400)
|
||||
@ -106,7 +111,7 @@ func (api *WebAPI) LogInfo(r *Request) {
|
||||
|
||||
entry, err := api.parseLogEntry(r)
|
||||
if err != nil {
|
||||
r.Json(GetLogResponse{
|
||||
r.Json(LogResponse{
|
||||
Ok: false,
|
||||
Message: "Could not parse request",
|
||||
}, 400)
|
||||
@ -123,7 +128,7 @@ func (api *WebAPI) LogWarn(r *Request) {
|
||||
|
||||
entry, err := api.parseLogEntry(r)
|
||||
if err != nil {
|
||||
r.Json(GetLogResponse{
|
||||
r.Json(LogResponse{
|
||||
Ok: false,
|
||||
Message: "Could not parse request",
|
||||
}, 400)
|
||||
@ -140,7 +145,7 @@ func (api *WebAPI) LogError(r *Request) {
|
||||
|
||||
entry, err := api.parseLogEntry(r)
|
||||
if err != nil {
|
||||
r.Json(GetLogResponse{
|
||||
r.Json(LogResponse{
|
||||
Ok: false,
|
||||
Message: "Could not parse request",
|
||||
}, 400)
|
||||
|
@ -202,7 +202,15 @@ func (api *WebAPI) ProjectGet(r *Request) {
|
||||
|
||||
func (api *WebAPI) ProjectGetAllProjects(r *Request) {
|
||||
|
||||
projects := api.Database.GetAllProjects()
|
||||
worker, _ := api.validateSignature(r)
|
||||
|
||||
var id int64
|
||||
if worker == nil {
|
||||
id = 0
|
||||
} else {
|
||||
id = worker.Id
|
||||
}
|
||||
projects := api.Database.GetAllProjects(id)
|
||||
|
||||
r.OkJson(GetAllProjectsResponse{
|
||||
Ok: true,
|
||||
|
17
api/task.go
17
api/task.go
@ -156,11 +156,20 @@ func (api *WebAPI) TaskGet(r *Request) {
|
||||
}
|
||||
|
||||
task := api.Database.GetTask(worker)
|
||||
if task == nil {
|
||||
|
||||
r.OkJson(GetTaskResponse{
|
||||
Ok: true,
|
||||
Task: task,
|
||||
})
|
||||
r.OkJson(GetTaskResponse{
|
||||
Ok: false,
|
||||
Message: "No task available",
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
r.OkJson(GetTaskResponse{
|
||||
Ok: true,
|
||||
Task: task,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (api WebAPI) validateSignature(r *Request) (*storage.Worker, error) {
|
||||
|
@ -8,9 +8,9 @@ database:
|
||||
git:
|
||||
webhook_secret: "very_secret_secret"
|
||||
# Github: sha1, Gogs: sha256
|
||||
webhook_hash: "sha1"
|
||||
webhook_hash: "sha256"
|
||||
# Github: 'X-Hub-Signature', Gogs: 'X-Gogs-Signature'
|
||||
webhook_sig_header: "X-Hub-Signature"
|
||||
webhook_sig_header: "X-Gogs-Signature"
|
||||
|
||||
log:
|
||||
# panic, fatal, error, warn, info, debug, trace
|
||||
|
33
schema.sql
33
schema.sql
@ -113,3 +113,36 @@ CREATE TRIGGER on_task_delete
|
||||
ON task
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_task_delete_proc();
|
||||
|
||||
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver INT) RETURNS BOOLEAN AS
|
||||
$$
|
||||
DECLARE
|
||||
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;
|
||||
|
||||
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';
|
||||
|
@ -104,8 +104,8 @@ func (database *Database) UpdateManager(manager *Manager) {
|
||||
func (database *Database) UpdateManagerPassword(manager *Manager, newPassword []byte) {
|
||||
|
||||
hash := crypto.SHA512.New()
|
||||
hash.Write([]byte(manager.Username))
|
||||
hash.Write(newPassword)
|
||||
hash.Write([]byte(manager.Username))
|
||||
hashedPassword := hash.Sum(nil)
|
||||
|
||||
db := database.getDB()
|
||||
|
@ -131,14 +131,27 @@ func (database *Database) UpdateProject(project *Project) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (database Database) GetAllProjects() *[]Project {
|
||||
func (database Database) GetAllProjects(workerId int64) *[]Project {
|
||||
projects := make([]Project, 0)
|
||||
|
||||
db := database.getDB()
|
||||
rows, err := db.Query(`SELECT
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
if workerId == 0 {
|
||||
rows, err = db.Query(`SELECT
|
||||
Id, priority, name, clone_url, git_repo, version, motd, public
|
||||
FROM project
|
||||
LEFT JOIN worker_has_access_to_project whatp ON whatp.project = id
|
||||
WHERE public
|
||||
ORDER BY name`)
|
||||
} else {
|
||||
rows, err = db.Query(`SELECT
|
||||
Id, priority, name, clone_url, git_repo, version, motd, public
|
||||
FROM project
|
||||
LEFT JOIN worker_has_access_to_project whatp ON whatp.project = id
|
||||
WHERE public OR whatp.worker = $1
|
||||
ORDER BY name`, workerId)
|
||||
}
|
||||
handleErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
|
@ -134,52 +134,34 @@ func (database Database) ReleaseTask(id int64, workerId int64, result TaskResult
|
||||
|
||||
db := database.getDB()
|
||||
|
||||
var rowsAffected int64
|
||||
var taskUpdated bool
|
||||
if result == TR_OK {
|
||||
var pid int64
|
||||
|
||||
//If no verification is required
|
||||
row := db.QueryRow(`DELETE FROM task WHERE id=$1 AND assignee=$2 AND verification_count < 2
|
||||
RETURNING project`, id, workerId)
|
||||
err := row.Scan(&pid)
|
||||
if err == nil {
|
||||
rowsAffected = 1
|
||||
} else {
|
||||
//If verification is required
|
||||
_, err = db.Exec(`INSERT INTO worker_verifies_task (worker, verification_hash, task)
|
||||
SELECT $1,$2,task.id FROM task WHERE assignee=$1`, workerId, verification)
|
||||
handleErr(err)
|
||||
|
||||
res, _ := db.Exec(`DELETE FROM task WHERE id=$1 AND assignee=$2 AND
|
||||
(SELECT COUNT(*) as vcnt FROM worker_verifies_task wvt WHERE task=$1
|
||||
GROUP BY wvt.verification_hash ORDER BY vcnt DESC LIMIT 1) >= task.verification_count`,
|
||||
id, workerId)
|
||||
rowsAffected, _ = res.RowsAffected()
|
||||
|
||||
_, _ = db.Exec(`UPDATE task SET assignee=NULL WHERE id=$1 AND assignee=$2`, id, workerId)
|
||||
}
|
||||
row := db.QueryRow(`SELECT release_task_ok($1,$2,$3)`, workerId, id, verification)
|
||||
|
||||
_ = row.Scan(&taskUpdated)
|
||||
} 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)
|
||||
WHERE id=$1 AND assignee=$2`, id, workerId)
|
||||
handleErr(err)
|
||||
rowsAffected, _ = res.RowsAffected()
|
||||
rowsAffected, _ := res.RowsAffected()
|
||||
taskUpdated = rowsAffected == 1
|
||||
} else if result == TR_SKIP {
|
||||
res, err := db.Exec(`UPDATE task SET (status, assignee) = (1, NULL)
|
||||
WHERE id=$1 AND assignee=$2`, id, workerId)
|
||||
handleErr(err)
|
||||
rowsAffected, _ = res.RowsAffected()
|
||||
rowsAffected, _ := res.RowsAffected()
|
||||
taskUpdated = rowsAffected == 1
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"rowsAffected": rowsAffected,
|
||||
"taskUpdated": taskUpdated,
|
||||
"taskId": id,
|
||||
"workerId": workerId,
|
||||
"verification": verification,
|
||||
}).Trace("Database.ReleaseTask")
|
||||
|
||||
return rowsAffected == 1
|
||||
return taskUpdated
|
||||
}
|
||||
|
||||
func (database *Database) GetTaskFromProject(worker *Worker, projectId int64) *Task {
|
||||
|
@ -113,3 +113,36 @@ CREATE TRIGGER on_task_delete
|
||||
ON task
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE on_task_delete_proc();
|
||||
|
||||
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver INT) RETURNS BOOLEAN AS
|
||||
$$
|
||||
DECLARE
|
||||
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;
|
||||
|
||||
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';
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
gopherbadger -md="README.md" -png=false -style flat-square
|
||||
rm coverage.out
|
@ -4,35 +4,31 @@
|
||||
<mat-card-subtitle>{{"project.create_subtitle" | translate}}</mat-card-subtitle>
|
||||
|
||||
<mat-card-content>
|
||||
<form (ngSubmit)="onSubmit()">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{"project.name" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.name" name="name" [placeholder]="'project.name' | translate">
|
||||
<input type="text" matInput [(ngModel)]="project.name" [placeholder]="'project.name' | translate">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{ "project.clone_url" | translate}}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.clone_url" name="clone_url"
|
||||
[placeholder]="'project.clone_url_placeholder' | translate">
|
||||
<input type="text" matInput [(ngModel)]="project.clone_url"
|
||||
[placeholder]="'project.clone_url_placeholder' | translate">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>{{ "project.git_repo" | translate }}</mat-label>
|
||||
<input type="text" matInput [(ngModel)]="project.git_repo" name="git_repo"
|
||||
[placeholder]="'project.git_repo_placeholder' | translate">
|
||||
<input type="text" matInput [(ngModel)]="project.git_repo"
|
||||
[placeholder]="'project.git_repo_placeholder' | translate">
|
||||
<mat-hint align="start">
|
||||
{{"project.git_repo_hint" | translate}}
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox matInput [(ngModel)]="project.public" name="public" style="padding-top: 1em">
|
||||
<mat-checkbox matInput [(ngModel)]="project.public" style="padding-top: 1em">
|
||||
{{"project.public" | translate}}</mat-checkbox>
|
||||
|
||||
<input type="hidden" name="version" value="{{project.version}}">
|
||||
|
||||
</form>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" type="submit">{{'project.create' | translate}}</button>
|
||||
<button mat-raised-button color="primary" (click)="onSubmit()">{{'project.create' | translate}}</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
@ -71,7 +71,7 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
}
|
||||
this.noTasks = false;
|
||||
|
||||
this.timeline.data.labels = this.snapshots.map(s => s.time_stamp as any);
|
||||
this.timeline.data.labels = this.snapshots.map(s => s.time_stamp * 1000 as any);
|
||||
this.timeline.data.datasets = this.makeTimelineDataset(this.snapshots);
|
||||
this.timeline.update();
|
||||
this.statusPie.data.datasets = [
|
||||
@ -164,7 +164,7 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
this.timeline = new Chart(ctx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: this.snapshots.map(s => s.time_stamp as any),
|
||||
labels: this.snapshots.map(s => s.time_stamp * 1000 as any),
|
||||
datasets: this.makeTimelineDataset(this.snapshots),
|
||||
},
|
||||
options: {
|
||||
@ -198,11 +198,16 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
|
||||
private setupStatusPie() {
|
||||
|
||||
if (this.lastSnapshot == null || (this.lastSnapshot.awaiting_verification_count == 0 &&
|
||||
if (this.lastSnapshot == undefined || (this.lastSnapshot.awaiting_verification_count == 0 &&
|
||||
this.lastSnapshot.closed_task_count == 0 &&
|
||||
this.lastSnapshot.new_task_count == 0 &&
|
||||
this.lastSnapshot.failed_task_count == 0)) {
|
||||
this.noTasks = true;
|
||||
|
||||
this.lastSnapshot = {
|
||||
closed_task_count: 0, time_stamp: 0, failed_task_count: 0,
|
||||
new_task_count: 0, awaiting_verification_count: 0
|
||||
}
|
||||
}
|
||||
|
||||
let elem = document.getElementById("status-pie") as any;
|
||||
|
Loading…
x
Reference in New Issue
Block a user