Add app and group management commands to bot

Introduces commands for adding, deleting, listing, and checking Apple and Google apps per group, as well as group management commands. Refactors models for app and group storage, adds caching for app data, and updates repositories to support cache expiration. Improves bot initialization and command registration logic.
This commit is contained in:
2025-11-05 23:06:24 +07:00
parent def45c7402
commit 5554d75534
22 changed files with 539 additions and 66 deletions
@@ -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());
}
}
}
@@ -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());
}
}
@@ -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();
}
@@ -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", "<appId>. 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");
}
}
@@ -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", "<appId>. 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");
}
}
@@ -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");
@@ -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("<b>Apple Apps:</b>\n");
sb.append("<code>\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("</code>\n");
sb.append("\n");
sb.append("<b>Google Apps:</b>\n");
sb.append("<code>\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("</code>");
sb.append("\n");
StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString());
}
}
@@ -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", "<appId>. 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");
}
}
@@ -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", "<appId>. 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");
}
}
@@ -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", "<groupId>. 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");
}
}
@@ -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à <code>%s</code>\n".formatted(groupId));
}
}
@@ -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", "<appId>. 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("<b>Apple Apps:</b>\n");
for (var appId : group.getAppleApps()) {
sb.append("- <code>%s</code>\n".formatted(appId));
}
sb.append("\n<b>Google Apps:</b>\n");
for (var appId : group.getGoogleApps()) {
sb.append("- <code>%s</code>\n".formatted(appId));
}
StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString());
}
}
@@ -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("<b>Groups:</b>/n");
sb.append("<b>Groups:</b>\n");
for (var groupId : groups) {
sb.append("- ").append(groupId).append("\n");
sb.append("- <code>%s</code>\n".formatted(groupId));
}
StoreScrapeBotTelegramClient.INSTANCE.sendMessage(chat.getId(), sb.toString());
}
@@ -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;
}
@@ -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<K> {
final K key;
protected K key;
@SerializedName("class")
protected String clazz = getClass().getSimpleName();
@@ -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<String> {
List<Long> groups = new ArrayList<>();
public Admin(String key) {
super(key);
}
final List<Long> groups = new ArrayList<>();
}
@@ -7,10 +7,5 @@ import lombok.Setter;
@Getter
@Setter
public class AppleApp extends AbstractModel<String> {
long cacheTime;
AppleAppResponse rawResponse;
public AppleApp(String key) {
super(key);
}
AppleAppResponse app;
}
@@ -7,10 +7,5 @@ import lombok.Setter;
@Getter
@Setter
public class GoogleApp extends AbstractModel<String> {
long cacheTime;
GoogleAppResponse rawResponse;
public GoogleApp(String key) {
super(key);
}
GoogleAppResponse app;
}
@@ -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<Long> {
List<App> apps;
public Group(Long key) {
super(key);
}
public static class App {
String appId;
AppType type;
}
List<String> appleApps = new ArrayList<>();
List<String> googleApps = new ArrayList<>();
}
@@ -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<K, V extends AbstractModel<K>> {
public static final String SEPARATOR = ":";
protected final Class<K> classK = getKeyClass();
// protected final Class<K> classK = getKeyClass();
protected final Class<V> classV = getDataClass();
protected final String prefix =
String.join(
@@ -24,10 +25,10 @@ public abstract class AbstractRepository<K, V extends AbstractModel<K>> {
Config.ENV.name().toLowerCase(),
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, classV.getSimpleName()));
protected Class<K> getKeyClass() {
return (Class<K>)
((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
// protected Class<K> getKeyClass() {
// return (Class<K>)
// ((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<K, V extends AbstractModel<K>> {
((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<K, V extends AbstractModel<K>> {
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);
}
@@ -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<String, AppleApp> {
public static final AppleAppRepository INSTANCE = new AppleAppRepository();
@Override
protected long getExpireSeconds() {
return Constant.APP_CACHE_SECONDS;
}
}
@@ -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<String, GoogleApp> {
private static final GoogleAppRepository INSTANCE = new GoogleAppRepository();
public static final GoogleAppRepository INSTANCE = new GoogleAppRepository();
@Override
protected long getExpireSeconds() {
return Constant.APP_CACHE_SECONDS;
}
}