6816289552
build / build (push) Successful in 1m23s
周报页新增自动发送区:管理员配置 SMTP/收件人/发送星期与小时,授权码用主密钥加密保存。 确认绑定当前草稿版本与正文哈希,正文再改则确认失效;worker 每分钟仅在启用、到点、周已结束且未发送过时发一次。 邮件同时提供渲染后的 HTML 与可读纯文本;SMTP 仅允许 TLS,拒绝明文。 迁移 000060 新增设置、确认与发送记录三张表,唯一键防重复发送。
134 lines
4.2 KiB
Go
134 lines
4.2 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"knowledge-governance/internal/dobotaiops"
|
|
"knowledge-governance/internal/qawemail"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
type weeklyMailStore interface {
|
|
ReadSettings(context.Context) (qawemail.Settings, error)
|
|
SaveSettings(context.Context, string, qawemail.SettingsInput) (qawemail.Settings, error)
|
|
Confirm(context.Context, string, string) (qawemail.Confirmation, error)
|
|
Unconfirm(context.Context, string) error
|
|
ReadConfirmation(context.Context, string) (*qawemail.Confirmation, error)
|
|
Sends(context.Context, string) ([]qawemail.Send, error)
|
|
SendDue(context.Context, time.Time) (qawemail.DueResult, error)
|
|
}
|
|
|
|
func weeklyMailError(w http.ResponseWriter, err error) {
|
|
switch {
|
|
case errors.Is(err, qawemail.ErrConflict):
|
|
writeJSON(w, http.StatusConflict, map[string]string{"error": "发送设置已被其他人修改,请重新读取后再保存"})
|
|
case errors.Is(err, qawemail.ErrInvalid):
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "发送设置无效:请检查服务器、发件地址、收件人与时间"})
|
|
case errors.Is(err, qawemail.ErrUnavailable):
|
|
writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "周报邮件暂不可用,请稍后重试;未标记为已发送"})
|
|
default:
|
|
qaOpsError(w, dobotaiops.ErrUnavailable)
|
|
}
|
|
}
|
|
|
|
func qaWeeklyMailSettings(w http.ResponseWriter, r *http.Request, c Config) {
|
|
if !authorizeQAOps(w, r) {
|
|
return
|
|
}
|
|
store, ok := c.QAWeeklyMail.(weeklyMailStore)
|
|
if !ok {
|
|
weeklyMailError(w, qawemail.ErrUnavailable)
|
|
return
|
|
}
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
settings, err := store.ReadSettings(r.Context())
|
|
if err != nil {
|
|
weeklyMailError(w, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"data": settings})
|
|
case http.MethodPost:
|
|
if !authorizeQAIntent(w, r, "qa-weekly-mail") {
|
|
return
|
|
}
|
|
if identity, ok := sessionFrom(r.Context()); !ok || identity.Role != "admin" {
|
|
writeJSON(w, http.StatusForbidden, map[string]string{"error": "仅管理员可修改邮件发送设置"})
|
|
return
|
|
}
|
|
var input qawemail.SettingsInput
|
|
if decodeQualityJSON(w, r, &input) != nil {
|
|
weeklyMailError(w, qawemail.ErrInvalid)
|
|
return
|
|
}
|
|
identity, _ := sessionFrom(r.Context())
|
|
actor := identity.Username
|
|
settings, err := store.SaveSettings(r.Context(), actor, input)
|
|
if err != nil {
|
|
weeklyMailError(w, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"data": settings})
|
|
default:
|
|
w.Header().Set("Allow", "GET, POST")
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "不支持的方法"})
|
|
}
|
|
}
|
|
|
|
func qaWeeklyMailConfirm(w http.ResponseWriter, r *http.Request, c Config) {
|
|
if !authorizeQAOps(w, r) || !authorizeQAIntent(w, r, "qa-weekly-mail") {
|
|
return
|
|
}
|
|
store, ok := c.QAWeeklyMail.(weeklyMailStore)
|
|
if !ok {
|
|
weeklyMailError(w, qawemail.ErrUnavailable)
|
|
return
|
|
}
|
|
week := r.PathValue("week")
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
confirmation, err := store.ReadConfirmation(r.Context(), week)
|
|
if err != nil {
|
|
weeklyMailError(w, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"data": map[string]any{"confirmation": confirmation}})
|
|
case http.MethodPost:
|
|
identity, _ := sessionFrom(r.Context())
|
|
actor := identity.Username
|
|
confirmation, err := store.Confirm(r.Context(), week, actor)
|
|
if err != nil {
|
|
weeklyMailError(w, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"data": map[string]any{"confirmation": confirmation}})
|
|
case http.MethodDelete:
|
|
if err := store.Unconfirm(r.Context(), week); err != nil {
|
|
weeklyMailError(w, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"data": map[string]any{"confirmation": nil}})
|
|
default:
|
|
w.Header().Set("Allow", "GET, POST, DELETE")
|
|
writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "不支持的方法"})
|
|
}
|
|
}
|
|
|
|
func qaWeeklyMailSends(w http.ResponseWriter, r *http.Request, c Config) {
|
|
if !authorizeQAOps(w, r) {
|
|
return
|
|
}
|
|
store, ok := c.QAWeeklyMail.(weeklyMailStore)
|
|
if !ok {
|
|
weeklyMailError(w, qawemail.ErrUnavailable)
|
|
return
|
|
}
|
|
sends, err := store.Sends(r.Context(), r.URL.Query().Get("week"))
|
|
if err != nil {
|
|
weeklyMailError(w, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"data": map[string]any{"sends": sends}})
|
|
}
|