0202-финиш перед десктопом

пересчет поправил
редактирование с перепроведением
галка автопроведения работает
рекомендации починил
This commit is contained in:
2026-02-02 13:53:38 +03:00
parent 10882f55c8
commit 88620f3fb6
37 changed files with 1905 additions and 11162 deletions

View File

@@ -2,6 +2,7 @@ package handlers
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
@@ -48,13 +49,16 @@ func (h *SettingsHandler) SetNotifier(n Notifier) {
// SettingsResponse - DTO для отдачи настроек
type SettingsResponse struct {
ID string `json:"id"`
Name string `json:"name"`
BaseURL string `json:"base_url"`
DefaultStoreID *string `json:"default_store_id"` // Nullable
RootGroupID *string `json:"root_group_id"` // Nullable
AutoConduct bool `json:"auto_conduct"`
Role string `json:"role"` // OWNER, ADMIN, OPERATOR
ID string `json:"id"`
Name string `json:"name"`
BaseURL string `json:"base_url"`
DefaultStoreID *string `json:"default_store_id"` // Nullable
RootGroupID *string `json:"root_group_id"` // Nullable
AutoConduct bool `json:"auto_conduct"`
Role string `json:"role"` // OWNER, ADMIN, OPERATOR
SyncInterval int `json:"sync_interval"` // Интервал синхронизации в минутах
LastSyncAt *time.Time `json:"last_sync_at"` // Время последней синхронизации
LastActivityAt *time.Time `json:"last_activity_at"` // Время последней активности
}
// GetSettings возвращает настройки активного сервера + роль пользователя
@@ -77,11 +81,14 @@ func (h *SettingsHandler) GetSettings(c *gin.Context) {
}
resp := SettingsResponse{
ID: server.ID.String(),
Name: server.Name,
BaseURL: server.BaseURL,
AutoConduct: server.AutoProcess,
Role: string(role),
ID: server.ID.String(),
Name: server.Name,
BaseURL: server.BaseURL,
AutoConduct: server.AutoProcess,
Role: string(role),
SyncInterval: server.SyncInterval,
LastSyncAt: server.LastSyncAt,
LastActivityAt: server.LastActivityAt,
}
if server.DefaultStoreID != nil {
@@ -96,16 +103,17 @@ func (h *SettingsHandler) GetSettings(c *gin.Context) {
c.JSON(http.StatusOK, resp)
}
// UpdateSettingsDTO
// UpdateSettingsDTO - DTO для частичного обновления настроек (PATCH-семантика)
type UpdateSettingsDTO struct {
Name string `json:"name"`
DefaultStoreID string `json:"default_store_id"`
RootGroupID string `json:"root_group_id"`
AutoProcess bool `json:"auto_process"`
AutoConduct bool `json:"auto_conduct"`
Name *string `json:"name"`
DefaultStoreID *string `json:"default_store_id"`
RootGroupID *string `json:"root_group_id"`
AutoProcess *bool `json:"auto_process"` // Legacy для обратной совместимости
AutoConduct *bool `json:"auto_conduct"` // Новое поле
SyncInterval *int `json:"sync_interval,omitempty"` // Интервал синхронизации в минутах (5 - 10080)
}
// UpdateSettings сохраняет настройки
// UpdateSettings сохраняет настройки с PATCH-семантикой
func (h *SettingsHandler) UpdateSettings(c *gin.Context) {
userID := c.MustGet("userID").(uuid.UUID)
@@ -115,6 +123,11 @@ func (h *SettingsHandler) UpdateSettings(c *gin.Context) {
return
}
// Логирование полученных данных для отладки
logger.Log.Info("Получен запрос на обновление настроек",
zap.Any("request", req),
)
server, err := h.accountRepo.GetActiveServer(userID)
if err != nil || server == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "No active server"})
@@ -132,31 +145,56 @@ func (h *SettingsHandler) UpdateSettings(c *gin.Context) {
return
}
if req.Name != "" {
server.Name = req.Name
// Обновление имени (только если передано)
if req.Name != nil {
server.Name = *req.Name
}
if req.AutoConduct {
server.AutoProcess = true
} else {
server.AutoProcess = req.AutoProcess || req.AutoConduct
// Обновление флага авто-проведения
if req.AutoConduct != nil {
server.AutoProcess = *req.AutoConduct
} else if req.AutoProcess != nil {
// Fallback для старых клиентов, которые используют legacy поле
server.AutoProcess = *req.AutoProcess
}
if req.DefaultStoreID != "" {
if uid, err := uuid.Parse(req.DefaultStoreID); err == nil {
server.DefaultStoreID = &uid
// Обновление интервала синхронизации
if req.SyncInterval != nil {
// Валидация диапазона: от 5 минут до 1 недели (10080 минут)
if *req.SyncInterval < 5 || *req.SyncInterval > 10080 {
c.JSON(http.StatusBadRequest, gin.H{"error": "sync_interval должен быть от 5 минут до 1 недели (10080 минут)"})
return
}
} else {
server.DefaultStoreID = nil
server.SyncInterval = *req.SyncInterval
}
if req.RootGroupID != "" {
if uid, err := uuid.Parse(req.RootGroupID); err == nil {
server.RootGroupGUID = &uid
// Обновление DefaultStoreID
if req.DefaultStoreID != nil {
if *req.DefaultStoreID == "" {
// Пустая строка -> сбрасываем в nil
server.DefaultStoreID = nil
} else {
// UUID -> обновляем
if uid, err := uuid.Parse(*req.DefaultStoreID); err == nil {
server.DefaultStoreID = &uid
}
}
} else {
server.RootGroupGUID = nil
}
// Если nil -> не трогаем текущее значение
// Обновление RootGroupID
if req.RootGroupID != nil {
if *req.RootGroupID == "" {
// Пустая строка -> сбрасываем в nil
server.RootGroupGUID = nil
} else {
// UUID -> обновляем
if uid, err := uuid.Parse(*req.RootGroupID); err == nil {
server.RootGroupGUID = &uid
}
}
}
// Если nil -> не трогаем текущее значение
if err := h.accountRepo.SaveServerSettings(server); err != nil {
logger.Log.Error("Failed to save settings", zap.Error(err))