oef/orm/response.go

348 lines
8.1 KiB
Go
Raw Normal View History

2019-11-18 17:04:07 +01:00
package orm
import (
"fmt"
"log"
2019-11-18 17:04:07 +01:00
"net/http"
2019-12-18 09:47:37 +01:00
"strconv"
"strings"
"time"
2019-11-18 17:04:07 +01:00
2019-12-29 17:23:50 +01:00
"git.andreafazzi.eu/andrea/oef/errors"
2019-11-18 17:04:07 +01:00
"git.andreafazzi.eu/andrea/oef/renderer"
"github.com/jinzhu/gorm"
)
2019-12-18 09:47:37 +01:00
type SingleResponse struct {
AnswerID uint
}
2019-11-18 17:04:07 +01:00
type Response struct {
gorm.Model
2020-01-27 08:35:37 +01:00
UserModifier
2019-12-13 12:55:11 +01:00
2019-11-22 11:16:27 +01:00
Name string
Participant *Participant
ParticipantID uint
Contest *Contest
ContestID uint
2019-12-13 12:55:11 +01:00
QuestionsOrder string
2019-12-18 09:47:37 +01:00
AnswersIDs string
2019-12-13 12:55:11 +01:00
StartTime time.Time
EndTime time.Time
TimeLeft time.Duration
2021-01-05 12:28:40 +01:00
Score int `gorm:"-"`
ScoreString string `gorm:"-"`
Duration time.Duration `gorm:"-"`
2019-11-18 17:04:07 +01:00
2019-12-18 09:47:37 +01:00
Questions []*Question
SingleResponses []*SingleResponse `gorm:"-"`
2019-11-18 17:04:07 +01:00
}
2019-12-18 09:47:37 +01:00
func (sr *SingleResponse) UnmarshalText(text []byte) error {
id, err := strconv.Atoi(string(text))
sr.AnswerID = uint(id)
if err != nil {
return err
}
return nil
}
2019-11-18 17:04:07 +01:00
func (model *Response) GetID() uint { return model.ID }
func (model *Response) String() string {
2019-11-22 11:16:27 +01:00
return model.Name
2019-11-18 17:04:07 +01:00
}
2019-12-29 17:23:50 +01:00
func (model *Response) IsActive() bool {
if !model.StartTime.IsZero() {
return !time.Now().After(model.EndTime) || model.Contest.IsAlwaysActive()
}
return (!time.Now().Before(model.Contest.StartTime) && !time.Now().After(model.Contest.EndTime)) || model.Contest.IsAlwaysActive()
2019-12-29 17:23:50 +01:00
}
2020-01-27 11:43:56 +01:00
func (model *Response) SetCreatorID(id uint) {
model.CreatorID = id
}
func (model *Response) SetCreatorRole(role string) {
model.CreatorRole = role
}
func (model *Response) SetCreatorIP(addr string) {
model.CreatorIP = addr
}
func (model *Response) SetUpdaterID(id uint) {
model.UpdaterID = id
}
func (model *Response) SetUpdaterRole(role string) {
model.UpdaterRole = role
}
func (model *Response) SetUpdaterIP(addr string) {
model.UpdaterIP = addr
}
2019-12-18 09:47:37 +01:00
func (model *Response) generateAnswersIDs() string {
ids := make([]string, 0)
for _, sr := range model.SingleResponses {
ids = append(ids, strconv.Itoa(int(sr.AnswerID)))
}
return strings.Join(ids, " ")
}
func (model *Response) BeforeSave(tx *gorm.DB) error {
model.AnswersIDs = model.generateAnswersIDs()
return nil
}
2021-01-05 12:28:40 +01:00
func calcScoreAndDuration(db *Database, response *Response) error {
2021-01-05 11:37:49 +01:00
response.Score = 0
if response.AnswersIDs != "" {
srIDs := strings.Split(response.AnswersIDs, " ")
for _, srID := range srIDs {
id, err := strconv.Atoi(srID)
if err != nil {
return err
}
response.SingleResponses = append(response.SingleResponses, &SingleResponse{uint(id)})
}
for _, sr := range response.SingleResponses {
var answer Answer
if err := db._db.First(&answer, sr.AnswerID).Error; err != nil {
return err
}
if answer.Correct {
response.Score++
}
}
}
2021-01-05 12:28:40 +01:00
if response.StartTime.IsZero() {
response.ScoreString = "non ancora visualizzata"
} else {
response.Duration = response.UpdatedAt.Sub(response.StartTime)
response.ScoreString = fmt.Sprintf("%s punti %v", strconv.Itoa(response.Score), response.Duration)
}
2021-01-05 11:37:49 +01:00
return nil
}
func (model *Response) Create(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
2019-11-18 17:04:07 +01:00
if r.Method == "GET" {
response := new(Response)
2019-12-13 12:55:11 +01:00
2019-11-18 17:04:07 +01:00
contestID := r.URL.Query().Get("contest_id")
if err := db._db.Preload("Answers").Where("contest_id = ?", contestID).Find(&response.Questions).Error; err != nil {
2019-11-18 17:04:07 +01:00
return nil, err
}
return response, nil
} else {
response := new(Response)
err := renderer.Decode(response, r)
if err != nil {
return nil, err
}
2019-12-13 12:55:11 +01:00
2020-01-27 11:43:56 +01:00
WriteCreator(r, response)
2019-12-13 12:55:11 +01:00
response, err = CreateResponse(db, response)
2019-11-18 17:04:07 +01:00
if err != nil {
return nil, err
}
return response, nil
}
}
func (model *Response) Read(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
2019-11-18 17:04:07 +01:00
var response Response
id := args["id"]
2020-02-03 12:52:56 +01:00
if err := db._db.
Preload("Contest").
Preload("Participant").
Preload("Creator").
Preload("Updater").
First(&response, id).Error; err != nil {
2019-11-18 17:04:07 +01:00
return nil, err
}
2020-02-05 10:10:27 +01:00
if isParticipant(r) {
if strconv.Itoa(int(response.ParticipantID)) != getModelIDFromToken(r) {
return nil, errors.NotAuthorized
}
}
2019-12-18 09:57:07 +01:00
if response.AnswersIDs != "" {
2021-01-05 11:37:49 +01:00
response.Score = 0
2019-12-18 09:57:07 +01:00
srIDs := strings.Split(response.AnswersIDs, " ")
for _, srID := range srIDs {
id, err := strconv.Atoi(srID)
if err != nil {
return nil, err
}
response.SingleResponses = append(response.SingleResponses, &SingleResponse{uint(id)})
2019-12-18 09:47:37 +01:00
}
2019-12-18 09:57:07 +01:00
for _, sr := range response.SingleResponses {
var answer Answer
2019-12-18 09:47:37 +01:00
if err := db._db.First(&answer, sr.AnswerID).Error; err != nil {
2019-12-18 09:57:07 +01:00
return nil, err
}
2019-12-18 09:47:37 +01:00
2019-12-18 09:57:07 +01:00
if answer.Correct {
response.Score++
}
2019-12-18 09:47:37 +01:00
}
2019-12-18 09:57:07 +01:00
2019-12-18 09:47:37 +01:00
}
if response.QuestionsOrder == "" {
return nil, errors.QuestionsOrderIsEmpty
}
qOrder := make([]uint, 0)
qIDs := strings.Split(response.QuestionsOrder, " ")
for _, id := range qIDs {
id, err := strconv.Atoi(id)
if err != nil {
return nil, err
}
qOrder = append(qOrder, uint(id))
}
2019-12-13 12:55:11 +01:00
// Fetch questions in the given order
field := fmt.Sprintf("FIELD(id,%s)", strings.Replace(response.QuestionsOrder, " ", ",", -1))
if err := db._db.Order(field).Where("contest_id = ?", response.Contest.ID).Preload("Answers", func(db *gorm.DB) *gorm.DB {
return db.Order("RAND()")
}).Find(&response.Questions).Error; err != nil {
2019-12-13 12:55:11 +01:00
return nil, err
}
2019-11-18 17:04:07 +01:00
return &response, nil
}
func (model *Response) ReadAll(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
2019-11-18 17:04:07 +01:00
var responses []*Response
if err := db._db.Preload("Contest").Preload("Participant").Order("created_at").Find(&responses).Error; err != nil {
2019-11-18 17:04:07 +01:00
return nil, err
}
return responses, nil
}
func (model *Response) Update(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
2019-11-18 17:04:07 +01:00
if r.Method == "GET" {
result, err := model.Read(db, args, w, r)
2019-11-18 17:04:07 +01:00
if err != nil {
return nil, err
}
response := result.(*Response)
// Write StartTime for the first time if user is a participant
if isParticipant(r) && !response.Contest.IsAlwaysActive() {
2019-12-29 17:23:50 +01:00
if !response.IsActive() {
return nil, errors.OutOfTime
}
if response.StartTime.IsZero() {
if err := db._db.Model(&response).Update("start_time", time.Now()).Error; err != nil {
return nil, err
}
endTime := time.Now().Add(time.Duration(response.Contest.Duration) * time.Minute)
if endTime.After(response.Contest.EndTime) {
endTime = response.Contest.EndTime
}
if err := db._db.Model(&response).Update("end_time", endTime).Error; err != nil {
return nil, err
}
log.Println("StartTime/EndTime", response.StartTime, response.EndTime)
}
response.TimeLeft = response.EndTime.Sub(time.Now())
}
2019-11-18 17:04:07 +01:00
return response, nil
} else {
response, err := model.Read(db, args, w, r)
2019-11-18 17:04:07 +01:00
if err != nil {
return nil, err
}
2019-12-29 17:23:50 +01:00
// Check if the contest is still active
if isParticipant(r) && !response.(*Response).IsActive() {
2019-12-29 17:23:50 +01:00
return nil, errors.OutOfTime
}
response.(*Response).SingleResponses = make([]*SingleResponse, 0)
2019-11-18 17:04:07 +01:00
err = renderer.Decode(response, r)
if err != nil {
return nil, err
}
2019-12-13 12:55:11 +01:00
// If there aren't single responses then participant
// response Starttime is resetted.
if isAdministrator(r) {
if len(response.(*Response).SingleResponses) == 0 {
response.(*Response).StartTime = time.Time{}
}
}
2020-01-27 11:43:56 +01:00
WriteUpdater(r, response.(*Response))
2019-12-13 12:55:11 +01:00
_, err = SaveResponse(db, response)
2019-11-18 17:04:07 +01:00
if err != nil {
return nil, err
}
response, err = model.Read(db, args, w, r)
2019-11-18 17:04:07 +01:00
if err != nil {
return nil, err
}
return response.(*Response), nil
}
}
func (model *Response) Delete(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
response, err := model.Read(db, args, w, r)
2019-11-18 17:04:07 +01:00
if err != nil {
return nil, err
}
if err := db._db.Unscoped().Delete(response.(*Response)).Error; err != nil {
2019-11-18 17:04:07 +01:00
return nil, err
}
return response.(*Response), nil
}
func CreateResponse(db *Database, response *Response) (*Response, error) {
if err := db._db.Create(response).Error; err != nil {
2019-11-18 17:04:07 +01:00
return nil, err
}
return response, nil
}
func SaveResponse(db *Database, response interface{}) (interface{}, error) {
if err := db._db.Omit("Creator", "Updater").Save(response).Error; err != nil {
2019-11-18 17:04:07 +01:00
return nil, err
}
return response, nil
}