Use gin-gonic instead of httprouter

This commit is contained in:
nemunaire 2022-07-09 19:42:00 +02:00
commit a203cdc36a
22 changed files with 1631 additions and 1355 deletions

View file

@ -1,97 +1,113 @@
package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/julienschmidt/httprouter"
"github.com/gin-gonic/gin"
)
func init() {
router.GET("/api/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(
func(q Question, u *User, _ []byte) HTTPResponse {
return formatApiResponse(q.GetProposals())
}), loggedUser))
router.POST("/api/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(func(q Question, u *User, body []byte) HTTPResponse {
var new Proposal
if err := json.Unmarshal(body, &new); err != nil {
return APIErrorResponse{err: err}
func declareAPIAuthProposalsRoutes(router *gin.RouterGroup) {
router.GET("/proposals", func(c *gin.Context) {
q := c.MustGet("question").(*Question)
proposals, err := q.GetProposals()
if err != nil {
log.Printf("Unable to GetProposals(qid=%d): %s", q.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during proposals retrieving"})
return
}
return formatApiResponse(q.NewProposal(new.Label))
}), adminRestricted))
router.PUT("/api/questions/:qid/proposals/:pid", apiAuthHandler(proposalAuthHandler(func(current Proposal, u *User, body []byte) HTTPResponse {
var new Proposal
if err := json.Unmarshal(body, &new); err != nil {
return APIErrorResponse{err: err}
}
new.Id = current.Id
return formatApiResponse(new.Update())
}), adminRestricted))
router.DELETE("/api/questions/:qid/proposals/:pid", apiAuthHandler(proposalAuthHandler(func(p Proposal, u *User, body []byte) HTTPResponse {
return formatApiResponse(p.Delete())
}), adminRestricted))
router.GET("/api/surveys/:sid/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(
func(q Question, u *User, _ []byte) HTTPResponse {
return formatApiResponse(q.GetProposals())
}), loggedUser))
router.POST("/api/surveys/:sid/questions/:qid/proposals", apiAuthHandler(questionAuthHandler(func(q Question, u *User, body []byte) HTTPResponse {
var new Proposal
if err := json.Unmarshal(body, &new); err != nil {
return APIErrorResponse{err: err}
}
return formatApiResponse(q.NewProposal(new.Label))
}), adminRestricted))
router.PUT("/api/surveys/:sid/questions/:qid/proposals/:pid", apiAuthHandler(proposalAuthHandler(func(current Proposal, u *User, body []byte) HTTPResponse {
var new Proposal
if err := json.Unmarshal(body, &new); err != nil {
return APIErrorResponse{err: err}
}
new.Id = current.Id
return formatApiResponse(new.Update())
}), adminRestricted))
router.DELETE("/api/surveys/:sid/questions/:qid/proposals/:pid", apiAuthHandler(proposalAuthHandler(func(p Proposal, u *User, body []byte) HTTPResponse {
return formatApiResponse(p.Delete())
}), adminRestricted))
c.JSON(http.StatusOK, proposals)
})
}
func proposalHandler(f func(Proposal, []byte) HTTPResponse) func(httprouter.Params, []byte) HTTPResponse {
return func(ps httprouter.Params, body []byte) HTTPResponse {
var question *Question = nil
func declareAPIAdminProposalsRoutes(router *gin.RouterGroup) {
router.POST("/proposals", func(c *gin.Context) {
q := c.MustGet("question").(*Question)
if qid, err := strconv.Atoi(string(ps.ByName("qid"))); err == nil {
if q, err := getQuestion(qid); err == nil {
question = &q
}
var new Proposal
if err := c.ShouldBindJSON(&new); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
if pid, err := strconv.Atoi(string(ps.ByName("pid"))); err != nil {
return APIErrorResponse{err: err}
} else if question == nil {
if proposal, err := getProposal(pid); err != nil {
return APIErrorResponse{err: err}
} else {
return f(proposal, body)
}
} else {
if proposal, err := question.GetProposal(pid); err != nil {
return APIErrorResponse{err: err}
} else {
return f(proposal, body)
}
proposal, err := q.NewProposal(new.Label)
if err != nil {
log.Printf("Unable to NewProposal(qid=%d): %s", q.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to insert new proposal."})
return
}
c.JSON(http.StatusOK, proposal)
})
proposalsRoutes := router.Group("/proposals/:pid")
proposalsRoutes.Use(proposalHandler)
proposalsRoutes.PUT("", func(c *gin.Context) {
current := c.MustGet("proposal").(*Proposal)
var new Proposal
if err := c.ShouldBindJSON(&new); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
new.Id = current.Id
proposal, err := new.Update()
if err != nil {
log.Println("Unable to Update proposal:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during proposal updating."})
return
}
c.JSON(http.StatusOK, proposal)
})
proposalsRoutes.DELETE("", func(c *gin.Context) {
p := c.MustGet("proposal").(*Proposal)
if _, err := p.Delete(); err != nil {
log.Printf("Unable to Delete(pid=%d) proposal: %s", p.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to delete proposal."})
return
}
c.JSON(http.StatusOK, nil)
})
}
func proposalHandler(c *gin.Context) {
var question *Question = nil
if q, ok := c.Get("question"); ok {
question = q.(*Question)
}
var proposal *Proposal
if pid, err := strconv.Atoi(string(c.Param("pid"))); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Invalid proposal ID"})
return
} else if question == nil {
if proposal, err = getProposal(pid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Proposal not found"})
return
}
} else {
if proposal, err = question.GetProposal(pid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Proposal not found"})
return
}
}
}
func proposalAuthHandler(f func(Proposal, *User, []byte) HTTPResponse) func(*User, httprouter.Params, []byte) HTTPResponse {
return func(u *User, ps httprouter.Params, body []byte) HTTPResponse {
return proposalHandler(func(p Proposal, body []byte) HTTPResponse {
return f(p, u, body)
})(ps, body)
if proposal == nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Proposal not found"})
return
} else {
c.Set("proposal", proposal)
c.Next()
}
}
@ -101,7 +117,7 @@ type Proposal struct {
Label string `json:"label"`
}
func (q *Question) GetProposals() (proposals []Proposal, err error) {
func (q *Question) GetProposals() (proposals []*Proposal, err error) {
if rows, errr := DBQuery("SELECT id_proposal, id_question, label FROM survey_proposals WHERE id_question=?", q.Id); errr != nil {
return nil, errr
} else {
@ -112,7 +128,7 @@ func (q *Question) GetProposals() (proposals []Proposal, err error) {
if err = rows.Scan(&p.Id, &p.IdQuestion, &p.Label); err != nil {
return
}
proposals = append(proposals, p)
proposals = append(proposals, &p)
}
if err = rows.Err(); err != nil {
return
@ -122,12 +138,14 @@ func (q *Question) GetProposals() (proposals []Proposal, err error) {
}
}
func getProposal(id int) (p Proposal, err error) {
func getProposal(id int) (p *Proposal, err error) {
p = new(Proposal)
err = DBQueryRow("SELECT id_proposal, id_question, label FROM survey_proposals WHERE id_proposal=?", id).Scan(&p.Id, &p.IdQuestion, &p.Label)
return
}
func (q *Question) GetProposal(id int) (p Proposal, err error) {
func (q *Question) GetProposal(id int) (p *Proposal, err error) {
p = new(Proposal)
err = DBQueryRow("SELECT id_proposal, id_question, label FROM survey_proposals WHERE id_proposal=? AND id_question=?", id, q.Id).Scan(&p.Id, &p.IdQuestion, &p.Label)
return
}