Skip to content

Commit

Permalink
DQ admin fix
Browse files Browse the repository at this point in the history
  • Loading branch information
kish1n committed Aug 27, 2024
1 parent 26b0162 commit 1ec0a37
Show file tree
Hide file tree
Showing 18 changed files with 450 additions and 194 deletions.
55 changes: 55 additions & 0 deletions docs/spec/components/schemas/DailyQuestionCreate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
allOf:
- $ref: "#/components/schemas/DailyQuestionEditKey"
- type: object
required:
- attributes
properties:
attributes:
type: object
required:
- title
- reward
- options
- correct_answer
- time_for_answer
- starts_at
properties:
title:
type: string
description: Question title
example: Georgian capital
reward:
type: integer
format: int64
description: Reward for a correct answer
options:
type: array
description: Answer options. Minimum 2, maximum 6
items:
$ref: "#/components/schemas/DailyQuestionOptions"
example: [
{
"id": 0,
"title": ""
},
{
"id": 1,
"title": ""
},
{
"id": 2,
"title": ""
}
]
correct_answer:
type: integer
format: int64
description: Correct answer ID
time_for_answer:
type: integer
format: int64
description: Time for answer
starts_at:
type: string
description: Start date when this question is available, hours and minutes are always 0
example: "2024-08-23"
11 changes: 11 additions & 0 deletions docs/spec/components/schemas/DailyQuestionCreateKey.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type: object
required:
- id
- type
properties:
id:
type: string
description: Question id
type:
type: string
enum: [ daily_questions ]
7 changes: 0 additions & 7 deletions docs/spec/components/schemas/DailyQuestionEdit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@ allOf:
properties:
attributes:
type: object
required:
- title
- reward
- options
- correct_answer
- time_for_answer
- starts_at
properties:
title:
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ post:
- data
properties:
data:
$ref: '#/components/schemas/DailyQuestionEdit'
$ref: '#/components/schemas/DailyQuestionCreate'
responses:
200:
description: Success
Expand Down
23 changes: 13 additions & 10 deletions internal/data/daily_questions.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ import (
"time"

"github.com/rarimo/geo-points-svc/resources"
"gitlab.com/distributed_lab/kit/pgdb"
)

const (
ColDailyQuestionTitle = "title"
ColTimeForAnswer = "time_for_answer"
ColDailyQuestionReward = "reward"
ColAnswerOption = "answer_options"
ColCorrectAnswerId = "correct_answer"

ColCorrectAnswers = "num_correct_answers"
ColIncorrectAnswers = "num_incorrect_answers"
ColAllParticipants = "num_all_participants"
ColDailyQuestionTitle = "title"
ColTimeForAnswer = "time_for_answer"
ColAnswerOption = "answer_options"
ColCorrectAnswerId = "correct_answer"
ColReward = "reward"
ColStartAt = "start_at"
ColCorrectAnswers = "num_correct_answers"
ColIncorrectAnswers = "num_incorrect_answers"
ColAllParticipants = "num_all_participants"
)

