(no commit message provided)

This commit is contained in:
2025-03-26 22:45:10 +03:00
parent 8b11ae080e
commit 9056b4dbd9
5 changed files with 186 additions and 0 deletions
@@ -0,0 +1,29 @@
package ru.cathub.telegabot.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
// Указываем имя таблицы и схему из application.properties
@Table(name = "bot_settings", schema = "telegabot")
public class BotSetting {
@Id
@Column(name = "setting_key", nullable = false, unique = true)
private String settingKey; // Ключ настройки (например, "ENABLE_WELCOME_MESSAGE")
@Column(name = "setting_value", columnDefinition = "TEXT") // Используем TEXT для гибкости
private String settingValue; // Значение настройки
// Можно добавить поле для описания, если нужно
// @Column(name = "description")
// private String description;
}
@@ -0,0 +1,11 @@
package ru.cathub.telegabot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import ru.cathub.telegabot.model.BotSetting;
@Repository
public interface BotSettingRepository extends JpaRepository<BotSetting, String> {
// JpaRepository уже предоставляет findById (для получения по ключу), save (для сохранения/обновления), findAll и т.д.
// Дополнительные методы пока не требуются.
}
@@ -0,0 +1,49 @@
package ru.cathub.telegabot.service;
import ru.cathub.telegabot.exception.ServiceException;
import ru.cathub.telegabot.model.BotUser;
import java.util.Map;
import java.util.Optional;
public interface BotSettingService {
/**
* Получает значение настройки по ключу.
* @param key Ключ настройки.
* @return Optional со значением, если найдено, иначе Optional.empty().
*/
Optional<String> getSettingValue(String key);
/**
* Получает значение настройки по ключу или значение по умолчанию.
* @param key Ключ настройки.
* @param defaultValue Значение по умолчанию.
* @return Значение настройки или defaultValue.
*/
String getSettingValueOrDefault(String key, String defaultValue);
/**
* Устанавливает значение настройки. Требует прав администратора.
* @param key Ключ настройки.
* @param value Новое значение.
* @param requestingUser Пользователь, выполняющий операцию.
* @throws ServiceException если у пользователя нет прав администратора.
*/
void setSettingValue(String key, String value, BotUser requestingUser) throws ServiceException;
/**
* Получает все настройки в виде Map. Требует прав администратора.
* @param requestingUser Пользователь, выполняющий операцию.
* @return Map, где ключ - settingKey, значение - settingValue.
* @throws ServiceException если у пользователя нет прав администратора.
*/
Map<String, String> getAllSettings(BotUser requestingUser) throws ServiceException;
/**
* Проверяет, является ли пользователь администратором.
* @param user Пользователь для проверки.
* @return true, если пользователь администратор, иначе false.
*/
boolean isAdmin(BotUser user);
}
@@ -0,0 +1,81 @@
package ru.cathub.telegabot.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.cathub.telegabot.exception.ServiceException;
import ru.cathub.telegabot.model.BotSetting;
import ru.cathub.telegabot.model.BotUser;
import ru.cathub.telegabot.repository.BotSettingRepository;
import ru.cathub.telegabot.service.BotSettingService;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class BotSettingServiceImpl implements BotSettingService {
private final BotSettingRepository settingRepository;
@Override
@Transactional(readOnly = true) // Указываем, что метод только для чтения
public Optional<String> getSettingValue(String key) {
Optional<BotSetting> setting = settingRepository.findById(key);
log.trace("Getting setting '{}'. Found: {}", key, setting.isPresent()); // Используем trace для менее важных логов
return setting.map(BotSetting::getSettingValue);
}
@Override
@Transactional(readOnly = true) // Указываем, что метод только для чтения
public String getSettingValueOrDefault(String key, String defaultValue) {
String value = getSettingValue(key).orElse(defaultValue);
log.trace("Getting setting '{}' with default '{}'. Result: '{}'", key, defaultValue, value);
return value;
}
@Override
@Transactional
public void setSettingValue(String key, String value, BotUser requestingUser) throws ServiceException {
if (!isAdmin(requestingUser)) {
log.warn("User {} (ID: {}) attempted to set setting '{}' without admin rights.",
requestingUser.getChatId(), requestingUser.getId(), key); // Логируем попытку неавторизованного доступа
throw new ServiceException("У вас нет прав для изменения настроек бота.");
}
BotSetting setting = settingRepository.findById(key)
.orElse(new BotSetting(key, null)); // Создаем новую, если не найдена
String oldValue = setting.getSettingValue();
log.info("Admin User {} (ID: {}) is setting '{}' from '{}' to '{}'",
requestingUser.getChatId(), requestingUser.getId(), key, oldValue, value);
setting.setSettingValue(value);
settingRepository.save(setting);
}
@Override
@Transactional(readOnly = true) // Указываем, что метод только для чтения
public Map<String, String> getAllSettings(BotUser requestingUser) throws ServiceException {
if (!isAdmin(requestingUser)) {
log.warn("User {} (ID: {}) attempted to list all settings without admin rights.",
requestingUser.getChatId(), requestingUser.getId());
throw new ServiceException("У вас нет прав для просмотра настроек бота.");
}
log.debug("Admin User {} (ID: {}) requested all settings.", requestingUser.getChatId(), requestingUser.getId());
return settingRepository.findAll().stream()
.collect(Collectors.toMap(BotSetting::getSettingKey, setting -> Optional.ofNullable(setting.getSettingValue()).orElse(""))); // Собираем в Map, заменяя null на пустую строку
}
@Override
public boolean isAdmin(BotUser user) {
// Используем существующее поле UserType
boolean isAdmin = user != null && user.getUserType() == BotUser.UserType.ADMIN;
log.trace("Checking admin status for user ID {}: {}", user != null ? user.getId() : "null", isAdmin);
return isAdmin;
}
}
@@ -0,0 +1,16 @@
-- Создание таблицы для хранения глобальных настроек бота
CREATE TABLE telegabot.bot_settings (
setting_key VARCHAR(255) PRIMARY KEY NOT NULL, -- Ключ настройки (уникальный)
setting_value TEXT -- Значение настройки (может быть длинным)
-- description VARCHAR(1000) -- Опциональное описание настройки
);
-- Добавляем комментарии к таблице и столбцам (для PostgreSQL)
COMMENT ON TABLE telegabot.bot_settings IS 'Таблица для хранения глобальных настроек бота';
COMMENT ON COLUMN telegabot.bot_settings.setting_key IS 'Уникальный ключ настройки';
COMMENT ON COLUMN telegabot.bot_settings.setting_value IS 'Значение настройки';
-- Добавляем начальное значение для модели AI (рекомендуется)
INSERT INTO telegabot.bot_settings (setting_key, setting_value)
VALUES ('OPENROUTER_API_MODEL', 'google/gemini-2.5-pro-exp-03-25:free')
ON CONFLICT (setting_key) DO NOTHING; -- Не перезаписывать, если ключ уже существует