diff --git a/docs/docs.go b/docs/docs.go index 931199ff693e5055421c6601d9d533be163f6180..9e72b0b029a24d96014014b30d84b4ff9b06e6ad 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1440,6 +1440,54 @@ const docTemplate = `{ } } }, + "/course/{id}/quiz": { + "get": { + "description": "Get all cours", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "course" + ], + "summary": "Get Course quiz", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Course id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/web.BaseResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/quiz.Quiz" + } + } + } + } + ] + } + } + } + } + }, "/material/{id}": { "get": { "description": "Get material detail", @@ -1645,6 +1693,51 @@ const docTemplate = `{ } } }, + "/quiz/{id}": { + "get": { + "description": "Get Quiz Detail", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "quiz" + ], + "summary": "Get Quiz Detail", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Quiz id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/web.BaseResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/quiz.Quiz" + } + } + } + ] + } + } + } + } + }, "/reset/confirm": { "put": { "description": "Do confirmation to reset password", @@ -2156,6 +2249,23 @@ const docTemplate = `{ } } }, + "quiz.Quiz": { + "type": "object", + "properties": { + "course_id": { + "type": "string" + }, + "creator_email": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "refresh.RefreshResponsePayload": { "description": "Refresh endpoint response when process success", "type": "object", diff --git a/docs/swagger.json b/docs/swagger.json index f9da30dc7f51afeb01e68dc5388c964419c1db75..07c6617ab34c4011a16323b020510a7289432e12 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1432,6 +1432,54 @@ } } }, + "/course/{id}/quiz": { + "get": { + "description": "Get all cours", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "course" + ], + "summary": "Get Course quiz", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Course id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/web.BaseResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/quiz.Quiz" + } + } + } + } + ] + } + } + } + } + }, "/material/{id}": { "get": { "description": "Get material detail", @@ -1637,6 +1685,51 @@ } } }, + "/quiz/{id}": { + "get": { + "description": "Get Quiz Detail", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "quiz" + ], + "summary": "Get Quiz Detail", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Quiz id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/web.BaseResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/quiz.Quiz" + } + } + } + ] + } + } + } + } + }, "/reset/confirm": { "put": { "description": "Do confirmation to reset password", @@ -2148,6 +2241,23 @@ } } }, + "quiz.Quiz": { + "type": "object", + "properties": { + "course_id": { + "type": "string" + }, + "creator_email": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "refresh.RefreshResponsePayload": { "description": "Refresh endpoint response when process success", "type": "object", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0341f675c5fd29504631807c095716cdf5fb3c0b..ee7cc0f2bd3089513cd4d4688a70efda551cca03 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -298,6 +298,17 @@ definitions: upload_link: type: string type: object + quiz.Quiz: + properties: + course_id: + type: string + creator_email: + type: string + id: + type: string + name: + type: string + type: object refresh.RefreshResponsePayload: description: Refresh endpoint response when process success properties: @@ -917,6 +928,35 @@ paths: summary: Get materials tags: - content + /course/{id}/quiz: + get: + consumes: + - application/json + description: Get all cours + parameters: + - description: Course id + format: uuid + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/web.BaseResponse' + - properties: + data: + items: + $ref: '#/definitions/quiz.Quiz' + type: array + type: object + summary: Get Course quiz + tags: + - course /course/faculty: get: description: Retrieves a list of all faculties @@ -1438,6 +1478,33 @@ paths: summary: Delete Content tags: - content + /quiz/{id}: + get: + consumes: + - application/json + description: Get Quiz Detail + parameters: + - description: Quiz id + format: uuid + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/web.BaseResponse' + - properties: + data: + $ref: '#/definitions/quiz.Quiz' + type: object + summary: Get Quiz Detail + tags: + - quiz /reset/confirm: put: description: Do confirmation to reset password diff --git a/handler/di.go b/handler/di.go index 643a1fcfdc45a1bb37cd1e2e197932b5e320cb55..399ef81ecbb23c9d70b0431c6129610c92d5dadc 100644 --- a/handler/di.go +++ b/handler/di.go @@ -7,6 +7,7 @@ import ( "gitlab.informatika.org/ocw/ocw-backend/handler/common" "gitlab.informatika.org/ocw/ocw-backend/handler/course" "gitlab.informatika.org/ocw/ocw-backend/handler/material" + "gitlab.informatika.org/ocw/ocw-backend/handler/quiz" "gitlab.informatika.org/ocw/ocw-backend/handler/reset" "gitlab.informatika.org/ocw/ocw-backend/handler/swagger" ) @@ -39,4 +40,8 @@ var HandlerSet = wire.NewSet( // Material wire.Struct(new(material.MaterialHandlerImpl), "*"), wire.Bind(new(material.MaterialHandler), new(*material.MaterialHandlerImpl)), + + // Quiz + wire.Struct(new(quiz.QuizHandlerImpl), "*"), + wire.Bind(new(quiz.QuizHandler), new(*quiz.QuizHandlerImpl)), ) diff --git a/handler/material/impl.go b/handler/material/impl.go index 647ce941833b3c696b66271c41dd2565bb23a874..f8aab59ca45cb8ce12796599e6b197e1a0d8c418 100644 --- a/handler/material/impl.go +++ b/handler/material/impl.go @@ -12,7 +12,7 @@ type MaterialHandlerImpl struct { material.MaterialService material.MaterialContentService httputil.HttpUtil + logger.Logger wrapper.WrapperUtil course.CourseRepository - logger.Logger } diff --git a/handler/quiz/get.go b/handler/quiz/get.go new file mode 100644 index 0000000000000000000000000000000000000000..799ca822a991240a0c6febccb29640720f1b5e67 --- /dev/null +++ b/handler/quiz/get.go @@ -0,0 +1,57 @@ +package quiz + +import ( + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/web" +) + +// Index godoc +// +// @Tags quiz +// @Summary Get Quiz Detail +// @Description Get Quiz Detail +// @Produce json +// @Accept json +// @Param id path string true "Quiz id" Format(uuid) +// @Success 200 {object} web.BaseResponse{data=quiz.Quiz} +// @Router /quiz/{id} [get] +func (m QuizHandlerImpl) GetQuizDetail(w http.ResponseWriter, r *http.Request) { + quizId := chi.URLParam(r, "id") + + if quizId == "" { + payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil) + m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload) + return + } + + id, err := uuid.Parse(quizId) + + if err != nil { + // invalid uuid + payload := m.WrapperUtil.ErrorResponseWrap(err.Error(), nil) + m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload) + return + } + + result, err := m.QuizService.GetQuizDetail(id) + + if err != nil { + respErr, ok := err.(web.ResponseError) + if ok { + payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr) + + m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload) + } else { + payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil) + m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload) + } + return + } + + responsePayload := m.WrapperUtil.SuccessResponseWrap(result) + m.HttpUtil.WriteSuccessJson(w, responsePayload) + +} diff --git a/handler/quiz/impl.go b/handler/quiz/impl.go new file mode 100644 index 0000000000000000000000000000000000000000..f95f7e5f0ca56fe2c605c5c3692eb5c4dab1008a --- /dev/null +++ b/handler/quiz/impl.go @@ -0,0 +1,15 @@ +package quiz + +import ( + "gitlab.informatika.org/ocw/ocw-backend/service/logger" + "gitlab.informatika.org/ocw/ocw-backend/service/quiz" + "gitlab.informatika.org/ocw/ocw-backend/utils/httputil" + "gitlab.informatika.org/ocw/ocw-backend/utils/wrapper" +) + +type QuizHandlerImpl struct { + quiz.QuizService + wrapper.WrapperUtil + httputil.HttpUtil + logger.Logger +} diff --git a/handler/quiz/list.go b/handler/quiz/list.go new file mode 100644 index 0000000000000000000000000000000000000000..544894fcc9985ee8ebea4f75fd3032da1ff0fd2d --- /dev/null +++ b/handler/quiz/list.go @@ -0,0 +1,50 @@ +package quiz + +import ( + "net/http" + + "github.com/go-chi/chi/v5" + "gitlab.informatika.org/ocw/ocw-backend/model/web" +) + +// Index godoc +// +// @Tags course +// @Summary Get Course quiz +// @Description Get all cours +// @Produce json +// @Accept json +// @Param id path string true "Course id" Format(uuid) +// @Success 200 {object} web.BaseResponse{data=[]quiz.Quiz} +// @Router /course/{id}/quiz [get] +func (m QuizHandlerImpl) GetAllQuizes(w http.ResponseWriter, r *http.Request) { + courseId := chi.URLParam(r, "id") + + if courseId == "" { + payload := m.WrapperUtil.ErrorResponseWrap("course id is required", nil) + m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload) + return + } + + result, err := m.QuizService.ListAllQuiz(courseId) + + if err != nil { + respErr, ok := err.(web.ResponseError) + if ok { + payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr) + + if respErr.Code != "NOT_OWNER" { + m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload) + } else { + m.HttpUtil.WriteJson(w, http.StatusForbidden, payload) + } + } else { + payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil) + m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload) + } + return + } + + responsePayload := m.WrapperUtil.SuccessResponseWrap(result) + m.HttpUtil.WriteSuccessJson(w, responsePayload) +} diff --git a/handler/quiz/type.go b/handler/quiz/type.go new file mode 100644 index 0000000000000000000000000000000000000000..2c9d3e03d76b678496942f6101f39a27b074d2a3 --- /dev/null +++ b/handler/quiz/type.go @@ -0,0 +1,8 @@ +package quiz + +import "net/http" + +type QuizHandler interface { + GetAllQuizes(w http.ResponseWriter, r *http.Request) + GetQuizDetail(w http.ResponseWriter, r *http.Request) +} diff --git a/model/domain/quiz/answer.go b/model/domain/quiz/answer.go new file mode 100644 index 0000000000000000000000000000000000000000..477b2039d253b51934420202f7e1c34adbb23dac --- /dev/null +++ b/model/domain/quiz/answer.go @@ -0,0 +1,8 @@ +package quiz + +import "github.com/google/uuid" + +type Answer struct { + QuestionId uuid.UUID + OptionId uuid.UUID +} diff --git a/model/domain/quiz/option.go b/model/domain/quiz/option.go new file mode 100644 index 0000000000000000000000000000000000000000..6f3af1fb082860285b9d141abb98245fe0d723f8 --- /dev/null +++ b/model/domain/quiz/option.go @@ -0,0 +1,9 @@ +package quiz + +import "github.com/google/uuid" + +type Option struct { + Id uuid.UUID `json:"id"` + Text string `json:"text"` + IsAnswer bool `json:"is_answer"` +} diff --git a/model/domain/quiz/options.go b/model/domain/quiz/options.go deleted file mode 100644 index d2bdddbf7da440ce8b48385cd7a5d5b0f118bcef..0000000000000000000000000000000000000000 --- a/model/domain/quiz/options.go +++ /dev/null @@ -1,14 +0,0 @@ -package quiz - -import "github.com/google/uuid" - -type AnswerOption struct { - Id uuid.UUID `gorm:"primaryKey" json:"id"` - QuizProblemId uuid.UUID `gorm:"primaryKey" json:"problem_id"` - Statement string `json:"statement"` - IsAnswer bool `json:"isAnswer"` -} - -func (AnswerOption) TableName() string { - return "quiz_choice_answer" -} diff --git a/model/domain/quiz/problem_type.go b/model/domain/quiz/problem_type.go deleted file mode 100644 index c03621526c635dc524f1caee1518665931b80d10..0000000000000000000000000000000000000000 --- a/model/domain/quiz/problem_type.go +++ /dev/null @@ -1,67 +0,0 @@ -package quiz - -import ( - "database/sql/driver" - "encoding/json" - "errors" - "fmt" -) - -type ProblemType int - -const ( - Choice ProblemType = iota -) - -var roleMapping = map[ProblemType]string{ - Choice: "choice", -} - -func (ur *ProblemType) Scan(value interface{}) error { - val := value.(string) - - for key, label := range roleMapping { - if label == val { - *ur = key - return nil - } - } - - return fmt.Errorf("invalid user role") -} - -func (u ProblemType) Value() (driver.Value, error) { - value, ok := roleMapping[u] - - if !ok { - return nil, fmt.Errorf("invalid user role") - } - - return value, nil -} - -func (u *ProblemType) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - - for key, label := range roleMapping { - if label == s { - *u = key - return nil - } - } - - return fmt.Errorf("unkown role, given %s", s) -} - -func (u ProblemType) MarshalJSON() ([]byte, error) { - s, ok := roleMapping[u] - - if !ok { - return nil, errors.New("unkown user role") - } - - return json.Marshal(s) -} diff --git a/model/domain/quiz/question.go b/model/domain/quiz/question.go new file mode 100644 index 0000000000000000000000000000000000000000..d8b5fdfea2ca012266489b05e2ced985cbdb75d2 --- /dev/null +++ b/model/domain/quiz/question.go @@ -0,0 +1,9 @@ +package quiz + +import "github.com/google/uuid" + +type Question struct { + Id uuid.UUID `json:"id"` + Description string `json:"string"` + Options []Option `json:"options"` +} diff --git a/model/domain/quiz/quiz.go b/model/domain/quiz/quiz.go index f4dcce5a8155d1c0a670dd962bd549233d95b2d8..1300dbc89fddcec83976bbaa726125d1e7a13e86 100644 --- a/model/domain/quiz/quiz.go +++ b/model/domain/quiz/quiz.go @@ -2,18 +2,14 @@ package quiz import ( "github.com/google/uuid" - "gitlab.informatika.org/ocw/ocw-backend/model/domain/course" - "gitlab.informatika.org/ocw/ocw-backend/model/domain/user" ) type Quiz struct { - Id uuid.UUID `gorm:"primaryKey" json:"id"` - Name string `json:"name"` - CourseId string `json:"course_id"` - CreatorEmail string `json:"creator_email"` - Creator user.User `gorm:"foreignKey:CreatorEmail;references:Email" json:"creator"` - Course course.Course `gorm:"foreignKey:CourseId;references:Id" json:"course"` - Problems []QuizProblem `gorm:"foreignKey:QuizId;references:Id" json:"problems"` + Id uuid.UUID `gorm:"primaryKey" json:"id"` + Name string `json:"name"` + CourseId string `json:"course_id"` + CreatorEmail string `json:"creator_email"` + QuizPath string `json:"-"` } func (Quiz) TableName() string { diff --git a/model/domain/quiz/quiz_problem.go b/model/domain/quiz/quiz_problem.go deleted file mode 100644 index 1bcdcf880ad9eaeeadd164cf60d253fd9eedb8db..0000000000000000000000000000000000000000 --- a/model/domain/quiz/quiz_problem.go +++ /dev/null @@ -1,15 +0,0 @@ -package quiz - -import "github.com/google/uuid" - -type QuizProblem struct { - Id uuid.UUID `gorm:"primaryKey" json:"id"` - Statement string `json:"statement"` - Type ProblemType `json:"type"` - QuizId uuid.UUID `json:"quiz_id"` - Options []AnswerOption `gorm:"foreignKey:QuizProblemId;references:Id" json:"options"` -} - -func (QuizProblem) TableName() string { - return "quiz_problem" -} diff --git a/model/domain/quiz/take.go b/model/domain/quiz/take.go index 2c707ab601da28e630420015393607aef0f9d228..399989d2db63432372643f615caecafee0cbc896 100644 --- a/model/domain/quiz/take.go +++ b/model/domain/quiz/take.go @@ -1,22 +1,18 @@ package quiz import ( - "os/user" "time" "github.com/google/uuid" ) type QuizTake struct { - Id uuid.UUID `gorm:"primaryKey" json:"id"` - QuizId uuid.UUID `json:"quiz_id"` - Email string `json:"email"` - StartTime time.Time `json:"start"` - IsFinished bool `json:"finished"` - Score int `json:"score"` - Quiz `gorm:"foreignKey:QuizId;references:Id" json:"quiz"` - user.User `gorm:"foreignKey:Email;references:Email" json:"user"` - ChoiceAnswers []TakeChoiceAnswer `gorm:"foreignKey:QuizTakeId;references:Id" json:"-"` + Id uuid.UUID `gorm:"primaryKey" json:"id"` + QuizId uuid.UUID `json:"quiz_id"` + Email string `json:"email"` + StartTime time.Time `json:"start"` + IsFinished bool `json:"finished"` + Score int `json:"score"` } func (QuizTake) TableName() string { diff --git a/model/domain/quiz/take_choice_answer.go b/model/domain/quiz/take_choice_answer.go deleted file mode 100644 index 25e76746d8951251d3dbdee694986205ce364d53..0000000000000000000000000000000000000000 --- a/model/domain/quiz/take_choice_answer.go +++ /dev/null @@ -1,14 +0,0 @@ -package quiz - -import "github.com/google/uuid" - -type TakeChoiceAnswer struct { - QuizTakeId uuid.UUID `gorm:"primaryKey"` - AnswerChoice uuid.UUID - QuizProblemId uuid.UUID `gorm:"primaryKey"` - AnswerOption `gorm:"foreignKey:AnswerChoice,QuizProblemId;references:Id,QuizProblemId"` -} - -func (TakeChoiceAnswer) TableName() string { - return "quiz_take_choice_answer" -} diff --git a/repository/di.go b/repository/di.go index 9136c031788ba4f56d8d3bfe4c46f2864b641571..b564bd5406f7d94427c5c0f80ccc518bc23fd5b2 100644 --- a/repository/di.go +++ b/repository/di.go @@ -2,12 +2,13 @@ package repository import ( "github.com/google/wire" - "gitlab.informatika.org/ocw/ocw-backend/repository/user" - "gitlab.informatika.org/ocw/ocw-backend/repository/course" "gitlab.informatika.org/ocw/ocw-backend/repository/cache" "gitlab.informatika.org/ocw/ocw-backend/repository/content" + "gitlab.informatika.org/ocw/ocw-backend/repository/course" "gitlab.informatika.org/ocw/ocw-backend/repository/material" + "gitlab.informatika.org/ocw/ocw-backend/repository/quiz" "gitlab.informatika.org/ocw/ocw-backend/repository/transaction" + "gitlab.informatika.org/ocw/ocw-backend/repository/user" ) var RepositoryBasicSet = wire.NewSet( @@ -37,6 +38,9 @@ var RepositoryBasicSet = wire.NewSet( transaction.NewBuilder, wire.Bind(new(transaction.Transaction), new(*transaction.TransactionRepositoryImpl)), wire.Bind(new(transaction.TransactionBuilder), new(*transaction.TransactionBuilderImpl)), + + quiz.New, + wire.Bind(new(quiz.QuizRepository), new(*quiz.QuizRepositoryImpl)), ) var RepositorySet = wire.NewSet( diff --git a/repository/quiz/impl.go b/repository/quiz/impl.go new file mode 100644 index 0000000000000000000000000000000000000000..03665df4d4915b3c188da6e737bed27e7dc1582d --- /dev/null +++ b/repository/quiz/impl.go @@ -0,0 +1,88 @@ +package quiz + +import ( + "errors" + "time" + + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz" + "gitlab.informatika.org/ocw/ocw-backend/model/web" + "gitlab.informatika.org/ocw/ocw-backend/provider/db" + "gorm.io/gorm" +) + +type QuizRepositoryImpl struct { + db *gorm.DB +} + +func New( + db db.Database, +) *QuizRepositoryImpl { + return &QuizRepositoryImpl{db.Connect()} +} + +func (q *QuizRepositoryImpl) GetQuizes(courseId string) ([]quiz.Quiz, error) { + result := &[]quiz.Quiz{} + err := q.db.Where("course_id = ?", courseId).Find(result).Error + + return *result, err +} + +func (q *QuizRepositoryImpl) GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error) { + result := &quiz.Quiz{} + err := q.db.Where("id = ?", quizId).First(result).Error + + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, web.NewResponseError("Record not found", "ERR_NOT_FOUND") + } + + return result, nil +} + +func (q *QuizRepositoryImpl) UpdateScore(takeId uuid.UUID, score int) error { + return q.db. + Model(&quiz.QuizTake{}). + Update("score", score). + Update("is_finished", true). + Where("id = ?", takeId).Error +} + +func (q *QuizRepositoryImpl) NewTake(quizId uuid.UUID, userEmail string) (uuid.UUID, error) { + id := uuid.New() + err := q.db.Create( + &quiz.QuizTake{ + Id: id, + Email: userEmail, + StartTime: time.Now(), + QuizId: quizId, + IsFinished: false, + Score: 0, + }, + ).Error + + return id, err +} + +func (q *QuizRepositoryImpl) IsActiveTake(quizId uuid.UUID, userEmail string) (bool, error) { + result := struct{ cnt int }{} + err := q.db. + Select("COUNT(*) as cnt"). + Where("quiz_id = ? AND email = ? AND is_finished = false", quizId, userEmail). + Find(result). + Error + + if err != nil { + return false, nil + } + + return result.cnt > 0, nil +} + +func (q *QuizRepositoryImpl) GetAllTake(quizId uuid.UUID, userEmail string) ([]quiz.QuizTake, error) { + result := []quiz.QuizTake{} + err := q.db. + Where("quiz_id = ? AND email = ?", quizId, userEmail). + Find(result).Error + + return result, err +} diff --git a/repository/quiz/type.go b/repository/quiz/type.go new file mode 100644 index 0000000000000000000000000000000000000000..0fc33d4d153ff2f8eabaea5cc9b44be16be724e7 --- /dev/null +++ b/repository/quiz/type.go @@ -0,0 +1,15 @@ +package quiz + +import ( + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz" +) + +type QuizRepository interface { + GetQuizes(courseId string) ([]quiz.Quiz, error) + GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error) + UpdateScore(takeId uuid.UUID, score int) error + NewTake(quizId uuid.UUID, userEmail string) (uuid.UUID, error) + IsActiveTake(quizId uuid.UUID, userEmail string) (bool, error) + GetAllTake(quizId uuid.UUID, userEmail string) ([]quiz.QuizTake, error) +} diff --git a/routes/di.go b/routes/di.go index e05148661337dd26d5400800ca389644f93aa3be..ddae40f95c5cde473aadc4f6d26a357c98b5f089 100644 --- a/routes/di.go +++ b/routes/di.go @@ -7,6 +7,7 @@ import ( "gitlab.informatika.org/ocw/ocw-backend/routes/common" "gitlab.informatika.org/ocw/ocw-backend/routes/course" "gitlab.informatika.org/ocw/ocw-backend/routes/material" + "gitlab.informatika.org/ocw/ocw-backend/routes/quiz" "gitlab.informatika.org/ocw/ocw-backend/routes/reset" "gitlab.informatika.org/ocw/ocw-backend/routes/swagger" ) @@ -19,6 +20,7 @@ var routesCollectionSet = wire.NewSet( wire.Struct(new(reset.ResetRoutes), "*"), wire.Struct(new(course.CourseRoutes), "*"), wire.Struct(new(material.MaterialRoutes), "*"), + wire.Struct(new(quiz.QuizRoutes), "*"), ) var RoutesSet = wire.NewSet( diff --git a/routes/quiz/route.go b/routes/quiz/route.go new file mode 100644 index 0000000000000000000000000000000000000000..58dbb0deb323c33a1138db79b8692b79aad0c5c0 --- /dev/null +++ b/routes/quiz/route.go @@ -0,0 +1,15 @@ +package quiz + +import ( + "github.com/go-chi/chi/v5" + "gitlab.informatika.org/ocw/ocw-backend/handler/quiz" +) + +type QuizRoutes struct { + quiz.QuizHandler +} + +func (q QuizRoutes) Register(r chi.Router) { + r.Get("/course/{id}/quiz", q.QuizHandler.GetAllQuizes) + r.Get("/quiz/{id}", q.QuizHandler.GetQuizDetail) +} diff --git a/routes/routes.go b/routes/routes.go index 63e1d79fb448d35384bc6f062d360cdb2a7a258f..096f4d5005e2bfe01f82bfe53552edc99b1d0258 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -6,6 +6,7 @@ import ( "gitlab.informatika.org/ocw/ocw-backend/routes/common" "gitlab.informatika.org/ocw/ocw-backend/routes/course" "gitlab.informatika.org/ocw/ocw-backend/routes/material" + "gitlab.informatika.org/ocw/ocw-backend/routes/quiz" "gitlab.informatika.org/ocw/ocw-backend/routes/reset" "gitlab.informatika.org/ocw/ocw-backend/routes/swagger" @@ -19,6 +20,7 @@ type AppRouter struct { common.CommonRoutes auth.AuthRoutes reset.ResetRoutes + quiz.QuizRoutes course.CourseRoutes material.MaterialRoutes diff --git a/service/di.go b/service/di.go index 6cdb051667f746ccdc3ff0244fd29bdf19f69561..3a133f5fc0ccdaba5c7260c52fa6a068306cf8a2 100644 --- a/service/di.go +++ b/service/di.go @@ -5,13 +5,14 @@ import ( "gitlab.informatika.org/ocw/ocw-backend/service/admin" "gitlab.informatika.org/ocw/ocw-backend/service/auth" "gitlab.informatika.org/ocw/ocw-backend/service/common" + "gitlab.informatika.org/ocw/ocw-backend/service/course" "gitlab.informatika.org/ocw/ocw-backend/service/logger" "gitlab.informatika.org/ocw/ocw-backend/service/logger/hooks" "gitlab.informatika.org/ocw/ocw-backend/service/material" + "gitlab.informatika.org/ocw/ocw-backend/service/quiz" "gitlab.informatika.org/ocw/ocw-backend/service/reporter" "gitlab.informatika.org/ocw/ocw-backend/service/reset" "gitlab.informatika.org/ocw/ocw-backend/service/verification" - "gitlab.informatika.org/ocw/ocw-backend/service/course" ) var ServiceTestSet = wire.NewSet( @@ -64,6 +65,12 @@ var ServiceTestSet = wire.NewSet( wire.Bind(new(material.MaterialContentService), new(*material.MaterialContentServiceImpl)), wire.Bind(new(material.MaterialService), new(*material.MaterialServiceImpl)), ), + + // Quiz service + wire.NewSet( + wire.Struct(new(quiz.QuizServiceImpl), "*"), + wire.Bind(new(quiz.QuizService), new(*quiz.QuizServiceImpl)), + ), ) var ServiceSet = wire.NewSet( diff --git a/service/quiz/impl.go b/service/quiz/impl.go new file mode 100644 index 0000000000000000000000000000000000000000..5bf6171e4d6fd4535810463b454f7bae90b93c9c --- /dev/null +++ b/service/quiz/impl.go @@ -0,0 +1,19 @@ +package quiz + +import ( + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz" + quizRepo "gitlab.informatika.org/ocw/ocw-backend/repository/quiz" +) + +type QuizServiceImpl struct { + quizRepo.QuizRepository +} + +func (q QuizServiceImpl) ListAllQuiz(courseId string) ([]quiz.Quiz, error) { + return q.QuizRepository.GetQuizes(courseId) +} + +func (q QuizServiceImpl) GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error) { + return q.QuizRepository.GetQuizDetail(quizId) +} diff --git a/service/quiz/type.go b/service/quiz/type.go new file mode 100644 index 0000000000000000000000000000000000000000..f7d0f72eb3a7a148c1e324a5ff800f99d38f5304 --- /dev/null +++ b/service/quiz/type.go @@ -0,0 +1,11 @@ +package quiz + +import ( + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz" +) + +type QuizService interface { + ListAllQuiz(courseId string) ([]quiz.Quiz, error) + GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error) +}