package api import ( "fmt" "log" "net/http" "strconv" "strings" "srs.epita.fr/fic-server/libfic" "github.com/gin-gonic/gin" ) func declareTodoRoutes(router *gin.RouterGroup) { router.GET("/qa_exercices.json", getExerciceTested) router.GET("/qa_mywork.json", getQAWork) router.GET("/qa_myexercices.json", getQAView) router.GET("/qa_work.json", getQATodo) } func declareTodoManagerRoutes(router *gin.RouterGroup) { router.POST("/qa_assign_work", assignWork) router.POST("/qa_my_exercices.json", addQAView) router.POST("/qa_work.json", createQATodo) todosRoutes := router.Group("/todo/:wid") todosRoutes.Use(todoHandler) todosRoutes.GET("", showTodo) todosRoutes.DELETE("", deleteQATodo) } type exerciceTested map[int64]string func getExerciceTested(c *gin.Context) { var teamid int64 if team, ok := c.Get("team"); ok { teamid = team.(*fic.Team).Id } else { teamid = c.MustGet("LoggedTeam").(int64) } team, err := fic.GetTeam(teamid) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } exercices, err := fic.GetExercices() if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } ret := exerciceTested{} for _, exercice := range exercices { if team.HasAccess(exercice) { if t := team.HasSolved(exercice); t != nil { ret[exercice.Id] = "solved" } else if cnt, _ := team.CountTries(exercice); cnt > 0 { ret[exercice.Id] = "tried" } else { ret[exercice.Id] = "access" } } } c.JSON(http.StatusOK, ret) } func getQAView(c *gin.Context) { var teamid int64 if team, ok := c.Get("team"); ok { teamid = team.(*fic.Team).Id } else { teamid = c.MustGet("LoggedTeam").(int64) } team, err := fic.GetTeam(teamid) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } view, err := team.GetQAView() if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } c.JSON(http.StatusOK, view) } func getQAWork(c *gin.Context) { var teamid int64 if team, ok := c.Get("team"); ok { teamid = team.(*fic.Team).Id } else { teamid = c.MustGet("LoggedTeam").(int64) } team, err := fic.GetTeam(teamid) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } queries, err := team.GetQAQueries() if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } c.JSON(http.StatusOK, queries) } func getQATodo(c *gin.Context) { var teamid int64 if team, ok := c.Get("team"); ok { teamid = team.(*fic.Team).Id } else { teamid = c.MustGet("LoggedTeam").(int64) } team, err := fic.GetTeam(teamid) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } todo, err := team.GetQATodo() if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } exercices, err := fic.GetExercices() if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } for _, exercice := range exercices { if cnt, _ := team.CountTries(exercice); cnt > 0 { todo = append(todo, &fic.QATodo{ Id: 0, IdTeam: teamid, IdExercice: exercice.Id, }) } } c.JSON(http.StatusOK, todo) } func createQATodo(c *gin.Context) { var ut fic.QATodo if err := c.ShouldBindJSON(&ut); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } team, err := fic.GetTeam(ut.IdTeam) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } todo, err := team.NewQATodo(ut.IdExercice) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } c.JSON(http.StatusOK, todo) } func addQAView(c *gin.Context) { var ut fic.QATodo if err := c.ShouldBindJSON(&ut); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } team, err := fic.GetTeam(ut.IdTeam) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } view, err := team.NewQAView(ut.IdExercice) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } c.JSON(http.StatusOK, view) } func todoHandler(c *gin.Context) { team := c.MustGet("team").(*fic.Team) var wid int64 var todos []*fic.QATodo var err error if wid, err = strconv.ParseInt(string(c.Param("wid")), 10, 64); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad todo identifier."}) return } if todos, err = team.GetQATodo(); err != nil { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Todo not found."}) return } for _, t := range todos { if t.Id == wid { c.Set("todo", t) c.Next() return } } c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Unable to find the requested QA Todo"}) } func showTodo(c *gin.Context) { c.JSON(http.StatusOK, c.MustGet("todo")) } func deleteQATodo(c *gin.Context) { todo := c.MustGet("todo").(*fic.QATodo) if _, err := todo.Delete(); err != nil { c.AbortWithError(http.StatusInternalServerError, err) } else { c.Status(http.StatusOK) } } type QAAssignWork struct { Turns int `json:"turns"` Start int `json:"start"` TeamPrefix string `json:"team_prefix"` TeamAssistants string `json:"team_assistants"` } func assignWork(c *gin.Context) { var uaw QAAssignWork if err := c.ShouldBindJSON(&uaw); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } if uaw.Turns == 0 { uaw.Turns = 1 } if uaw.TeamPrefix == "" { uaw.TeamPrefix = "FIC Groupe " } if uaw.TeamAssistants == "" { uaw.TeamAssistants = "assistants" } teams, err := fic.GetTeams() if err != nil { log.Println("Unable to GetTeams: ", err.Error()) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to list teams: %s", err.Error())}) return } // Remove assistant team for tid := len(teams) - 1; tid >= 0; tid-- { team := teams[tid] if strings.Contains(strings.ToLower(team.Name), uaw.TeamAssistants) { teams = append(teams[:tid], teams[tid+1:]...) } } exercices, err := fic.GetExercices() if err != nil { log.Println("Unable to GetExercices: ", err.Error()) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to list exercices: %s", err.Error())}) return } // Struct to store reported team (due to owned exercice) var teamIdStack []int64 for i := 0; i < uaw.Turns; i++ { for eid, ex := range exercices { team := teams[(uaw.Start+eid+uaw.Turns*i)%len(teams)] if len(teamIdStack) > 0 { teamIdStack = append(teamIdStack, team.Id) team, _ = fic.GetTeam(teamIdStack[0]) teamIdStack = append([]int64{}, teamIdStack[1:]...) } j := 0 // Find a team not responsible for this exercice for (strings.Contains(ex.Path, "grp") && strings.Contains(ex.Path, "-grp"+strings.TrimPrefix(team.Name, uaw.TeamPrefix)+"-")) || (!strings.Contains(ex.Path, "grp") && strings.HasPrefix(ex.Path, strings.TrimPrefix(team.Name, uaw.TeamPrefix)+"-")) { j += 1 teamIdStack = append(teamIdStack, team.Id) team = teams[(uaw.Start+eid+uaw.Turns*i+j)%len(teams)] } _, err := team.NewQATodo(ex.Id) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } } } c.JSON(http.StatusOK, "true") }