package main import ( "encoding/json" "errors" "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", apiHandler(questionHandler( func(s Question, _ []byte) HTTPResponse { return APIResponse{s} }), adminRestricted)) 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 } }