refactor: убрать qt_pricelist_sync_status, lot_log и лишние права БД
- Удалить все записи в qt_pricelist_sync_status (RecordSyncHeartbeat и ensureUserSyncStatusTable); ListUserSyncStatuses переведён на qt_client_schema_state - Подавлять устаревший OFFLINE_UNVERIFIED_SCHEMA в UI когда соединение уже восстановлено - Удалить все обращения к lot_log: repository/price.go, сортировка quote_count в component.go, UpdatePopularityScores в stats.go, модель LotLog Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -427,7 +427,6 @@ func (s *Service) SyncPricelists() (int, error) {
|
||||
now := time.Now()
|
||||
s.localDB.SetLastSyncTime(now)
|
||||
s.recordPricelistSyncSuccess(now)
|
||||
s.RecordSyncHeartbeat()
|
||||
s.localDB.AppendSyncLog("pricelists", "ok", "", synced, plSyncStart, time.Since(plSyncStart).Milliseconds())
|
||||
|
||||
slog.Info("pricelist sync completed", "synced", synced, "total", len(serverPricelists))
|
||||
@@ -612,58 +611,29 @@ func (s *Service) backfillUsedPricelistItemCategories(pricelistRepo *repository.
|
||||
}
|
||||
}
|
||||
|
||||
// RecordSyncHeartbeat updates shared sync heartbeat for current DB user.
|
||||
// Only users with write rights are expected to be able to update this table.
|
||||
func (s *Service) RecordSyncHeartbeat() {
|
||||
username := strings.TrimSpace(s.localDB.GetDBUser())
|
||||
if username == "" {
|
||||
return
|
||||
}
|
||||
|
||||
mariaDB, err := s.getDB()
|
||||
if err != nil || mariaDB == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := ensureUserSyncStatusTable(mariaDB); err != nil {
|
||||
slog.Warn("sync heartbeat: failed to ensure table", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
if err := mariaDB.Exec(`
|
||||
INSERT INTO qt_pricelist_sync_status (username, last_sync_at, updated_at, app_version)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
last_sync_at = VALUES(last_sync_at),
|
||||
updated_at = VALUES(updated_at),
|
||||
app_version = VALUES(app_version)
|
||||
`, username, now, now, appmeta.Version()).Error; err != nil {
|
||||
slog.Debug("sync heartbeat: skipped", "username", username, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ListUserSyncStatuses returns users who have recorded sync heartbeat.
|
||||
// ListUserSyncStatuses returns users who have recorded a client schema state check.
|
||||
func (s *Service) ListUserSyncStatuses(onlineThreshold time.Duration) ([]UserSyncStatus, error) {
|
||||
mariaDB, err := s.getDB()
|
||||
if err != nil || mariaDB == nil {
|
||||
return nil, ErrOffline
|
||||
}
|
||||
|
||||
if err := ensureUserSyncStatusTable(mariaDB); err != nil {
|
||||
return nil, fmt.Errorf("ensure sync status table: %w", err)
|
||||
}
|
||||
|
||||
type row struct {
|
||||
Username string `gorm:"column:username"`
|
||||
LastSyncAt time.Time `gorm:"column:last_sync_at"`
|
||||
AppVersion string `gorm:"column:app_version"`
|
||||
Username string `gorm:"column:username"`
|
||||
LastCheckedAt time.Time `gorm:"column:last_checked_at"`
|
||||
AppVersion string `gorm:"column:app_version"`
|
||||
}
|
||||
var rows []row
|
||||
if err := mariaDB.Raw(`
|
||||
SELECT username, last_sync_at, COALESCE(app_version, '') AS app_version
|
||||
FROM qt_pricelist_sync_status
|
||||
ORDER BY last_sync_at DESC, username ASC
|
||||
SELECT s.username, s.last_checked_at, COALESCE(s.app_version, '') AS app_version
|
||||
FROM qt_client_schema_state s
|
||||
INNER JOIN (
|
||||
SELECT username, MAX(last_checked_at) AS max_checked
|
||||
FROM qt_client_schema_state
|
||||
GROUP BY username
|
||||
) latest ON s.username = latest.username AND s.last_checked_at = latest.max_checked
|
||||
GROUP BY s.username
|
||||
ORDER BY s.last_checked_at DESC, s.username ASC
|
||||
`).Scan(&rows).Error; err != nil {
|
||||
return nil, fmt.Errorf("load sync status rows: %w", err)
|
||||
}
|
||||
@@ -683,7 +653,7 @@ func (s *Service) ListUserSyncStatuses(onlineThreshold time.Duration) ([]UserSyn
|
||||
continue
|
||||
}
|
||||
|
||||
isOnline := now.Sub(r.LastSyncAt) <= onlineThreshold
|
||||
isOnline := now.Sub(r.LastCheckedAt) <= onlineThreshold
|
||||
if _, connected := activeUsers[username]; connected {
|
||||
isOnline = true
|
||||
delete(activeUsers, username)
|
||||
@@ -693,7 +663,7 @@ func (s *Service) ListUserSyncStatuses(onlineThreshold time.Duration) ([]UserSyn
|
||||
|
||||
result = append(result, UserSyncStatus{
|
||||
Username: username,
|
||||
LastSyncAt: r.LastSyncAt,
|
||||
LastSyncAt: r.LastCheckedAt,
|
||||
AppVersion: appVersion,
|
||||
IsOnline: isOnline,
|
||||
})
|
||||
@@ -747,36 +717,6 @@ func (s *Service) listConnectedDBUsers(mariaDB *gorm.DB) (map[string]struct{}, e
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func ensureUserSyncStatusTable(db *gorm.DB) error {
|
||||
// Check if table exists instead of trying to create (avoids permission issues)
|
||||
if !tableExists(db, "qt_pricelist_sync_status") {
|
||||
if err := db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS qt_pricelist_sync_status (
|
||||
username VARCHAR(100) NOT NULL,
|
||||
last_sync_at DATETIME NOT NULL,
|
||||
updated_at DATETIME NOT NULL,
|
||||
app_version VARCHAR(64) NULL,
|
||||
PRIMARY KEY (username),
|
||||
INDEX idx_qt_pricelist_sync_status_last_sync (last_sync_at)
|
||||
)
|
||||
`).Error; err != nil {
|
||||
return fmt.Errorf("create qt_pricelist_sync_status table: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Backward compatibility for environments where table was created without app_version.
|
||||
// Only try to add column if table exists.
|
||||
if tableExists(db, "qt_pricelist_sync_status") {
|
||||
if err := db.Exec(`
|
||||
ALTER TABLE qt_pricelist_sync_status
|
||||
ADD COLUMN IF NOT EXISTS app_version VARCHAR(64) NULL
|
||||
`).Error; err != nil {
|
||||
// Log but don't fail if alter fails (column might already exist)
|
||||
slog.Debug("failed to add app_version column", "error", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncPricelistItems synchronizes items for a specific pricelist
|
||||
func (s *Service) SyncPricelistItems(localPricelistID uint) (int, error) {
|
||||
|
||||
@@ -100,8 +100,5 @@ func (w *Worker) runSync() {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark user's sync heartbeat (used for online/offline status in UI).
|
||||
w.service.RecordSyncHeartbeat()
|
||||
|
||||
w.logger.Info("background sync cycle completed")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user