diff --git a/.env.example b/.env.example index f687753..ca95628 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ # cp .env.example .env # Couchbase configuration -COUCHBASE_CONNECTION_STRING=localhost:8091 +COUCHBASE_CONNECTION_STRING=couchbase://localhost COUCHBASE_USERNAME=admin COUCHBASE_PASSWORD=your_password_here COUCHBASE_BUCKET_NAME=store_scraper diff --git a/build.gradle.kts b/build.gradle.kts index 5ba9f7f..ca2127c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,7 +23,6 @@ configurations { dependencies { annotationProcessor("org.projectlombok:lombok:1.18.36") implementation("com.couchbase.client:java-client:3.4.11") - implementation("com.lmax:disruptor:4.0.0") implementation("org.apache.logging.log4j:log4j-1.2-api:2.24.3") implementation("org.apache.logging.log4j:log4j-core:2.24.3") implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3") diff --git a/src/main/java/com/miti99/storescraperbot/Main.java b/src/main/java/com/miti99/storescraperbot/Main.java index 882ac9b..48a2ed1 100644 --- a/src/main/java/com/miti99/storescraperbot/Main.java +++ b/src/main/java/com/miti99/storescraperbot/Main.java @@ -2,6 +2,7 @@ package com.miti99.storescraperbot; import com.miti99.storescraperbot.bot.StoreScrapeBot; import com.miti99.storescraperbot.config.Config; +import com.miti99.storescraperbot.repository.AdminRepository; import lombok.extern.log4j.Log4j2; import org.telegram.telegrambots.longpolling.TelegramBotsLongPollingApplication; @@ -9,6 +10,8 @@ import org.telegram.telegrambots.longpolling.TelegramBotsLongPollingApplication; public class Main { public static void main(String[] args) { + AdminRepository.INSTANCE.init(); + try (var botsApplication = new TelegramBotsLongPollingApplication()) { botsApplication.registerBot(Config.TELEGRAM_BOT_TOKEN, StoreScrapeBot.INSTANCE); log.info("StoreScrapeBot successfully started!"); diff --git a/src/main/java/com/miti99/storescraperbot/bot/ScoreScrapeBotTelegramClient.java b/src/main/java/com/miti99/storescraperbot/bot/ScoreScrapeBotTelegramClient.java deleted file mode 100644 index 2e8373c..0000000 --- a/src/main/java/com/miti99/storescraperbot/bot/ScoreScrapeBotTelegramClient.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.miti99.storescraperbot.bot; - -import com.miti99.storescraperbot.config.Config; -import org.telegram.telegrambots.client.okhttp.OkHttpTelegramClient; - -public class ScoreScrapeBotTelegramClient extends OkHttpTelegramClient { - public static final ScoreScrapeBotTelegramClient INSTANCE = new ScoreScrapeBotTelegramClient(); - - public ScoreScrapeBotTelegramClient() { - super(Config.TELEGRAM_BOT_TOKEN); - } -} diff --git a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java index dbf035a..df9d0f2 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java +++ b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java @@ -3,8 +3,10 @@ package com.miti99.storescraperbot.bot; import com.miti99.storescraperbot.bot.command.AddGroupCommand; import lombok.extern.log4j.Log4j2; import org.telegram.telegrambots.extensions.bots.commandbot.CommandLongPollingTelegramBot; +import org.telegram.telegrambots.meta.api.methods.commands.SetMyCommands; import org.telegram.telegrambots.meta.api.methods.send.SendMessage; import org.telegram.telegrambots.meta.api.objects.Update; +import org.telegram.telegrambots.meta.api.objects.commands.BotCommand; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; @Log4j2 @@ -12,8 +14,22 @@ public class StoreScrapeBot extends CommandLongPollingTelegramBot { public static final StoreScrapeBot INSTANCE = new StoreScrapeBot(); StoreScrapeBot() { - super(ScoreScrapeBotTelegramClient.INSTANCE, true, ScoreScrapeBotUsernameSupplier.INSTANCE); + super(StoreScrapeBotTelegramClient.INSTANCE, true, StoreScrapeBotUsernameSupplier.INSTANCE); register(AddGroupCommand.INSTANCE); + setMyCommands(); + } + + private void setMyCommands() { + try { + var commands = + getRegisteredCommands().stream() + .map(cmd -> new BotCommand(cmd.getCommandIdentifier(), cmd.getDescription())) + .toList(); + var setMyCommands = SetMyCommands.builder().commands(commands).build(); + StoreScrapeBotTelegramClient.INSTANCE.execute(setMyCommands); + } catch (TelegramApiException e) { + log.error("register error", e); + } } @Override diff --git a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBotTelegramClient.java b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBotTelegramClient.java new file mode 100644 index 0000000..51718fe --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBotTelegramClient.java @@ -0,0 +1,41 @@ +package com.miti99.storescraperbot.bot; + +import com.miti99.storescraperbot.config.Config; +import lombok.extern.log4j.Log4j2; +import org.telegram.telegrambots.client.okhttp.OkHttpTelegramClient; +import org.telegram.telegrambots.meta.api.methods.ParseMode; +import org.telegram.telegrambots.meta.api.methods.send.SendMessage; + +@Log4j2 +public class StoreScrapeBotTelegramClient extends OkHttpTelegramClient { + public static final StoreScrapeBotTelegramClient INSTANCE = new StoreScrapeBotTelegramClient(); + + public StoreScrapeBotTelegramClient() { + super(Config.TELEGRAM_BOT_TOKEN); + } + + public void sendMessage(long chatId, String text) { + try { + var sendMessage = + SendMessage.builder().parseMode(ParseMode.HTML).chatId(chatId).text(text).build(); + execute(sendMessage); + } catch (Exception e) { + log.error("sendMessage error", e); + } + } + + public void sendMessage(long chatId, int threadId, String text) { + try { + var sendMessage = + SendMessage.builder() + .parseMode(ParseMode.HTML) + .chatId(chatId) + .messageThreadId(threadId) + .text(text) + .build(); + execute(sendMessage); + } catch (Exception e) { + log.error("sendMessage error", e); + } + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/ScoreScrapeBotUsernameSupplier.java b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBotUsernameSupplier.java similarity index 56% rename from src/main/java/com/miti99/storescraperbot/bot/ScoreScrapeBotUsernameSupplier.java rename to src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBotUsernameSupplier.java index 9f5eac6..30575ae 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/ScoreScrapeBotUsernameSupplier.java +++ b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBotUsernameSupplier.java @@ -3,9 +3,9 @@ package com.miti99.storescraperbot.bot; import com.miti99.storescraperbot.config.Config; import java.util.function.Supplier; -public class ScoreScrapeBotUsernameSupplier implements Supplier { - public static final ScoreScrapeBotUsernameSupplier INSTANCE = - new ScoreScrapeBotUsernameSupplier(); +public class StoreScrapeBotUsernameSupplier implements Supplier { + public static final StoreScrapeBotUsernameSupplier INSTANCE = + new StoreScrapeBotUsernameSupplier(); @Override public String get() { diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/AddGroupCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/AddGroupCommand.java index 05a6254..72294bf 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/AddGroupCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/AddGroupCommand.java @@ -1,23 +1,48 @@ package com.miti99.storescraperbot.bot.command; +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; import com.miti99.storescraperbot.config.Config; -import org.telegram.telegrambots.extensions.bots.commandbot.commands.BotCommand; +import com.miti99.storescraperbot.repository.AdminRepository; import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.api.objects.chat.Chat; import org.telegram.telegrambots.meta.generics.TelegramClient; -public class AddGroupCommand extends BotCommand { +public class AddGroupCommand extends BaseStoreScraperBotCommand { public static final AddGroupCommand INSTANCE = new AddGroupCommand(); AddGroupCommand() { - super("addgroup", "Thêm group vào list group cho phép sử dụng bot"); + super("addgroup", ". Thêm group vào list group cho phép sử dụng bot"); } @Override - public void execute(TelegramClient telegramClient, User user, Chat chat, String[] arguments) { - if (!Config.ADMIN_IDS.contains(user.getId()) ) { + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + if (!Config.ADMIN_IDS.contains(user.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "You are not admin"); return; } - // TODO + + if (arguments.length != 1) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + long groupId; + try { + groupId = Long.parseLong(arguments[0]); + } catch (NumberFormatException e) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid groupId"); + return; + } + + var admin = AdminRepository.INSTANCE.load(); + if (admin.getGroups().contains(groupId)) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Group is already added"); + return; + } + + admin.getGroups().add(groupId); + AdminRepository.INSTANCE.save(admin); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Group added successfully"); } } diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/BaseStoreScraperBotCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/BaseStoreScraperBotCommand.java new file mode 100644 index 0000000..8edfa27 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/BaseStoreScraperBotCommand.java @@ -0,0 +1,29 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import lombok.extern.log4j.Log4j2; +import org.telegram.telegrambots.extensions.bots.commandbot.commands.BotCommand; +import org.telegram.telegrambots.meta.api.objects.User; +import org.telegram.telegrambots.meta.api.objects.chat.Chat; +import org.telegram.telegrambots.meta.generics.TelegramClient; + +@Log4j2 +public abstract class BaseStoreScraperBotCommand extends BotCommand { + + public BaseStoreScraperBotCommand(String commandIdentifier, String description) { + super(commandIdentifier, description); + } + + @Override + public void execute(TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + try { + executeCommand(telegramClient, user, chat, arguments); + } catch (Exception e) { + log.error("execute error", e); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Internal server error"); + } + } + + protected abstract void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments); +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/GetGroupCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/GetGroupCommand.java new file mode 100644 index 0000000..38b8191 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/GetGroupCommand.java @@ -0,0 +1,40 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.config.Config; +import com.miti99.storescraperbot.repository.AdminRepository; +import org.telegram.telegrambots.meta.api.objects.User; +import org.telegram.telegrambots.meta.api.objects.chat.Chat; +import org.telegram.telegrambots.meta.generics.TelegramClient; + +public class GetGroupCommand extends BaseStoreScraperBotCommand { + public static final GetGroupCommand INSTANCE = new GetGroupCommand(); + + GetGroupCommand() { + super("getgroup", "Lấy danh sách group được phép sử dụng bot hiện tại"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + if (!Config.ADMIN_IDS.contains(user.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "You are not admin"); + return; + } + + if (arguments.length != 0) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + + var admin = AdminRepository.INSTANCE.load(); + var groups = admin.getGroups(); + var sb = new StringBuilder(); + sb.append("Groups:/n"); + for (var groupId : groups) { + sb.append("- ").append(groupId).append("\n"); + } + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString()); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java index e089d5f..44b3586 100644 --- a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java +++ b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java @@ -2,13 +2,10 @@ package com.miti99.storescraperbot.model; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; -import lombok.Setter; @Getter public abstract class AbstractModel { @JsonProperty("class") protected String clazz = getClass().getSimpleName(); - - @Setter protected K key; } diff --git a/src/main/java/com/miti99/storescraperbot/model/Admin.java b/src/main/java/com/miti99/storescraperbot/model/Admin.java index c1ea3b4..fec1850 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Admin.java +++ b/src/main/java/com/miti99/storescraperbot/model/Admin.java @@ -1,5 +1,6 @@ package com.miti99.storescraperbot.model; +import java.util.ArrayList; import java.util.List; import lombok.Data; import lombok.Getter; @@ -8,5 +9,5 @@ import lombok.Setter; @Getter @Setter public class Admin extends AbstractModel { - List groups; + List groups = new ArrayList<>(); } diff --git a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java index 17f7fcc..adffca0 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java @@ -19,6 +19,7 @@ public abstract class AbstractRepository> { protected AbstractRepository(String collectionName) { this.collectionName = collectionName.toLowerCase(); + CouchbaseUtil.createCollection(scopeName, collectionName); } public Collection collection() { diff --git a/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java index a4dc038..03f447f 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AdminRepository.java @@ -6,7 +6,7 @@ import com.miti99.storescraperbot.model.Admin; * Đây là repository chỉ chứa 1 key duy nhất, key là "" (rỗng) */ public class AdminRepository extends AbstractRepository { - private static final AdminRepository INSTANCE = new AdminRepository(); + public static final AdminRepository INSTANCE = new AdminRepository(); protected AdminRepository() { super("admin"); diff --git a/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java b/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java index bc1f4f7..20487f6 100644 --- a/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java +++ b/src/main/java/com/miti99/storescraperbot/util/CouchbaseUtil.java @@ -8,8 +8,12 @@ import static com.miti99.storescraperbot.config.Config.COUCHBASE_USERNAME; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.ClusterOptions; +import com.couchbase.client.java.manager.collection.CollectionSpec; +import com.miti99.storescraperbot.config.Config; import java.time.Duration; +import lombok.extern.log4j.Log4j2; +@Log4j2 public class CouchbaseUtil { public static final Cluster CLUSTER; public static final Bucket BUCKET; @@ -24,4 +28,54 @@ public class CouchbaseUtil { BUCKET = CLUSTER.bucket(COUCHBASE_BUCKET_NAME); BUCKET.waitUntilReady(Duration.ofSeconds(10)); } + + public static void createScope(String scopeName) { + var collectionManager = BUCKET.collections(); + try { + boolean scopeExists = + collectionManager.getAllScopes().stream().anyMatch(s -> s.name().equals(scopeName)); + + if (!scopeExists) { + collectionManager.createScope(scopeName); + log.info("Scope created: {}", scopeName); + } else { + log.info("Scope existed: {}", scopeName); + } + } catch (Exception e) { + log.error("createScope error - scopeName: '{}'", scopeName, e); + } + } + + public static void createCollection(String scopeName, String collectionName) { + var collectionManager = BUCKET.collections(); + try { + var scopeSpecOpt = + collectionManager.getAllScopes().stream() + .filter(s -> s.name().equals(scopeName)) + .findFirst(); + if (scopeSpecOpt.isEmpty()) { + createScope(scopeName); + createCollection(scopeName, collectionName); + return; + } + + var scopeSpec = scopeSpecOpt.get(); + boolean collectionExists = + scopeSpec.collections().stream().anyMatch(c -> c.name().equals(collectionName)); + + if (!collectionExists) { + var spec = CollectionSpec.create(collectionName, scopeName); + collectionManager.createCollection(spec); + log.info("Collection created: {} in {}", collectionName, scopeName); + } else { + log.info("Collection existed: {} in {}", collectionName, scopeName); + } + } catch (Exception e) { + log.error( + "createCollection error - collectionName: '{}', scopeName: '{}'", + collectionName, + scopeName, + e); + } + } } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index b10433f..c52c9ad 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -14,8 +14,8 @@ - + - +