From 6f1eeceedfb2d9b6b7310f60a8131306e951647d Mon Sep 17 00:00:00 2001 From: bayusamudra5502 <bayusamudra.55.02.com@gmail.com> Date: Sun, 12 Mar 2023 19:00:20 +0700 Subject: [PATCH] feat: adding table --- .env | 5 +- .env.local.example | 11 ++++ .gitignore | 3 +- Makefile | 2 +- model/domain/course/course.go | 19 +++++++ model/domain/course/major.go | 12 +++++ model/domain/material/content.go | 14 +++++ model/domain/material/material.go | 20 +++++++ model/domain/material/material_type.go | 69 +++++++++++++++++++++++++ model/domain/quiz/options.go | 14 +++++ model/domain/quiz/problem_type.go | 67 ++++++++++++++++++++++++ model/domain/quiz/quiz.go | 21 ++++++++ model/domain/quiz/quiz_problem.go | 15 ++++++ model/domain/quiz/take.go | 24 +++++++++ model/domain/quiz/take_choice_answer.go | 14 +++++ provider/storage/s3.go | 4 +- utils/env/env.go | 22 ++++---- 17 files changed, 319 insertions(+), 17 deletions(-) create mode 100644 .env.local.example create mode 100644 model/domain/course/course.go create mode 100644 model/domain/course/major.go create mode 100644 model/domain/material/content.go create mode 100644 model/domain/material/material.go create mode 100644 model/domain/material/material_type.go create mode 100644 model/domain/quiz/options.go create mode 100644 model/domain/quiz/problem_type.go create mode 100644 model/domain/quiz/quiz.go create mode 100644 model/domain/quiz/quiz_problem.go create mode 100644 model/domain/quiz/take.go create mode 100644 model/domain/quiz/take_choice_answer.go diff --git a/.env b/.env index f0f1fec..43bf5fd 100644 --- a/.env +++ b/.env @@ -4,9 +4,6 @@ PORT=8080 LOGTAIL_TOKEN= HTTP_TIMEOUT_SEC=2 LOG_FLUSH_INTERVAL_MS=1000 -DB_STRING="host=localhost user=ocw password=ocw dbname=ocw-db port=5433 sslmode=disable TimeZone=Asia/Shanghai" SMTP_USERNAME="noreply@ocw.id" -SMTP_SERVER=localhost SMTP_PORT=1025 -REDIS_STRING="localhost" -FE_BASE_URL="http://localhost:3000" \ No newline at end of file +FE_BASE_URL="http://localhost:3000" diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..c251113 --- /dev/null +++ b/.env.local.example @@ -0,0 +1,11 @@ +# Sesuaikan dengan environment masing-masing +BUCKET_ENDPOINT="minio:9000" +BUCKET_SECRET_KEY="SUTT" +BUCKET_ACCESS_ID="ACCESS" +BUKET_TOKEN_KEY="" +BUCKET_USE_SSL=false +BUCKET_NAME="ocw" + +SMTP_SERVER=localhost +DB_STRING="host=localhost user=ocw password=ocw dbname=ocw-db port=5433 sslmode=disable TimeZone=Asia/Shanghai" +REDIS_STRING="localhost" diff --git a/.gitignore b/.gitignore index c5c1358..d3eeb07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bin/ tmp/ wire_gen.go -__debug_bin* \ No newline at end of file +__debug_bin* +.env.local diff --git a/Makefile b/Makefile index 9488716..961e188 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ build: dependency @go build -o=bin/server.app . watch: dependency - @air --build.cmd="make build" --build.bin="./bin/server.app" --build.exclude_dir="bin,tmp,docs" --build.exclude_file="wire_gen.go" + @air --build.cmd="make build" --build.bin="./bin/server.app" --build.exclude_dir="bin,tmp,docs" --build.exclude_file="wire_gen.go" --build.kill_delay="0s" test: test-dependency @go test ./test/... -v diff --git a/model/domain/course/course.go b/model/domain/course/course.go new file mode 100644 index 0000000..b80e0b4 --- /dev/null +++ b/model/domain/course/course.go @@ -0,0 +1,19 @@ +package course + +import ( + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/user" +) + +type Course struct { + Id string `gorm:"primaryKey"` + Name string + MajorId uuid.UUID + Description string + Major Major `gorm:"foreignKey:MajorId;references:Id"` + Contributors []user.User `gorm:"many2many:course_contributor;foreignKey:Id;joinForeignKey:CourseId;references:Email;joinReferences:Email"` +} + +func (Course) TableName() string { + return "course" +} diff --git a/model/domain/course/major.go b/model/domain/course/major.go new file mode 100644 index 0000000..7b19ab0 --- /dev/null +++ b/model/domain/course/major.go @@ -0,0 +1,12 @@ +package course + +import "github.com/google/uuid" + +type Major struct { + Id uuid.UUID `gorm:"type:uuid;primaryKey"` + Name string +} + +func (Major) TableName() string { + return "major" +} diff --git a/model/domain/material/content.go b/model/domain/material/content.go new file mode 100644 index 0000000..0e18104 --- /dev/null +++ b/model/domain/material/content.go @@ -0,0 +1,14 @@ +package material + +import "github.com/google/uuid" + +type Content struct { + Id uuid.UUID `gorm:"primaryKey"` + Type MaterialType + Link string + MaterialId uuid.UUID +} + +func (Content) TableName() string { + return "material_data" +} diff --git a/model/domain/material/material.go b/model/domain/material/material.go new file mode 100644 index 0000000..55d6bfb --- /dev/null +++ b/model/domain/material/material.go @@ -0,0 +1,20 @@ +package material + +import ( + "github.com/google/uuid" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/course" + "gitlab.informatika.org/ocw/ocw-backend/model/domain/user" +) + +type Material struct { + Id uuid.UUID `gorm:"primaryKey"` + CourseId string + CreatorEmail string + Creator user.User `gorm:"foreignKey:CreatorEmail;references:Email"` + Course course.Course `gorm:"foreignKey:CourseId;references:Id"` + Contents []Content `gorm:"foreignKey:MaterialId;references:Id"` +} + +func (Material) TableName() string { + return "material" +} diff --git a/model/domain/material/material_type.go b/model/domain/material/material_type.go new file mode 100644 index 0000000..a4ed9ba --- /dev/null +++ b/model/domain/material/material_type.go @@ -0,0 +1,69 @@ +package material + +import ( + "database/sql/driver" + "encoding/json" + "errors" + "fmt" +) + +type MaterialType int + +const ( + Video MaterialType = iota + Handout +) + +var roleMapping = map[MaterialType]string{ + Video: "video", + Handout: "handout", +} + +func (ur *MaterialType) 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 MaterialType) Value() (driver.Value, error) { + value, ok := roleMapping[u] + + if !ok { + return nil, fmt.Errorf("invalid user role") + } + + return value, nil +} + +func (u *MaterialType) 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 MaterialType) 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/options.go b/model/domain/quiz/options.go new file mode 100644 index 0000000..de062c3 --- /dev/null +++ b/model/domain/quiz/options.go @@ -0,0 +1,14 @@ +package quiz + +import "github.com/google/uuid" + +type AnswerOption struct { + Id uuid.UUID `gorm:"primaryKey"` + QuizProblemId uuid.UUID `gorm:"primaryKey"` + Statement string + IsAnswer bool +} + +func (AnswerOption) TableName() string { + return "quiz_choice_answer" +} diff --git a/model/domain/quiz/problem_type.go b/model/domain/quiz/problem_type.go new file mode 100644 index 0000000..c036215 --- /dev/null +++ b/model/domain/quiz/problem_type.go @@ -0,0 +1,67 @@ +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/quiz.go b/model/domain/quiz/quiz.go new file mode 100644 index 0000000..6caade4 --- /dev/null +++ b/model/domain/quiz/quiz.go @@ -0,0 +1,21 @@ +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"` + Name string + CourseId string + CreatorEmail string + Creator user.User `gorm:"foreignKey:CreatorEmail;references:Email"` + Course course.Course `gorm:"foreignKey:CourseId;references:Id"` + Problems []QuizProblem `gorm:"foreignKey:QuizId;references:Id"` +} + +func (Quiz) TableName() string { + return "quiz" +} diff --git a/model/domain/quiz/quiz_problem.go b/model/domain/quiz/quiz_problem.go new file mode 100644 index 0000000..3ce4195 --- /dev/null +++ b/model/domain/quiz/quiz_problem.go @@ -0,0 +1,15 @@ +package quiz + +import "github.com/google/uuid" + +type QuizProblem struct { + Id uuid.UUID `gorm:"primaryKey"` + Statement string + Type ProblemType + QuizId uuid.UUID + Options []AnswerOption `gorm:"foreignKey:QuizProblemId;references:Id"` +} + +func (QuizProblem) TableName() string { + return "quiz_problem" +} diff --git a/model/domain/quiz/take.go b/model/domain/quiz/take.go new file mode 100644 index 0000000..c66263f --- /dev/null +++ b/model/domain/quiz/take.go @@ -0,0 +1,24 @@ +package quiz + +import ( + "os/user" + "time" + + "github.com/google/uuid" +) + +type QuizTake struct { + Id uuid.UUID `gorm:"primaryKey"` + QuizId uuid.UUID + Email string + StartTime time.Time + IsFinished bool + Score int + Quiz `gorm:"foreignKey:QuizId;references:Id"` + user.User `gorm:"foreignKey:Email;references:Email"` + ChoiceAnswers []TakeChoiceAnswer `gorm:"foreignKey:QuizTakeId;references:Id"` +} + +func (QuizTake) TableName() string { + return "quiz_take" +} diff --git a/model/domain/quiz/take_choice_answer.go b/model/domain/quiz/take_choice_answer.go new file mode 100644 index 0000000..25e7674 --- /dev/null +++ b/model/domain/quiz/take_choice_answer.go @@ -0,0 +1,14 @@ +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/provider/storage/s3.go b/provider/storage/s3.go index 435b0bf..3f74671 100644 --- a/provider/storage/s3.go +++ b/provider/storage/s3.go @@ -15,8 +15,8 @@ func NewS3( env *env.Environment, ) (*S3Storage, error) { client, err := minio.New(env.BucketEndpoint, &minio.Options{ - Creds: credentials.NewStaticV4(env.BucketKeyId, env.BucketAccessKey, ""), - Secure: true, + Creds: credentials.NewStaticV4(env.BucketAccessKey, env.BucketSecretKey, env.BucketTokenKey), + Secure: env.BucketUseSSL, }) if err != nil { diff --git a/utils/env/env.go b/utils/env/env.go index 754b1eb..617338e 100644 --- a/utils/env/env.go +++ b/utils/env/env.go @@ -52,16 +52,17 @@ type Environment struct { RedisUseAuth bool `env:"REDIS_USE_AUTH" envDefault:"false"` RedisPrefixKey string `env:"REDIS_PREFIX_KEY" envDefault:"app:"` - BucketEndpoint string `env:"BUCKET_ENDPOINT"` - BucketAccessKey string `env:"BUCKET_ACCESS_KEY"` - BucketKeyId string `env:"BUCKET_KEY_ID"` - BucketUseSSL bool `env:"BUCKET_USE_SSL" envDefault:"true"` - BucketName string `env:"BUCKET_NAME"` + BucketEndpoint string `env:"BUCKET_ENDPOINT"` + BucketSecretKey string `env:"BUCKET_SECRET_KEY"` + BucketAccessKey string `env:"BUCKET_ACCESS_KEY"` + BucketTokenKey string `env:"BUCKET_TOKEN_KEY"` + BucketUseSSL bool `env:"BUCKET_USE_SSL" envDefault:"true"` + BucketName string `env:"BUCKET_NAME"` - BucketSignedPutDuration int64 `env:"BUCKET_SIGNED_PUT_DURATION_S" envDefault:"36000"` - BucketSignedGetDuration int64 `env:"BUCKET_SIGNED_GET_DURATION_S" envDefault:"1800"` + BucketSignedPutDuration int64 `env:"BUCKET_SIGNED_PUT_DURATION_S" envDefault:"36000"` + BucketSignedGetDuration int64 `env:"BUCKET_SIGNED_GET_DURATION_S" envDefault:"1800"` - BucketMaterialBasePath string `env:"BUCKET_MATERIAL_BASE_PATH" envDefault:"materials/"` + BucketMaterialBasePath string `env:"BUCKET_MATERIAL_BASE_PATH" envDefault:"materials/"` } func New() (*Environment, error) { @@ -83,7 +84,10 @@ func NewEnv() (*Environment, error) { } func NewDotEnv() (*Environment, error) { - err := godotenv.Load() + err := godotenv.Load( + ".env", + ".env.local", + ) if err != nil { return nil, err -- GitLab