Pierre-Olivier Mercier
0e5961c406
All checks were successful
continuous-integration/drone/push Build is passing
239 lines
7.7 KiB
Go
239 lines
7.7 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
"github.com/russross/blackfriday/v2"
|
|
)
|
|
|
|
func init() {
|
|
router.GET("/api/questions", apiHandler(
|
|
func(httprouter.Params, []byte) HTTPResponse {
|
|
return formatApiResponse(getQuestions())
|
|
}, adminRestricted))
|
|
router.GET("/api/surveys/:sid/questions", apiAuthHandler(surveyAuthHandler(
|
|
func(s Survey, u *User, _ []byte) HTTPResponse {
|
|
if !s.Shown && !u.IsAdmin {
|
|
return APIErrorResponse{err: errors.New("Not accessible")}
|
|
}
|
|
if s.StartAvailability.After(time.Now()) && !u.IsAdmin {
|
|
return APIErrorResponse{status: http.StatusPaymentRequired, err: errors.New("Not available yet")}
|
|
}
|
|
return formatApiResponse(s.GetQuestions())
|
|
}), loggedUser))
|
|
router.POST("/api/surveys/:sid/questions", apiAuthHandler(surveyAuthHandler(func(s Survey, u *User, body []byte) HTTPResponse {
|
|
if !s.Shown && !u.IsAdmin {
|
|
return APIErrorResponse{err: errors.New("Not accessible")}
|
|
}
|
|
|
|
var new Question
|
|
if err := json.Unmarshal(body, &new); err != nil {
|
|
return APIErrorResponse{err: err}
|
|
}
|
|
|
|
return formatApiResponse(s.NewQuestion(new.Title, new.DescriptionRaw, new.Placeholder, new.Kind))
|
|
}), adminRestricted))
|
|
router.GET("/api/questions/:qid", apiAuthHandler(questionAuthHandler(
|
|
func(q Question, u *User, _ []byte) HTTPResponse {
|
|
if u.IsAdmin {
|
|
return APIResponse{q}
|
|
} else if s, err := getSurvey(int(q.IdSurvey)); err != nil {
|
|
return APIErrorResponse{err: err}
|
|
} else if s.Shown || (s.Direct != nil && *s.Direct == q.Id) {
|
|
return APIResponse{q}
|
|
} else {
|
|
return APIErrorResponse{err: fmt.Errorf("Not authorized"), status: http.StatusForbidden}
|
|
}
|
|
}), loggedUser))
|
|
router.GET("/api/surveys/:sid/questions/:qid", apiHandler(questionHandler(
|
|
func(s Question, _ []byte) HTTPResponse {
|
|
return APIResponse{s}
|
|
}), adminRestricted))
|
|
router.PUT("/api/questions/:qid", apiHandler(questionHandler(func(current Question, body []byte) HTTPResponse {
|
|
var new Question
|
|
if err := json.Unmarshal(body, &new); err != nil {
|
|
return APIErrorResponse{err: err}
|
|
}
|
|
|
|
new.Id = current.Id
|
|
return formatApiResponse(new.Update())
|
|
}), adminRestricted))
|
|
router.PUT("/api/surveys/:sid/questions/:qid", apiHandler(questionHandler(func(current Question, body []byte) HTTPResponse {
|
|
var new Question
|
|
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", apiHandler(questionHandler(
|
|
func(q Question, _ []byte) HTTPResponse {
|
|
return formatApiResponse(q.Delete())
|
|
}), adminRestricted))
|
|
router.DELETE("/api/surveys/:sid/questions/:qid", apiHandler(questionHandler(
|
|
func(q Question, _ []byte) HTTPResponse {
|
|
return formatApiResponse(q.Delete())
|
|
}), adminRestricted))
|
|
}
|
|
|
|
func questionHandler(f func(Question, []byte) HTTPResponse) func(httprouter.Params, []byte) HTTPResponse {
|
|
return func(ps httprouter.Params, body []byte) HTTPResponse {
|
|
var survey *Survey = nil
|
|
|
|
if sid, err := strconv.Atoi(string(ps.ByName("sid"))); err == nil {
|
|
if s, err := getSurvey(sid); err == nil {
|
|
survey = &s
|
|
}
|
|
}
|
|
|
|
if qid, err := strconv.Atoi(string(ps.ByName("qid"))); err != nil {
|
|
return APIErrorResponse{err: err}
|
|
} else if survey == nil {
|
|
if question, err := getQuestion(qid); err != nil {
|
|
return APIErrorResponse{err: err}
|
|
} else {
|
|
return f(question, body)
|
|
}
|
|
} else {
|
|
if question, err := survey.GetQuestion(qid); err != nil {
|
|
return APIErrorResponse{err: err}
|
|
} else {
|
|
return f(question, body)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func questionAuthHandler(f func(Question, *User, []byte) HTTPResponse, access ...func(*User, *Question) error) func(*User, httprouter.Params, []byte) HTTPResponse {
|
|
return func(u *User, ps httprouter.Params, body []byte) HTTPResponse {
|
|
return questionHandler(func(q Question, body []byte) HTTPResponse {
|
|
// Check access limitation
|
|
for _, a := range access {
|
|
if err := a(u, &q); err != nil {
|
|
return APIErrorResponse{
|
|
status: http.StatusForbidden,
|
|
err: err,
|
|
}
|
|
}
|
|
}
|
|
|
|
return f(q, u, body)
|
|
})(ps, body)
|
|
}
|
|
}
|
|
|
|
type Question struct {
|
|
Id int64 `json:"id"`
|
|
IdSurvey int64 `json:"id_survey"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
DescriptionRaw string `json:"desc_raw,omitempty"`
|
|
Placeholder string `json:"placeholder,omitempty"`
|
|
Kind string `json:"kind"`
|
|
}
|
|
|
|
func getQuestions() (questions []Question, err error) {
|
|
if rows, errr := DBQuery("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests"); errr != nil {
|
|
return nil, errr
|
|
} else {
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var q Question
|
|
if err = rows.Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind); err != nil {
|
|
return
|
|
}
|
|
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
|
questions = append(questions, q)
|
|
}
|
|
if err = rows.Err(); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
func (s *Survey) GetQuestions() (questions []Question, err error) {
|
|
if rows, errr := DBQuery("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_survey=?", s.Id); errr != nil {
|
|
return nil, errr
|
|
} else {
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var q Question
|
|
if err = rows.Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind); err != nil {
|
|
return
|
|
}
|
|
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
|
questions = append(questions, q)
|
|
}
|
|
if err = rows.Err(); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
func getQuestion(id int) (q Question, err error) {
|
|
err = DBQueryRow("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_question=?", id).Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind)
|
|
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
|
return
|
|
}
|
|
|
|
func (s *Survey) GetQuestion(id int) (q Question, err error) {
|
|
err = DBQueryRow("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_question=? AND id_survey=?", id, s.Id).Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind)
|
|
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
|
return
|
|
}
|
|
|
|
func (s *Survey) NewQuestion(title string, description string, placeholder string, kind string) (Question, error) {
|
|
if res, err := DBExec("INSERT INTO survey_quests (id_survey, title, description, placeholder, kind) VALUES (?, ?, ?, ?, ?)", s.Id, title, description, placeholder, kind); err != nil {
|
|
return Question{}, err
|
|
} else if qid, err := res.LastInsertId(); err != nil {
|
|
return Question{}, err
|
|
} else {
|
|
return Question{qid, s.Id, title, string(blackfriday.Run([]byte(description))), description, placeholder, kind}, nil
|
|
}
|
|
}
|
|
|
|
func (q Question) GetSurvey() (Survey, error) {
|
|
return getSurvey(int(q.IdSurvey))
|
|
}
|
|
|
|
func (q Question) Update() (Question, error) {
|
|
if _, err := DBExec("UPDATE survey_quests SET id_survey = ?, title = ?, description = ?, placeholder = ?, kind = ? WHERE id_question = ?", q.IdSurvey, q.Title, q.DescriptionRaw, q.Placeholder, q.Kind, q.Id); err != nil {
|
|
return Question{}, err
|
|
} else {
|
|
return q, err
|
|
}
|
|
}
|
|
|
|
func (q Question) Delete() (int64, error) {
|
|
if res, err := DBExec("DELETE FROM survey_quests WHERE id_question = ?", q.Id); err != nil {
|
|
return 0, err
|
|
} else if nb, err := res.RowsAffected(); err != nil {
|
|
return 0, err
|
|
} else {
|
|
return nb, err
|
|
}
|
|
}
|
|
|
|
func ClearQuestions() (int64, error) {
|
|
if res, err := DBExec("DELETE FROM survey_quests"); err != nil {
|
|
return 0, err
|
|
} else if nb, err := res.RowsAffected(); err != nil {
|
|
return 0, err
|
|
} else {
|
|
return nb, err
|
|
}
|
|
}
|