mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
добавил пользователей для сервера и роли
добавил инвайт-ссылки с ролью оператор для сервера добавил супер-админку для смены владельцев добавил уведомления о смене ролей на серверах добавил модалку для фото прям в черновике добавил UI для редактирования прав
This commit is contained in:
@@ -30,74 +30,47 @@ func NewFactory(repo account.Repository, cm *crypto.CryptoManager) *Factory {
|
||||
}
|
||||
}
|
||||
|
||||
// GetClientByServerID возвращает готовый клиент для конкретного сервера
|
||||
func (f *Factory) GetClientByServerID(serverID uuid.UUID) (ClientI, error) {
|
||||
// 1. Пытаемся найти в кэше (быстрый путь)
|
||||
// GetClientForUser возвращает клиент для текущего активного сервера пользователя.
|
||||
// Использует личные или наследуемые (от Owner) учетные данные.
|
||||
func (f *Factory) GetClientForUser(userID uuid.UUID) (ClientI, error) {
|
||||
// 1. Пытаемся найти в кэше
|
||||
f.mu.RLock()
|
||||
client, exists := f.clients[serverID]
|
||||
client, exists := f.clients[userID]
|
||||
f.mu.RUnlock()
|
||||
|
||||
if exists {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// 2. Если нет в кэше - ищем в БД (медленный путь)
|
||||
// Здесь нам нужен метод GetServerByID, но в репо есть только GetAll/GetActive.
|
||||
// Для MVP загрузим все сервера юзера и найдем нужный, либо (лучше) добавим метод в репо позже.
|
||||
// ПОКА: предполагаем, что factory используется в контексте User, поэтому лучше метод GetClientForUser
|
||||
return nil, fmt.Errorf("client not found in cache (use GetClientForUser or implement GetServerByID)")
|
||||
}
|
||||
|
||||
// GetClientForUser находит активный сервер пользователя и возвращает клиент
|
||||
func (f *Factory) GetClientForUser(userID uuid.UUID) (ClientI, error) {
|
||||
// 1. Получаем настройки активного сервера из БД
|
||||
server, err := f.accountRepo.GetActiveServer(userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db error: %w", err)
|
||||
}
|
||||
if server == nil {
|
||||
return nil, fmt.Errorf("у пользователя нет активного сервера RMS")
|
||||
}
|
||||
|
||||
// 2. Проверяем кэш по ID сервера
|
||||
f.mu.RLock()
|
||||
cachedClient, exists := f.clients[server.ID]
|
||||
f.mu.RUnlock()
|
||||
|
||||
if exists {
|
||||
return cachedClient, nil
|
||||
}
|
||||
|
||||
// 3. Создаем новый клиент под блокировкой (защита от гонки)
|
||||
// 2. Создаем новый клиент под блокировкой
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
// Double check
|
||||
if cachedClient, exists := f.clients[server.ID]; exists {
|
||||
return cachedClient, nil
|
||||
if client, exists := f.clients[userID]; exists {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Расшифровка пароля
|
||||
plainPass, err := f.cryptoManager.Decrypt(server.EncryptedPassword)
|
||||
// 3. Получаем креды из репозитория (учитывая фоллбэк на Owner'а)
|
||||
baseURL, login, encryptedPass, err := f.accountRepo.GetActiveConnectionCredentials(userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ошибка получения настроек подключения: %w", err)
|
||||
}
|
||||
|
||||
// 4. Расшифровка пароля
|
||||
plainPass, err := f.cryptoManager.Decrypt(encryptedPass)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ошибка расшифровки пароля RMS: %w", err)
|
||||
}
|
||||
|
||||
// Создание клиента
|
||||
newClient := NewClient(server.BaseURL, server.Login, plainPass)
|
||||
// 5. Создание клиента
|
||||
newClient := NewClient(baseURL, login, plainPass)
|
||||
f.clients[userID] = newClient
|
||||
|
||||
// Можно сразу проверить авторизацию (опционально, но полезно для fail-fast)
|
||||
// if err := newClient.Auth(); err != nil { ... }
|
||||
// Но лучше лениво, чтобы не тормозить старт.
|
||||
|
||||
f.clients[server.ID] = newClient
|
||||
|
||||
// Запускаем очистку старых клиентов из мапы? Пока нет, iiko токены живут не вечно,
|
||||
// но структура Client легкая. Можно добавить TTL позже.
|
||||
|
||||
logger.Log.Info("RMS Factory: Client created and cached",
|
||||
zap.String("server_name", server.Name),
|
||||
zap.String("user_id", userID.String()))
|
||||
logger.Log.Info("RMS Factory: Client created for user",
|
||||
zap.String("user_id", userID.String()),
|
||||
zap.String("login", login),
|
||||
zap.String("url", baseURL))
|
||||
|
||||
return newClient, nil
|
||||
}
|
||||
@@ -107,9 +80,17 @@ func (f *Factory) CreateClientFromRawCredentials(url, login, password string) *C
|
||||
return NewClient(url, login, password)
|
||||
}
|
||||
|
||||
// ClearCache сбрасывает кэш для сервера (например, при смене пароля)
|
||||
func (f *Factory) ClearCache(serverID uuid.UUID) {
|
||||
// ClearCacheForUser сбрасывает кэш пользователя (при смене сервера или выходе)
|
||||
func (f *Factory) ClearCacheForUser(userID uuid.UUID) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
delete(f.clients, serverID)
|
||||
delete(f.clients, userID)
|
||||
}
|
||||
|
||||
// ClearCacheForServer сбрасывает кэш для ВСЕХ пользователей сервера (например, при смене пароля владельцем)
|
||||
// Это дорогая операция, но необходимая при изменении общих кредов.
|
||||
func (f *Factory) ClearCacheForServer(serverID uuid.UUID) {
|
||||
// Пока не реализовано эффективно (нужен обратный индекс).
|
||||
// Для MVP можно просто очистить весь кэш или оставить как есть,
|
||||
// так как токены iiko все равно протухнут.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user