266 lines
7.0 KiB
Go
266 lines
7.0 KiB
Go
package result
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"gitea.pena/SQuiz/common/dal/sqlcgen"
|
|
"gitea.pena/SQuiz/common/model"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Deps struct {
|
|
Queries *sqlcgen.Queries
|
|
Pool *sql.DB
|
|
}
|
|
|
|
type ResultRepository struct {
|
|
queries *sqlcgen.Queries
|
|
pool *sql.DB
|
|
}
|
|
|
|
func NewResultRepository(deps Deps) *ResultRepository {
|
|
return &ResultRepository{
|
|
queries: deps.Queries,
|
|
pool: deps.Pool,
|
|
}
|
|
}
|
|
|
|
type GetQuizResDeps struct {
|
|
To, From time.Time
|
|
New bool
|
|
Page uint64
|
|
Limit uint64
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) GetQuizResults(ctx context.Context, quizID uint64, reqExport GetQuizResDeps, payment bool) ([]model.AnswerExport, uint64, error) {
|
|
var results []model.AnswerExport
|
|
|
|
queryBase := "FROM answer WHERE quiz_id = $1 AND result = TRUE AND deleted = FALSE"
|
|
queryParams := []interface{}{quizID}
|
|
|
|
if !reqExport.From.IsZero() {
|
|
queryBase += " AND created_at >= $" + strconv.Itoa(len(queryParams)+1)
|
|
queryParams = append(queryParams, reqExport.From)
|
|
}
|
|
if !reqExport.To.IsZero() {
|
|
queryBase += " AND created_at <= $" + strconv.Itoa(len(queryParams)+1)
|
|
queryParams = append(queryParams, reqExport.To)
|
|
}
|
|
|
|
if reqExport.New {
|
|
queryBase += " AND new = $" + strconv.Itoa(len(queryParams)+1)
|
|
queryParams = append(queryParams, reqExport.New)
|
|
}
|
|
|
|
offset := reqExport.Page * reqExport.Limit
|
|
mainQuery := "SELECT content, id, new, created_at,version " + queryBase + " ORDER BY created_at DESC LIMIT $" + strconv.Itoa(len(queryParams)+1) + " OFFSET $" + strconv.Itoa(len(queryParams)+2)
|
|
queryParams = append(queryParams, reqExport.Limit, offset)
|
|
|
|
rows, err := r.pool.QueryContext(ctx, mainQuery, queryParams...)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var answer model.AnswerExport
|
|
if err := rows.Scan(&answer.Content, &answer.Id, &answer.New, &answer.CreatedAt, &answer.Version); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
if !payment {
|
|
answer.Content = "***"
|
|
}
|
|
|
|
results = append(results, answer)
|
|
}
|
|
|
|
totalCountQuery := "SELECT COUNT(*) " + queryBase
|
|
var totalCount uint64
|
|
if err := r.pool.QueryRowContext(ctx, totalCountQuery, queryParams[:len(queryParams)-2]...).Scan(&totalCount); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return results, totalCount, nil
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) UpdateAnswersStatus(ctx context.Context, accountID string, answersIDs []uint64) error {
|
|
idsPlaceholder := make([]string, len(answersIDs))
|
|
params := make([]interface{}, len(answersIDs)+1)
|
|
params[0] = accountID
|
|
|
|
for i, id := range answersIDs {
|
|
params[i+1] = id
|
|
idsPlaceholder[i] = fmt.Sprintf("$%d", i+2)
|
|
}
|
|
|
|
placeholders := strings.Join(idsPlaceholder, ", ")
|
|
sqlStatement := `
|
|
UPDATE answer AS ans
|
|
SET new = false
|
|
FROM quiz
|
|
WHERE ans.quiz_id = quiz.id
|
|
AND quiz.accountid = $1
|
|
AND ans.new = true
|
|
AND ans.id IN (` + placeholders + ")"
|
|
|
|
_, err := r.pool.ExecContext(ctx, sqlStatement, params...)
|
|
return err
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) GetQuizResultsCSV(ctx context.Context, quizID uint64, reqExport GetQuizResDeps) ([]model.Answer, error) {
|
|
var results []model.Answer
|
|
|
|
mainQuery := `SELECT DISTINCT ON (a.question_id, a.session, a.created_at, a.result)
|
|
a.id, a.content, a.question_id, a.quiz_id, a.fingerprint, a.session, a.result, a.created_at, a.new, a.deleted,a.version
|
|
FROM
|
|
answer a
|
|
WHERE
|
|
a.quiz_id = $1 AND a.deleted = FALSE`
|
|
|
|
queryParams := []interface{}{quizID}
|
|
|
|
if !reqExport.From.IsZero() || !reqExport.To.IsZero() {
|
|
mainQuery += ` AND a.created_at BETWEEN $2 AND $3`
|
|
queryParams = append(queryParams, reqExport.From, reqExport.To)
|
|
}
|
|
|
|
if reqExport.New {
|
|
mainQuery += ` AND a.new = $` + strconv.Itoa(len(queryParams)+1)
|
|
queryParams = append(queryParams, reqExport.New)
|
|
}
|
|
|
|
mainQuery += ` AND EXISTS (
|
|
SELECT 1 FROM answer as a2
|
|
WHERE a2.session = a.session AND a2.result = TRUE AND a2.quiz_id = a.quiz_id
|
|
)`
|
|
|
|
mainQuery += ` ORDER BY a.session, a.question_id ASC, a.created_at DESC, a.result DESC`
|
|
|
|
rows, err := r.pool.QueryContext(ctx, mainQuery, queryParams...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var answer model.Answer
|
|
if err := rows.Scan(&answer.Id, &answer.Content, &answer.QuestionId, &answer.QuizId, &answer.Fingerprint, &answer.Session, &answer.Result, &answer.CreatedAt, &answer.New, &answer.Deleted, &answer.Version); err != nil {
|
|
return nil, err
|
|
}
|
|
results = append(results, answer)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) CheckResultsOwner(ctx context.Context, answersIDs []int64, accountID string) ([]uint64, error) {
|
|
answerIDs, err := r.queries.CheckResultsOwner(ctx, sqlcgen.CheckResultsOwnerParams{
|
|
Column1: answersIDs,
|
|
Accountid: accountID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var answers []uint64
|
|
for _, answerID := range answerIDs {
|
|
answers = append(answers, uint64(answerID))
|
|
}
|
|
|
|
return answers, nil
|
|
}
|
|
|
|
func (r *ResultRepository) SoftDeleteResultByID(ctx context.Context, answerID uint64) error {
|
|
err := r.queries.SoftDeleteResultByID(ctx, int64(answerID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) GetQuestions(ctx context.Context, quizID uint64) ([]model.Question, error) {
|
|
rows, err := r.queries.GetQuestions(ctx, int64(quizID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var questions []model.Question
|
|
|
|
for _, row := range rows {
|
|
question := model.Question{
|
|
Id: uint64(row.ID),
|
|
QuizId: uint64(row.QuizID),
|
|
Title: row.Title,
|
|
Description: row.Description.String,
|
|
Type: string(row.Questiontype.([]byte)),
|
|
Required: row.Required.Bool,
|
|
Deleted: row.Deleted.Bool,
|
|
Page: int(row.Page.Int16),
|
|
Content: row.Content.String,
|
|
Version: int(row.Version.Int16),
|
|
ParentIds: row.ParentIds,
|
|
CreatedAt: row.CreatedAt.Time,
|
|
UpdatedAt: row.UpdatedAt.Time,
|
|
}
|
|
|
|
questions = append(questions, question)
|
|
}
|
|
|
|
return questions, nil
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) GetResultAnswers(ctx context.Context, answerID uint64) ([]model.Answer, error) {
|
|
rows, err := r.queries.GetResultAnswers(ctx, int64(answerID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var answers []model.Answer
|
|
|
|
for _, row := range rows {
|
|
answer := model.Answer{
|
|
Id: uint64(row.ID),
|
|
Content: row.Content.String,
|
|
QuestionId: uint64(row.QuestionID),
|
|
QuizId: uint64(row.QuizID),
|
|
Fingerprint: row.Fingerprint.String,
|
|
Session: row.Session.String,
|
|
Result: row.Result.Bool,
|
|
CreatedAt: row.CreatedAt.Time,
|
|
New: row.New.Bool,
|
|
Deleted: row.Deleted.Bool,
|
|
Device: row.Device,
|
|
DeviceType: row.DeviceType,
|
|
OS: row.Os,
|
|
IP: row.Ip,
|
|
Browser: row.Browser,
|
|
Version: row.Version,
|
|
}
|
|
|
|
answers = append(answers, answer)
|
|
}
|
|
|
|
return answers, nil
|
|
}
|
|
|
|
// test +
|
|
func (r *ResultRepository) CheckResultOwner(ctx context.Context, answerID uint64, accountID string) (bool, error) {
|
|
ownerAccountID, err := r.queries.CheckResultOwner(ctx, int64(answerID))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return ownerAccountID == accountID, nil
|
|
}
|