oef/orm/contest.go

225 lines
5.3 KiB
Go

package orm
import (
"fmt"
"log"
"math/rand"
"strconv"
"strings"
"net/http"
"time"
"git.andreafazzi.eu/andrea/oef/errors"
"git.andreafazzi.eu/andrea/oef/renderer"
"github.com/dgrijalva/jwt-go"
"github.com/jinzhu/gorm"
)
type Contest struct {
gorm.Model
Name string
Category string
Description string
Date time.Time
StartTime time.Time
EndTime time.Time
Duration int // in minutes
NumQuestions int
NumAnswersPerQuestion int
Questions []*Question
Participants []*Participant `gorm:"many2many:subscriptions"`
}
func (c *Contest) GetID() uint { return c.ID }
func (c *Contest) String() string {
return c.Name
}
func (c *Contest) Create(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
return nil, nil
} else {
contest := new(Contest)
err := r.ParseForm()
if err != nil {
return nil, err
}
date := r.FormValue("Date")
startTime := r.FormValue("StartTime")
endTime := r.FormValue("EndTime")
log.Println("Zero time", date)
if date == "" {
r.PostForm.Set("Date", time.Time{}.Format(time.RFC3339))
r.PostForm.Set("StartTime", time.Time{}.Format(time.RFC3339))
r.PostForm.Set("EndTime", time.Time{}.Format(time.RFC3339))
} else {
r.PostForm.Set("Date", fmt.Sprintf("%sT%s:00+01:00", date, startTime))
r.PostForm.Set("StartTime", fmt.Sprintf("%sT%s:00+01:00", date, startTime))
r.PostForm.Set("EndTime", fmt.Sprintf("%sT%s:00+01:00", date, endTime))
}
err = renderer.Decode(contest, r)
if err != nil {
return nil, err
}
contest, err = CreateContest(db, contest)
if err != nil {
return nil, err
}
return contest, nil
}
}
func (c *Contest) Read(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var contest Contest
id := args["id"]
if err := db._db.Preload("Participants").Preload("Questions").First(&contest, id).Error; err != nil {
return nil, err
}
return &contest, nil
}
func (c *Contest) ReadAll(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var contests []*Contest
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
if claims["admin"].(bool) {
if err := db._db.Order("created_at").Find(&contests).Error; err != nil {
return nil, err
} else {
return contests, nil
}
}
participant := &Participant{}
if err := db._db.Preload("Contests").Where("username = ?", claims["name"].(string)).First(&participant).Error; err != nil {
return nil, err
} else {
return participant.Contests, nil
}
}
func (c *Contest) Update(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := c.Read(db, args, w, r)
if err != nil {
return nil, err
}
contest := result.(*Contest)
return contest, nil
} else {
contest, err := c.Read(db, args, w, r)
if err != nil {
return nil, err
}
err = r.ParseForm()
if err != nil {
return nil, err
}
date := r.FormValue("Date")
startTime := r.FormValue("StartTime")
endTime := r.FormValue("EndTime")
if date == "" {
r.PostForm.Set("Date", time.Time{}.Format(time.RFC3339))
r.PostForm.Set("StartTime", time.Time{}.Format(time.RFC3339))
r.PostForm.Set("EndTime", time.Time{}.Format(time.RFC3339))
} else {
r.PostForm.Set("Date", fmt.Sprintf("%sT%s:00+01:00", date, startTime))
r.PostForm.Set("StartTime", fmt.Sprintf("%sT%s:00+01:00", date, startTime))
r.PostForm.Set("EndTime", fmt.Sprintf("%sT%s:00+01:00", date, endTime))
}
err = renderer.Decode(contest, r)
if err != nil {
return nil, err
}
_, err = SaveContest(db, contest)
if err != nil {
return nil, err
}
contest, err = c.Read(db, args, w, r)
if err != nil {
return nil, err
}
return contest.(*Contest), nil
}
}
func (model *Contest) Delete(db *Database, args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
contest, err := model.Read(db, args, w, r)
if err != nil {
return nil, err
}
if err := db._db.Unscoped().Delete(contest.(*Contest)).Error; err != nil {
return nil, err
}
return contest.(*Contest), nil
}
func CreateContest(db *Database, contest *Contest) (*Contest, error) {
if err := db._db.Create(contest).Error; err != nil {
return nil, err
}
return contest, nil
}
func SaveContest(db *Database, contest interface{}) (interface{}, error) {
if err := db._db.Omit("Contests").Save(contest).Error; err != nil {
return nil, err
}
return contest, nil
}
func (c *Contest) isAlwaysActive() bool {
return c.StartTime.IsZero() || c.EndTime.IsZero() || c.Duration == 0
}
func (c *Contest) generateQuestionsOrder(db *gorm.DB) (string, error) {
var (
order []string
questions []*Question
)
if err := db.Find(&questions, Question{ContestID: c.ID}).Error; err != nil {
return "", err
}
if len(questions) == 0 {
return "", errors.ContestHasZeroQuestions
}
count := 0
generated := make(map[int]bool, 0)
rand.Seed(time.Now().UnixNano())
for count < len(questions) {
position := rand.Intn(len(questions))
if generated[position] {
continue
}
generated[position] = true
order = append(order, strconv.Itoa(int(questions[position].ID)))
count++
}
return strings.Join(order, " "), nil
}