diff --git a/configs/common.dev b/configs/common.dev index a74f1e7..998af8c 100644 --- a/configs/common.dev +++ b/configs/common.dev @@ -1,10 +1,10 @@ package config const ( - BASE_URL = "https://cslms-api.jongyeob.com" - PORT = ":3030" - DATABASE_URL = "cslms:atobot2013!#%@tcp(ma.codingschool.co.kr:3306)/cslms5?charset=utf8&parseTime=True&loc=Local" - //DATABASE_URL = "root:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(learnsteam-quiz-db:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local" + MODE = "debug" + BASE_URL = "https://codingschool.co.kr" + PORT = ":30303" + DATABASE_URL = "cslms:atobot2013!#%@tcp(localhost:3306)/cslms5?charset=utf8&parseTime=True&loc=Local" KAKAO_CLIENT_ID = "986830" KAKAO_CLIENT_SECRET = "14f63a8e91c4e0fe88bc40e3ff348233" diff --git a/configs/common.go b/configs/common.go index f54c01a..d39388b 100644 --- a/configs/common.go +++ b/configs/common.go @@ -1,6 +1,7 @@ package config const ( + MODE = "debug" BASE_URL = "http://localhost:3030" PORT = ":3030" DATABASE_URL = "cslms:atobot2013!#%@tcp(localhost:33061)/cslms5?charset=utf8&parseTime=True&loc=Local" diff --git a/configs/common.local b/configs/common.local index f54c01a..d39388b 100644 --- a/configs/common.local +++ b/configs/common.local @@ -1,6 +1,7 @@ package config const ( + MODE = "debug" BASE_URL = "http://localhost:3030" PORT = ":3030" DATABASE_URL = "cslms:atobot2013!#%@tcp(localhost:33061)/cslms5?charset=utf8&parseTime=True&loc=Local" diff --git a/configs/common.prod b/configs/common.prod index 69f71f9..8a272bf 100644 --- a/configs/common.prod +++ b/configs/common.prod @@ -1,8 +1,9 @@ package config const ( - BASE_URL = "https://cslms-api.jongyeob.com" - PORT = ":3030" + MODE = "release" + BASE_URL = "https://cslms-api.codingschool.co.kr" + PORT = ":30303" DATABASE_URL = "root:fbOgZ6Xxn5VXBYihjqygRXyaK6ZUgKL6@tcp(learnsteam-quiz-db:3306)/learnsteam_quiz?charset=utf8&parseTime=True&loc=Local" KAKAO_CLIENT_ID = "986830" diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 8918605..ce18cb9 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -15,7 +15,7 @@ WORKDIR /app RUN apk add --no-cache sqlite-libs mariadb-connector-c libgcc COPY --from=builder /app/bootstrap . -EXPOSE 3030 -ENV PORT 3030 +EXPOSE 30303 +ENV PORT 30303 CMD ["sh", "-c", "./bootstrap"] \ No newline at end of file diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index b02d84f..cef541b 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -7,4 +7,6 @@ services: dockerfile: docker/dev/Dockerfile image: learnsteam/cslms-api:dev ports: - - "3030:3030" + - "30303:30303" + network_mode: "host" + restart: on-failure diff --git a/docker/local/docker-compose.yml b/docker/local/docker-compose.yml index 89b20d5..c7d7d91 100644 --- a/docker/local/docker-compose.yml +++ b/docker/local/docker-compose.yml @@ -8,3 +8,5 @@ services: image: learnsteam/cslms-api:local ports: - "3030:3030" + network_mode: "host" + restart: on-failure diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 1a91329..fa63b30 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -15,7 +15,7 @@ WORKDIR /app RUN apk add --no-cache sqlite-libs mariadb-connector-c libgcc COPY --from=builder /app/bootstrap . -EXPOSE 3030 -ENV PORT 3030 +EXPOSE 30303 +ENV PORT 30303 CMD ["sh", "-c", "./bootstrap"] \ No newline at end of file diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index 4aa831d..afc75ef 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -7,4 +7,6 @@ services: dockerfile: docker/prod/Dockerfile image: learnsteam/cslms-api ports: - - "3030:3030" + - "30303:30303" + network_mode: "host" + restart: on-failure diff --git a/docs/docs.go b/docs/docs.go index c211de8..dbf8ba7 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -52,6 +52,27 @@ const docTemplate = `{ } } }, + "/auth/logout": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "로그아웃하고 Token, Cookie 삭제", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "로그아웃" + ], + "summary": "로그아웃", + "responses": {} + } + }, "/auth/register": { "post": { "description": "회원가입", @@ -1319,7 +1340,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/learnsteam_cslms-api_internal_models.Quiz" + "$ref": "#/definitions/learnsteam_cslms-api_internal_models.QuizResponse" } }, "page": { @@ -1459,8 +1480,14 @@ const docTemplate = `{ "tag": { "type": "array", "items": { - "type": "integer" - } + "type": "string" + }, + "example": [ + "Python", + "AI", + "Robot", + "파이썬" + ] }, "title": { "type": "string", @@ -1498,8 +1525,14 @@ const docTemplate = `{ "tag": { "type": "array", "items": { - "type": "integer" - } + "type": "string" + }, + "example": [ + "Python", + "AI", + "Robot", + "파이썬" + ] }, "title": { "type": "string", @@ -1867,7 +1900,13 @@ const docTemplate = `{ "type": "array", "items": { "type": "integer" - } + }, + "example": [ + 1000001, + 1000002, + 1000003, + 1000004 + ] } } }, @@ -1975,6 +2014,10 @@ const docTemplate = `{ "type": "string", "example": "choice" }, + "quiz_id": { + "type": "integer", + "example": 1000001 + }, "quiz_paper_id": { "type": "integer", "example": 1000001 @@ -2037,6 +2080,10 @@ const docTemplate = `{ "type": "string", "example": "check" }, + "quiz_id": { + "type": "integer", + "example": 1000001 + }, "result": { "type": "string", "example": "success" diff --git a/docs/swagger.json b/docs/swagger.json index 4fdfcb3..d648772 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -44,6 +44,27 @@ } } }, + "/auth/logout": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "로그아웃하고 Token, Cookie 삭제", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "로그아웃" + ], + "summary": "로그아웃", + "responses": {} + } + }, "/auth/register": { "post": { "description": "회원가입", @@ -1311,7 +1332,7 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/learnsteam_cslms-api_internal_models.Quiz" + "$ref": "#/definitions/learnsteam_cslms-api_internal_models.QuizResponse" } }, "page": { @@ -1451,8 +1472,14 @@ "tag": { "type": "array", "items": { - "type": "integer" - } + "type": "string" + }, + "example": [ + "Python", + "AI", + "Robot", + "파이썬" + ] }, "title": { "type": "string", @@ -1490,8 +1517,14 @@ "tag": { "type": "array", "items": { - "type": "integer" - } + "type": "string" + }, + "example": [ + "Python", + "AI", + "Robot", + "파이썬" + ] }, "title": { "type": "string", @@ -1859,7 +1892,13 @@ "type": "array", "items": { "type": "integer" - } + }, + "example": [ + 1000001, + 1000002, + 1000003, + 1000004 + ] } } }, @@ -1967,6 +2006,10 @@ "type": "string", "example": "choice" }, + "quiz_id": { + "type": "integer", + "example": 1000001 + }, "quiz_paper_id": { "type": "integer", "example": 1000001 @@ -2029,6 +2072,10 @@ "type": "string", "example": "check" }, + "quiz_id": { + "type": "integer", + "example": 1000001 + }, "result": { "type": "string", "example": "success" diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ff49d8a..ca78e85 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -146,7 +146,7 @@ definitions: properties: data: items: - $ref: '#/definitions/learnsteam_cslms-api_internal_models.Quiz' + $ref: '#/definitions/learnsteam_cslms-api_internal_models.QuizResponse' type: array page: example: 1 @@ -244,8 +244,13 @@ definitions: example: "on" type: string tag: + example: + - Python + - AI + - Robot + - 파이썬 items: - type: integer + type: string type: array title: example: 퀴즈 시트 제목 @@ -272,8 +277,13 @@ definitions: example: "on" type: string tag: + example: + - Python + - AI + - Robot + - 파이썬 items: - type: integer + type: string type: array title: example: 퀴즈 시트 제목 @@ -533,6 +543,11 @@ definitions: example: 1000002 type: integer users: + example: + - 1000001 + - 1000002 + - 1000003 + - 1000004 items: type: integer type: array @@ -612,6 +627,9 @@ definitions: question_type: example: choice type: string + quiz_id: + example: 1000001 + type: integer quiz_paper_id: example: 1000001 type: integer @@ -657,6 +675,9 @@ definitions: question_type: example: check type: string + quiz_id: + example: 1000001 + type: integer result: example: success type: string @@ -706,6 +727,19 @@ paths: summary: 사용자 로그인 로그인 tags: - 로그인 + /auth/logout: + post: + consumes: + - application/json + description: 로그아웃하고 Token, Cookie 삭제 + produces: + - application/json + responses: {} + security: + - Bearer: [] + summary: 로그아웃 + tags: + - 로그아웃 /auth/register: post: consumes: diff --git a/go.mod b/go.mod index f479f8a..d8daa3c 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( golang.org/x/crypto v0.15.0 gorm.io/datatypes v1.2.0 gorm.io/driver/mysql v1.5.2 + gorm.io/driver/sqlite v1.5.4 gorm.io/gorm v1.25.5 ) @@ -43,6 +44,7 @@ require ( 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/mattn/go-sqlite3 v1.14.17 // 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 @@ -56,11 +58,11 @@ require ( 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 + github.com/tj/assert v0.0.3 ) diff --git a/internal/controllers/auth.go b/internal/controllers/auth.go index d02298f..434209b 100644 --- a/internal/controllers/auth.go +++ b/internal/controllers/auth.go @@ -1,7 +1,9 @@ package controllers import ( + "fmt" "net/http" + "strings" "learnsteam/cslms-api/internal/models" "learnsteam/cslms-api/internal/services" @@ -12,6 +14,7 @@ import ( type AuthController interface { Register(*gin.Context) Login(*gin.Context) + Logout(*gin.Context) } type authController struct { @@ -29,7 +32,7 @@ func NewAuthController(service services.AuthService, tokenService services.Token // Register // // @Summary 회원가입 -// @Description 회원가입 +// @Description 회원가입 // @Tags 회원가입 // @Accept json // @Produce json @@ -62,7 +65,7 @@ func (controller *authController) Register(c *gin.Context) { // Login 사용자 로그인 // // @Summary 사용자 로그인 로그인 -// @Description 사용자가 로그인합니다. +// @Description 사용자가 로그인합니다. // @Tags 로그인 // // @Accept json @@ -98,25 +101,47 @@ func (controller *authController) Login(c *gin.Context) { }) } -// Logout +// Logout 로그아웃 +// +// @Summary 로그아웃 +// @Description 로그아웃하고 Token, Cookie 삭제 +// @Tags 로그아웃 +// +// @Accept json +// @Produce json +// +// @Security Bearer +// +// @Router /auth/logout [post] func (controller *authController) Logout(c *gin.Context) { - token := c.GetHeader("Authorization") - if token == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}) - return - } + token, err := func() (*string, error) { + authorization := c.GetHeader("Authorization") + strArr := strings.Split(authorization, " ") + if len(strArr) == 2 { + return &strArr[1], nil + } else { + return nil, fmt.Errorf("invalid authorization header") + } + }() - err := controller.tokenService.Delete(token) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } + + user_id := c.GetInt64("sub") + + err = controller.tokenService.Invalid(user_id, *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"}) } diff --git a/internal/controllers/quizpaper.go b/internal/controllers/quizpaper.go index d9f6d78..101dc17 100644 --- a/internal/controllers/quizpaper.go +++ b/internal/controllers/quizpaper.go @@ -1,6 +1,7 @@ package controllers import ( + "encoding/json" "fmt" "net/http" "strconv" @@ -11,6 +12,7 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" + "gorm.io/datatypes" ) type QuizPaperController interface { @@ -147,6 +149,12 @@ func (controller *quizPaperController) Create(c *gin.Context) { user_id := c.GetInt64("sub") + var tag datatypes.JSON + tag, err := json.Marshal(request.Tag) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } quizPaper := &models.QuizPaper{ GUID: uuid.NewString(), CenterID: request.CenterID, @@ -154,7 +162,7 @@ func (controller *quizPaperController) Create(c *gin.Context) { Title: request.Title, Content: request.Content, Category: request.Category, - Tag: request.Tag, + Tag: tag, Status: request.Status, CreatedAt: time.Now(), UpdatedAt: time.Now(), @@ -204,13 +212,20 @@ func (controller *quizPaperController) Update(c *gin.Context) { return } + var tag datatypes.JSON + tag, err = json.Marshal(request.Tag) + 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.Tag = tag quizPaper.Status = request.Status quizPaper.UpdatedAt = time.Now() diff --git a/internal/controllers/user.go b/internal/controllers/user.go index 7e9e73f..cdeeead 100644 --- a/internal/controllers/user.go +++ b/internal/controllers/user.go @@ -109,18 +109,6 @@ func (controller *userController) Find(c *gin.Context) { 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()}) diff --git a/internal/controllers/userquiz.go b/internal/controllers/userquiz.go index be754c7..fe06e42 100644 --- a/internal/controllers/userquiz.go +++ b/internal/controllers/userquiz.go @@ -159,6 +159,7 @@ func (controller *userQuizController) Create(c *gin.Context) { CenterID: request.CenterID, UserQuizPaperID: request.UserQuizPaperID, No: request.No, + QuizID: request.QuizID, QuestionType: request.QuestionType, Question: request.Question, Content: content, @@ -223,8 +224,29 @@ func (controller *userQuizController) Update(c *gin.Context) { // Result string `json:"result" example:"success"` // Score float32 `json:"score" example:"10"` + 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 + } + userquiz.CenterID = request.CenterID userquiz.UserQuizPaperID = request.UserQuizPaperID + userquiz.No = request.No + userquiz.QuestionType = request.QuestionType + userquiz.Question = request.Question + userquiz.Content = content + userquiz.Answer = answer + userquiz.Status = request.Status + userquiz.Score = request.Score result, err := controller.service.Update(userquiz) if err != nil { diff --git a/internal/controllers/userquizpaper.go b/internal/controllers/userquizpaper.go index 80af787..fff21c7 100644 --- a/internal/controllers/userquizpaper.go +++ b/internal/controllers/userquizpaper.go @@ -1,7 +1,6 @@ package controllers import ( - "encoding/json" "fmt" "net/http" "strconv" @@ -160,14 +159,14 @@ func (controller *userQuizPaperController) Create(c *gin.Context) { return } - var users []int64 - err = json.Unmarshal(request.Users, &users) - 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) + templates := controller.service.Generate(request.Users, quizPaper) userQuizPapers, err := controller.service.Insert(templates) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index b98f875..3ce5483 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -7,6 +7,8 @@ import ( "strings" config "learnsteam/cslms-api/configs" + "learnsteam/cslms-api/internal/database" + "learnsteam/cslms-api/internal/models" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" @@ -35,10 +37,14 @@ func Auth(permission string) gin.HandlerFunc { return } - fmt.Println("token", extract(c.Request)) - fmt.Println("sub", sub) + valid := Valid(c.Request) + if !valid { + c.JSON(http.StatusUnauthorized, gin.H{"error": "token is not valid"}) + c.Abort() + return + } - c.Set("token", extract(c.Request)) + c.Set("token", Extract(c.Request)) c.Set("sub", sub) c.Set("role", role) c.Next() @@ -67,17 +73,21 @@ func Permission(permission *string) gin.HandlerFunc { return } - fmt.Println("token", extract(c.Request)) - fmt.Println("sub", sub) + valid := Valid(c.Request) + if !valid { + c.JSON(http.StatusUnauthorized, gin.H{"error": "token is not valid"}) + c.Abort() + return + } - c.Set("token", extract(c.Request)) + c.Set("token", Extract(c.Request)) c.Set("sub", sub) c.Set("role", role) c.Next() } } -func extract(r *http.Request) string { +func Extract(r *http.Request) string { authorization := r.Header.Get("Authorization") strArr := strings.Split(authorization, " ") if len(strArr) == 2 { @@ -86,8 +96,8 @@ func extract(r *http.Request) string { return "" } -func verify(r *http.Request) (*jwt.Token, error) { - tokenString := extract(r) +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"]) @@ -99,8 +109,9 @@ func verify(r *http.Request) (*jwt.Token, error) { } func UserID(r *http.Request) (int64, error) { - jwtToken, err := verify(r) + jwtToken, err := Verify(r) if err != nil { + fmt.Println(err) return -1, err } @@ -120,7 +131,7 @@ func UserID(r *http.Request) (int64, error) { } func Role(r *http.Request) (*string, error) { - jwtToken, err := verify(r) + jwtToken, err := Verify(r) if err != nil { return nil, err } @@ -134,3 +145,12 @@ func Role(r *http.Request) (*string, error) { return &role, nil } + +func Valid(r *http.Request) bool { + tokenString := Extract(r) + var token models.Token + fmt.Println(tokenString) + err := database.DB.Where("token = ? AND status = ?", tokenString, "on").First(&token).Error + fmt.Println(&token) + return err == nil +} diff --git a/internal/models/center.go b/internal/models/center.go index cb3f57a..560b18b 100644 --- a/internal/models/center.go +++ b/internal/models/center.go @@ -4,21 +4,6 @@ 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;"` diff --git a/internal/models/quiz.go b/internal/models/quiz.go index d11f2d7..e668e11 100644 --- a/internal/models/quiz.go +++ b/internal/models/quiz.go @@ -59,11 +59,11 @@ type QuizResponse struct { } 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"` + Data []QuizResponse `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 { diff --git a/internal/models/quizpaper.go b/internal/models/quizpaper.go index 7b917c5..c36224e 100644 --- a/internal/models/quizpaper.go +++ b/internal/models/quizpaper.go @@ -6,24 +6,6 @@ import ( "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;"` @@ -44,23 +26,23 @@ func (QuizPaper) TableName() string { } 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"` + CenterID int64 `json:"center_id" example:"100001"` + Title string `json:"title" example:"퀴즈 시트 제목"` + Content string `json:"content" example:"퀴즈 시트 설명"` + Category string `json:"category" example:"파이썬기본"` + Tag []string `json:"tag" example:"Python,AI,Robot,파이썬"` + 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"` + 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 []string `json:"tag" example:"Python,AI,Robot,파이썬"` + Status string `json:"status" example:"on"` } type QuizPaperListResponse struct { diff --git a/internal/models/token.go b/internal/models/token.go index 87fde2d..8ea3534 100644 --- a/internal/models/token.go +++ b/internal/models/token.go @@ -2,17 +2,6 @@ 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;"` diff --git a/internal/models/user.go b/internal/models/user.go index e4419ca..3c4a730 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -2,27 +2,6 @@ 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;"` diff --git a/internal/models/userquiz.go b/internal/models/userquiz.go index 7651fab..4a60c39 100644 --- a/internal/models/userquiz.go +++ b/internal/models/userquiz.go @@ -12,6 +12,7 @@ type UserQuiz struct { 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;"` + QuizID int64 `json:"quiz_id" db:"quiz_id" example:"1000001" gorm:"column:quiz_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;"` @@ -33,6 +34,7 @@ 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"` + QuizID int64 `json:"quiz_id" example:"1000001"` No int `json:"vol_no" example:"1"` QuestionType string `json:"question_type" example:"choice"` Question string `json:"question" example:"질문입니다."` @@ -49,6 +51,7 @@ type UserQuizResponse struct { 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"` + QuizID int64 `json:"quiz_id" example:"1000001"` No int `json:"vol_no" example:"5"` QuestionType string `json:"question_type" example:"check"` Question string `json:"question" example:"퀴즈 질문입니다."` diff --git a/internal/models/userquizpaper.go b/internal/models/userquizpaper.go index 22c3834..869708a 100644 --- a/internal/models/userquizpaper.go +++ b/internal/models/userquizpaper.go @@ -2,30 +2,8 @@ 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"` @@ -47,8 +25,8 @@ func (UserQuizPaper) TableName() string { } type UserQuizPaperRequest struct { - QuizPaperID int64 `json:"quiz_paper_id" example:"1000002"` - Users datatypes.JSON `json:"users"` + QuizPaperID int64 `json:"quiz_paper_id" example:"1000002"` + Users []int64 `json:"users" example:"1000001,1000002,1000003,1000004"` } type UserQuizPaperResponse struct { diff --git a/internal/repositories/token.go b/internal/repositories/token.go index 04d0287..204a1c9 100644 --- a/internal/repositories/token.go +++ b/internal/repositories/token.go @@ -26,6 +26,7 @@ type TokenRepository interface { Create(*models.Token) (*models.Token, error) Update(*models.Token) (*models.Token, error) Delete(string) error + Invalid(int64, string) error } func (s *tokenRepository) Generate(user_id int64, expire_at int64, role string) (string, error) { @@ -69,6 +70,11 @@ func (r *tokenRepository) Update(token *models.Token) (*models.Token, error) { return row, err } +func (r *tokenRepository) Invalid(user_id int64, tokenString string) error { + err := r.DB.Model(&models.Token{}).Where("user_id = ? AND token = ?", user_id, tokenString).Update("status", "off").Error + return err +} + func (r *tokenRepository) Delete(id string) error { var token *models.Token if err := r.DB.Where("id=?", id).First(&token).Error; err != nil { diff --git a/internal/repositories/userquiz.go b/internal/repositories/userquiz.go index 30eca8a..03250a1 100644 --- a/internal/repositories/userquiz.go +++ b/internal/repositories/userquiz.go @@ -1,10 +1,10 @@ package repositories import ( - "fmt" "learnsteam/cslms-api/internal/models" "gorm.io/gorm" + "gorm.io/gorm/clause" ) type userQuizRepository struct { @@ -64,8 +64,7 @@ func (r *userQuizRepository) Create(row *models.UserQuiz) (*models.UserQuiz, err } func (r *userQuizRepository) Insert(items []models.UserQuiz) ([]models.UserQuiz, error) { - fmt.Println(items) - err := r.DB.Create(&items).Error + err := r.DB.Clauses(clause.OnConflict{DoNothing: true}).Create(&items).Error return items, err } diff --git a/internal/repositories/userquizpaper.go b/internal/repositories/userquizpaper.go index b04c304..6afab95 100644 --- a/internal/repositories/userquizpaper.go +++ b/internal/repositories/userquizpaper.go @@ -4,6 +4,7 @@ import ( "learnsteam/cslms-api/internal/models" "gorm.io/gorm" + "gorm.io/gorm/clause" ) type userQuizPaperRepository struct { @@ -63,7 +64,7 @@ func (r *userQuizPaperRepository) Create(userQuizPaper *models.UserQuizPaper) (* } func (r *userQuizPaperRepository) Insert(items []models.UserQuizPaper) ([]models.UserQuizPaper, error) { - err := r.DB.Create(&items).Error + err := r.DB.Clauses(clause.OnConflict{DoNothing: true}).Create(&items).Error return items, err } diff --git a/internal/routers/auth.go b/internal/routers/auth.go index 1ded136..8db8fbb 100644 --- a/internal/routers/auth.go +++ b/internal/routers/auth.go @@ -2,6 +2,7 @@ package routers import ( "learnsteam/cslms-api/internal/controllers" + "learnsteam/cslms-api/internal/middleware" "learnsteam/cslms-api/internal/repositories" "learnsteam/cslms-api/internal/services" @@ -50,4 +51,5 @@ func (r *authRouter) SetAuthRouter() { group := r.router.Group("/auth") group.POST("login", r.controller.Login) group.POST("register", r.controller.Register) + group.POST("logout", middleware.Auth("member"), r.controller.Logout) } diff --git a/internal/routers/router.go b/internal/routers/router.go index 3997222..076a7ab 100644 --- a/internal/routers/router.go +++ b/internal/routers/router.go @@ -1,6 +1,7 @@ package routers import ( + configs "learnsteam/cslms-api/configs" "learnsteam/cslms-api/internal/database" "github.com/gin-contrib/cors" @@ -10,10 +11,11 @@ import ( var Router *gin.Engine func Init() { - gin.SetMode(gin.ReleaseMode) + gin.SetMode(configs.MODE) 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.AllowOrigins = []string{"http://127.0.0.1:3000", "http://localhost:3000", "http://localhost:3030", "https://cslms-api.codingschool.co.kr"} config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "PATCH"} config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type"} Router.Use(cors.New(config)) @@ -21,6 +23,7 @@ func Init() { maindb := database.GetDB() InitAuthRouter(maindb, Router) + InitCenterRouter(maindb, Router) InitQuizPaperRouter(maindb, Router) InitQuizRouter(maindb, Router) diff --git a/internal/services/token.go b/internal/services/token.go index 35a27db..bb81c2c 100644 --- a/internal/services/token.go +++ b/internal/services/token.go @@ -25,8 +25,9 @@ type TokenService interface { Refresh(string) (*models.Token, error) - Generate(string, int64, string) (string, error) - Verify(tokenString string) (*jwt.Token, error) + Generate(int64, int64, string) (string, error) + Verify(string) (*jwt.Token, error) + Invalid(int64, string) error GetJwtToken(string) (*jwt.Token, error) ExtractTokenString(string) string @@ -90,7 +91,12 @@ func (s *tokenService) Verify(tokenString string) (*jwt.Token, error) { return jwtToken, err } -func (s *tokenService) Generate(user_id string, expire_at int64, role string) (string, error) { +func (s *tokenService) Invalid(user_id int64, tokenString string) error { + err := s.repository.Invalid(user_id, tokenString) + return err +} + +func (s *tokenService) Generate(user_id int64, expire_at int64, role string) (string, error) { claims := jwt.MapClaims{} claims["authorized"] = true claims["sub"] = user_id @@ -153,14 +159,6 @@ func (s *tokenService) Refresh(refreshToken string) (*models.Token, error) { }) 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 } @@ -173,6 +171,7 @@ func (s *tokenService) Refresh(refreshToken string) (*models.Token, error) { if err != nil { return nil, errors.New("wrong user") } + role := claims["role"].(string) token, err := s.repository.FindByRefreshToken(sub, refreshToken) diff --git a/internal/services/userquiz.go b/internal/services/userquiz.go index a6a9533..a0530e1 100644 --- a/internal/services/userquiz.go +++ b/internal/services/userquiz.go @@ -80,6 +80,7 @@ func (s *userQuizService) Generate(quiz_paper_id int64, userQuizPaper *models.Us UserQuizPaperID: userQuizPaper.ID, UserID: userQuizPaper.UserID, No: quiz.No, + QuizID: quiz.ID, QuestionType: quiz.QuestionType, Question: quiz.Question, Content: quiz.Content, diff --git a/test/quiz_test.go b/test/quiz_test.go index 1244357..b92aba8 100644 --- a/test/quiz_test.go +++ b/test/quiz_test.go @@ -2,8 +2,11 @@ package learsteam_quiz_test import ( "learnsteam/cslms-api/internal/controllers" + "learnsteam/cslms-api/internal/models" "learnsteam/cslms-api/internal/repositories" "learnsteam/cslms-api/internal/services" + "os" + "testing" "github.com/stretchr/testify/suite" "gorm.io/gorm" @@ -36,7 +39,7 @@ type QuizTestSuite struct { // suite.repository = repository // suite.controller = controller -// suite.CreateSampleData() +// // suite.CreateSampleData() // } // func (suite *QuizTestSuite) CreateSampleData() { @@ -68,26 +71,26 @@ type QuizTestSuite struct { // } // } -// 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) 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) SetupTest() { + // suite.CreateSampleData() +} -// func (suite *QuizTestSuite) TearDownTest() { +func (suite *QuizTestSuite) TearDownTest() { -// } +} -// func TestQuizSuite(t *testing.T) { -// suite.Run(t, new(QuizTestSuite)) -// } +func TestQuizSuite(t *testing.T) { + suite.Run(t, new(QuizTestSuite)) +} // // 목록 테스트 // func (suite *QuizTestSuite) TestListQuizSuccess() { diff --git a/test/token_test.go b/test/token_test.go index 4857201..50d79da 100644 --- a/test/token_test.go +++ b/test/token_test.go @@ -1,33 +1,49 @@ package learsteam_quiz_test -// type TokenTestSuite struct { -// suite.Suite -// db *gorm.DB -// repository repositories.TokenRepository -// service services.TokenService -// controller controllers.TokenController -// } +import ( + "fmt" + config "learnsteam/cslms-api/configs" + "learnsteam/cslms-api/internal/controllers" + "learnsteam/cslms-api/internal/repositories" + "learnsteam/cslms-api/internal/services" + "testing" + "time" -// func (suite *TokenTestSuite) SetupSuite() { -// err := os.Remove("test.db") -// if err != nil { -// suite.Fail("Failed to remove the test database file") -// } + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/suite" + "github.com/tj/assert" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) -// 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) +type TokenTestSuite struct { + suite.Suite + db *gorm.DB + repository repositories.TokenRepository + service services.TokenService + controller controllers.TokenController +} -// suite.db = db -// suite.service = service -// suite.repository = repository -// suite.controller = controller +func (suite *TokenTestSuite) SetupSuite() { + // err := os.Remove("test.db") + // if err != nil { + // suite.Fail("Failed to remove the test database file") + // } -// suite.CreateSampleData() -// } + 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{}) @@ -51,34 +67,36 @@ package learsteam_quiz_test // } // } -// func (suite *TokenTestSuite) TearDownSuite() { -// // suite.db.Migrator().DropTable(&models.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") -// } + // err := os.Remove("test.db") + // if err != nil { + // suite.Fail("Failed to remove the test database file") + // } +} -// func (suite *TokenTestSuite) TearDownTest() { +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 TestTokenSuite(t *testing.T) { + suite.Run(t, new(TokenTestSuite)) +} + +// 토큰 생성 테스트 +func (suite *TokenTestSuite) TestGenerateTokenSuccess() { + user_id := int64(100000001) + role := "admin" + expire_at := time.Now().Add(time.Hour * 24 * 365).Unix() + token, err := suite.service.Generate(user_id, expire_at, role) + assert.NoError(suite.T(), err) + assert.NotNil(suite.T(), token) +} // // 토큰 생성 테스트 // func (suite *TokenTestSuite) TestGenerateTokenString() { @@ -243,3 +261,37 @@ package learsteam_quiz_test // assert.True(suite.T(), true) // } // } + +func (suite *TokenTestSuite) TestVerifyValidToken() { + expire_at := time.Now().Add(time.Hour * 24 * 365 * 100).Unix() + validToken, err := suite.service.Generate(10001, expire_at, "admin") + assert.NoError(suite.T(), err) + + jwtToken, err := jwt.Parse(validToken, 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 + }) + + assert.NoError(suite.T(), err) + assert.True(suite.T(), jwtToken.Valid) +} + +func (suite *TokenTestSuite) TestVerifyExpiredToken() { + expire_at := time.Now().Add(-time.Hour * 24 * 365 * 100).Unix() + expiredToken, err := suite.service.Generate(10001, expire_at, "admin") + assert.NoError(suite.T(), err) + + assert.Equal(suite.T(), "1", expiredToken) + + jwtToken, err := jwt.Parse(expiredToken, 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 + }) + + assert.Error(suite.T(), err) + assert.False(suite.T(), jwtToken.Valid) +}