feat: add upload logic

This commit is contained in:
王性驊 2025-11-12 15:38:56 +08:00
parent 0d13e54be5
commit 28b232159f
5 changed files with 274 additions and 153 deletions

View File

@ -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"
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

View File

@ -69,10 +69,10 @@ DeliveryConfig:
enable_history: false
AmazonS3Settings:
Region: ap-northeast-3
Bucket:
CloudFrontDomain:
CloudFrontURI:
BucketURI:
AccessKey:
SecretKey:
CloudFrontID:
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

View File

@ -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",

View File

@ -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

View File

@ -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