fix anwser token and database issus
This commit is contained in:
+12
-22
@@ -11,39 +11,31 @@ import (
|
||||
)
|
||||
|
||||
// MaxFollowUpCount 每条提问允许的最大追问次数(防滥用)。
|
||||
// 提问者被回答后,用 token(或登录账号)继续追问,达到上限后不可再追问。
|
||||
const MaxFollowUpCount = 3
|
||||
|
||||
// 追问相关错误(供 handler 区分处理,避免把业务错误当 500)
|
||||
// 追问相关错误,供 handler 区分处理,避免把业务错误当 500。
|
||||
var (
|
||||
// ErrFollowUpLimitReached 追问次数已达上限
|
||||
ErrFollowUpLimitReached = errors.New("follow up limit reached")
|
||||
// ErrFollowUpNotFound 追问不存在或不属于该问题
|
||||
ErrFollowUpNotFound = errors.New("follow up not found")
|
||||
// ErrFollowUpAlreadyAnswered 追问已被回答(禁止覆盖)
|
||||
ErrFollowUpLimitReached = errors.New("follow up limit reached")
|
||||
ErrFollowUpNotFound = errors.New("follow up not found")
|
||||
ErrFollowUpAlreadyAnswered = errors.New("follow up already answered")
|
||||
)
|
||||
|
||||
var FollowUps FollowUpsStore
|
||||
|
||||
type FollowUpsStore interface {
|
||||
// CreateIfBelowLimit 原子创建追问:仅当该问题追问次数未达上限时创建。
|
||||
// 返回 created=false 且 err==ErrFollowUpLimitReached 表示已达上限。
|
||||
// 通过事务内锁定问题行,串行化同一问题的并发追问,消除 count-then-create 竞态。
|
||||
// CreateIfBelowLimit 原子创建追问:仅当该问题追问次数未达上限时创建;
|
||||
// 事务内锁定问题行串行化并发追问,消除 count-then-create 竞态。已达上限返回 (false, ErrFollowUpLimitReached)。
|
||||
CreateIfBelowLimit(ctx context.Context, opts CreateFollowUpOptions) (created bool, err error)
|
||||
GetByQuestionID(ctx context.Context, questionID uint) ([]*FollowUp, error)
|
||||
// GetLatestByQuestionID 返回某条提问最新的一条追问;无追问时返回 (nil, nil)。
|
||||
GetLatestByQuestionID(ctx context.Context, questionID uint) (*FollowUp, error)
|
||||
// GetByQuestionIDs 批量获取多个提问的追问,按 question_id 分组返回。
|
||||
// 用于账号导出等场景,将 N 次单题查询合并为 1 次 IN 查询,避免 N+1。
|
||||
// GetByQuestionIDs 批量获取多个提问的追问,按 question_id 分组返回(导出场景合并 N+1 为 1 次 IN 查询)。
|
||||
GetByQuestionIDs(ctx context.Context, questionIDs []uint) (map[uint][]*FollowUp, error)
|
||||
CountByQuestionID(ctx context.Context, questionID uint) (int64, error)
|
||||
// AnswerByID 回答某条追问;questionID 用于防止越权(必须属于该问题)。
|
||||
// 仅允许回答尚未回答的追问(answer 为空),已回答的返回 ErrFollowUpAlreadyAnswered,
|
||||
// 不存在/不属于该问题返回 ErrFollowUpNotFound。
|
||||
// AnswerByID 回答某条追问;questionID 防越权(必须属于该问题),仅允许回答尚未回答的(answer 为空)。
|
||||
// 已回答返回 ErrFollowUpAlreadyAnswered,不存在/不属于该问题返回 ErrFollowUpNotFound。
|
||||
AnswerByID(ctx context.Context, questionID uint, id uint, answer string) error
|
||||
// UpdateAnswerByID 修改某条追问的回答内容(带 question_id 条件防止越权),
|
||||
// 与 AnswerByID 不同,此处允许覆盖已回答的追问(供主人修改回复使用)。
|
||||
// UpdateAnswerByID 修改某条追问的回答内容(带 question_id 条件防越权),允许覆盖已回答的(供主人修改回复)。
|
||||
// 不存在/不属于该问题返回 ErrFollowUpNotFound。
|
||||
UpdateAnswerByID(ctx context.Context, questionID uint, id uint, answer string) error
|
||||
// DeleteByQuestionID 删除某条提问时级联清理其全部追问(软删除,与提问保持一致)。
|
||||
@@ -120,8 +112,7 @@ func (db *followUps) GetByQuestionID(ctx context.Context, questionID uint) ([]*F
|
||||
return followUps, nil
|
||||
}
|
||||
|
||||
// GetLatestByQuestionID 返回某条提问最新的一条追问(created_at 倒序取首条);
|
||||
// 无追问时返回 (nil, nil)。供发布追问前校验"上一条是否已回复"。
|
||||
// GetLatestByQuestionID 返回某条提问最新的一条追问(created_at 倒序);无追问时返回 (nil, nil),供发布前校验上一条是否已回复。
|
||||
func (db *followUps) GetLatestByQuestionID(ctx context.Context, questionID uint) (*FollowUp, error) {
|
||||
var fu FollowUp
|
||||
err := db.WithContext(ctx).
|
||||
@@ -169,9 +160,8 @@ func (db *followUps) CountByQuestionID(ctx context.Context, questionID uint) (in
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// AnswerByID 更新某条追问的回答内容(带 question_id 条件防止越权)。
|
||||
// 原子更新条件含 answer=”:已回答的追问不会被覆盖(避免重复提交时邮件/回答被二次写入)。
|
||||
// RowsAffected==0 时再查一次以区分"不存在"与"已回答",返回对应错误。
|
||||
// AnswerByID 更新回答(带 question_id 防越权)。
|
||||
// 原子条件含 answer=”,已回答的不被覆盖;RowsAffected==0 再查一次以区分"不存在"与"已回答"。
|
||||
func (db *followUps) AnswerByID(ctx context.Context, questionID uint, id uint, answer string) error {
|
||||
res := db.WithContext(ctx).
|
||||
Model(&FollowUp{}).
|
||||
|
||||
Reference in New Issue
Block a user