diff --git a/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java b/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java index 1e7370b..a518cf1 100644 --- a/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java +++ b/src/main/java/com/miti99/storescraperbot/api/apple/AppStoreScraper.java @@ -2,6 +2,7 @@ package com.miti99.storescraperbot.api.apple; import com.miti99.storescraperbot.api.apple.request.AppleAppRequest; import com.miti99.storescraperbot.api.apple.response.AppleAppResponse; +import com.miti99.storescraperbot.repository.AppleAppRepository; import com.miti99.storescraperbot.util.GsonUtil; import java.net.URI; import java.net.http.HttpClient; @@ -9,8 +10,16 @@ import java.net.http.HttpClient.Redirect; import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse.BodyHandlers; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +@Log4j2 +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class AppStoreScraper { public static final String BASE_URL = "https://miti-app-store-scraper.vercel.app/"; @@ -24,13 +33,34 @@ public class AppStoreScraper { .POST(BodyPublishers.ofString(GsonUtil.toJson(request))) .build(); - var body = + try (var httpClient = HttpClient.newBuilder() .followRedirects(Redirect.NORMAL) // .connectTimeout(Duration.ofMillis(TIMEOUT)) - .build() - .send(httpRequest, BodyHandlers.ofString()) - .body(); - return GsonUtil.fromJson(body, AppleAppResponse.class); + .build()) { + var body = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); + return GsonUtil.fromJson(body, AppleAppResponse.class); + } + } + + public static LocalDate getLastUpdateOfApp(String appId) { + boolean isInCache = AppleAppRepository.INSTANCE.exist(appId); + AppleAppResponse response = null; + if (isInCache) { + var app = AppleAppRepository.INSTANCE.load(appId); + response = app.getApp(); + } else { + response = app(new AppleAppRequest(appId)); + AppleAppRepository.INSTANCE.init(appId); + var app = AppleAppRepository.INSTANCE.load(appId); + app.setApp(response); + AppleAppRepository.INSTANCE.save(appId, app); + } + if (response != null) { + return LocalDate.ofInstant(Instant.parse(response.updated()), ZoneId.systemDefault()); + } else { + log.error("response is null"); + return LocalDate.ofInstant(Instant.ofEpochMilli(0), ZoneId.systemDefault()); + } } } diff --git a/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java b/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java index 02b3c09..159d466 100644 --- a/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java +++ b/src/main/java/com/miti99/storescraperbot/api/google/GooglePlayScraper.java @@ -2,6 +2,7 @@ package com.miti99.storescraperbot.api.google; import com.miti99.storescraperbot.api.google.request.GoogleAppRequest; import com.miti99.storescraperbot.api.google.response.GoogleAppResponse; +import com.miti99.storescraperbot.repository.GoogleAppRepository; import com.miti99.storescraperbot.util.GsonUtil; import java.net.URI; import java.net.http.HttpClient; @@ -9,8 +10,16 @@ import java.net.http.HttpClient.Redirect; import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse.BodyHandlers; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +@Log4j2 +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class GooglePlayScraper { public static final String BASE_URL = "https://miti-google-play-scraper.vercel.app/"; @@ -24,13 +33,35 @@ public class GooglePlayScraper { .POST(BodyPublishers.ofString(GsonUtil.toJson(request))) .build(); - var body = + try (var httpClient = HttpClient.newBuilder() // .connectTimeout(Duration.ofMillis(TIMEOUT)) .followRedirects(Redirect.NORMAL) - .build() - .send(httpRequest, BodyHandlers.ofString()) - .body(); - return GsonUtil.fromJson(body, GoogleAppResponse.class); + .build()) { + var body = httpClient.send(httpRequest, BodyHandlers.ofString()).body(); + return GsonUtil.fromJson(body, GoogleAppResponse.class); + } + } + + public static LocalDate getLastUpdateOfApp(String appId) { + boolean isInCache = GoogleAppRepository.INSTANCE.exist(appId); + GoogleAppResponse response = null; + if (isInCache) { + var app = GoogleAppRepository.INSTANCE.load(appId); + response = app.getApp(); + } else { + response = app(new GoogleAppRequest(appId)); + GoogleAppRepository.INSTANCE.init(appId); + var app = GoogleAppRepository.INSTANCE.load(appId); + app.setApp(response); + GoogleAppRepository.INSTANCE.save(appId, app); + } + long lastUpdateMillis = 0; + if (response != null) { + lastUpdateMillis = response.updated(); + } else { + log.error("response is null"); + } + return LocalDate.ofInstant(Instant.ofEpochMilli(lastUpdateMillis), ZoneId.systemDefault()); } } diff --git a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java index df9d0f2..daf3dc6 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java +++ b/src/main/java/com/miti99/storescraperbot/bot/StoreScrapeBot.java @@ -1,6 +1,14 @@ package com.miti99.storescraperbot.bot; +import com.miti99.storescraperbot.bot.command.AddAppleAppCommand; +import com.miti99.storescraperbot.bot.command.AddGoogleAppCommand; import com.miti99.storescraperbot.bot.command.AddGroupCommand; +import com.miti99.storescraperbot.bot.command.CheckAppCommand; +import com.miti99.storescraperbot.bot.command.DeleteAppleAppCommand; +import com.miti99.storescraperbot.bot.command.DeleteGroupCommand; +import com.miti99.storescraperbot.bot.command.InfoCommand; +import com.miti99.storescraperbot.bot.command.ListAppCommand; +import com.miti99.storescraperbot.bot.command.ListGroupCommand; import lombok.extern.log4j.Log4j2; import org.telegram.telegrambots.extensions.bots.commandbot.CommandLongPollingTelegramBot; import org.telegram.telegrambots.meta.api.methods.commands.SetMyCommands; @@ -15,7 +23,18 @@ public class StoreScrapeBot extends CommandLongPollingTelegramBot { StoreScrapeBot() { super(StoreScrapeBotTelegramClient.INSTANCE, true, StoreScrapeBotUsernameSupplier.INSTANCE); + register(InfoCommand.INSTANCE); + register(AddGroupCommand.INSTANCE); + register(DeleteGroupCommand.INSTANCE); + register(ListGroupCommand.INSTANCE); + + register(AddAppleAppCommand.INSTANCE); + register(DeleteAppleAppCommand.INSTANCE); + register(AddGoogleAppCommand.INSTANCE); + register(DeleteAppleAppCommand.INSTANCE); + register(ListAppCommand.INSTANCE); + register(CheckAppCommand.INSTANCE); setMyCommands(); } diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java new file mode 100644 index 0000000..631e3df --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/AddAppleAppCommand.java @@ -0,0 +1,45 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +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 AddAppleAppCommand extends BaseStoreScraperBotCommand { + public static final AddAppleAppCommand INSTANCE = new AddAppleAppCommand(); + + AddAppleAppCommand() { + super("addapple", ". Thêm Apple app vào danh sách theo dõi của nhóm"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(chat.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Group is not allowed to use bot"); + return; + } + + if (arguments.length != 1) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + var appId = arguments[0]; + long groupId = chat.getId(); + var group = GroupRepository.INSTANCE.load(groupId); + + if (group.getAppleApps().contains(appId)) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app is already added"); + return; + } + + group.getAppleApps().add(appId); + GroupRepository.INSTANCE.save(groupId, group); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app added successfully"); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java new file mode 100644 index 0000000..ed85769 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/AddGoogleAppCommand.java @@ -0,0 +1,47 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +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 AddGoogleAppCommand extends BaseStoreScraperBotCommand { + public static final AddGoogleAppCommand INSTANCE = new AddGoogleAppCommand(); + + AddGoogleAppCommand() { + super("addgoogle", ". Thêm Google app vào danh sách theo dõi của nhóm"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(chat.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Group is not allowed to use bot"); + return; + } + + if (arguments.length != 1) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + var appId = arguments[0]; + long groupId = chat.getId(); + var group = GroupRepository.INSTANCE.load(groupId); + + if (group.getGoogleApps().contains(appId)) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Google app is already added"); + return; + } + + group.getGoogleApps().add(appId); + GroupRepository.INSTANCE.save(groupId, group); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Google app added successfully"); + } +} 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 72294bf..1df5f84 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/AddGroupCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/AddGroupCommand.java @@ -3,6 +3,7 @@ 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 com.miti99.storescraperbot.repository.GroupRepository; import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.api.objects.chat.Chat; import org.telegram.telegrambots.meta.generics.TelegramClient; @@ -22,17 +23,21 @@ public class AddGroupCommand extends BaseStoreScraperBotCommand { return; } - if (arguments.length != 1) { + 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; + if (arguments.length == 1) { + try { + groupId = Long.parseLong(arguments[0]); + } catch (NumberFormatException e) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid groupId"); + return; + } + } else { + groupId = chat.getId(); } var admin = AdminRepository.INSTANCE.load(); @@ -41,6 +46,7 @@ public class AddGroupCommand extends BaseStoreScraperBotCommand { return; } + GroupRepository.INSTANCE.init(groupId); 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/CheckAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppCommand.java new file mode 100644 index 0000000..316a875 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/CheckAppCommand.java @@ -0,0 +1,74 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.api.apple.AppStoreScraper; +import com.miti99.storescraperbot.api.google.GooglePlayScraper; +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.constant.Constant; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +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 CheckAppCommand extends BaseStoreScraperBotCommand { + public static final CheckAppCommand INSTANCE = new CheckAppCommand(); + + CheckAppCommand() { + super("checkapp", "Kiểm tra cập nhật các app"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(chat.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Group is not allowed to use bot"); + return; + } + + if (arguments.length != 0) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + long groupId = chat.getId(); + var group = GroupRepository.INSTANCE.load(groupId); + var now = LocalDate.now(); + + var sb = new StringBuilder(); + sb.append("Apple Apps:\n"); + sb.append("\n"); + sb.append("%-20s | %-10s | %-4s | %-2s\n".formatted("AppId", "Updated", "Days", "OK")); + sb.append("-".repeat(46)); + sb.append("\n"); + for (var appId : group.getAppleApps()) { + var updated = AppStoreScraper.getLastUpdateOfApp(appId); + long days = ChronoUnit.DAYS.between(updated, now); + boolean passed = days <= Constant.NUM_DAYS_WARNING_NOT_UPDATED; + sb.append( + "%-20s | %-10s | %-4s | %-2s\n".formatted(appId, updated, days, passed ? "✅" : "❌")); + } + sb.append("\n"); + sb.append("\n"); + sb.append("Google Apps:\n"); + sb.append("\n"); + sb.append("%-20s | %-10s | %-4s | %-2s\n".formatted("AppId", "Updated", "Date", "OK")); + sb.append("-".repeat(46)); + sb.append("\n"); + for (var appId : group.getGoogleApps()) { + var updated = GooglePlayScraper.getLastUpdateOfApp(appId); + long days = ChronoUnit.DAYS.between(updated, now); + boolean passed = days <= Constant.NUM_DAYS_WARNING_NOT_UPDATED; + sb.append( + "%-20s | %-10s | %-4s | %-2s\n".formatted(appId, updated, days, passed ? "✅" : "❌")); + } + sb.append(""); + sb.append("\n"); + + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString()); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java new file mode 100644 index 0000000..711d14e --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteAppleAppCommand.java @@ -0,0 +1,45 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +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 DeleteAppleAppCommand extends BaseStoreScraperBotCommand { + public static final DeleteAppleAppCommand INSTANCE = new DeleteAppleAppCommand(); + + DeleteAppleAppCommand() { + super("delapple", ". Xoá Apple app khỏi danh sách theo dõi của nhóm"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(chat.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Group is not allowed to use bot"); + return; + } + + if (arguments.length != 1) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + var appId = arguments[0]; + long groupId = chat.getId(); + var group = GroupRepository.INSTANCE.load(groupId); + + if (!group.getAppleApps().contains(appId)) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app is not added"); + return; + } + + group.getAppleApps().remove(appId); + GroupRepository.INSTANCE.save(groupId, group); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Apple app deleted successfully"); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java new file mode 100644 index 0000000..0869a7f --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGoogleAppCommand.java @@ -0,0 +1,46 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +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 DeleteGoogleAppCommand extends BaseStoreScraperBotCommand { + public static final DeleteGoogleAppCommand INSTANCE = new DeleteGoogleAppCommand(); + + DeleteGoogleAppCommand() { + super("delgoogle", ". Xoá Google app khỏi danh sách theo dõi của nhóm"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(chat.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Group is not allowed to use bot"); + return; + } + + if (arguments.length != 1) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + var appId = arguments[0]; + long groupId = chat.getId(); + var group = GroupRepository.INSTANCE.load(groupId); + + if (!group.getGoogleApps().contains(appId)) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Google app is not added"); + return; + } + + group.getGoogleApps().remove(appId); + GroupRepository.INSTANCE.save(groupId, group); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Google app deleted successfully"); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGroupCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGroupCommand.java new file mode 100644 index 0000000..8d986b0 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/DeleteGroupCommand.java @@ -0,0 +1,52 @@ +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 DeleteGroupCommand extends BaseStoreScraperBotCommand { + public static final DeleteGroupCommand INSTANCE = new DeleteGroupCommand(); + + DeleteGroupCommand() { + super("delgroup", ". Xoá group khỏi list group cho phép sử dụng bot"); + } + + @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 > 1) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + long groupId; + if (arguments.length == 1) { + try { + groupId = Long.parseLong(arguments[0]); + } catch (NumberFormatException e) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid groupId"); + return; + } + } else { + groupId = chat.getId(); + } + + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(groupId)) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Group is not added"); + return; + } + + admin.getGroups().remove(groupId); + AdminRepository.INSTANCE.save(admin); + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Group deleted successfully"); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/InfoCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/InfoCommand.java new file mode 100644 index 0000000..b2eb24c --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/InfoCommand.java @@ -0,0 +1,29 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +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 InfoCommand extends BaseStoreScraperBotCommand { + public static final InfoCommand INSTANCE = new InfoCommand(); + + InfoCommand() { + super("info", "Lấy thông tin của nhóm (chatId, threadId,...)"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + if (arguments.length != 0) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + long groupId = chat.getId(); + + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Id của nhóm là %s\n".formatted(groupId)); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java new file mode 100644 index 0000000..49b5546 --- /dev/null +++ b/src/main/java/com/miti99/storescraperbot/bot/command/ListAppCommand.java @@ -0,0 +1,47 @@ +package com.miti99.storescraperbot.bot.command; + +import com.miti99.storescraperbot.bot.StoreScrapeBotTelegramClient; +import com.miti99.storescraperbot.repository.AdminRepository; +import com.miti99.storescraperbot.repository.GroupRepository; +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 ListAppCommand extends BaseStoreScraperBotCommand { + public static final ListAppCommand INSTANCE = new ListAppCommand(); + + ListAppCommand() { + super("listapp", ". Thêm Google app vào danh sách theo dõi của nhóm"); + } + + @Override + protected void executeCommand( + TelegramClient telegramClient, User user, Chat chat, String[] arguments) { + var admin = AdminRepository.INSTANCE.load(); + if (!admin.getGroups().contains(chat.getId())) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage( + chat.getId(), "Group is not allowed to use bot"); + return; + } + + if (arguments.length != 0) { + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), "Invalid arguments"); + return; + } + + long groupId = chat.getId(); + var group = GroupRepository.INSTANCE.load(groupId); + + var sb = new StringBuilder(); + sb.append("Apple Apps:\n"); + for (var appId : group.getAppleApps()) { + sb.append("- %s\n".formatted(appId)); + } + sb.append("\nGoogle Apps:\n"); + for (var appId : group.getGoogleApps()) { + sb.append("- %s\n".formatted(appId)); + } + + StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString()); + } +} diff --git a/src/main/java/com/miti99/storescraperbot/bot/command/GetGroupCommand.java b/src/main/java/com/miti99/storescraperbot/bot/command/ListGroupCommand.java similarity index 75% rename from src/main/java/com/miti99/storescraperbot/bot/command/GetGroupCommand.java rename to src/main/java/com/miti99/storescraperbot/bot/command/ListGroupCommand.java index 38b8191..1b69b23 100644 --- a/src/main/java/com/miti99/storescraperbot/bot/command/GetGroupCommand.java +++ b/src/main/java/com/miti99/storescraperbot/bot/command/ListGroupCommand.java @@ -7,11 +7,11 @@ 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(); +public class ListGroupCommand extends BaseStoreScraperBotCommand { + public static final ListGroupCommand INSTANCE = new ListGroupCommand(); - GetGroupCommand() { - super("getgroup", "Lấy danh sách group được phép sử dụng bot hiện tại"); + ListGroupCommand() { + super("listgroup", "Lấy danh sách group được phép sử dụng bot hiện tại"); } @Override @@ -27,13 +27,12 @@ public class GetGroupCommand extends BaseStoreScraperBotCommand { return; } - var admin = AdminRepository.INSTANCE.load(); var groups = admin.getGroups(); var sb = new StringBuilder(); - sb.append("Groups:/n"); + sb.append("Groups:\n"); for (var groupId : groups) { - sb.append("- ").append(groupId).append("\n"); + sb.append("- %s\n".formatted(groupId)); } StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString()); } diff --git a/src/main/java/com/miti99/storescraperbot/constant/Constant.java b/src/main/java/com/miti99/storescraperbot/constant/Constant.java index 4a7fee3..24b3445 100644 --- a/src/main/java/com/miti99/storescraperbot/constant/Constant.java +++ b/src/main/java/com/miti99/storescraperbot/constant/Constant.java @@ -2,4 +2,6 @@ package com.miti99.storescraperbot.constant; public class Constant { public static final String APP_NAME = "store_scraper_bot"; + public static final long APP_CACHE_SECONDS = 600; + public static final long NUM_DAYS_WARNING_NOT_UPDATED = 30; } diff --git a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java index 6659b30..3d430c8 100644 --- a/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java +++ b/src/main/java/com/miti99/storescraperbot/model/AbstractModel.java @@ -2,12 +2,14 @@ package com.miti99.storescraperbot.model; import com.google.gson.annotations.SerializedName; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Setter; @Getter -@RequiredArgsConstructor +@NoArgsConstructor +@Setter public abstract class AbstractModel { - final K key; + protected K key; @SerializedName("class") protected String clazz = getClass().getSimpleName(); diff --git a/src/main/java/com/miti99/storescraperbot/model/Admin.java b/src/main/java/com/miti99/storescraperbot/model/Admin.java index 49fd54b..17be171 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Admin.java +++ b/src/main/java/com/miti99/storescraperbot/model/Admin.java @@ -2,16 +2,9 @@ package com.miti99.storescraperbot.model; import java.util.ArrayList; import java.util.List; -import lombok.Data; import lombok.Getter; -import lombok.Setter; @Getter -@Setter public class Admin extends AbstractModel { - List groups = new ArrayList<>(); - - public Admin(String key) { - super(key); - } + final List groups = new ArrayList<>(); } diff --git a/src/main/java/com/miti99/storescraperbot/model/AppleApp.java b/src/main/java/com/miti99/storescraperbot/model/AppleApp.java index 3463b99..4b1cbaa 100644 --- a/src/main/java/com/miti99/storescraperbot/model/AppleApp.java +++ b/src/main/java/com/miti99/storescraperbot/model/AppleApp.java @@ -7,10 +7,5 @@ import lombok.Setter; @Getter @Setter public class AppleApp extends AbstractModel { - long cacheTime; - AppleAppResponse rawResponse; - - public AppleApp(String key) { - super(key); - } + AppleAppResponse app; } diff --git a/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java b/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java index a6d7903..de9b993 100644 --- a/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java +++ b/src/main/java/com/miti99/storescraperbot/model/GoogleApp.java @@ -7,10 +7,5 @@ import lombok.Setter; @Getter @Setter public class GoogleApp extends AbstractModel { - long cacheTime; - GoogleAppResponse rawResponse; - - public GoogleApp(String key) { - super(key); - } + GoogleAppResponse app; } diff --git a/src/main/java/com/miti99/storescraperbot/model/Group.java b/src/main/java/com/miti99/storescraperbot/model/Group.java index 609aea5..a15b016 100644 --- a/src/main/java/com/miti99/storescraperbot/model/Group.java +++ b/src/main/java/com/miti99/storescraperbot/model/Group.java @@ -1,22 +1,13 @@ package com.miti99.storescraperbot.model; -import com.miti99.storescraperbot.type.AppType; +import java.util.ArrayList; import java.util.List; -import lombok.Data; import lombok.Getter; import lombok.Setter; @Getter @Setter public class Group extends AbstractModel { - List apps; - - public Group(Long key) { - super(key); - } - - public static class App { - String appId; - AppType type; - } + List appleApps = new ArrayList<>(); + List googleApps = 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 5be7b34..161eddf 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AbstractRepository.java @@ -10,12 +10,13 @@ import java.lang.reflect.ParameterizedType; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.log4j.Log4j2; +import redis.clients.jedis.params.SetParams; @Log4j2 @NoArgsConstructor(access = AccessLevel.PROTECTED) public abstract class AbstractRepository> { public static final String SEPARATOR = ":"; - protected final Class classK = getKeyClass(); + // protected final Class classK = getKeyClass(); protected final Class classV = getDataClass(); protected final String prefix = String.join( @@ -24,10 +25,10 @@ public abstract class AbstractRepository> { Config.ENV.name().toLowerCase(), CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, classV.getSimpleName())); - protected Class getKeyClass() { - return (Class) - ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - } + // protected Class getKeyClass() { + // return (Class) + // ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + // } /** * Lấy ra class của V. Khi tạo 1 abstract class extends AbstractRepository mà không phải final thì @@ -41,12 +42,20 @@ public abstract class AbstractRepository> { ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1]; } + /** + * @return expire seconds. <= 0 mean never expire. + */ + protected long getExpireSeconds() { + return 0; + } + public void init(K key) { try { if (exist(key)) { return; } - V data = classV.getDeclaredConstructor(classK).newInstance(key); + V data = classV.getDeclaredConstructor().newInstance(); + data.setKey(key); save(key, data); } catch (Exception e) { log.error("Error while initializing data", e); @@ -61,7 +70,11 @@ public abstract class AbstractRepository> { var databaseKey = getDatabaseKey(key); try (var jedis = RedisUtil.getJedis()) { var json = GsonUtil.toJson(data); - jedis.set(databaseKey, json); + if (getExpireSeconds() <= 0) { + jedis.set(databaseKey, json); + } else { + jedis.set(databaseKey, json, SetParams.setParams().ex(getExpireSeconds())); + } } catch (Exception e) { log.error("save error - key {}, databaseKey {}", key, databaseKey, e); } diff --git a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java index d8b0ae4..733d935 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/AppleAppRepository.java @@ -1,7 +1,13 @@ package com.miti99.storescraperbot.repository; +import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.AppleApp; public class AppleAppRepository extends AbstractRepository { public static final AppleAppRepository INSTANCE = new AppleAppRepository(); + + @Override + protected long getExpireSeconds() { + return Constant.APP_CACHE_SECONDS; + } } diff --git a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java index 8c2186f..92835fb 100644 --- a/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java +++ b/src/main/java/com/miti99/storescraperbot/repository/GoogleAppRepository.java @@ -1,7 +1,13 @@ package com.miti99.storescraperbot.repository; +import com.miti99.storescraperbot.constant.Constant; import com.miti99.storescraperbot.model.GoogleApp; public class GoogleAppRepository extends AbstractRepository { - private static final GoogleAppRepository INSTANCE = new GoogleAppRepository(); + public static final GoogleAppRepository INSTANCE = new GoogleAppRepository(); + + @Override + protected long getExpireSeconds() { + return Constant.APP_CACHE_SECONDS; + } }