feat: 完善照片更新和删除业务逻辑
- 实现照片更新功能 (updatePhotoLogic.go) - 支持部分字段更新 (title, description, category_id) - 添加用户权限验证,只能更新自己的照片 - 添加分类存在性验证 - 完善错误处理和响应格式 - 实现照片删除功能 (deletePhotoLogic.go) - 添加用户权限验证,只能删除自己的照片 - 同时删除数据库记录和文件系统文件 - 安全的文件删除处理 - 更新Handler使用统一响应格式 - updatePhotoHandler.go: 使用response.Response统一处理 - deletePhotoHandler.go: 使用response.Response统一处理 - 添加完整API测试用例 (test_photo_crud.http) - 涵盖正常场景和错误场景测试 - 包含权限验证测试 - 更新项目进度 (TASK_PROGRESS.md) - 完成率从8%提升到12% - 更新API接口状态 - 记录技术成果和里程碑
This commit is contained in:
241
TASK_PROGRESS.md
Normal file
241
TASK_PROGRESS.md
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
# Photography Portfolio 项目任务进度
|
||||||
|
|
||||||
|
> 最后更新: 2025-01-10
|
||||||
|
> 项目状态: 开发中 🚧
|
||||||
|
|
||||||
|
## 📊 总体进度概览
|
||||||
|
|
||||||
|
- **总任务数**: 26
|
||||||
|
- **已完成**: 3 ✅
|
||||||
|
- **进行中**: 0 🔄
|
||||||
|
- **待开始**: 23 ⏳
|
||||||
|
- **完成率**: 12%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔥 高优先级任务 (9/26)
|
||||||
|
|
||||||
|
### ✅ 已完成 (3/9)
|
||||||
|
|
||||||
|
#### 1. ✅ 完善照片上传功能
|
||||||
|
**状态**: 已完成 ✅
|
||||||
|
**完成时间**: 2025-01-10
|
||||||
|
**完成内容**:
|
||||||
|
- 创建了完整的文件处理工具包 (`pkg/utils/file/file.go`)
|
||||||
|
- 实现了图片上传、缩略图生成、文件存储
|
||||||
|
- 支持多种图片格式 (JPEG, PNG, GIF, WebP)
|
||||||
|
- 添加了文件大小和类型验证
|
||||||
|
- 实现了自动缩略图生成 (300px宽度)
|
||||||
|
- 更新了上传处理器支持 multipart form
|
||||||
|
- 更新了业务逻辑层处理文件上传
|
||||||
|
- 添加了静态文件服务 (`/uploads/*`)
|
||||||
|
- 集成了图片处理库 (`github.com/disintegration/imaging`)
|
||||||
|
|
||||||
|
#### 2. ✅ 实现 JWT 认证中间件
|
||||||
|
**状态**: 已完成 ✅
|
||||||
|
**完成时间**: 2025-01-10
|
||||||
|
**完成内容**:
|
||||||
|
- 创建了 JWT 认证中间件 (`internal/middleware/auth.go`)
|
||||||
|
- 实现了 Bearer Token 验证
|
||||||
|
- 支持用户信息注入到请求上下文
|
||||||
|
- 完善的错误处理和响应
|
||||||
|
- 与现有 JWT 工具包集成
|
||||||
|
- go-zero 框架已内置 JWT 支持,路由配置完整
|
||||||
|
|
||||||
|
#### 3. ✅ 完善照片更新和删除业务逻辑
|
||||||
|
**状态**: 已完成 ✅
|
||||||
|
**完成时间**: 2025-01-10
|
||||||
|
**完成内容**:
|
||||||
|
- 实现了完整的照片更新逻辑 (`updatePhotoLogic.go`)
|
||||||
|
- 参数验证和权限检查
|
||||||
|
- 支持部分字段更新 (title, description, category_id)
|
||||||
|
- 分类存在性验证
|
||||||
|
- 用户权限验证 (只能更新自己的照片)
|
||||||
|
- 实现了完整的照片删除逻辑 (`deletePhotoLogic.go`)
|
||||||
|
- 权限验证 (只能删除自己的照片)
|
||||||
|
- 同时删除数据库记录和文件系统文件
|
||||||
|
- 安全的文件删除处理 (即使文件删除失败也不回滚)
|
||||||
|
- 更新了 Handler 使用统一响应格式
|
||||||
|
- 创建了完整的 API 测试用例 (`test_photo_crud.http`)
|
||||||
|
- 包含正常场景和错误场景的测试覆盖
|
||||||
|
|
||||||
|
### 🔄 进行中 (0/9)
|
||||||
|
|
||||||
|
### ⏳ 待开始 (6/9)
|
||||||
|
|
||||||
|
#### 4. 完善分类更新和删除业务逻辑
|
||||||
|
**优先级**: 高 🔥
|
||||||
|
**预估工作量**: 0.5天
|
||||||
|
**依赖**: 无
|
||||||
|
|
||||||
|
#### 5. 前端与后端 API 集成测试
|
||||||
|
**优先级**: 高 🔥
|
||||||
|
**预估工作量**: 1天
|
||||||
|
**依赖**: 前端项目
|
||||||
|
|
||||||
|
#### 6. 实现用户认证流程 (登录/注册界面)
|
||||||
|
**优先级**: 高 🔥
|
||||||
|
**预估工作量**: 1天
|
||||||
|
**依赖**: 前端项目
|
||||||
|
|
||||||
|
#### 7. 实现照片上传界面和进度显示
|
||||||
|
**优先级**: 高 🔥
|
||||||
|
**预估工作量**: 1天
|
||||||
|
**依赖**: 前端项目
|
||||||
|
|
||||||
|
#### 8. 配置生产环境数据库 (PostgreSQL)
|
||||||
|
**优先级**: 高 🔥
|
||||||
|
**预估工作量**: 0.5天
|
||||||
|
**依赖**: 生产环境服务器
|
||||||
|
|
||||||
|
#### 9. 更新 CI/CD 流程支持后端部署
|
||||||
|
**优先级**: 高 🔥
|
||||||
|
**预估工作量**: 1天
|
||||||
|
**依赖**: 部署环境
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 中优先级任务 (11/26)
|
||||||
|
|
||||||
|
### 后端功能 (5项)
|
||||||
|
- **完善用户管理 CRUD 操作** ⏳
|
||||||
|
- **添加数据库迁移脚本和种子数据** ⏳
|
||||||
|
- **实现 CORS 中间件和安全配置** ⏳
|
||||||
|
- **添加 API 接口测试用例** ⏳
|
||||||
|
- **实现日志中间件和错误处理** ⏳
|
||||||
|
|
||||||
|
### 前端功能 (3项)
|
||||||
|
- **完善照片管理界面 (编辑/删除)** ⏳
|
||||||
|
- **实现分类管理界面** ⏳
|
||||||
|
- **添加响应式设计优化** ⏳
|
||||||
|
|
||||||
|
### 部署和运维 (2项)
|
||||||
|
- **配置反向代理 (前后端统一域名)** ⏳
|
||||||
|
- **配置文件存储服务 (图片上传)** ⏳
|
||||||
|
|
||||||
|
### 测试和文档 (2项)
|
||||||
|
- **编写 API 集成测试** ⏳
|
||||||
|
- **完善 API 接口文档** ⏳
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📌 低优先级任务 (6/26)
|
||||||
|
|
||||||
|
### 后端扩展 (3项)
|
||||||
|
- **完善生产环境配置 (PostgreSQL)** ⏳
|
||||||
|
- **添加 Docker 容器化配置** ⏳
|
||||||
|
- **实现 API 文档生成 (Swagger)** ⏳
|
||||||
|
|
||||||
|
### 部署优化 (1项)
|
||||||
|
- **设置监控和日志收集** ⏳
|
||||||
|
|
||||||
|
### 测试和文档 (2项)
|
||||||
|
- **编写前端 E2E 测试** ⏳
|
||||||
|
- **编写部署文档** ⏳
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 里程碑规划
|
||||||
|
|
||||||
|
### 第一阶段:核心功能完善 (本周)
|
||||||
|
- [x] 照片上传功能
|
||||||
|
- [x] JWT 认证中间件
|
||||||
|
- [ ] 照片和分类的完整 CRUD
|
||||||
|
- [ ] 前后端 API 集成
|
||||||
|
|
||||||
|
**目标**: 实现核心业务功能的完整闭环
|
||||||
|
|
||||||
|
### 第二阶段:功能完整性 (下周)
|
||||||
|
- [ ] 用户界面完善
|
||||||
|
- [ ] 数据库配置
|
||||||
|
- [ ] 基础测试用例
|
||||||
|
- [ ] 安全性配置
|
||||||
|
|
||||||
|
**目标**: 功能完整性和用户体验
|
||||||
|
|
||||||
|
### 第三阶段:部署和优化 (后续)
|
||||||
|
- [ ] CI/CD 更新
|
||||||
|
- [ ] 生产环境部署
|
||||||
|
- [ ] 性能优化
|
||||||
|
- [ ] 监控和文档
|
||||||
|
|
||||||
|
**目标**: 生产环境就绪
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💻 技术成果
|
||||||
|
|
||||||
|
### ✅ 已实现的核心功能
|
||||||
|
- **文件上传系统**: 完整的图片上传和缩略图生成
|
||||||
|
- **JWT 认证体系**: 用户认证和权限管理
|
||||||
|
- **静态文件服务**: 图片资源访问
|
||||||
|
- **图片处理能力**: 自动缩放和格式支持
|
||||||
|
- **安全文件验证**: 类型和大小检查
|
||||||
|
- **照片CRUD完整**: 创建、读取、更新、删除全功能
|
||||||
|
- **权限控制**: 用户只能操作自己的照片
|
||||||
|
- **文件系统管理**: 删除照片时同步删除文件
|
||||||
|
|
||||||
|
### 📊 API 接口状态
|
||||||
|
- ✅ `POST /api/v1/auth/login` - 用户登录
|
||||||
|
- ✅ `POST /api/v1/auth/register` - 用户注册
|
||||||
|
- ✅ `GET /api/v1/health` - 健康检查
|
||||||
|
- ✅ `GET /api/v1/photos` - 照片列表
|
||||||
|
- ✅ `POST /api/v1/photos` - 上传照片 (支持文件上传)
|
||||||
|
- ✅ `GET /api/v1/photos/:id` - 获取照片详情
|
||||||
|
- ✅ `PUT /api/v1/photos/:id` - 更新照片 (支持权限验证)
|
||||||
|
- ✅ `DELETE /api/v1/photos/:id` - 删除照片 (同时删除文件)
|
||||||
|
- ✅ `GET /api/v1/categories` - 分类列表
|
||||||
|
- ✅ `POST /api/v1/categories` - 创建分类
|
||||||
|
- ✅ `GET /api/v1/users` - 用户列表
|
||||||
|
- ✅ `GET /uploads/*` - 静态文件访问
|
||||||
|
- ⏳ `PUT /api/v1/categories/:id` - 更新分类
|
||||||
|
- ⏳ `DELETE /api/v1/categories/:id` - 删除分类
|
||||||
|
|
||||||
|
### 🛠️ 技术栈
|
||||||
|
- **后端框架**: go-zero v1.8.0
|
||||||
|
- **数据库**: SQLite (开发) / PostgreSQL (生产)
|
||||||
|
- **认证**: JWT Token
|
||||||
|
- **文件处理**: imaging + uuid
|
||||||
|
- **构建工具**: Go 1.23+ + Makefile
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 每日进度记录
|
||||||
|
|
||||||
|
### 2025-01-10
|
||||||
|
- ✅ **照片上传功能完成**: 实现文件处理、缩略图生成、静态服务
|
||||||
|
- ✅ **JWT 认证中间件完成**: Bearer Token 验证和用户上下文注入
|
||||||
|
- ✅ **照片更新删除功能完成**: 实现权限验证、文件同步删除、完整CRUD
|
||||||
|
- 📝 **下一步**: 完善分类的更新删除功能
|
||||||
|
|
||||||
|
### 待补充...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 更新日志
|
||||||
|
|
||||||
|
### v0.2.0 - 2025-01-10
|
||||||
|
- 新增完整的文件上传系统
|
||||||
|
- 新增 JWT 认证中间件
|
||||||
|
- 新增静态文件服务
|
||||||
|
- 优化图片处理能力
|
||||||
|
- 完善照片更新和删除功能
|
||||||
|
- 实现用户权限控制
|
||||||
|
- 添加文件系统同步管理
|
||||||
|
|
||||||
|
### v0.1.0 - 2025-01-09
|
||||||
|
- 初始化 go-zero 项目架构
|
||||||
|
- 实现基础 CRUD 接口
|
||||||
|
- 配置开发环境
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 联系信息
|
||||||
|
|
||||||
|
**项目负责人**: iriver
|
||||||
|
**项目仓库**: https://git.iriver.top/iriver/photography
|
||||||
|
**更新频率**: 每日更新
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*本文档自动同步项目进度,如有疑问请查看具体模块的 CLAUDE.md 文件*
|
||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"photography-backend/internal/logic/photo"
|
"photography-backend/internal/logic/photo"
|
||||||
"photography-backend/internal/svc"
|
"photography-backend/internal/svc"
|
||||||
"photography-backend/internal/types"
|
"photography-backend/internal/types"
|
||||||
|
"photography-backend/pkg/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 删除照片
|
// 删除照片
|
||||||
@ -20,10 +21,6 @@ func DeletePhotoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
|
|
||||||
l := photo.NewDeletePhotoLogic(r.Context(), svcCtx)
|
l := photo.NewDeletePhotoLogic(r.Context(), svcCtx)
|
||||||
resp, err := l.DeletePhoto(&req)
|
resp, err := l.DeletePhoto(&req)
|
||||||
if err != nil {
|
response.Response(w, resp, err)
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
|
||||||
} else {
|
|
||||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"photography-backend/internal/logic/photo"
|
"photography-backend/internal/logic/photo"
|
||||||
"photography-backend/internal/svc"
|
"photography-backend/internal/svc"
|
||||||
"photography-backend/internal/types"
|
"photography-backend/internal/types"
|
||||||
|
"photography-backend/pkg/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 更新照片
|
// 更新照片
|
||||||
@ -20,10 +21,6 @@ func UpdatePhotoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
|
|
||||||
l := photo.NewUpdatePhotoLogic(r.Context(), svcCtx)
|
l := photo.NewUpdatePhotoLogic(r.Context(), svcCtx)
|
||||||
resp, err := l.UpdatePhoto(&req)
|
resp, err := l.UpdatePhoto(&req)
|
||||||
if err != nil {
|
response.Response(w, resp, err)
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
|
||||||
} else {
|
|
||||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,11 @@ package photo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"photography-backend/internal/model"
|
||||||
"photography-backend/internal/svc"
|
"photography-backend/internal/svc"
|
||||||
"photography-backend/internal/types"
|
"photography-backend/internal/types"
|
||||||
|
"photography-backend/pkg/errorx"
|
||||||
|
fileUtil "photography-backend/pkg/utils/file"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
@ -25,7 +28,57 @@ func NewDeletePhotoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delet
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *DeletePhotoLogic) DeletePhoto(req *types.DeletePhotoRequest) (resp *types.DeletePhotoResponse, err error) {
|
func (l *DeletePhotoLogic) DeletePhoto(req *types.DeletePhotoRequest) (resp *types.DeletePhotoResponse, err error) {
|
||||||
// todo: add your logic here and delete this line
|
// 1. 获取当前用户ID (从JWT中间件获取)
|
||||||
|
userID := l.ctx.Value("userID")
|
||||||
|
if userID == nil {
|
||||||
|
return nil, errorx.NewWithCode(errorx.AuthError)
|
||||||
|
}
|
||||||
|
currentUserID := userID.(int64)
|
||||||
|
|
||||||
return
|
// 2. 查询照片是否存在
|
||||||
|
photo, err := l.svcCtx.PhotoModel.FindOne(l.ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errorx.NewWithCode(errorx.PhotoNotFound)
|
||||||
|
}
|
||||||
|
logx.Errorf("查询照片失败: %v", err)
|
||||||
|
return nil, errorx.NewWithCode(errorx.ServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 检查权限 - 只有照片所有者可以删除
|
||||||
|
if photo.UserId != currentUserID {
|
||||||
|
return nil, errorx.NewWithCode(errorx.Forbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 删除数据库记录
|
||||||
|
err = l.svcCtx.PhotoModel.Delete(l.ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("删除照片记录失败: %v", err)
|
||||||
|
return nil, errorx.NewWithCode(errorx.ServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 删除文件系统中的文件
|
||||||
|
// 删除原图
|
||||||
|
if photo.FilePath != "" {
|
||||||
|
if err := fileUtil.DeleteFile(photo.FilePath); err != nil {
|
||||||
|
logx.Errorf("删除原图文件失败: %v", err)
|
||||||
|
// 注意:即使文件删除失败,我们也不回滚数据库操作,因为文件可能已经被手动删除
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除缩略图
|
||||||
|
if photo.ThumbnailPath != "" {
|
||||||
|
if err := fileUtil.DeleteFile(photo.ThumbnailPath); err != nil {
|
||||||
|
logx.Errorf("删除缩略图文件失败: %v", err)
|
||||||
|
// 注意:即使文件删除失败,我们也不回滚数据库操作
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 返回成功响应
|
||||||
|
return &types.DeletePhotoResponse{
|
||||||
|
BaseResponse: types.BaseResponse{
|
||||||
|
Code: errorx.Success,
|
||||||
|
Message: "照片删除成功",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,13 @@ package photo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"photography-backend/internal/model"
|
||||||
"photography-backend/internal/svc"
|
"photography-backend/internal/svc"
|
||||||
"photography-backend/internal/types"
|
"photography-backend/internal/types"
|
||||||
|
"photography-backend/pkg/errorx"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
@ -25,7 +29,75 @@ func NewUpdatePhotoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Updat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *UpdatePhotoLogic) UpdatePhoto(req *types.UpdatePhotoRequest) (resp *types.UpdatePhotoResponse, err error) {
|
func (l *UpdatePhotoLogic) UpdatePhoto(req *types.UpdatePhotoRequest) (resp *types.UpdatePhotoResponse, err error) {
|
||||||
// todo: add your logic here and delete this line
|
// 1. 获取当前用户ID (从JWT中间件获取)
|
||||||
|
userID := l.ctx.Value("userID")
|
||||||
|
if userID == nil {
|
||||||
|
return nil, errorx.NewWithCode(errorx.AuthError)
|
||||||
|
}
|
||||||
|
currentUserID := userID.(int64)
|
||||||
|
|
||||||
return
|
// 2. 查询照片是否存在
|
||||||
|
photo, err := l.svcCtx.PhotoModel.FindOne(l.ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errorx.NewWithCode(errorx.PhotoNotFound)
|
||||||
|
}
|
||||||
|
logx.Errorf("查询照片失败: %v", err)
|
||||||
|
return nil, errorx.NewWithCode(errorx.ServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 检查权限 - 只有照片所有者可以更新
|
||||||
|
if photo.UserId != currentUserID {
|
||||||
|
return nil, errorx.NewWithCode(errorx.Forbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 验证分类是否存在 (如果要更新分类)
|
||||||
|
if req.CategoryId > 0 {
|
||||||
|
_, err = l.svcCtx.CategoryModel.FindOne(l.ctx, req.CategoryId)
|
||||||
|
if err != nil {
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
return nil, errorx.NewWithCode(errorx.CategoryNotFound)
|
||||||
|
}
|
||||||
|
logx.Errorf("查询分类失败: %v", err)
|
||||||
|
return nil, errorx.NewWithCode(errorx.ServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 更新照片信息
|
||||||
|
if req.Title != "" {
|
||||||
|
photo.Title = req.Title
|
||||||
|
}
|
||||||
|
if req.Description != "" {
|
||||||
|
photo.Description = sql.NullString{String: req.Description, Valid: true}
|
||||||
|
}
|
||||||
|
if req.CategoryId > 0 {
|
||||||
|
photo.CategoryId = req.CategoryId
|
||||||
|
}
|
||||||
|
photo.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
// 6. 保存到数据库
|
||||||
|
err = l.svcCtx.PhotoModel.Update(l.ctx, photo)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("更新照片失败: %v", err)
|
||||||
|
return nil, errorx.NewWithCode(errorx.ServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 构造响应
|
||||||
|
return &types.UpdatePhotoResponse{
|
||||||
|
BaseResponse: types.BaseResponse{
|
||||||
|
Code: errorx.Success,
|
||||||
|
Message: "照片更新成功",
|
||||||
|
},
|
||||||
|
Data: types.Photo{
|
||||||
|
Id: photo.Id,
|
||||||
|
Title: photo.Title,
|
||||||
|
Description: photo.Description.String,
|
||||||
|
FilePath: photo.FilePath,
|
||||||
|
ThumbnailPath: photo.ThumbnailPath,
|
||||||
|
UserId: photo.UserId,
|
||||||
|
CategoryId: photo.CategoryId,
|
||||||
|
CreatedAt: photo.CreatedAt.Unix(),
|
||||||
|
UpdatedAt: photo.UpdatedAt.Unix(),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
94
backend/test_photo_crud.http
Normal file
94
backend/test_photo_crud.http
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
### 照片CRUD测试
|
||||||
|
|
||||||
|
### 1. 用户登录获取token
|
||||||
|
POST http://localhost:8888/api/v1/auth/login
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"password": "123456"
|
||||||
|
}
|
||||||
|
|
||||||
|
### 设置变量
|
||||||
|
@token = {{login.response.body.data.token}}
|
||||||
|
|
||||||
|
### 2. 获取照片列表
|
||||||
|
GET http://localhost:8888/api/v1/photos?page=1&page_size=5
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
### 3. 上传照片 (可选,用于创建测试数据)
|
||||||
|
POST http://localhost:8888/api/v1/photos
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
Content-Type: multipart/form-data; boundary=boundary
|
||||||
|
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="title"
|
||||||
|
|
||||||
|
测试照片更新删除
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="description"
|
||||||
|
|
||||||
|
这是一张用于测试更新和删除功能的照片
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="category_id"
|
||||||
|
|
||||||
|
1
|
||||||
|
--boundary
|
||||||
|
Content-Disposition: form-data; name="file"; filename="test.jpg"
|
||||||
|
Content-Type: image/jpeg
|
||||||
|
|
||||||
|
< ./test.jpg
|
||||||
|
--boundary--
|
||||||
|
|
||||||
|
### 4. 获取单个照片详情
|
||||||
|
GET http://localhost:8888/api/v1/photos/1
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
### 5. 更新照片信息
|
||||||
|
PUT http://localhost:8888/api/v1/photos/1
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "更新后的照片标题",
|
||||||
|
"description": "更新后的照片描述信息",
|
||||||
|
"category_id": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
### 6. 再次获取照片详情验证更新
|
||||||
|
GET http://localhost:8888/api/v1/photos/1
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
### 7. 删除照片
|
||||||
|
DELETE http://localhost:8888/api/v1/photos/1
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
### 8. 验证删除(应该返回404)
|
||||||
|
GET http://localhost:8888/api/v1/photos/1
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
### 错误场景测试
|
||||||
|
|
||||||
|
### 9. 尝试更新不存在的照片
|
||||||
|
PUT http://localhost:8888/api/v1/photos/999
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "不存在的照片"
|
||||||
|
}
|
||||||
|
|
||||||
|
### 10. 尝试删除不存在的照片
|
||||||
|
DELETE http://localhost:8888/api/v1/photos/999
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
### 11. 无认证更新照片
|
||||||
|
PUT http://localhost:8888/api/v1/photos/1
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "无认证更新"
|
||||||
|
}
|
||||||
|
|
||||||
|
### 12. 无认证删除照片
|
||||||
|
DELETE http://localhost:8888/api/v1/photos/1
|
||||||
Reference in New Issue
Block a user