|
|
2b47380ac5
|
feat: 实现赞/踩系统(P2)
- 新增 PostLike/PostDislike 模型,复合主键 (user_id, post_id)
- Post 表新增 LikesCount/DislikesCount 冗余计数器
- Repository 层:reaction_repo.go,含 WithTx 事务支持
- Service 层:reaction_service.go,赞踩互斥逻辑(6 态切换),事务包裹
- Controller 层:reaction_controller.go,3 个 API(ToggleLike/ToggleDislike/GetReaction)
- 接口定义:controller/interfaces.go 新增 reactionUseCase,service/repository.go 新增 ReactionStore
- 路由注册 + 依赖注入 + AutoMigrate
- 前端:文章详情页赞踩按钮 + 状态查询 + 401 跳转登录
- 样式:posts.css 新增赞踩按钮样式
|
2026-06-01 15:48:18 +08:00 |
|
|
|
26e557de8a
|
feat: 实现社区激励金(公户)系统,经济闭环
- 新增 CommunityFund / FundLog 模型(公户余额单行表 + 6种流水类型)
- 新增 FundRepo 仓储(GetBalance / IncrBalance / CreateLog / ListLogs / WithTx)
- 改造 EnergyService 五个方法:Energize 税收入公户、DeductOnRename/DeductOnDeletePost 入公户、RefundOnRenameReject 从公户支出、AdminAdjust 拆分为 admin_transfer/system_operation
- 新增 ErrInsufficientFund 错误哨兵
- 管理后台新增公户余额展示 + 公户流水页面 + 域能调整资金来源选择
- 新增 energy.css / energy.js 前端交互
- 侧边栏新增公户流水入口
|
2026-06-01 15:10:47 +08:00 |
|
|
|
43c35ddaf2
|
fix: 评论系统全量检查修复(7 项 Gap 全部修复)
- Delete 权限:新增 requesterID/isAdmin 参数,Service 层鉴权(仅本人/管理员可删)
- 通知内容:改用 GetUsernameByID 显示真实用户名,非数字 UID
- SearchUsers:Repository 返回 exp,Service 调用 GetLevelByExp 计算等级
- 通知高亮:Notification 新增 CommentID 字段,消息链接支持 #comment-{id}
- 已删除提示:前端 hash 检测 + 3 秒超时 Toast "该评论已不存在"
- Admin CSS:移除不存在的 comments.css 引用
- 错误哨兵:改用 common.ErrCommentNotFound/ErrCommentEmpty/PermissionDenied
|
2026-06-01 14:05:47 +08:00 |
|
|
|
36c571b6bb
|
feat: 评论系统补充功能完成——图片上传、后台管理、通知跳转高亮
- 评论图片上传(LV4+,经验≥1500),JPEG/PNG 自动转 WebP,二进制搜索质量优化
- 后台评论管理页面,支持关键词搜索、分页、删除,侧边栏新增入口
- 通知跳转高亮:评论通知 RelatedID 改为 postID,消息页链接到 #comments,前端自动滚动
- 新增 adminCommentUseCase/commentStore 接口(遵循 ISP),AdminCommentRow 移至 model 层
- 前端 @mention 联想/图片上传光标插入/评论展开收起/内联回复交互完善
|
2026-06-01 13:35:41 +08:00 |
|
|
|
b7acc91f8c
|
feat: 实现评论系统(后端 + 前端)
- 新增 Comment/CommentMention 模型,Post 新增 CommentsCount 冗余计数器
- 新增 CommentRepo(CRUD + @搜索 LV3+ + 回复统计 + 文章作者查询)
- 新增 CommentService(发表/回复/删除/@解析/通知 NotifyComment/NotifyCommentReply)
- 新增 CommentController(6 个 API 端点),commentUseCase ISP 接口
- 新增评论路由(公开读取 + 需登录写入),依赖注入,错误哨兵,数据库迁移
- 前端评论区 HTML/CSS/JS:分页加载、回复折叠展开、内联回复表单、@提及自动补全
|
2026-06-01 13:24:16 +08:00 |
|
|
|
e1d7c318ab
|
feat: 实现域能系统
- 新增域能完整分层:EnergyLog/PostEnergizeLog/DailyExpSummary 模型、EnergyRepo、EnergyService、EnergyController/AdminEnergyController
- 支持签到获取域能(+1)、帖子赋能(-1/-2)/被赋能(+1/+2)、改名扣能(-6)/退款(+6)、删帖扣能(-2)
- 赋能单人单帖上限20域能,每日赋能获得经验上限50
- 管理员支持批量调整域能(owner)和查询域能日志(admin)
- LV0用户(exp<1)禁止签到和发帖,余额为负可签到/被赋能/删帖但不能赋能/改名
- 首次改名免费(通过HasCompletedTask判重),改名扣能在提交审核时执行
- 移除导航栏手动签到按钮,签到融入域能系统(自动签到)
- 新增个人中心域能TAB展示余额和流水日志(近7天)
- 新增帖子详情页赋能按钮(轻赋/重赋)
- 管理后台新增域能管理和域能日志页面
|
2026-06-01 03:32:50 +08:00 |
|
|
|
fdb636f98f
|
feat: 实现积分与等级系统 + 签到功能 + 下拉菜单优化
- User 模型增加 exp 字段,等级规则 Lv0-Lv6
- 新增签到记录(UserCheckIn)与任务记录(UserTask)模型,唯一索引防重
- 自动签到:AuthMiddleware 验证会话后,基于 Asia/Shanghai 自然日自动签到 +5 经验
- 手动签到:下拉菜单"签到"按钮兜底,已签到显示"今日已签到"并禁用
- 首次任务经验:上传头像/设置用户名/设置个性签名各 +10,审核通过与直接更新均触发
- 经验值变动后自动比对等级,升级时通过通知系统发送"恭喜提升至 LvX"
- 下拉菜单重构:顶部头像+用户名+LvX 等级标签,菜单项增加左侧图标,优化布局样式
- 新增 API:POST /api/level/checkin、GET /api/level/info
|
2026-05-31 20:58:14 +08:00 |
|
|
|
968e8af8a3
|
feat: 锁定文章需填写锁定理由,编辑器显示锁定理由
- Post 模型新增 LockReason 字段,锁定必填理由,解锁清空
- PostLockRequest DTO:reason 必填,1-500字
- Admin JS:锁定操作弹出 prompt 要求填写理由
- 编辑器锁定横幅显示"锁定理由:XXX",理由为空时不显示该行
|
2026-05-31 20:10:55 +08:00 |
|
|
|
55c408d86c
|
fix: 审计问题全量修复 + RateLimiter 原子化重构 + CDN 本地化收紧
- 安全:移除 CSP 中 esm.sh/cdnjs.cloudflare.com,highlight.js 主题已本地化 73 个文件
- 安全:StatusBanned 分支补 dummy hash 防时序攻击
- 安全:手写 constantTimeEq 替换为 crypto/subtle.ConstantTimeCompare
- Bug:锁定操作消息已删除→已锁定
- YAGNI:删除 12 个空预留模板目录
- KISS:删除 common.CheckPassword 薄封装,统一用 bcrypt 调用
- KISS:删除 tokenCtrl 别名字段,api.go 统一用 authCtrl
- RateLimiter:check()+recordFail 闭包模式重构为 try() 原子操作,消除竞态
- RateLimiter:新增 ClearIP() 方法,注册成功时清除 IP 计数
- 文档:修正 audit_service.go 注释编号跳跃(3→5→4)
- 文档:修正 deps_core.go 过清理→过期清理
|
2026-05-31 11:13:32 +08:00 |
|
|
|
e3853071d6
|
chore: 清理 JWT 向后兼容残留,移除全部死代码
- 删除 5 个空壳占位文件:auth_token.go/auth_parser.go/repository.go(middleware)/token_service.go/provider.go
- 移除 Config.JWT 字段、JWTConfig 结构体、JWT_SECRET 环境变量绑定
- 移除 config.yaml 中的 jwt 配置段
- 移除 model.User.TokenVersion 字段(session DestroyByUID 替代)
- 移除 service/repository.go 中已废弃的 userTokenStore 接口
|
2026-05-30 23:42:27 +08:00 |
|
|
|
67444434b9
|
feat: 对接稿件审核通知系统 + 消息页面系统消息区域
- 新增通知类型 post_approved / post_rejected
- PostService.Approve/Reject 完成后通知作者(通知失败不影响主流程)
- NotificationService 新增 NotifyPostApproved/NotifyPostRejected 方法
- 消息页面顶部增加系统消息标识和分隔线,之下为全部消息列表
- 稿件审核通过通知卡片点击跳转到 /posts/{id} 页面
- 稿件审核拒绝通知卡片点击跳转到 /studio/posts 创作中心
- 新增 postNotifier 接口遵循 ISP 原则
|
2026-05-30 21:24:30 +08:00 |
|
|
|
eabc1e7d3d
|
feat: 已发布帖子编辑后进修订审核,通过前保持展示旧内容
- Post 模型新增 PendingTitle/PendingBody 字段,分离已发布内容与待审修订
- Update: approved 帖子编辑写入 Pending 字段,不覆盖正文,不改变发布状态
- Approve: 有 PendingBody 时复制到正式字段后清空,无 PendingBody 走首次审核
- Reject: 有 PendingBody 时仅清空待审修订(保持已发布),无 PendingBody 走普通退回
- 新增 ListPendingRevisions 查询,管理后台独立展示"修订待审核"区域
- 详情页展示"修订审核中"标识,编辑页加载待审内容
- 通过修订后直接覆盖,不保留历史版本
|
2026-05-30 20:24:43 +08:00 |
|
|
|
89fa50a013
|
fix: 锁定机制不再改变帖子状态,锁定与退回独立
- Post 模型新增 IsLocked 字段,与 Status 解耦
- Lock 仅设 IsLocked=true(不改 Status),已通过帖子锁定后仍公开可见
- Unlock 仅设 IsLocked=false(不改 Status)
- Update/EditPage 编辑检查改用 IsLocked 而非 Status==locked
- Reject 与 Lock 独立,可单独退回或锁定+退回组合使用
- 新增 ErrPostCannotLock 错误哨兵
- 前端模板编辑按钮/锁定标识基于 IsLocked 渲染
|
2026-05-30 20:08:41 +08:00 |
|
|
|
bacfd4945d
|
feat: 编辑器与帖子展示布局优化 + 新增个人空间
- 编辑器投稿页布局优化:标题与编辑器高度动态适配,工具栏与内容区视觉对齐
- 稿件展示页布局优化:MD 渲染区与评论区视觉分离,代码块主题微调
- CSRF 中间件:图像上传端点豁免,解决 Vditor 拖拽/粘贴上传 403
- Post 状态映射、GetGinUser、SaveUploadedFile 提取至 common 包,遵循审计建议
- 新增个人空间功能:/space(需登录)重定向到 /space/:uid,/space/:uid 公开访问
- 空间页模板:参考 B 站布局,展示头像、用户名、个性签名、UID、加入时间及稿件列表
- 导航栏:用户名链接指向 /space,新增「设置」入口
- 分层实现:SpaceController → SpaceService → PostRepo.FindByUserID,严格 ISP 接口隔离
|
2026-05-30 19:06:10 +08:00 |
|
|
|
6ec12010f3
|
feat: Tiptap替换为Vditor + MD存储重构 + Shortcode卡片扩展
- 编辑器:Tiptap 替换为 Vditor 3.11.2(wysiwyg 模式,本地托管 5.8MB,去 CDN)
- 存储:Body 字段从 HTML 改为 Markdown,去除 BodyHTML,新增 Excerpt 列表摘要
- 安全:去除 bluemonday 依赖(MD 纯文本无 XSS 风险),go.mod 已清理
- Shortcode:新增 [zone:type:params] 扩展语法,支持活动/游戏/投票/资源卡片
- 图片上传:POST /api/posts/upload-image 直接返回 Vditor 原生响应格式
- 草稿:localStorage 键名改为 draft_post_body_md,与旧 HTML 草稿隔离
- 详情页:Vditor.method.min.js 客户端 MD → HTML 渲染,去 highlight.js CDN
- 样式:去 Tiptap 样式 ~190 行,精简工具栏 CSS,新增卡片样式
- 文档:vditor-migration-plan.md 完整记录迁移决策、架构、用法
|
2026-05-30 15:56:22 +08:00 |
|
|
|
8a8d801187
|
fix: 修复帖子系统5项缺陷 + 代码块插入位置/language-class/分割线占位
- 作者显示 用户名(UID): 修正Post.AuthorName GORM标签从 -:all 改为 -:migration;<-:false;column:author_name
- 审核流程: 帖子详情页新增"提交审核"按钮(draft/rejected时作者可见)
- 图片上传: 新增 POST /api/posts/upload-image 端点,限制5MB/jpg/png/gif/webp
- 代码块语言标注: 工具栏插入代码块时弹出语言输入框,生成 language-xxx class
- 状态中文显示: 管理后台/帖子详情页状态改为 PostStatusDisplayNames 映射
- 修复代码块插入位置错误: init时调用switchMode同步DOM; 无选区时appendChild; 防<pre>嵌套
- 修复 bluemonday.UGCPolicy() 剥离 code/pre 的 class 属性,显式 AllowAttrs("class")
- 修复分割线工具栏插入多余text占位符: hr/link/image以外不强制填占位文本
|
2026-05-27 19:22:47 +08:00 |
|
|
|
03a01a09be
|
feat: 实现内容系统 MVC(Post CRUD + 审核流转)
按 content-system.md 设计文档,实现帖子内容系统的最小可行 MVC。
新增:
- Model: Post 模型,含 5 种状态(draft/pending/approved/rejected/locked)
- Repository: post_repo.go,分页查询(前台 approved 列表 + 后台全状态筛选)
- Service: post_service.go,核心业务逻辑(状态流转、Markdown 渲染 Goldmark)
- Controller: post_controller + admin_post_controller,SSR 页面 6 个 + API 13 个
- Template: 列表/详情/编辑器/404 + 管理员列表,各配 CSS/JS
- 路由: /posts, /posts/:id, /posts/new, /posts/:id/edit, REST API, Admin API
- gomod: + github.com/yuin/goldmark v1.8.2
修改:
- Main: AutoMigrate Post 表
- Router: deps 注册 PostService/Controller,路由注册
- Nav: 新增“帖子”导航链接
- Admin Sidebar: 新增“内容管理”入口
设计:
- 审核开关复用 audit.enabled,开启时帖子为 draft,关闭后直接 approved
- 仅 approved 公开可见,作者/admin 可预览非公开状态帖子
- 严格分层 ISP 接口: Controller → postUseCase, Service → postStore, Repo → *PostRepo
- 状态保护: pending/locked 禁止编辑,rejected 编辑后自动重置为 draft
|
2026-05-27 18:22:48 +08:00 |
|
|
|
f26da8f06e
|
refactor: 清理死代码 + 修复ISP接口注释
- 移除未使用的DTO类型(ChangePasswordRequest/DeleteAccountRequest)
- 移除service层未引用的错误重导出(auth_service/audit_service)
- 删除未使用的SiteSettingRepo(数据访问由config.SiteSettings直接处理)
- 删除未使用的FindByStatus方法(user_repo)
- 删除未使用的AutoMigrate方法(audit_repo/notification_repo)
- 删除未使用的PaginatedResult/NewPaginatedResult(pagination.go)
- 修复接口注释:notifProvider(5→4)、auditUseCase(4→3)、siteSettingUseCase(3→4)
- 移除auditStatusProvider未使用的FindByUsername方法
- 统一使用common.ErrXxx直接引用,消除跨service错误重导出耦合
|
2026-05-27 13:52:42 +08:00 |
|
|
|
0800ee2f3e
|
feat: 消息通知中心 + 账号安全体系 + Bug修复
## 新增功能
### 消息通知中心 (全新模块)
- 新增 MessageController / NotificationService / NotificationRepo
- SSR 消息页面 (/messages):左侧边栏 + 右侧卡片列表,noindex 元标签
- 通知能力:列表分页、单条标为已读、一键全部标为已读
- 未读数角标 (1/66/99+):侧边栏 + 导航栏铃铛图标
- 导航栏轮询 /api/messages/unread 每 60 秒刷新未读数
- 审核通过/驳回时自动 fire-and-forget 推送通知
### 密码修改
- ChangePassword:验证当前密码 → 新密码强度校验(8位+字母+数字) → 哈希更新
- 修改后递增 token_version 强制所有设备退登
### 账号自助注销
- DeleteAccount:验证密码 → 设置 deleted 状态 → 记录原因 → 吊销 JWT
- 注销后登录二次确认:Login 检测 deleted → 返回 confirm_restore
- ConfirmRestore 恢复账号,重新签发 token
- 注销页文案:"账号将在 7 天后正式注销,期间可随时重新登录恢复"
### IP 审计记录
- 注册时记录 RegIP,登录时记录 LastLoginIP + LastLoginAt
- clientIP() 支持 X-Forwarded-For / X-Real-IP 反向代理
### 安全加固
- Login 防时序攻击:用户不存在时仍执行完整 bcrypt 比对
- FindByEmail 改用 Unscoped() 覆盖软删除用户
- 站长 (owner) 不允许自主注销,避免权限体系死锁
## Bug 修复
1. 注销按钮不触发:JS IIFE 中 profile 代码 return 阻塞了 account 标签页处理器注册
→ 拆分为两层 IIFE,profile 放在内层
2. label 缺少 for 属性导致控制台警告 → 全部补充 for 属性
3. 注销后未自动退登:DeleteAccount 只设状态未吊销 JWT → 末尾加 InvalidateSessions
4. 退登后重定向 500 panic:authenticateToken 中 err||versionMismatch 合并判断
在 err=nil 但版本不匹配时返回 (nil,nil) → 拆为两个独立判断
injectUserContext 增加 claims==nil / 类型断言空安全守卫
5. 注销后登录直接提示"登录成功":FindByEmail 默认 scope 排除软删除记录
→ 改用 Unscoped()
## 文件变更
- 新建 17 个文件 (消息/审核/站点设置完整模块)
- 修改 25 个文件 (认证/设置/中间件/前端)
- 统计:+3229 / -161,42 files changed
|
2026-05-27 13:32:45 +08:00 |
|
|
|
39d13993ba
|
fix: 设计原则审查修复 — DIP/ISP, LoD, DRY, OCP, URL, 301缓存
- P0 DIP+ISP: 全链路注入接口,消除零接口紧耦合
- P0 URL: auth 301→302,修复登出后浏览器缓存陷阱
- P1 DRY: JWT 认证逻辑收敛至 TokenService+中间件
- P2 DRY: 前后端角色/状态映射统一为 model 常量
- P2 LoD: 新增 SettingsController,router 不再跨层调 repo
- P2 URL: settings ?tab= → /settings/:tab 伪静态
- P3 OCP: 角色权限 map 化,告别硬编码 switch
|
2026-05-26 21:12:19 +08:00 |
|
|
|
483fdd919f
|
初始化项目:基础设施 + 用户认证 + 后台管理系统 + AGPL 3.0 许可
|
2026-05-26 13:46:33 +08:00 |
|