first commit
This commit is contained in:
		
							
								
								
									
										8
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "editor.detectIndentation": false,
 | 
			
		||||
  "editor.tabSize": 2,
 | 
			
		||||
  "editor.formatOnSave": true,
 | 
			
		||||
  "diffEditor.codeLens": true,
 | 
			
		||||
  "files.autoSave": "afterDelay",
 | 
			
		||||
  "editor.wordWrap": "on"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
FUNCTION_NAME	=cslms-api
 | 
			
		||||
BUILD					=$(CURDIR)/build
 | 
			
		||||
BIN						=$(CURDIR)/bin
 | 
			
		||||
MAIN					=$(CURDIR)/cmd/main.go
 | 
			
		||||
BUCKET 				=AWS_BUCKET_NAME
 | 
			
		||||
REGION				=ap-northeast-2
 | 
			
		||||
ARCH					=amd64
 | 
			
		||||
PROD_ZIPFILE	=$(FUNCTION_NAME)-prod-linux-$(ARCH).zip
 | 
			
		||||
PROD_HANDLER 	=bootstrap
 | 
			
		||||
DEV_ZIPFILE		=$(FUNCTION_NAME)-dev-linux-$(ARCH).zip
 | 
			
		||||
DEV_HANDLER 	=bootstrap
 | 
			
		||||
 | 
			
		||||
default: help
 | 
			
		||||
 | 
			
		||||
swag: ## swagger docs
 | 
			
		||||
	@echo "\033[32mSwagger API Docs ...\033[0m"
 | 
			
		||||
	@swag init --parseDependency -g cmd/main.go
 | 
			
		||||
 | 
			
		||||
deps: ## install dependency
 | 
			
		||||
	@echo "\033[32mDependency ...\033[0m"
 | 
			
		||||
	@go install gorm.io/gorm
 | 
			
		||||
.PHONY: deps
 | 
			
		||||
 | 
			
		||||
env.local: ## copy env for local
 | 
			
		||||
	@cp configs/common.local configs/common.go
 | 
			
		||||
 | 
			
		||||
env.dev: ## copy env for development
 | 
			
		||||
	@cp configs/common.dev configs/common.go
 | 
			
		||||
 | 
			
		||||
env.prod: ## copy env for production
 | 
			
		||||
	@cp configs/common.prod configs/common.go
 | 
			
		||||
 | 
			
		||||
run: env.local ## run local
 | 
			
		||||
	@echo "\033[32mRunning ...\033[0m"
 | 
			
		||||
	@go run $(MAIN)
 | 
			
		||||
.PHONY: run
 | 
			
		||||
 | 
			
		||||
fmt: ## show formatting
 | 
			
		||||
	@echo "\033[32mfmt ...\033[0m"
 | 
			
		||||
	@gofmt -s -w . && go mod tidy
 | 
			
		||||
.PHONY: fmt
 | 
			
		||||
 | 
			
		||||
lint: fmt ## linting
 | 
			
		||||
	golangci-lint run ./...
 | 
			
		||||
 | 
			
		||||
build: deps ## build
 | 
			
		||||
	@echo "\033[32mBuilding ...\033[0m"
 | 
			
		||||
	@go build -o $(BIN) $(MAIN)
 | 
			
		||||
.PHONY: build
 | 
			
		||||
 | 
			
		||||
install: ## install
 | 
			
		||||
	@echo "\033[32mInstalling ...\033[0m"
 | 
			
		||||
	go install -v
 | 
			
		||||
.PHONY: install
 | 
			
		||||
 | 
			
		||||
test: ## testing
 | 
			
		||||
	@echo "\033[32mTesting...\033[0m"
 | 
			
		||||
	@go test ./... -v
 | 
			
		||||
	@echo "all tests passed"
 | 
			
		||||
.PHONY: test
 | 
			
		||||
 | 
			
		||||
build.local: env.local ## build for local
 | 
			
		||||
	@echo "\033[32mBuilding for Local running ...\033[0m"
 | 
			
		||||
	@go build -o $(BUILD)/main $(MAIN)
 | 
			
		||||
 | 
			
		||||
build.dev: env.dev ## build for development
 | 
			
		||||
	@echo "\033[32mBuilding for AWS Lamdbda Development ...\033[0m"
 | 
			
		||||
	@GOOS=linux GOARCH=$(ARCH) go build -o $(BUILD)/$(DEV_HANDLER) $(MAIN)
 | 
			
		||||
	@cd $(BUILD) && \
 | 
			
		||||
		zip -9 $(DEV_ZIPFILE) $(DEV_HANDLER)
 | 
			
		||||
 | 
			
		||||
build.prod: env.prod ## build for production
 | 
			
		||||
	@echo "\033[32mBuilding for AWS Lamdbda Production ...\033[0m"
 | 
			
		||||
	@GOOS=linux GOARCH=$(ARCH) go build -o $(BUILD)/$(PROD_HANDLER) $(MAIN)
 | 
			
		||||
	@cd $(BUILD) && \
 | 
			
		||||
		zip -9 $(PROD_ZIPFILE) $(PROD_HANDLER)
 | 
			
		||||
 | 
			
		||||
deploy.dev: build.dev lambda.deploy.dev ## deploy for development
 | 
			
		||||
deploy.prod: build.prod lambda.deploy.prod ## deploy for production
 | 
			
		||||
 | 
			
		||||
lambda.deploy.dev: ## copy to S3 & update lambda function for development
 | 
			
		||||
	@echo "\033[32mDistribution Development : copy to S3 & update lambda function ...\033[0m"
 | 
			
		||||
	@aws s3 cp $(BUILD)/$(DEV_ZIPFILE) s3://$(BUCKET)
 | 
			
		||||
	@aws lambda update-function-code \
 | 
			
		||||
		--function-name $(FUNCTION_NAME)-dev \
 | 
			
		||||
		--s3-bucket $(BUCKET) \
 | 
			
		||||
		--s3-key $(DEV_ZIPFILE) \
 | 
			
		||||
		--region $(REGION) \
 | 
			
		||||
	 &2> /dev/null
 | 
			
		||||
 | 
			
		||||
lambda.deploy.prod: ## copy to S3 & update lambda function for production
 | 
			
		||||
	@echo "\033[32mDistribution Prodction : copy to S3 & update lambda function ...\033[0m"
 | 
			
		||||
	@aws s3 cp $(BUILD)/$(PROD_ZIPFILE) s3://$(BUCKET)
 | 
			
		||||
	@aws lambda update-function-code \
 | 
			
		||||
		--function-name $(FUNCTION_NAME) \
 | 
			
		||||
		--s3-bucket $(BUCKET) \
 | 
			
		||||
		--s3-key $(PROD_ZIPFILE) \
 | 
			
		||||
		--region $(REGION) \
 | 
			
		||||
	 &2> /dev/null
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
docker.build.local: ## build docker for local running
 | 
			
		||||
	@echo "\033[32mDocker for local ...\033[0m"
 | 
			
		||||
	@docker compose -f docker/local/docker-compose.yml build --no-cache
 | 
			
		||||
	@docker compose -f docker/local/docker-compose.yml create
 | 
			
		||||
.PHONY: docker.build.local
 | 
			
		||||
 | 
			
		||||
docker.start.local: ## start docker for local
 | 
			
		||||
	@echo "\033[32mDocker start ...\033[0m"
 | 
			
		||||
	@docker compose -f docker/local/docker-compose.yml up -d
 | 
			
		||||
.PHONY: docker.start.local
 | 
			
		||||
 | 
			
		||||
docker.stop.local:    ## stop docker for local
 | 
			
		||||
	@echo "\033[32mDocker stop ...\033[0m"
 | 
			
		||||
	@docker compose -f docker/local/docker-compose.yml down
 | 
			
		||||
.PHONY: docker.stop.local
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
docker.build.dev: ## build docker for development
 | 
			
		||||
	@echo "\033[32mDocker for development ...\033[0m"
 | 
			
		||||
	@docker compose -f docker/dev/docker-compose.yml build --no-cache
 | 
			
		||||
	@docker compose -f docker/dev/docker-compose.yml create
 | 
			
		||||
.PHONY: docker.build.dev
 | 
			
		||||
 | 
			
		||||
docker.start.dev: ## start docker for development
 | 
			
		||||
	@echo "\033[32mDocker start for development...\033[0m"
 | 
			
		||||
	@docker compose -f docker/dev/docker-compose.yml up -d
 | 
			
		||||
.PHONY: docker.start.dev
 | 
			
		||||
 | 
			
		||||
docker.stop.dev: ## stop docker for development
 | 
			
		||||
	@echo "\033[32mDocker stop for development...\033[0m"
 | 
			
		||||
	@docker compose -f docker/dev/docker-compose.yml down
 | 
			
		||||
.PHONY: docker.stop.dev
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
docker.build.prod: ## build docker for production
 | 
			
		||||
	@echo "\033[32mDocker for production ...\033[0m"
 | 
			
		||||
	@docker compose -f docker/prod/docker-compose.yml build --no-cache
 | 
			
		||||
	@docker compose -f docker/prod/docker-compose.yml create
 | 
			
		||||
.PHONY: docker.build.prod
 | 
			
		||||
 | 
			
		||||
docker.start.prod: ## start docker for production
 | 
			
		||||
	@echo "\033[32mDocker start for production...\033[0m"
 | 
			
		||||
	@docker compose -f docker/prod/docker-compose.yml up -d
 | 
			
		||||
.PHONY: docker.start.prod
 | 
			
		||||
 | 
			
		||||
docker.stop.prod: ## stop docker for production
 | 
			
		||||
	@echo "\033[32mDocker stop for production...\033[0m"
 | 
			
		||||
	@docker compose -f docker/prod/docker-compose.yml down
 | 
			
		||||
