feat: configurable level roles via !levelrole admin command
- LevelRoleCommand: set/remove/clear role mappings per level - LevelRoleService: reads from ConfigRepository, falls back to defaults - LevelCommandRegistrar: wires new command
This commit is contained in:
parent
283b30f979
commit
0787e98921
6 changed files with 237 additions and 10 deletions
10
TODO.md
10
TODO.md
|
|
@ -135,7 +135,7 @@
|
|||
|
||||
## 🚀 Новые фичи (Roadmap)
|
||||
|
||||
## 🚀 Экономика — план реализации (в работе)
|
||||
## 🚀 Экономика — ✅ реализовано
|
||||
|
||||
### Модель данных
|
||||
|
||||
|
|
@ -234,15 +234,15 @@ feature/economy/
|
|||
|
||||
### Приоритет 1
|
||||
- [ ] Система достижений (Achievements)
|
||||
- [x] Система экономики (Economy) — **в работе**
|
||||
- [x] Система экономики (Economy) — **✅**
|
||||
|
||||
### Приоритет 2
|
||||
- [x] Авто-модерация (3 варна = авто-мут на 1ч)
|
||||
- [x] Музыка (lavaplayer: play, skip, stop, queue, np, volume, leave)
|
||||
- [x] ~~Музыка — поиск с выбором (yt/sc/list + выбор номера)~~
|
||||
- [x] Server Stats (участники, каналы, роли, бусты)
|
||||
- [ ] Level Roles (роли за уровни)
|
||||
- [ ] Красивые level-up embed с прогресс-баром
|
||||
- [x] Level Roles (роли за уровни)
|
||||
- [x] Красивые level-up embed с прогресс-баром
|
||||
|
||||
### Приоритет 3
|
||||
- [ ] Статистика сервера — графики, CSV export
|
||||
|
|
@ -251,4 +251,4 @@ feature/economy/
|
|||
|
||||
---
|
||||
|
||||
**Версия:** 2.2 | **Последнее обновление:** 2026-06-20 | **Java 21 ✅, God Constructor ✅, Critical баги ✅, Economy 🚧**
|
||||
**Версия:** 2.2 | **Последнее обновление:** 2026-06-20 | **Java 21 ✅, God Constructor ✅, Critical баги ✅, Economy ✅, Level Roles ✅**
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Репозиторий для работы с конфигурацией
|
||||
|
|
@ -54,6 +56,19 @@ public class ConfigRepository implements StringConfigStore {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getAll() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
try (PreparedStatement stmt = database.prepare("SELECT key, value FROM config")) {
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
result.put(rs.getString("key"), rs.getString("value"));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Ошибка получения всех конфигураций", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удалить значение конфигурации
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package creator.loki.feature.level;
|
|||
import com.google.inject.Inject;
|
||||
import creator.loki.core.registry.CommandRegistrar;
|
||||
import creator.loki.core.registry.CommandRegistry;
|
||||
import creator.loki.feature.config.repository.ConfigRepository;
|
||||
import creator.loki.feature.leaderboard.LeaderboardCommand;
|
||||
import creator.loki.feature.level.commands.LevelRoleCommand;
|
||||
import creator.loki.feature.level.service.LeaderboardService;
|
||||
import creator.loki.feature.level.service.LevelService;
|
||||
import creator.loki.feature.profile.ProfileCommand;
|
||||
|
|
@ -13,16 +15,22 @@ public class LevelCommandRegistrar implements CommandRegistrar {
|
|||
private final LeaderboardService leaderboardService;
|
||||
private final ResetLevelsCommand resetLevelsCommand;
|
||||
private final ProfileService profileService;
|
||||
private final LevelRoleService levelRoleService;
|
||||
private final ConfigRepository configRepository;
|
||||
|
||||
@Inject
|
||||
public LevelCommandRegistrar(
|
||||
LeaderboardService leaderboardService,
|
||||
ResetLevelsCommand resetLevelsCommand,
|
||||
ProfileService profileService
|
||||
ProfileService profileService,
|
||||
LevelRoleService levelRoleService,
|
||||
ConfigRepository configRepository
|
||||
) {
|
||||
this.leaderboardService = leaderboardService;
|
||||
this.resetLevelsCommand = resetLevelsCommand;
|
||||
this.profileService = profileService;
|
||||
this.levelRoleService = levelRoleService;
|
||||
this.configRepository = configRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -31,5 +39,6 @@ public class LevelCommandRegistrar implements CommandRegistrar {
|
|||
registry.register(new StatsCommand());
|
||||
registry.register(resetLevelsCommand);
|
||||
registry.register(new ProfileCommand(profileService));
|
||||
registry.register(new LevelRoleCommand(levelRoleService, configRepository));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ public class LevelModule extends AbstractModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
LevelRoleService provideLevelRoleService() {
|
||||
return new LevelRoleService();
|
||||
LevelRoleService provideLevelRoleService(ConfigRepository configRepository) {
|
||||
return new LevelRoleService(configRepository);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package creator.loki.feature.level;
|
||||
|
||||
import creator.loki.feature.config.repository.ConfigRepository;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -10,7 +11,7 @@ import java.util.Map;
|
|||
|
||||
public class LevelRoleService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LevelRoleService.class);
|
||||
private static final Map<Integer, String> REWARD_ROLES = Map.of(
|
||||
private static final Map<Integer, String> DEFAULT_ROLES = Map.of(
|
||||
5, "Активный",
|
||||
10, "Постоянный",
|
||||
20, "Ветеран",
|
||||
|
|
@ -18,8 +19,28 @@ public class LevelRoleService {
|
|||
50, "Мастер"
|
||||
);
|
||||
|
||||
private final ConfigRepository configRepository;
|
||||
|
||||
public LevelRoleService(ConfigRepository configRepository) {
|
||||
this.configRepository = configRepository;
|
||||
}
|
||||
|
||||
public String getRoleForLevel(int level) {
|
||||
String configRole = configRepository.get("level_role_" + level);
|
||||
if (configRole != null) return configRole;
|
||||
return DEFAULT_ROLES.get(level);
|
||||
}
|
||||
|
||||
public void setRoleForLevel(int level, String roleName) {
|
||||
configRepository.set("level_role_" + level, roleName);
|
||||
}
|
||||
|
||||
public void removeRoleForLevel(int level) {
|
||||
configRepository.delete("level_role_" + level);
|
||||
}
|
||||
|
||||
public String assignRewardRole(Member member, int newLevel) {
|
||||
String roleName = REWARD_ROLES.get(newLevel);
|
||||
String roleName = getRoleForLevel(newLevel);
|
||||
if (roleName == null) return null;
|
||||
|
||||
List<Role> roles = member.getGuild().getRolesByName(roleName, true);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,182 @@
|
|||
package creator.loki.feature.level.commands;
|
||||
|
||||
import creator.loki.command.Command;
|
||||
import creator.loki.command.CommandContext;
|
||||
import creator.loki.embed.EmbedTemplates;
|
||||
import creator.loki.feature.config.repository.ConfigRepository;
|
||||
import creator.loki.feature.level.LevelRoleService;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class LevelRoleCommand implements Command {
|
||||
private final LevelRoleService levelRoleService;
|
||||
private final ConfigRepository configRepository;
|
||||
|
||||
public LevelRoleCommand(LevelRoleService levelRoleService, ConfigRepository configRepository) {
|
||||
this.levelRoleService = levelRoleService;
|
||||
this.configRepository = configRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "levelrole";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Управление ролями за уровни";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "levelrole [set <level> <role-name>|remove <level>|clear]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Настройка";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandContext context) {
|
||||
if (context.getAuthor() == null || !context.getAuthor().hasPermission(Permission.ADMINISTRATOR)) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Недостаточно прав", "Эта команда доступна только администраторам.")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> args = context.getArgs();
|
||||
if (args.isEmpty()) {
|
||||
showMappings(context);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "set" -> handleSet(context, args);
|
||||
case "remove" -> handleRemove(context, args);
|
||||
case "clear" -> handleClear(context);
|
||||
default -> showMappings(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void showMappings(CommandContext context) {
|
||||
Map<String, String> allConfig = configRepository.getAll();
|
||||
Map<Integer, String> customRoles = allConfig.entrySet().stream()
|
||||
.filter(e -> e.getKey().startsWith("level_role_"))
|
||||
.collect(Collectors.toMap(
|
||||
e -> Integer.parseInt(e.getKey().substring("level_role_".length())),
|
||||
Map.Entry::getValue
|
||||
));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("**Текущие настройки ролей за уровни:**\n\n");
|
||||
|
||||
for (int level : new int[]{5, 10, 20, 30, 50}) {
|
||||
String custom = customRoles.get(level);
|
||||
String effective = levelRoleService.getRoleForLevel(level);
|
||||
sb.append("**Уровень ").append(level).append(":** ");
|
||||
if (custom != null) {
|
||||
sb.append("`").append(effective).append("`");
|
||||
} else {
|
||||
sb.append(effective).append(" *(по умолчанию)*");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, String> entry : customRoles.entrySet()) {
|
||||
int level = entry.getKey();
|
||||
if (level != 5 && level != 10 && level != 20 && level != 30 && level != 50) {
|
||||
sb.append("**Уровень ").append(level).append(":** `").append(entry.getValue()).append("`\n");
|
||||
}
|
||||
}
|
||||
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.info("Управление ролями", sb.toString())
|
||||
).queue();
|
||||
}
|
||||
|
||||
private void handleSet(CommandContext context, List<String> args) {
|
||||
if (args.size() < 3) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Ошибка", "Использование: `!levelrole set <уровень> <название роли>`")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
int level;
|
||||
try {
|
||||
level = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException e) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Ошибка", "Уровень должен быть числом.")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (level < 1) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Ошибка", "Уровень должен быть положительным числом.")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
String roleName = String.join(" ", args.subList(2, args.size()));
|
||||
if (roleName.isEmpty()) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Ошибка", "Название роли не может быть пустым.")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
levelRoleService.setRoleForLevel(level, roleName);
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.success("Роль назначена",
|
||||
"Роль `" + roleName + "` будет выдаваться за уровень **" + level + "**.")
|
||||
).queue();
|
||||
}
|
||||
|
||||
private void handleRemove(CommandContext context, List<String> args) {
|
||||
if (args.size() < 2) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Ошибка", "Использование: `!levelrole remove <уровень>`")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
int level;
|
||||
try {
|
||||
level = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException e) {
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.error("Ошибка", "Уровень должен быть числом.")
|
||||
).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
levelRoleService.removeRoleForLevel(level);
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.success("Роль сброшена",
|
||||
"Для уровня **" + level + "** будет использоваться роль по умолчанию.")
|
||||
).queue();
|
||||
}
|
||||
|
||||
private void handleClear(CommandContext context) {
|
||||
Map<String, String> allConfig = configRepository.getAll();
|
||||
int removed = 0;
|
||||
for (String key : allConfig.keySet()) {
|
||||
if (key.startsWith("level_role_")) {
|
||||
configRepository.delete(key);
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
|
||||
context.getChannel().sendMessageEmbeds(
|
||||
EmbedTemplates.success("Настройки сброшены",
|
||||
"Удалено пользовательских ролей: **" + removed + "**. Будут использоваться роли по умолчанию.")
|
||||
).queue();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue