This repository has been archived on 2024-03-28. You can view files and clone it, but cannot push or open issues or pull requests.
atsebay.t/repositories.go

346 lines
9.9 KiB
Go
Raw Normal View History

2022-09-04 09:38:10 +00:00
package main
import (
"flag"
2022-09-04 09:38:10 +00:00
"fmt"
"log"
"net/http"
"strconv"
2022-09-05 01:30:10 +00:00
"strings"
2022-09-04 09:38:10 +00:00
"time"
"github.com/drone/drone-go/drone"
2022-09-04 09:38:10 +00:00
"github.com/gin-gonic/gin"
"golang.org/x/oauth2"
2022-09-04 09:38:10 +00:00
)
var (
droneToken = ""
droneConfig *http.Client
droneEndpoint string
)
func init() {
flag.StringVar(&droneToken, "drone-token", droneToken, "Token for Drone Oauth")
flag.StringVar(&droneEndpoint, "drone-endpoint", droneEndpoint, "Drone Endpoint")
}
func initializeDroneOauth() {
if droneToken != "" {
config := new(oauth2.Config)
droneConfig = config.Client(
oauth2.NoContext,
&oauth2.Token{
AccessToken: droneToken,
},
)
}
}
2022-09-04 09:38:10 +00:00
func declareAPIAuthRepositoriesRoutes(router *gin.RouterGroup) {
router.GET("/repositories", func(c *gin.Context) {
var u *User
if user, ok := c.Get("user"); ok {
u = user.(*User)
} else {
u = c.MustGet("LoggedUser").(*User)
}
repositories, err := u.GetRepositories()
if err != nil {
log.Println("Unable to GetRepositories:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to retrieve your repositories. Please try again in a few moment."})
return
}
c.JSON(http.StatusOK, repositories)
})
router.POST("/repositories", func(c *gin.Context) {
var u *User
if user, ok := c.Get("user"); ok {
u = user.(*User)
} else {
u = c.MustGet("LoggedUser").(*User)
}
var repository Repository
if err := c.ShouldBindJSON(&repository); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
2022-09-04 15:59:36 +00:00
var w *Work
if work, ok := c.Get("work"); ok {
w = work.(*Work)
} else if repository.IdWork > 0 {
var err error
w, err = getWork(int(repository.IdWork))
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Unable to find the given work identifier."})
return
}
} else {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Unable to find the given work identifier."})
return
}
2022-09-04 09:38:10 +00:00
k, err := u.NewRepository(w, repository.URI)
if err != nil {
log.Println("Unable to NewRepository:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to register your public repository. Please try again in a few moment."})
return
}
c.JSON(http.StatusOK, k)
})
repositoriesRoutes := router.Group("/repositories/:rid")
repositoriesRoutes.Use(repositoryHandler)
repositoriesRoutes.GET("", func(c *gin.Context) {
repo := c.MustGet("repository").(*Repository)
c.JSON(http.StatusOK, repo)
})
repositoriesRoutes.PUT("", func(c *gin.Context) {
current := c.MustGet("repository").(*Repository)
var new Repository
if err := c.ShouldBindJSON(&new); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
new.Id = current.Id
u := c.MustGet("LoggedUser").(*User)
if new.IdUser != current.IdUser && !u.IsAdmin {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Operation not allowed."})
return
}
if repository, err := new.Update(); err != nil {
log.Println("Unable to Update repository:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs during repository updation: %s", err.Error())})
return
} else {
c.JSON(http.StatusOK, repository)
}
})
repositoriesRoutes.DELETE("", func(c *gin.Context) {
repository := c.MustGet("repository").(*Repository)
if _, err := repository.Delete(); err != nil {
log.Println("Unable to Delete repository:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs during repository deletion: %s", err.Error())})
return
} else {
c.JSON(http.StatusOK, nil)
}
})
2022-09-04 21:54:10 +00:00
repositoriesRoutes.POST("/trigger", func(c *gin.Context) {
var u *User
if user, ok := c.Get("user"); ok {
u = user.(*User)
} else {
u = c.MustGet("LoggedUser").(*User)
}
2022-09-04 21:54:10 +00:00
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
}
2022-09-04 21:54:10 +00:00
now := time.Now()
2022-09-05 02:40:49 +00:00
if repo.LastCheck != nil && !repo.LastCheck.Before(now.Add(-5*time.Minute)) {
2022-09-04 21:54:10 +00:00
c.AbortWithStatusJSON(http.StatusPaymentRequired, gin.H{"errmsg": "Please wait between two pulls."})
return
2022-09-05 02:40:49 +00:00
}
2022-09-04 21:54:10 +00:00
client := drone.NewClient(droneEndpoint, droneConfig)
result, err := client.BuildCreate("srs", "atsebay.t-worker", "", "master", map[string]string{
"REPO_URL": repo.URI,
"REPO_TAG": work.Tag,
"LOGIN": u.Login,
"DEST": fmt.Sprintf("%d", work.Id),
})
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
}
repo.DroneRef = fmt.Sprintf("%s/%s/%d", "srs", "atsebay.t-worker", result.Number)
2022-09-04 21:54:10 +00:00
repo.LastCheck = &now
repo.Update()
c.JSON(http.StatusOK, repo)
})
2022-09-05 01:30:10 +00:00
repositoriesRoutes.GET("/state", func(c *gin.Context) {
repo := c.MustGet("repository").(*Repository)
tmp := strings.Split(repo.DroneRef, "/")
2022-09-05 02:40:49 +00:00
if len(tmp) < 3 {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "No build number. Please try pulling your work."})
return
}
2022-09-05 01:30:10 +00:00
nbuild, err := strconv.Atoi(tmp[2])
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Bad build number. Please retry pulling your work."})
return
}
client := drone.NewClient(droneEndpoint, droneConfig)
result, err := client.Build(tmp[0], tmp[1], nbuild)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Unable to find the referenced extraction."})
return
}
c.JSON(http.StatusOK, result)
2022-09-05 02:07:41 +00:00
})
2022-09-05 02:58:48 +00:00
repositoriesRoutes.GET("/state-logs", func(c *gin.Context) {
repo := c.MustGet("repository").(*Repository)
tmp := strings.Split(repo.DroneRef, "/")
if len(tmp) < 3 {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "No build number. Please try pulling your work."})
return
}
nbuild, err := strconv.Atoi(tmp[2])
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Bad build number. Please retry pulling your work."})
return
}
client := drone.NewClient(droneEndpoint, droneConfig)
result, err := client.Logs(tmp[0], tmp[1], nbuild, 1, 2)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Unable to retrieve logs."})
return
}
if len(result) > 7 {
c.JSON(http.StatusOK, result[7:])
} else {
c.JSON(http.StatusOK, result)
}
})
2022-09-04 09:38:10 +00:00
}
func repositoryHandler(c *gin.Context) {
var u *User
if user, ok := c.Get("user"); ok {
u = user.(*User)
} else {
u = c.MustGet("LoggedUser").(*User)
}
if rid, err := strconv.Atoi(string(c.Param("rid"))); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad repository identifier."})
return
} else if u.IsAdmin {
if repository, err := getRepository(rid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Repository not found."})
return
} else {
c.Set("repository", repository)
c.Next()
}
} else if repository, err := u.getRepository(rid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Repository not found."})
return
} else {
c.Set("repository", repository)
c.Next()
}
}
type Repository struct {
Id int64 `json:"id"`
IdUser int64 `json:"id_user"`
IdWork int64 `json:"id_work"`
URI string `json:"uri"`
LastCheck *time.Time `json:"last_check"`
DroneRef string `json:"drone_ref,omitempty"`
2022-09-04 09:38:10 +00:00
}
func (u *User) GetRepositories() (repositories []*Repository, err error) {
if rows, errr := DBQuery("SELECT id_repository, id_user, id_work, uri, last_check, droneref FROM user_work_repositories WHERE id_user=?", u.Id); errr != nil {
2022-09-04 09:38:10 +00:00
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var repo Repository
if err = rows.Scan(&repo.Id, &repo.IdUser, &repo.IdWork, &repo.URI, &repo.LastCheck, &repo.DroneRef); err != nil {
2022-09-04 09:38:10 +00:00
return
}
repositories = append(repositories, &repo)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
func getRepository(id int) (r *Repository, err error) {
r = new(Repository)
err = DBQueryRow("SELECT id_repository, id_user, id_work, uri, last_check, droneref FROM user_work_repositories WHERE id_repository=?", id).Scan(&r.Id, &r.IdUser, &r.IdWork, &r.URI, &r.LastCheck, &r.DroneRef)
2022-09-04 09:38:10 +00:00
return
}
func (u *User) getRepository(id int) (r *Repository, err error) {
r = new(Repository)
err = DBQueryRow("SELECT id_repository, id_user, id_work, uri, last_check, droneref FROM user_work_repositories WHERE id_repository=? AND id_user=?", id, u.Id).Scan(&r.Id, &r.IdUser, &r.IdWork, &r.URI, &r.LastCheck, &r.DroneRef)
2022-09-04 09:38:10 +00:00
return
}
func (u *User) NewRepository(w *Work, uri string) (*Repository, error) {
2022-09-05 01:30:10 +00:00
if res, err := DBExec("INSERT INTO user_work_repositories (id_user, id_work, uri, droneref) VALUES (?, ?, ?, ?)", u.Id, w.Id, uri, ""); err != nil {
2022-09-04 09:38:10 +00:00
return nil, err
} else if rid, err := res.LastInsertId(); err != nil {
return nil, err
} else {
return &Repository{rid, u.Id, w.Id, uri, nil, ""}, nil
2022-09-04 09:38:10 +00:00
}
}
func (r *Repository) Update() (*Repository, error) {
if _, err := DBExec("UPDATE user_work_repositories SET id_user = ?, id_work = ?, uri = ?, last_check = ?, droneref = ? WHERE id_repository = ?", r.IdUser, r.IdWork, r.URI, r.LastCheck, r.DroneRef, r.Id); err != nil {
2022-09-04 09:38:10 +00:00
return nil, err
} else {
return r, err
}
}
func (r Repository) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM user_work_repositories WHERE id_repository = ?", r.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func ClearRepositories() (int64, error) {
if res, err := DBExec("DELETE FROM user_work_repositories"); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}