.PHONY: docker.stop.prod
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
clean: ## clean
 | 
			
		||||
	@echo "\033[32mCleaning...\033[0m"
 | 
			
		||||
	@go clean
 | 
			
		||||
	@rm -rf $(BIN)/*
 | 
			
		||||
	@rm -rf $(BUILD)/*
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
 | 
			
		||||
help: ## Show help for each of the Makefile recipes.
 | 
			
		||||
	@grep -E '^[a-zA-Z0-9 -.]+:.*#'  $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
 | 
			
		||||
.PHONY: help
 | 
			
		||||
							
								
								
									
										45
									
								
								cmd/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								cmd/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	configs "learnsteam/cslms-api/configs"
 | 
			
		||||
	_ "learnsteam/cslms-api/docs"
 | 
			
		||||
	"learnsteam/cslms-api/internal/database"
 | 
			
		||||
	"learnsteam/cslms-api/internal/helpers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/routers"
 | 
			
		||||
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/apex/gateway"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// @title Learnsteam CodingSchool API
 | 
			
		||||
// @version 1.0
 | 
			
		||||
// @description Learnsteam CodingSchool API
 | 
			
		||||
 | 
			
		||||
// @contact.name Jay Sheen
 | 
			
		||||
// @contact.email sheen@jongyeob.com
 | 
			
		||||
 | 
			
		||||
// @securityDefinitions.apikey Bearer
 | 
			
		||||
// @in header
 | 
			
		||||
// @name Authorization
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	Init()
 | 
			
		||||
	Run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	database.Init()
 | 
			
		||||
	routers.Init()
 | 
			
		||||
 | 
			
		||||
	database.AutoMigrate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Run() {
 | 
			
		||||
	if helpers.InLambda() {
 | 
			
		||||
		log.Fatal(gateway.ListenAndServe(configs.PORT, routers.Router))
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Fatal(http.ListenAndServe(configs.PORT, routers.Router))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								configs/common.dev
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								configs/common.dev
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package config
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BASE_URL     = "https://cslms-api.jongyeob.com"
 | 
			
		||||
	PORT         = ":3030"
 | 
			
		||||
	DATABASE_URL = "root:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(learnsteam-quiz-db:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
 | 
			
		||||
	KAKAO_CLIENT_ID     = "986830"
 | 
			
		||||
	KAKAO_CLIENT_SECRET = "14f63a8e91c4e0fe88bc40e3ff348233"
 | 
			
		||||
 | 
			
		||||
	SECRET_KEY  = "GmhiMJuAIyF3jwkd97iODSoJoN3bIVkF"
 | 
			
		||||
	ACCESS_KEY  = "NQD9AXmpn13asz84oPf5Dyc9rhLyhmHp"
 | 
			
		||||
	REFRESH_KEY = "qFzFMlX2PfTSXgA9QPFltcNhJk1SVF0a"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										16
									
								
								configs/common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								configs/common.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
package config
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BASE_URL     = "http://localhost:3030"
 | 
			
		||||
	PORT         = ":3030"
 | 
			
		||||
	DATABASE_URL = "cslms:atobot2013!#%@tcp(localhost:33061)/cslms5?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
	//DATABASE_URL = "learnsteam:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(localhost:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
	//DATABASE_URL = "root:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(learnsteam-quiz-db:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
 | 
			
		||||
	KAKAO_CLIENT_ID     = "986830"
 | 
			
		||||
	KAKAO_CLIENT_SECRET = "14f63a8e91c4e0fe88bc40e3ff348233"
 | 
			
		||||
 | 
			
		||||
	SECRET_KEY  = "GmhiMJuAIyF3jwkd97iODSoJoN3bIVkF"
 | 
			
		||||
	ACCESS_KEY  = "NQD9AXmpn13asz84oPf5Dyc9rhLyhmHp"
 | 
			
		||||
	REFRESH_KEY = "qFzFMlX2PfTSXgA9QPFltcNhJk1SVF0a"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										16
									
								
								configs/common.local
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								configs/common.local
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
package config
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BASE_URL     = "http://localhost:3030"
 | 
			
		||||
	PORT         = ":3030"
 | 
			
		||||
	DATABASE_URL = "cslms:atobot2013!#%@tcp(localhost:33061)/cslms5?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
	//DATABASE_URL = "learnsteam:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(localhost:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
	//DATABASE_URL = "root:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(learnsteam-quiz-db:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
 | 
			
		||||
	KAKAO_CLIENT_ID     = "986830"
 | 
			
		||||
	KAKAO_CLIENT_SECRET = "14f63a8e91c4e0fe88bc40e3ff348233"
 | 
			
		||||
 | 
			
		||||
	SECRET_KEY  = "GmhiMJuAIyF3jwkd97iODSoJoN3bIVkF"
 | 
			
		||||
	ACCESS_KEY  = "NQD9AXmpn13asz84oPf5Dyc9rhLyhmHp"
 | 
			
		||||
	REFRESH_KEY = "qFzFMlX2PfTSXgA9QPFltcNhJk1SVF0a"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										14
									
								
								configs/common.prod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								configs/common.prod
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package config
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BASE_URL     = "https://cslms-api.jongyeob.com"
 | 
			
		||||
	PORT         = ":3030"
 | 
			
		||||
	DATABASE_URL = "root:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(learnsteam-quiz-db:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local"
 | 
			
		||||
 | 
			
		||||
	KAKAO_CLIENT_ID     = "986830"
 | 
			
		||||
	KAKAO_CLIENT_SECRET = "14f63a8e91c4e0fe88bc40e3ff348233"
 | 
			
		||||
 | 
			
		||||
	SECRET_KEY  = "GmhiMJuAIyF3jwkd97iODSoJoN3bIVkF"
 | 
			
		||||
	ACCESS_KEY  = "NQD9AXmpn13asz84oPf5Dyc9rhLyhmHp"
 | 
			
		||||
	REFRESH_KEY = "qFzFMlX2PfTSXgA9QPFltcNhJk1SVF0a"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										21
									
								
								docker/dev/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								docker/dev/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
# syntax=docker/dockerfile:1
 | 
			
		||||
 | 
			
		||||
FROM alpine:latest AS deps
 | 
			
		||||
RUN apk add --no-cache mariadb-dev sqlite-dev build-base go
 | 
			
		||||
 | 
			
		||||
FROM deps AS builder
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
COPY . .
 | 
			
		||||
RUN cp configs/common.dev configs/common.go
 | 
			
		||||
RUN go mod download && go mod verify
 | 
			
		||||
RUN CGO_ENABLED=1 go build -v -o bootstrap cmd/main.go
 | 
			
		||||
 | 
			
		||||
FROM alpine:latest AS runner
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
RUN apk add --no-cache sqlite-libs mariadb-connector-c libgcc
 | 
			
		||||
COPY --from=builder /app/bootstrap .
 | 
			
		||||
 | 
			
		||||
EXPOSE 3030
 | 
			
		||||
ENV PORT 3030
 | 
			
		||||
 | 
			
		||||
CMD ["sh", "-c", "./bootstrap"]
 | 
			
		||||
							
								
								
									
										10
									
								
								docker/dev/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								docker/dev/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
version: "3"
 | 
			
		||||
 | 
			
		||||
services:
 | 
			
		||||
  cslms-api:
 | 
			
		||||
    build:
 | 
			
		||||
      context: ../../
 | 
			
		||||
      dockerfile: docker/dev/Dockerfile
 | 
			
		||||
    image: learnsteam/cslms-api:dev
 | 
			
		||||
    ports:
 | 
			
		||||
      - "3030:3030"
 | 
			
		||||
							
								
								
									
										21
									
								
								docker/local/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								docker/local/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
# syntax=docker/dockerfile:1
 | 
			
		||||
 | 
			
		||||
FROM golang:alpine AS deps
 | 
			
		||||
RUN apk add --no-cache mariadb-dev sqlite-dev build-base
 | 
			
		||||
 | 
			
		||||
FROM deps AS builder
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
COPY . .
 | 
			
		||||
RUN cp configs/common.local configs/common.go
 | 
			
		||||
RUN go mod download && go mod verify
 | 
			
		||||
RUN CGO_ENABLED=1 go build -v -o bootstrap cmd/main.go
 | 
			
		||||
 | 
			
		||||
FROM alpine:latest AS runner
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
RUN apk add --no-cache sqlite-libs mariadb-connector-c libgcc
 | 
			
		||||
COPY --from=builder /app/bootstrap .
 | 
			
		||||
 | 
			
		||||
EXPOSE 3030
 | 
			
		||||
ENV PORT 3030
 | 
			
		||||
 | 
			
		||||
CMD ["sh", "-c", "./bootstrap"]
 | 
			
		||||
							
								
								
									
										10
									
								
								docker/local/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								docker/local/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
version: "3"
 | 
			
		||||
 | 
			
		||||
services:
 | 
			
		||||
  cslms-api:
 | 
			
		||||
    build:
 | 
			
		||||
      context: ../../
 | 
			
		||||
      dockerfile: docker/local/Dockerfile
 | 
			
		||||
    image: learnsteam/cslms-api:local
 | 
			
		||||
    ports:
 | 
			
		||||
      - "3030:3030"
 | 
			
		||||
							
								
								
									
										21
									
								
								docker/prod/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								docker/prod/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
# syntax=docker/dockerfile:1
 | 
			
		||||
 | 
			
		||||
FROM alpine:latest AS deps
 | 
			
		||||
RUN apk add --no-cache mariadb-dev sqlite-dev build-base go
 | 
			
		||||
 | 
			
		||||
FROM deps AS builder
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
COPY . .
 | 
			
		||||
RUN cp configs/common.prod configs/common.go
 | 
			
		||||
RUN go mod download && go mod verify
 | 
			
		||||
RUN CGO_ENABLED=1 go build -v -o bootstrap cmd/main.go
 | 
			
		||||
 | 
			
		||||
FROM alpine:latest AS runner
 | 
			
		||||
WORKDIR /app
 | 
			
		||||
RUN apk add --no-cache sqlite-libs mariadb-connector-c libgcc
 | 
			
		||||
COPY --from=builder /app/bootstrap .
 | 
			
		||||
 | 
			
		||||
EXPOSE 3030
 | 
			
		||||
ENV PORT 3030
 | 
			
		||||
 | 
			
		||||
CMD ["sh", "-c", "./bootstrap"]
 | 
			
		||||
							
								
								
									
										10
									
								
								docker/prod/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								docker/prod/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
version: "3"
 | 
			
		||||
 | 
			
		||||
services:
 | 
			
		||||
  cslms-api:
 | 
			
		||||
    build:
 | 
			
		||||
      context: ../../
 | 
			
		||||
      dockerfile: docker/prod/Dockerfile
 | 
			
		||||
    image: learnsteam/cslms-api
 | 
			
		||||
    ports:
 | 
			
		||||
      - "3030:3030"
 | 
			
		||||
							
								
								
									
										2092
									
								
								docs/docs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2092
									
								
								docs/docs.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2066
									
								
								docs/swagger.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2066
									
								
								docs/swagger.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1381
									
								
								docs/swagger.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1381
									
								
								docs/swagger.yaml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										66
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
module learnsteam/cslms-api
 | 
			
		||||
 | 
			
		||||
go 1.21
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/apex/gateway v1.1.2
 | 
			
		||||
	github.com/gin-contrib/cors v1.4.0
 | 
			
		||||
	github.com/golang-jwt/jwt/v5 v5.1.0
 | 
			
		||||
	github.com/google/uuid v1.4.0
 | 
			
		||||
	github.com/stretchr/testify v1.8.4
 | 
			
		||||
	github.com/swaggo/files v1.0.1
 | 
			
		||||
	github.com/swaggo/gin-swagger v1.6.0
 | 
			
		||||
	github.com/swaggo/swag v1.16.2
 | 
			
		||||
	golang.org/x/crypto v0.15.0
 | 
			
		||||
	gorm.io/datatypes v1.2.0
 | 
			
		||||
	gorm.io/driver/mysql v1.5.2
 | 
			
		||||
	gorm.io/gorm v1.25.5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/KyleBanks/depth v1.2.1 // indirect
 | 
			
		||||
	github.com/bytedance/sonic v1.10.2 // indirect
 | 
			
		||||
	github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
 | 
			
		||||
	github.com/chenzhuoyu/iasm v0.9.1 // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
			
		||||
	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
 | 
			
		||||
	github.com/gin-contrib/sse v0.1.0 // indirect
 | 
			
		||||
	github.com/go-openapi/jsonpointer v0.20.0 // indirect
 | 
			
		||||
	github.com/go-openapi/jsonreference v0.20.2 // indirect
 | 
			
		||||
	github.com/go-openapi/spec v0.20.9 // indirect
 | 
			
		||||
	github.com/go-openapi/swag v0.22.4 // indirect
 | 
			
		||||
	github.com/go-playground/locales v0.14.1 // indirect
 | 
			
		||||
	github.com/go-playground/universal-translator v0.18.1 // indirect
 | 
			
		||||
	github.com/go-playground/validator/v10 v10.16.0 // indirect
 | 
			
		||||
	github.com/go-sql-driver/mysql v1.7.0 // indirect
 | 
			
		||||
	github.com/goccy/go-json v0.10.2 // indirect
 | 
			
		||||
	github.com/google/go-cmp v0.5.9 // indirect
 | 
			
		||||
	github.com/jinzhu/inflection v1.0.0 // indirect
 | 
			
		||||
	github.com/jinzhu/now v1.1.5 // indirect
 | 
			
		||||
	github.com/josharian/intern v1.0.0 // indirect
 | 
			
		||||
	github.com/json-iterator/go v1.1.12 // indirect
 | 
			
		||||
	github.com/klauspost/cpuid/v2 v2.2.6 // indirect
 | 
			
		||||
	github.com/leodido/go-urn v1.2.4 // indirect
 | 
			
		||||
	github.com/mailru/easyjson v0.7.7 // indirect
 | 
			
		||||
	github.com/mattn/go-isatty v0.0.20 // indirect
 | 
			
		||||
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 | 
			
		||||
	github.com/modern-go/reflect2 v1.0.2 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml/v2 v2.1.0 // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
			
		||||
	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 | 
			
		||||
	github.com/ugorji/go/codec v1.2.11 // indirect
 | 
			
		||||
	golang.org/x/arch v0.6.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.18.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.14.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.14.0 // indirect
 | 
			
		||||
	golang.org/x/tools v0.15.0 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.31.0 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
			
		||||
	gorm.io/driver/sqlite v1.5.4 // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/aws/aws-lambda-go v1.17.0 // indirect
 | 
			
		||||
	github.com/gin-gonic/gin v1.9.1
 | 
			
		||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										250
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,250 @@
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
			
		||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 | 
			
		||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
 | 
			
		||||
github.com/apex/gateway v1.1.2 h1:OWyLov8eaau8YhkYKkRuOAYqiUhpBJalBR1o+3FzX+8=
 | 
			
		||||
github.com/apex/gateway v1.1.2/go.mod h1:AMTkVbz5u5Hvd6QOGhhg0JUrNgCcLVu3XNJOGntdoB4=
 | 
			
		||||
github.com/aws/aws-lambda-go v1.17.0 h1:Ogihmi8BnpmCNktKAGpNwSiILNNING1MiosnKUfU8m0=
 | 
			
		||||
github.com/aws/aws-lambda-go v1.17.0/go.mod h1:FEwgPLE6+8wcGBTe5cJN3JWurd1Ztm9zN4jsXsjzKKw=
 | 
			
		||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
 | 
			
		||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
 | 
			
		||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
 | 
			
		||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
 | 
			
		||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
 | 
			
		||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
 | 
			
		||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
 | 
			
		||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
 | 
			
		||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
 | 
			
		||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
 | 
			
		||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
 | 
			
		||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 | 
			
		||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
 | 
			
		||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
 | 
			
		||||
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
 | 
			
		||||
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
 | 
			
		||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
 | 
			
		||||
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
 | 
			
		||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 | 
			
		||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 | 
			
		||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
 | 
			
		||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
 | 
			
		||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
 | 
			
		||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 | 
			
		||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 | 
			
		||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
 | 
			
		||||
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
 | 
			
		||||
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
 | 
			
		||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
 | 
			
		||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
 | 
			
		||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
 | 
			
		||||
github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
 | 
			
		||||
github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
 | 
			
		||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 | 
			
		||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
 | 
			
		||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 | 
			
		||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
 | 
			
		||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 | 
			
		||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 | 
			
		||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 | 
			
		||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 | 
			
		||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
 | 
			
		||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 | 
			
		||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 | 
			
		||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 | 
			
		||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 | 
			
		||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 | 
			
		||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
 | 
			
		||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
 | 
			
		||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
 | 
			
		||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 | 
			
		||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 | 
			
		||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 | 
			
		||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 | 
			
		||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 | 
			
		||||
github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU=
 | 
			
		||||
github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 | 
			
		||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
 | 
			
		||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
 | 
			
		||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
 | 
			
		||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
 | 
			
		||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 | 
			
		||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
			
		||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 | 
			
		||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 | 
			
		||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
			
		||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
 | 
			
		||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
			
		||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 | 
			
		||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 | 
			
		||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
 | 
			
		||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
 | 
			
		||||
github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA=
 | 
			
		||||
github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
 | 
			
		||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 | 
			
		||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 | 
			
		||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 | 
			
		||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 | 
			
		||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 | 
			
		||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 | 
			
		||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 | 
			
		||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
 | 
			
		||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
 | 
			
		||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
			
		||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 | 
			
		||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
 | 
			
		||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 | 
			
		||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 | 
			
		||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
			
		||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
			
		||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 | 
			
		||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 | 
			
		||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 | 
			
		||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
 | 
			
		||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
 | 
			
		||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 | 
			
		||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 | 
			
		||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 | 
			
		||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 | 
			
		||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 | 
			
		||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 | 
			
		||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
 | 
			
		||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 | 
			
		||||
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
 | 
			
		||||
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
 | 
			
		||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
			
		||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 | 
			
		||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
			
		||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 | 
			
		||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 | 
			
		||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 | 
			
		||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
 | 
			
		||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
 | 
			
		||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 | 
			
		||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 | 
			
		||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 | 
			
		||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 | 
			
		||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 | 
			
		||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 | 
			
		||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 | 
			
		||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 | 
			
		||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
			
		||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 | 
			
		||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 | 
			
		||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 | 
			
		||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 | 
			
		||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 | 
			
		||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 | 
			
		||||
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
 | 
			
		||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
 | 
			
		||||
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
 | 
			
		||||
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
 | 
			
		||||
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
 | 
			
		||||
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
 | 
			
		||||
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
 | 
			
		||||
github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
 | 
			
		||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 | 
			
		||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 | 
			
		||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 | 
			
		||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
 | 
			
		||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
 | 
			
		||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 | 
			
		||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 | 
			
		||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 | 
			
		||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 | 
			
		||||
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
 | 
			
		||||
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 | 
			
		||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
 | 
			
		||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
 | 
			
		||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 | 
			
		||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
 | 
			
		||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 | 
			
		||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
			
		||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 | 
			
		||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 | 
			
		||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
 | 
			
		||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
 | 
			
		||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
 | 
			
		||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
			
		||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
			
		||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 | 
			
		||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 | 
			
		||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 | 
			
		||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
 | 
			
		||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
 | 
			
		||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
			
		||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 | 
			
		||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 | 
			
		||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
 | 
			
		||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 | 
			
		||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 | 
			
		||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco=
 | 
			
		||||
gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04=
 | 
			
		||||
gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
 | 
			
		||||
gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
 | 
			
		||||
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
 | 
			
		||||
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
 | 
			
		||||
gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0=
 | 
			
		||||
gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
 | 
			
		||||
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
 | 
			
		||||
gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
 | 
			
		||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 | 
			
		||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
 | 
			
		||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
 | 
			
		||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
 | 
			
		||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 | 
			
		||||
							
								
								
									
										122
									
								
								internal/controllers/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								internal/controllers/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthController interface {
 | 
			
		||||
	Register(*gin.Context)
 | 
			
		||||
	Login(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type authController struct {
 | 
			
		||||
	service      services.AuthService
 | 
			
		||||
	tokenService services.TokenService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAuthController(service services.AuthService, tokenService services.TokenService) AuthController {
 | 
			
		||||
	return &authController{
 | 
			
		||||
		service:      service,
 | 
			
		||||
		tokenService: tokenService,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Register
 | 
			
		||||
//
 | 
			
		||||
// @Summary     회원가입
 | 
			
		||||
// @Description  회원가입
 | 
			
		||||
// @Tags        회원가입
 | 
			
		||||
// @Accept      json
 | 
			
		||||
// @Produce      json
 | 
			
		||||
//
 | 
			
		||||
// @Param registerBody body models.RegisterRequest true "Register Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success      200    {object} models.RegisterResponse
 | 
			
		||||
// @Router        /auth/register [post]
 | 
			
		||||
func (controller *authController) Register(c *gin.Context) {
 | 
			
		||||
	var params models.RegisterRequest
 | 
			
		||||
	if c.BindJSON(¶ms) != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user, err := controller.service.Register(¶ms)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := controller.tokenService.Create(user.ID, user.UserRole)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"user": user, "token": token.Token, "refresh_token": token.RefreshToken})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Login 사용자 로그인
 | 
			
		||||
//
 | 
			
		||||
// @Summary       사용자 로그인 로그인
 | 
			
		||||
// @Description    사용자가 로그인합니다.
 | 
			
		||||
// @Tags          로그인
 | 
			
		||||
//
 | 
			
		||||
// @Accept        json
 | 
			
		||||
// @Produce        json
 | 
			
		||||
//
 | 
			
		||||
// @Param loginBody body models.LoginRequest true "Login Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success      200    {object} models.LoginResponse
 | 
			
		||||
// @Router        /auth/login [post]
 | 
			
		||||
func (controller *authController) Login(c *gin.Context) {
 | 
			
		||||
	var request models.LoginRequest
 | 
			
		||||
	if err := c.BindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user, err := controller.service.Login(&request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := controller.tokenService.Create(user.ID, user.UserRole)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{
 | 
			
		||||
		"user":          user,
 | 
			
		||||
		"token":         token.Token,
 | 
			
		||||
		"refresh_token": token.RefreshToken,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logout
 | 
			
		||||
func (controller *authController) Logout(c *gin.Context) {
 | 
			
		||||
	token := c.GetHeader("Authorization")
 | 
			
		||||
	if token == "" {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := controller.tokenService.Delete(token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.SetCookie("Authorization", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.SetCookie("RefreshToken", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.SetCookie("ExpiresAt", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.SetCookie("RefreshExpiresAt", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.SetCookie("RefreshTokenExpiresAt", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.SetCookie("RefreshTokenExpiresAt", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.SetCookie("RefreshTokenExpiresAt", "", -1, "/", "localhost", false, true)
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"message": "logout"})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								internal/controllers/center.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								internal/controllers/center.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CenterController interface {
 | 
			
		||||
	List(*gin.Context)
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
	Create(*gin.Context)
 | 
			
		||||
	Update(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type centerController struct {
 | 
			
		||||
	service      services.CenterService
 | 
			
		||||
	tokenService services.TokenService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCenterController(service services.CenterService, tokenService services.TokenService) CenterController {
 | 
			
		||||
	return ¢erController{
 | 
			
		||||
		service:      service,
 | 
			
		||||
		tokenService: tokenService,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Center List
 | 
			
		||||
//
 | 
			
		||||
// @Summary     센터 목록 가져오기
 | 
			
		||||
// @Description 센터 목록을 가져옵니다.
 | 
			
		||||
// @Tags        센터
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param q query string false "검색어"
 | 
			
		||||
// @Param page query int false "페이지"
 | 
			
		||||
// @Param limit query int false "페이지 사이즈"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.CenterListResponse
 | 
			
		||||
// @Router /center  [get]
 | 
			
		||||
func (controller *centerController) List(c *gin.Context) {
 | 
			
		||||
	q := c.DefaultQuery("q", "")
 | 
			
		||||
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : page")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : limit")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.List(q, page, limit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalNumber, err := controller.service.Total(q)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : list")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	totalPage := int64(totalNumber/int64(limit) + 1)
 | 
			
		||||
 | 
			
		||||
	response := models.CenterListResponse{
 | 
			
		||||
		Data:      *result,
 | 
			
		||||
		Total:     totalPage,
 | 
			
		||||
		Page:      page,
 | 
			
		||||
		TotalPage: totalPage,
 | 
			
		||||
		PageSize:  limit,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, response)
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get Center
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		센터 정보 가져오기
 | 
			
		||||
// @Description	ID로 센터 정보를 가져옵니다.
 | 
			
		||||
// @Tags        센터
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "센터 ID"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.Center
 | 
			
		||||
// @Router /center/{id} [get]
 | 
			
		||||
func (controller *centerController) Find(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create Center
 | 
			
		||||
//
 | 
			
		||||
// @Summary 센터 생성
 | 
			
		||||
// @Description 센터를 만듭니다.
 | 
			
		||||
// @Tags    센터
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param quizBody body models.CenterRequest true "Center Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.Center
 | 
			
		||||
// @Router /quiz [post]
 | 
			
		||||
func (controller *centerController) Create(c *gin.Context) {
 | 
			
		||||
	var request models.CenterRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	center := &models.Center{
 | 
			
		||||
		GUID:      uuid.NewString(),
 | 
			
		||||
		Title:     request.Title,
 | 
			
		||||
		Name:      request.Name,
 | 
			
		||||
		OwnerID:   request.OwnerID,
 | 
			
		||||
		Content:   request.Content,
 | 
			
		||||
		Info:      request.Info,
 | 
			
		||||
		Memo:      request.Memo,
 | 
			
		||||
		Status:    request.Status,
 | 
			
		||||
		UpdatedAt: time.Now(),
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Create(center)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update Center
 | 
			
		||||
//
 | 
			
		||||
// @Summary 센터 수정
 | 
			
		||||
// @Description 센터를 수정합니다.
 | 
			
		||||
// @Tags    센터
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path int64 true "Center ID"
 | 
			
		||||
// @Param centerBody body models.CenterRequest true "Center Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.Center
 | 
			
		||||
// @Router /center/{id} [put]
 | 
			
		||||
func (controller *centerController) Update(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.CenterRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	center, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	center.OwnerID = request.OwnerID
 | 
			
		||||
	center.Title = request.Title
 | 
			
		||||
	center.Name = request.Name
 | 
			
		||||
	center.Content = request.Content
 | 
			
		||||
	center.Info = request.Info
 | 
			
		||||
	center.Memo = request.Memo
 | 
			
		||||
	center.Status = request.Status
 | 
			
		||||
	center.UpdatedAt = time.Now()
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Update(center)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										243
									
								
								internal/controllers/quiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								internal/controllers/quiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,243 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"gorm.io/datatypes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type QuizController interface {
 | 
			
		||||
	List(*gin.Context)
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
	Create(*gin.Context)
 | 
			
		||||
	Update(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quizController struct {
 | 
			
		||||
	service services.QuizService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizController(service services.QuizService) QuizController {
 | 
			
		||||
	return &quizController{
 | 
			
		||||
		service: service,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Quiz List
 | 
			
		||||
//
 | 
			
		||||
// @Summary     퀴즈 목록 가져오기
 | 
			
		||||
// @Description 퀴즈 목록을 가져옵니다.
 | 
			
		||||
// @Tags        퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param quiz_paper_id query string true "퀴즈페이퍼 ID"
 | 
			
		||||
// @Param q query string false "검색어"
 | 
			
		||||
// @Param page query int false "페이지"
 | 
			
		||||
// @Param limit query int false "페이지 사이즈"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizListResponse
 | 
			
		||||
// @Router /quiz  [get]
 | 
			
		||||
func (controller *quizController) List(c *gin.Context) {
 | 
			
		||||
	quiz_paper_id, err := strconv.ParseInt(c.DefaultQuery("quiz_paper_id", ""), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : page")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : limit")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.List(quiz_paper_id, page, limit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalNumber, err := controller.service.Total(quiz_paper_id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : list")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	totalPage := int64(totalNumber/int64(limit) + 1)
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"data": result, "total": totalNumber, "page": page, "totalPage": totalPage, "pageSize": limit})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get Quiz
 | 
			
		||||
//
 | 
			
		||||
// @Summary 퀴즈 가져오기
 | 
			
		||||
// @Description ID로 퀴즈를 가져옵니다.
 | 
			
		||||
// @Tags    퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "퀴즈 ID"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizResponse
 | 
			
		||||
// @Router /quiz/{id} [get]
 | 
			
		||||
func (controller *quizController) Find(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create Quiz
 | 
			
		||||
//
 | 
			
		||||
// @Summary 퀴즈 생성
 | 
			
		||||
// @Description 퀴즈를 만듭니다.
 | 
			
		||||
// @Tags    퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param quizBody body models.QuizRequest true "Quiz Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizResponse
 | 
			
		||||
// @Router /quiz [post]
 | 
			
		||||
func (controller *quizController) Create(c *gin.Context) {
 | 
			
		||||
	var request models.QuizRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var content datatypes.JSON
 | 
			
		||||
	content, err := json.Marshal(request.Content)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var answer datatypes.JSON
 | 
			
		||||
	answer, err = json.Marshal(request.Answer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quiz := &models.Quiz{
 | 
			
		||||
		GUID:         uuid.NewString(),
 | 
			
		||||
		CenterID:     request.CenterID,
 | 
			
		||||
		QuizPaperID:  request.QuizPaperID,
 | 
			
		||||
		No:           request.No,
 | 
			
		||||
		QuestionType: request.QuestionType,
 | 
			
		||||
		Question:     request.Question,
 | 
			
		||||
		Content:      content,
 | 
			
		||||
		Answer:       answer,
 | 
			
		||||
		UpdatedAt:    time.Now(),
 | 
			
		||||
		CreatedAt:    time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Create(quiz)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update Quiz
 | 
			
		||||
//
 | 
			
		||||
// @Summary 퀴즈 수정
 | 
			
		||||
// @Description 퀴즈를 수정합니다.
 | 
			
		||||
// @Tags    퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path int64 true "Quiz ID"
 | 
			
		||||
// @Param quizBody body models.QuizRequest true "Quiz Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizResponse
 | 
			
		||||
// @Router /quiz/{id} [put]
 | 
			
		||||
func (controller *quizController) Update(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.QuizRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quiz, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var content datatypes.JSON
 | 
			
		||||
	content, err = json.Marshal(request.Content)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var answer datatypes.JSON
 | 
			
		||||
	answer, err = json.Marshal(request.Answer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quiz.QuizPaperID = request.QuizPaperID
 | 
			
		||||
	quiz.No = request.No
 | 
			
		||||
	quiz.QuestionType = request.QuestionType
 | 
			
		||||
	quiz.Question = request.Question
 | 
			
		||||
	quiz.Content = content
 | 
			
		||||
	quiz.Answer = answer
 | 
			
		||||
	quiz.UpdatedAt = time.Now()
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Update(quiz)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										314
									
								
								internal/controllers/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								internal/controllers/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,314 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type QuizPaperController interface {
 | 
			
		||||
	List(*gin.Context)
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
	Create(*gin.Context)
 | 
			
		||||
	Update(*gin.Context)
 | 
			
		||||
	Copy(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quizPaperController struct {
 | 
			
		||||
	service     services.QuizPaperService
 | 
			
		||||
	quizService services.QuizService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizPaperController(service services.QuizPaperService, quizService services.QuizService) QuizPaperController {
 | 
			
		||||
	return &quizPaperController{
 | 
			
		||||
		service:     service,
 | 
			
		||||
		quizService: quizService,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QuizPaper List
 | 
			
		||||
//
 | 
			
		||||
// @Summary			퀴즈페이퍼 목록 가져오기
 | 
			
		||||
// @Description	퀴즈페이퍼 목록을 가져옵니다.
 | 
			
		||||
// @Tags        퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param tag query string false "태그"
 | 
			
		||||
// @Param q query string false "검색어"
 | 
			
		||||
// @Param page query int false "페이지"
 | 
			
		||||
// @Param limit query int false "페이지 사이즈"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizPaperListResponse
 | 
			
		||||
// @Router /quizpaper  [get]
 | 
			
		||||
func (controller *quizPaperController) List(c *gin.Context) {
 | 
			
		||||
	tag := c.DefaultQuery("tag", "")
 | 
			
		||||
	q := c.DefaultQuery("q", "")
 | 
			
		||||
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : page")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : limit")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.List(q, tag, page, limit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalNumber, err := controller.service.Total(q, tag)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : list")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	totalPage := int64(totalNumber/int64(limit) + 1)
 | 
			
		||||
 | 
			
		||||
	response := models.QuizPaperListResponse{
 | 
			
		||||
		Data:      *result,
 | 
			
		||||
		Total:     totalPage,
 | 
			
		||||
		Page:      page,
 | 
			
		||||
		TotalPage: totalPage,
 | 
			
		||||
		PageSize:  limit,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get quizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		퀴즈 퀴즈페이퍼 가져오기
 | 
			
		||||
// @Description	ID로 퀴즈 퀴즈페이퍼을 가져옵니다.
 | 
			
		||||
// @Tags        퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "퀴즈 퀴즈페이퍼 ID"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizPaperResponse
 | 
			
		||||
// @Router /quizpaper/{id} [get]
 | 
			
		||||
func (controller *quizPaperController) Find(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create QuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		퀴즈 퀴즈페이퍼 생성
 | 
			
		||||
// @Description	퀴즈 퀴즈페이퍼을 만듭니다.
 | 
			
		||||
// @Tags        퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param quizPaperBody body models.QuizPaperRequest true "QuizPaper Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizPaperResponse
 | 
			
		||||
// @Router /quizpaper [post]
 | 
			
		||||
func (controller *quizPaperController) Create(c *gin.Context) {
 | 
			
		||||
	var request models.QuizPaperRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user_id := c.GetInt64("sub")
 | 
			
		||||
 | 
			
		||||
	quizPaper := &models.QuizPaper{
 | 
			
		||||
		GUID:      uuid.NewString(),
 | 
			
		||||
		CenterID:  request.CenterID,
 | 
			
		||||
		ManagerID: user_id,
 | 
			
		||||
		Title:     request.Title,
 | 
			
		||||
		Content:   request.Content,
 | 
			
		||||
		Category:  request.Category,
 | 
			
		||||
		Tag:       request.Tag,
 | 
			
		||||
		Status:    request.Status,
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
		UpdatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Create(quizPaper)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update QuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary			퀴즈 퀴즈페이퍼 수정
 | 
			
		||||
// @Description 퀴즈 퀴즈페이퍼을 수정합니다.
 | 
			
		||||
// @Tags        퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "퀴즈 퀴즈페이퍼 ID"
 | 
			
		||||
// @Param quizPaperUpdateBody body models.QuizPaperRequest true "QuizPaper Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizPaperResponse
 | 
			
		||||
// @Router /quizpaper/{id} [put]
 | 
			
		||||
func (controller *quizPaperController) Update(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.QuizPaperRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quizPaper, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user_id := c.GetInt64("sub")
 | 
			
		||||
	quizPaper.ManagerID = user_id
 | 
			
		||||
	quizPaper.CenterID = request.CenterID
 | 
			
		||||
	quizPaper.Title = request.Title
 | 
			
		||||
	quizPaper.Content = request.Content
 | 
			
		||||
	quizPaper.Category = request.Category
 | 
			
		||||
	quizPaper.Tag = request.Tag
 | 
			
		||||
	quizPaper.Status = request.Status
 | 
			
		||||
	quizPaper.UpdatedAt = time.Now()
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Update(quizPaper)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy QuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary			퀴즈 퀴즈페이퍼 복사
 | 
			
		||||
// @Description 퀴즈 퀴즈페이퍼와 퀴즈를 복사합니다.
 | 
			
		||||
// @Tags        퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "퀴즈페이퍼 ID"
 | 
			
		||||
// @Param quizPaperCopyBody body models.QuizPaperCopyRequest true "QuizPaper Copy Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.QuizPaperCopyResponse
 | 
			
		||||
// @Router /quizpaper/{id}/copy [post]
 | 
			
		||||
func (controller *quizPaperController) Copy(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	fmt.Println("id : ", c.Param("id"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("id convert err")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.QuizPaperCopyRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		fmt.Println("req err")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user_id := c.GetInt64("sub")
 | 
			
		||||
	template, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newQuizPaper := &models.QuizPaper{
 | 
			
		||||
		GUID:      uuid.NewString(),
 | 
			
		||||
		CenterID:  request.CenterID,
 | 
			
		||||
		ManagerID: user_id,
 | 
			
		||||
		Title:     request.Title,
 | 
			
		||||
		Content:   template.Content,
 | 
			
		||||
		Category:  template.Category,
 | 
			
		||||
		Tag:       template.Tag,
 | 
			
		||||
		Status:    template.Status,
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
		UpdatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quizPaper, err := controller.service.Create(newQuizPaper)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quizTemplates, err := controller.quizService.List(id, 1, 10000)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// iterate quizTemplate
 | 
			
		||||
	var quizzes []*models.Quiz
 | 
			
		||||
	for _, quiz := range *quizTemplates {
 | 
			
		||||
		newQuiz := &models.Quiz{
 | 
			
		||||
			GUID:         uuid.NewString(),
 | 
			
		||||
			CenterID:     request.CenterID,
 | 
			
		||||
			QuizPaperID:  quizPaper.ID,
 | 
			
		||||
			No:           quiz.No,
 | 
			
		||||
			QuestionType: quiz.QuestionType,
 | 
			
		||||
			Question:     quiz.Question,
 | 
			
		||||
			Content:      quiz.Content,
 | 
			
		||||
			Answer:       quiz.Answer,
 | 
			
		||||
			UpdatedAt:    time.Now(),
 | 
			
		||||
			CreatedAt:    time.Now(),
 | 
			
		||||
		}
 | 
			
		||||
		result, err := controller.quizService.Create(newQuiz)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		quizzes = append(quizzes, result)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"quiz_paper": quizPaper, "quiz": quizzes})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								internal/controllers/swagger.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								internal/controllers/swagger.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SwaggerController interface {
 | 
			
		||||
	Get(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type swaggerController struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSwaggerController() SwaggerController {
 | 
			
		||||
	return &swaggerController{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (controller *swaggerController) Get(c *gin.Context) {
 | 
			
		||||
	c.Redirect(http.StatusFound, "/swagger/index.html")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								internal/controllers/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								internal/controllers/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TokenController interface {
 | 
			
		||||
	Refresh(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tokenController struct {
 | 
			
		||||
	service services.TokenService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenController(service services.TokenService) TokenController {
 | 
			
		||||
	return &tokenController{
 | 
			
		||||
		service: service,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Refresh Token
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		AccessToken Refresh
 | 
			
		||||
// @Description	AccessToken을 RefreshToken으로 갱신합니다.
 | 
			
		||||
// @Tags 				Token
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Param refresh_token body string true "RefreshToken"
 | 
			
		||||
//
 | 
			
		||||
// @Router /token/refresh [post]
 | 
			
		||||
// @Success 200 {object} models.Token
 | 
			
		||||
func (controller *tokenController) Refresh(c *gin.Context) {
 | 
			
		||||
	var request models.RefreshTokenRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Refresh(request.RefreshToken)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										131
									
								
								internal/controllers/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								internal/controllers/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserController interface {
 | 
			
		||||
	List(*gin.Context)
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userController struct {
 | 
			
		||||
	service      services.UserService
 | 
			
		||||
	tokenService services.TokenService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserController(service services.UserService, tokenService services.TokenService) UserController {
 | 
			
		||||
	return &userController{
 | 
			
		||||
		service:      service,
 | 
			
		||||
		tokenService: tokenService,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// User List
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		사용자 목록 가져오기
 | 
			
		||||
// @Description 사용자 목록을 가져옵니다.
 | 
			
		||||
// @Tags        사용자
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param q query string false "검색어"
 | 
			
		||||
// @Param page query int false "페이지"
 | 
			
		||||
// @Param limit query int false "페이지 사이즈"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserListResponse
 | 
			
		||||
// @Router /user  [get]
 | 
			
		||||
func (controller *userController) List(c *gin.Context) {
 | 
			
		||||
	q := c.DefaultQuery("q", "")
 | 
			
		||||
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : page")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : limit")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.List(q, page, limit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalNumber, err := controller.service.Total(q)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : list")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	totalPage := int64(totalNumber/int64(limit) + 1)
 | 
			
		||||
 | 
			
		||||
	response := models.UserListResponse{
 | 
			
		||||
		Data:      *result,
 | 
			
		||||
		Total:     totalPage,
 | 
			
		||||
		Page:      page,
 | 
			
		||||
		TotalPage: totalPage,
 | 
			
		||||
		PageSize:  limit,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, response)
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get User
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		사용자 정보 가져오기
 | 
			
		||||
// @Description	ID로 사용자 정보를 가져옵니다.
 | 
			
		||||
// @Tags        사용자
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "사용자 ID"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.User
 | 
			
		||||
// @Router /user/{id} [get]
 | 
			
		||||
func (controller *userController) Find(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sub := c.GetString("sub")
 | 
			
		||||
	user_id, err := strconv.ParseInt(sub, 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if user_id != id {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "Wrong user"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										236
									
								
								internal/controllers/userquiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								internal/controllers/userquiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,236 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"gorm.io/datatypes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserQuizController interface {
 | 
			
		||||
	List(*gin.Context)
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
	Create(*gin.Context)
 | 
			
		||||
	Update(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userQuizController struct {
 | 
			
		||||
	service services.UserQuizService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizController(service services.UserQuizService) QuizController {
 | 
			
		||||
	return &userQuizController{
 | 
			
		||||
		service: service,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UserQuiz List
 | 
			
		||||
//
 | 
			
		||||
// @Summary     사용자퀴즈 목록 가져오기
 | 
			
		||||
// @Description 사용자퀴즈 목록을 가져옵니다.
 | 
			
		||||
// @Tags        사용자퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param user_quiz_paper_id query string true "사용자퀴즈페이퍼 ID"
 | 
			
		||||
// @Param q query string false "검색어"
 | 
			
		||||
// @Param page query int false "페이지"
 | 
			
		||||
// @Param limit query int false "페이지 사이즈"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizListResponse
 | 
			
		||||
// @Router /userquiz  [get]
 | 
			
		||||
func (controller *userQuizController) List(c *gin.Context) {
 | 
			
		||||
	quiz_paper_id, err := strconv.ParseInt(c.DefaultQuery("user_quiz_paper_id", ""), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : page")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : limit")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.List(quiz_paper_id, page, limit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalNumber, err := controller.service.Total(quiz_paper_id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : list")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	totalPage := int64(totalNumber/int64(limit) + 1)
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"data": result, "total": totalNumber, "page": page, "totalPage": totalPage, "pageSize": limit})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get UserQuiz
 | 
			
		||||
//
 | 
			
		||||
// @Summary     사용자퀴즈 가져오기
 | 
			
		||||
// @Description ID로 사용자퀴즈를 가져옵니다.
 | 
			
		||||
// @Tags        사용자퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "사용자퀴즈 ID"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizResponse
 | 
			
		||||
// @Router /userquiz/{id} [get]
 | 
			
		||||
func (controller *userQuizController) Find(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create Quiz
 | 
			
		||||
//
 | 
			
		||||
// @Summary     사용자퀴즈 생성
 | 
			
		||||
// @Description 사용자퀴즈를 만듭니다.
 | 
			
		||||
// @Tags        사용자퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param quizBody body models.UserQuizRequest true "UserQuiz Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizResponse
 | 
			
		||||
// @Router /userquiz [post]
 | 
			
		||||
func (controller *userQuizController) Create(c *gin.Context) {
 | 
			
		||||
	var request models.UserQuizRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var content datatypes.JSON
 | 
			
		||||
	content, err := json.Marshal(request.Content)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var answer datatypes.JSON
 | 
			
		||||
	answer, err = json.Marshal([]string{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quiz := &models.UserQuiz{
 | 
			
		||||
		GUID:            uuid.NewString(),
 | 
			
		||||
		CenterID:        request.CenterID,
 | 
			
		||||
		UserQuizPaperID: request.UserQuizPaperID,
 | 
			
		||||
		No:              request.No,
 | 
			
		||||
		QuestionType:    request.QuestionType,
 | 
			
		||||
		Question:        request.Question,
 | 
			
		||||
		Content:         content,
 | 
			
		||||
		Answer:          answer,
 | 
			
		||||
		UpdatedAt:       time.Now(),
 | 
			
		||||
		CreatedAt:       time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Create(quiz)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update Quiz
 | 
			
		||||
//
 | 
			
		||||
// @Summary 사용자퀴즈 수정
 | 
			
		||||
// @Description 사용자퀴즈를 수정합니다.
 | 
			
		||||
// @Tags    사용자퀴즈
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path int64 true "Quiz ID"
 | 
			
		||||
// @Param quizBody body models.UserQuizRequest true "Quiz Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizResponse
 | 
			
		||||
// @Router /userquiz/{id} [put]
 | 
			
		||||
func (controller *userQuizController) Update(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.UserQuizRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userquiz, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 	CenterID        int64          `json:"center_id" example:"1000001"`
 | 
			
		||||
	// UserQuizPaperID int64          `json:"quiz_paper_id" example:"1000001"`
 | 
			
		||||
	// UserID          int64          `json:"user_id" example:"1000001"`
 | 
			
		||||
	// No              int            `json:"vol_no" example:"1"`
 | 
			
		||||
	// QuestionType    string         `json:"question_type" example:"choice"`
 | 
			
		||||
	// Question        string         `json:"question" example:"질문입니다."`
 | 
			
		||||
	// Content         datatypes.JSON `json:"content"`
 | 
			
		||||
	// Answer          datatypes.JSON `json:"answer"`
 | 
			
		||||
	// Status          string         `json:"status" example:"waiting"`
 | 
			
		||||
	// Result          string         `json:"result" example:"success"`
 | 
			
		||||
	// Score           float32        `json:"score" example:"10"`
 | 
			
		||||
 | 
			
		||||
	userquiz.CenterID = request.CenterID
 | 
			
		||||
	userquiz.UserQuizPaperID = request.UserQuizPaperID
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Update(userquiz)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										331
									
								
								internal/controllers/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								internal/controllers/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,331 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperController interface {
 | 
			
		||||
	List(*gin.Context)
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
	Create(*gin.Context)
 | 
			
		||||
	Update(*gin.Context)
 | 
			
		||||
	Patch(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userQuizPaperController struct {
 | 
			
		||||
	service          services.UserQuizPaperService
 | 
			
		||||
	userService      services.UserService
 | 
			
		||||
	quizPaperService services.QuizPaperService
 | 
			
		||||
	userQuizService  services.UserQuizService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizPaperController(
 | 
			
		||||
	service services.UserQuizPaperService,
 | 
			
		||||
	userService services.UserService,
 | 
			
		||||
	quizPaperService services.QuizPaperService,
 | 
			
		||||
	userQuizService services.UserQuizService,
 | 
			
		||||
) UserQuizPaperController {
 | 
			
		||||
	return &userQuizPaperController{
 | 
			
		||||
		service:          service,
 | 
			
		||||
		userService:      userService,
 | 
			
		||||
		quizPaperService: quizPaperService,
 | 
			
		||||
		userQuizService:  userQuizService,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UserQuizPaper List
 | 
			
		||||
//
 | 
			
		||||
// @Summary			응시 목록 가져오기
 | 
			
		||||
// @Description	응시 목록을 가져옵니다.
 | 
			
		||||
// @Tags        사용자퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param q query string false "검색어"
 | 
			
		||||
// @Param page query int false "페이지"
 | 
			
		||||
// @Param limit query int false "페이지 사이즈"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizPaperListResponse
 | 
			
		||||
// @Router /userquizpaper  [get]
 | 
			
		||||
func (controller *userQuizPaperController) List(c *gin.Context) {
 | 
			
		||||
	q := c.DefaultQuery("q", "")
 | 
			
		||||
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : page")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	limit, err := strconv.Atoi(c.DefaultQuery("limit", "10"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : limit")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.List(q, page, limit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	totalNumber, err := controller.service.Total(q)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error : list")
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	totalPage := int64(totalNumber/int64(limit) + 1)
 | 
			
		||||
 | 
			
		||||
	response := models.UserQuizPaperListResponse{
 | 
			
		||||
		Data:      *result,
 | 
			
		||||
		Total:     totalNumber,
 | 
			
		||||
		Page:      page,
 | 
			
		||||
		TotalPage: totalPage,
 | 
			
		||||
		PageSize:  limit,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, response)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get userQuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		응시 정보 가져오기
 | 
			
		||||
// @Description	ID로 응시 정보를 가져옵니다.
 | 
			
		||||
// @Tags        사용자퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path string true "응시 ID"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizPaperResponse
 | 
			
		||||
// @Router /userquizpaper/{id} [get]
 | 
			
		||||
func (controller *userQuizPaperController) Find(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create UserQuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary 		응시 매칭 생성
 | 
			
		||||
// @Description	응시 매칭을 만듭니다.
 | 
			
		||||
// @Tags        사용자퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param userQuizPaperBody body models.UserQuizPaperRequest true "UserQuizPaper Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} []models.UserQuizPaper
 | 
			
		||||
// @Router /userquizpaper [post]
 | 
			
		||||
func (controller *userQuizPaperController) Create(c *gin.Context) {
 | 
			
		||||
	var request models.UserQuizPaperRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("users", request.Users)
 | 
			
		||||
 | 
			
		||||
	quizPaper, err := controller.quizPaperService.Find(request.QuizPaperID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var users []int64
 | 
			
		||||
	err = json.Unmarshal(request.Users, &users)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	templates := controller.service.Generate(users, quizPaper)
 | 
			
		||||
	userQuizPapers, err := controller.service.Insert(templates)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var userquizzes []models.UserQuiz
 | 
			
		||||
	for _, userQuizPaper := range userQuizPapers {
 | 
			
		||||
		items, err := controller.userQuizService.Generate(request.QuizPaperID, &userQuizPaper)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			userquizzes = append(userquizzes, items...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = controller.userQuizService.Insert(userquizzes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"userQuizPaper": userQuizPapers})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update UserQuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary			응시 수정
 | 
			
		||||
// @Description 응시를 수정합니다.
 | 
			
		||||
// @Tags        사용자퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path int64 true "UserQuizPaper ID"
 | 
			
		||||
// @Param userQuizPaperUpdateBody body models.UserQuizPaperUpdateRequest true "UserQuizPaper Update Body"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizPaperResponse
 | 
			
		||||
// @Router /userquizpaper/{id} [put]
 | 
			
		||||
func (controller *userQuizPaperController) Update(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.UserQuizPaperUpdateRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("request", request)
 | 
			
		||||
	userQuizPaper, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userQuizPaper.QuizPaperID = request.QuizPaperID
 | 
			
		||||
	userQuizPaper.UserID = request.UserID
 | 
			
		||||
	userQuizPaper.Status = request.Status
 | 
			
		||||
	userQuizPaper.UserScore = request.UserScore
 | 
			
		||||
	userQuizPaper.TotalScore = request.TotalScore
 | 
			
		||||
 | 
			
		||||
	if request.StartAt != "" {
 | 
			
		||||
		fmt.Println("request.StartAt", request.StartAt)
 | 
			
		||||
		start_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.StartAt)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			userQuizPaper.StartAt = &start_at
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("start_at", start_at)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if request.DoneAt != "" {
 | 
			
		||||
		fmt.Println("request.EndAt", request.DoneAt)
 | 
			
		||||
		done_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.DoneAt)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			userQuizPaper.DoneAt = &done_at
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("done_at", done_at)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("userQuizPaper", userQuizPaper)
 | 
			
		||||
	result, err := controller.service.Update(userQuizPaper)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("result", result)
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Patch UserQuizPaper
 | 
			
		||||
//
 | 
			
		||||
// @Summary			응시 정보 변경
 | 
			
		||||
// @Description 응시 정보를 변경합니다.
 | 
			
		||||
// @Tags        사용자퀴즈페이퍼
 | 
			
		||||
//
 | 
			
		||||
// @Accept json
 | 
			
		||||
// @Produce json
 | 
			
		||||
//
 | 
			
		||||
// @Security Bearer
 | 
			
		||||
//
 | 
			
		||||
// @Param id path int64 true "UserQuizPaper ID"
 | 
			
		||||
// @Param userQuizPaperPatchBody body models.UserQuizPaperPatchRequest true "UserQuizPaper Patch Body (변경할 필드만 입력)"
 | 
			
		||||
//
 | 
			
		||||
// @Success 200 {object} models.UserQuizPaperResponse
 | 
			
		||||
// @Router /userquizpaper/{id} [patch]
 | 
			
		||||
func (controller *userQuizPaperController) Patch(c *gin.Context) {
 | 
			
		||||
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var request models.UserQuizPaperPatchRequest
 | 
			
		||||
	if err := c.ShouldBindJSON(&request); err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("request", request)
 | 
			
		||||
	userQuizPaper, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if request.Status != "" {
 | 
			
		||||
		userQuizPaper.Status = request.Status
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if request.StartAt != "" {
 | 
			
		||||
		fmt.Println("request.StartAt", request.StartAt)
 | 
			
		||||
		start_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.StartAt)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			userQuizPaper.StartAt = &start_at
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("start_at", start_at)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if request.DoneAt != "" {
 | 
			
		||||
		fmt.Println("request.EndAt", request.DoneAt)
 | 
			
		||||
		done_at, err := time.Parse("2006-01-02T15:04:05-07:00", request.DoneAt)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			userQuizPaper.DoneAt = &done_at
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("done_at", done_at)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("userQuizPaper", userQuizPaper)
 | 
			
		||||
	result, err := controller.service.Update(userQuizPaper)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("result", result)
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								internal/database/database.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								internal/database/database.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
package database
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	config "learnsteam/cslms-api/configs"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/driver/mysql"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"gorm.io/gorm/schema"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Database struct {
 | 
			
		||||
	*gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var DB *gorm.DB
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	DB = ConnectDB((config.DATABASE_URL))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ConnectDB(url string) *gorm.DB {
 | 
			
		||||
	gorm_config := gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}}
 | 
			
		||||
	db, err := gorm.Open(mysql.Open(url), &gorm_config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetDB() *gorm.DB {
 | 
			
		||||
	return DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AutoMigrate() {
 | 
			
		||||
	fmt.Println("AugoMigrate")
 | 
			
		||||
	// DB.AutoMigrate(
 | 
			
		||||
	// 	&models.User{},
 | 
			
		||||
	// 	&models.Token{},
 | 
			
		||||
	// 	&models.Program{},
 | 
			
		||||
	// 	&models.Quiz{},
 | 
			
		||||
	// 	&models.Exam{},
 | 
			
		||||
	// )
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								internal/helpers/cipher/cipher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								internal/helpers/cipher/cipher.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
package cipher
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Crypto interface {
 | 
			
		||||
	Encrypt(plainText string) (string, error)
 | 
			
		||||
	Decrypt(cipherIvKey string) (string, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type niceCrypto struct {
 | 
			
		||||
	cipherKey   string
 | 
			
		||||
	cipherIvKey string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c niceCrypto) Encrypt(plainText string) (string, error) {
 | 
			
		||||
	if strings.TrimSpace(plainText) == "" {
 | 
			
		||||
		return plainText, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block, err := aes.NewCipher([]byte(c.cipherKey))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	encrypter := cipher.NewCBCEncrypter(block, []byte(c.cipherIvKey))
 | 
			
		||||
	paddedPlainText := padPKCS7([]byte(plainText), encrypter.BlockSize())
 | 
			
		||||
 | 
			
		||||
	cipherText := make([]byte, len(paddedPlainText))
 | 
			
		||||
	// CryptBlocks 함수에 데이터(paddedPlainText)와 암호화 될 데이터를 저장할 슬라이스(cipherText)를 넣으면 암호화가 된다.
 | 
			
		||||
	encrypter.CryptBlocks(cipherText, paddedPlainText)
 | 
			
		||||
 | 
			
		||||
	return base64.StdEncoding.EncodeToString(cipherText), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c niceCrypto) Decrypt(cipherText string) (string, error) {
 | 
			
		||||
	if strings.TrimSpace(cipherText) == "" {
 | 
			
		||||
		return cipherText, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decodedCipherText, err := base64.StdEncoding.DecodeString(cipherText)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block, err := aes.NewCipher([]byte(c.cipherKey))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decrypter := cipher.NewCBCDecrypter(block, []byte(c.cipherIvKey))
 | 
			
		||||
	plainText := make([]byte, len(decodedCipherText))
 | 
			
		||||
 | 
			
		||||
	decrypter.CryptBlocks(plainText, decodedCipherText)
 | 
			
		||||
	trimmedPlainText := trimPKCS5(plainText)
 | 
			
		||||
 | 
			
		||||
	return string(trimmedPlainText), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewNiceCrypto(cipherKey, cipherIvKey string) (Crypto, error) {
 | 
			
		||||
	if ck := len(cipherKey); ck != 32 {
 | 
			
		||||
		return nil, aes.KeySizeError(ck)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cik := len(cipherIvKey); cik != 16 {
 | 
			
		||||
		return nil, aes.KeySizeError(cik)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &niceCrypto{cipherKey, cipherIvKey}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func padPKCS7(plainText []byte, blockSize int) []byte {
 | 
			
		||||
	padding := blockSize - len(plainText)%blockSize
 | 
			
		||||
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
 | 
			
		||||
	return append(plainText, padText...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func trimPKCS5(text []byte) []byte {
 | 
			
		||||
	padding := text[len(text)-1]
 | 
			
		||||
	return text[:len(text)-int(padding)]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								internal/helpers/helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								internal/helpers/helpers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
package helpers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InLambda() bool {
 | 
			
		||||
	if lambdaTaskRoot := os.Getenv("LAMBDA_TASK_ROOT"); lambdaTaskRoot != "" {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Datetime(timeString string) (time.Time, error) {
 | 
			
		||||
	layout := "2006-01-02T15:04:05.000Z"
 | 
			
		||||
	result, err := time.Parse(layout, timeString)
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										150
									
								
								internal/helpers/securityutil/securityutil.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								internal/helpers/securityutil/securityutil.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
package securityutil
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SHA256(data string) string {
 | 
			
		||||
	hash := sha256.New()
 | 
			
		||||
	hash.Write([]byte(data))
 | 
			
		||||
	return hex.EncodeToString(hash.Sum(nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func HashPassword(password string) (string, error) {
 | 
			
		||||
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
 | 
			
		||||
	return string(bytes), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CheckPasswordHash(password string, hash string) bool {
 | 
			
		||||
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
 | 
			
		||||
	return err == nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AES256Encode(plaintext string, key string, iv string, blockSize int) string {
 | 
			
		||||
	bKey := []byte(key)
 | 
			
		||||
	bIV := []byte(iv)
 | 
			
		||||
	bPlaintext := PKCS5Padding([]byte(plaintext), blockSize, len(plaintext))
 | 
			
		||||
	block, err := aes.NewCipher(bKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	ciphertext := make([]byte, len(bPlaintext))
 | 
			
		||||
	mode := cipher.NewCBCEncrypter(block, bIV)
 | 
			
		||||
	mode.CryptBlocks(ciphertext, bPlaintext)
 | 
			
		||||
	// return hex.EncodeToString(ciphertext)
 | 
			
		||||
	fmt.Printf("hex.EncodeToString(ciphertext) : %s\n", hex.EncodeToString(ciphertext))
 | 
			
		||||
	fmt.Printf("base64.StdEncoding.EncodeToString(ciphertext) : %s\n", base64.StdEncoding.EncodeToString(ciphertext))
 | 
			
		||||
	fmt.Printf("base64.RawStdEncoding.EncodeToString(ciphertext) : %s\n", base64.RawStdEncoding.EncodeToString(ciphertext))
 | 
			
		||||
	return base64.StdEncoding.EncodeToString(ciphertext)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AES256Decode(cipherText string, encKey string, iv string) (decryptedString string) {
 | 
			
		||||
	bKey := []byte(encKey)
 | 
			
		||||
	bIV := []byte(iv)
 | 
			
		||||
	// cipherTextDecoded, err := hex.DecodeString(cipherText)
 | 
			
		||||
	cipherTextDecoded, err := base64.StdEncoding.DecodeString(cipherText)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block, err := aes.NewCipher(bKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mode := cipher.NewCBCDecrypter(block, bIV)
 | 
			
		||||
	mode.CryptBlocks([]byte(cipherTextDecoded), []byte(cipherTextDecoded))
 | 
			
		||||
	return string(cipherTextDecoded)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func PKCS5Padding(ciphertext []byte, blockSize int, after int) []byte {
 | 
			
		||||
	padding := (blockSize - len(ciphertext)%blockSize)
 | 
			
		||||
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
 | 
			
		||||
	return append(ciphertext, padtext...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// func pkcs7Pad(b []byte, blocksize int) ([]byte, error) {
 | 
			
		||||
// 	if blocksize <= 0 {
 | 
			
		||||
// 		return nil, ErrInvalidBlockSize
 | 
			
		||||
// 	}
 | 
			
		||||
// 	if b == nil || len(b) == 0 {
 | 
			
		||||
// 		return nil, ErrInvalidPKCS7Data
 | 
			
		||||
// 	}
 | 
			
		||||
// 	n := blocksize - (len(b) % blocksize)
 | 
			
		||||
// 	pb := make([]byte, len(b)+n)
 | 
			
		||||
// 	copy(pb, b)
 | 
			
		||||
// 	copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
 | 
			
		||||
// 	return pb, nil
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // pkcs7Unpad validates and unpads data from the given bytes slice.
 | 
			
		||||
// // The returned value will be 1 to n bytes smaller depending on the
 | 
			
		||||
// // amount of padding, where n is the block size.
 | 
			
		||||
// func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) {
 | 
			
		||||
// 	if blocksize <= 0 {
 | 
			
		||||
// 		return nil, ErrInvalidBlockSize
 | 
			
		||||
// 	}
 | 
			
		||||
// 	if b == nil || len(b) == 0 {
 | 
			
		||||
// 		return nil, ErrInvalidPKCS7Data
 | 
			
		||||
// 	}
 | 
			
		||||
// 	if len(b)%blocksize != 0 {
 | 
			
		||||
// 		return nil, ErrInvalidPKCS7Padding
 | 
			
		||||
// 	}
 | 
			
		||||
// 	c := b[len(b)-1]
 | 
			
		||||
// 	n := int(c)
 | 
			
		||||
// 	if n == 0 || n > len(b) {
 | 
			
		||||
// 		return nil, ErrInvalidPKCS7Padding
 | 
			
		||||
// 	}
 | 
			
		||||
// 	for i := 0; i < n; i++ {
 | 
			
		||||
// 		if b[len(b)-n+i] != c {
 | 
			
		||||
// 			return nil, ErrInvalidPKCS7Padding
 | 
			
		||||
// 		}
 | 
			
		||||
// 	}
 | 
			
		||||
// 	return b[:len(b)-n], nil
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // func Encrypt(b cipher.Block, plaintext []byte) []byte {
 | 
			
		||||
// // 	if mod := len(plaintext) % aes.BlockSize; mod != 0 { // 블록 크기의 배수가 되어야함
 | 
			
		||||
// // 		padding := make([]byte, aes.BlockSize-mod) // 블록 크기에서 모자라는 부분을
 | 
			
		||||
// // 		plaintext = append(plaintext, padding...)  // 채워줌
 | 
			
		||||
// // 	}
 | 
			
		||||
 | 
			
		||||
// // 	ciphertext := make([]byte, aes.BlockSize+len(plaintext)) // 초기화 벡터 공간(aes.BlockSize)만큼 더 생성
 | 
			
		||||
// // 	// iv := ciphertext[:aes.BlockSize]                         // 부분 슬라이스로 초기화 벡터 공간을 가져옴
 | 
			
		||||
// // 	// if _, err := io.ReadFull(rand.Reader, iv); err != nil {  // 랜덤 값을 초기화 벡터에 넣어줌
 | 
			
		||||
// // 	// 	fmt.Println(err)
 | 
			
		||||
// // 	// 	return nil
 | 
			
		||||
// // 	// }
 | 
			
		||||
// // 	iv := []byte("0000000000000000")
 | 
			
		||||
// // 	mode := cipher.NewCBCEncrypter(b, iv)                   // 암호화 블록과 초기화 벡터를 넣어서 암호화 블록 모드 인스턴스 생성
 | 
			
		||||
// // 	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) // 암호화 블록 모드 인스턴스로
 | 
			
		||||
// // 	// 암호화
 | 
			
		||||
 | 
			
		||||
// // 	return ciphertext
 | 
			
		||||
// // }
 | 
			
		||||
 | 
			
		||||
// // func Decrypt(b cipher.Block, ciphertext []byte) []byte {
 | 
			
		||||
// // 	if len(ciphertext)%aes.BlockSize != 0 { // 블록 크기의 배수가 아니면 리턴
 | 
			
		||||
// // 		fmt.Println("암호화된 데이터의 길이는 블록 크기의 배수가 되어야합니다.")
 | 
			
		||||
// // 		return nil
 | 
			
		||||
// // 	}
 | 
			
		||||
 | 
			
		||||
// // 	// iv := ciphertext[:aes.BlockSize]        // 부분 슬라이스로 초기화 벡터 공간을 가져옴
 | 
			
		||||
// // 	iv := []byte("0000000000000000")
 | 
			
		||||
// // 	ciphertext = ciphertext[aes.BlockSize:] // 부분 슬라이스로 암호화된 데이터를 가져옴
 | 
			
		||||
 | 
			
		||||
// // 	plaintext := make([]byte, len(ciphertext)) // 평문 데이터를 저장할 공간 생성
 | 
			
		||||
// // 	mode := cipher.NewCBCDecrypter(b, iv)      // 암호화 블록과 초기화 벡터를 넣어서
 | 
			
		||||
// // 	// 복호화 블록 모드 인스턴스 생성
 | 
			
		||||
// // 	mode.CryptBlocks(plaintext, ciphertext) // 복호화 블록 모드 인스턴스로 복호화
 | 
			
		||||
 | 
			
		||||
// // 	return plaintext
 | 
			
		||||
// // }
 | 
			
		||||
							
								
								
									
										136
									
								
								internal/middleware/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								internal/middleware/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
package middleware
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	config "learnsteam/cslms-api/configs"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/golang-jwt/jwt/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Auth(permission string) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		sub, err := UserID(c.Request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		role, err := Role(c.Request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if permission != "member" && *role != permission {
 | 
			
		||||
			fmt.Println("permission", permission, "role", *role)
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Println("token", extract(c.Request))
 | 
			
		||||
		fmt.Println("sub", sub)
 | 
			
		||||
 | 
			
		||||
		c.Set("token", extract(c.Request))
 | 
			
		||||
		c.Set("sub", sub)
 | 
			
		||||
		c.Set("role", role)
 | 
			
		||||
		c.Next()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Permission(permission *string) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		sub, err := UserID(c.Request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		role, err := Role(c.Request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if role != permission {
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Println("token", extract(c.Request))
 | 
			
		||||
		fmt.Println("sub", sub)
 | 
			
		||||
 | 
			
		||||
		c.Set("token", extract(c.Request))
 | 
			
		||||
		c.Set("sub", sub)
 | 
			
		||||
		c.Set("role", role)
 | 
			
		||||
		c.Next()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func extract(r *http.Request) string {
 | 
			
		||||
	authorization := r.Header.Get("Authorization")
 | 
			
		||||
	strArr := strings.Split(authorization, " ")
 | 
			
		||||
	if len(strArr) == 2 {
 | 
			
		||||
		return strArr[1]
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func verify(r *http.Request) (*jwt.Token, error) {
 | 
			
		||||
	tokenString := extract(r)
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return jwtToken, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UserID(r *http.Request) (int64, error) {
 | 
			
		||||
	jwtToken, err := verify(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	claims, ok := jwtToken.Claims.(jwt.MapClaims)
 | 
			
		||||
	if !ok || !jwtToken.Valid {
 | 
			
		||||
		return -1, errors.New("refresh token is invalid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sub := claims["sub"].(float64)
 | 
			
		||||
	user_id := int64(sub)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println(user_id)
 | 
			
		||||
 | 
			
		||||
	return user_id, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Role(r *http.Request) (*string, error) {
 | 
			
		||||
	jwtToken, err := verify(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	claims, ok := jwtToken.Claims.(jwt.MapClaims)
 | 
			
		||||
	if !ok || !jwtToken.Valid {
 | 
			
		||||
		return nil, errors.New("refresh token is invalid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	role := claims["role"].(string)
 | 
			
		||||
 | 
			
		||||
	return &role, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								internal/middleware/transaction.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								internal/middleware/transaction.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
package middleware
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func StatusInList(status int, statusList []int) bool {
 | 
			
		||||
	for _, i := range statusList {
 | 
			
		||||
		for i == status {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Transaction(db *gorm.DB) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		txHandle := db.Begin()
 | 
			
		||||
		log.Print("begining database transaction")
 | 
			
		||||
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if r := recover(); r != nil {
 | 
			
		||||
				txHandle.Rollback()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		c.Set("db_trx", txHandle)
 | 
			
		||||
		c.Next()
 | 
			
		||||
 | 
			
		||||
		if StatusInList(c.Writer.Status(), []int{http.StatusOK, http.StatusCreated}) {
 | 
			
		||||
			log.Print("committing transactions")
 | 
			
		||||
			if err := txHandle.Commit().Error; err != nil {
 | 
			
		||||
				log.Print("transaction commit error: ", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Print("rollback transaction due to status code: ", c.Writer.Status())
 | 
			
		||||
				txHandle.Rollback()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								internal/models/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								internal/models/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
type LoginRequest struct {
 | 
			
		||||
	Username string `json:"user_name" example:"admin0"`
 | 
			
		||||
	Password string `json:"password" example:"testme"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LoginResponse struct {
 | 
			
		||||
	User         User   `json:"user"`
 | 
			
		||||
	Token        string `json:"token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE3MDI3MTMwMjcsInN1"`
 | 
			
		||||
	RefreshToken string `json:"refresh_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE3MDc4OTcwMjcs"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegisterRequest struct {
 | 
			
		||||
	FirstName string `json:"first_name" example:"길순"`
 | 
			
		||||
	LastName  string `json:"last_name" example:"홍"`
 | 
			
		||||
	Username  string `json:"user_name" example:"gilsoon"`
 | 
			
		||||
	Password  string `json:"password" example:"StrongPass!@#$"`
 | 
			
		||||
	Gender    string `json:"gender" example:"F"`
 | 
			
		||||
	UserRole  string `json:"user_role" example:"member"`
 | 
			
		||||
	Phone     string `json:"phone_cs" example:"01012345678"`
 | 
			
		||||
	Image     string `json:"upload_image" example:""`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegisterResponse struct {
 | 
			
		||||
	User         User   `json:"user"`
 | 
			
		||||
	Token        string `json:"token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE3MDI3MTMwMjcsInN1"`
 | 
			
		||||
	RefreshToken string `json:"refresh_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE3MDc4OTcwMjcs"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								internal/models/center.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								internal/models/center.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CREATE TABLE `Centers` (
 | 
			
		||||
//   `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
//   `guid_id` varchar(36) DEFAULT '',
 | 
			
		||||
//   `center_title` varchar(50) DEFAULT '' COMMENT '강동런스팀로봇코딩학원',
 | 
			
		||||
//   `center_name` varchar(50) DEFAULT '' COMMENT 'learnsteam_kd',
 | 
			
		||||
//   `owner_id` bigint(20) DEFAULT 0,
 | 
			
		||||
//   `content_page` text DEFAULT '' COMMENT '학원상세페이지, html/마크다운/text',
 | 
			
		||||
//   `company_info` text DEFAULT '' COMMENT '사업자정보-json\r\n기타 정보 추가 가능\r\n\r\n{\r\n  "company_ceo": "대표자이름",\r\n  "company_code": "사업자번호",\r\n  "company_phone": "대표전화번호",\r\n  "company_email": "대표전자메일",\r\n  "company_homepage": "대표홈페이지 url",\r\n  "company_logo": "로고이미지 url",\r\n  "company_cover_image": "대표 이미지", \r\n}',
 | 
			
		||||
//   `memo` varchar(256) DEFAULT '',
 | 
			
		||||
//   `created_at` timestamp NULL DEFAULT current_timestamp(),
 | 
			
		||||
//   `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
			
		||||
//   `status` varchar(10) DEFAULT NULL,
 | 
			
		||||
//   PRIMARY KEY (`id`)
 | 
			
		||||
// ) ENGINE=InnoDB AUTO_INCREMENT=1000005 DEFAULT CHARSET=utf8mb4 COMMENT='Centers의 이미지/영상은 Links에서 관리됨. ';
 | 
			
		||||
 | 
			
		||||
type Center struct {
 | 
			
		||||
	ID        int64     `json:"id" db:"id" example:"100001" gorm:"column:id;primary_key;"`
 | 
			
		||||
	GUID      string    `json:"guid_id" db:"guid_id" example:"2036023a-fb56-4b6c-b3bb-c787c681ada6" gorm:"column:guid_id;size:255;index;"`
 | 
			
		||||
	Title     string    `json:"center_title" db:"center_title" example:"강동런스팀로봇코딩학원" gorm:"column:center_title;size:50;index;"`
 | 
			
		||||
	Name      string    `json:"center_name" db:"center_name" example:"learnsteam_kd" gorm:"column:center_name;size:50;index;"`
 | 
			
		||||
	OwnerID   int64     `json:"owner_id" db:"owner_id" example:"100001" gorm:"column:owner_id;index;"`
 | 
			
		||||
	Content   string    `json:"content_page" db:"content_page" example:"학원상세페이지, html/마크다운/text" gorm:"column:content_page;size:2048;"`
 | 
			
		||||
	Info      string    `json:"company_info" db:"company_info" example:"사업자정보-json 기타 정보 추가 가능" gorm:"column:company_info;size:2048;"`
 | 
			
		||||
	Memo      string    `json:"memo" db:"memo" example:"메모" gorm:"column:memo;size:1024;"`
 | 
			
		||||
	Status    string    `json:"status" db:"status" example:"on" gorm:"column:status;size:10;index;"`
 | 
			
		||||
	UpdatedAt time.Time `json:"-" gorm:"column:updated_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;index;->:false"`
 | 
			
		||||
	CreatedAt time.Time `json:"-" gorm:"column:created_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;index;->:false;<-:create"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (Center) TableName() string {
 | 
			
		||||
	return "Centers"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CenterRequest struct {
 | 
			
		||||
	Title   string `json:"center_title" example:"강동런스팀로봇코딩학원"`
 | 
			
		||||
	Name    string `json:"center_name" example:"learnsteam_kd"`
 | 
			
		||||
	OwnerID int64  `json:"owner_id" example:"100001"`
 | 
			
		||||
	Content string `json:"content_page" example:"학원상세페이지, html/마크다운/text"`
 | 
			
		||||
	Info    string `json:"company_info" example:"사업자정보-json 기타 정보 추가 가능"`
 | 
			
		||||
	Memo    string `json:"memo" example:"메모"`
 | 
			
		||||
	Status  string `json:"status" example:"on"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CenterListResponse struct {
 | 
			
		||||
	Data      []Center `json:"data"`
 | 
			
		||||
	Total     int64    `json:"total" example:"5"`
 | 
			
		||||
	Page      int      `json:"page" example:"1"`
 | 
			
		||||
	TotalPage int64    `json:"totalPage" example:"1"`
 | 
			
		||||
	PageSize  int      `json:"pageSize" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								internal/models/quiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								internal/models/quiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/datatypes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 문항 json,
 | 
			
		||||
// option1~4는 구분이름일 뿐, 실제로는 셔플되어서 반환됨.
 | 
			
		||||
/*
 | 
			
		||||
{
 | 
			
		||||
  "option1": {"content": "markdown 문서로 작성됨", "is_answer": false},
 | 
			
		||||
  "option2": {"content": "markdown 문서로 작성됨", "is_answer": false},
 | 
			
		||||
  "option3": {"content": "markdown 문서로 작성됨", "is_answer": false},
 | 
			
		||||
  "option4": {"content": "markdown 문서로 작성됨", "is_answer": true},
 | 
			
		||||
  "hint": "markdown문서로 작성됨",
 | 
			
		||||
   "score": 10
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
type Quiz struct {
 | 
			
		||||
	ID           int64          `json:"id" db:"id" example:"1000001" gorm:"column:id;primary_key;"`
 | 
			
		||||
	GUID         string         `json:"guid_id" db:"guid_id" example:"2036023a-fb56-4b6c-b3bb-c787c681ada6" gorm:"column:guid_id;size:255;index;"`
 | 
			
		||||
	CenterID     int64          `json:"center_id" db:"center_id" example:"100001" gorm:"column:center_id;index;"`
 | 
			
		||||
	QuizPaperID  int64          `json:"quiz_paper_id" db:"quiz_paper_id" example:"100001" gorm:"column:quiz_paper_id;index;"`
 | 
			
		||||
	No           int            `json:"vol_no" db:"vol_no" example:"5" gorm:"column:vol_no;index;"`
 | 
			
		||||
	QuestionType string         `json:"question_type" db:"question_type" example:"choice" gorm:"column:question_type;size:10;index;"`
 | 
			
		||||
	Question     string         `json:"question" db:"question" example:"퀴즈 질문입니다." gorm:"column:question;size:512;"`
 | 
			
		||||
	Content      datatypes.JSON `json:"content" db:"content" gorm:"column:content;"`
 | 
			
		||||
	Answer       datatypes.JSON `json:"answer" db:"answer" gorm:"column:answer;"`
 | 
			
		||||
	UpdatedAt    time.Time      `json:"-" gorm:"column:updated_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;index;->:false"`
 | 
			
		||||
	CreatedAt    time.Time      `json:"-" gorm:"column:created_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;index;->:false;<-:create"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (Quiz) TableName() string {
 | 
			
		||||
	return "Quizs"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizRequest struct {
 | 
			
		||||
	QuizPaperID  int64       `json:"quiz_paper_id" example:"1000001"`
 | 
			
		||||
	CenterID     int64       `json:"center_id" example:"1000001"`
 | 
			
		||||
	No           int         `json:"vol_no" example:"1"`
 | 
			
		||||
	QuestionType string      `json:"question_type" example:"choice"`
 | 
			
		||||
	Question     string      `json:"question" example:"질문입니다."`
 | 
			
		||||
	Content      QuizContent `json:"content"`
 | 
			
		||||
	Answer       []string    `json:"answer" example:"option1,option2"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizResponse struct {
 | 
			
		||||
	ID           int64       `json:"id" example:"1000001"`
 | 
			
		||||
	QuizPaperID  int64       `json:"quiz_paper_id" example:"1000001"`
 | 
			
		||||
	No           int         `json:"vol_no" example:"5"`
 | 
			
		||||
	QuestionType string      `json:"question_type" example:"check"`
 | 
			
		||||
	Question     string      `json:"question" example:"퀴즈 질문입니다."`
 | 
			
		||||
	Content      QuizContent `json:"content"`
 | 
			
		||||
	Answer       []string    `json:"answer" example:"option1,option2"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizListResponse struct {
 | 
			
		||||
	Data      []Quiz `json:"data"`
 | 
			
		||||
	Total     int64  `json:"total" example:"5"`
 | 
			
		||||
	Page      int    `json:"page" example:"1"`
 | 
			
		||||
	TotalPage int64  `json:"totalPage" example:"1"`
 | 
			
		||||
	PageSize  int    `json:"pageSize" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizContent struct {
 | 
			
		||||
	Option1 string `json:"option1" example:"markdown 문서로 작성됨"`
 | 
			
		||||
	Option2 string `json:"option2" example:"markdown 문서로 작성됨"`
 | 
			
		||||
	Option3 string `json:"option3" example:"markdown 문서로 작성됨"`
 | 
			
		||||
	Option4 string `json:"option4" example:"markdown 문서로 작성됨"`
 | 
			
		||||
	Hint    string `json:"hint" example:"markdown문서로 작성됨"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizAnswer struct {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								internal/models/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								internal/models/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/datatypes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CREATE TABLE `QuizPapers` (
 | 
			
		||||
//   `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
//   `guid_id` char(36) NOT NULL DEFAULT '0',
 | 
			
		||||
//   `center_id` bigint(20) NOT NULL DEFAULT 0,
 | 
			
		||||
//   `manager_id` bigint(20) NOT NULL DEFAULT 0,
 | 
			
		||||
//   `title` varchar(256) NOT NULL DEFAULT '' COMMENT '퀴즈시트 제목',
 | 
			
		||||
//   `status` varchar(10) NOT NULL DEFAULT '0' COMMENT 'on/off',
 | 
			
		||||
//   `content` text NOT NULL DEFAULT '' COMMENT 'markdown 문서',
 | 
			
		||||
//   `tags` varchar(256) NOT NULL DEFAULT '' COMMENT '출력,hello world,for반복문...',
 | 
			
		||||
//   `category` varchar(256) NOT NULL DEFAULT '파이썬기본',
 | 
			
		||||
//   `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
 | 
			
		||||
//   `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
			
		||||
//   PRIMARY KEY (`id`) USING BTREE,
 | 
			
		||||
//   KEY `guid_id` (`guid_id`) USING BTREE,
 | 
			
		||||
//   KEY `center_id` (`center_id`) USING BTREE,
 | 
			
		||||
//   KEY `manager_id` (`manager_id`) USING BTREE
 | 
			
		||||
// ) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='퀴즈시험지 관리 테이블\r\n\r\n';
 | 
			
		||||
 | 
			
		||||
type QuizPaper struct {
 | 
			
		||||
	ID        int64          `json:"id" db:"id" example:"100001" gorm:"column:id;primary_key;"`
 | 
			
		||||
	GUID      string         `json:"guid_id" db:"guid_id" example:"ef74c59a-c707-4162-a52b-455906c81ec1" gorm:"column:guid_id;size:255;index;"`
 | 
			
		||||
	CenterID  int64          `json:"center_id" db:"center_id" example:"100001"  gorm:"column:center_id;index;"`
 | 
			
		||||
	ManagerID int64          `json:"manager_id" db:"manager_id" example:"100001"  gorm:"column:manager_id;index;"`
 | 
			
		||||
	Title     string         `json:"title" db:"title" example:"퀴즈 시트 제목" gorm:"column:title;size:255;index;"`
 | 
			
		||||
	Content   string         `json:"content" db:"content" example:"퀴즈 시트 설명" gorm:"column:content;size:512;"`
 | 
			
		||||
	Category  string         `json:"category" db:"category" example:"파이썬기본" gorm:"column:title;size:255;"`
 | 
			
		||||
	Tag       datatypes.JSON `json:"tag" db:"tag" gorm:"column:tag;"`
 | 
			
		||||
	Status    string         `json:"status" example:"on" gorm:"column:status;size:10;index;"`
 | 
			
		||||
	UpdatedAt time.Time      `json:"-" gorm:"column:updated_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;index;->:false"`
 | 
			
		||||
	CreatedAt time.Time      `json:"-" gorm:"column:created_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;index;->:false;<-:create"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (QuizPaper) TableName() string {
 | 
			
		||||
	return "QuizPapers"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperRequest struct {
 | 
			
		||||
	CenterID int64          `json:"center_id" example:"100001"`
 | 
			
		||||
	Title    string         `json:"title" example:"퀴즈 시트 제목"`
 | 
			
		||||
	Content  string         `json:"content" example:"퀴즈 시트 설명"`
 | 
			
		||||
	Category string         `json:"category" example:"파이썬기본"`
 | 
			
		||||
	Tag      datatypes.JSON `json:"tag"`
 | 
			
		||||
	Status   string         `json:"status" example:"on"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperResponse struct {
 | 
			
		||||
	ID        int64          `json:"id" example:"100001"`
 | 
			
		||||
	CenterID  int64          `json:"center_id" example:"100001"`
 | 
			
		||||
	ManagerID int64          `json:"manager_id" example:"100001"`
 | 
			
		||||
	Title     string         `json:"title" example:"퀴즈 시트 제목"`
 | 
			
		||||
	Content   string         `json:"content" example:"퀴즈 시트 설명"`
 | 
			
		||||
	Category  string         `json:"category" example:"파이썬기본"`
 | 
			
		||||
	Tag       datatypes.JSON `json:"tag"`
 | 
			
		||||
	Status    string         `json:"status" example:"on"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperListResponse struct {
 | 
			
		||||
	Data      []QuizPaper `json:"data"`
 | 
			
		||||
	Total     int64       `json:"total" example:"999"`
 | 
			
		||||
	Page      int         `json:"page" example:"1"`
 | 
			
		||||
	TotalPage int64       `json:"totalPage" example:"99"`
 | 
			
		||||
	PageSize  int         `json:"pageSize" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperCopyRequest struct {
 | 
			
		||||
	Title    string `json:"title" example:"퀴즈 시트 제목"`
 | 
			
		||||
	CenterID int64  `json:"center_id" example:"100002"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperCopyResponse struct {
 | 
			
		||||
	QuizPaper QuizPaper `json:"quiz_paper"`
 | 
			
		||||
	Quiz      []Quiz    `json:"quiz"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								internal/models/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								internal/models/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// CREATE TABLE `UserTokens` (
 | 
			
		||||
//   `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
//   `user_id` bigint(20) DEFAULT 0,
 | 
			
		||||
//   `token` varchar(256) DEFAULT '',
 | 
			
		||||
//   `refresh_token` varchar(256) DEFAULT '',
 | 
			
		||||
//   `status` varchar(3) DEFAULT 'on' COMMENT 'on/off',
 | 
			
		||||
//   `register_at` timestamp NULL DEFAULT current_timestamp(),
 | 
			
		||||
//   `ending_at` timestamp NULL DEFAULT NULL COMMENT '종료날짜',
 | 
			
		||||
//   PRIMARY KEY (`id`) USING BTREE
 | 
			
		||||
// ) ENGINE=InnoDB AUTO_INCREMENT=1000017 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
 | 
			
		||||
 | 
			
		||||
type Token struct {
 | 
			
		||||
	ID           int64  `json:"-" db:"id" gorm:"primary_key"`
 | 
			
		||||
	UserID       int64  `json:"user_id" db:"user_id" gorm:"index;"`
 | 
			
		||||
	Token        string `json:"token" db:"token" gorm:"size:255;index;"`
 | 
			
		||||
	RefreshToken string `json:"refresh_token" db:"refresh_token" gorm:"size:255;index;"`
 | 
			
		||||
 | 
			
		||||
	Status string `json:"status" gorm:"size:3;index"`
 | 
			
		||||
 | 
			
		||||
	RegisterAt time.Time `json:"register_at" db:"register_at"`
 | 
			
		||||
	EndingAt   time.Time `json:"ending_at" db:"ending_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (Token) TableName() string {
 | 
			
		||||
	return "UserTokens"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RefreshTokenRequest struct {
 | 
			
		||||
	RefreshToken string `json:"refresh_token" binding:"required"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenResponse struct {
 | 
			
		||||
	Token     string    `json:"token"`
 | 
			
		||||
	TokenBody TokenBody `json:"tokenBody"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenBody struct {
 | 
			
		||||
	ExpireAt  time.Time `json:"tokenExpiredDate"`
 | 
			
		||||
	TokenIdx  int       `json:"tokenIdx"`
 | 
			
		||||
	TokenType int       `json:"tokenType"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								internal/models/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								internal/models/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// CREATE TABLE `Users` (
 | 
			
		||||
//   `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
//   `guid_id` longtext DEFAULT NULL,
 | 
			
		||||
//   `first_name` longtext DEFAULT NULL,
 | 
			
		||||
//   `last_name` longtext DEFAULT NULL,
 | 
			
		||||
//   `user_name` longtext DEFAULT NULL,
 | 
			
		||||
//   `password` longtext DEFAULT NULL,
 | 
			
		||||
//   `gender` char(1) DEFAULT 'M' COMMENT 'M(남)/F(여)',
 | 
			
		||||
//   `user_role` longtext DEFAULT NULL,
 | 
			
		||||
//   `memo_cs` longtext DEFAULT NULL,
 | 
			
		||||
//   `register_at` datetime(3) DEFAULT NULL,
 | 
			
		||||
//   `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT '업데이트될때마다 자동저장',
 | 
			
		||||
//   `phone_cs` longtext DEFAULT NULL,
 | 
			
		||||
//   `upload_image` longtext DEFAULT NULL,
 | 
			
		||||
//   PRIMARY KEY (`id`) USING BTREE,
 | 
			
		||||
//   KEY `guid_id` (`guid_id`(768)),
 | 
			
		||||
//   KEY `first_name` (`first_name`(768)),
 | 
			
		||||
//   KEY `last_name` (`last_name`(768)),
 | 
			
		||||
//   KEY `user_name` (`user_name`(768))
 | 
			
		||||
// ) ENGINE=InnoDB AUTO_INCREMENT=1000023 DEFAULT CHARSET=utf8mb4;
 | 
			
		||||
 | 
			
		||||
type User struct {
 | 
			
		||||
	ID         int64     `json:"id" db:"id" example:"100001" gorm:"column:id;primary_key;"`
 | 
			
		||||
	GUID       string    `json:"guid_id" db:"guid_id" example:"137c1683-2ad6-4201-b256-253828b61c49" gorm:"column:guid_id;size:255;"`
 | 
			
		||||
	FirstName  string    `json:"first_name" db:"first_name" example:"길순" gorm:"column:first_name;size:255;"`
 | 
			
		||||
	LastName   string    `json:"last_name" db:"last_name" example:"홍" gorm:"column:last_name;size:255;"`
 | 
			
		||||
	Username   string    `json:"user_name" db:"user_name" example:"user0" gorm:"column:user_name;size:50;uniqueIndex;"`
 | 
			
		||||
	Password   string    `json:"-" db:"password" gorm:"column:password;size:255;not null;"`
 | 
			
		||||
	Gender     string    `json:"gender" db:"gender" example:"F" gorm:"column:gender;size:1;"`
 | 
			
		||||
	UserRole   string    `json:"user_role" db:"user_role" example:"member" gorm:"column:user_role;size:255;"`
 | 
			
		||||
	Memo       string    `json:"memo_cs" db:"memo_cs" example:"사용자 메모" gorm:"column:memo_cs;size:255;"`
 | 
			
		||||
	Phone      string    `json:"phone_cs" db:"phone_cs" example:"010-1234-5678" gorm:"column:phone_cs;size:255;"`
 | 
			
		||||
	Image      string    `json:"upload_image" db:"upload_image" example:"image_url" gorm:"column:upload_image;size:255;"`
 | 
			
		||||
	RegisterAt time.Time `json:"register_at" db:"regiser_at" gorm:"column:register_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;index;->:false"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (User) TableName() string {
 | 
			
		||||
	return "Users"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserListResponse struct {
 | 
			
		||||
	Data      []User `json:"data"`
 | 
			
		||||
	Total     int64  `json:"total" example:"90"`
 | 
			
		||||
	Page      int    `json:"page" example:"1"`
 | 
			
		||||
	TotalPage int64  `json:"totalPage" example:"9"`
 | 
			
		||||
	PageSize  int    `json:"pageSize" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								internal/models/userquiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								internal/models/userquiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/datatypes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserQuiz struct {
 | 
			
		||||
	ID              int64          `json:"id" db:"id" example:"1000001" gorm:"column:id;primary_key;"`
 | 
			
		||||
	GUID            string         `json:"guid_id" db:"guid_id" example:"2036023a-fb56-4b6c-b3bb-c787c681ada6" gorm:"column:guid_id;size:255;index;"`
 | 
			
		||||
	CenterID        int64          `json:"center_id" db:"center_id" example:"100001" gorm:"column:center_id;index;"`
 | 
			
		||||
	UserQuizPaperID int64          `json:"user_quiz_paper_id" db:"user_quiz_paper_id" example:"1000001" gorm:"column:user_quiz_paper_id;index;"`
 | 
			
		||||
	UserID          int64          `json:"user_id" db:"user_id" example:"1000001" gorm:"column:user_id;index;"`
 | 
			
		||||
	No              int            `json:"vol_no" db:"vol_no" example:"5" gorm:"column:vol_no;index;"`
 | 
			
		||||
	QuestionType    string         `json:"question_type" db:"question_type" example:"choice" gorm:"column:question_type;size:10;index;"`
 | 
			
		||||
	Question        string         `json:"question" db:"question" example:"퀴즈 질문입니다." gorm:"column:question;size:512;"`
 | 
			
		||||
	Content         datatypes.JSON `json:"content" db:"content" gorm:"column:content;"`
 | 
			
		||||
	Answer          datatypes.JSON `json:"answer,omitempty" db:"answer" gorm:"column:answer;default:'[]';"`
 | 
			
		||||
	Status          string         `json:"status" db:"status" example:"waiting" gorm:"column:status;size:10;index;"`
 | 
			
		||||
	Result          string         `json:"result" db:"result" example:"success" gorm:"column:result;size:10;index;"`
 | 
			
		||||
	Score           float32        `json:"score" db:"score" example:"10" gorm:"column:score;"`
 | 
			
		||||
	UpdatedAt       time.Time      `json:"-" gorm:"column:updated_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;index;->:false"`
 | 
			
		||||
	CreatedAt       time.Time      `json:"-" gorm:"column:created_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;index;->:false;<-:create"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (UserQuiz) TableName() string {
 | 
			
		||||
	return "UserQuizs"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizRequest struct {
 | 
			
		||||
	CenterID        int64       `json:"center_id" example:"1000001"`
 | 
			
		||||
	UserQuizPaperID int64       `json:"quiz_paper_id" example:"1000001"`
 | 
			
		||||
	UserID          int64       `json:"user_id" example:"1000001"`
 | 
			
		||||
	No              int         `json:"vol_no" example:"1"`
 | 
			
		||||
	QuestionType    string      `json:"question_type" example:"choice"`
 | 
			
		||||
	Question        string      `json:"question" example:"질문입니다."`
 | 
			
		||||
	Content         QuizContent `json:"content"`
 | 
			
		||||
	Answer          []string    `json:"answer" example:"option1,option2"`
 | 
			
		||||
	Status          string      `json:"status" example:"waiting"`
 | 
			
		||||
	Result          string      `json:"result" example:"success"`
 | 
			
		||||
	Score           float32     `json:"score" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizResponse struct {
 | 
			
		||||
	ID              int64       `json:"id" example:"1000001"`
 | 
			
		||||
	GUID            string      `json:"guid_id" example:"2036023a-fb56-4b6c-b3bb-c787c681ada6"`
 | 
			
		||||
	CenterD         string      `json:"center_id" example:"2036023a-fb56-4b6c-b3bb-c787c681ada6"`
 | 
			
		||||
	UserQuizPaperID int64       `json:"user_quiz_paper_id" example:"1000001"`
 | 
			
		||||
	UserID          int64       `json:"user_id" example:"1000001"`
 | 
			
		||||
	No              int         `json:"vol_no" example:"5"`
 | 
			
		||||
	QuestionType    string      `json:"question_type" example:"check"`
 | 
			
		||||
	Question        string      `json:"question" example:"퀴즈 질문입니다."`
 | 
			
		||||
	Content         QuizContent `json:"content"`
 | 
			
		||||
	Answer          []string    `json:"answer" example:"option1,option2"`
 | 
			
		||||
	Status          string      `json:"status" example:"waiting"`
 | 
			
		||||
	Result          string      `json:"result" example:"success"`
 | 
			
		||||
	Score           float32     `json:"score" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizListResponse struct {
 | 
			
		||||
	Data      []UserQuizResponse `json:"data"`
 | 
			
		||||
	Total     int64              `json:"total" example:"5"`
 | 
			
		||||
	Page      int                `json:"page" example:"1"`
 | 
			
		||||
	TotalPage int64              `json:"totalPage" example:"1"`
 | 
			
		||||
	PageSize  int                `json:"pageSize" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								internal/models/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								internal/models/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/datatypes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CREATE TABLE `UserQuizPapers` (
 | 
			
		||||
//   `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
//   `guid_id` char(36) NOT NULL DEFAULT '0',
 | 
			
		||||
//   `center_id` bigint(20) NOT NULL DEFAULT 0,
 | 
			
		||||
//   `quiz_paper_id` bigint(20) NOT NULL DEFAULT 0,
 | 
			
		||||
//   `status` varchar(10) NOT NULL DEFAULT '0' COMMENT '매칭된 학생퀴즈시험지 상태: \r\nwaiting(대기)/processing(시험진행중)/abort(취소)/marking(채점중)/done(완료) ',
 | 
			
		||||
//   `user_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '매칭된 학생',
 | 
			
		||||
//   `user_score` float NOT NULL DEFAULT 5 COMMENT '10',
 | 
			
		||||
//   `total_score` float NOT NULL DEFAULT 100 COMMENT '100.0, 5.0',
 | 
			
		||||
//   `start_at` timestamp NULL DEFAULT NULL COMMENT '학생시험시작시각',
 | 
			
		||||
//   `done_at` timestamp NULL DEFAULT NULL COMMENT '학생시험종료시각',
 | 
			
		||||
//   `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
 | 
			
		||||
//   `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
			
		||||
//   PRIMARY KEY (`id`) USING BTREE,
 | 
			
		||||
//   KEY `guid_id` (`guid_id`) USING BTREE,
 | 
			
		||||
//   KEY `center_id` (`center_id`) USING BTREE,
 | 
			
		||||
//   KEY `user_id` (`user_id`),
 | 
			
		||||
//   KEY `manager_id` (`quiz_paper_id`) USING BTREE
 | 
			
		||||
// ) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='학생퀴즈시험지 매칭\r\n';
 | 
			
		||||
 | 
			
		||||
type UserQuizPaper struct {
 | 
			
		||||
	ID          int64      `json:"id" db:"id" example:"1000015" gorm:"column:id;primary_key;"`
 | 
			
		||||
	GUID        string     `json:"guid_id" db:"guid_id" example:"7f9329f5-2e36-4638-92d2-73064b7291a4" gorm:"column:guid_id;size:255;uniqueIndex"`
 | 
			
		||||
	CenterID    int64      `json:"center_id" db:"center_id" example:"1000015" gorm:"column:center_id;index;"`
 | 
			
		||||
	QuizPaperID int64      `json:"quiz_paper_id" db:"quiz_paper_id" example:"1000001" gorm:"column:quiz_paper_id;index;"`
 | 
			
		||||
	UserID      int64      `json:"user_id" db:"user_id" example:"1000002" gorm:"column:user_id;index;"`
 | 
			
		||||
	UserScore   float32    `json:"user_score" db:"user_score" example:"5" gorm:"column:user_score;"`
 | 
			
		||||
	TotalScore  float32    `json:"total_score" db:"total_score" example:"100" gorm:"column:total_score;"`
 | 
			
		||||
	Status      string     `json:"status" example:"wating" gorm:"column:status;size:10;index;"`
 | 
			
		||||
	StartAt     *time.Time `json:"start_at" gorm:"column:start_at;index;"`
 | 
			
		||||
	DoneAt      *time.Time `json:"done_at" gorm:"column:done_at;index;"`
 | 
			
		||||
	UpdatedAt   time.Time  `json:"-" gorm:"column:updated_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;index;->:false"`
 | 
			
		||||
	CreatedAt   time.Time  `json:"-" gorm:"column:created_at;type:DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;index;->:false;<-:create"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 테이블이름 정의
 | 
			
		||||
func (UserQuizPaper) TableName() string {
 | 
			
		||||
	return "UserQuizPapers"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperRequest struct {
 | 
			
		||||
	QuizPaperID int64          `json:"quiz_paper_id" example:"1000002"`
 | 
			
		||||
	Users       datatypes.JSON `json:"users"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperResponse struct {
 | 
			
		||||
	ID          int64      `json:"id" db:"id" example:"1000015"`
 | 
			
		||||
	GUID        string     `json:"guid_id" db:"guid_id" example:"7f9329f5-2e36-4638-92d2-73064b7291a4"`
 | 
			
		||||
	CenterID    int64      `json:"center_id" db:"center_id" example:"1000015"`
 | 
			
		||||
	QuizPaperID int64      `json:"quiz_paper_id" db:"quiz_paper_id" example:"1000001"`
 | 
			
		||||
	UserID      int64      `json:"user_id" db:"user_id" example:"1000002"`
 | 
			
		||||
	UserScore   float32    `json:"user_score" db:"user_score" example:"5"`
 | 
			
		||||
	TotalScore  float32    `json:"total_score" db:"total_score" example:"100"`
 | 
			
		||||
	Status      string     `json:"status" example:"wating"`
 | 
			
		||||
	StartAt     *time.Time `json:"start_at"`
 | 
			
		||||
	DoneAt      *time.Time `json:"done_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperUpdateRequest struct {
 | 
			
		||||
	QuizPaperID int64   `json:"quiz_paper_id" example:"1000002"`
 | 
			
		||||
	UserID      int64   `json:"user_id" example:"1000003"`
 | 
			
		||||
	UserScore   float32 `json:"user_score" example:"5"`
 | 
			
		||||
	TotalScore  float32 `json:"total_score" example:"100"`
 | 
			
		||||
	Status      string  `json:"status" example:"ready"`
 | 
			
		||||
	StartAt     string  `json:"start_at,omitempty" example:"2023-11-10T13:10:00+09:00"`
 | 
			
		||||
	DoneAt      string  `json:"done_at,omitempty" example:"2023-11-10T13:25:00+09:00"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperPatchRequest struct {
 | 
			
		||||
	UserScore  float32 `json:"user_score" example:"4"`
 | 
			
		||||
	TotalScore float32 `json:"total_score" example:"80"`
 | 
			
		||||
	Status     string  `json:"status" example:"ready"`
 | 
			
		||||
	StartAt    string  `json:"start_at,omitempty" example:"2023-11-10T13:10:00+09:00"`
 | 
			
		||||
	DoneAt     string  `json:"done_at,omitempty" example:"2023-11-10T13:25:00+09:00"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperListResponse struct {
 | 
			
		||||
	Data      []UserQuizPaper `json:"data"`
 | 
			
		||||
	Total     int64           `json:"total" example:"999"`
 | 
			
		||||
	Page      int             `json:"page" example:"1"`
 | 
			
		||||
	TotalPage int64           `json:"totalPage" example:"99"`
 | 
			
		||||
	PageSize  int             `json:"pageSize" example:"10"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								internal/repositories/center.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								internal/repositories/center.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type centerRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCenterRepository(db *gorm.DB) CenterRepository {
 | 
			
		||||
	return ¢erRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CenterRepository interface {
 | 
			
		||||
	List(string, int, int) (*[]models.Center, error)
 | 
			
		||||
	Total(string) (int64, error)
 | 
			
		||||
	Find(int64) (*models.Center, error)
 | 
			
		||||
	FindByTitle(string) (*models.Center, error)
 | 
			
		||||
	Create(*models.Center) (*models.Center, error)
 | 
			
		||||
	Update(*models.Center) (*models.Center, error)
 | 
			
		||||
	Delete(int64) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) List(q string, page int, limit int) (*[]models.Center, error) {
 | 
			
		||||
	var centers *[]models.Center
 | 
			
		||||
	var err error
 | 
			
		||||
	offset := limit * (page - 1)
 | 
			
		||||
	fmt.Println("q", q)
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("center_title ASC").Where("center_title LIKE ? OR center_name LIKE ?", "%"+q+"%", "%"+q+"%").Find(¢ers).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("center_title ASC").Find(¢ers).Error
 | 
			
		||||
	}
 | 
			
		||||
	return centers, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) Total(q string) (int64, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	var err error
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Model(&models.Center{}).Where("center_title LIKE ? OR center_name LIKE ?", "%"+q+"%", "%"+q+"%").Count(&total).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Model(&models.Center{}).Count(&total).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) Find(id int64) (*models.Center, error) {
 | 
			
		||||
	var center *models.Center
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(¢er).Error
 | 
			
		||||
	return center, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) FindByTitle(center_title string) (*models.Center, error) {
 | 
			
		||||
	var center *models.Center
 | 
			
		||||
	err := r.DB.Where("center_title = ?", center_title).First(¢er).Error
 | 
			
		||||
	return center, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) Create(center *models.Center) (*models.Center, error) {
 | 
			
		||||
	err := r.DB.Create(¢er).Error
 | 
			
		||||
	return center, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) Update(center *models.Center) (*models.Center, error) {
 | 
			
		||||
	var row *models.Center
 | 
			
		||||
	if err := r.DB.Where("id=?", center.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(¢er).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRepository) Delete(id int64) error {
 | 
			
		||||
	var center *models.Center
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(¢er).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(¢er).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								internal/repositories/quiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								internal/repositories/quiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type quizRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizRepository(db *gorm.DB) QuizRepository {
 | 
			
		||||
	return &quizRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizRepository interface {
 | 
			
		||||
	List(int64, int, int) (*[]models.Quiz, error)
 | 
			
		||||
	Total(int64) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.Quiz, error)
 | 
			
		||||
	Create(*models.Quiz) (*models.Quiz, error)
 | 
			
		||||
	Update(*models.Quiz) (*models.Quiz, error)
 | 
			
		||||
	Delete(int64) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRepository) List(quiz_paper_id int64, page int, limit int) (*[]models.Quiz, error) {
 | 
			
		||||
	var quizzes *[]models.Quiz
 | 
			
		||||
	var err error
 | 
			
		||||
	offset := limit * (page - 1)
 | 
			
		||||
	if quiz_paper_id > 0 {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("vol_no ASC").Where("quiz_paper_id = ?", quiz_paper_id).Find(&quizzes).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Find(&quizzes).Error
 | 
			
		||||
	}
 | 
			
		||||
	return quizzes, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRepository) Total(quiz_paper_id int64) (int64, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	var err error
 | 
			
		||||
	if quiz_paper_id > 0 {
 | 
			
		||||
		err = r.DB.Model(&models.Quiz{}).Where("quiz_paper_id = ?", quiz_paper_id).Count(&total).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Model(&models.Quiz{}).Count(&total).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRepository) Find(id int64) (*models.Quiz, error) {
 | 
			
		||||
	var quiz *models.Quiz
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&quiz).Error
 | 
			
		||||
	return quiz, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRepository) Create(quiz *models.Quiz) (*models.Quiz, error) {
 | 
			
		||||
	err := r.DB.Create(&quiz).Error
 | 
			
		||||
	return quiz, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRepository) Update(quiz *models.Quiz) (*models.Quiz, error) {
 | 
			
		||||
	var row *models.Quiz
 | 
			
		||||
	if err := r.DB.Where("id=?", quiz.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&quiz).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRepository) Delete(id int64) error {
 | 
			
		||||
	var quiz *models.Quiz
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&quiz).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&quiz).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								internal/repositories/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								internal/repositories/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type quizPaperRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizPaperRepository(db *gorm.DB) QuizPaperRepository {
 | 
			
		||||
	return &quizPaperRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperRepository interface {
 | 
			
		||||
	List(string, string, int, int) (*[]models.QuizPaper, error)
 | 
			
		||||
	Total(string, string) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.QuizPaper, error)
 | 
			
		||||
	Create(*models.QuizPaper) (*models.QuizPaper, error)
 | 
			
		||||
	Update(*models.QuizPaper) (*models.QuizPaper, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRepository) List(q string, tag string, page int, limit int) (*[]models.QuizPaper, error) {
 | 
			
		||||
	var quizPapers *[]models.QuizPaper
 | 
			
		||||
	var err error
 | 
			
		||||
	offset := limit * (page - 1)
 | 
			
		||||
	fmt.Println("q", q)
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		fmt.Println(" 1 q", q)
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("created_at DESC").Where("title LIKE ? OR category LIKE ? OR tag LIKE ?", "%"+q+"%", "%"+q+"%", "%"+q+"%").Find(&quizPapers).Error
 | 
			
		||||
	} else if tag != "" {
 | 
			
		||||
		fmt.Println(" tag", tag)
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("created_at DESC").Where("tag LIKE ?", "%"+tag+"%").Find(&quizPapers).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Println(" query")
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("created_at DESC").Find(&quizPapers).Error
 | 
			
		||||
	}
 | 
			
		||||
	return quizPapers, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRepository) Total(q string, tag string) (int64, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	var err error
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Model(&models.QuizPaper{}).Where("title LIKE ? OR category LIKE ? OR tag LIKE ?", "%"+q+"%", "%"+q+"%", "%"+q+"%").Count(&total).Error
 | 
			
		||||
	} else if tag != "" {
 | 
			
		||||
		err = r.DB.Model(&models.QuizPaper{}).Where("tag LIKE ?", "%"+tag+"%").Count(&total).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Model(&models.QuizPaper{}).Count(&total).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRepository) Find(id int64) (*models.QuizPaper, error) {
 | 
			
		||||
	var quizPaper *models.QuizPaper
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&quizPaper).Error
 | 
			
		||||
	return quizPaper, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRepository) Create(quizPaper *models.QuizPaper) (*models.QuizPaper, error) {
 | 
			
		||||
	err := r.DB.Create(&quizPaper).Error
 | 
			
		||||
	return quizPaper, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRepository) Update(quizPaper *models.QuizPaper) (*models.QuizPaper, error) {
 | 
			
		||||
	var row *models.QuizPaper
 | 
			
		||||
	if err := r.DB.Where("id=?", quizPaper.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&quizPaper).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRepository) Delete(id string) error {
 | 
			
		||||
	var quizPaper *models.QuizPaper
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&quizPaper).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&quizPaper).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								internal/repositories/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								internal/repositories/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	config "learnsteam/cslms-api/configs"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang-jwt/jwt/v5"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tokenRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenRepository(db *gorm.DB) TokenRepository {
 | 
			
		||||
	return &tokenRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenRepository interface {
 | 
			
		||||
	Generate(int64, int64, string) (string, error)
 | 
			
		||||
	Find(int64) (*models.Token, error)
 | 
			
		||||
	FindByRefreshToken(int64, string) (*models.Token, error)
 | 
			
		||||
	Create(*models.Token) (*models.Token, error)
 | 
			
		||||
	Update(*models.Token) (*models.Token, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenRepository) Generate(user_id int64, expire_at int64, role string) (string, error) {
 | 
			
		||||
	fmt.Println(user_id, role)
 | 
			
		||||
	claims := jwt.MapClaims{}
 | 
			
		||||
	claims["authorized"] = true
 | 
			
		||||
	claims["sub"] = user_id
 | 
			
		||||
	claims["exp"] = expire_at
 | 
			
		||||
	claims["role"] = role
 | 
			
		||||
	at := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 | 
			
		||||
	token, err := at.SignedString([]byte(config.SECRET_KEY))
 | 
			
		||||
 | 
			
		||||
	fmt.Println(token)
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Find(id int64) (*models.Token, error) {
 | 
			
		||||
	var token *models.Token
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&token).Error
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) FindByRefreshToken(user_id int64, refreshToken string) (*models.Token, error) {
 | 
			
		||||
	var token *models.Token
 | 
			
		||||
	err := r.DB.Where("user_id = ? AND refresh_token = ?", user_id, refreshToken).First(&token).Error
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Create(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	err := r.DB.Create(&token).Error
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Update(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	var row *models.Token
 | 
			
		||||
	if err := r.DB.Where("id=?", token.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&token).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Delete(id string) error {
 | 
			
		||||
	var token *models.Token
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&token).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&token).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								internal/repositories/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								internal/repositories/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserRepository(db *gorm.DB) UserRepository {
 | 
			
		||||
	return &userRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserRepository interface {
 | 
			
		||||
	List(string, int, int) (*[]models.User, error)
 | 
			
		||||
	Total(string) (int64, error)
 | 
			
		||||
	Find(int64) (*models.User, error)
 | 
			
		||||
	FindByUsername(string) (*models.User, error)
 | 
			
		||||
	Create(*models.User) (*models.User, error)
 | 
			
		||||
	Update(*models.User) (*models.User, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) List(q string, page int, limit int) (*[]models.User, error) {
 | 
			
		||||
	var users *[]models.User
 | 
			
		||||
	var err error
 | 
			
		||||
	offset := limit * (page - 1)
 | 
			
		||||
	fmt.Println("q", q)
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("last_name ASC, first_name ASC").Where("user_role = ?", "member").Where("name LIKE ? OR user_name LIKE ?", "%"+q+"%", "%"+q+"%").Find(&users).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Println(" query")
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("last_name ASC, first_name ASC").Where("user_role = ?", "member").Find(&users).Error
 | 
			
		||||
	}
 | 
			
		||||
	return users, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Total(q string) (int64, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	var err error
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Model(&models.User{}).Where("user_role = ?", "member").Where("name LIKE ? OR user_name LIKE ?", "%"+q+"%", "%"+q+"%").Count(&total).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Model(&models.User{}).Where("user_role = ?", "member").Count(&total).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Find(id int64) (*models.User, error) {
 | 
			
		||||
	var user *models.User
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&user).Error
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) FindByUsername(username string) (*models.User, error) {
 | 
			
		||||
	var user *models.User
 | 
			
		||||
	err := r.DB.Where("user_name = ?", username).First(&user).Error
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Create(user *models.User) (*models.User, error) {
 | 
			
		||||
	err := r.DB.Create(&user).Error
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Update(user *models.User) (*models.User, error) {
 | 
			
		||||
	var row *models.User
 | 
			
		||||
	if err := r.DB.Where("id=?", user.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&user).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Delete(id string) error {
 | 
			
		||||
	var user *models.User
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&user).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&user).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								internal/repositories/userquiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								internal/repositories/userquiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userQuizRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizRepository(db *gorm.DB) UserQuizRepository {
 | 
			
		||||
	return &userQuizRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizRepository interface {
 | 
			
		||||
	List(int64, int, int) (*[]models.UserQuiz, error)
 | 
			
		||||
	Total(int64) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.UserQuiz, error)
 | 
			
		||||
	Create(*models.UserQuiz) (*models.UserQuiz, error)
 | 
			
		||||
	Insert([]models.UserQuiz) ([]models.UserQuiz, error)
 | 
			
		||||
	Update(*models.UserQuiz) (*models.UserQuiz, error)
 | 
			
		||||
	Delete(int64) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) List(user_quiz_paper_id int64, page int, limit int) (*[]models.UserQuiz, error) {
 | 
			
		||||
	var rows *[]models.UserQuiz
 | 
			
		||||
	var err error
 | 
			
		||||
	offset := limit * (page - 1)
 | 
			
		||||
	if user_quiz_paper_id > 0 {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("vol_no ASC").Where("user_quiz_paper_id = ?", user_quiz_paper_id).Find(&rows).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Find(&rows).Error
 | 
			
		||||
	}
 | 
			
		||||
	return rows, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) Total(user_quiz_paper_id int64) (int64, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	var err error
 | 
			
		||||
	if user_quiz_paper_id > 0 {
 | 
			
		||||
		err = r.DB.Model(&models.UserQuiz{}).Where("user_quiz_paper_id = ?", user_quiz_paper_id).Count(&total).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Model(&models.UserQuiz{}).Count(&total).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) Find(id int64) (*models.UserQuiz, error) {
 | 
			
		||||
	var row *models.UserQuiz
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&row).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) Create(row *models.UserQuiz) (*models.UserQuiz, error) {
 | 
			
		||||
	err := r.DB.Create(&row).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) Insert(items []models.UserQuiz) ([]models.UserQuiz, error) {
 | 
			
		||||
	fmt.Println(items)
 | 
			
		||||
	err := r.DB.Create(&items).Error
 | 
			
		||||
	return items, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) Update(quiz *models.UserQuiz) (*models.UserQuiz, error) {
 | 
			
		||||
	var row *models.UserQuiz
 | 
			
		||||
	if err := r.DB.Where("id=?", quiz.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&quiz).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRepository) Delete(id int64) error {
 | 
			
		||||
	var row *models.UserQuiz
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&row).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&row).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										87
									
								
								internal/repositories/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								internal/repositories/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userQuizPaperRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizPaperRepository(db *gorm.DB) UserQuizPaperRepository {
 | 
			
		||||
	return &userQuizPaperRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperRepository interface {
 | 
			
		||||
	List(string, int, int) (*[]models.UserQuizPaper, error)
 | 
			
		||||
	Total(string) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.UserQuizPaper, error)
 | 
			
		||||
	Create(*models.UserQuizPaper) (*models.UserQuizPaper, error)
 | 
			
		||||
	Insert([]models.UserQuizPaper) ([]models.UserQuizPaper, error)
 | 
			
		||||
	Update(*models.UserQuizPaper) (*models.UserQuizPaper, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) List(q string, page int, limit int) (*[]models.UserQuizPaper, error) {
 | 
			
		||||
	var userQuizPapers *[]models.UserQuizPaper
 | 
			
		||||
	var err error
 | 
			
		||||
	offset := limit * (page - 1)
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("created_at DESC").Where("subject LIKE ? OR program LIKE ? OR name LIKE ?", "%"+q+"%", "%"+q+"%", "%"+q+"%").Find(&userQuizPapers).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Offset(offset).Limit(limit).Order("created_at DESC").Find(&userQuizPapers).Error
 | 
			
		||||
	}
 | 
			
		||||
	return userQuizPapers, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) Total(q string) (int64, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	var err error
 | 
			
		||||
	if q != "" {
 | 
			
		||||
		err = r.DB.Model(&models.UserQuizPaper{}).Where("subject LIKE ? OR program LIKE ? OR name LIKE ?", "%"+q+"%", "%"+q+"%", "%"+q+"%").Count(&total).Error
 | 
			
		||||
	} else {
 | 
			
		||||
		err = r.DB.Model(&models.UserQuizPaper{}).Count(&total).Error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) Find(id int64) (*models.UserQuizPaper, error) {
 | 
			
		||||
	var userQuizPaper *models.UserQuizPaper
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&userQuizPaper).Error
 | 
			
		||||
	return userQuizPaper, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) Create(userQuizPaper *models.UserQuizPaper) (*models.UserQuizPaper, error) {
 | 
			
		||||
	err := r.DB.Create(&userQuizPaper).Error
 | 
			
		||||
	return userQuizPaper, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) Insert(items []models.UserQuizPaper) ([]models.UserQuizPaper, error) {
 | 
			
		||||
	err := r.DB.Create(&items).Error
 | 
			
		||||
	return items, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) Update(userQuizPaper *models.UserQuizPaper) (*models.UserQuizPaper, error) {
 | 
			
		||||
	var row *models.UserQuizPaper
 | 
			
		||||
	if err := r.DB.Where("id=?", userQuizPaper.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&userQuizPaper).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRepository) Delete(id string) error {
 | 
			
		||||
	var userQuizPaper *models.UserQuizPaper
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&userQuizPaper).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&userQuizPaper).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								internal/routers/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								internal/routers/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitAuthRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewAuthRouter(db, router)
 | 
			
		||||
	r.SetAuthRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AuthRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type authRouter struct {
 | 
			
		||||
	db              *gorm.DB
 | 
			
		||||
	userRepository  repositories.UserRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
	service         services.AuthService
 | 
			
		||||
	tokenService    services.TokenService
 | 
			
		||||
	controller      controllers.AuthController
 | 
			
		||||
	router          *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAuthRouter(db *gorm.DB, router *gin.Engine) *authRouter {
 | 
			
		||||
	userRepository := repositories.NewUserRepository(db)
 | 
			
		||||
	tokenRepository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewAuthService(userRepository, tokenRepository)
 | 
			
		||||
	tokenService := services.NewTokenService(tokenRepository)
 | 
			
		||||
	controller := controllers.NewAuthController(service, tokenService)
 | 
			
		||||
 | 
			
		||||
	return &authRouter{
 | 
			
		||||
		db:              db,
 | 
			
		||||
		userRepository:  userRepository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
		service:         service,
 | 
			
		||||
		tokenService:    tokenService,
 | 
			
		||||
		controller:      controller,
 | 
			
		||||
		router:          router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *authRouter) SetAuthRouter() {
 | 
			
		||||
	group := r.router.Group("/auth")
 | 
			
		||||
	group.POST("login", r.controller.Login)
 | 
			
		||||
	group.POST("register", r.controller.Register)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								internal/routers/center.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								internal/routers/center.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/middleware"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitCenterRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewCenterRouter(db, router)
 | 
			
		||||
	r.SetCenterRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CenterRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type centerRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.CenterRepository
 | 
			
		||||
	service    services.CenterService
 | 
			
		||||
	controller controllers.CenterController
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCenterRouter(db *gorm.DB, router *gin.Engine) *centerRouter {
 | 
			
		||||
	repository := repositories.NewCenterRepository(db)
 | 
			
		||||
	tokenRepository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewCenterService(repository, tokenRepository)
 | 
			
		||||
 | 
			
		||||
	tokenService := services.NewTokenService(tokenRepository)
 | 
			
		||||
	controller := controllers.NewCenterController(service, tokenService)
 | 
			
		||||
 | 
			
		||||
	return ¢erRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *centerRouter) SetCenterRouter() {
 | 
			
		||||
	group := r.router.Group("/center")
 | 
			
		||||
	group.GET("", middleware.Auth("admin"), r.controller.List)
 | 
			
		||||
	group.GET("/:id", middleware.Auth("admin"), r.controller.Find)
 | 
			
		||||
	group.POST("", middleware.Auth("admin"), r.controller.Create)
 | 
			
		||||
	group.PUT("/:id", middleware.Auth("admin"), r.controller.Update)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								internal/routers/quiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								internal/routers/quiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/middleware"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitQuizRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewQuizRouter(db, router)
 | 
			
		||||
	r.SetQuizRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quizRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.QuizRepository
 | 
			
		||||
	service    services.QuizService
 | 
			
		||||
	controller controllers.QuizController
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizRouter(db *gorm.DB, router *gin.Engine) *quizRouter {
 | 
			
		||||
	repository := repositories.NewQuizRepository(db)
 | 
			
		||||
	service := services.NewQuizService(repository)
 | 
			
		||||
	controller := controllers.NewQuizController(service)
 | 
			
		||||
 | 
			
		||||
	return &quizRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizRouter) SetQuizRouter() {
 | 
			
		||||
	group := r.router.Group("/quiz")
 | 
			
		||||
	group.GET("", middleware.Auth("admin"), r.controller.List)
 | 
			
		||||
	group.GET("/:id", middleware.Auth("admin"), r.controller.Find)
 | 
			
		||||
	group.POST("", middleware.Auth("admin"), r.controller.Create)
 | 
			
		||||
	group.PUT("/:id", middleware.Auth("admin"), r.controller.Update)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								internal/routers/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								internal/routers/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/middleware"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitQuizPaperRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewQuizPaperRouter(db, router)
 | 
			
		||||
	r.SetQuizPaperRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quizPaperRouter struct {
 | 
			
		||||
	db             *gorm.DB
 | 
			
		||||
	repository     repositories.QuizPaperRepository
 | 
			
		||||
	quizRepository repositories.QuizRepository
 | 
			
		||||
	service        services.QuizPaperService
 | 
			
		||||
	quizService    services.QuizService
 | 
			
		||||
	controller     controllers.QuizPaperController
 | 
			
		||||
	router         *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizPaperRouter(db *gorm.DB, router *gin.Engine) *quizPaperRouter {
 | 
			
		||||
	repository := repositories.NewQuizPaperRepository(db)
 | 
			
		||||
	quizRepository := repositories.NewQuizRepository(db)
 | 
			
		||||
	service := services.NewQuizPaperService(repository)
 | 
			
		||||
	quizService := services.NewQuizService(quizRepository)
 | 
			
		||||
	controller := controllers.NewQuizPaperController(service, quizService)
 | 
			
		||||
 | 
			
		||||
	return &quizPaperRouter{
 | 
			
		||||
		db:             db,
 | 
			
		||||
		repository:     repository,
 | 
			
		||||
		quizRepository: quizRepository,
 | 
			
		||||
		service:        service,
 | 
			
		||||
		quizService:    quizService,
 | 
			
		||||
		controller:     controller,
 | 
			
		||||
		router:         router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *quizPaperRouter) SetQuizPaperRouter() {
 | 
			
		||||
	group := r.router.Group("/quizpaper")
 | 
			
		||||
	group.GET("", middleware.Auth("admin"), r.controller.List)
 | 
			
		||||
	group.GET("/:id", middleware.Auth("admin"), r.controller.Find)
 | 
			
		||||
	group.POST("", middleware.Auth("admin"), r.controller.Create)
 | 
			
		||||
	group.PUT("/:id", middleware.Auth("admin"), r.controller.Update)
 | 
			
		||||
	group.POST("/:id/copy", middleware.Auth("admin"), r.controller.Copy)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								internal/routers/router.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								internal/routers/router.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/database"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-contrib/cors"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var Router *gin.Engine
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	gin.SetMode(gin.ReleaseMode)
 | 
			
		||||
	Router = gin.Default()
 | 
			
		||||
	config := cors.DefaultConfig()
 | 
			
		||||
	config.AllowOrigins = []string{"http://127.0.0.1:3000", "http://localhost:3000", "http://localhost:3030", "https://learnsteam-quiz.jongyeob.com"}
 | 
			
		||||
	config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "PATCH"}
 | 
			
		||||
	config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type"}
 | 
			
		||||
	Router.Use(cors.New(config))
 | 
			
		||||
 | 
			
		||||
	maindb := database.GetDB()
 | 
			
		||||
 | 
			
		||||
	InitAuthRouter(maindb, Router)
 | 
			
		||||
	InitCenterRouter(maindb, Router)
 | 
			
		||||
	InitQuizPaperRouter(maindb, Router)
 | 
			
		||||
	InitQuizRouter(maindb, Router)
 | 
			
		||||
	InitTokenRouter(maindb, Router)
 | 
			
		||||
	InitUserQuizPaperRouter(maindb, Router)
 | 
			
		||||
	InitUserQuizRouter(maindb, Router)
 | 
			
		||||
	InitUserRouter(maindb, Router)
 | 
			
		||||
 | 
			
		||||
	InitSwaggerRouter(Router)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								internal/routers/swagger.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								internal/routers/swagger.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
 | 
			
		||||
	swaggerFiles "github.com/swaggo/files"
 | 
			
		||||
	ginSwagger "github.com/swaggo/gin-swagger"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitSwaggerRouter(router *gin.Engine) {
 | 
			
		||||
	r := NewSwaggerRouter(router)
 | 
			
		||||
	r.SetSwaggerRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SwaggerRouter interface {
 | 
			
		||||
	SetRouter(router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type swaggerRouter struct {
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
	controller controllers.SwaggerController
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSwaggerRouter(router *gin.Engine) *swaggerRouter {
 | 
			
		||||
	controller := controllers.NewSwaggerController()
 | 
			
		||||
	return &swaggerRouter{
 | 
			
		||||
		router:     router,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *swaggerRouter) SetSwaggerRouter() {
 | 
			
		||||
	group := r.router.Group("/swagger")
 | 
			
		||||
	group.GET("*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								internal/routers/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								internal/routers/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitTokenRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewTokenRouter(db, router)
 | 
			
		||||
	r.SetTokenRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tokenRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.TokenRepository
 | 
			
		||||
	service    services.TokenService
 | 
			
		||||
	controller controllers.TokenController
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenRouter(db *gorm.DB, router *gin.Engine) *tokenRouter {
 | 
			
		||||
	repository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewTokenService(repository)
 | 
			
		||||
	controller := controllers.NewTokenController(service)
 | 
			
		||||
 | 
			
		||||
	return &tokenRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRouter) SetTokenRouter() {
 | 
			
		||||
	group := r.router.Group("/token")
 | 
			
		||||
	group.POST("refresh", r.controller.Refresh)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								internal/routers/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								internal/routers/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/middleware"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitUserRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewUserRouter(db, router)
 | 
			
		||||
	r.SetUserRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.UserRepository
 | 
			
		||||
	service    services.UserService
 | 
			
		||||
	controller controllers.UserController
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserRouter(db *gorm.DB, router *gin.Engine) *userRouter {
 | 
			
		||||
	repository := repositories.NewUserRepository(db)
 | 
			
		||||
	tokenRepository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewUserService(repository, tokenRepository)
 | 
			
		||||
 | 
			
		||||
	tokenService := services.NewTokenService(tokenRepository)
 | 
			
		||||
	controller := controllers.NewUserController(service, tokenService)
 | 
			
		||||
 | 
			
		||||
	return &userRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRouter) SetUserRouter() {
 | 
			
		||||
	group := r.router.Group("/user")
 | 
			
		||||
	group.GET("", middleware.Auth("admin"), r.controller.List)
 | 
			
		||||
	group.GET("/:id", middleware.Auth("admin"), r.controller.Find)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								internal/routers/userquiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								internal/routers/userquiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/middleware"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitUserQuizRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewUserQuizRouter(db, router)
 | 
			
		||||
	r.SetUserQuizRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userQuizRouter struct {
 | 
			
		||||
	db             *gorm.DB
 | 
			
		||||
	repository     repositories.UserQuizRepository
 | 
			
		||||
	quizRepository repositories.QuizRepository
 | 
			
		||||
	service        services.UserQuizService
 | 
			
		||||
	controller     controllers.UserQuizController
 | 
			
		||||
	router         *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizRouter(db *gorm.DB, router *gin.Engine) *userQuizRouter {
 | 
			
		||||
	repository := repositories.NewUserQuizRepository(db)
 | 
			
		||||
	quizRepostory := repositories.NewQuizRepository(db)
 | 
			
		||||
	service := services.NewUserQuizService(repository, quizRepostory)
 | 
			
		||||
	controller := controllers.NewUserQuizController(service)
 | 
			
		||||
 | 
			
		||||
	return &userQuizRouter{
 | 
			
		||||
		db:             db,
 | 
			
		||||
		repository:     repository,
 | 
			
		||||
		quizRepository: quizRepostory,
 | 
			
		||||
		service:        service,
 | 
			
		||||
		controller:     controller,
 | 
			
		||||
		router:         router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizRouter) SetUserQuizRouter() {
 | 
			
		||||
	group := r.router.Group("/userquiz")
 | 
			
		||||
	group.GET("", middleware.Auth("admin"), r.controller.List)
 | 
			
		||||
	group.GET("/:id", middleware.Auth("admin"), r.controller.Find)
 | 
			
		||||
	group.POST("", middleware.Auth("admin"), r.controller.Create)
 | 
			
		||||
	group.PUT("/:id", middleware.Auth("admin"), r.controller.Update)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								internal/routers/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								internal/routers/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/middleware"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitUserQuizPaperRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewUserQuizPaperRouter(db, router)
 | 
			
		||||
	r.SetUserQuizPaperRouter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userQuizPaperRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.UserQuizPaperRepository
 | 
			
		||||
	service    services.UserQuizPaperService
 | 
			
		||||
	controller controllers.UserQuizPaperController
 | 
			
		||||
	// quizPaperRepository repositories.QuizPaperRepository
 | 
			
		||||
	// userRepository      repositories.UserRepository
 | 
			
		||||
 | 
			
		||||
	// quizPaperService services.QuizPaperService
 | 
			
		||||
	// userService      services.UserService
 | 
			
		||||
 | 
			
		||||
	router *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizPaperRouter(db *gorm.DB, router *gin.Engine) *userQuizPaperRouter {
 | 
			
		||||
	repository := repositories.NewUserQuizPaperRepository(db)
 | 
			
		||||
	quizRepository := repositories.NewQuizRepository(db)
 | 
			
		||||
	quizPaperRepository := repositories.NewQuizPaperRepository(db)
 | 
			
		||||
	tokenRepository := repositories.NewTokenRepository(db)
 | 
			
		||||
	userRepository := repositories.NewUserRepository(db)
 | 
			
		||||
	userQuizRepository := repositories.NewUserQuizRepository(db)
 | 
			
		||||
 | 
			
		||||
	service := services.NewUserQuizPaperService(repository)
 | 
			
		||||
	quizPaperService := services.NewQuizPaperService(quizPaperRepository)
 | 
			
		||||
	userService := services.NewUserService(userRepository, tokenRepository)
 | 
			
		||||
	userQuizService := services.NewUserQuizService(userQuizRepository, quizRepository)
 | 
			
		||||
 | 
			
		||||
	controller := controllers.NewUserQuizPaperController(service, userService, quizPaperService, userQuizService)
 | 
			
		||||
 | 
			
		||||
	return &userQuizPaperRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userQuizPaperRouter) SetUserQuizPaperRouter() {
 | 
			
		||||
	group := r.router.Group("/userquizpaper")
 | 
			
		||||
	group.GET("", middleware.Auth("admin"), r.controller.List)
 | 
			
		||||
	group.GET("/:id", middleware.Auth("admin"), r.controller.Find)
 | 
			
		||||
	group.POST("", middleware.Auth("admin"), r.controller.Create)
 | 
			
		||||
	group.PUT("/:id", middleware.Auth("admin"), r.controller.Update)
 | 
			
		||||
	group.PATCH("/:id", middleware.Auth("admin"), r.controller.Patch)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								internal/services/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								internal/services/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type authService struct {
 | 
			
		||||
	userRepository  repositories.UserRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AuthService interface {
 | 
			
		||||
	Register(*models.RegisterRequest) (*models.User, error)
 | 
			
		||||
	Login(*models.LoginRequest) (*models.User, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAuthService(userRepository repositories.UserRepository, tokenRepository repositories.TokenRepository) AuthService {
 | 
			
		||||
	return &authService{
 | 
			
		||||
		userRepository:  userRepository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *authService) Register(request *models.RegisterRequest) (*models.User, error) {
 | 
			
		||||
	hash, err := bcrypt.GenerateFromPassword([]byte(request.Password), 10)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("fail to hash password")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create the user
 | 
			
		||||
	newUser := models.User{
 | 
			
		||||
		GUID:       uuid.NewString(),
 | 
			
		||||
		FirstName:  request.FirstName,
 | 
			
		||||
		LastName:   request.LastName,
 | 
			
		||||
		Username:   request.Username,
 | 
			
		||||
		Password:   string(hash),
 | 
			
		||||
		Gender:     request.Gender,
 | 
			
		||||
		Phone:      request.Phone,
 | 
			
		||||
		UserRole:   request.UserRole,
 | 
			
		||||
		Image:      request.Image,
 | 
			
		||||
		RegisterAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println(newUser)
 | 
			
		||||
 | 
			
		||||
	user, err := s.userRepository.Create(&newUser)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("fail to create user")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *authService) Login(request *models.LoginRequest) (*models.User, error) {
 | 
			
		||||
	user, err := s.userRepository.FindByUsername(request.Username)
 | 
			
		||||
	if err != nil || user == nil {
 | 
			
		||||
		return nil, errors.New("invalid user or password")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(request.Password))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("invalid user or password")
 | 
			
		||||
	}
 | 
			
		||||
	return user, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								internal/services/center.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								internal/services/center.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type centerService struct {
 | 
			
		||||
	repository      repositories.CenterRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CenterService interface {
 | 
			
		||||
	List(string, int, int) (*[]models.Center, error)
 | 
			
		||||
	Total(string) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.Center, error)
 | 
			
		||||
	FindByTitle(string) (*models.Center, error)
 | 
			
		||||
 | 
			
		||||
	Create(*models.Center) (*models.Center, error)
 | 
			
		||||
	Update(*models.Center) (*models.Center, error)
 | 
			
		||||
	Delete(int64) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewCenterService(repository repositories.CenterRepository, tokenRepository repositories.TokenRepository) CenterService {
 | 
			
		||||
	return ¢erService{
 | 
			
		||||
		repository:      repository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) List(q string, page int, limit int) (*[]models.Center, error) {
 | 
			
		||||
	return s.repository.List(q, page, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) Total(q string) (int64, error) {
 | 
			
		||||
	return s.repository.Total(q)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) Find(id int64) (*models.Center, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) FindByTitle(centername string) (*models.Center, error) {
 | 
			
		||||
	return s.repository.FindByTitle(centername)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) Create(center *models.Center) (*models.Center, error) {
 | 
			
		||||
	result, err := s.repository.Create(center)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) Update(center *models.Center) (*models.Center, error) {
 | 
			
		||||
	result, err := s.repository.Update(center)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *centerService) Delete(id int64) error {
 | 
			
		||||
	err := s.repository.Delete(id)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								internal/services/quiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								internal/services/quiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type quizService struct {
 | 
			
		||||
	repository repositories.QuizRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizService interface {
 | 
			
		||||
	List(int64, int, int) (*[]models.Quiz, error)
 | 
			
		||||
	Total(int64) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.Quiz, error)
 | 
			
		||||
	Create(*models.Quiz) (*models.Quiz, error)
 | 
			
		||||
	Update(*models.Quiz) (*models.Quiz, error)
 | 
			
		||||
	Delete(int64) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizService(repository repositories.QuizRepository) QuizService {
 | 
			
		||||
	return &quizService{
 | 
			
		||||
		repository: repository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) List(quiz_paper_id int64, page int, limit int) (*[]models.Quiz, error) {
 | 
			
		||||
	return s.repository.List(quiz_paper_id, page, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) Total(quiz_paper_id int64) (int64, error) {
 | 
			
		||||
	return s.repository.Total(quiz_paper_id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) Find(id int64) (*models.Quiz, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) Create(quiz *models.Quiz) (*models.Quiz, error) {
 | 
			
		||||
	result, err := s.repository.Create(quiz)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) Update(quiz *models.Quiz) (*models.Quiz, error) {
 | 
			
		||||
	result, err := s.repository.Update(quiz)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) Delete(id int64) error {
 | 
			
		||||
	err := s.repository.Delete(id)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizService) Generate(quizpaper *models.QuizPaper) ([]models.Quiz, error) {
 | 
			
		||||
	templates, err := s.repository.List(quizpaper.ID, 1, 1000)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var quizzes []models.Quiz
 | 
			
		||||
	for _, q := range *templates {
 | 
			
		||||
		quiz := models.Quiz{
 | 
			
		||||
			GUID:         uuid.NewString(),
 | 
			
		||||
			CenterID:     quizpaper.CenterID,
 | 
			
		||||
			QuizPaperID:  quizpaper.ID,
 | 
			
		||||
			No:           q.No,
 | 
			
		||||
			QuestionType: q.QuestionType,
 | 
			
		||||
			Question:     q.Question,
 | 
			
		||||
			Content:      q.Content,
 | 
			
		||||
			Answer:       q.Answer,
 | 
			
		||||
			UpdatedAt:    time.Now(),
 | 
			
		||||
			CreatedAt:    time.Now(),
 | 
			
		||||
		}
 | 
			
		||||
		quizzes = append(quizzes, quiz)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return quizzes, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								internal/services/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								internal/services/quizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type quizPaperService struct {
 | 
			
		||||
	repository repositories.QuizPaperRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QuizPaperService interface {
 | 
			
		||||
	List(string, string, int, int) (*[]models.QuizPaper, error)
 | 
			
		||||
	Total(string, string) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.QuizPaper, error)
 | 
			
		||||
	Create(*models.QuizPaper) (*models.QuizPaper, error)
 | 
			
		||||
	Update(*models.QuizPaper) (*models.QuizPaper, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewQuizPaperService(repository repositories.QuizPaperRepository) QuizPaperService {
 | 
			
		||||
	return &quizPaperService{
 | 
			
		||||
		repository: repository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizPaperService) List(q string, tag string, page int, limit int) (*[]models.QuizPaper, error) {
 | 
			
		||||
	return s.repository.List(q, tag, page, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizPaperService) Total(q string, tag string) (int64, error) {
 | 
			
		||||
	return s.repository.Total(q, tag)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizPaperService) Find(id int64) (*models.QuizPaper, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizPaperService) Create(quizPaper *models.QuizPaper) (*models.QuizPaper, error) {
 | 
			
		||||
	result, err := s.repository.Create(quizPaper)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizPaperService) Update(quizPaper *models.QuizPaper) (*models.QuizPaper, error) {
 | 
			
		||||
	result, err := s.repository.Update(quizPaper)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *quizPaperService) Delete(id string) error {
 | 
			
		||||
	err := s.repository.Delete(id)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										200
									
								
								internal/services/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								internal/services/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,200 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	config "learnsteam/cslms-api/configs"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang-jwt/jwt/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tokenService struct {
 | 
			
		||||
	repository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenService interface {
 | 
			
		||||
	Find(int64) (*models.Token, error)
 | 
			
		||||
	Create(int64, string) (*models.Token, error)
 | 
			
		||||
	Update(*models.Token) (*models.Token, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
 | 
			
		||||
	Refresh(string) (*models.Token, error)
 | 
			
		||||
 | 
			
		||||
	Generate(string, int64, string) (string, error)
 | 
			
		||||
	Verify(tokenString string) (*jwt.Token, error)
 | 
			
		||||
 | 
			
		||||
	GetJwtToken(string) (*jwt.Token, error)
 | 
			
		||||
	ExtractTokenString(string) string
 | 
			
		||||
	VerifyTokenString(string) (*jwt.Token, error)
 | 
			
		||||
	ValidToken(*jwt.Token) (bool, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenService(repository repositories.TokenRepository) TokenService {
 | 
			
		||||
	return &tokenService{
 | 
			
		||||
		repository: repository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Find(id int64) (*models.Token, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Create(user_id int64, role string) (*models.Token, error) {
 | 
			
		||||
	expiredAt := time.Now().Add(time.Hour * 24 * 30)
 | 
			
		||||
	accessToken, err := s.repository.Generate(user_id, expiredAt.Unix(), role)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
 | 
			
		||||
	refreshToken, err := s.repository.Generate(user_id, refreshExpiredAt.Unix(), role)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newToken := &models.Token{
 | 
			
		||||
		UserID:       user_id,
 | 
			
		||||
		Token:        accessToken,
 | 
			
		||||
		RefreshToken: refreshToken,
 | 
			
		||||
		Status:       "on",
 | 
			
		||||
		EndingAt:     expiredAt,
 | 
			
		||||
		RegisterAt:   time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := s.repository.Create(newToken)
 | 
			
		||||
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Update(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	return s.repository.Update(token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Delete(id string) error {
 | 
			
		||||
	return s.repository.Delete(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Verify(tokenString string) (*jwt.Token, error) {
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return jwtToken, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Generate(user_id string, expire_at int64, role string) (string, error) {
 | 
			
		||||
	claims := jwt.MapClaims{}
 | 
			
		||||
	claims["authorized"] = true
 | 
			
		||||
	claims["sub"] = user_id
 | 
			
		||||
	claims["exp"] = expire_at
 | 
			
		||||
	claims["role"] = role
 | 
			
		||||
	at := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 | 
			
		||||
	token, err := at.SignedString([]byte(config.SECRET_KEY))
 | 
			
		||||
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) GetJwtToken(tokenString string) (*jwt.Token, error) {
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
	return jwtToken, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) ExtractTokenString(authorization string) string {
 | 
			
		||||
	strArr := strings.Split(authorization, " ")
 | 
			
		||||
	if len(strArr) == 2 {
 | 
			
		||||
		return strArr[1]
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) VerifyTokenString(tokenString string) (*jwt.Token, error) {
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return jwtToken, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) ValidToken(jwtToken *jwt.Token) (bool, error) {
 | 
			
		||||
	if jwtToken == nil {
 | 
			
		||||
		return false, fmt.Errorf("no token")
 | 
			
		||||
	}
 | 
			
		||||
	return jwtToken.Valid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Refresh(refreshToken string) (*models.Token, error) {
 | 
			
		||||
	fmt.Println("refresh_token", refreshToken)
 | 
			
		||||
 | 
			
		||||
	jwtToken, err := jwt.Parse(refreshToken, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("refresh token is not valid")
 | 
			
		||||
	} else {
 | 
			
		||||
 | 
			
		||||
		fmt.Println("refresh token is  valid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("error", err.Error())
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	claims, ok := jwtToken.Claims.(jwt.MapClaims)
 | 
			
		||||
	if !ok || !jwtToken.Valid {
 | 
			
		||||
		return nil, errors.New("refresh token is invalid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sub := claims["sub"].(int64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("wrong user")
 | 
			
		||||
	}
 | 
			
		||||
	role := claims["role"].(string)
 | 
			
		||||
 | 
			
		||||
	token, err := s.repository.FindByRefreshToken(sub, refreshToken)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("wrong token")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expiredAt := time.Now().Add(time.Hour * 24 * 30)
 | 
			
		||||
	accessToken, err := s.repository.Generate(sub, expiredAt.Unix(), role)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
 | 
			
		||||
	refreshToken, err = s.repository.Generate(sub, refreshExpiredAt.Unix(), role)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token.Token = accessToken
 | 
			
		||||
	token.EndingAt = expiredAt
 | 
			
		||||
	token.RefreshToken = refreshToken
 | 
			
		||||
 | 
			
		||||
	return s.repository.Update(token)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								internal/services/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								internal/services/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userService struct {
 | 
			
		||||
	repository      repositories.UserRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserService interface {
 | 
			
		||||
	List(string, int, int) (*[]models.User, error)
 | 
			
		||||
	Total(string) (int64, error)
 | 
			
		||||
	Find(int64) (*models.User, error)
 | 
			
		||||
	FindByUsername(string) (*models.User, error)
 | 
			
		||||
	Create(*models.User) (*models.User, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserService(repository repositories.UserRepository, tokenRepository repositories.TokenRepository) UserService {
 | 
			
		||||
	return &userService{
 | 
			
		||||
		repository:      repository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) List(q string, page int, limit int) (*[]models.User, error) {
 | 
			
		||||
	return s.repository.List(q, page, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) Total(q string) (int64, error) {
 | 
			
		||||
	return s.repository.Total(q)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) Find(id int64) (*models.User, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) FindByUsername(username string) (*models.User, error) {
 | 
			
		||||
	return s.repository.FindByUsername(username)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) Create(user *models.User) (*models.User, error) {
 | 
			
		||||
	result, err := s.repository.Create(user)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								internal/services/userquiz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								internal/services/userquiz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userQuizService struct {
 | 
			
		||||
	repository     repositories.UserQuizRepository
 | 
			
		||||
	quizRepository repositories.QuizRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizService interface {
 | 
			
		||||
	List(int64, int, int) (*[]models.UserQuiz, error)
 | 
			
		||||
	Total(int64) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.UserQuiz, error)
 | 
			
		||||
	Create(*models.UserQuiz) (*models.UserQuiz, error)
 | 
			
		||||
	Insert([]models.UserQuiz) ([]models.UserQuiz, error)
 | 
			
		||||
	Update(*models.UserQuiz) (*models.UserQuiz, error)
 | 
			
		||||
	Delete(int64) error
 | 
			
		||||
	Generate(int64, *models.UserQuizPaper) ([]models.UserQuiz, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizService(repository repositories.UserQuizRepository, quizRepository repositories.QuizRepository) UserQuizService {
 | 
			
		||||
	return &userQuizService{
 | 
			
		||||
		repository:     repository,
 | 
			
		||||
		quizRepository: quizRepository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) List(user_quiz_paper_id int64, page int, limit int) (*[]models.UserQuiz, error) {
 | 
			
		||||
	return s.repository.List(user_quiz_paper_id, page, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Total(user_quiz_paper_id int64) (int64, error) {
 | 
			
		||||
	return s.repository.Total(user_quiz_paper_id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Find(id int64) (*models.UserQuiz, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Create(quiz *models.UserQuiz) (*models.UserQuiz, error) {
 | 
			
		||||
	result, err := s.repository.Create(quiz)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Insert(items []models.UserQuiz) ([]models.UserQuiz, error) {
 | 
			
		||||
	result, err := s.repository.Insert(items)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Update(quiz *models.UserQuiz) (*models.UserQuiz, error) {
 | 
			
		||||
	result, err := s.repository.Update(quiz)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Delete(id int64) error {
 | 
			
		||||
	err := s.repository.Delete(id)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizService) Generate(quiz_paper_id int64, userQuizPaper *models.UserQuizPaper) ([]models.UserQuiz, error) {
 | 
			
		||||
	var userQuizzes []models.UserQuiz
 | 
			
		||||
	quizzes, err := s.quizRepository.List(quiz_paper_id, 1, 1000)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, quiz := range *quizzes {
 | 
			
		||||
		userQuiz := models.UserQuiz{
 | 
			
		||||
			GUID:            quiz.GUID,
 | 
			
		||||
			CenterID:        quiz.CenterID,
 | 
			
		||||
			UserQuizPaperID: userQuizPaper.ID,
 | 
			
		||||
			UserID:          userQuizPaper.UserID,
 | 
			
		||||
			No:              quiz.No,
 | 
			
		||||
			QuestionType:    quiz.QuestionType,
 | 
			
		||||
			Question:        quiz.Question,
 | 
			
		||||
			Content:         quiz.Content,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Println(userQuiz.Content)
 | 
			
		||||
		// fmt.Println(userQuiz.Answer)
 | 
			
		||||
		userQuizzes = append(userQuizzes, userQuiz)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return userQuizzes, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								internal/services/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								internal/services/userquizpaper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/models"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userQuizPaperService struct {
 | 
			
		||||
	repository repositories.UserQuizPaperRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserQuizPaperService interface {
 | 
			
		||||
	List(string, int, int) (*[]models.UserQuizPaper, error)
 | 
			
		||||
	Total(string) (int64, error)
 | 
			
		||||
 | 
			
		||||
	Find(int64) (*models.UserQuizPaper, error)
 | 
			
		||||
	Create(*models.UserQuizPaper) (*models.UserQuizPaper, error)
 | 
			
		||||
	Insert([]models.UserQuizPaper) ([]models.UserQuizPaper, error)
 | 
			
		||||
	Update(*models.UserQuizPaper) (*models.UserQuizPaper, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
	Generate([]int64, *models.QuizPaper) []models.UserQuizPaper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserQuizPaperService(repository repositories.UserQuizPaperRepository) UserQuizPaperService {
 | 
			
		||||
	return &userQuizPaperService{
 | 
			
		||||
		repository: repository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) List(q string, page int, limit int) (*[]models.UserQuizPaper, error) {
 | 
			
		||||
	return s.repository.List(q, page, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Total(q string) (int64, error) {
 | 
			
		||||
	return s.repository.Total(q)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Find(id int64) (*models.UserQuizPaper, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Create(userQuizPaper *models.UserQuizPaper) (*models.UserQuizPaper, error) {
 | 
			
		||||
	result, err := s.repository.Create(userQuizPaper)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Insert(items []models.UserQuizPaper) ([]models.UserQuizPaper, error) {
 | 
			
		||||
	result, err := s.repository.Insert(items)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Update(userQuizPaper *models.UserQuizPaper) (*models.UserQuizPaper, error) {
 | 
			
		||||
	result, err := s.repository.Update(userQuizPaper)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Delete(id string) error {
 | 
			
		||||
	err := s.repository.Delete(id)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userQuizPaperService) Generate(users []int64, quizPaper *models.QuizPaper) []models.UserQuizPaper {
 | 
			
		||||
	var userQuizPapers []models.UserQuizPaper
 | 
			
		||||
 | 
			
		||||
	for _, user_id := range users {
 | 
			
		||||
		userQuizPaper := models.UserQuizPaper{
 | 
			
		||||
			GUID:        uuid.NewString(),
 | 
			
		||||
			CenterID:    quizPaper.CenterID,
 | 
			
		||||
			UserID:      user_id,
 | 
			
		||||
			QuizPaperID: quizPaper.ID,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		userQuizPapers = append(userQuizPapers, userQuizPaper)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return userQuizPapers
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										170
									
								
								test/program_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								test/program_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
package learsteam_quiz_test
 | 
			
		||||
 | 
			
		||||
// type ProgramTestSuite struct {
 | 
			
		||||
// 	suite.Suite
 | 
			
		||||
// 	db         *gorm.DB
 | 
			
		||||
// 	repository repositories.ProgramRepository
 | 
			
		||||
// 	service    services.ProgramService
 | 
			
		||||
// 	controller controllers.ProgramController
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *ProgramTestSuite) SetupSuite() {
 | 
			
		||||
// 	// err := os.Remove("test.db")
 | 
			
		||||
// 	// if err != nil {
 | 
			
		||||
// 	// 	suite.Fail("Failed to remove the test database file")
 | 
			
		||||
// 	// }
 | 
			
		||||
 | 
			
		||||
// 	gorm_config := gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}}
 | 
			
		||||
// 	db, _ := gorm.Open(sqlite.Open("test.db"), &gorm_config)
 | 
			
		||||
// 	db.AutoMigrate(&models.Program{})
 | 
			
		||||
 | 
			
		||||
// 	repository := repositories.NewProgramRepository(db)
 | 
			
		||||
// 	service := services.NewProgramService(repository)
 | 
			
		||||
// 	controller := controllers.NewProgramController(service)
 | 
			
		||||
 | 
			
		||||
// 	suite.db = db
 | 
			
		||||
// 	suite.service = service
 | 
			
		||||
// 	suite.repository = repository
 | 
			
		||||
// 	suite.controller = controller
 | 
			
		||||
 | 
			
		||||
// 	suite.CreateSampleData()
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *ProgramTestSuite) CreateSampleData() {
 | 
			
		||||
// 	var programs []models.Program
 | 
			
		||||
// 	for i := 1; i < 101; i++ {
 | 
			
		||||
// 		t := []string{"tag" + strconv.Itoa(i), "taga", "tagb"}
 | 
			
		||||
// 		var j datatypes.JSON
 | 
			
		||||
// 		j, _ = json.Marshal(t)
 | 
			
		||||
// 		p := models.Program{
 | 
			
		||||
// 			ID:        strconv.Itoa(i) + "_id",
 | 
			
		||||
// 			Subject:   strconv.Itoa(i) + " subject",
 | 
			
		||||
// 			Content:   strconv.Itoa(i) + " content",
 | 
			
		||||
// 			Tag:       j,
 | 
			
		||||
// 			Tags:      j.String(),
 | 
			
		||||
// 			Status:    "on",
 | 
			
		||||
// 			PublishAt: time.Now(),
 | 
			
		||||
// 			UpdatedAt: time.Now(),
 | 
			
		||||
// 			CreatedAt: time.Now(),
 | 
			
		||||
// 		}
 | 
			
		||||
// 		programs = append(programs, p)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	for _, program := range programs {
 | 
			
		||||
// 		suite.db.Create(&program)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *ProgramTestSuite) TearDownSuite() {
 | 
			
		||||
// 	// DB 삭제
 | 
			
		||||
// 	suite.db.Migrator().DropTable(&models.Program{})
 | 
			
		||||
// 	err := os.Remove("test.db")
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		suite.Fail("Failed to remove the test database file")
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *ProgramTestSuite) SetupTest() {
 | 
			
		||||
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *ProgramTestSuite) TearDownTest() {
 | 
			
		||||
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func TestProgramSuite(t *testing.T) {
 | 
			
		||||
// 	suite.Run(t, new(ProgramTestSuite))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 목록 테스트 : 1page, 10개
 | 
			
		||||
// func (suite *ProgramTestSuite) TestListProgramSuccess() {
 | 
			
		||||
// 	programs, err := suite.repository.List("", "", 1, 10)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), programs)
 | 
			
		||||
// 	assert.Equal(suite.T(), 10, len(*programs))
 | 
			
		||||
// 	program0 := (*programs)[0]
 | 
			
		||||
// 	assert.Equal(suite.T(), "100_id", program0.ID)
 | 
			
		||||
 | 
			
		||||
// 	program9 := (*programs)[9]
 | 
			
		||||
// 	assert.Equal(suite.T(), "91_id", program9.ID)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 목록 테스트 : tag 검색
 | 
			
		||||
// func (suite *ProgramTestSuite) TestListProgramTagSearchSuccess() {
 | 
			
		||||
// 	programs, err := suite.repository.List("", "tag9", 1, 10)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), programs)
 | 
			
		||||
// 	assert.Equal(suite.T(), 10, len(*programs))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // Total 테스트
 | 
			
		||||
// func (suite *ProgramTestSuite) TestTotalSuccess() {
 | 
			
		||||
// 	total, err := suite.repository.Total("", "")
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.Equal(suite.T(), int64(100), total)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // Total 테스트 : tag 검색
 | 
			
		||||
// func (suite *ProgramTestSuite) TestTotalTagSuccess() {
 | 
			
		||||
// 	total, err := suite.repository.Total("", "tag2")
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.Equal(suite.T(), int64(11), total)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // // 수정 테스트
 | 
			
		||||
// // func (suite *ProgramTestSuite) TestUpdateProgramSuccess() {
 | 
			
		||||
// // 	t := []string{"TAG"}
 | 
			
		||||
// // 	var j datatypes.JSON
 | 
			
		||||
// // 	j, _ = json.Marshal(t)
 | 
			
		||||
// // 	p := &models.Program{
 | 
			
		||||
// // 		ID:        uuid.NewString(),
 | 
			
		||||
// // 		Subject:   "My Subject",
 | 
			
		||||
// // 		Content:   "My Content",
 | 
			
		||||
// // 		Tag:       j,
 | 
			
		||||
// // 		Tags:      j.String(),
 | 
			
		||||
// // 		Status:    "on",
 | 
			
		||||
// // 		PublishAt: time.Now(),
 | 
			
		||||
// // 		UpdatedAt: time.Now(),
 | 
			
		||||
// // 		CreatedAt: time.Now(),
 | 
			
		||||
// // 	}
 | 
			
		||||
 | 
			
		||||
// // 	program, err := suite.repository.Create(p)
 | 
			
		||||
// // 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// // 	program.Subject = "My Subject Updated"
 | 
			
		||||
// // 	program.Content = "My Content Updated"
 | 
			
		||||
// // 	program.Tag = j
 | 
			
		||||
// // 	program.Tags = j.String()
 | 
			
		||||
// // 	program.Status = "draft"
 | 
			
		||||
 | 
			
		||||
// // 	updatedProgram, err := suite.repository.Update(program)
 | 
			
		||||
// // 	assert.NoError(suite.T(), err)
 | 
			
		||||
// // 	assert.Equal(suite.T(), program.Subject, updatedProgram.Subject)
 | 
			
		||||
// // 	assert.Equal(suite.T(), program.Content, updatedProgram.Content)
 | 
			
		||||
// // 	assert.Equal(suite.T(), program.Tag, updatedProgram.Tag)
 | 
			
		||||
// // 	assert.Equal(suite.T(), program.Status, updatedProgram.Status)
 | 
			
		||||
// // }
 | 
			
		||||
 | 
			
		||||
// // // 삭제 테스트
 | 
			
		||||
// // func (suite *ProgramTestSuite) TestDeleteProgramSuccess() {
 | 
			
		||||
// // 	t := []string{"TAG"}
 | 
			
		||||
// // 	var j datatypes.JSON
 | 
			
		||||
// // 	j, _ = json.Marshal(t)
 | 
			
		||||
// // 	p := &models.Program{
 | 
			
		||||
// // 		ID:        uuid.NewString(),
 | 
			
		||||
// // 		Subject:   "My Subject",
 | 
			
		||||
// // 		Content:   "My Content",
 | 
			
		||||
// // 		Tag:       j,
 | 
			
		||||
// // 		Tags:      j.String(),
 | 
			
		||||
// // 		Status:    "on",
 | 
			
		||||
// // 		PublishAt: time.Now(),
 | 
			
		||||
// // 		UpdatedAt: time.Now(),
 | 
			
		||||
// // 		CreatedAt: time.Now(),
 | 
			
		||||
// // 	}
 | 
			
		||||
// // 	_, err := suite.repository.Create(p)
 | 
			
		||||
// // 	assert.NoError(suite.T(), err)
 | 
			
		||||
// // 	err = suite.repository.Delete(p.ID)
 | 
			
		||||
// // 	assert.NoError(suite.T(), err)
 | 
			
		||||
// // 	_, err = suite.repository.Find(p.ID)
 | 
			
		||||
// // 	assert.Error(suite.T(), err)
 | 
			
		||||
// // }
 | 
			
		||||
							
								
								
									
										172
									
								
								test/quiz_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								test/quiz_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
package learsteam_quiz_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"learnsteam/cslms-api/internal/controllers"
 | 
			
		||||
	"learnsteam/cslms-api/internal/repositories"
 | 
			
		||||
	"learnsteam/cslms-api/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/suite"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type QuizTestSuite struct {
 | 
			
		||||
	suite.Suite
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.QuizRepository
 | 
			
		||||
	service    services.QuizService
 | 
			
		||||
	controller controllers.QuizController
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// func (suite *QuizTestSuite) SetupSuite() {
 | 
			
		||||
// 	// err := os.Remove("test.db")
 | 
			
		||||
// 	// if err != nil {
 | 
			
		||||
// 	// 	suite.Fail("Failed to remove the test database file")
 | 
			
		||||
// 	// }
 | 
			
		||||
 | 
			
		||||
// 	gorm_config := gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}}
 | 
			
		||||
// 	db, _ := gorm.Open(sqlite.Open("test.db"), &gorm_config)
 | 
			
		||||
// 	db.AutoMigrate(&models.Quiz{})
 | 
			
		||||
 | 
			
		||||
// 	repository := repositories.NewQuizRepository(db)
 | 
			
		||||
// 	service := services.NewQuizService(repository)
 | 
			
		||||
// 	controller := controllers.NewQuizController(service)
 | 
			
		||||
 | 
			
		||||
// 	suite.db = db
 | 
			
		||||
// 	suite.service = service
 | 
			
		||||
// 	suite.repository = repository
 | 
			
		||||
// 	suite.controller = controller
 | 
			
		||||
 | 
			
		||||
// 	suite.CreateSampleData()
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *QuizTestSuite) CreateSampleData() {
 | 
			
		||||
// 	var quizzes []models.Quiz
 | 
			
		||||
// 	quiz_paper_id := "1_id"
 | 
			
		||||
 | 
			
		||||
// 	c := []string{"1", "2", "3", "4"}
 | 
			
		||||
// 	var j datatypes.JSON
 | 
			
		||||
// 	j, _ = json.Marshal(c)
 | 
			
		||||
 | 
			
		||||
// 	for i := 1; i < 6; i++ {
 | 
			
		||||
// 		q := models.Quiz{
 | 
			
		||||
// 			ID:           strconv.Itoa(i),
 | 
			
		||||
// 			QuizPaperID:  quiz_paper_id,
 | 
			
		||||
// 			No:           i,
 | 
			
		||||
// 			QuestionType: "multiple",
 | 
			
		||||
// 			Question:     strconv.Itoa(i) + " question",
 | 
			
		||||
// 			Content:      j,
 | 
			
		||||
// 			Answer:       j,
 | 
			
		||||
// 			Hint:         "힌트입니다.",
 | 
			
		||||
// 			Comment:      "설명입니다.",
 | 
			
		||||
// 			UpdatedAt:    time.Now(),
 | 
			
		||||
// 			CreatedAt:    time.Now(),
 | 
			
		||||
// 		}
 | 
			
		||||
// 		quizzes = append(quizzes, q)
 | 
			
		||||
// 	}
 | 
			
		||||
// 	for _, quiz := range quizzes {
 | 
			
		||||
// 		suite.db.Create(&quiz)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *QuizTestSuite) TearDownSuite() {
 | 
			
		||||
// 	// DB 삭제
 | 
			
		||||
// 	suite.db.Migrator().DropTable(&models.Quiz{})
 | 
			
		||||
// 	err := os.Remove("test.db")
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		suite.Fail("Failed to remove the test database file")
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *QuizTestSuite) SetupTest() {
 | 
			
		||||
// 	suite.CreateSampleData()
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *QuizTestSuite) TearDownTest() {
 | 
			
		||||
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func TestQuizSuite(t *testing.T) {
 | 
			
		||||
// 	suite.Run(t, new(QuizTestSuite))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 목록 테스트
 | 
			
		||||
// func (suite *QuizTestSuite) TestListQuizSuccess() {
 | 
			
		||||
// 	quizzes, err := suite.repository.List("id_1", 1, 10)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), quizzes)
 | 
			
		||||
// 	assert.Equal(suite.T(), 5, len(*quizzes))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // Find 테스트
 | 
			
		||||
// func (suite *QuizTestSuite) TestFindQuizSuccess() {
 | 
			
		||||
// 	quiz, err := suite.repository.Find("1")
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.Equal(suite.T(), "1", quiz.ID)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // Find 테스트
 | 
			
		||||
// func (suite *QuizTestSuite) TestFindQuizFail() {
 | 
			
		||||
// 	_, err := suite.repository.Find("x")
 | 
			
		||||
// 	assert.Error(suite.T(), err)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 수정 테스트
 | 
			
		||||
// func (suite *QuizTestSuite) TestUpdateQuizFail() {
 | 
			
		||||
// 	c := []string{"1", "2", "3", "4"}
 | 
			
		||||
// 	var j datatypes.JSON
 | 
			
		||||
// 	j, _ = json.Marshal(c)
 | 
			
		||||
// 	q := &models.Quiz{
 | 
			
		||||
// 		ID:           uuid.NewString(),
 | 
			
		||||
// 		QuizPaperID:  uuid.NewString(),
 | 
			
		||||
// 		No:           1,
 | 
			
		||||
// 		QuestionType: "multiple",
 | 
			
		||||
// 		Question:     "question",
 | 
			
		||||
// 		Content:      j,
 | 
			
		||||
// 		Answer:       j,
 | 
			
		||||
// 		Hint:         "힌트입니다.",
 | 
			
		||||
// 		Comment:      "설명입니다.",
 | 
			
		||||
// 		UpdatedAt:    time.Now(),
 | 
			
		||||
// 		CreatedAt:    time.Now(),
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	quiz, err := suite.repository.Create(q)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	quiz.QuestionType = "check"
 | 
			
		||||
// 	quiz.Content = j
 | 
			
		||||
// 	quiz.Answer = j
 | 
			
		||||
// 	quiz.Hint = "힌트입니다!"
 | 
			
		||||
 | 
			
		||||
// 	updatedQuiz, err := suite.repository.Update(quiz)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	assert.Equal(suite.T(), updatedQuiz.QuestionType, quiz.QuestionType)
 | 
			
		||||
// 	assert.Equal(suite.T(), updatedQuiz.Content, quiz.Content)
 | 
			
		||||
// 	assert.Equal(suite.T(), updatedQuiz.Answer, quiz.Answer)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 삭제 테스트
 | 
			
		||||
// func (suite *QuizTestSuite) TestDeleteQuizSuccess() {
 | 
			
		||||
// 	c := []string{"1", "2", "3", "4"}
 | 
			
		||||
// 	var j datatypes.JSON
 | 
			
		||||
// 	j, _ = json.Marshal(c)
 | 
			
		||||
// 	q := &models.Quiz{
 | 
			
		||||
// 		ID:           uuid.NewString(),
 | 
			
		||||
// 		QuizPaperID:  uuid.NewString(),
 | 
			
		||||
// 		No:           1,
 | 
			
		||||
// 		QuestionType: "multiple",
 | 
			
		||||
// 		Question:     "question",
 | 
			
		||||
// 		Content:      j,
 | 
			
		||||
// 		Answer:       j,
 | 
			
		||||
// 		Hint:         "힌트입니다.",
 | 
			
		||||
// 		Comment:      "설명입니다.",
 | 
			
		||||
// 		UpdatedAt:    time.Now(),
 | 
			
		||||
// 		CreatedAt:    time.Now(),
 | 
			
		||||
// 	}
 | 
			
		||||
// 	_, err := suite.repository.Create(q)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	err = suite.repository.Delete(q.ID)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	_, err = suite.repository.Find(q.ID)
 | 
			
		||||
// 	assert.Error(suite.T(), err)
 | 
			
		||||
// }
 | 
			
		||||
							
								
								
									
										245
									
								
								test/token_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								test/token_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,245 @@
 | 
			
		||||
package learsteam_quiz_test
 | 
			
		||||
 | 
			
		||||
// type TokenTestSuite struct {
 | 
			
		||||
// 	suite.Suite
 | 
			
		||||
// 	db         *gorm.DB
 | 
			
		||||
// 	repository repositories.TokenRepository
 | 
			
		||||
// 	service    services.TokenService
 | 
			
		||||
// 	controller controllers.TokenController
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) SetupSuite() {
 | 
			
		||||
// 	err := os.Remove("test.db")
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		suite.Fail("Failed to remove the test database file")
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	database.Init()
 | 
			
		||||
// 	gorm_config := gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}}
 | 
			
		||||
// 	db, _ := gorm.Open(sqlite.Open("test.db"), &gorm_config)
 | 
			
		||||
// 	repository := repositories.NewTokenRepository(db)
 | 
			
		||||
// 	service := services.NewTokenService(repository)
 | 
			
		||||
// 	controller := controllers.NewTokenController(service)
 | 
			
		||||
 | 
			
		||||
// 	suite.db = db
 | 
			
		||||
// 	suite.service = service
 | 
			
		||||
// 	suite.repository = repository
 | 
			
		||||
// 	suite.controller = controller
 | 
			
		||||
 | 
			
		||||
// 	suite.CreateSampleData()
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) CreateSampleData() {
 | 
			
		||||
// 	suite.db.AutoMigrate(&models.Token{})
 | 
			
		||||
// 	var tokens []models.Token
 | 
			
		||||
// 	for i := 1; i < 100; i++ {
 | 
			
		||||
// 		expire_at := time.Now().Add(time.Hour * 24 * time.Duration(i+45))
 | 
			
		||||
// 		tokenString, _ := suite.service.Generate("superrichquiz_octet", expire_at.Unix())
 | 
			
		||||
// 		token := models.Token{
 | 
			
		||||
// 			ID:        uuid.NewString(),
 | 
			
		||||
// 			Token:     tokenString,
 | 
			
		||||
// 			Status:    "valid",
 | 
			
		||||
// 			ExpireAt:  expire_at,
 | 
			
		||||
// 			UpdatedAt: time.Now(),
 | 
			
		||||
// 			CreatedAt: time.Now(),
 | 
			
		||||
// 		}
 | 
			
		||||
// 		tokens = append(tokens, token)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	for _, token := range tokens {
 | 
			
		||||
// 		suite.db.Create(&token)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) TearDownSuite() {
 | 
			
		||||
// 	// suite.db.Migrator().DropTable(&models.Token{})
 | 
			
		||||
 | 
			
		||||
// 	// err := os.Remove("test.db")
 | 
			
		||||
// 	// if err != nil {
 | 
			
		||||
// 	// 	suite.Fail("Failed to remove the test database file")
 | 
			
		||||
// 	// }
 | 
			
		||||
// }
 | 
			
		||||
// func (suite *TokenTestSuite) SetupTest() {
 | 
			
		||||
// 	// suite.userRepository.DeleteByName("testUserName0001")
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) TearDownTest() {
 | 
			
		||||
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func TestTokenSuite(t *testing.T) {
 | 
			
		||||
// 	suite.Run(t, new(TokenTestSuite))
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 토큰 생성 테스트
 | 
			
		||||
// func (suite *TokenTestSuite) TestGenerateTokenSuccess() {
 | 
			
		||||
// 	user_id := "testuser"
 | 
			
		||||
// 	expire_at := time.Now().Add(time.Hour * 24 * 365).Unix()
 | 
			
		||||
// 	token, err := suite.service.Generate(user_id, expire_at)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), token)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 토큰 생성 테스트
 | 
			
		||||
// func (suite *TokenTestSuite) TestGenerateTokenString() {
 | 
			
		||||
// 	user_id := "superrichquiz_octet"
 | 
			
		||||
// 	expire_at := time.Now().Add(time.Hour * 24 * 365 * 100).Unix()
 | 
			
		||||
// 	tokenString, err := suite.service.Generate(user_id, expire_at)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	jwtToken, err := suite.service.VerifyTokenString(tokenString)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), jwtToken)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 토큰 검증 테스트
 | 
			
		||||
// func (suite *TokenTestSuite) TestVerifyTokenString() {
 | 
			
		||||
// 	user_id := "testuser"
 | 
			
		||||
// 	expire_at := time.Now().Add(time.Hour * 24 * 365).Unix()
 | 
			
		||||
// 	tokenString, err := suite.service.Generate(user_id, expire_at)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	jwtToken, err := suite.service.VerifyTokenString(tokenString)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), jwtToken)
 | 
			
		||||
// 	assert.Equal(suite.T(), tokenString, jwtToken.Raw)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 토큰 유효성 테스트
 | 
			
		||||
// func (suite *TokenTestSuite) TestValidToken() {
 | 
			
		||||
// 	user_id := "testuser"
 | 
			
		||||
// 	expire_at := time.Now().Add(time.Hour * 24 * 365).Unix()
 | 
			
		||||
// 	tokenString, err := suite.service.Generate(user_id, expire_at)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	jwtToken, err := suite.service.VerifyTokenString(tokenString)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), jwtToken)
 | 
			
		||||
 | 
			
		||||
// 	valid, err := suite.service.ValidToken(jwtToken)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.True(suite.T(), valid)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 토큰 유효성 테스트 : Expire
 | 
			
		||||
// func (suite *TokenTestSuite) TestExpiredToken() {
 | 
			
		||||
// 	user_id := "testuser"
 | 
			
		||||
// 	expire_at := time.Now().Add(time.Hour * 1).Unix()
 | 
			
		||||
// 	tokenString, err := suite.service.Generate(user_id, expire_at)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	jwtToken, err := suite.service.GetJwtToken(tokenString)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	// assert.Nil(suite.T(), jwtToken)
 | 
			
		||||
 | 
			
		||||
// 	expirationTime, err := jwtToken.Claims.GetExpirationTime()
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.Greater(suite.T(), expirationTime.Time, time.Now())
 | 
			
		||||
 | 
			
		||||
// 	expire_at = time.Now().Add(-time.Hour * 1).Unix()
 | 
			
		||||
// 	tokenString, err = suite.service.Generate(user_id, expire_at)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 	jwtToken, err = suite.service.GetJwtToken(tokenString)
 | 
			
		||||
// 	assert.Error(suite.T(), err)
 | 
			
		||||
// 	// assert.Nil(suite.T(), jwtToken)
 | 
			
		||||
 | 
			
		||||
// 	expirationTime, err = jwtToken.Claims.GetExpirationTime()
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.Greater(suite.T(), time.Now(), expirationTime.Time)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) TestCreateToken() {
 | 
			
		||||
// 	dateString := "2023-08-15T01:50:08.706Z"
 | 
			
		||||
// 	layout := "2006-01-02T15:04:05.000Z"
 | 
			
		||||
// 	tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkeCI6MTc2NTQyLCJ0b2tlblR5cGUiOiJXQUxMRVQiLCJ0b2tlbkV4cGlyZWREYXRlIjoiMjAyMy0wOC0xNVQwMTo1MDowOC43MDZaIn0.skgP6ysLNx6KRDBYZy3miZW1Q95iV_Cw0ZVWXj1tJyw"
 | 
			
		||||
// 	expire_at, _ := time.Parse(layout, dateString)
 | 
			
		||||
// 	token := models.Token{
 | 
			
		||||
// 		ID:       uuid.NewString(),
 | 
			
		||||
// 		Token:    tokenString,
 | 
			
		||||
// 		Status:   "valid",
 | 
			
		||||
// 		ExpireAt: expire_at,
 | 
			
		||||
// 	}
 | 
			
		||||
// 	result, err := suite.repository.Create(&token)
 | 
			
		||||
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.Equal(suite.T(), tokenString, result.Token)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 리프레시할 토큰 목록
 | 
			
		||||
// func (suite *TokenTestSuite) TestListOfTokensToRefresh() {
 | 
			
		||||
// 	tokens, err := suite.repository.ListRefresh()
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), tokens)
 | 
			
		||||
// 	assert.Greater(suite.T(), len(*tokens), 0)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// // 토큰 리프레시
 | 
			
		||||
// func (suite *TokenTestSuite) TestOldTokenRefresh() {
 | 
			
		||||
// 	tokens, err := suite.repository.ListRefresh()
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), tokens)
 | 
			
		||||
 | 
			
		||||
// 	for _, token := range *tokens {
 | 
			
		||||
// 		token.Status = "expired"
 | 
			
		||||
// 		result, err := suite.repository.Update(&token)
 | 
			
		||||
// 		assert.NoError(suite.T(), err)
 | 
			
		||||
// 		assert.Equal(suite.T(), "expired", result.Status)
 | 
			
		||||
 | 
			
		||||
// 		user_id := "superrichquiz_octet"
 | 
			
		||||
// 		expire_at := result.ExpireAt.Add(time.Hour * 24 * 90)
 | 
			
		||||
// 		tokenString, err := suite.service.Generate(user_id, expire_at.Unix())
 | 
			
		||||
// 		assert.NoError(suite.T(), err)
 | 
			
		||||
 | 
			
		||||
// 		refreshedToken := models.Token{
 | 
			
		||||
// 			ID:       uuid.NewString(),
 | 
			
		||||
// 			Token:    tokenString,
 | 
			
		||||
// 			Status:   "valid",
 | 
			
		||||
// 			ExpireAt: expire_at,
 | 
			
		||||
// 		}
 | 
			
		||||
 | 
			
		||||
// 		newToken, err := suite.repository.Create(&refreshedToken)
 | 
			
		||||
// 		assert.NoError(suite.T(), err)
 | 
			
		||||
// 		assert.Equal(suite.T(), tokenString, newToken.Token)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) TestResponseToken() {
 | 
			
		||||
// 	respBody := []byte(`{
 | 
			
		||||
//     "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkeCI6MTc1MzU4LCJ0b2tlblR5cGUiOiJXQUxMRVQiLCJ0b2tlbkV4cGlyZWREYXRlIjoiMjAyMy0wOC0xNFQwNToxMTo1Ni41MzhaIn0.e1i4_y8ItC8Vje13Ew8NHwZTElOMBObIZjpGLgRCdyE",
 | 
			
		||||
//     "tokenBody": {
 | 
			
		||||
//         "tokenExpiredDate": "2023-08-13T06:06:12.065Z",
 | 
			
		||||
//         "tokenIdx": 174025,
 | 
			
		||||
//         "tokenType": "WALLET"
 | 
			
		||||
//     }
 | 
			
		||||
// 	}`)
 | 
			
		||||
 | 
			
		||||
// 	var response map[string]interface{}
 | 
			
		||||
// 	err := json.Unmarshal(respBody, &response)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), response)
 | 
			
		||||
// 	assert.Equal(suite.T(), response["token"], "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkeCI6MTc1MzU4LCJ0b2tlblR5cGUiOiJXQUxMRVQiLCJ0b2tlbkV4cGlyZWREYXRlIjoiMjAyMy0wOC0xNFQwNToxMTo1Ni41MzhaIn0.e1i4_y8ItC8Vje13Ew8NHwZTElOMBObIZjpGLgRCdyE")
 | 
			
		||||
 | 
			
		||||
// 	tokenBody := response["tokenBody"].(map[string]interface{})
 | 
			
		||||
// 	tokenExpiredDate := tokenBody["tokenExpiredDate"].(string)
 | 
			
		||||
// 	assert.Equal(suite.T(), "2023-08-13T06:06:12.065Z", tokenExpiredDate)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// func (suite *TokenTestSuite) TestResponseError() {
 | 
			
		||||
// 	respBody := []byte(`{
 | 
			
		||||
//     "errorCode": "ERR_0105001",
 | 
			
		||||
//     "message": "Invalid token"
 | 
			
		||||
// 	}`)
 | 
			
		||||
 | 
			
		||||
// 	var response map[string]interface{}
 | 
			
		||||
// 	err := json.Unmarshal(respBody, &response)
 | 
			
		||||
// 	assert.NoError(suite.T(), err)
 | 
			
		||||
// 	assert.NotNil(suite.T(), response)
 | 
			
		||||
 | 
			
		||||
// 	assert.NotNil(suite.T(), response["errorCode"])
 | 
			
		||||
// 	assert.Equal(suite.T(), "ERR_0105001", response["errorCode"].(string))
 | 
			
		||||
 | 
			
		||||
// 	if response["errorCode"] != nil && response["errorCode"].(string) == "ERR_0105001" {
 | 
			
		||||
// 		assert.True(suite.T(), true)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
		Reference in New Issue
	
	Block a user