some bug fixes, some optimizations

This commit is contained in:
simon987 2019-02-11 20:10:33 -05:00
parent 51eb9ae6da
commit 4edf354f8d
13 changed files with 141 additions and 61 deletions

View File

@ -1,8 +1,8 @@
<a href='https://github.com/jpoles1/gopherbadger' target='_blank'>![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-93%25-brightgreen.svg?longCache=true&style=flat-square)</a>
<a href='https://github.com/jpoles1/gopherbadger' target='_blank'>![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-78%25-brightgreen.svg?longCache=true&style=flat-square)</a>
### Running tests
```bash
cd test/
go test -bench
go test
```

View File

@ -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)

View File

@ -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,

View File

@ -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) {

View File

@ -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

View File

@ -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';

View File

@ -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()

View File

@ -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() {

View File

@ -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 {

View File

@ -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';

View File

@ -1,4 +0,0 @@
#!/usr/bin/env bash
gopherbadger -md="README.md" -png=false -style flat-square
rm coverage.out

View File

@ -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>

View File

@ -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;