From 0cc0ae3c7dd0e4090b7c2b4cd9d3da0dfb60cb87 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sun, 1 Jan 2023 21:11:20 +0100 Subject: [PATCH] New route to run gradation tests --- repositories.go | 103 +++++++++++++++++- ui/src/lib/works.js | 12 ++ ui/src/routes/works/[wid]/rendus/+page.svelte | 16 ++- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/repositories.go b/repositories.go index 6a4dbe4..0ce2517 100644 --- a/repositories.go +++ b/repositories.go @@ -8,10 +8,13 @@ import ( "log" "net/http" "net/url" + "path/filepath" "strconv" "strings" "time" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/s3" "github.com/drone/drone-go/drone" "github.com/gin-gonic/gin" "golang.org/x/oauth2" @@ -291,6 +294,29 @@ func declareAPIAuthRepositoriesRoutes(router *gin.RouterGroup) { c.JSON(http.StatusOK, result) } }) + + repositoriesRoutes.POST("/gradation", func(c *gin.Context) { + loggeduser := c.MustGet("LoggedUser").(*User) + if !loggeduser.IsAdmin { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Permission denied."}) + return + } + + var u *User + if user, ok := c.Get("user"); ok { + u = user.(*User) + } else { + u = loggeduser + } + repo := c.MustGet("repository").(*Repository) + work, err := getWork(int(repo.IdWork)) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to find related work."}) + return + } + + TriggerTests(c, work, repo, u) + }) } type GitLabWebhook struct { @@ -465,6 +491,79 @@ func TriggerTagUpdate(c *gin.Context, work *Work, repo *Repository, u *User, tag c.JSON(http.StatusOK, repo) } +func TriggerTests(c *gin.Context, work *Work, repo *Repository, u *User) { + if work.GradationRepo == nil || len(*work.GradationRepo) == 0 { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "No tests defined for this work."}) + return + } + + slug := strings.SplitN(*work.GradationRepo, "/", 2) + if len(slug) != 2 { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Graduation repository is invalid."}) + return + } + + login := u.Login + groups := u.Groups + if u.Id != repo.IdUser { + user, _ := getUser(int(repo.IdUser)) + if user != nil { + login = user.Login + groups = user.Groups + } + } + + branch := "master" + if len(work.Tag) > 0 { + branch = work.Tag + } + if branch[len(branch)-1] == '-' { + branch += "grades" + } + + s, err := s3NewSession() + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Something goes wrong."}) + return + } + + req, _ := s3.New(s).GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String(s3_bucket), + Key: aws.String(filepath.Join(fmt.Sprintf("%d", work.Id), fmt.Sprintf("rendu-%s.tar.xz", u.Login))), + }) + + url, err := req.Presign(SharingTime) + if err != nil { + log.Println("Unable to create presign URL:", err) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Something goes wrong when creating the presigned URL."}) + return + } + + env := map[string]string{ + "SUBMISSION_URL": repo.URI, + "META_URL": url, + "LOGIN": login, + "GROUPS": groups, + "DEST": fmt.Sprintf("%d", work.Id), + } + + client := drone.NewClient(droneEndpoint, droneConfig) + result, err := client.BuildCreate(slug[0], slug[1], "", branch, env) + if err != nil { + log.Println("Unable to communicate with Drone:", err.Error()) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to communication with the extraction service."}) + return + } + + now := time.Now() + repo.TestsRef = fmt.Sprintf("%s/%d", *work.GradationRepo, result.Number) + repo.LastTests = &now + repo.Update() + + repo.Secret = []byte{} + c.JSON(http.StatusOK, repo) +} + type Repository struct { Id int64 `json:"id"` IdUser int64 `json:"id_user"` @@ -474,7 +573,7 @@ type Repository struct { LastCheck *time.Time `json:"last_check"` DroneRef string `json:"drone_ref,omitempty"` LastTests *time.Time `json:"last_tests"` - TestsRef string `json:"drone_ref,omitempty"` + TestsRef string `json:"tests_ref,omitempty"` AlreadyUsed bool `json:"already_used,omitempty"` } @@ -544,7 +643,7 @@ func (u *User) NewRepository(w *Work, uri string) (*Repository, error) { } else if rid, err := res.LastInsertId(); err != nil { return nil, err } else { - return &Repository{rid, u.Id, w.Id, uri, secret, nil, "", false}, nil + return &Repository{rid, u.Id, w.Id, uri, secret, nil, "", nil, "", false}, nil } } diff --git a/ui/src/lib/works.js b/ui/src/lib/works.js index df100d8..f44a47a 100644 --- a/ui/src/lib/works.js +++ b/ui/src/lib/works.js @@ -115,6 +115,18 @@ export class Work { throw new Error((await res.json()).errmsg); } } + + async runGradation(uid) { + const res = await fetch(uid?`api/users/${uid}/works/${this.id}/gradation`:`api/works/${this.id}/gradation`, { + method: 'POST', + headers: {'Accept': 'application/json'}, + }); + if (res.status == 200) { + return await res.json(); + } else { + throw new Error((await res.json()).errmsg); + } + } } export async function getWorks() { diff --git a/ui/src/routes/works/[wid]/rendus/+page.svelte b/ui/src/routes/works/[wid]/rendus/+page.svelte index 8ee3ba7..651b332 100644 --- a/ui/src/routes/works/[wid]/rendus/+page.svelte +++ b/ui/src/routes/works/[wid]/rendus/+page.svelte @@ -61,8 +61,8 @@ {#each users as user (user.id)} - {user.login} - + {user.login} + { nb_rendus += 1; show_dl_btn[user.id] = true; }} /> @@ -74,7 +74,7 @@ {repo.uri} -
+
{#if repo.last_check} - + + {/each}