feat: 实现端停用与删除的消息作废与群主转让级联
This commit is contained in:
@@ -320,18 +320,39 @@ func (h *Handler) handleEndpointPatch(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
wasEnabled, err := h.patchEndpoint(r.Context(), id, req.Name, req.Remark, req.DefaultDelaySeconds, req.Enabled)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
hasMeta := req.Name != nil || req.Remark != nil || req.DefaultDelaySeconds != nil
|
||||
var wasEnabled bool
|
||||
var err error
|
||||
if hasMeta || (req.Enabled != nil && h.identity == nil) {
|
||||
wasEnabled, err = h.patchEndpoint(r.Context(), id, req.Name, req.Remark, req.DefaultDelaySeconds, req.Enabled)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
h.audit(actorString(p), "endpoint_patch", id, "not_found", ip)
|
||||
httpx.WriteError(w, http.StatusNotFound, "not_found", "端不存在")
|
||||
return
|
||||
}
|
||||
h.audit(actorString(p), "endpoint_patch", id, "error", ip)
|
||||
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.Enabled != nil && h.identity != nil {
|
||||
var found bool
|
||||
found, err = h.setEndpointEnabled(r.Context(), id, *req.Enabled)
|
||||
if err != nil {
|
||||
h.audit(actorString(p), "endpoint_patch", id, "error", ip)
|
||||
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
h.audit(actorString(p), "endpoint_patch", id, "not_found", ip)
|
||||
httpx.WriteError(w, http.StatusNotFound, "not_found", "端不存在")
|
||||
return
|
||||
}
|
||||
h.audit(actorString(p), "endpoint_patch", id, "error", ip)
|
||||
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
|
||||
return
|
||||
}
|
||||
if req.Enabled != nil && !*req.Enabled && wasEnabled {
|
||||
if !*req.Enabled {
|
||||
_, _ = h.kickEndpoint(r.Context(), id)
|
||||
}
|
||||
} else if req.Enabled != nil && !*req.Enabled && wasEnabled {
|
||||
_, _ = h.kickEndpoint(r.Context(), id)
|
||||
}
|
||||
row, err := h.getEndpoint(r.Context(), id)
|
||||
|
||||
@@ -308,6 +308,21 @@ func (h *Handler) patchEndpoint(ctx context.Context, id string, name, remark *st
|
||||
}
|
||||
|
||||
func (h *Handler) setEndpointEnabled(ctx context.Context, id string, enabled bool) (found bool, err error) {
|
||||
if h.identity != nil {
|
||||
var opErr error
|
||||
if enabled {
|
||||
opErr = h.identity.Enable(ctx, id)
|
||||
} else {
|
||||
opErr = h.identity.Disable(ctx, id)
|
||||
}
|
||||
if opErr != nil {
|
||||
if isEndpointNotFound(opErr) {
|
||||
return false, nil
|
||||
}
|
||||
return false, opErr
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
err = h.db.Queue.Do(ctx, func(tx *sql.Tx) error {
|
||||
v := 0
|
||||
if enabled {
|
||||
@@ -331,9 +346,18 @@ func (h *Handler) setEndpointEnabled(ctx context.Context, id string, enabled boo
|
||||
return found, err
|
||||
}
|
||||
|
||||
// deleteEndpointBasic 删除端行并清掉与之相关的 talk_grants。
|
||||
// 作废消息、群主转让等完整级联留给 I5。
|
||||
// deleteEndpointBasic 删除端;注入 Identity 时走 I5 完整级联。
|
||||
func (h *Handler) deleteEndpointBasic(ctx context.Context, id string) (found bool, err error) {
|
||||
if h.identity != nil {
|
||||
opErr := h.identity.Delete(ctx, id)
|
||||
if opErr != nil {
|
||||
if isEndpointNotFound(opErr) {
|
||||
return false, nil
|
||||
}
|
||||
return false, opErr
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
err = h.db.Queue.Do(ctx, func(tx *sql.Tx) error {
|
||||
if _, e := tx.ExecContext(ctx, `DELETE FROM talk_grants WHERE sender_id = ? OR target_id = ?`, id, id); e != nil {
|
||||
return e
|
||||
@@ -349,6 +373,11 @@ func (h *Handler) deleteEndpointBasic(ctx context.Context, id string) (found boo
|
||||
return found, err
|
||||
}
|
||||
|
||||
func isEndpointNotFound(err error) bool {
|
||||
var pe *protocol.Error
|
||||
return errors.As(err, &pe) && pe.Code == protocol.CodeNotFound
|
||||
}
|
||||
|
||||
func (h *Handler) resetLoginPassword(ctx context.Context, id, loginHash string) (bool, error) {
|
||||
var found bool
|
||||
err := h.db.Queue.Do(ctx, func(tx *sql.Tx) error {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.asio.asia/nixevol/NixMsg/internal/app/identity"
|
||||
"git.asio.asia/nixevol/NixMsg/internal/auth"
|
||||
"git.asio.asia/nixevol/NixMsg/internal/store"
|
||||
)
|
||||
@@ -38,6 +39,8 @@ type Deps struct {
|
||||
SecureCookies bool
|
||||
// KickEndpoint 踢下线钩子(只断开连接);nil 时踢线为 no-op。
|
||||
KickEndpoint EndpointKickFunc
|
||||
// Identity 端停用/启用/删除级联(I5);nil 时回退为仅改 enabled/删行。
|
||||
Identity identity.Service
|
||||
}
|
||||
|
||||
// Handler 是可挂载的管理接口(路由前缀 /api/admin/)。
|
||||
@@ -51,6 +54,7 @@ type Handler struct {
|
||||
ttl time.Duration
|
||||
forceSec bool
|
||||
kick EndpointKickFunc
|
||||
identity identity.Service
|
||||
|
||||
mux *http.ServeMux
|
||||
|
||||
@@ -80,6 +84,7 @@ func New(d Deps) *Handler {
|
||||
ttl: ttl,
|
||||
forceSec: d.SecureCookies,
|
||||
kick: d.KickEndpoint,
|
||||
identity: d.Identity,
|
||||
mux: http.NewServeMux(),
|
||||
lastUsed: make(map[string]time.Time),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user