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

@@ -7,8 +7,10 @@ import (
"time"
"rmser/internal/domain/account"
"rmser/pkg/logger"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
)
@@ -78,7 +80,8 @@ func (r *pgRepository) ConnectServer(userID uuid.UUID, rawURL, login, encryptedP
var created bool
err := r.db.Transaction(func(tx *gorm.DB) error {
err := tx.Where("base_url = ?", cleanURL).First(&server).Error
// Сначала ищем среди удаленных серверов
err := tx.Unscoped().Where("base_url = ?", cleanURL).First(&server).Error
if err != nil && err != gorm.ErrRecordNotFound {
return err
}
@@ -100,8 +103,17 @@ func (r *pgRepository) ConnectServer(userID uuid.UUID, rawURL, login, encryptedP
return err
}
created = true
} else if server.DeletedAt.Valid {
// --- СЦЕНАРИЙ 2: ВОССТАНОВЛЕНИЕ УДАЛЕННОГО СЕРВЕРА ---
// Восстанавливаем сервер, сохраняя старые значения Balance, InvoiceCount и ID
server.Name = name
server.DeletedAt = gorm.DeletedAt{} // Сбрасываем deleted_at
if err := tx.Save(&server).Error; err != nil {
return err
}
created = true // При восстановлении пользователь становится владельцем
} else {
// --- СЦЕНАРИЙ 2: СУЩЕСТВУЮЩИЙ СЕРВЕР ---
// --- СЦЕНАРИЙ 3: СУЩЕСТВУЮЩИЙ АКТИВНЫЙ СЕРВЕР ---
var userCount int64
tx.Model(&account.ServerUser{}).Where("server_id = ?", server.ID).Count(&userCount)
if userCount >= int64(server.MaxUsers) {
@@ -156,9 +168,92 @@ func (r *pgRepository) SaveServerSettings(server *account.RMSServer) error {
"root_group_guid": server.RootGroupGUID,
"auto_process": server.AutoProcess,
"max_users": server.MaxUsers,
"sync_interval": server.SyncInterval,
}).Error
}
// UpdateLastActivity обновляет время последней активности пользователя
func (r *pgRepository) UpdateLastActivity(serverID uuid.UUID) error {
result := r.db.Model(&account.RMSServer{}).
Where("id = ?", serverID).
Update("last_activity_at", gorm.Expr("NOW()"))
if result.Error != nil {
logger.Log.Error("Failed to update last_activity_at",
zap.String("server_id", serverID.String()),
zap.Error(result.Error))
return result.Error
}
if result.RowsAffected == 0 {
logger.Log.Warn("UpdateLastActivity: server not found",
zap.String("server_id", serverID.String()))
return fmt.Errorf("сервер не найден")
}
return nil
}
// UpdateLastSync обновляет время последней успешной синхронизации
func (r *pgRepository) UpdateLastSync(serverID uuid.UUID) error {
result := r.db.Model(&account.RMSServer{}).
Where("id = ?", serverID).
Update("last_sync_at", gorm.Expr("NOW()"))
if result.Error != nil {
logger.Log.Error("Failed to update last_sync_at",
zap.String("server_id", serverID.String()),
zap.Error(result.Error))
return result.Error
}
if result.RowsAffected == 0 {
logger.Log.Warn("UpdateLastSync: server not found",
zap.String("server_id", serverID.String()))
return fmt.Errorf("сервер не найден")
}
return nil
}
// GetServersForSync возвращает серверы, готовые для синхронизации
func (r *pgRepository) GetServersForSync(idleThreshold time.Duration) ([]account.RMSServer, error) {
var servers []account.RMSServer
// Конвертируем duration в минуты для SQL
idleMinutes := int(idleThreshold.Minutes())
query := `
SELECT * FROM rms_servers
WHERE
deleted_at IS NULL
AND (
-- Случай 1: Настало время периодической синхронизации
(EXTRACT(EPOCH FROM (NOW() - COALESCE(last_sync_at, '1970-01-01'::timestamp))) / 60) >= sync_interval
OR
-- Случай 2: Прошло N мин с последней активности, и активность была ПОЗЖЕ синхронизации
(
last_activity_at > last_sync_at
AND (EXTRACT(EPOCH FROM (NOW() - last_activity_at)) / 60) >= ?
)
)
`
err := r.db.Raw(query, idleMinutes).Scan(&servers).Error
if err != nil {
logger.Log.Error("Failed to get servers for sync",
zap.Int("idle_threshold_minutes", idleMinutes),
zap.Error(err))
return nil, err
}
logger.Log.Info("Servers ready for sync",
zap.Int("count", len(servers)),
zap.Int("idle_threshold_minutes", idleMinutes))
return servers, nil
}
func (r *pgRepository) SetActiveServer(userID, serverID uuid.UUID) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// Проверка доступа
@@ -252,7 +347,7 @@ func (r *pgRepository) GetAllAvailableServers(userID uuid.UUID) ([]account.RMSSe
}
func (r *pgRepository) DeleteServer(serverID uuid.UUID) error {
// Полное удаление сервера и всех связей
// Мягкое удаление сервера и всех связей
return r.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("server_id = ?", serverID).Delete(&account.ServerUser{}).Error; err != nil {
return err