type DailyQuestion struct {
Expand All @@ -42,8 +43,10 @@ type DailyQuestionsQ interface {
Delete() (int64, error)
Count() (int64, error)
Select() ([]DailyQuestion, error)
Get() (*DailyQuestion, error)
SelectByTime() ([]DailyQuestion, error)

Get() (*DailyQuestion, error)
Page(*pgdb.OffsetPageParams) DailyQuestionsQ
FilterTodayQuestions(offset int) DailyQuestionsQ
FilterByCreatedAtAfter(date time.Time) DailyQuestionsQ
FilterByStartsAtAfter(date time.Time) DailyQuestionsQ
Expand Down
57 changes: 44 additions & 13 deletions internal/data/pg/daily_questions.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@ import (
const dailyQuestionsTable = "daily_questions"

type dailyQuestionsQ struct {
db *pgdb.DB
selector squirrel.SelectBuilder
updater squirrel.UpdateBuilder
counter squirrel.SelectBuilder
deleter squirrel.DeleteBuilder
db *pgdb.DB
selector squirrel.SelectBuilder
updater squirrel.UpdateBuilder
counter squirrel.SelectBuilder
deleter squirrel.DeleteBuilder
timeSelector squirrel.SelectBuilder
}

func NewDailyQuestionsQ(db *pgdb.DB) data.DailyQuestionsQ {
return &dailyQuestionsQ{
db: db,
selector: squirrel.Select("*").From(dailyQuestionsTable),
updater: squirrel.Update(dailyQuestionsTable),
deleter: squirrel.Delete(dailyQuestionsTable),
counter: squirrel.Select("COUNT(*) as count").From(dailyQuestionsTable),
db: db,
selector: squirrel.Select("*").From(dailyQuestionsTable),
updater: squirrel.Update(dailyQuestionsTable),
deleter: squirrel.Delete(dailyQuestionsTable),
counter: squirrel.Select("COUNT(*) as count").From(dailyQuestionsTable),
timeSelector: squirrel.Select("*").From(dailyQuestionsTable).OrderBy("starts_at ASC"),
}
}

Expand Down Expand Up @@ -94,6 +96,14 @@ func (q *dailyQuestionsQ) Select() ([]data.DailyQuestion, error) {
return res, nil
}

func (q *dailyQuestionsQ) SelectByTime() ([]data.DailyQuestion, error) {
var res []data.DailyQuestion
if err := q.db.Select(&res, q.timeSelector); err != nil {
return res, fmt.Errorf("select daily questions: %w", err)
}
return res, nil
}

func (q *dailyQuestionsQ) Get() (*data.DailyQuestion, error) {
var res data.DailyQuestion

Expand All @@ -107,6 +117,26 @@ func (q *dailyQuestionsQ) Get() (*data.DailyQuestion, error) {
return &res, nil
}

func applyDailyQuestionPage(page *pgdb.OffsetPageParams, sql squirrel.SelectBuilder) squirrel.SelectBuilder {
if page.Limit == 0 {
page.Limit = 15
}
if page.Order == "" {
page.Order = pgdb.OrderTypeDesc
}

offset := page.Limit * page.PageNumber

sql = sql.Limit(page.Limit).Offset(offset)

return sql
}

func (q *dailyQuestionsQ) Page(page *pgdb.OffsetPageParams) data.DailyQuestionsQ {
q.selector = applyDailyQuestionPage(page, q.selector)
return q
}

func (q *dailyQuestionsQ) FilterByCreatedAtAfter(date time.Time) data.DailyQuestionsQ {
return q.applyCondition(squirrel.GtOrEq{"created_at": date})
}
Expand All @@ -130,12 +160,12 @@ func (q *dailyQuestionsQ) FilterTodayQuestions(offset int) data.DailyQuestionsQ

func (q *dailyQuestionsQ) FilterDayQuestions(location *time.Location, day time.Time) data.DailyQuestionsQ {
dayInLocation := day.In(location)
dayStart := time.Date(dayInLocation.Year(), dayInLocation.Month(), dayInLocation.Day(), 0, 0, 0, 0, location).UTC()
dayEnd := dayStart.Add(24 * time.Hour).Add(-time.Nanosecond).UTC()
dayStart := time.Date(dayInLocation.Year(), dayInLocation.Month(), dayInLocation.Day(), 0, 0, 0, 0, location)
dayEnd := dayStart.Add(24 * time.Hour)

return q.applyCondition(squirrel.And{
squirrel.GtOrEq{"starts_at": dayStart},
squirrel.LtOrEq{"starts_at": dayEnd},
squirrel.Lt{"starts_at": dayEnd},
})
}

Expand Down Expand Up @@ -174,5 +204,6 @@ func (q *dailyQuestionsQ) applyCondition(cond squirrel.Sqlizer) data.DailyQuesti
q.updater = q.updater.Where(cond)
q.deleter = q.deleter.Where(cond)
q.counter = q.counter.Where(cond)
q.timeSelector = q.timeSelector.Where(cond)
return q
}
66 changes: 36 additions & 30 deletions internal/service/handlers/daily_question_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package handlers
import (
"encoding/json"
"net/http"
"strconv"
"time"

"github.com/rarimo/geo-points-svc/internal/data"
"github.com/rarimo/geo-points-svc/internal/service/requests"
Expand All @@ -13,29 +13,47 @@ import (
)

func CreateDailyQuestion(w http.ResponseWriter, r *http.Request) {
//if !auth.Authenticates(UserClaims(r), auth.AdminGrant) {
// ape.RenderErr(w, problems.Unauthorized())
// return
//}

req, err := requests.NewDailyQuestion(r)
if err != nil {
Log(r).Errorf("Error get request NewDailyQuestion: %v", err)
ape.RenderErr(w, problems.InternalError())
Log(r).WithError(err).Error("Error get request NewDailyQuestion: %v")
ape.RenderErr(w, problems.BadRequest(err)...)
return
}

location := DailyQuestions(r).Location
question, err := DailyQuestionsQ(r).FilterDayQuestions(location, req.StartsAt).Get()
if question != nil {
Log(r).Errorf("Error on this day %v, the daily question already has %v", question.StartsAt, question)
ape.RenderErr(w, problems.Conflict())
timeReq, err := time.Parse("2006-01-02", req.StartsAt)
if err != nil {
Log(r).WithError(err).Error("Failed to parse start time")
ape.RenderErr(w, problems.BadRequest(err)...)
return
}
nowTime := time.Now().UTC()
if !timeReq.After(time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day()+1, 0, 0, 0, 0, time.UTC)) {
Log(r).Warnf("Arg start_at must be more or equal tommorow midnoght noe: %s", timeReq.String())
ape.RenderErr(w, problems.Forbidden())
return
}

question, err := DailyQuestionsQ(r).FilterDayQuestions(location, timeReq).Get()
if err != nil {
Log(r).Errorf("Error on this day %v", err)
Log(r).WithError(err).Error("Error on this day")
ape.RenderErr(w, problems.InternalError())
return
}
if question != nil {
Log(r).Infof("Question already exist for date %s, question: %+v", question.StartsAt, question)
ape.RenderErr(w, problems.Conflict())
return
}

answerOptions, err := json.Marshal(req.Options)
if err != nil {
Log(r).Errorf("Error marshalling answer options: %v", err)
Log(r).WithError(err).Error("Failed to get questions")
ape.RenderErr(w, problems.InternalError())
return
}
Expand All @@ -56,10 +74,10 @@ func CreateDailyQuestion(w http.ResponseWriter, r *http.Request) {
stmt := data.DailyQuestion{
Title: req.Title,
TimeForAnswer: req.TimeForAnswer,
Reward: int64(req.Reward),
Reward: req.Reward,
AnswerOptions: answerOptions,
CorrectAnswer: req.CorrectAnswer,
StartsAt: req.StartsAt,
StartsAt: timeReq,
}

err = DailyQuestionsQ(r).Insert(stmt)
Expand All @@ -69,35 +87,23 @@ func CreateDailyQuestion(w http.ResponseWriter, r *http.Request) {
return
}

question, err = DailyQuestionsQ(r).FilterDayQuestions(location, req.StartsAt).Get()
if question == nil {
Log(r).Errorf("Error on this day %v, create question '%v'", req.StartsAt, req.Title)
ape.RenderErr(w, problems.InternalError())
return
}
if err != nil {
Log(r).Errorf("Error on this day %v", err)
ape.RenderErr(w, problems.InternalError())
return
}
question, _ = DailyQuestionsQ(r).FilterDayQuestions(location, timeReq).Get()

ape.Render(w, NewDailyQuestionCrate(&stmt, req.Options, question.ID))
}

func NewDailyQuestionCrate(q *data.DailyQuestion, options []resources.DailyQuestionOptions, ID int64) resources.DailyQuestionDetailsResponse {
return resources.DailyQuestionDetailsResponse{
Data: resources.DailyQuestionDetails{
Key: resources.Key{
ID: strconv.Itoa(int(ID)),
Type: resources.DAILY_QUESTIONS,
},
Key: resources.NewKeyInt64(ID, resources.DAILY_QUESTIONS),
Attributes: resources.DailyQuestionDetailsAttributes{
CorrectAnswer: q.CorrectAnswer,
Title: q.Title,
Options: options,
Reward: int(q.Reward),
StartsAt: q.StartsAt,
CorrectAnswer: q.CorrectAnswer,
Reward: q.Reward,
TimeForAnswer: q.TimeForAnswer,
Title: q.Title,
StartsAt: q.StartsAt.String(),
CreatedAt: time.Now().UTC().String(),
},
},
}
Expand Down
Loading

0 comments on commit 1ec0a37

Please sign in to comment.