diff --git a/deployment/docker-compose.yaml b/deployment/docker-compose.yaml index ba1bc9d..cf0f4eb 100644 --- a/deployment/docker-compose.yaml +++ b/deployment/docker-compose.yaml @@ -8,7 +8,6 @@ services: environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: example - etcd: image: quay.io/coreos/etcd:v3.5.5 container_name: etcd @@ -22,10 +21,21 @@ services: ports: - "2379:2379" - "2380:2380" - redis: image: redis:7.0 container_name: redis restart: always ports: - - "6379:6379" \ No newline at end of file + - "6379:6379" + + minio: + image: minio/minio + container_name: minio + ports: + - "9000:9000" # MinIO S3 API port + - "9001:9001" # MinIO Console port + environment: + MINIO_ROOT_USER: minioadmin # Replace with your desired root username + MINIO_ROOT_PASSWORD: minioadmin # Replace with your desired root password + # MINIO_DEFAULT_BUCKETS: mybucket # Optional: Create a default bucket on startup + command: server /data --console-address ":9001" # Start MinIO server and specify console address diff --git a/etc/gateway.yaml b/etc/gateway.yaml index e125572..552284e 100644 --- a/etc/gateway.yaml +++ b/etc/gateway.yaml @@ -69,10 +69,10 @@ DeliveryConfig: enable_history: false AmazonS3Settings: Region: ap-northeast-3 - Bucket: - CloudFrontDomain: - CloudFrontURI: - BucketURI: - AccessKey: - SecretKey: - CloudFrontID: \ No newline at end of file + Bucket: gutenbergtw-prod + CloudFrontDomain: d2gk3kpttfhhhf.cloudfront.net + CloudFrontURI: https://d2gk3kpttfhhhf.cloudfront.net + BucketURI: https://gutenbergtw-prod.s3.ap-northeast-3.amazonaws.com + AccessKey: AKIAVRUVVY4IJOBFOY42 + SecretKey: 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 + CloudFrontID: E3UMOQ0CGBOBAE \ No newline at end of file diff --git a/gateway.json b/gateway.json index 363bef2..b6254a3 100644 --- a/gateway.json +++ b/gateway.json @@ -29,27 +29,6 @@ ], "type": "object" }, - "ErrorResp": { - "properties": { - "code": { - "type": "integer" - }, - "details": { - "type": "string" - }, - "error": { - "description": "可選的錯誤信息" - }, - "msg": { - "type": "string" - } - }, - "required": [ - "code", - "msg" - ], - "type": "object" - }, "LoginReq": { "properties": { "auth_method": { @@ -97,6 +76,100 @@ ], "type": "object" }, + "MyInfo": { + "properties": { + "address": { + "description": "地址", + "type": "string" + }, + "alarm_category": { + "description": "告警狀態", + "type": "string" + }, + "avatar_url": { + "description": "頭像 URL", + "type": "string" + }, + "birthdate": { + "description": "生日 (格式: 1993-04-17)", + "type": "string" + }, + "carrier": { + "description": "載具", + "type": "string" + }, + "create_at": { + "type": "string" + }, + "currency": { + "description": "偏好幣種", + "type": "string" + }, + "email": { + "description": "信箱", + "type": "string" + }, + "full_name": { + "description": "用戶全名", + "type": "string" + }, + "gender_code": { + "description": "性別代碼", + "type": "string" + }, + "is_email_verified": { + "description": "信箱是否已驗證", + "type": "boolean" + }, + "is_phone_verified": { + "description": "手機是否已驗證", + "type": "boolean" + }, + "nickname": { + "description": "暱稱", + "type": "string" + }, + "phone_number": { + "description": "電話", + "type": "string" + }, + "platform": { + "description": "註冊平台", + "type": "string" + }, + "post_code": { + "description": "郵遞區號", + "type": "string" + }, + "preferred_language": { + "description": "偏好語言", + "type": "string" + }, + "role": { + "description": "角色", + "type": "string" + }, + "uid": { + "description": "用戶 UID", + "type": "string" + }, + "update_at": { + "type": "string" + }, + "user_status": { + "description": "用戶狀態", + "type": "string" + } + }, + "required": [ + "platform", + "uid", + "role", + "update_at", + "create_at" + ], + "type": "object" + }, "PagerResp": { "properties": { "index": { @@ -135,11 +208,15 @@ }, "RefreshTokenReq": { "properties": { + "access_token": { + "type": "string" + }, "refresh_token": { "type": "string" } }, "required": [ + "access_token", "refresh_token" ], "type": "object" @@ -182,6 +259,9 @@ }, "RequestVerificationCodeReq": { "properties": { + "Account": { + "type": "string" + }, "purpose": { "type": "string" } @@ -217,24 +297,33 @@ ], "type": "object" }, - "RespOK": { + "Resp": { "properties": { "code": { - "type": "integer" + "type": "string" }, "data": {}, - "msg": { + "error": { + "description": "可選的錯誤信息" + }, + "message": { "type": "string" } }, "required": [ "code", - "msg" + "message" ], "type": "object" }, + "RespOK": { + "type": "object" + }, "SubmitVerificationCodeReq": { "properties": { + "Account": { + "type": "string" + }, "purpose": { "type": "string" }, @@ -316,6 +405,41 @@ }, "type": "object" }, + "UploadImgReq": { + "properties": { + "content": { + "description": "base64 編碼的圖片內容", + "type": "string" + } + }, + "required": [ + "content" + ], + "type": "object" + }, + "UploadResp": { + "properties": { + "file_size": { + "description": "文件大小(bytes)", + "type": "integer" + }, + "file_url": { + "description": "文件訪問 URL", + "type": "string" + }, + "mime_type": { + "description": "MIME 類型", + "type": "string" + } + }, + "required": [ + "file_url" + ], + "type": "object" + }, + "UploadVideoReq": { + "type": "object" + }, "UserInfoResp": { "properties": { "address": { @@ -330,10 +454,6 @@ "description": "生日 (格式: 1993-04-17)", "type": "string" }, - "carrier": { - "description": "載具", - "type": "string" - }, "create_at": { "type": "string" }, @@ -361,10 +481,6 @@ "description": "手機是否已驗證", "type": "boolean" }, - "national": { - "description": "國家", - "type": "string" - }, "nickname": { "description": "暱稱", "type": "string" @@ -377,10 +493,6 @@ "description": "註冊平台", "type": "string" }, - "post_code": { - "description": "郵遞區號", - "type": "string" - }, "preferred_language": { "description": "偏好語言", "type": "string" @@ -417,9 +529,6 @@ "user_status", "preferred_language", "currency", - "national", - "post_code", - "carrier", "role", "update_at", "create_at" @@ -482,9 +591,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"驗證碼無效或請求參數錯誤\"" @@ -492,9 +599,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -531,9 +636,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤\"" @@ -541,9 +644,7 @@ "429": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求過於頻繁\" // 429 Too Many Requests" @@ -551,9 +652,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -590,9 +689,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"驗證碼無效或已過期\"" @@ -600,9 +697,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -639,9 +734,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤\"" @@ -649,9 +742,7 @@ "409": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"帳號已被註冊\" // 409 Conflict: 資源衝突" @@ -659,9 +750,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -698,9 +787,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤\"" @@ -708,9 +795,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"帳號或密碼錯誤 / 無效的平台 Token\" // 401 Unauthorized" @@ -718,9 +803,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -757,9 +840,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤\"" @@ -767,9 +848,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"無效或已過期的 Refresh Token\" // 401 Unauthorized" @@ -777,9 +856,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -788,6 +865,72 @@ "summary": "刷新 Access Token" } }, + "/api/v1/fileStorage/fileStorage/img/upload": { + "post": { + "description": "上傳轉成 base64 過後的圖片,建議圖片大小不超過 10MB", + "operationId": "fileStorageUploadImgHandler", + "parameters": [ + { + "in": "header", + "name": "Authorization", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadImgReq" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadResp" + } + } + }, + "description": "" + } + }, + "summary": "create - 上傳圖片檔案" + } + }, + "/api/v1/fileStorage/fileStorage/video/upload": { + "post": { + "description": "使用 multipart/form-data 上傳影片檔案,form field 名稱為 'file',注意:大檔案(\u003e50MB)建議使用分片上傳機制", + "operationId": "fileStorageUploadVideoHandler", + "parameters": [ + { + "in": "header", + "name": "Authorization", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadResp" + } + } + }, + "description": "" + } + }, + "summary": "create - 上傳影片檔案" + } + }, "/api/v1/health": { "get": { "description": "檢查系統服務狀態,用於監控和負載均衡器健康檢查。返回系統運行狀態信息。", @@ -831,9 +974,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"未授權或 Token 無效\"" @@ -841,9 +982,7 @@ "404": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"找不到使用者\"" @@ -851,9 +990,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -888,9 +1025,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤\"" @@ -898,9 +1033,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"未授權或 Token 無效\"" @@ -908,9 +1041,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -956,9 +1087,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤或新舊密碼不符\"" @@ -966,9 +1095,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"未授權或 Token 無效\"" @@ -976,9 +1103,7 @@ "403": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"當前密碼不正確\" // 403 Forbidden" @@ -986,9 +1111,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -1034,9 +1157,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求參數格式錯誤\"" @@ -1044,9 +1165,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"未授權或 Token 無效\"" @@ -1054,9 +1173,7 @@ "429": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"請求過於頻繁\" // 429 Too Many Requests" @@ -1064,9 +1181,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -1110,9 +1225,7 @@ "400": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"驗證碼無效或已過期\"" @@ -1120,9 +1233,7 @@ "401": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "\"未授權或 Token 無效\"" @@ -1130,9 +1241,7 @@ "500": { "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResp" - } + "schema": {} } }, "description": "// 伺服器內部錯誤" @@ -1150,7 +1259,7 @@ "url": "https://localhost:8888" } ], - "x-date": "2025-10-02 23:03:53", + "x-date": "2025-11-12 14:59:58", "x-description": "This is a go-doc generated swagger file.", "x-generator": "go-doc", "x-github": "https://github.com/danielchan-25/go-doc", diff --git a/internal/logic/fileStorage/upload_img_logic.go b/internal/logic/fileStorage/upload_img_logic.go index 2317a53..0380ca0 100644 --- a/internal/logic/fileStorage/upload_img_logic.go +++ b/internal/logic/fileStorage/upload_img_logic.go @@ -1,6 +1,7 @@ package fileStorage import ( + "backend/pkg/permission/domain/token" "context" "encoding/base64" "fmt" @@ -20,7 +21,7 @@ type UploadImgLogic struct { svcCtx *svc.ServiceContext } -// 上傳圖片檔案 +// NewUploadImgLogic 上傳圖片檔案 func NewUploadImgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadImgLogic { return &UploadImgLogic{ Logger: logx.WithContext(ctx), @@ -62,7 +63,7 @@ func (l *UploadImgLogic) UploadImg(req *types.UploadImgReq) (resp *types.UploadR // 生成唯一文件名 fileExt := l.getExtensionFromMimeType(mimeType) fileName := fmt.Sprintf("%s%s", uuid.New().String(), fileExt) - objectPath := fmt.Sprintf("images/%d/%s", time.Now().Year(), fileName) + objectPath := fmt.Sprintf("images/%s/%d/%s", token.UID(l.ctx), time.Now().Year(), fileName) // 上傳到 S3 fileStorageUC := l.svcCtx.FileStorageUC diff --git a/internal/logic/fileStorage/upload_video_logic.go b/internal/logic/fileStorage/upload_video_logic.go index 7077d05..c6fdd81 100644 --- a/internal/logic/fileStorage/upload_video_logic.go +++ b/internal/logic/fileStorage/upload_video_logic.go @@ -1,6 +1,7 @@ package fileStorage import ( + "backend/pkg/permission/domain/token" "context" "fmt" "io" @@ -65,7 +66,7 @@ func (l *UploadVideoLogic) UploadVideo(req *types.UploadVideoReq, file multipart fileExt = l.getExtensionFromMimeType(mimeType) } fileName := fmt.Sprintf("%s%s", uuid.New().String(), fileExt) - objectPath := fmt.Sprintf("videos/%d/%s", time.Now().Year(), fileName) + objectPath := fmt.Sprintf("videos/%s/%d/%s", token.UID(l.ctx), time.Now().Year(), fileName) // 上傳到 S3 fileStorageUC := l.svcCtx.FileStorageUC