Add notion of promo

This commit is contained in:
nemunaire 2021-03-01 17:47:00 +01:00
parent e5b16b0802
commit 000ac334cc
5 changed files with 40 additions and 20 deletions

2
db.go
View File

@ -60,6 +60,7 @@ CREATE TABLE IF NOT EXISTS users(
firstname VARCHAR(255) NOT NULL, firstname VARCHAR(255) NOT NULL,
lastname VARCHAR(255) NOT NULL, lastname VARCHAR(255) NOT NULL,
time TIMESTAMP NOT NULL, time TIMESTAMP NOT NULL,
promo MEDIUMINT NOT NULL,
is_admin BOOLEAN NOT NULL DEFAULT FALSE is_admin BOOLEAN NOT NULL DEFAULT FALSE
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
`); err != nil { `); err != nil {
@ -79,6 +80,7 @@ CREATE TABLE IF NOT EXISTS user_sessions(
CREATE TABLE IF NOT EXISTS surveys( CREATE TABLE IF NOT EXISTS surveys(
id_survey INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_survey INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255), title VARCHAR(255),
promo MEDIUMINT NOT NULL,
shown BOOLEAN NOT NULL DEFAULT FALSE, shown BOOLEAN NOT NULL DEFAULT FALSE,
corrected BOOLEAN NOT NULL DEFAULT FALSE, corrected BOOLEAN NOT NULL DEFAULT FALSE,
start_availability TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, start_availability TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

View File

@ -16,6 +16,13 @@
</div> </div>
</div> </div>
<div class="form-group row">
<label for="promo" class="col-2 col-form-label col-form-label-sm">Promo</label>
<div class="col-10">
<input type="number" step="1" min="0" max="2068" class="form-control form-control-sm" id="promo" ng-model="survey.promo">
</div>
</div>
<div class="form-group row"> <div class="form-group row">
<label for="start_availability" class="col-2 col-form-label col-form-label-sm">Date de début</label> <label for="start_availability" class="col-2 col-form-label col-form-label-sm">Date de début</label>
<div class="col-10"> <div class="col-10">

View File

@ -60,6 +60,7 @@ func main() {
var bind = flag.String("bind", ":8081", "Bind port/socket") var bind = flag.String("bind", ":8081", "Bind port/socket")
var dsn = flag.String("dsn", DSNGenerator(), "DSN to connect to the MySQL server") var dsn = flag.String("dsn", DSNGenerator(), "DSN to connect to the MySQL server")
flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL") flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL")
flag.UintVar(&currentPromo, "current-promo", currentPromo, "Year of the current promotion")
flag.Parse() flag.Parse()
// Sanitize options // Sanitize options

View File

@ -3,6 +3,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"net/http" "net/http"
"strconv" "strconv"
"time" "time"
@ -14,11 +15,11 @@ func init() {
router.GET("/api/surveys", apiAuthHandler( router.GET("/api/surveys", apiAuthHandler(
func(u *User, _ httprouter.Params, _ []byte) HTTPResponse { func(u *User, _ httprouter.Params, _ []byte) HTTPResponse {
if u == nil { if u == nil {
return formatApiResponse(getSurveys("WHERE shown = TRUE AND NOW() > start_availability")) return formatApiResponse(getSurveys(fmt.Sprintf("WHERE shown = TRUE AND NOW() > start_availability AND promo = %d", currentPromo)))
} else if u.IsAdmin { } else if u.IsAdmin {
return formatApiResponse(getSurveys("")) return formatApiResponse(getSurveys(""))
} else { } else {
return formatApiResponse(getSurveys("WHERE shown = TRUE")) return formatApiResponse(getSurveys(fmt.Sprintf("WHERE shown = TRUE AND promo = %d", u.Promo)))
} }
})) }))
router.POST("/api/surveys", apiHandler(func(_ httprouter.Params, body []byte) HTTPResponse { router.POST("/api/surveys", apiHandler(func(_ httprouter.Params, body []byte) HTTPResponse {
@ -27,11 +28,15 @@ func init() {
return APIErrorResponse{err: err} return APIErrorResponse{err: err}
} }
return formatApiResponse(NewSurvey(new.Title, new.Shown, new.StartAvailability, new.EndAvailability)) if new.Promo == 0 {
new.Promo = currentPromo
}
return formatApiResponse(NewSurvey(new.Title, new.Promo, new.Shown, new.StartAvailability, new.EndAvailability))
}, adminRestricted)) }, adminRestricted))
router.GET("/api/surveys/:sid", apiAuthHandler(surveyAuthHandler( router.GET("/api/surveys/:sid", apiAuthHandler(surveyAuthHandler(
func(s Survey, u *User, _ []byte) HTTPResponse { func(s Survey, u *User, _ []byte) HTTPResponse {
if s.Shown || (u != nil && u.IsAdmin) { if (s.Promo == u.Promo && s.Shown) || (u != nil && u.IsAdmin) {
return APIResponse{s} return APIResponse{s}
} else { } else {
return APIErrorResponse{ return APIErrorResponse{
@ -55,7 +60,7 @@ func init() {
}), adminRestricted)) }), adminRestricted))
router.GET("/api/surveys/:sid/score", apiAuthHandler(surveyAuthHandler( router.GET("/api/surveys/:sid/score", apiAuthHandler(surveyAuthHandler(
func(s Survey, u *User, _ []byte) HTTPResponse { func(s Survey, u *User, _ []byte) HTTPResponse {
if s.Shown || (u != nil && u.IsAdmin) { if (s.Promo == u.Promo && s.Shown) || (u != nil && u.IsAdmin) {
if score, err := s.GetScore(u); err != nil { if score, err := s.GetScore(u); err != nil {
return APIErrorResponse{err: err} return APIErrorResponse{err: err}
} else if score == nil { } else if score == nil {
@ -73,7 +78,7 @@ func init() {
router.GET("/api/users/:uid/surveys/:sid/score", apiAuthHandler(func(uauth *User, ps httprouter.Params, body []byte) HTTPResponse { router.GET("/api/users/:uid/surveys/:sid/score", apiAuthHandler(func(uauth *User, ps httprouter.Params, body []byte) HTTPResponse {
return surveyAuthHandler(func(s Survey, uauth *User, _ []byte) HTTPResponse { return surveyAuthHandler(func(s Survey, uauth *User, _ []byte) HTTPResponse {
return userHandler(func(u User, _ []byte) HTTPResponse { return userHandler(func(u User, _ []byte) HTTPResponse {
if uauth != nil && ((s.Shown && u.Id == uauth.Id) || uauth.IsAdmin) { if uauth != nil && ((s.Promo == u.Promo && s.Shown && u.Id == uauth.Id) || uauth.IsAdmin) {
if score, err := s.GetScore(&u); err != nil { if score, err := s.GetScore(&u); err != nil {
return APIErrorResponse{err: err} return APIErrorResponse{err: err}
} else if score == nil { } else if score == nil {
@ -119,6 +124,7 @@ func surveyAuthHandler(f func(Survey, *User, []byte) HTTPResponse) func(*User, h
type Survey struct { type Survey struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Promo uint `json:"promo"`
Shown bool `json:"shown"` Shown bool `json:"shown"`
Corrected bool `json:"corrected"` Corrected bool `json:"corrected"`
StartAvailability time.Time `json:"start_availability"` StartAvailability time.Time `json:"start_availability"`
@ -126,14 +132,14 @@ type Survey struct {
} }
func getSurveys(cnd string, param ...interface{}) (surveys []Survey, err error) { func getSurveys(cnd string, param ...interface{}) (surveys []Survey, err error) {
if rows, errr := DBQuery("SELECT id_survey, title, shown, corrected, start_availability, end_availability FROM surveys "+cnd, param...); errr != nil { if rows, errr := DBQuery("SELECT id_survey, title, promo, shown, corrected, start_availability, end_availability FROM surveys "+cnd, param...); errr != nil {
return nil, errr return nil, errr
} else { } else {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var s Survey var s Survey
if err = rows.Scan(&s.Id, &s.Title, &s.Shown, &s.Corrected, &s.StartAvailability, &s.EndAvailability); err != nil { if err = rows.Scan(&s.Id, &s.Title, &s.Promo, &s.Shown, &s.Corrected, &s.StartAvailability, &s.EndAvailability); err != nil {
return return
} }
surveys = append(surveys, s) surveys = append(surveys, s)
@ -147,17 +153,17 @@ func getSurveys(cnd string, param ...interface{}) (surveys []Survey, err error)
} }
func getSurvey(id int) (s Survey, err error) { func getSurvey(id int) (s Survey, err error) {
err = DBQueryRow("SELECT id_survey, title, shown, corrected, start_availability, end_availability FROM surveys WHERE id_survey=?", id).Scan(&s.Id, &s.Title, &s.Shown, &s.Corrected, &s.StartAvailability, &s.EndAvailability) err = DBQueryRow("SELECT id_survey, title, promo, shown, corrected, start_availability, end_availability FROM surveys WHERE id_survey=?", id).Scan(&s.Id, &s.Title, &s.Promo, &s.Shown, &s.Corrected, &s.StartAvailability, &s.EndAvailability)
return return
} }
func NewSurvey(title string, shown bool, startAvailability time.Time, endAvailability time.Time) (Survey, error) { func NewSurvey(title string, promo uint, shown bool, startAvailability time.Time, endAvailability time.Time) (Survey, error) {
if res, err := DBExec("INSERT INTO surveys (title, shown, start_availability, end_availability) VALUES (?, ?, ?, ?)", title, shown, startAvailability, endAvailability); err != nil { if res, err := DBExec("INSERT INTO surveys (title, promo, shown, start_availability, end_availability) VALUES (?, ?, ?, ?, ?)", title, promo, shown, startAvailability, endAvailability); err != nil {
return Survey{}, err return Survey{}, err
} else if sid, err := res.LastInsertId(); err != nil { } else if sid, err := res.LastInsertId(); err != nil {
return Survey{}, err return Survey{}, err
} else { } else {
return Survey{sid, title, shown, false, startAvailability, endAvailability}, nil return Survey{sid, title, promo, shown, false, startAvailability, endAvailability}, nil
} }
} }
@ -195,7 +201,7 @@ func (s Survey) GetScores() (scores map[int64]*float64, err error) {
} }
func (s Survey) Update() (int64, error) { func (s Survey) Update() (int64, error) {
if res, err := DBExec("UPDATE surveys SET title = ?, shown = ?, corrected = ?, start_availability = ?, end_availability = ? WHERE id_survey = ?", s.Title, s.Shown, s.Corrected, s.StartAvailability, s.EndAvailability, s.Id); err != nil { if res, err := DBExec("UPDATE surveys SET title = ?, promo = ?, shown = ?, corrected = ?, start_availability = ?, end_availability = ? WHERE id_survey = ?", s.Title, s.Promo, s.Shown, s.Corrected, s.StartAvailability, s.EndAvailability, s.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err

View File

@ -8,6 +8,8 @@ import (
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
) )
var currentPromo uint = 0
func init() { func init() {
router.GET("/api/users", apiHandler( router.GET("/api/users", apiHandler(
func(httprouter.Params, []byte) HTTPResponse { func(httprouter.Params, []byte) HTTPResponse {
@ -47,18 +49,19 @@ type User struct {
Firstname string `json:"firstname"` Firstname string `json:"firstname"`
Lastname string `json:"lastname"` Lastname string `json:"lastname"`
Time time.Time `json:"time"` Time time.Time `json:"time"`
Promo uint `json:"promo"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
} }
func getUsers() (users []User, err error) { func getUsers() (users []User, err error) {
if rows, errr := DBQuery("SELECT id_user, login, email, firstname, lastname, time, is_admin FROM users"); errr != nil { if rows, errr := DBQuery("SELECT id_user, login, email, firstname, lastname, time, promo, is_admin FROM users"); errr != nil {
return nil, errr return nil, errr
} else { } else {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var u User var u User
if err = rows.Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.IsAdmin); err != nil { if err = rows.Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.Promo, &u.IsAdmin); err != nil {
return return
} }
users = append(users, u) users = append(users, u)
@ -72,12 +75,12 @@ func getUsers() (users []User, err error) {
} }
func getUser(id int) (u User, err error) { func getUser(id int) (u User, err error) {
err = DBQueryRow("SELECT id_user, login, email, firstname, lastname, time, is_admin FROM users WHERE id_user=?", id).Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.IsAdmin) err = DBQueryRow("SELECT id_user, login, email, firstname, lastname, time, promo, is_admin FROM users WHERE id_user=?", id).Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.Promo, &u.IsAdmin)
return return
} }
func getUserByLogin(login string) (u User, err error) { func getUserByLogin(login string) (u User, err error) {
err = DBQueryRow("SELECT id_user, login, email, firstname, lastname, time, is_admin FROM users WHERE login=?", login).Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.IsAdmin) err = DBQueryRow("SELECT id_user, login, email, firstname, lastname, time, promo, is_admin FROM users WHERE login=?", login).Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.Promo, &u.IsAdmin)
return return
} }
@ -89,17 +92,17 @@ func userExists(login string) bool {
func NewUser(login string, email string, firstname string, lastname string) (User, error) { func NewUser(login string, email string, firstname string, lastname string) (User, error) {
t := time.Now() t := time.Now()
if res, err := DBExec("INSERT INTO users (login, email, firstname, lastname, time) VALUES (?, ?, ?, ?, ?)", login, email, firstname, lastname, t); err != nil { if res, err := DBExec("INSERT INTO users (login, email, firstname, lastname, time, promo) VALUES (?, ?, ?, ?, ?, ?)", login, email, firstname, lastname, t, currentPromo); err != nil {
return User{}, err return User{}, err
} else if sid, err := res.LastInsertId(); err != nil { } else if sid, err := res.LastInsertId(); err != nil {
return User{}, err return User{}, err
} else { } else {
return User{sid, login, email, firstname, lastname, t, false}, nil return User{sid, login, email, firstname, lastname, t, currentPromo, false}, nil
} }
} }
func (u User) Update() (int64, error) { func (u User) Update() (int64, error) {
if res, err := DBExec("UPDATE users SET login = ?, email = ?, firstname = ?, lastname = ?, time = ? WHERE id_user = ?", u.Login, u.Email, u.Firstname, u.Lastname, u.Time, u.Id); err != nil { if res, err := DBExec("UPDATE users SET login = ?, email = ?, firstname = ?, lastname = ?, time = ?, promo = ? WHERE id_user = ?", u.Login, u.Email, u.Firstname, u.Lastname, u.Time, u.Promo, u.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err
@ -148,5 +151,6 @@ func updateUser(current User, body []byte) HTTPResponse {
current.Firstname = new.Firstname current.Firstname = new.Firstname
current.Lastname = new.Lastname current.Lastname = new.Lastname
current.Time = new.Time current.Time = new.Time
current.Promo = new.Promo
return formatApiResponse(current.Update()) return formatApiResponse(current.Update())
} }