From 7b16b89e72de64ae4c32d2606ea15ea4e89129e5 Mon Sep 17 00:00:00 2001 From: Mohan Date: Wed, 12 Aug 2026 10:04:57 +0800 Subject: [PATCH] feat(contract): bump openapi to v0.3.1 with comment endpoints --- openapi.yaml | 529 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 507 insertions(+), 22 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 6947111..b206e4c 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -8,12 +8,12 @@ info: - 列表查询返回 `PageResult` - 认证方式:JWT Bearer Token - 时间格式:ISO-8601(`2024-01-15T08:30:00Z`) - version: 0.1.0 + version: 0.3.1 contact: name: Mach-CMS Team servers: - - url: http://localhost:8080/api + - url: http://localhost:8080 description: 本地开发环境 security: @@ -36,12 +36,16 @@ tags: description: 媒体文件上传 - name: Search description: 全文搜索 + - name: Comment + description: 评论(前台免登录提交,展示已审核) + - name: CommentAdmin + description: 评论管理(需 ADMIN) - name: User description: 用户管理(需 ADMIN) paths: # ==================== Public ==================== - /public/health: + /api/public/health: get: tags: [Public] summary: 健康检查 @@ -59,7 +63,7 @@ paths: data: UP # ==================== Auth ==================== - /auth/register: + /api/auth/register: post: tags: [Auth] summary: 用户注册 @@ -78,7 +82,7 @@ paths: schema: $ref: '#/components/schemas/ResponseTokenPair' - /auth/login: + /api/auth/login: post: tags: [Auth] summary: 用户登录 @@ -97,7 +101,7 @@ paths: schema: $ref: '#/components/schemas/ResponseTokenPair' - /auth/refresh: + /api/auth/refresh: post: tags: [Auth] summary: 刷新 Access Token @@ -116,7 +120,7 @@ paths: schema: $ref: '#/components/schemas/ResponseTokenPair' - /auth/logout: + /api/auth/logout: post: tags: [Auth] summary: 退出登录(吊销 Refresh Token) @@ -129,7 +133,7 @@ paths: $ref: '#/components/schemas/ResponseVoid' # ==================== Article (Public) ==================== - /articles: + /api/articles: get: tags: [Article] summary: 文章列表(分页) @@ -164,7 +168,28 @@ paths: schema: $ref: '#/components/schemas/ResponsePageArticleListItem' - /articles/{slug}: + /api/articles/popular: + get: + tags: [Article] + summary: 热门文章(按浏览量降序,仅 PUBLISHED) + security: [] + parameters: + - name: limit + in: query + schema: + type: integer + default: 5 + maximum: 10 + minimum: 1 + responses: + '200': + description: 热门文章列表 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseListArticleListItem' + + /api/articles/{slug}: get: tags: [Article] summary: 文章详情(按 slug) @@ -189,7 +214,150 @@ paths: schema: $ref: '#/components/schemas/ResponseVoid' - /articles/search: + /api/articles/{slug}/meta: + get: + tags: [Article] + summary: 文章 OpenGraph 元数据(分享预览) + security: [] + parameters: + - name: slug + in: path + required: true + schema: + type: string + responses: + '200': + description: 元数据(文章不存在时为 null) + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseOpenGraphMeta' + + /api/articles/{slug}/star: + post: + tags: [Article] + summary: 点赞文章(已登录) + parameters: + - name: slug + in: path + required: true + schema: + type: string + responses: + '200': + description: 点赞成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseVoid' + '401': + description: 未登录 + + delete: + tags: [Article] + summary: 取消点赞文章(已登录) + parameters: + - name: slug + in: path + required: true + schema: + type: string + responses: + '200': + description: 取消成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseVoid' + '401': + description: 未登录 + + /api/comments/{id}/star: + post: + tags: [Comment] + summary: 点赞评论(已登录) + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 点赞成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseVoid' + '401': + description: 未登录 + + delete: + tags: [Comment] + summary: 取消点赞评论(已登录) + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 取消成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseVoid' + '401': + description: 未登录 + + # ==================== Comment (Public) ==================== + /api/articles/{slug}/comments: + get: + tags: [Comment] + summary: 文章评论列表(仅返回已审核 APPROVED) + security: [] + parameters: + - name: slug + in: path + required: true + schema: + type: string + responses: + '200': + description: 评论列表 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseListComment' + + post: + tags: [Comment] + summary: 提交评论(免登录,提交后为 PENDING 待审核) + security: [] + parameters: + - name: slug + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CommentSubmitRequest' + responses: + '200': + description: 提交成功,返回待审核评论 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseComment' + + /api/articles/search: get: tags: [Search] summary: 全文搜索文章 @@ -223,7 +391,7 @@ paths: $ref: '#/components/schemas/ResponsePageArticleListItem' # ==================== ArticleAdmin ==================== - /admin/articles: + /api/admin/articles: post: tags: [ArticleAdmin] summary: 创建文章 @@ -241,7 +409,31 @@ paths: schema: $ref: '#/components/schemas/ResponseArticleDetail' - /admin/articles/{id}: + /api/admin/articles/{id}: + get: + tags: [ArticleAdmin] + summary: 文章详情(按 id,管理端,含草稿/归档等任意状态) + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 文章详情 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseArticleDetail' + '404': + description: 文章不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseVoid' + put: tags: [ArticleAdmin] summary: 更新文章 @@ -284,7 +476,7 @@ paths: schema: $ref: '#/components/schemas/ResponseVoid' - /admin/articles/{id}/publish: + /api/admin/articles/{id}/publish: patch: tags: [ArticleAdmin] summary: 发布文章(状态机:DRAFT → PUBLISHED) @@ -303,7 +495,7 @@ paths: schema: $ref: '#/components/schemas/ResponseArticleDetail' - /admin/articles/{id}/archive: + /api/admin/articles/{id}/archive: patch: tags: [ArticleAdmin] summary: 归档文章 @@ -323,7 +515,7 @@ paths: $ref: '#/components/schemas/ResponseArticleDetail' # ==================== Tag (Public) ==================== - /tags: + /api/tags: get: tags: [Tag] summary: 标签列表(带文章计数) @@ -337,7 +529,7 @@ paths: $ref: '#/components/schemas/ResponseListTagWithCount' # ==================== TagAdmin ==================== - /admin/tags: + /api/admin/tags: post: tags: [TagAdmin] summary: 创建标签 @@ -355,7 +547,7 @@ paths: schema: $ref: '#/components/schemas/ResponseTag' - /admin/tags/{id}: + /api/admin/tags/{id}: put: tags: [TagAdmin] summary: 更新标签 @@ -399,7 +591,7 @@ paths: $ref: '#/components/schemas/ResponseVoid' # ==================== Media ==================== - /media/upload: + /api/media/upload: post: tags: [Media] summary: 上传文件 @@ -426,8 +618,89 @@ paths: schema: $ref: '#/components/schemas/ResponseStoredFile' + # ==================== CommentAdmin ==================== + /api/admin/comments: + get: + tags: [CommentAdmin] + summary: 待审核评论列表(分页,状态 PENDING) + parameters: + - name: page + in: query + schema: + type: integer + default: 1 + - name: size + in: query + schema: + type: integer + default: 20 + responses: + '200': + description: 待审核评论列表 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponsePageComment' + + /api/admin/comments/{id}: + delete: + tags: [CommentAdmin] + summary: 删除评论 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 删除成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseVoid' + + /api/admin/comments/{id}/approve: + patch: + tags: [CommentAdmin] + summary: 审核通过评论(PENDING → APPROVED) + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 审核成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseComment' + + /api/admin/comments/{id}/reject: + patch: + tags: [CommentAdmin] + summary: 驳回评论(PENDING → REJECTED) + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 驳回成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseComment' + # ==================== User ==================== - /admin/users: + /api/admin/users: get: tags: [User] summary: 用户列表(分页) @@ -450,6 +723,56 @@ paths: schema: $ref: '#/components/schemas/ResponsePageUserInfo' + /api/admin/users/{id}/role: + patch: + tags: [User] + summary: 修改用户角色 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateRoleRequest' + responses: + '200': + description: 修改成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseUserInfo' + + /api/admin/users/{id}/status: + patch: + tags: [User] + summary: 启用/禁用用户 + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateStatusRequest' + responses: + '200': + description: 修改成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ResponseUserInfo' + components: securitySchemes: bearerAuth: @@ -458,7 +781,7 @@ components: bearerFormat: JWT description: | 在请求头中携带 `Authorization: Bearer `。 - Access Token 有效期 15 分钟,过期后用 Refresh Token 调用 `/auth/refresh` 换取新的 Access Token。 + Access Token 有效期 15 分钟,过期后用 Refresh Token 调用 `/api/auth/refresh` 换取新的 Access Token。 schemas: # ---------- 通用包装体 ---------- @@ -619,7 +942,15 @@ components: type: array items: type: string - required: [id, title, slug, status, createdAt, authorName, tagNames] + starCount: + type: integer + format: int64 + description: 点赞数 + hasStarred: + type: boolean + nullable: true + description: 当前用户是否已点赞(null 表示未登录) + required: [id, title, slug, status, createdAt, authorName, tagNames, starCount] ArticleDetail: type: object @@ -657,7 +988,31 @@ components: type: array items: type: string - required: [id, title, slug, content, status, viewCount, createdAt, updatedAt, authorName, tagNames] + starCount: + type: integer + format: int64 + description: 点赞数 + hasStarred: + type: boolean + nullable: true + description: 当前用户是否已点赞(null 表示未登录) + required: [id, title, slug, content, status, viewCount, createdAt, updatedAt, authorName, tagNames, starCount] + + OpenGraphMeta: + type: object + properties: + title: + type: string + description: + type: string + image: + type: string + url: + type: string + type: + type: string + default: article + required: [title, description, url, type] # ---------- Tag ---------- Tag: @@ -712,6 +1067,9 @@ components: type: string url: type: string + thumbnailUrl: + type: string + description: 图片缩略图 URL(非图片为 null) size: type: integer format: int64 @@ -741,6 +1099,81 @@ components: format: date-time required: [id, username, role, enabled, createdAt] + # ---------- Comment ---------- + CommentStatus: + type: string + enum: [PENDING, APPROVED, REJECTED] + description: | + - PENDING: 待审核 + - APPROVED: 已通过,前台可见 + - REJECTED: 已驳回 + + CommentSubmitRequest: + type: object + properties: + parentId: + type: integer + format: int64 + description: 父评论 ID(回复场景,可空) + authorName: + type: string + maxLength: 100 + authorEmail: + type: string + format: email + content: + type: string + maxLength: 2000 + required: [authorName, content] + + CommentResponse: + type: object + properties: + id: + type: integer + format: int64 + articleId: + type: integer + format: int64 + parentId: + type: integer + format: int64 + authorName: + type: string + authorEmail: + type: string + content: + type: string + status: + $ref: '#/components/schemas/CommentStatus' + createdAt: + type: string + format: date-time + starCount: + type: integer + format: int64 + description: 评论点赞数 + hasStarred: + type: boolean + nullable: true + description: 当前用户是否已点赞(null 表示未登录) + required: [id, articleId, authorName, content, status, createdAt] + + # ---------- User Admin ---------- + UpdateRoleRequest: + type: object + properties: + role: + $ref: '#/components/schemas/UserRole' + required: [role] + + UpdateStatusRequest: + type: object + properties: + enabled: + type: boolean + required: [enabled] + # ---------- 包装体实例化 ---------- ResponseString: allOf: @@ -770,6 +1203,13 @@ components: data: $ref: '#/components/schemas/ArticleDetail' + ResponseOpenGraphMeta: + allOf: + - $ref: '#/components/schemas/Response' + properties: + data: + $ref: '#/components/schemas/OpenGraphMeta' + ResponsePageArticleListItem: allOf: - $ref: '#/components/schemas/Response' @@ -783,6 +1223,15 @@ components: items: $ref: '#/components/schemas/ArticleListItem' + ResponseListArticleListItem: + allOf: + - $ref: '#/components/schemas/Response' + properties: + data: + type: array + items: + $ref: '#/components/schemas/ArticleListItem' + ResponseTag: allOf: - $ref: '#/components/schemas/Response' @@ -818,3 +1267,39 @@ components: type: array items: $ref: '#/components/schemas/UserInfo' + + ResponseComment: + allOf: + - $ref: '#/components/schemas/Response' + properties: + data: + $ref: '#/components/schemas/CommentResponse' + + ResponseListComment: + allOf: + - $ref: '#/components/schemas/Response' + properties: + data: + type: array + items: + $ref: '#/components/schemas/CommentResponse' + + ResponseUserInfo: + allOf: + - $ref: '#/components/schemas/Response' + properties: + data: + $ref: '#/components/schemas/UserInfo' + + ResponsePageComment: + allOf: + - $ref: '#/components/schemas/Response' + properties: + data: + allOf: + - $ref: '#/components/schemas/PageResult' + properties: + list: + type: array + items: + $ref: '#/components/schemas/CommentResponse'