diff --git a/db/queries/quiz.sql b/db/queries/quiz.sql index dada85e..b6fefea 100644 --- a/db/queries/quiz.sql +++ b/db/queries/quiz.sql @@ -24,32 +24,7 @@ SET active = 0 WHERE filename = ? AND version <> ?; --- name: FindQuizBySha1 :one -SELECT * -FROM quiz -WHERE sha1 = ?; - -- name: FindQuizFullBySha1 :many -SELECT q.sha1 AS quiz_sha1, - q.filename AS quiz_filename, - q.name AS quiz_name, - q.version AS quiz_version, - q.created_at AS quiz_created_at, - q.duration AS quiz_duration, - q.active AS quiz_active, - qq.sha1 AS question_sha1, - qq.content AS question_content, - qa.sha1 AS answer_sha1, - qa.content AS answer_content, - qa.valid AS answer_valid -FROM quiz q - JOIN quiz_question_quiz qqq ON q.sha1 = qqq.quiz_sha1 - JOIN quiz_question qq ON qq.sha1 = qqq.question_sha1 - JOIN quiz_question_answer qqa ON qq.sha1 = qqa.question_sha1 - JOIN quiz_answer qa ON qa.sha1 = qqa.answer_sha1 -WHERE q.sha1 = ?; - --- name: FindQuizFullBySha1RestrictedToClass :many SELECT q.sha1 AS quiz_sha1, q.filename AS quiz_filename, q.name AS quiz_name, @@ -71,7 +46,7 @@ FROM quiz q JOIN student_class sc ON sc.uuid = qcv.class_uuid JOIN user u ON sc.uuid = u.class_uuid WHERE q.sha1 = ? - AND u.id = ?; + AND u.id IS NULL OR u.id = ?; -- name: FindQuizByFilenameAndLatestVersion :one SELECT * @@ -82,18 +57,12 @@ LIMIT 1; -- name: FindAllActiveQuiz :many SELECT * -FROM quiz -WHERE active = 1 -LIMIT ? OFFSET ?; - --- name: FindAllActiveQuizRestrictedToClass :many -SELECT * FROM quiz q JOIN quiz_class_visibility qcv ON q.sha1 = qcv.quiz_sha1 JOIN student_class sc ON sc.uuid = qcv.class_uuid JOIN user u ON sc.uuid = u.class_uuid WHERE q.active = 1 - AND u.id = ? + AND u.id IS NULL OR u.id = ? LIMIT ? OFFSET ?; -- name: CountAllActiveQuiz :one diff --git a/internal/back/domain/mock_ClassRepository_test.go b/internal/back/domain/mock_ClassRepository_test.go index 4ed2a26..6be3694 100644 --- a/internal/back/domain/mock_ClassRepository_test.go +++ b/internal/back/domain/mock_ClassRepository_test.go @@ -117,6 +117,50 @@ func (_c *MockClassRepository_CreateOrReplace_Call) RunAndReturn(run func(contex return _c } +// CreateQuizClassVisibility provides a mock function with given fields: ctx, quizSha1, classId +func (_m *MockClassRepository) CreateQuizClassVisibility(ctx context.Context, quizSha1 string, classId uuid.UUID) error { + ret := _m.Called(ctx, quizSha1, classId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, uuid.UUID) error); ok { + r0 = rf(ctx, quizSha1, classId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClassRepository_CreateQuizClassVisibility_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateQuizClassVisibility' +type MockClassRepository_CreateQuizClassVisibility_Call struct { + *mock.Call +} + +// CreateQuizClassVisibility is a helper method to define mock.On call +// - ctx context.Context +// - quizSha1 string +// - classId uuid.UUID +func (_e *MockClassRepository_Expecter) CreateQuizClassVisibility(ctx interface{}, quizSha1 interface{}, classId interface{}) *MockClassRepository_CreateQuizClassVisibility_Call { + return &MockClassRepository_CreateQuizClassVisibility_Call{Call: _e.mock.On("CreateQuizClassVisibility", ctx, quizSha1, classId)} +} + +func (_c *MockClassRepository_CreateQuizClassVisibility_Call) Run(run func(ctx context.Context, quizSha1 string, classId uuid.UUID)) *MockClassRepository_CreateQuizClassVisibility_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(uuid.UUID)) + }) + return _c +} + +func (_c *MockClassRepository_CreateQuizClassVisibility_Call) Return(_a0 error) *MockClassRepository_CreateQuizClassVisibility_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClassRepository_CreateQuizClassVisibility_Call) RunAndReturn(run func(context.Context, string, uuid.UUID) error) *MockClassRepository_CreateQuizClassVisibility_Call { + _c.Call.Return(run) + return _c +} + // Delete provides a mock function with given fields: ctx, classId func (_m *MockClassRepository) Delete(ctx context.Context, classId uuid.UUID) error { ret := _m.Called(ctx, classId) @@ -160,6 +204,50 @@ func (_c *MockClassRepository_Delete_Call) RunAndReturn(run func(context.Context return _c } +// DeleteQuizClassVisibility provides a mock function with given fields: ctx, quizSha1, classId +func (_m *MockClassRepository) DeleteQuizClassVisibility(ctx context.Context, quizSha1 string, classId uuid.UUID) error { + ret := _m.Called(ctx, quizSha1, classId) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, uuid.UUID) error); ok { + r0 = rf(ctx, quizSha1, classId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClassRepository_DeleteQuizClassVisibility_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteQuizClassVisibility' +type MockClassRepository_DeleteQuizClassVisibility_Call struct { + *mock.Call +} + +// DeleteQuizClassVisibility is a helper method to define mock.On call +// - ctx context.Context +// - quizSha1 string +// - classId uuid.UUID +func (_e *MockClassRepository_Expecter) DeleteQuizClassVisibility(ctx interface{}, quizSha1 interface{}, classId interface{}) *MockClassRepository_DeleteQuizClassVisibility_Call { + return &MockClassRepository_DeleteQuizClassVisibility_Call{Call: _e.mock.On("DeleteQuizClassVisibility", ctx, quizSha1, classId)} +} + +func (_c *MockClassRepository_DeleteQuizClassVisibility_Call) Run(run func(ctx context.Context, quizSha1 string, classId uuid.UUID)) *MockClassRepository_DeleteQuizClassVisibility_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(uuid.UUID)) + }) + return _c +} + +func (_c *MockClassRepository_DeleteQuizClassVisibility_Call) Return(_a0 error) *MockClassRepository_DeleteQuizClassVisibility_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClassRepository_DeleteQuizClassVisibility_Call) RunAndReturn(run func(context.Context, string, uuid.UUID) error) *MockClassRepository_DeleteQuizClassVisibility_Call { + _c.Call.Return(run) + return _c +} + // ExistsById provides a mock function with given fields: ctx, classId func (_m *MockClassRepository) ExistsById(ctx context.Context, classId uuid.UUID) bool { ret := _m.Called(ctx, classId) diff --git a/internal/back/domain/mock_QuizRepository_test.go b/internal/back/domain/mock_QuizRepository_test.go index f61b547..d86ac55 100644 --- a/internal/back/domain/mock_QuizRepository_test.go +++ b/internal/back/domain/mock_QuizRepository_test.go @@ -262,25 +262,25 @@ func (_c *MockQuizRepository_Create_Call) RunAndReturn(run func(context.Context, return _c } -// FindAllActive provides a mock function with given fields: ctx, limit, offset -func (_m *MockQuizRepository) FindAllActive(ctx context.Context, limit uint16, offset uint16) ([]*Quiz, error) { - ret := _m.Called(ctx, limit, offset) +// FindAllActive provides a mock function with given fields: ctx, userId, limit, offset +func (_m *MockQuizRepository) FindAllActive(ctx context.Context, userId string, limit uint16, offset uint16) ([]*Quiz, error) { + ret := _m.Called(ctx, userId, limit, offset) var r0 []*Quiz var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint16, uint16) ([]*Quiz, error)); ok { - return rf(ctx, limit, offset) + if rf, ok := ret.Get(0).(func(context.Context, string, uint16, uint16) ([]*Quiz, error)); ok { + return rf(ctx, userId, limit, offset) } - if rf, ok := ret.Get(0).(func(context.Context, uint16, uint16) []*Quiz); ok { - r0 = rf(ctx, limit, offset) + if rf, ok := ret.Get(0).(func(context.Context, string, uint16, uint16) []*Quiz); ok { + r0 = rf(ctx, userId, limit, offset) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*Quiz) } } - if rf, ok := ret.Get(1).(func(context.Context, uint16, uint16) error); ok { - r1 = rf(ctx, limit, offset) + if rf, ok := ret.Get(1).(func(context.Context, string, uint16, uint16) error); ok { + r1 = rf(ctx, userId, limit, offset) } else { r1 = ret.Error(1) } @@ -295,15 +295,16 @@ type MockQuizRepository_FindAllActive_Call struct { // FindAllActive is a helper method to define mock.On call // - ctx context.Context +// - userId string // - limit uint16 // - offset uint16 -func (_e *MockQuizRepository_Expecter) FindAllActive(ctx interface{}, limit interface{}, offset interface{}) *MockQuizRepository_FindAllActive_Call { - return &MockQuizRepository_FindAllActive_Call{Call: _e.mock.On("FindAllActive", ctx, limit, offset)} +func (_e *MockQuizRepository_Expecter) FindAllActive(ctx interface{}, userId interface{}, limit interface{}, offset interface{}) *MockQuizRepository_FindAllActive_Call { + return &MockQuizRepository_FindAllActive_Call{Call: _e.mock.On("FindAllActive", ctx, userId, limit, offset)} } -func (_c *MockQuizRepository_FindAllActive_Call) Run(run func(ctx context.Context, limit uint16, offset uint16)) *MockQuizRepository_FindAllActive_Call { +func (_c *MockQuizRepository_FindAllActive_Call) Run(run func(ctx context.Context, userId string, limit uint16, offset uint16)) *MockQuizRepository_FindAllActive_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint16), args[2].(uint16)) + run(args[0].(context.Context), args[1].(string), args[2].(uint16), args[3].(uint16)) }) return _c } @@ -313,7 +314,7 @@ func (_c *MockQuizRepository_FindAllActive_Call) Return(_a0 []*Quiz, _a1 error) return _c } -func (_c *MockQuizRepository_FindAllActive_Call) RunAndReturn(run func(context.Context, uint16, uint16) ([]*Quiz, error)) *MockQuizRepository_FindAllActive_Call { +func (_c *MockQuizRepository_FindAllActive_Call) RunAndReturn(run func(context.Context, string, uint16, uint16) ([]*Quiz, error)) *MockQuizRepository_FindAllActive_Call { _c.Call.Return(run) return _c } @@ -376,80 +377,25 @@ func (_c *MockQuizRepository_FindAllSessions_Call) RunAndReturn(run func(context return _c } -// FindBySha1 provides a mock function with given fields: ctx, sha1 -func (_m *MockQuizRepository) FindBySha1(ctx context.Context, sha1 string) (*Quiz, error) { - ret := _m.Called(ctx, sha1) +// FindFullBySha1 provides a mock function with given fields: ctx, sha1, userId +func (_m *MockQuizRepository) FindFullBySha1(ctx context.Context, sha1 string, userId string) (*Quiz, error) { + ret := _m.Called(ctx, sha1, userId) var r0 *Quiz var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*Quiz, error)); ok { - return rf(ctx, sha1) + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*Quiz, error)); ok { + return rf(ctx, sha1, userId) } - if rf, ok := ret.Get(0).(func(context.Context, string) *Quiz); ok { - r0 = rf(ctx, sha1) + if rf, ok := ret.Get(0).(func(context.Context, string, string) *Quiz); ok { + r0 = rf(ctx, sha1, userId) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*Quiz) } } - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, sha1) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockQuizRepository_FindBySha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindBySha1' -type MockQuizRepository_FindBySha1_Call struct { - *mock.Call -} - -// FindBySha1 is a helper method to define mock.On call -// - ctx context.Context -// - sha1 string -func (_e *MockQuizRepository_Expecter) FindBySha1(ctx interface{}, sha1 interface{}) *MockQuizRepository_FindBySha1_Call { - return &MockQuizRepository_FindBySha1_Call{Call: _e.mock.On("FindBySha1", ctx, sha1)} -} - -func (_c *MockQuizRepository_FindBySha1_Call) Run(run func(ctx context.Context, sha1 string)) *MockQuizRepository_FindBySha1_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *MockQuizRepository_FindBySha1_Call) Return(_a0 *Quiz, _a1 error) *MockQuizRepository_FindBySha1_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockQuizRepository_FindBySha1_Call) RunAndReturn(run func(context.Context, string) (*Quiz, error)) *MockQuizRepository_FindBySha1_Call { - _c.Call.Return(run) - return _c -} - -// FindFullBySha1 provides a mock function with given fields: ctx, sha1 -func (_m *MockQuizRepository) FindFullBySha1(ctx context.Context, sha1 string) (*Quiz, error) { - ret := _m.Called(ctx, sha1) - - var r0 *Quiz - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*Quiz, error)); ok { - return rf(ctx, sha1) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *Quiz); ok { - r0 = rf(ctx, sha1) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*Quiz) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, sha1) + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, sha1, userId) } else { r1 = ret.Error(1) } @@ -465,13 +411,14 @@ type MockQuizRepository_FindFullBySha1_Call struct { // FindFullBySha1 is a helper method to define mock.On call // - ctx context.Context // - sha1 string -func (_e *MockQuizRepository_Expecter) FindFullBySha1(ctx interface{}, sha1 interface{}) *MockQuizRepository_FindFullBySha1_Call { - return &MockQuizRepository_FindFullBySha1_Call{Call: _e.mock.On("FindFullBySha1", ctx, sha1)} +// - userId string +func (_e *MockQuizRepository_Expecter) FindFullBySha1(ctx interface{}, sha1 interface{}, userId interface{}) *MockQuizRepository_FindFullBySha1_Call { + return &MockQuizRepository_FindFullBySha1_Call{Call: _e.mock.On("FindFullBySha1", ctx, sha1, userId)} } -func (_c *MockQuizRepository_FindFullBySha1_Call) Run(run func(ctx context.Context, sha1 string)) *MockQuizRepository_FindFullBySha1_Call { +func (_c *MockQuizRepository_FindFullBySha1_Call) Run(run func(ctx context.Context, sha1 string, userId string)) *MockQuizRepository_FindFullBySha1_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) + run(args[0].(context.Context), args[1].(string), args[2].(string)) }) return _c } @@ -481,7 +428,7 @@ func (_c *MockQuizRepository_FindFullBySha1_Call) Return(_a0 *Quiz, _a1 error) * return _c } -func (_c *MockQuizRepository_FindFullBySha1_Call) RunAndReturn(run func(context.Context, string) (*Quiz, error)) *MockQuizRepository_FindFullBySha1_Call { +func (_c *MockQuizRepository_FindFullBySha1_Call) RunAndReturn(run func(context.Context, string, string) (*Quiz, error)) *MockQuizRepository_FindFullBySha1_Call { _c.Call.Return(run) return _c } diff --git a/internal/back/domain/quizService.go b/internal/back/domain/quizService.go index 0add782..5baf7a3 100644 --- a/internal/back/domain/quizService.go +++ b/internal/back/domain/quizService.go @@ -34,8 +34,8 @@ func NewQuizService(r QuizRepository) QuizService { return QuizService{r: r} } -func (s *QuizService) FindFullBySha1(ctx context.Context, sha1 string) (*Quiz, error) { - quiz, err := s.r.FindFullBySha1(ctx, sha1) +func (s *QuizService) FindFullBySha1(ctx context.Context, sha1 string, userId string) (*Quiz, error) { + quiz, err := s.r.FindFullBySha1(ctx, sha1, userId) if err != nil { return nil, err } @@ -43,8 +43,8 @@ func (s *QuizService) FindFullBySha1(ctx context.Context, sha1 string) (*Quiz, e return quiz, nil } -func (s *QuizService) FindAllActive(ctx context.Context, limit uint16, offset uint16) ([]*Quiz, uint32, error) { - quizzes, err := s.r.FindAllActive(ctx, limit, offset) +func (s *QuizService) FindAllActive(ctx context.Context, userId string, limit uint16, offset uint16) ([]*Quiz, uint32, error) { + quizzes, err := s.r.FindAllActive(ctx, userId, limit, offset) if err != nil { return nil, 0, err } diff --git a/internal/back/domain/repositories.go b/internal/back/domain/repositories.go index c4b8737..772d44e 100644 --- a/internal/back/domain/repositories.go +++ b/internal/back/domain/repositories.go @@ -24,10 +24,9 @@ import ( //go:generate mockery --name QuizRepository type QuizRepository interface { - FindBySha1(ctx context.Context, sha1 string) (*Quiz, error) - FindFullBySha1(ctx context.Context, sha1 string) (*Quiz, error) + FindFullBySha1(ctx context.Context, sha1 string, userId string) (*Quiz, error) FindLatestVersionByFilename(ctx context.Context, filename string) (*Quiz, error) - FindAllActive(ctx context.Context, limit uint16, offset uint16) ([]*Quiz, error) + FindAllActive(ctx context.Context, userId string, limit uint16, offset uint16) ([]*Quiz, error) CountAllActive(ctx context.Context) (uint32, error) Create(ctx context.Context, quiz *Quiz) error ActivateOnlyVersion(ctx context.Context, filename string, version int) error diff --git a/internal/back/infrastructure/quizRepositoryImpl.go b/internal/back/infrastructure/quizRepositoryImpl.go index 68bd5b5..7bdfa71 100644 --- a/internal/back/infrastructure/quizRepositoryImpl.go +++ b/internal/back/infrastructure/quizRepositoryImpl.go @@ -39,17 +39,11 @@ func NewQuizRepository(c *sql.DB) *QuizDBRepository { return &QuizDBRepository{q: sqlc.New(c)} } -func (r *QuizDBRepository) FindBySha1(ctx context.Context, sha1 string) (*domain.Quiz, error) { - entity, err := r.q.FindQuizBySha1(ctx, sha1) - if err != nil { - return nil, err - } - - return r.toQuiz(entity), nil -} - -func (r *QuizDBRepository) FindFullBySha1(ctx context.Context, sha1 string) (*domain.Quiz, error) { - entities, err := r.q.FindQuizFullBySha1(ctx, sha1) +func (r *QuizDBRepository) FindFullBySha1(ctx context.Context, sha1 string, userId string) (*domain.Quiz, error) { + entities, err := r.q.FindQuizFullBySha1(ctx, sqlc.FindQuizFullBySha1Params{ + Sha1: sha1, + ID: userId, + }) if err != nil { return nil, err } @@ -91,8 +85,9 @@ func (r *QuizDBRepository) FindFullBySha1(ctx context.Context, sha1 string) (*do return &quiz, nil } -func (r *QuizDBRepository) FindAllActive(ctx context.Context, limit uint16, offset uint16) ([]*domain.Quiz, error) { +func (r *QuizDBRepository) FindAllActive(ctx context.Context, userId string, limit uint16, offset uint16) ([]*domain.Quiz, error) { quizzes, err := r.q.FindAllActiveQuiz(ctx, sqlc.FindAllActiveQuizParams{ + ID: userId, Limit: int64(limit), Offset: int64(offset), }) @@ -202,11 +197,19 @@ func (r *QuizDBRepository) toQuiz(entity sqlc.Quiz) *domain.Quiz { } } -func (r *QuizDBRepository) toQuizArray(entities []sqlc.Quiz) []*domain.Quiz { +func (r *QuizDBRepository) toQuizArray(entities []sqlc.FindAllActiveQuizRow) []*domain.Quiz { domains := make([]*domain.Quiz, len(entities)) for i, entity := range entities { - domains[i] = r.toQuiz(entity) + domains[i] = &domain.Quiz{ + Sha1: entity.Sha1, + Filename: entity.Filename, + Name: entity.Name, + Version: int(entity.Version), + Duration: int(entity.Duration), + Active: entity.Active, + CreatedAt: entity.CreatedAt, + } } return domains diff --git a/internal/back/infrastructure/sqlc/quiz.sql.go b/internal/back/infrastructure/sqlc/quiz.sql.go index de715f3..5815c06 100644 --- a/internal/back/infrastructure/sqlc/quiz.sql.go +++ b/internal/back/infrastructure/sqlc/quiz.sql.go @@ -116,66 +116,23 @@ func (q *Queries) CreateOrReplaceQuiz(ctx context.Context, arg CreateOrReplaceQu } const findAllActiveQuiz = `-- name: FindAllActiveQuiz :many -SELECT sha1, name, filename, version, active, created_at, duration -FROM quiz -WHERE active = 1 -LIMIT ? OFFSET ? -` - -type FindAllActiveQuizParams struct { - Limit int64 `db:"limit"` - Offset int64 `db:"offset"` -} - -func (q *Queries) FindAllActiveQuiz(ctx context.Context, arg FindAllActiveQuizParams) ([]Quiz, error) { - rows, err := q.db.QueryContext(ctx, findAllActiveQuiz, arg.Limit, arg.Offset) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Quiz{} - for rows.Next() { - var i Quiz - if err := rows.Scan( - &i.Sha1, - &i.Name, - &i.Filename, - &i.Version, - &i.Active, - &i.CreatedAt, - &i.Duration, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const findAllActiveQuizRestrictedToClass = `-- name: FindAllActiveQuizRestrictedToClass :many SELECT sha1, q.name, filename, version, q.active, created_at, duration, qcv.class_uuid, quiz_sha1, uuid, sc.name, id, email, firstname, lastname, u.active, role_id, u.class_uuid FROM quiz q JOIN quiz_class_visibility qcv ON q.sha1 = qcv.quiz_sha1 JOIN student_class sc ON sc.uuid = qcv.class_uuid JOIN user u ON sc.uuid = u.class_uuid WHERE q.active = 1 - AND u.id = ? + AND u.id IS NULL OR u.id = ? LIMIT ? OFFSET ? ` -type FindAllActiveQuizRestrictedToClassParams struct { +type FindAllActiveQuizParams struct { ID string `db:"id"` Limit int64 `db:"limit"` Offset int64 `db:"offset"` } -type FindAllActiveQuizRestrictedToClassRow struct { +type FindAllActiveQuizRow struct { Sha1 string `db:"sha1"` Name string `db:"name"` Filename string `db:"filename"` @@ -196,15 +153,15 @@ type FindAllActiveQuizRestrictedToClassRow struct { ClassUuid_2 uuid.UUID `db:"class_uuid_2"` } -func (q *Queries) FindAllActiveQuizRestrictedToClass(ctx context.Context, arg FindAllActiveQuizRestrictedToClassParams) ([]FindAllActiveQuizRestrictedToClassRow, error) { - rows, err := q.db.QueryContext(ctx, findAllActiveQuizRestrictedToClass, arg.ID, arg.Limit, arg.Offset) +func (q *Queries) FindAllActiveQuiz(ctx context.Context, arg FindAllActiveQuizParams) ([]FindAllActiveQuizRow, error) { + rows, err := q.db.QueryContext(ctx, findAllActiveQuiz, arg.ID, arg.Limit, arg.Offset) if err != nil { return nil, err } defer rows.Close() - items := []FindAllActiveQuizRestrictedToClassRow{} + items := []FindAllActiveQuizRow{} for rows.Next() { - var i FindAllActiveQuizRestrictedToClassRow + var i FindAllActiveQuizRow if err := rows.Scan( &i.Sha1, &i.Name, @@ -283,78 +240,6 @@ func (q *Queries) FindQuizBySha1(ctx context.Context, sha1 string) (Quiz, error) } const findQuizFullBySha1 = `-- name: FindQuizFullBySha1 :many -SELECT q.sha1 AS quiz_sha1, - q.filename AS quiz_filename, - q.name AS quiz_name, - q.version AS quiz_version, - q.created_at AS quiz_created_at, - q.duration AS quiz_duration, - q.active AS quiz_active, - qq.sha1 AS question_sha1, - qq.content AS question_content, - qa.sha1 AS answer_sha1, - qa.content AS answer_content, - qa.valid AS answer_valid -FROM quiz q - JOIN quiz_question_quiz qqq ON q.sha1 = qqq.quiz_sha1 - JOIN quiz_question qq ON qq.sha1 = qqq.question_sha1 - JOIN quiz_question_answer qqa ON qq.sha1 = qqa.question_sha1 - JOIN quiz_answer qa ON qa.sha1 = qqa.answer_sha1 -WHERE q.sha1 = ? -` - -type FindQuizFullBySha1Row struct { - QuizSha1 string `db:"quiz_sha1"` - QuizFilename string `db:"quiz_filename"` - QuizName string `db:"quiz_name"` - QuizVersion int64 `db:"quiz_version"` - QuizCreatedAt string `db:"quiz_created_at"` - QuizDuration int64 `db:"quiz_duration"` - QuizActive bool `db:"quiz_active"` - QuestionSha1 string `db:"question_sha1"` - QuestionContent string `db:"question_content"` - AnswerSha1 string `db:"answer_sha1"` - AnswerContent string `db:"answer_content"` - AnswerValid bool `db:"answer_valid"` -} - -func (q *Queries) FindQuizFullBySha1(ctx context.Context, sha1 string) ([]FindQuizFullBySha1Row, error) { - rows, err := q.db.QueryContext(ctx, findQuizFullBySha1, sha1) - if err != nil { - return nil, err - } - defer rows.Close() - items := []FindQuizFullBySha1Row{} - for rows.Next() { - var i FindQuizFullBySha1Row - if err := rows.Scan( - &i.QuizSha1, - &i.QuizFilename, - &i.QuizName, - &i.QuizVersion, - &i.QuizCreatedAt, - &i.QuizDuration, - &i.QuizActive, - &i.QuestionSha1, - &i.QuestionContent, - &i.AnswerSha1, - &i.AnswerContent, - &i.AnswerValid, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const findQuizFullBySha1RestrictedToClass = `-- name: FindQuizFullBySha1RestrictedToClass :many SELECT q.sha1 AS quiz_sha1, q.filename AS quiz_filename, q.name AS quiz_name, @@ -376,15 +261,15 @@ FROM quiz q JOIN student_class sc ON sc.uuid = qcv.class_uuid JOIN user u ON sc.uuid = u.class_uuid WHERE q.sha1 = ? - AND u.id = ? + AND u.id IS NULL OR u.id = ? ` -type FindQuizFullBySha1RestrictedToClassParams struct { +type FindQuizFullBySha1Params struct { Sha1 string `db:"sha1"` ID string `db:"id"` } -type FindQuizFullBySha1RestrictedToClassRow struct { +type FindQuizFullBySha1Row struct { QuizSha1 string `db:"quiz_sha1"` QuizFilename string `db:"quiz_filename"` QuizName string `db:"quiz_name"` @@ -399,15 +284,15 @@ type FindQuizFullBySha1RestrictedToClassRow struct { AnswerValid bool `db:"answer_valid"` } -func (q *Queries) FindQuizFullBySha1RestrictedToClass(ctx context.Context, arg FindQuizFullBySha1RestrictedToClassParams) ([]FindQuizFullBySha1RestrictedToClassRow, error) { - rows, err := q.db.QueryContext(ctx, findQuizFullBySha1RestrictedToClass, arg.Sha1, arg.ID) +func (q *Queries) FindQuizFullBySha1(ctx context.Context, arg FindQuizFullBySha1Params) ([]FindQuizFullBySha1Row, error) { + rows, err := q.db.QueryContext(ctx, findQuizFullBySha1, arg.Sha1, arg.ID) if err != nil { return nil, err } defer rows.Close() - items := []FindQuizFullBySha1RestrictedToClassRow{} + items := []FindQuizFullBySha1Row{} for rows.Next() { - var i FindQuizFullBySha1RestrictedToClassRow + var i FindQuizFullBySha1Row if err := rows.Scan( &i.QuizSha1, &i.QuizFilename, diff --git a/internal/back/presentation/authController.go b/internal/back/presentation/authController.go index 44281a6..124c1d6 100644 --- a/internal/back/presentation/authController.go +++ b/internal/back/presentation/authController.go @@ -57,6 +57,14 @@ func isAdmin(ctx *gin.Context) bool { return false } +func isStudent(ctx *gin.Context) bool { + if role, found := getRoleFromContext(ctx); found { + return role == domain.Student + } + + return false +} + func getUserIdFromContext(ctx *gin.Context) (string, bool) { if r, found := ctx.Get(userIdCtxKey); found { return r.(string), true diff --git a/internal/back/presentation/quizController.go b/internal/back/presentation/quizController.go index 4fc8efe..e21fd14 100644 --- a/internal/back/presentation/quizController.go +++ b/internal/back/presentation/quizController.go @@ -32,7 +32,17 @@ func (c *ApiController) quizList(ctx *gin.Context) { return } - quizzes, total, err := c.quizService.FindAllActive(ctx.Request.Context(), end-start, start) + userId := "" + if isStudent(ctx) { + if id, found := getUserIdFromContext(ctx); found { + userId = id + } else { + handleHttpError(ctx, http.StatusUnauthorized, "userId not present in context") + return + } + } + + quizzes, total, err := c.quizService.FindAllActive(ctx.Request.Context(), userId, end-start, start) if err != nil { handleError(ctx, err) return @@ -45,7 +55,17 @@ func (c *ApiController) quizList(ctx *gin.Context) { func (c *ApiController) quizBySha1(ctx *gin.Context) { sha1 := ctx.Param("sha1") - quiz, err := c.quizService.FindFullBySha1(ctx, sha1) + userId := "" + if isStudent(ctx) { + if id, found := getUserIdFromContext(ctx); found { + userId = id + } else { + handleHttpError(ctx, http.StatusUnauthorized, "userId not present in context") + return + } + } + + quiz, err := c.quizService.FindFullBySha1(ctx, sha1, userId) if err != nil { handleError(ctx, err) return