From 09c72c516726daafedfff46cf58af421c7bafd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A7=E9=A9=8A?= Date: Wed, 12 Nov 2025 16:17:23 +0800 Subject: [PATCH] feat: update mongo doc --- Makefile | 62 +-- generate/api/file_storage.api | 2 +- .../mongo/20240422112701_audo_id.down.txt | 1 - .../mongo/20240422112701_audo_id.up.txt | 1 - .../mongo/2024110500000001_account.down.txt | 3 + .../mongo/2024110500000001_account.up.txt | 1 - .../2024110500000002_account_uid.down.txt | 4 + .../mongo/2024110500000002_account_uid.up.txt | 1 - .../mongo/2024110500000003_user.down.txt | 3 + .../mongo/2024110500000003_user.up.txt | 1 - .../mongo/2024121000000001_product.up.txt | 22 - .../2024121000000002_product_item.up.txt | 9 - ...2024121000000003_supplementary_info.up.txt | 8 - .../mongo/2024121800000001_cart.up.txt | 6 - .../2025100900000001_permission.down.txt | 7 + .../mongo/2025100900000001_permission.up.txt | 7 + .../mongo/2025100900000002_role.down.txt | 8 + .../mongo/2025100900000002_role.up.txt | 8 + .../2025100900000003_role_permission.down.txt | 6 + .../2025100900000003_role_permission.up.txt | 6 + .../mongo/2025100900000004_user_role.down.txt | 8 + .../mongo/2025100900000004_user_role.up.txt | 8 + .../mongo/2025101200000001_roles.up.txt | 18 +- .../database/mongo/Doc/DATABASE_SCHEMA.md | 457 ++++++++++++++++++ generate/database/mongo/Doc/README.md | 52 ++ go.mod | 2 +- .../fileStorage/upload_video_handler.go | 1 + .../handler/user/get_user_info_handler.go | 1 + internal/logic/user/get_user_info_logic.go | 3 +- internal/middleware/auth_middleware.go | 1 + internal/svc/account_model.go | 1 + internal/svc/logs.go | 1 + internal/svc/service_context.go | 1 + internal/svc/token.go | 1 + pkg/fileStorage/repository/aws_s3.go | 11 +- pkg/library/errors/errors.go | 1 + pkg/library/errors/errors_test.go | 1 + pkg/library/errors/from_errors.go | 1 + pkg/library/errors/from_errors_test.go | 1 + pkg/notification/repository/aws_ses_mailer.go | 1 + .../repository/mitake_sms_sender.go | 1 + pkg/notification/repository/smtp_mailer.go | 1 + pkg/notification/usecase/template.go | 2 +- pkg/permission/domain/config/config_test.go | 1 - pkg/permission/domain/config/errors.go | 1 - pkg/permission/domain/entity/blacklist.go | 1 - .../domain/entity/blacklist_test.go | 15 +- pkg/permission/domain/entity/permission.go | 1 + .../domain/entity/request_response.go | 1 - pkg/permission/domain/entity/role.go | 1 + .../domain/entity/role_permission.go | 1 + pkg/permission/domain/entity/token.go | 4 +- pkg/permission/domain/entity/token_test.go | 5 +- pkg/permission/domain/entity/user_role.go | 1 + .../domain/repository/permission.go | 1 + pkg/permission/domain/repository/role.go | 1 + pkg/permission/domain/repository/token.go | 7 +- pkg/permission/domain/repository/user_role.go | 1 + pkg/permission/domain/token/grant_type.go | 1 - .../domain/token/grant_type_test.go | 1 - .../domain/token/token_type_test.go | 1 - pkg/permission/domain/usecase/permission.go | 12 +- pkg/permission/domain/usecase/role.go | 6 +- pkg/permission/repository/permission_test.go | 6 +- .../repository/role_permission_test.go | 17 +- pkg/permission/repository/role_test.go | 5 +- pkg/permission/repository/testhelper_test.go | 1 - .../repository/token_blacklist_test.go | 11 +- pkg/permission/repository/user_role_test.go | 5 +- pkg/permission/usecase/permission_tree.go | 1 - .../usecase/permission_tree_test.go | 1 - pkg/permission/usecase/permission_usecase.go | 1 - .../usecase/role_permission_usecase.go | 1 - pkg/permission/usecase/role_usecase.go | 1 - pkg/permission/usecase/role_usecase_test.go | 2 +- pkg/permission/usecase/token_test.go | 413 ++++++++-------- pkg/permission/usecase/user_role_usecase.go | 1 - .../usecase/user_role_usecase_test.go | 4 +- 78 files changed, 897 insertions(+), 377 deletions(-) create mode 100644 generate/database/mongo/2024110500000001_account.down.txt create mode 100644 generate/database/mongo/2024110500000002_account_uid.down.txt create mode 100644 generate/database/mongo/2024110500000003_user.down.txt delete mode 100755 generate/database/mongo/2024121000000001_product.up.txt delete mode 100755 generate/database/mongo/2024121000000002_product_item.up.txt delete mode 100755 generate/database/mongo/2024121000000003_supplementary_info.up.txt delete mode 100755 generate/database/mongo/2024121800000001_cart.up.txt create mode 100644 generate/database/mongo/2025100900000001_permission.down.txt create mode 100644 generate/database/mongo/2025100900000001_permission.up.txt create mode 100644 generate/database/mongo/2025100900000002_role.down.txt create mode 100644 generate/database/mongo/2025100900000002_role.up.txt create mode 100644 generate/database/mongo/2025100900000003_role_permission.down.txt create mode 100644 generate/database/mongo/2025100900000003_role_permission.up.txt create mode 100644 generate/database/mongo/2025100900000004_user_role.down.txt create mode 100644 generate/database/mongo/2025100900000004_user_role.up.txt create mode 100644 generate/database/mongo/Doc/DATABASE_SCHEMA.md create mode 100644 generate/database/mongo/Doc/README.md diff --git a/Makefile b/Makefile index 4db4ca3..4e97a0f 100644 --- a/Makefile +++ b/Makefile @@ -7,22 +7,33 @@ LDFLAGS := -s -w VERSION="v1.0.0" DOCKER_REPO="refactor-service" + +# 默認目標 +.DEFAULT_GOAL := help + +# 顏色定義 +GREEN := \033[0;32m +YELLOW := \033[0;33m +NC := \033[0m # No Color +help: ## 顯示幫助訊息 + @echo "$(GREEN)可用命令:$(NC)" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(YELLOW)%-20s$(NC) %s\n", $$1, $$2}' + .PHONY: test -test: # 進行測試 +test: ## 進行測試 go test -v --cover ./... - .PHONY: gen-api -gen-api: # 產生 api +gen-api: ## 產生 api goctl api go -api ./generate/api/gateway.api -dir . -style go_zero .PHONY: gen-doc -gen-doc: # 生成 Swagger 文檔 +gen-doc: ## 生成 Swagger 文檔 # go-doc openapi --api ./generate/api/gateway.api --filename gateway.json --host dev-api.truheart.com.tw --basepath /api/v1 go-doc -a generate/api/gateway.api -d ./ -f gateway -s openapi3.0 .PHONY: mock-gen -mock-gen: # 建立 mock 資料 +mock-gen: ## 建立 mock 資料 mockgen -source=./pkg/member/domain/repository/account.go -destination=./pkg/member/mock/repository/account.go -package=mock mockgen -source=./pkg/member/domain/repository/account_uid.go -destination=./pkg/member/mock/repository/account_uid.go -package=mock mockgen -source=./pkg/member/domain/repository/auto_id.go -destination=./pkg/member/mock/repository/auto_id.go -package=mock @@ -45,48 +56,19 @@ mock-gen: # 建立 mock 資料 @echo "Generate mock files successfully" .PHONY: fmt -fmt: # 格式優化 +fmt: ## 格式優化 $(GOFMT) -w $(GOFILES) goimports -w ./ -.PHONY: build -build: # 編譯專案 - go build -ldflags "$(LDFLAGS)" -o bin/gateway cmd/gateway/main.go - .PHONY: run -run: # 運行專案 - go run cmd/gateway/main.go +run: ## 運行專案 + go run geteway.go .PHONY: clean -clean: # 清理編譯文件 +clean: ## 清理編譯文件 rm -rf bin/ -.PHONY: docker-build -docker-build: # 構建 Docker 映像 - docker build -t $(DOCKER_REPO):$(VERSION) . - -.PHONY: docker-run -docker-run: # 運行 Docker 容器 - docker run -p 8888:8888 $(DOCKER_REPO):$(VERSION) - .PHONY: install -install: # 安裝依賴 +install: ## 安裝依賴 go mod tidy - go mod download - -.PHONY: help -help: # 顯示幫助信息 - @echo "Available commands:" - @echo " test - 運行測試" - @echo " gen-api - 產生 api" - @echo " gen-doc - 生成 Swagger 文檔" - @echo " mock-gen - 建立 mock 資料" - @echo " fmt - 格式化代碼" - @echo " build - 編譯專案" - @echo " run - 運行專案" - @echo " clean - 清理編譯文件" - @echo " docker-build - 構建 Docker 映像" - @echo " docker-run - 運行 Docker 容器" - @echo " install - 安裝依賴" - @echo " help - 顯示幫助信息" - + go mod download \ No newline at end of file diff --git a/generate/api/file_storage.api b/generate/api/file_storage.api index fce2613..456052e 100644 --- a/generate/api/file_storage.api +++ b/generate/api/file_storage.api @@ -7,7 +7,7 @@ type UploadImgReq { } // 影片上傳請求(使用 multipart/form-data 文件上傳) -// 注意:文件字段需要在 handler 中通過 r.FormFile("file") 獲取 +// 注意:文件需要在 handler 中通過 r.FormFile("file") 獲取 type UploadVideoReq { Authorization } diff --git a/generate/database/mongo/20240422112701_audo_id.down.txt b/generate/database/mongo/20240422112701_audo_id.down.txt index 80451dc..fcdd721 100755 --- a/generate/database/mongo/20240422112701_audo_id.down.txt +++ b/generate/database/mongo/20240422112701_audo_id.down.txt @@ -1,2 +1 @@ -use digimon_member db.count.dropIndex("name_1"); \ No newline at end of file diff --git a/generate/database/mongo/20240422112701_audo_id.up.txt b/generate/database/mongo/20240422112701_audo_id.up.txt index 6d428b9..9c90032 100755 --- a/generate/database/mongo/20240422112701_audo_id.up.txt +++ b/generate/database/mongo/20240422112701_audo_id.up.txt @@ -1,2 +1 @@ -use digimon_member db.count.createIndex({ "name": 1 }, { unique: true }); \ No newline at end of file diff --git a/generate/database/mongo/2024110500000001_account.down.txt b/generate/database/mongo/2024110500000001_account.down.txt new file mode 100644 index 0000000..9bcee77 --- /dev/null +++ b/generate/database/mongo/2024110500000001_account.down.txt @@ -0,0 +1,3 @@ +db.account.dropIndex("login_id_1_platform_1"); +db.account.dropIndex("create_at_1"); + diff --git a/generate/database/mongo/2024110500000001_account.up.txt b/generate/database/mongo/2024110500000001_account.up.txt index 3b053e3..337efce 100755 --- a/generate/database/mongo/2024110500000001_account.up.txt +++ b/generate/database/mongo/2024110500000001_account.up.txt @@ -1,3 +1,2 @@ -use digimon_member; db.account.createIndex({ "login_id": 1, "platform": 1}, {unique: true}) db.account.createIndex({"create_at": 1}) diff --git a/generate/database/mongo/2024110500000002_account_uid.down.txt b/generate/database/mongo/2024110500000002_account_uid.down.txt new file mode 100644 index 0000000..1ad5dae --- /dev/null +++ b/generate/database/mongo/2024110500000002_account_uid.down.txt @@ -0,0 +1,4 @@ +db.account_uid_binding.dropIndex("login_id_1"); +db.account_uid_binding.dropIndex("uid_1"); +db.account_uid_binding.dropIndex("create_at_1"); + diff --git a/generate/database/mongo/2024110500000002_account_uid.up.txt b/generate/database/mongo/2024110500000002_account_uid.up.txt index e584c35..407f4f3 100755 --- a/generate/database/mongo/2024110500000002_account_uid.up.txt +++ b/generate/database/mongo/2024110500000002_account_uid.up.txt @@ -1,4 +1,3 @@ -use digimon_member; db.account_uid_binding.createIndex({"login_id": 1}, {unique: true}) db.account_uid_binding.createIndex({"uid": 1}) db.account_uid_binding.createIndex({"create_at": 1}) diff --git a/generate/database/mongo/2024110500000003_user.down.txt b/generate/database/mongo/2024110500000003_user.down.txt new file mode 100644 index 0000000..f0bcc22 --- /dev/null +++ b/generate/database/mongo/2024110500000003_user.down.txt @@ -0,0 +1,3 @@ +db.user_info.dropIndex("uid_1"); +db.user_info.dropIndex("create_at_1"); + diff --git a/generate/database/mongo/2024110500000003_user.up.txt b/generate/database/mongo/2024110500000003_user.up.txt index ec9f664..2c5d90e 100755 --- a/generate/database/mongo/2024110500000003_user.up.txt +++ b/generate/database/mongo/2024110500000003_user.up.txt @@ -1,3 +1,2 @@ -use digimon_member; db.user_info.createIndex({"uid": 1},{unique: true}) db.user_info.createIndex({"create_at": 1}) diff --git a/generate/database/mongo/2024121000000001_product.up.txt b/generate/database/mongo/2024121000000001_product.up.txt deleted file mode 100755 index aefee8c..0000000 --- a/generate/database/mongo/2024121000000001_product.up.txt +++ /dev/null @@ -1,22 +0,0 @@ -use digimon_product; - -# 精確查詢索引(針對 owner_uid, is_published, is_visible, created_at) -db.product.createIndex({"owner_uid": 1, "is_published": 1, "is_visible": 1, "created_at": -1}) - -# 範圍查詢索引(針對 start_time, end_time, created_at) -db.product.createIndex({"start_time": 1, "end_time": 1, "created_at": -1}) - -# 金額範圍索引(針對 target_amount, created_at) -db.product.createIndex({"target_amount": 1, "created_at": -1}) - -# 成功排序專用索引(針對 finished, updated_at) -db.product.createIndex({"finished": 1, "updated_at": -1}) - -# URL 精確查詢索引(針對 url_slug) -db.product.createIndex({"url_slug": 1}) - -# 基礎排序索引(針對 created_at 單列) -db.product.createIndex({"created_at": -1}) - -# URL 精確查詢索引(針對 url_slug) -db.product.createIndex({"category": 1}) \ No newline at end of file diff --git a/generate/database/mongo/2024121000000002_product_item.up.txt b/generate/database/mongo/2024121000000002_product_item.up.txt deleted file mode 100755 index 02565a4..0000000 --- a/generate/database/mongo/2024121000000002_product_item.up.txt +++ /dev/null @@ -1,9 +0,0 @@ -use digimon_product; - -# 精確查詢與範圍條件組合索引 -db.product_item.createIndex({"reference_id": 1}) # 精確匹配 reference_id -db.product_item.createIndex({"sale_start_time": 1, "sale_end_time": 1}) # 範圍查詢索引,提升 SaleStartTime 與 SaleEndTime 查詢效率 -db.product_item.createIndex({"status": 1}) # 精確查詢 status - -# 排序索引 -db.product_item.createIndex({"created_at": -1}) # 用於按 created_at 倒序排序 \ No newline at end of file diff --git a/generate/database/mongo/2024121000000003_supplementary_info.up.txt b/generate/database/mongo/2024121000000003_supplementary_info.up.txt deleted file mode 100755 index 5a4ab15..0000000 --- a/generate/database/mongo/2024121000000003_supplementary_info.up.txt +++ /dev/null @@ -1,8 +0,0 @@ -use digimon_product; - -# 精確查詢與範圍條件組合索引 -db.supplementary_info.createIndex({"reference_id": 1}) # 精確匹配 reference_id -db.supplementary_info.createIndex({"info_type": 1}) # 精確查詢 status - -# 排序索引 -db.supplementary_info.createIndex({"created_at": -1}) # 用於按 created_at 倒序排序 \ No newline at end of file diff --git a/generate/database/mongo/2024121800000001_cart.up.txt b/generate/database/mongo/2024121800000001_cart.up.txt deleted file mode 100755 index e2bc160..0000000 --- a/generate/database/mongo/2024121800000001_cart.up.txt +++ /dev/null @@ -1,6 +0,0 @@ -use digimon_cart; - -# 精確查詢與範圍條件組合索引 -db.cart.createIndex({ "uid": 1, "product_id": 1 }, { unique: true }) -# 排序索引 -db.supplementary_info.createIndex({"created_at": -1}) # 用於按 created_at 倒序排序 \ No newline at end of file diff --git a/generate/database/mongo/2025100900000001_permission.down.txt b/generate/database/mongo/2025100900000001_permission.down.txt new file mode 100644 index 0000000..d895ec8 --- /dev/null +++ b/generate/database/mongo/2025100900000001_permission.down.txt @@ -0,0 +1,7 @@ +db.permission.dropIndex("name_1"); +db.permission.dropIndex("http_path_1_http_method_1"); +db.permission.dropIndex("status_1"); +db.permission.dropIndex("parent_id_1"); +db.permission.dropIndex("type_1_status_1"); +db.permission.dropIndex("create_time_1"); + diff --git a/generate/database/mongo/2025100900000001_permission.up.txt b/generate/database/mongo/2025100900000001_permission.up.txt new file mode 100644 index 0000000..00ce5fe --- /dev/null +++ b/generate/database/mongo/2025100900000001_permission.up.txt @@ -0,0 +1,7 @@ +db.permission.createIndex({"name": 1}, {unique: true}); +db.permission.createIndex({"http_path": 1, "http_method": 1}, {unique: true, sparse: true}); +db.permission.createIndex({"status": 1}); +db.permission.createIndex({"parent_id": 1}); +db.permission.createIndex({"type": 1, "status": 1}); +db.permission.createIndex({"create_time": 1}); + diff --git a/generate/database/mongo/2025100900000002_role.down.txt b/generate/database/mongo/2025100900000002_role.down.txt new file mode 100644 index 0000000..6936dc0 --- /dev/null +++ b/generate/database/mongo/2025100900000002_role.down.txt @@ -0,0 +1,8 @@ +db.role.dropIndex("uid_1"); +db.role.dropIndex("client_id_1_name_1"); +db.role.dropIndex("client_id_1"); +db.role.dropIndex("status_1"); +db.role.dropIndex("client_id_1_status_1"); +db.role.dropIndex("create_time_1"); +db.role.dropIndex("update_time_-1"); + diff --git a/generate/database/mongo/2025100900000002_role.up.txt b/generate/database/mongo/2025100900000002_role.up.txt new file mode 100644 index 0000000..dbed02b --- /dev/null +++ b/generate/database/mongo/2025100900000002_role.up.txt @@ -0,0 +1,8 @@ +db.role.createIndex({"uid": 1}, {unique: true}); +db.role.createIndex({"client_id": 1, "name": 1}, {unique: true}); +db.role.createIndex({"client_id": 1}); +db.role.createIndex({"status": 1}); +db.role.createIndex({"client_id": 1, "status": 1}); +db.role.createIndex({"create_time": 1}); +db.role.createIndex({"update_time": -1}); + diff --git a/generate/database/mongo/2025100900000003_role_permission.down.txt b/generate/database/mongo/2025100900000003_role_permission.down.txt new file mode 100644 index 0000000..a3ef475 --- /dev/null +++ b/generate/database/mongo/2025100900000003_role_permission.down.txt @@ -0,0 +1,6 @@ +db.role_permission.dropIndex("role_id_1_permission_id_1"); +db.role_permission.dropIndex("role_id_1"); +db.role_permission.dropIndex("permission_id_1"); +db.role_permission.dropIndex("permission_id_1_status_1"); +db.role_permission.dropIndex("create_time_1"); + diff --git a/generate/database/mongo/2025100900000003_role_permission.up.txt b/generate/database/mongo/2025100900000003_role_permission.up.txt new file mode 100644 index 0000000..1bf8cf3 --- /dev/null +++ b/generate/database/mongo/2025100900000003_role_permission.up.txt @@ -0,0 +1,6 @@ +db.role_permission.createIndex({"role_id": 1, "permission_id": 1}, {unique: true}); +db.role_permission.createIndex({"role_id": 1}); +db.role_permission.createIndex({"permission_id": 1}); +db.role_permission.createIndex({"permission_id": 1, "status": 1}); +db.role_permission.createIndex({"create_time": 1}); + diff --git a/generate/database/mongo/2025100900000004_user_role.down.txt b/generate/database/mongo/2025100900000004_user_role.down.txt new file mode 100644 index 0000000..2b07cf6 --- /dev/null +++ b/generate/database/mongo/2025100900000004_user_role.down.txt @@ -0,0 +1,8 @@ +db.user_role.dropIndex("uid_1"); +db.user_role.dropIndex("role_id_1"); +db.user_role.dropIndex("brand_1"); +db.user_role.dropIndex("status_1"); +db.user_role.dropIndex("brand_1_role_id_1"); +db.user_role.dropIndex("brand_1_status_1"); +db.user_role.dropIndex("create_time_1"); + diff --git a/generate/database/mongo/2025100900000004_user_role.up.txt b/generate/database/mongo/2025100900000004_user_role.up.txt new file mode 100644 index 0000000..89edcbb --- /dev/null +++ b/generate/database/mongo/2025100900000004_user_role.up.txt @@ -0,0 +1,8 @@ +db.user_role.createIndex({"uid": 1}, {unique: true}); +db.user_role.createIndex({"role_id": 1}); +db.user_role.createIndex({"brand": 1}); +db.user_role.createIndex({"status": 1}); +db.user_role.createIndex({"brand": 1, "role_id": 1}); +db.user_role.createIndex({"brand": 1, "status": 1}); +db.user_role.createIndex({"create_time": 1}); + diff --git a/generate/database/mongo/2025101200000001_roles.up.txt b/generate/database/mongo/2025101200000001_roles.up.txt index 2e15e49..8200639 100644 --- a/generate/database/mongo/2025101200000001_roles.up.txt +++ b/generate/database/mongo/2025101200000001_roles.up.txt @@ -22,11 +22,13 @@ db.role.insertMany([ "status": 1, "create_time": NumberLong(1728745200), "update_time": NumberLong(1728745200) - } -]); - -// 建立索引 -db.role.createIndex({ "uid": 1 }, { unique: true }); -db.role.createIndex({ "client_id": 1 }); -db.role.createIndex({ "status": 1 }); - + }, + { + "client_id": 1, + "uid": "PLAYER", + "name": "陪玩專員", + "status": 1, + "create_time": NumberLong(1728745200), + "update_time": NumberLong(1728745200) + }, +]); \ No newline at end of file diff --git a/generate/database/mongo/Doc/DATABASE_SCHEMA.md b/generate/database/mongo/Doc/DATABASE_SCHEMA.md new file mode 100644 index 0000000..3f2be1b --- /dev/null +++ b/generate/database/mongo/Doc/DATABASE_SCHEMA.md @@ -0,0 +1,457 @@ +# MongoDB 資料庫結構文檔 + +本文檔描述所有 MongoDB 集合(Collection)的結構定義。 + +## 目錄 + +- [Member 模組](#member-模組) + - [account](#account) + - [account_uid_binding](#account_uid_binding) + - [user_info](#user_info) + - [count](#count) +- [Permission 模組](#permission-模組) + - [permission](#permission) + - [role](#role) + - [role_permission](#role_permission) + - [user_role](#user_role) + +--- + +## Member 模組 + +### account + +**集合名稱**: `account` + +**說明**: 用戶帳號認證資訊,儲存登入憑證、加密密碼和平台相關資料。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `login_id` | string | 是 | 唯一登入識別碼(email、phone、username) | +| `token` | string | 是 | 加密後的密碼或平台特定的 token | +| `platform` | int8 | 是 | 平台類型:1=credentials, 2=google, 3=line, 4=apple | +| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) | +| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) | + +#### 索引 + +1. **複合唯一索引**: `{login_id: 1, platform: 1}` + - 確保同一平台下 login_id 唯一 +2. **時間索引**: `{create_at: 1}` + - 用於按建立時間排序和查詢 + +#### Platform 枚舉值 + +- `1` = credentials (Digimon 平台) +- `2` = google +- `3` = line +- `4` = apple + +#### AccountType 枚舉值 + +- `1` = phone (手機) +- `2` = email (信箱) +- `3` = platform (自定義帳號) + +#### AlarmType 枚舉值 + +- `0` = uninitialized (未初始化) +- `1` = no_alert (未告警) +- `2` = system_alert (系統告警中) + +--- + +### account_uid_binding + +**集合名稱**: `account_uid_binding` + +**說明**: 帳號與 UID 的綁定關係,用於將多個帳號(不同平台)綁定到同一個用戶。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `login_id` | string | 是 | 登入識別碼 | +| `uid` | string | 是 | 用戶唯一識別碼 | +| `type` | int32 | 是 | 帳號類型:1=phone, 2=email, 3=platform | +| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) | +| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) | + +#### 索引 + +1. **唯一索引**: `{login_id: 1}` + - 確保 login_id 唯一 +2. **索引**: `{uid: 1}` + - 用於查詢某用戶的所有帳號綁定 +3. **時間索引**: `{create_at: 1}` + - 用於按建立時間排序 + +--- + +### user_info + +**集合名稱**: `user_info` + +**說明**: 用戶個人資料,包含詳細的用戶資訊,與認證憑證分離。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `uid` | string | 是 | 用戶唯一識別碼 | +| `avatar_url` | string | 否 | 用戶頭像 URL | +| `full_name` | string | 否 | 用戶全名 | +| `nickname` | string | 否 | 用戶暱稱 | +| `gender_code` | int64 | 否 | 性別代碼 | +| `birthdate` | int64 | 否 | 生日(格式:19930417) | +| `address` | string | 否 | 用戶地址 | +| `alarm_category` | int32 | 是 | 通知設定類型:0=未初始化, 1=未告警, 2=系統告警中 | +| `user_status` | int32 | 是 | 用戶帳號狀態:0=未初始化, 1=未驗證, 2=啟用中, 3=停權中 | +| `preferred_language` | string | 是 | 偏好語言 | +| `currency` | string | 是 | 偏好貨幣 | +| `phone_number` | string | 否 | 電話號碼(驗證後顯示) | +| `email` | string | 否 | 電子郵件(驗證後顯示) | +| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) | +| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) | + +#### 索引 + +1. **唯一索引**: `{uid: 1}` + - 確保 uid 唯一 +2. **時間索引**: `{create_at: 1}` + - 用於按建立時間排序 + +#### UserStatus 枚舉值 + +- `0` = uninitialized (未初始化) +- `1` = unverified (尚未驗證) +- `2` = active (啟用中) +- `3` = suspended (停權中) + +--- + +### count + +**集合名稱**: `count` + +**說明**: 自增 ID 計數器,用於生成唯一序號。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `name` | string | 是 | 計數器名稱(唯一) | +| `counter` | uint64 | 是 | 當前計數值 | +| `create_at` | int64 | 否 | 建立時間(Unix 時間戳,納秒) | +| `update_at` | int64 | 否 | 更新時間(Unix 時間戳,納秒) | + +#### 索引 + +1. **唯一索引**: `{name: 1}` + - 確保計數器名稱唯一 + +--- + +## Permission 模組 + +### permission + +**集合名稱**: `permission` + +**說明**: 權限實體,定義系統中的各種權限,支援階層結構和 API 權限。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `parent_id` | ObjectID | 否 | 父權限 ID(用於階層結構) | +| `name` | string | 是 | 權限名稱(唯一) | +| `http_method` | string | 否 | HTTP 方法(GET、POST、PUT、DELETE 等) | +| `http_path` | string | 否 | HTTP 路徑(API 端點) | +| `status` | int8 | 是 | 權限狀態:0=停用, 1=啟用, 2=已刪除 | +| `type` | int8 | 是 | 權限類型:1=後台權限, 2=前台權限 | +| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) | +| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) | + +#### 索引 + +1. **唯一索引**: `{name: 1}` + - 確保權限名稱唯一 +2. **複合唯一稀疏索引**: `{http_path: 1, http_method: 1}` (sparse: true) + - 確保 API 權限的路徑和方法組合唯一(只索引存在這些欄位的文檔) +3. **查詢索引**: `{status: 1}` + - 用於查詢啟用/停用的權限 +4. **查詢索引**: `{parent_id: 1}` + - 用於查詢子權限 +5. **複合索引**: `{type: 1, status: 1}` + - 用於按類型和狀態組合查詢 +6. **時間戳索引**: `{create_time: 1}` + - 用於排序和時間範圍查詢 + +#### RecordState 枚舉值 + +- `0` = inactive (停用) +- `1` = active (啟用) +- `2` = deleted (已刪除) + +#### Type 枚舉值 + +- `1` = backend (後台權限) +- `2` = frontend (前台權限) + +--- + +### role + +**集合名稱**: `role` + +**說明**: 角色實體,定義系統中的角色,每個角色可以擁有多個權限。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `client_id` | int | 是 | 客戶端 ID | +| `uid` | string | 是 | 角色唯一識別碼(唯一) | +| `name` | string | 是 | 角色名稱 | +| `status` | int8 | 是 | 角色狀態:0=停用, 1=啟用, 2=已刪除 | +| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) | +| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) | + +#### 索引 + +1. **唯一索引**: `{uid: 1}` + - 確保角色 UID 唯一 +2. **複合唯一索引**: `{client_id: 1, name: 1}` + - 確保同一客戶端下角色名稱唯一 +3. **查詢索引**: `{client_id: 1}` + - 用於按客戶端查詢 +4. **查詢索引**: `{status: 1}` + - 用於按狀態查詢 +5. **複合索引**: `{client_id: 1, status: 1}` + - 用於按客戶端和狀態組合查詢 +6. **時間戳索引**: `{create_time: 1}` + - 用於排序和時間範圍查詢 +7. **時間戳索引**: `{update_time: -1}` (降序) + - 用於按更新時間排序 + +#### 預設角色數據 + +系統會自動插入以下初始角色: + +- `ADMIN` - 管理員 +- `OPERATOR` - 操作員 +- `USER` - 一般使用者 +- `PLAYER` - 陪玩專員 + +--- + +### role_permission + +**集合名稱**: `role_permission` + +**說明**: 角色權限關聯表,建立角色與權限的多對多關係。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `role_id` | ObjectID | 是 | 角色 ID | +| `permission_id` | ObjectID | 是 | 權限 ID | +| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) | +| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) | + +#### 索引 + +1. **複合唯一索引**: `{role_id: 1, permission_id: 1}` + - 確保角色和權限的組合唯一(避免重複關聯) +2. **查詢索引**: `{role_id: 1}` + - 用於查詢某角色的所有權限 +3. **查詢索引**: `{permission_id: 1}` + - 用於查詢擁有某權限的所有角色 +4. **複合索引**: `{permission_id: 1, status: 1}` + - 用於按權限和狀態組合查詢 +5. **時間戳索引**: `{create_time: 1}` + - 用於排序和時間範圍查詢 + +--- + +### user_role + +**集合名稱**: `user_role` + +**說明**: 用戶角色關聯表,建立用戶與角色的關係(一個用戶只能有一個角色)。 + +#### 欄位定義 + +| 欄位名稱 | 類型 | 必填 | 說明 | +|---------|------|------|------| +| `_id` | ObjectID | 是 | MongoDB 自動生成的唯一識別碼 | +| `brand` | string | 是 | 品牌識別碼 | +| `uid` | string | 是 | 用戶唯一識別碼(唯一) | +| `role_id` | string | 是 | 角色 ID(角色 UID) | +| `status` | int8 | 是 | 狀態:0=停用, 1=啟用, 2=已刪除 | +| `create_time` | int64 | 是 | 建立時間(Unix 時間戳,秒) | +| `update_time` | int64 | 是 | 更新時間(Unix 時間戳,秒) | + +#### 索引 + +1. **唯一索引**: `{uid: 1}` + - 確保一個用戶只能有一個角色 +2. **查詢索引**: `{role_id: 1}` + - 用於查詢某角色的所有用戶 +3. **查詢索引**: `{brand: 1}` + - 用於按品牌查詢 +4. **查詢索引**: `{status: 1}` + - 用於按狀態查詢 +5. **複合索引**: `{brand: 1, role_id: 1}` + - 用於按品牌和角色組合查詢 +6. **複合索引**: `{brand: 1, status: 1}` + - 用於按品牌和狀態組合查詢 +7. **時間戳索引**: `{create_time: 1}` + - 用於排序和時間範圍查詢 + +--- + +## 資料類型說明 + +### 時間戳記 + +- **Member 模組**: 使用 `int64` 類型,單位為納秒(nanoseconds),欄位名為 `create_at`、`update_at` +- **Permission 模組**: 使用 `int64` 類型,單位為秒(seconds),欄位名為 `create_time`、`update_time` + +### 枚舉類型 + +#### Platform (平台類型) +- `1` = credentials (Digimon 平台) +- `2` = google +- `3` = line +- `4` = apple + +#### Status (帳號狀態) +- `0` = uninitialized (未初始化) +- `1` = unverified (尚未驗證) +- `2` = active (啟用中) +- `3` = suspended (停權中) + +#### RecordState (記錄狀態) +- `0` = inactive (停用) +- `1` = active (啟用) +- `2` = deleted (已刪除) + +#### Type (權限類型) +- `1` = backend (後台權限) +- `2` = frontend (前台權限) + +#### AccountType (帳號類型) +- `1` = phone (手機) +- `2` = email (信箱) +- `3` = platform (自定義帳號) + +#### AlarmType (通知類型) +- `0` = uninitialized (未初始化) +- `1` = no_alert (未告警) +- `2` = system_alert (系統告警中) + +--- + +## 索引總覽 + +### Member 模組索引 + +| 集合 | 索引類型 | 索引欄位 | 唯一 | 說明 | +|------|---------|---------|------|------| +| account | 複合唯一 | login_id, platform | ✅ | 確保同一平台下 login_id 唯一 | +| account | 單一 | create_at | ❌ | 時間排序 | +| account_uid_binding | 唯一 | login_id | ✅ | 確保 login_id 唯一 | +| account_uid_binding | 單一 | uid | ❌ | 查詢用戶的所有帳號 | +| account_uid_binding | 單一 | create_at | ❌ | 時間排序 | +| user_info | 唯一 | uid | ✅ | 確保 uid 唯一 | +| user_info | 單一 | create_at | ❌ | 時間排序 | +| count | 唯一 | name | ✅ | 確保計數器名稱唯一 | + +### Permission 模組索引 + +| 集合 | 索引類型 | 索引欄位 | 唯一 | 稀疏 | 說明 | +|------|---------|---------|------|------|------| +| permission | 唯一 | name | ✅ | ❌ | 權限名稱唯一 | +| permission | 複合唯一稀疏 | http_path, http_method | ✅ | ✅ | API 權限唯一 | +| permission | 單一 | status | ❌ | ❌ | 狀態查詢 | +| permission | 單一 | parent_id | ❌ | ❌ | 子權限查詢 | +| permission | 複合 | type, status | ❌ | ❌ | 類型和狀態組合查詢 | +| permission | 單一 | create_time | ❌ | ❌ | 時間排序 | +| role | 唯一 | uid | ✅ | ❌ | 角色 UID 唯一 | +| role | 複合唯一 | client_id, name | ✅ | ❌ | 同客戶端下角色名稱唯一 | +| role | 單一 | client_id | ❌ | ❌ | 客戶端查詢 | +| role | 單一 | status | ❌ | ❌ | 狀態查詢 | +| role | 複合 | client_id, status | ❌ | ❌ | 客戶端和狀態組合查詢 | +| role | 單一 | create_time | ❌ | ❌ | 時間排序 | +| role | 單一 | update_time | ❌ | ❌ | 更新時間排序(降序) | +| role_permission | 複合唯一 | role_id, permission_id | ✅ | ❌ | 避免重複關聯 | +| role_permission | 單一 | role_id | ❌ | ❌ | 角色權限查詢 | +| role_permission | 單一 | permission_id | ❌ | ❌ | 權限角色查詢 | +| role_permission | 複合 | permission_id, status | ❌ | ❌ | 權限和狀態組合查詢 | +| role_permission | 單一 | create_time | ❌ | ❌ | 時間排序 | +| user_role | 唯一 | uid | ✅ | ❌ | 一個用戶一個角色 | +| user_role | 單一 | role_id | ❌ | ❌ | 角色用戶查詢 | +| user_role | 單一 | brand | ❌ | ❌ | 品牌查詢 | +| user_role | 單一 | status | ❌ | ❌ | 狀態查詢 | +| user_role | 複合 | brand, role_id | ❌ | ❌ | 品牌和角色組合查詢 | +| user_role | 複合 | brand, status | ❌ | ❌ | 品牌和狀態組合查詢 | +| user_role | 單一 | create_time | ❌ | ❌ | 時間排序 | + +--- + +## 關聯關係 + +### Member 模組 + +``` +account (1) ──< (N) account_uid_binding (N) >── (1) user_info +``` + +- 一個 `account` 可以對應一個 `account_uid_binding` +- 一個 `user_info` 可以對應多個 `account_uid_binding`(多個帳號綁定到同一用戶) + +### Permission 模組 + +``` +role (N) <──> (N) permission (透過 role_permission) +user_role (N) >── (1) role +``` + +- 角色和權限是多對多關係(透過 `role_permission`) +- 用戶和角色是一對一關係(透過 `user_role`,一個用戶只能有一個角色) + +--- + +## 注意事項 + +1. **時間戳記差異**: + - Member 模組使用納秒級時間戳(`create_at`、`update_at`) + - Permission 模組使用秒級時間戳(`create_time`、`update_time`) + +2. **唯一性約束**: + - `account`: `login_id + platform` 組合必須唯一 + - `account_uid_binding`: `login_id` 必須唯一 + - `user_info`: `uid` 必須唯一 + - `permission`: `name` 必須唯一,`http_path + http_method` 組合必須唯一(稀疏索引) + - `role`: `uid` 必須唯一,`client_id + name` 組合必須唯一 + - `role_permission`: `role_id + permission_id` 組合必須唯一 + - `user_role`: `uid` 必須唯一(一個用戶只能有一個角色) + +3. **稀疏索引**: + - `permission` 集合的 `http_path + http_method` 索引是稀疏索引,只索引存在這些欄位的文檔 + +4. **預設數據**: + - `role` 集合會自動插入 4 個預設角色:ADMIN、OPERATOR、USER、PLAYER + diff --git a/generate/database/mongo/Doc/README.md b/generate/database/mongo/Doc/README.md new file mode 100644 index 0000000..e8c7366 --- /dev/null +++ b/generate/database/mongo/Doc/README.md @@ -0,0 +1,52 @@ +# MongoDB 資料庫文檔 + +本目錄包含 MongoDB 資料庫的結構文檔和相關說明。 + +## 文件說明 + +### DATABASE_SCHEMA.md + +完整的資料庫結構文檔,包含: + +- **所有集合(Collection)的結構定義** + - 欄位名稱、類型、必填性、說明 + - 索引定義和用途 + - 枚舉值說明 + +- **索引總覽** + - 所有集合的索引列表 + - 索引類型和唯一性說明 + +- **關聯關係** + - 集合之間的關聯圖 + - 一對一、一對多、多對多關係說明 + +- **資料類型說明** + - 時間戳記格式差異 + - 枚舉類型定義 + +## 集合列表 + +### Member 模組 +- `account` - 用戶帳號認證資訊 +- `account_uid_binding` - 帳號與 UID 綁定關係 +- `user_info` - 用戶個人資料 +- `count` - 自增 ID 計數器 + +### Permission 模組 +- `permission` - 權限實體 +- `role` - 角色實體 +- `role_permission` - 角色權限關聯表 +- `user_role` - 用戶角色關聯表 + +## 使用方式 + +1. **查看集合結構**:打開 `DATABASE_SCHEMA.md`,搜尋集合名稱 +2. **了解索引**:查看「索引總覽」章節 +3. **了解關聯**:查看「關聯關係」章節 +4. **了解枚舉值**:查看各集合的「枚舉值」說明 + +## 更新說明 + +當資料庫結構發生變更時,請更新 `DATABASE_SCHEMA.md` 文檔,確保文檔與實際結構保持一致。 + diff --git a/go.mod b/go.mod index 5300f0e..4a573bd 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ses v1.34.9 github.com/go-playground/validator/v10 v10.28.0 github.com/golang-jwt/jwt/v4 v4.5.2 + github.com/google/uuid v1.6.0 github.com/matcornic/hermes/v2 v2.1.0 github.com/minchao/go-mitake v1.0.0 github.com/panjf2000/ants/v2 v2.11.3 @@ -63,7 +64,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/grafana/pyroscope-go v1.2.7 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect diff --git a/internal/handler/fileStorage/upload_video_handler.go b/internal/handler/fileStorage/upload_video_handler.go index c631746..1373756 100644 --- a/internal/handler/fileStorage/upload_video_handler.go +++ b/internal/handler/fileStorage/upload_video_handler.go @@ -7,6 +7,7 @@ import ( "backend/internal/logic/fileStorage" "backend/internal/svc" "backend/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" ) diff --git a/internal/handler/user/get_user_info_handler.go b/internal/handler/user/get_user_info_handler.go index 930ff60..07e19f4 100644 --- a/internal/handler/user/get_user_info_handler.go +++ b/internal/handler/user/get_user_info_handler.go @@ -7,6 +7,7 @@ import ( "backend/internal/logic/user" "backend/internal/svc" "backend/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" ) diff --git a/internal/logic/user/get_user_info_logic.go b/internal/logic/user/get_user_info_logic.go index 4b1ac5e..5975e3f 100644 --- a/internal/logic/user/get_user_info_logic.go +++ b/internal/logic/user/get_user_info_logic.go @@ -5,9 +5,10 @@ import ( "backend/pkg/member/domain/usecase" "backend/pkg/permission/domain/token" "context" - "google.golang.org/protobuf/proto" "time" + "google.golang.org/protobuf/proto" + "backend/internal/svc" "backend/internal/types" diff --git a/internal/middleware/auth_middleware.go b/internal/middleware/auth_middleware.go index ff282cd..70dfbbe 100644 --- a/internal/middleware/auth_middleware.go +++ b/internal/middleware/auth_middleware.go @@ -6,6 +6,7 @@ import ( "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/token" "context" + "github.com/zeromicro/go-zero/rest/httpx" "backend/pkg/permission/domain/usecase" diff --git a/internal/svc/account_model.go b/internal/svc/account_model.go index 464d3ad..8320add 100644 --- a/internal/svc/account_model.go +++ b/internal/svc/account_model.go @@ -8,6 +8,7 @@ import ( "backend/pkg/member/repository" uc "backend/pkg/member/usecase" "context" + "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/cache" diff --git a/internal/svc/logs.go b/internal/svc/logs.go index 0b05ce1..4a871ce 100644 --- a/internal/svc/logs.go +++ b/internal/svc/logs.go @@ -3,6 +3,7 @@ package svc import ( errs "backend/pkg/library/errors" "context" + "github.com/zeromicro/go-zero/core/logx" ) diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 36ae88c..0448754 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -6,6 +6,7 @@ import ( errs "backend/pkg/library/errors" "backend/pkg/library/errors/code" "context" + "github.com/zeromicro/go-zero/core/logx" fileStorageUC "backend/pkg/fileStorage/domain/usecase" diff --git a/internal/svc/token.go b/internal/svc/token.go index 53a8eb2..5af7122 100644 --- a/internal/svc/token.go +++ b/internal/svc/token.go @@ -7,6 +7,7 @@ import ( "backend/pkg/permission/repository" uc "backend/pkg/permission/usecase" "context" + "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/mon" diff --git a/pkg/fileStorage/repository/aws_s3.go b/pkg/fileStorage/repository/aws_s3.go index dc528cf..0d134e9 100644 --- a/pkg/fileStorage/repository/aws_s3.go +++ b/pkg/fileStorage/repository/aws_s3.go @@ -9,17 +9,18 @@ import ( "bytes" "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" "io" "net/http" "os" "path" "strings" "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/s3/s3manager" ) type AwsS3FileStorageRepositoryParam struct { diff --git a/pkg/library/errors/errors.go b/pkg/library/errors/errors.go index b0babab..c6ec229 100644 --- a/pkg/library/errors/errors.go +++ b/pkg/library/errors/errors.go @@ -6,6 +6,7 @@ import ( "net/http" "backend/pkg/library/errors/code" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/pkg/library/errors/errors_test.go b/pkg/library/errors/errors_test.go index dc07090..6980ffb 100644 --- a/pkg/library/errors/errors_test.go +++ b/pkg/library/errors/errors_test.go @@ -6,6 +6,7 @@ import ( "testing" "backend/pkg/library/errors/code" + "google.golang.org/grpc/codes" ) diff --git a/pkg/library/errors/from_errors.go b/pkg/library/errors/from_errors.go index ce8664a..8e7eb57 100644 --- a/pkg/library/errors/from_errors.go +++ b/pkg/library/errors/from_errors.go @@ -4,6 +4,7 @@ import ( "errors" "backend/pkg/library/errors/code" + "google.golang.org/grpc/status" ) diff --git a/pkg/library/errors/from_errors_test.go b/pkg/library/errors/from_errors_test.go index aaee2ca..c4e9165 100644 --- a/pkg/library/errors/from_errors_test.go +++ b/pkg/library/errors/from_errors_test.go @@ -6,6 +6,7 @@ import ( "testing" "backend/pkg/library/errors/code" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/pkg/notification/repository/aws_ses_mailer.go b/pkg/notification/repository/aws_ses_mailer.go index f693836..d7e1ac9 100644 --- a/pkg/notification/repository/aws_ses_mailer.go +++ b/pkg/notification/repository/aws_ses_mailer.go @@ -4,6 +4,7 @@ import ( "backend/pkg/notification/config" "backend/pkg/notification/domain/repository" "context" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/ses" diff --git a/pkg/notification/repository/mitake_sms_sender.go b/pkg/notification/repository/mitake_sms_sender.go index e47b85e..4edda01 100644 --- a/pkg/notification/repository/mitake_sms_sender.go +++ b/pkg/notification/repository/mitake_sms_sender.go @@ -4,6 +4,7 @@ import ( "backend/pkg/notification/config" "backend/pkg/notification/domain/repository" "context" + "github.com/minchao/go-mitake" ) diff --git a/pkg/notification/repository/smtp_mailer.go b/pkg/notification/repository/smtp_mailer.go index 27ec6a8..57a048f 100644 --- a/pkg/notification/repository/smtp_mailer.go +++ b/pkg/notification/repository/smtp_mailer.go @@ -4,6 +4,7 @@ import ( "backend/pkg/notification/config" "backend/pkg/notification/domain/repository" "context" + "gopkg.in/gomail.v2" ) diff --git a/pkg/notification/usecase/template.go b/pkg/notification/usecase/template.go index 561ddae..bcaa85c 100644 --- a/pkg/notification/usecase/template.go +++ b/pkg/notification/usecase/template.go @@ -14,7 +14,7 @@ import ( type TemplateUseCaseParam struct { TemplateRepo repository.TemplateRepository // 可選的資料庫模板 repository - Logger errs.Logger // 日誌記錄器 + Logger errs.Logger // 日誌記錄器 } type TemplateUseCase struct { diff --git a/pkg/permission/domain/config/config_test.go b/pkg/permission/domain/config/config_test.go index 7c6046c..b4bab73 100644 --- a/pkg/permission/domain/config/config_test.go +++ b/pkg/permission/domain/config/config_test.go @@ -240,4 +240,3 @@ func TestTokenConfig_AllDefaults(t *testing.T) { assert.Equal(t, token.MaxTokensPerUser, config.MaxTokensPerUser) assert.Equal(t, token.MaxTokensPerDevice, config.MaxTokensPerDevice) } - diff --git a/pkg/permission/domain/config/errors.go b/pkg/permission/domain/config/errors.go index c8fee92..25110c0 100644 --- a/pkg/permission/domain/config/errors.go +++ b/pkg/permission/domain/config/errors.go @@ -7,4 +7,3 @@ import ( var ( ErrMissingSecret = fmt.Errorf("missing JWT secret key") ) - diff --git a/pkg/permission/domain/entity/blacklist.go b/pkg/permission/domain/entity/blacklist.go index 5d1faf1..1c0aed7 100644 --- a/pkg/permission/domain/entity/blacklist.go +++ b/pkg/permission/domain/entity/blacklist.go @@ -30,4 +30,3 @@ func (b *BlacklistEntry) Validate() error { } return nil } - diff --git a/pkg/permission/domain/entity/blacklist_test.go b/pkg/permission/domain/entity/blacklist_test.go index 75545e2..36ec7c0 100644 --- a/pkg/permission/domain/entity/blacklist_test.go +++ b/pkg/permission/domain/entity/blacklist_test.go @@ -9,9 +9,9 @@ import ( func TestBlacklistEntry_IsExpired(t *testing.T) { tests := []struct { - name string - entry *BlacklistEntry - expected bool + name string + entry *BlacklistEntry + expected bool }{ { name: "expired entry", @@ -58,9 +58,9 @@ func TestBlacklistEntry_IsExpired(t *testing.T) { func TestBlacklistEntry_Validate(t *testing.T) { tests := []struct { - name string - entry *BlacklistEntry - wantErr bool + name string + entry *BlacklistEntry + wantErr bool expectedErr error }{ { @@ -126,7 +126,7 @@ func TestBlacklistEntry_Validate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.entry.Validate() - + if tt.wantErr { assert.Error(t, err) if tt.expectedErr != nil { @@ -191,4 +191,3 @@ func TestBlacklistEntry_Reason(t *testing.T) { }) } } - diff --git a/pkg/permission/domain/entity/permission.go b/pkg/permission/domain/entity/permission.go index 82c9905..16186ba 100644 --- a/pkg/permission/domain/entity/permission.go +++ b/pkg/permission/domain/entity/permission.go @@ -2,6 +2,7 @@ package entity import ( "backend/pkg/permission/domain/permission" + "go.mongodb.org/mongo-driver/v2/bson" ) diff --git a/pkg/permission/domain/entity/request_response.go b/pkg/permission/domain/entity/request_response.go index 694450e..e6d4951 100644 --- a/pkg/permission/domain/entity/request_response.go +++ b/pkg/permission/domain/entity/request_response.go @@ -82,4 +82,3 @@ type DoTokenByDeviceIDReq struct { type CancelOneTimeTokenReq struct { Token []string `json:"token"` // 一次性 Token 列表 } - diff --git a/pkg/permission/domain/entity/role.go b/pkg/permission/domain/entity/role.go index fe1cd53..88ac858 100644 --- a/pkg/permission/domain/entity/role.go +++ b/pkg/permission/domain/entity/role.go @@ -2,6 +2,7 @@ package entity import ( "backend/pkg/permission/domain/permission" + "go.mongodb.org/mongo-driver/v2/bson" ) diff --git a/pkg/permission/domain/entity/role_permission.go b/pkg/permission/domain/entity/role_permission.go index 5d8f5ba..4980131 100644 --- a/pkg/permission/domain/entity/role_permission.go +++ b/pkg/permission/domain/entity/role_permission.go @@ -2,6 +2,7 @@ package entity import ( "backend/pkg/permission/domain/permission" + "go.mongodb.org/mongo-driver/v2/bson" ) diff --git a/pkg/permission/domain/entity/token.go b/pkg/permission/domain/entity/token.go index 923fea1..c7d13ee 100644 --- a/pkg/permission/domain/entity/token.go +++ b/pkg/permission/domain/entity/token.go @@ -2,7 +2,7 @@ package entity import ( "time" - + "github.com/golang-jwt/jwt/v4" ) @@ -62,4 +62,4 @@ func (t *Token) Validate() error { return ErrInvalidAccessToken } return nil -} \ No newline at end of file +} diff --git a/pkg/permission/domain/entity/token_test.go b/pkg/permission/domain/entity/token_test.go index f4183dc..4f698e1 100644 --- a/pkg/permission/domain/entity/token_test.go +++ b/pkg/permission/domain/entity/token_test.go @@ -122,7 +122,7 @@ func TestToken_RedisRefreshExpiredSec(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.token.RedisRefreshExpiredSec() - + if tt.expected == 0 { assert.Equal(t, 0, result) } else { @@ -195,7 +195,7 @@ func TestToken_Validate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.token.Validate() - + if tt.wantErr { assert.Error(t, err) if tt.expectedErr != nil { @@ -315,4 +315,3 @@ func TestToken_Timestamps(t *testing.T) { assert.Equal(t, now, token.AccessCreateAt) assert.True(t, token.RefreshCreateAt.After(token.AccessCreateAt)) } - diff --git a/pkg/permission/domain/entity/user_role.go b/pkg/permission/domain/entity/user_role.go index 085cc6d..5d4c113 100644 --- a/pkg/permission/domain/entity/user_role.go +++ b/pkg/permission/domain/entity/user_role.go @@ -2,6 +2,7 @@ package entity import ( "backend/pkg/permission/domain/permission" + "go.mongodb.org/mongo-driver/v2/bson" ) diff --git a/pkg/permission/domain/repository/permission.go b/pkg/permission/domain/repository/permission.go index 5820737..e31f862 100644 --- a/pkg/permission/domain/repository/permission.go +++ b/pkg/permission/domain/repository/permission.go @@ -3,6 +3,7 @@ package repository import ( "backend/pkg/permission/domain/entity" "context" + mongodriver "go.mongodb.org/mongo-driver/v2/mongo" ) diff --git a/pkg/permission/domain/repository/role.go b/pkg/permission/domain/repository/role.go index 8d9589f..be2a0e6 100644 --- a/pkg/permission/domain/repository/role.go +++ b/pkg/permission/domain/repository/role.go @@ -4,6 +4,7 @@ import ( "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/permission" "context" + mongodriver "go.mongodb.org/mongo-driver/v2/mongo" ) diff --git a/pkg/permission/domain/repository/token.go b/pkg/permission/domain/repository/token.go index 055877b..eca50c2 100644 --- a/pkg/permission/domain/repository/token.go +++ b/pkg/permission/domain/repository/token.go @@ -3,11 +3,12 @@ package repository import ( "context" "time" - + "backend/pkg/permission/domain/entity" ) // TokenRepository 定義了與 Redis 相關的 Token 操作方法 +// //nolint:interfacebloat type TokenRepository interface { // Create 建立新的 Token 並存儲至 Redis @@ -36,7 +37,7 @@ type TokenRepository interface { DeleteAccessTokensByUID(ctx context.Context, uid string) error // DeleteAccessTokensByDeviceID 根據裝置 ID 刪除該裝置的所有存取 Token DeleteAccessTokensByDeviceID(ctx context.Context, deviceID string) error - + // Blacklist operations // AddToBlacklist 將 JWT token 加入黑名單 AddToBlacklist(ctx context.Context, entry *entity.BlacklistEntry, ttl time.Duration) error @@ -46,4 +47,4 @@ type TokenRepository interface { RemoveFromBlacklist(ctx context.Context, jti string) error // GetBlacklistedTokensByUID 獲取用戶的所有黑名單 token GetBlacklistedTokensByUID(ctx context.Context, uid string) ([]*entity.BlacklistEntry, error) -} \ No newline at end of file +} diff --git a/pkg/permission/domain/repository/user_role.go b/pkg/permission/domain/repository/user_role.go index f1c637b..cba3ce5 100644 --- a/pkg/permission/domain/repository/user_role.go +++ b/pkg/permission/domain/repository/user_role.go @@ -4,6 +4,7 @@ import ( "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/permission" "context" + mongodriver "go.mongodb.org/mongo-driver/v2/mongo" ) diff --git a/pkg/permission/domain/token/grant_type.go b/pkg/permission/domain/token/grant_type.go index e4ab740..afa8a5b 100644 --- a/pkg/permission/domain/token/grant_type.go +++ b/pkg/permission/domain/token/grant_type.go @@ -23,4 +23,3 @@ const ( ClientCredentials GrantType = "client_credentials" Refreshing GrantType = "refresh_token" ) - diff --git a/pkg/permission/domain/token/grant_type_test.go b/pkg/permission/domain/token/grant_type_test.go index dd291fe..331f9d8 100644 --- a/pkg/permission/domain/token/grant_type_test.go +++ b/pkg/permission/domain/token/grant_type_test.go @@ -157,4 +157,3 @@ func TestGrantType_CaseSensitive(t *testing.T) { assert.False(t, gt2.IsValid()) }) } - diff --git a/pkg/permission/domain/token/token_type_test.go b/pkg/permission/domain/token/token_type_test.go index 0ccf1e6..cd77dc2 100644 --- a/pkg/permission/domain/token/token_type_test.go +++ b/pkg/permission/domain/token/token_type_test.go @@ -337,4 +337,3 @@ func TestKeyPrefixUniqueness(t *testing.T) { assert.Equal(t, len(prefixes), len(seen)) }) } - diff --git a/pkg/permission/domain/usecase/permission.go b/pkg/permission/domain/usecase/permission.go index 1988cda..c3c2931 100644 --- a/pkg/permission/domain/usecase/permission.go +++ b/pkg/permission/domain/usecase/permission.go @@ -21,13 +21,13 @@ type PermissionUseCase interface { // PermissionResponse 權限回應 type PermissionResponse struct { - ID string `json:"id"` - ParentID string `json:"parent_id"` - Name string `json:"name"` - HTTPPath string `json:"http_path,omitempty"` - HTTPMethod string `json:"http_method,omitempty"` + ID string `json:"id"` + ParentID string `json:"parent_id"` + Name string `json:"name"` + HTTPPath string `json:"http_path,omitempty"` + HTTPMethod string `json:"http_method,omitempty"` Status permission.AccessState `json:"status"` - Type permission.Type `json:"type"` + Type permission.Type `json:"type"` } // PermissionTreeNode 權限樹節點 diff --git a/pkg/permission/domain/usecase/role.go b/pkg/permission/domain/usecase/role.go index c49fa22..d749a08 100644 --- a/pkg/permission/domain/usecase/role.go +++ b/pkg/permission/domain/usecase/role.go @@ -30,9 +30,9 @@ type CreateRoleRequest struct { // UpdateRoleRequest 更新角色請求 type UpdateRoleRequest struct { - Name *string `json:"name"` - Status *permission.RecordState `json:"status"` - Permissions permission.Permissions `json:"permissions"` + Name *string `json:"name"` + Status *permission.RecordState `json:"status"` + Permissions permission.Permissions `json:"permissions"` } // RoleFilterRequest 角色查詢過濾請求 diff --git a/pkg/permission/repository/permission_test.go b/pkg/permission/repository/permission_test.go index 69e0fba..9edecbe 100644 --- a/pkg/permission/repository/permission_test.go +++ b/pkg/permission/repository/permission_test.go @@ -7,12 +7,14 @@ import ( domainRepo "backend/pkg/permission/domain/repository" "context" "fmt" - "github.com/alicebob/miniredis/v2" - "github.com/zeromicro/go-zero/core/stores/redis" "testing" "time" + "github.com/alicebob/miniredis/v2" + "github.com/zeromicro/go-zero/core/stores/redis" + mgo "backend/pkg/library/mongo" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/core/stores/cache" diff --git a/pkg/permission/repository/role_permission_test.go b/pkg/permission/repository/role_permission_test.go index 25b99a8..2d88300 100644 --- a/pkg/permission/repository/role_permission_test.go +++ b/pkg/permission/repository/role_permission_test.go @@ -105,7 +105,7 @@ func TestRolePermissionRepository_Create(t *testing.T) { assert.Error(t, err) } else { assert.NoError(t, err) - + // 注意:由於 ObjectID 生成機制,GetByRoleID 無法查到剛創建的數據 // 這是因為 roleID 每次轉換為 ObjectID 時都會生成不同的值 // 在實際使用中應該使用真實的 ObjectID 而不是 int64 @@ -116,7 +116,7 @@ func TestRolePermissionRepository_Create(t *testing.T) { func TestRolePermissionRepository_GetByRoleID(t *testing.T) { t.Skip("跳過:由於 int64 到 ObjectID 轉換問題,此測試無法正常運行。實際使用時應使用真實的 ObjectID") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -132,7 +132,7 @@ func TestRolePermissionRepository_GetByRoleID(t *testing.T) { func TestRolePermissionRepository_GetByRoleIDs(t *testing.T) { t.Skip("跳過:由於 int64 到 ObjectID 轉換問題,此測試無法正常運行。實際使用時應使用真實的 ObjectID") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -148,7 +148,7 @@ func TestRolePermissionRepository_GetByRoleIDs(t *testing.T) { func TestRolePermissionRepository_GetByPermissionIDs(t *testing.T) { t.Skip("跳過:由於 int64 到 ObjectID 轉換問題,此測試無法正常運行。實際使用時應使用真實的 ObjectID") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -164,7 +164,7 @@ func TestRolePermissionRepository_GetByPermissionIDs(t *testing.T) { func TestRolePermissionRepository_GetRolesByPermission(t *testing.T) { t.Skip("跳過:由於 int64 到 ObjectID 轉換問題,此測試無法正常運行。實際使用時應使用真實的 ObjectID") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -180,7 +180,7 @@ func TestRolePermissionRepository_GetRolesByPermission(t *testing.T) { func TestRolePermissionRepository_Update(t *testing.T) { t.Skip("跳過:由於 int64 到 ObjectID 轉換問題,此測試無法正常運行。實際使用時應使用真實的 ObjectID") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -195,7 +195,7 @@ func TestRolePermissionRepository_Update(t *testing.T) { func TestRolePermissionRepository_Delete(t *testing.T) { t.Skip("跳過:由於 int64 到 ObjectID 轉換問題,此測試無法正常運行。實際使用時應使用真實的 ObjectID") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -210,7 +210,7 @@ func TestRolePermissionRepository_Delete(t *testing.T) { func TestRolePermissionRepository_CreateDuplicateShouldFail(t *testing.T) { t.Skip("跳過:由於 ObjectID 生成機制,每次創建都會生成新的 roleID ObjectID,無法觸發唯一索引衝突") - + repo, tearDown, err := setupRolePermissionRepo("testDB") defer tearDown() assert.NoError(t, err) @@ -246,4 +246,3 @@ func TestRolePermissionRepository_IndexCreation(t *testing.T) { assert.NotNil(t, cursor) }) } - diff --git a/pkg/permission/repository/role_test.go b/pkg/permission/repository/role_test.go index e611038..18f2294 100644 --- a/pkg/permission/repository/role_test.go +++ b/pkg/permission/repository/role_test.go @@ -6,11 +6,12 @@ import ( domainRepo "backend/pkg/permission/domain/repository" "context" "fmt" - "github.com/alicebob/miniredis/v2" - "github.com/zeromicro/go-zero/core/stores/redis" "testing" "time" + "github.com/alicebob/miniredis/v2" + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/core/stores/cache" diff --git a/pkg/permission/repository/testhelper_test.go b/pkg/permission/repository/testhelper_test.go index 901ad9f..4692884 100644 --- a/pkg/permission/repository/testhelper_test.go +++ b/pkg/permission/repository/testhelper_test.go @@ -51,4 +51,3 @@ func startMongoContainer() (string, string, func(), error) { return host, port.Port(), tearDown, nil } - diff --git a/pkg/permission/repository/token_blacklist_test.go b/pkg/permission/repository/token_blacklist_test.go index da90609..a0e2b70 100644 --- a/pkg/permission/repository/token_blacklist_test.go +++ b/pkg/permission/repository/token_blacklist_test.go @@ -91,7 +91,7 @@ func TestTokenRepository_Blacklist(t *testing.T) { t.Run("GetBlacklistedTokensByUID", func(t *testing.T) { uid := "user789" - + // Add multiple entries for the same user entries := []*entity.BlacklistEntry{ { @@ -102,7 +102,7 @@ func TestTokenRepository_Blacklist(t *testing.T) { CreatedAt: time.Now().Unix(), }, { - JTI: "jti-2", + JTI: "jti-2", UID: uid, TokenID: "token-2", ExpiresAt: time.Now().Add(time.Hour).Unix(), @@ -245,7 +245,7 @@ func TestTokenRepository_CreateAndGet(t *testing.T) { t.Run("GetAccessTokenCountByUID", func(t *testing.T) { uid := "user789" now := time.Now() - + // Create multiple tokens for the user for i := 0; i < 3; i++ { token := entity.Token{ @@ -296,7 +296,7 @@ func TestTokenRepository_CreateAndGet(t *testing.T) { t.Run("DeleteAccessTokensByUID", func(t *testing.T) { uid := "delete-user-uid" now := time.Now() - + // Create multiple tokens for the user for i := 0; i < 2; i++ { token := entity.Token{ @@ -355,12 +355,11 @@ func TestTokenRepository_OneTimeToken(t *testing.T) { assert.NoError(t, err) }) - t.Run("DeleteOneTimeToken", func(t *testing.T) { // Create one-time tokens keys := []string{"delete-key-1", "delete-key-2"} ticket := entity.Ticket{ - Data: map[string]string{"test": "data"}, + Data: map[string]string{"test": "data"}, Token: entity.Token{ID: "test-token"}, } diff --git a/pkg/permission/repository/user_role_test.go b/pkg/permission/repository/user_role_test.go index 2212fe6..0371818 100644 --- a/pkg/permission/repository/user_role_test.go +++ b/pkg/permission/repository/user_role_test.go @@ -6,11 +6,12 @@ import ( domainRepo "backend/pkg/permission/domain/repository" "context" "fmt" - "github.com/alicebob/miniredis/v2" - "github.com/zeromicro/go-zero/core/stores/redis" "testing" "time" + "github.com/alicebob/miniredis/v2" + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/core/stores/cache" diff --git a/pkg/permission/usecase/permission_tree.go b/pkg/permission/usecase/permission_tree.go index f661d45..e85a398 100644 --- a/pkg/permission/usecase/permission_tree.go +++ b/pkg/permission/usecase/permission_tree.go @@ -314,4 +314,3 @@ func (t *PermissionTree) detectCircular(node *PermissionNode, visited map[string return nil } - diff --git a/pkg/permission/usecase/permission_tree_test.go b/pkg/permission/usecase/permission_tree_test.go index b20fefd..b8ddc79 100644 --- a/pkg/permission/usecase/permission_tree_test.go +++ b/pkg/permission/usecase/permission_tree_test.go @@ -156,4 +156,3 @@ func TestPermissionTree_DetectCircularDependency(t *testing.T) { err := tree.DetectCircularDependency() assert.NoError(t, err) } - diff --git a/pkg/permission/usecase/permission_usecase.go b/pkg/permission/usecase/permission_usecase.go index adca086..c35b6b3 100644 --- a/pkg/permission/usecase/permission_usecase.go +++ b/pkg/permission/usecase/permission_usecase.go @@ -235,4 +235,3 @@ func ConvertInt64ToOID(id int64) bson.ObjectID { } return bson.NewObjectIDFromTimestamp(time.Unix(id, 0)) } - diff --git a/pkg/permission/usecase/role_permission_usecase.go b/pkg/permission/usecase/role_permission_usecase.go index fe8c710..7a282e6 100644 --- a/pkg/permission/usecase/role_permission_usecase.go +++ b/pkg/permission/usecase/role_permission_usecase.go @@ -202,4 +202,3 @@ func (uc *rolePermissionUseCase) getAllPermissions(ctx context.Context) (permiss return permissions, nil } - diff --git a/pkg/permission/usecase/role_usecase.go b/pkg/permission/usecase/role_usecase.go index ec4a981..c6a8a22 100644 --- a/pkg/permission/usecase/role_usecase.go +++ b/pkg/permission/usecase/role_usecase.go @@ -276,4 +276,3 @@ func (uc *roleUseCase) toResponseList(ctx context.Context, roles []*entity.Role, return result } - diff --git a/pkg/permission/usecase/role_usecase_test.go b/pkg/permission/usecase/role_usecase_test.go index e5b4bb5..05e5c90 100644 --- a/pkg/permission/usecase/role_usecase_test.go +++ b/pkg/permission/usecase/role_usecase_test.go @@ -49,7 +49,7 @@ func TestRoleUseCase_Create(t *testing.T) { mockSetup: func() { mockRoleRepo.EXPECT().NextID(ctx).Return(int64(1), nil) mockRoleRepo.EXPECT().Create(ctx, gomock.Any()).Return(nil) - + role := &entity.Role{ ID: bson.NewObjectID(), UID: "ROLE0000000001", diff --git a/pkg/permission/usecase/token_test.go b/pkg/permission/usecase/token_test.go index c1fec24..2bf488c 100644 --- a/pkg/permission/usecase/token_test.go +++ b/pkg/permission/usecase/token_test.go @@ -87,21 +87,21 @@ func TestTokenUseCase_NewToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -223,21 +223,21 @@ func TestTokenUseCase_RefreshToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -342,21 +342,21 @@ func TestTokenUseCase_ValidationToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -462,21 +462,21 @@ func TestTokenUseCase_CancelToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -567,21 +567,21 @@ func TestTokenUseCase_CancelTokens(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -644,21 +644,21 @@ func TestTokenUseCase_CancelTokenByDeviceID(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -757,21 +757,21 @@ func TestTokenUseCase_GetUserTokensByUID(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -851,21 +851,21 @@ func TestTokenUseCase_GetUserTokensByDeviceID(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -986,21 +986,21 @@ func TestTokenUseCase_NewOneTimeToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -1064,21 +1064,21 @@ func TestTokenUseCase_CancelOneTimeToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -1156,21 +1156,21 @@ func TestTokenUseCase_ReadTokenBasicData(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -1262,21 +1262,21 @@ func TestTokenUseCase_BlacklistToken(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -1296,11 +1296,11 @@ func TestTokenUseCase_IsTokenBlacklisted(t *testing.T) { ctx := context.Background() tests := []struct { - name string - jti string - mockSetup func(*mockRepo.MockTokenRepository) + name string + jti string + mockSetup func(*mockRepo.MockTokenRepository) wantBlacklisted bool - wantErr bool + wantErr bool }{ { name: "Token 在黑名單中", @@ -1349,21 +1349,21 @@ func TestTokenUseCase_IsTokenBlacklisted(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -1403,9 +1403,9 @@ func TestTokenUseCase_BlacklistAllUserTokens(t *testing.T) { // 為每個 token 創建 JWT claims1 := entity.Claims{ Data: map[string]string{ - "uid": "user123", - "jti": "jti1", - "exp": fmt.Sprintf("%d", expires), + "uid": "user123", + "jti": "jti1", + "exp": fmt.Sprintf("%d", expires), }, RegisteredClaims: jwt.RegisteredClaims{ ID: "jti1", @@ -1418,9 +1418,9 @@ func TestTokenUseCase_BlacklistAllUserTokens(t *testing.T) { claims2 := entity.Claims{ Data: map[string]string{ - "uid": "user123", - "jti": "jti2", - "exp": fmt.Sprintf("%d", expires), + "uid": "user123", + "jti": "jti2", + "exp": fmt.Sprintf("%d", expires), }, RegisteredClaims: jwt.RegisteredClaims{ ID: "jti2", @@ -1495,21 +1495,21 @@ func TestTokenUseCase_BlacklistAllUserTokens(t *testing.T) { TokenRepo: mockTokenRepo, Config: &config.Config{ Token: struct { - AccessSecret string - RefreshSecret string - AccessTokenExpiry time.Duration - RefreshTokenExpiry time.Duration - OneTimeTokenExpiry time.Duration - MaxTokensPerUser int - MaxTokensPerDevice int + AccessSecret string + RefreshSecret string + AccessTokenExpiry time.Duration + RefreshTokenExpiry time.Duration + OneTimeTokenExpiry time.Duration + MaxTokensPerUser int + MaxTokensPerDevice int }{ - AccessSecret: "test-secret", - AccessTokenExpiry: time.Hour, - RefreshTokenExpiry: time.Hour * 24, - RefreshSecret: "refresh-secret", - OneTimeTokenExpiry: time.Minute * 5, - MaxTokensPerUser: 10, - MaxTokensPerDevice: 5, + AccessSecret: "test-secret", + AccessTokenExpiry: time.Hour, + RefreshTokenExpiry: time.Hour * 24, + RefreshSecret: "refresh-secret", + OneTimeTokenExpiry: time.Minute * 5, + MaxTokensPerUser: 10, + MaxTokensPerDevice: 5, }, }, }) @@ -1524,4 +1524,3 @@ func TestTokenUseCase_BlacklistAllUserTokens(t *testing.T) { }) } } - diff --git a/pkg/permission/usecase/user_role_usecase.go b/pkg/permission/usecase/user_role_usecase.go index 9f6fcdc..111770d 100644 --- a/pkg/permission/usecase/user_role_usecase.go +++ b/pkg/permission/usecase/user_role_usecase.go @@ -149,4 +149,3 @@ func (uc *userRoleUseCase) toResponse(userRole *entity.UserRole) *usecase.UserRo UpdateTime: time.Unix(userRole.UpdateTime, 0).UTC().Format(time.RFC3339), } } - diff --git a/pkg/permission/usecase/user_role_usecase_test.go b/pkg/permission/usecase/user_role_usecase_test.go index 4f66612..e977cfe 100644 --- a/pkg/permission/usecase/user_role_usecase_test.go +++ b/pkg/permission/usecase/user_role_usecase_test.go @@ -148,7 +148,7 @@ func TestUserRoleUseCase_Update(t *testing.T) { Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000002").Return(role, nil) - + updatedUserRole := &entity.UserRole{ ID: bson.NewObjectID(), Brand: "brand1", @@ -354,7 +354,7 @@ func TestUserRoleUseCase_GetByRole(t *testing.T) { Status: domain.RecordActive, } mockRoleRepo.EXPECT().GetByUID(ctx, "ROLE0000000001").Return(role, nil) - + userRoles := []*entity.UserRole{ {ID: bson.NewObjectID(), UID: "user1", RoleID: "ROLE0000000001"}, {ID: bson.NewObjectID(), UID: "user2", RoleID: "ROLE0000000001"},