qa: Use gin

This commit is contained in:
nemunaire 2022-11-06 16:36:31 +01:00
parent 9fd5564410
commit abdf146fea
13 changed files with 596 additions and 378 deletions

View file

@ -1,144 +1,231 @@
package api
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"strconv"
"srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
"github.com/gin-gonic/gin"
)
func init() {
router.GET("/api/qa/:eid", apiHandler(exerciceHandler(getExerciceQA)))
router.POST("/api/qa/:eid", apiHandler(exerciceHandler(createExerciceQA)))
func declareQARoutes(router *gin.RouterGroup) {
exercicesRoutes := router.Group("/qa/:eid")
exercicesRoutes.Use(exerciceHandler)
exercicesRoutes.GET("", getExerciceQA)
exercicesRoutes.POST("", createExerciceQA)
router.PUT("/api/qa/:eid/:qid", apiHandler(qaHandler(updateExerciceQA)))
router.DELETE("/api/qa/:eid/:qid", apiHandler(qaHandler(deleteExerciceQA)))
qaRoutes := exercicesRoutes.Group("/:qid")
qaRoutes.Use(qaHandler)
qaRoutes.PUT("", updateExerciceQA)
qaRoutes.DELETE("", deleteExerciceQA)
qaRoutes.GET("comments", getQAComments)
qaRoutes.POST("comments", createQAComment)
router.GET("/api/qa/:eid/:qid/comments", apiHandler(qaHandler(getQAComments)))
router.POST("/api/qa/:eid/:qid/comments", apiHandler(qaHandler(createQAComment)))
router.DELETE("/api/qa/:eid/:qid/comments/:cid", apiHandler(qaCommentHandler(deleteQAComment)))
commentsRoutes := qaRoutes.Group("comments/:cid")
commentsRoutes.Use(qaCommentHandler)
commentsRoutes.DELETE("", deleteQAComment)
}
func qaHandler(f func(QAUser, *fic.QAQuery, *fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) {
return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
return exerciceHandler(func(u QAUser, exercice *fic.Exercice, _ []byte) (interface{}, error) {
if qid, err := strconv.ParseInt(string(ps.ByName("qid")), 10, 64); err != nil {
return nil, err
} else if query, err := exercice.GetQAQuery(qid); err != nil {
return nil, err
} else {
return f(u, query, exercice, body)
}
})(u, ps, body)
func qaHandler(c *gin.Context) {
exercice := c.MustGet("exercice").(*fic.Exercice)
var qa *fic.QAQuery
if qid, err := strconv.ParseInt(string(c.Param("qid")), 10, 64); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad QA identifier."})
return
} else if qa, err = exercice.GetQAQuery(qid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "QA entry not found."})
return
}
c.Set("qa", qa)
c.Next()
}
func qaCommentHandler(f func(QAUser, *fic.QAComment, *fic.QAQuery, *fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) {
return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
return qaHandler(func(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, _ []byte) (interface{}, error) {
if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 64); err != nil {
return nil, err
} else if comment, err := query.GetComment(cid); err != nil {
return nil, err
} else {
return f(u, comment, query, exercice, body)
}
})(u, ps, body)
func qaCommentHandler(c *gin.Context) {
qa := c.MustGet("qa").(*fic.QAQuery)
var comment *fic.QAComment
if cid, err := strconv.ParseInt(string(c.Param("cid")), 10, 64); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad comment identifier."})
return
} else if comment, err = qa.GetComment(cid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Comment entry not found."})
return
}
c.Set("comment", comment)
c.Next()
}
func getExerciceQA(_ QAUser, exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetQAQueries()
func getExerciceQA(c *gin.Context) {
exercice := c.MustGet("exercice").(*fic.Exercice)
qa, err := exercice.GetQAQueries()
if err != nil {
log.Println("Unable to GetQAQueries: ", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to list QA entries: %s", err.Error())})
return
}
c.JSON(http.StatusOK, qa)
}
func createExerciceQA(u QAUser, exercice *fic.Exercice, body []byte) (interface{}, error) {
type QAQueryAndComment struct {
*fic.QAQuery
Content string `json:"content"`
}
func createExerciceQA(c *gin.Context) {
teamid := c.MustGet("LoggedTeam").(int64)
ficteam := c.MustGet("LoggedUser").(string)
// Create a new query
var uq *fic.QAQuery
if err := json.Unmarshal(body, &uq); err != nil {
return nil, err
var uq QAQueryAndComment
if err := c.ShouldBindJSON(&uq); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
if len(uq.State) == 0 {
return nil, errors.New("State not filled")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "State not filled"})
return
}
if len(uq.Subject) == 0 {
if uq.State == "ok" {
uq.Subject = "RAS"
} else {
return nil, errors.New("Subject not filled")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Subject not filled"})
return
}
}
if qa, err := exercice.NewQAQuery(uq.Subject, &u.TeamId, u.User, uq.State); err != nil {
return nil, err
} else {
var uc *fic.QAComment
if err := json.Unmarshal(body, &uc); err != nil {
return nil, err
}
if uc.Content != "" {
_, err = qa.AddComment(uc.Content, &u.TeamId, u.User)
}
return qa, err
exercice := c.MustGet("exercice").(*fic.Exercice)
qa, err := exercice.NewQAQuery(uq.Subject, &teamid, ficteam, uq.State)
if err != nil {
log.Println("Unable to NewQAQuery: ", err.Error())
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Unable to create the new QA query. Please retry."})
return
}
if len(uq.Content) > 0 {
_, err = qa.AddComment(uq.Content, &teamid, ficteam)
if err != nil {
log.Println("Unable to AddComment: ", err.Error())
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "QA entry added successfully, but unable to create the associated comment. Please retry."})
return
}
}
c.JSON(http.StatusOK, qa)
}
func updateExerciceQA(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
func updateExerciceQA(c *gin.Context) {
query := c.MustGet("qa").(*fic.QAQuery)
var uq *fic.QAQuery
if err := json.Unmarshal(body, &uq); err != nil {
return nil, err
if err := c.ShouldBindJSON(&uq); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
uq.Id = query.Id
if uq.User != query.User && (uq.IdExercice != query.IdExercice || uq.IdTeam != query.IdTeam || uq.User != query.User || uq.Creation != query.Creation || uq.State != query.State || uq.Subject != query.Subject || uq.Closed != query.Closed) {
return nil, errors.New("You can only update your own entry.")
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "You can only update your own entry."})
return
}
if _, err := uq.Update(); err != nil {
return nil, err
} else {
return uq, err
}
}
func deleteExerciceQA(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
if u.User != query.User {
return nil, errors.New("You can only delete your own entry.")
_, err := uq.Update()
if err != nil {
log.Println("Unable to Update QAQuery:", err.Error())
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Unable to update the query. Please try again."})
return
}
return query.Delete()
c.JSON(http.StatusOK, uq)
}
func getQAComments(_ QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
return query.GetComments()
func deleteExerciceQA(c *gin.Context) {
query := c.MustGet("qa").(*fic.QAQuery)
user := c.MustGet("LoggedUser").(string)
if user != query.User {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "You can only delete your own entry."})
return
}
_, err := query.Delete()
if err != nil {
log.Println("Unable to Delete QAQuery:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to delete the query. Please try again."})
return
}
c.JSON(http.StatusNoContent, nil)
}
func createQAComment(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
func getQAComments(c *gin.Context) {
query := c.MustGet("qa").(*fic.QAQuery)
comments, err := query.GetComments()
if err != nil {
log.Println("Unable to GetComments: ", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to list comments: %s", err.Error())})
return
}
c.JSON(http.StatusOK, comments)
}
func createQAComment(c *gin.Context) {
// Create a new query
var uc *fic.QAComment
if err := json.Unmarshal(body, &uc); err != nil {
return nil, err
if err := c.ShouldBindJSON(&uc); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
if len(uc.Content) == 0 {
return nil, errors.New("Empty comment")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Empty comment."})
return
}
return query.AddComment(uc.Content, &u.TeamId, u.User)
}
teamid := c.MustGet("LoggedTeam").(int64)
ficteam := c.MustGet("LoggedUser").(string)
func deleteQAComment(u QAUser, comment *fic.QAComment, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
if u.User != comment.User {
return nil, errors.New("You can only delete your own comment.")
query := c.MustGet("qa").(*fic.QAQuery)
comment, err := query.AddComment(uc.Content, &teamid, ficteam)
if err != nil {
log.Println("Unable to AddComment: ", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to add your comment. Please try again later."})
return
}
return comment.Delete()
c.JSON(http.StatusOK, comment)
}
func deleteQAComment(c *gin.Context) {
ficteam := c.MustGet("LoggedUser").(string)
comment := c.MustGet("comment").(*fic.QAComment)
if ficteam != comment.User {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "You can only delete your own comment."})
return
}
_, err := comment.Delete()
if err != nil {
log.Println("Unable to Delete QAComment:", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to delete the comment. Please try again."})
return
}
c.JSON(http.StatusNoContent, nil)
}