From c6ea74914de1fc677b621a5058135a97285a9db1 Mon Sep 17 00:00:00 2001 From: bulatruslanovich Date: Fri, 18 Oct 2024 03:59:35 +0300 Subject: [PATCH] feat: (big update) add new filter parameter exclusion --- .../bipbup/controllers/UpdateProcessor.java | 2 +- .../bipbup/easter/egg/EasterEggService.java | 6 +- .../src/main/resources/application.yaml | 4 +- .../main/java/com/bipbup/dao/AppUserDAO.java | 3 +- .../main/java/com/bipbup/entity/AppUser.java | 10 +++ .../java/com/bipbup/entity/AppUserConfig.java | 5 +- .../com/bipbup/entity/EducationLevel.java | 3 +- .../java/com/bipbup/entity/ScheduleType.java | 3 +- .../java/com/bipbup/enums/AppUserState.java | 2 + .../impl/callback/QueryMenuStateHandler.java | 18 ++++- .../callback/QueryUpdateStateHandler.java | 4 + .../message/WaitExclusionStateHandler.java | 80 +++++++++++++++++++ .../service/api/impl/VacancyServiceImpl.java | 24 +++--- .../service/bot/impl/MainServiceImpl.java | 4 +- .../service/bot/impl/NotifierServiceImpl.java | 6 +- .../com/bipbup/service/db/UserService.java | 2 +- .../service/db/impl/ConfigServiceImpl.java | 4 +- .../service/db/impl/UserServiceImpl.java | 28 ++++--- .../bipbup/utils/CommandMessageConstants.java | 20 ++++- .../utils/factory/KeyboardMarkupFactory.java | 38 ++++----- ...24-10-17_alert_table_t_app_user_active.sql | 1 + ...4-10-17_alert_table_t_config_exclusion.sql | 1 + .../db/changelog/db.changelog-master.yaml | 7 +- node/src/main/resources/messages.properties | 13 ++- 24 files changed, 215 insertions(+), 73 deletions(-) create mode 100644 node/src/main/java/com/bipbup/handlers/impl/message/WaitExclusionStateHandler.java create mode 100644 node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_app_user_active.sql create mode 100644 node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_config_exclusion.sql diff --git a/dispatcher/src/main/java/com/bipbup/controllers/UpdateProcessor.java b/dispatcher/src/main/java/com/bipbup/controllers/UpdateProcessor.java index c99afe5..024521c 100644 --- a/dispatcher/src/main/java/com/bipbup/controllers/UpdateProcessor.java +++ b/dispatcher/src/main/java/com/bipbup/controllers/UpdateProcessor.java @@ -103,7 +103,7 @@ private void sendStickerToTelegram(SendSticker sticker) { private void deactivateUser(User user) { var callbackQuery = new CallbackQuery(); callbackQuery.setFrom(user); - callbackQuery.setData("delete_me_from_db"); + callbackQuery.setData("deactivate_me"); var update = new Update(); update.setCallbackQuery(callbackQuery); diff --git a/dispatcher/src/main/java/com/bipbup/easter/egg/EasterEggService.java b/dispatcher/src/main/java/com/bipbup/easter/egg/EasterEggService.java index bad8145..de7f481 100644 --- a/dispatcher/src/main/java/com/bipbup/easter/egg/EasterEggService.java +++ b/dispatcher/src/main/java/com/bipbup/easter/egg/EasterEggService.java @@ -18,7 +18,11 @@ public class EasterEggService { "javascript" , "CAACAgIAAxkBAAIFdmbI5bDHR6rHgpLIXtLtIPy8ro-tAAL2QQACctF4S6_e0ZZv1pzyNQQ", "python" , "CAACAgIAAxkBAAIFd2bI5hnwHgT_BL5jTZtoeT1aL9JwAALISAAC5PF5S7Se8n5ySpqANQQ", "c#" , "CAACAgIAAxkBAAIFeGbI5kjF58JJGk4yeE-hYI6RwyvuAAJfQwACJad4SypZPWXZRAYeNQQ", - "котик" , "CAACAgIAAxkBAAIFeWbI5mG6zqA00c19q65qlyCqqJE2AAJ4FAACiQ5BS8wYzPDMMcXINQQ" + "котик" , "CAACAgIAAxkBAAIFeWbI5mG6zqA00c19q65qlyCqqJE2AAJ4FAACiQ5BS8wYzPDMMcXINQQ", + "assembler", "CAACAgIAAxkBAAIO8GcRrXoCcvRQp6FqPFwy9NhxDO4GAAL3IwACXpZISL-caYTJXWsLNgQ", + "spring", "CAACAgIAAxkBAAIO72cRrWWo_T_CDtDoIAKpZb5S2kTGAALARwACx9DJS1jIpYXzWxeJNgQ", + "1с", "CAACAgIAAxkBAAIO82cRrkssAAE5ROLBqlWz0PlUiLwnfQACV0AAAohqSUjWTTvAooLXNTYE", + "authors", "CAACAgIAAxkBAAIO9GcRrmF87jiheDcRgr-5-s-dpO7WAAKCTgACv9p4SN-YAf7zsPlCNgQ" ); public Optional getSendSticker(Update update) { diff --git a/dispatcher/src/main/resources/application.yaml b/dispatcher/src/main/resources/application.yaml index c2609cd..1fe80fc 100644 --- a/dispatcher/src/main/resources/application.yaml +++ b/dispatcher/src/main/resources/application.yaml @@ -4,9 +4,9 @@ server: enabled: false bot: - url: ${BOT_URI:unset} + url: ${BOT_URI:https://b33d-87-117-189-157.ngrok-free.app} username: ${BOT_USERNAME:headh_v2_bot} - token: ${BOT_TOKEN:token} + token: ${BOT_TOKEN:7361235631:AAGgia9VqWY6Q_o1pW2WTaLQ4d6vzLgRcOg} spring: kafka: diff --git a/node/src/main/java/com/bipbup/dao/AppUserDAO.java b/node/src/main/java/com/bipbup/dao/AppUserDAO.java index 02ddd6b..5d69b73 100644 --- a/node/src/main/java/com/bipbup/dao/AppUserDAO.java +++ b/node/src/main/java/com/bipbup/dao/AppUserDAO.java @@ -1,11 +1,10 @@ package com.bipbup.dao; import com.bipbup.entity.AppUser; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface AppUserDAO extends JpaRepository { diff --git a/node/src/main/java/com/bipbup/entity/AppUser.java b/node/src/main/java/com/bipbup/entity/AppUser.java index 05fcc18..028be46 100644 --- a/node/src/main/java/com/bipbup/entity/AppUser.java +++ b/node/src/main/java/com/bipbup/entity/AppUser.java @@ -1,16 +1,20 @@ package com.bipbup.entity; import com.bipbup.enums.Role; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.EqualsAndHashCode; @@ -51,9 +55,15 @@ public class AppUser { @Column(name = "username") private String username; + @Column(name = "active") + private Boolean active; + @NotNull @Builder.Default @Enumerated(EnumType.STRING) @Column(name = "role", nullable = false, length = 32) private Role role = Role.USER; + + @OneToMany(mappedBy = "appUser", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) + private List configs; } diff --git a/node/src/main/java/com/bipbup/entity/AppUserConfig.java b/node/src/main/java/com/bipbup/entity/AppUserConfig.java index f14bc34..6b967b5 100644 --- a/node/src/main/java/com/bipbup/entity/AppUserConfig.java +++ b/node/src/main/java/com/bipbup/entity/AppUserConfig.java @@ -56,7 +56,10 @@ public class AppUserConfig { @Column(name = "area") private String area; - @ManyToOne + @Column(name = "exclusion") + private String exclusion; + + @ManyToOne(fetch = FetchType.EAGER, optional = false) @JoinColumn(name = "app_user_id") private AppUser appUser; diff --git a/node/src/main/java/com/bipbup/entity/EducationLevel.java b/node/src/main/java/com/bipbup/entity/EducationLevel.java index 9eb6921..fa2f6a5 100644 --- a/node/src/main/java/com/bipbup/entity/EducationLevel.java +++ b/node/src/main/java/com/bipbup/entity/EducationLevel.java @@ -5,6 +5,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -37,7 +38,7 @@ public class EducationLevel { @Enumerated(EnumType.STRING) private EducationLevelParam param; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "config_id") private AppUserConfig config; } diff --git a/node/src/main/java/com/bipbup/entity/ScheduleType.java b/node/src/main/java/com/bipbup/entity/ScheduleType.java index db8fa0b..bfdef68 100644 --- a/node/src/main/java/com/bipbup/entity/ScheduleType.java +++ b/node/src/main/java/com/bipbup/entity/ScheduleType.java @@ -5,6 +5,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -37,7 +38,7 @@ public class ScheduleType { @Enumerated(EnumType.STRING) private ScheduleTypeParam param; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "config_id") private AppUserConfig config; } diff --git a/node/src/main/java/com/bipbup/enums/AppUserState.java b/node/src/main/java/com/bipbup/enums/AppUserState.java index b7c87e0..85649fd 100644 --- a/node/src/main/java/com/bipbup/enums/AppUserState.java +++ b/node/src/main/java/com/bipbup/enums/AppUserState.java @@ -13,6 +13,8 @@ public enum AppUserState { WAIT_QUERY_STATE(true), + WAIT_EXCLUSION_STATE(true), + QUERY_LIST_STATE(false), QUERY_MENU_STATE(false), diff --git a/node/src/main/java/com/bipbup/handlers/impl/callback/QueryMenuStateHandler.java b/node/src/main/java/com/bipbup/handlers/impl/callback/QueryMenuStateHandler.java index bf8e3c5..e1b0771 100644 --- a/node/src/main/java/com/bipbup/handlers/impl/callback/QueryMenuStateHandler.java +++ b/node/src/main/java/com/bipbup/handlers/impl/callback/QueryMenuStateHandler.java @@ -28,6 +28,7 @@ import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_AREA; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_CONFIG_NAME; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_EDUCATION; +import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_EXCLUSION; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_EXPERIENCE; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_QUERY; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.MENU_SCHEDULE; @@ -100,10 +101,21 @@ private String showDetailedQueryOutput(AppUserConfig config) { .append(config.getConfigName()).append("\n") .append(MENU_QUERY) .append(config.getQueryText()).append("\n") - .append(MENU_AREA) - .append(config.getArea() == null ? "Любой" : config.getArea()).append("\n") .append(MENU_EXPERIENCE) - .append(config.getExperience().getDescription()); + .append(config.getExperience().getDescription()).append("\n"); + + if (config.getArea() != null) { + output.append(MENU_AREA) + .append(config.getArea()) + .append("\n"); + } + + if (config.getExclusion() != null) { + output.append(MENU_EXCLUSION) + .append(config.getExclusion()) + .append("\n"); + } + var eduParams = config.getEducationLevels() .stream() .map(EducationLevel::getParam) diff --git a/node/src/main/java/com/bipbup/handlers/impl/callback/QueryUpdateStateHandler.java b/node/src/main/java/com/bipbup/handlers/impl/callback/QueryUpdateStateHandler.java index 2b2e0b0..bf57ab1 100644 --- a/node/src/main/java/com/bipbup/handlers/impl/callback/QueryUpdateStateHandler.java +++ b/node/src/main/java/com/bipbup/handlers/impl/callback/QueryUpdateStateHandler.java @@ -7,6 +7,7 @@ import static com.bipbup.enums.AppUserState.WAIT_AREA_STATE; import static com.bipbup.enums.AppUserState.WAIT_CONFIG_NAME_STATE; import static com.bipbup.enums.AppUserState.WAIT_EDUCATION_STATE; +import static com.bipbup.enums.AppUserState.WAIT_EXCLUSION_STATE; import static com.bipbup.enums.AppUserState.WAIT_EXPERIENCE_STATE; import static com.bipbup.enums.AppUserState.WAIT_QUERY_STATE; import static com.bipbup.enums.AppUserState.WAIT_SCHEDULE_STATE; @@ -17,6 +18,7 @@ import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.CONFIG_NOT_FOUND; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.ENTER_AREA; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.ENTER_CONFIG_NAME; +import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.ENTER_EXCLUSION; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.ENTER_QUERY; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.SELECT_EDUCATION; import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.SELECT_EXPERIENCE; @@ -49,6 +51,8 @@ public class QueryUpdateStateHandler implements StateHandler { new ActionInfo(WAIT_CONFIG_NAME_STATE, ENTER_CONFIG_NAME.toString(), true), Prefix.UPDATE_QUERY, new ActionInfo(WAIT_QUERY_STATE, ENTER_QUERY.toString(), true), + Prefix.UPDATE_EXCLUSION, + new ActionInfo(WAIT_EXCLUSION_STATE, ENTER_EXCLUSION.toString(), true), Prefix.UPDATE_EXPERIENCE, new ActionInfo(WAIT_EXPERIENCE_STATE, SELECT_EXPERIENCE.toString(), false), Prefix.UPDATE_AREA, diff --git a/node/src/main/java/com/bipbup/handlers/impl/message/WaitExclusionStateHandler.java b/node/src/main/java/com/bipbup/handlers/impl/message/WaitExclusionStateHandler.java new file mode 100644 index 0000000..fc82880 --- /dev/null +++ b/node/src/main/java/com/bipbup/handlers/impl/message/WaitExclusionStateHandler.java @@ -0,0 +1,80 @@ +package com.bipbup.handlers.impl.message; + +import com.bipbup.annotation.MessageQualifier; +import com.bipbup.entity.AppUser; +import com.bipbup.entity.AppUserConfig; +import com.bipbup.enums.AppUserState; +import com.bipbup.handlers.StateHandler; +import com.bipbup.service.cache.UserStateCacheService; +import com.bipbup.service.db.ConfigService; +import com.bipbup.utils.HandlerUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + + +import static com.bipbup.enums.AppUserState.WAIT_EXCLUSION_STATE; +import static com.bipbup.utils.CommandMessageConstants.EMPTY; +import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.EMPTY_EXCLUSION_SET; +import static com.bipbup.utils.CommandMessageConstants.MessageTemplate.EXCLUSION_SET; + +@Slf4j +@Component +@MessageQualifier +@RequiredArgsConstructor +public class WaitExclusionStateHandler implements StateHandler { + + protected static final int MAX_QUERY_LENGTH = 50; + + private final ConfigService configService; + + private final UserStateCacheService userStateCacheService; + + private final HandlerUtils handlerUtils; + + @Override + public String process(AppUser user, String input) { + if (handlerUtils.isCancelCommand(input)) + return handlerUtils.processCancelCommand(user); + if (handlerUtils.isBasicCommand(input)) + return handlerUtils.processBasicCommand(user, input); + if (isInvalidExclusionText(input)) + return handlerUtils.processInvalidInput(user); + + var optionalConfig = handlerUtils.fetchConfig(user); + + if (optionalConfig.isPresent()) { + var config = optionalConfig.get(); + return processValidExclusion(user, config, input); + } else { + return handlerUtils.processInvalidInput(user); + } + } + + @Override + public AppUserState state() { + return WAIT_EXCLUSION_STATE; + } + + private boolean isInvalidExclusionText(String input) { + return !(input != null && !input.trim() + .isEmpty() && input.length() <= MAX_QUERY_LENGTH); + } + + private String processValidExclusion(AppUser user, AppUserConfig config, String input) { + String output; + + if (EMPTY.equalsIgnoreCase(input)) { + config.setExclusion(null); + output = String.format(EMPTY_EXCLUSION_SET.toString(), config.getConfigName()); + } else { + config.setExclusion(input); + output = String.format(EXCLUSION_SET.toString(), input, config.getConfigName()); + } + + configService.saveConfig(config); + userStateCacheService.clearUserState(user.getTelegramId()); + log.info("User {} set exclusion '{}' in configuration '{}'", user.getFirstName(), input, config.getConfigName()); + return output; + } +} diff --git a/node/src/main/java/com/bipbup/service/api/impl/VacancyServiceImpl.java b/node/src/main/java/com/bipbup/service/api/impl/VacancyServiceImpl.java index 660f585..2bfcaf7 100644 --- a/node/src/main/java/com/bipbup/service/api/impl/VacancyServiceImpl.java +++ b/node/src/main/java/com/bipbup/service/api/impl/VacancyServiceImpl.java @@ -23,10 +23,6 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; -/** - * This service handles fetching vacancy data from the API. It uses the user configuration to query for new vacancies - * and processes the results. - */ @Slf4j @Service @RequiredArgsConstructor @@ -42,16 +38,8 @@ public class VacancyServiceImpl implements VacancyService { private AppUserConfig config; - /** - * Fetches new vacancies based on user configuration. - * - * @param config The user configuration containing query parameters. - * - * @return A list of new vacancies. - */ @Override public List fetchNewVacancies(AppUserConfig config) { - // TODO: будет ли работать на синглтоне бина this.config = config; var pageCount = fetchPageCount(); vacancyList = new ArrayList<>(); @@ -83,7 +71,7 @@ private String createVacanciesGetUri(int pageNumber) { var builder = UriComponentsBuilder.fromUriString(headHunterProperties.vacanciesGetUrl()) .queryParam("page", pageNumber) .queryParam("per_page", headHunterProperties.countVacanciesInPage()) - .queryParam("text", encodeQueryText(config.getQueryText())) + .queryParam("text", encodeForURLForm(config.getQueryText())) .queryParam("search_field", "name") .queryParam("period", headHunterProperties.periodOfDays()) .queryParam("order_by", "publication_time"); @@ -92,11 +80,12 @@ private String createVacanciesGetUri(int pageNumber) { addExperience(builder); addEducation(builder); addSchedule(builder); + addExclusion(builder); return builder.build().toString(); } - private String encodeQueryText(String queryText) { + private String encodeForURLForm(String queryText) { return URLEncoder.encode(queryText, StandardCharsets.UTF_8); } @@ -134,6 +123,13 @@ private void addSchedule(UriComponentsBuilder builder) { builder.queryParam("schedule", types); } + private void addExclusion(UriComponentsBuilder builder) { + var exclusion = config.getExclusion(); + + if (exclusion != null) + builder.queryParam("excluded_text", encodeForURLForm(exclusion)); + } + private void processVacancyPage(int pageNum) { var optionalPage = fetchVacancyPage(pageNum); diff --git a/node/src/main/java/com/bipbup/service/bot/impl/MainServiceImpl.java b/node/src/main/java/com/bipbup/service/bot/impl/MainServiceImpl.java index 76db30f..e7a3803 100644 --- a/node/src/main/java/com/bipbup/service/bot/impl/MainServiceImpl.java +++ b/node/src/main/java/com/bipbup/service/bot/impl/MainServiceImpl.java @@ -93,8 +93,8 @@ public void processCallbackQuery(Update update) { var user = userService.findOrSaveAppUser(update); var state = userStateCacheService.getUserState(user.getTelegramId()); - if (callbackData.equals("delete_me_from_db")) { - userService.deleteAppUser(user); + if (callbackData.equals("deactivate_me")) { + userService.deactivate(user); return; } diff --git a/node/src/main/java/com/bipbup/service/bot/impl/NotifierServiceImpl.java b/node/src/main/java/com/bipbup/service/bot/impl/NotifierServiceImpl.java index 158a31e..2843a0f 100644 --- a/node/src/main/java/com/bipbup/service/bot/impl/NotifierServiceImpl.java +++ b/node/src/main/java/com/bipbup/service/bot/impl/NotifierServiceImpl.java @@ -16,6 +16,7 @@ import org.springframework.stereotype.Service; import org.telegram.telegrambots.meta.api.methods.ParseMode; import org.telegram.telegrambots.meta.api.methods.send.SendMessage; +import org.telegram.telegrambots.meta.api.objects.LinkPreviewOptions; @Slf4j @RequiredArgsConstructor @@ -94,8 +95,7 @@ private void sendVacancyMessage(Vacancy vacancy, AppUserConfig config) { String.format("• Роль: %s", roles), String.format("• Опыт: %s", experience), String.format("• Тип занятости: %s", employmentType), - String.format("• График: %s", workSchedule), - String.format("• (Ссылка)[%s]", jobLink)); + String.format("• График: %s", workSchedule)); var telegramId = config.getAppUser() .getTelegramId(); @@ -103,6 +103,8 @@ private void sendVacancyMessage(Vacancy vacancy, AppUserConfig config) { var sendMessage = SendMessage.builder() .text(message) .parseMode(ParseMode.HTML) + .disableWebPagePreview(false) + .linkPreviewOptions(new LinkPreviewOptions(false, jobLink, true, false, true)) .chatId(telegramId) .build(); diff --git a/node/src/main/java/com/bipbup/service/db/UserService.java b/node/src/main/java/com/bipbup/service/db/UserService.java index dc8c1e4..55ef0b4 100644 --- a/node/src/main/java/com/bipbup/service/db/UserService.java +++ b/node/src/main/java/com/bipbup/service/db/UserService.java @@ -7,7 +7,7 @@ public interface UserService { - void deleteAppUser(AppUser user); + void deactivate(AppUser user); AppUser findOrSaveAppUser(Update update); diff --git a/node/src/main/java/com/bipbup/service/db/impl/ConfigServiceImpl.java b/node/src/main/java/com/bipbup/service/db/impl/ConfigServiceImpl.java index c73d472..e729be8 100644 --- a/node/src/main/java/com/bipbup/service/db/impl/ConfigServiceImpl.java +++ b/node/src/main/java/com/bipbup/service/db/impl/ConfigServiceImpl.java @@ -9,10 +9,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -@RequiredArgsConstructor @Service +@RequiredArgsConstructor public class ConfigServiceImpl implements ConfigService { private final AppUserConfigDAO appUserConfigDAO; @@ -30,7 +29,6 @@ public AppUserConfig saveConfig(AppUserConfig config) { } @Override - @Transactional public void deleteConfig(AppUserConfig config) { appUserConfigDAO.delete(config); } diff --git a/node/src/main/java/com/bipbup/service/db/impl/UserServiceImpl.java b/node/src/main/java/com/bipbup/service/db/impl/UserServiceImpl.java index daa470b..f7bc047 100644 --- a/node/src/main/java/com/bipbup/service/db/impl/UserServiceImpl.java +++ b/node/src/main/java/com/bipbup/service/db/impl/UserServiceImpl.java @@ -1,6 +1,5 @@ package com.bipbup.service.db.impl; -import com.bipbup.dao.AppUserConfigDAO; import com.bipbup.dao.AppUserDAO; import com.bipbup.entity.AppUser; import com.bipbup.enums.Role; @@ -9,27 +8,22 @@ import java.util.Objects; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.User; -@RequiredArgsConstructor @Service +@RequiredArgsConstructor public class UserServiceImpl implements UserService { private final AppUserDAO appUserDAO; - private final AppUserConfigDAO appUserConfigDAO; - @Override - @Transactional - public void deleteAppUser(AppUser user) { - appUserConfigDAO.deleteAllByAppUser(user); - appUserDAO.delete(user); + public void deactivate(AppUser user) { + user.setActive(false); + appUserDAO.save(user); } @Override - @Transactional public AppUser findOrSaveAppUser(Update update) { var sender = update.hasMessage() ? update.getMessage().getFrom() @@ -38,20 +32,31 @@ public AppUser findOrSaveAppUser(Update update) { if (optionalUser.isPresent()) { var user = optionalUser.get(); + boolean needUpdate = false; if (!Objects.equals(user.getUsername(), sender.getUserName())) { user.setUsername(sender.getUserName()); + needUpdate = true; } if (!Objects.equals(user.getFirstName(), sender.getFirstName())) { user.setFirstName(sender.getFirstName()); + needUpdate = true; } if (!Objects.equals(user.getLastName(), sender.getLastName())) { user.setLastName(sender.getLastName()); + needUpdate = true; + } + + if (!user.getActive()) { + user.setActive(true); + needUpdate = true; } - return appUserDAO.save(user); + if (needUpdate) + return appUserDAO.save(user); + return user; } return saveAppUser(sender); @@ -64,6 +69,7 @@ private AppUser saveAppUser(User sender) { .firstName(sender.getFirstName()) .lastName(sender.getLastName()) .role(Role.USER) + .active(true) .build(); appUserDAO.save(appUser); diff --git a/node/src/main/java/com/bipbup/utils/CommandMessageConstants.java b/node/src/main/java/com/bipbup/utils/CommandMessageConstants.java index abf62d3..0ae5cbe 100644 --- a/node/src/main/java/com/bipbup/utils/CommandMessageConstants.java +++ b/node/src/main/java/com/bipbup/utils/CommandMessageConstants.java @@ -1,13 +1,11 @@ package com.bipbup.utils; -import lombok.Getter; +import java.util.Locale; import lombok.RequiredArgsConstructor; import lombok.experimental.UtilityClass; import org.springframework.context.MessageSource; import org.springframework.context.support.ReloadableResourceBundleMessageSource; -import java.util.Locale; - @UtilityClass public class CommandMessageConstants { @@ -24,7 +22,9 @@ private static String get(String code) { return MESSAGE_SOURCE.getMessage(code, null, code, Locale.ROOT); } - public static final String ANY = "Любой"; + public static final String ANY = "any"; + + public static final String EMPTY = "empty"; @RequiredArgsConstructor public enum BotCommand { @@ -89,6 +89,10 @@ public enum MessageTemplate { QUERY_SET(get("message.query.set")), + EXCLUSION_SET(get("message.exclusion.set")), + + EMPTY_EXCLUSION_SET(get("message.empty.exclusion.set")), + EXP_SET(get("message.exp.set")), AREA_SET(get("message.area.set")), @@ -107,6 +111,8 @@ public enum MessageTemplate { ENTER_QUERY(get("message.enter.query")), + ENTER_EXCLUSION(get("message.enter.exclusion")), + ENTER_AREA(get("message.enter.area")), SELECT_EXPERIENCE(get("message.select.experience")), @@ -121,6 +127,8 @@ public enum MessageTemplate { MENU_QUERY(get("message.menu.config.query")), + MENU_EXCLUSION(get("message.menu.config.exclusion")), + MENU_AREA(get("message.menu.config.area")), MENU_EXPERIENCE(get("message.menu.config.experience")), @@ -181,6 +189,8 @@ public static class Prefix { public static final String UPDATE_QUERY = UPDATE_STATE + "query_"; + public static final String UPDATE_EXCLUSION = UPDATE_STATE + "exclusion_"; + public static final String UPDATE_AREA = UPDATE_STATE + "area_"; public static final String UPDATE_EXPERIENCE = UPDATE_STATE + "experience_"; @@ -219,6 +229,8 @@ public static class ButtonText { public static final String UPDATE_QUERY = get("button.update.query"); + public static final String UPDATE_EXCLUSION = get("button.update.exclusion"); + public static final String UPDATE_AREA = get("button.update.area"); public static final String UPDATE_EXPERIENCE = get("button.update.experience"); diff --git a/node/src/main/java/com/bipbup/utils/factory/KeyboardMarkupFactory.java b/node/src/main/java/com/bipbup/utils/factory/KeyboardMarkupFactory.java index f3b1ff9..5420038 100644 --- a/node/src/main/java/com/bipbup/utils/factory/KeyboardMarkupFactory.java +++ b/node/src/main/java/com/bipbup/utils/factory/KeyboardMarkupFactory.java @@ -40,22 +40,17 @@ public class KeyboardMarkupFactory { public InlineKeyboardMarkup createUserConfigListKeyboard(AppUser appUser) { var configs = configService.getConfigByUser(appUser); - List buttons = new ArrayList<>(); + var buttons = new ArrayList(); configs.forEach(config -> buttons.add(createButtonFromConfig(config))); return createMarkup(buttons, BUTTONS_PER_ROW); } - private InlineKeyboardButton createButtonFromConfig(AppUserConfig config) { - var callback = Prefix.QUERY + encoder.hashOf(config.getId()); - return createButton(config.getConfigName(), callback); - } - public InlineKeyboardMarkup createConfigManagementKeyboard(String callbackData) { var hash = extractHash(callbackData); - List buttons = List.of( + var buttons = List.of( createButton(ButtonText.UPDATE, Prefix.UPDATE + hash), createButton(ButtonText.DELETE, Prefix.DELETE + hash), createButton(ButtonText.BACK, MYQUERIES.toString()) @@ -67,7 +62,7 @@ public InlineKeyboardMarkup createConfigManagementKeyboard(String callbackData) public InlineKeyboardMarkup createDeleteConfirmationKeyboard(String callbackData) { var hash = extractHash(callbackData); - List buttons = List.of( + var buttons = List.of( createButton(ButtonText.DELETE_CONFIRM, Prefix.DELETE_CONFIRM + hash), createButton(ButtonText.DELETE_CANCEL, Prefix.QUERY + hash) ); @@ -78,9 +73,10 @@ public InlineKeyboardMarkup createDeleteConfirmationKeyboard(String callbackData public InlineKeyboardMarkup createUpdateConfigKeyboard(String callbackData) { var hash = extractHash(callbackData); - List buttons = List.of( + var buttons = List.of( createButton(ButtonText.UPDATE_CONFIG_NAME, Prefix.UPDATE_CONFIG_NAME + hash), createButton(ButtonText.UPDATE_QUERY, Prefix.UPDATE_QUERY + hash), + createButton(ButtonText.UPDATE_EXCLUSION, Prefix.UPDATE_EXCLUSION + hash), createButton(ButtonText.UPDATE_AREA, Prefix.UPDATE_AREA + hash), createButton(ButtonText.UPDATE_EXPERIENCE, Prefix.UPDATE_EXPERIENCE + hash), createButton(ButtonText.UPDATE_EDUCATION, Prefix.UPDATE_EDUCATION + hash), @@ -106,9 +102,9 @@ public InlineKeyboardMarkup createEducationLevelSelectionKeyboard(AppUser user, var hash = extractHash(callbackData); var buttons = new ArrayList<>(Arrays.stream(EducationLevelParam.values()) - .sorted(Comparator.comparing(EducationLevelParam::getDescription)) - .map(param -> createButtonFromEnum(param, selectedLevels, hash)) - .toList()); + .sorted(Comparator.comparing(EducationLevelParam::getDescription)) + .map(param -> createButtonFromEnum(param, selectedLevels, hash)) + .toList()); buttons.add(createButton(ButtonText.SAVE, Prefix.EDU_SAVE + hash)); @@ -120,17 +116,21 @@ public InlineKeyboardMarkup createScheduleTypeSelectionKeyboard(AppUser user, St var hash = extractHash(callbackData); var buttons = new ArrayList<>(Arrays.stream(ScheduleTypeParam.values()) - .sorted(Comparator.comparing(ScheduleTypeParam::getDescription)) - .map(param -> createButtonFromEnum(param, selectedTypes, hash)) - .toList()); + .sorted(Comparator.comparing(ScheduleTypeParam::getDescription)) + .map(param -> createButtonFromEnum(param, selectedTypes, hash)) + .toList()); buttons.add(createButton(ButtonText.SAVE, Prefix.SCHEDULE_SAVE + hash)); return createMarkup(buttons, 1); } - private InlineKeyboardButton createButtonFromEnum( - EnumParam enumParam, List params, String hash) { + private InlineKeyboardButton createButtonFromConfig(AppUserConfig config) { + var callback = Prefix.QUERY + encoder.hashOf(config.getId()); + return createButton(config.getConfigName(), callback); + } + + private InlineKeyboardButton createButtonFromEnum(EnumParam enumParam, List params, String hash) { String text = enumParam.getDescription(); if (params.contains(enumParam)) @@ -148,13 +148,13 @@ private InlineKeyboardButton createButton(String text, String callbackData) { } private InlineKeyboardMarkup createMarkup(List buttons, int buttonsPerRow) { - List> rows = new ArrayList<>(); + var rows = new ArrayList>(); for (int i = 0; i < buttons.size(); i += buttonsPerRow) { rows.add(buttons.subList(i, Math.min(i + buttonsPerRow, buttons.size()))); } - InlineKeyboardMarkup markup = new InlineKeyboardMarkup(); + var markup = new InlineKeyboardMarkup(); markup.setKeyboard(rows); return markup; } diff --git a/node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_app_user_active.sql b/node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_app_user_active.sql new file mode 100644 index 0000000..1f3377e --- /dev/null +++ b/node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_app_user_active.sql @@ -0,0 +1 @@ +alter table hhbot.t_app_user add column active boolean default true; \ No newline at end of file diff --git a/node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_config_exclusion.sql b/node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_config_exclusion.sql new file mode 100644 index 0000000..258805d --- /dev/null +++ b/node/src/main/resources/db/changelog/changeset/2024-10-17_alert_table_t_config_exclusion.sql @@ -0,0 +1 @@ +alter table hhbot.t_config add column exclusion varchar(255); \ No newline at end of file diff --git a/node/src/main/resources/db/changelog/db.changelog-master.yaml b/node/src/main/resources/db/changelog/db.changelog-master.yaml index 615fa96..4e0ed15 100644 --- a/node/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/node/src/main/resources/db/changelog/db.changelog-master.yaml @@ -8,4 +8,9 @@ databaseChangeLog: - include: file: db/changelog/changeset/2024-10-11_create_table_t_edu_param.sql - include: - file: db/changelog/changeset/2024-10-11_create_table_t_schedule_param.sql \ No newline at end of file + file: db/changelog/changeset/2024-10-11_create_table_t_schedule_param.sql + - include: + file: db/changelog/changeset/2024-10-17_alert_table_t_config_exclusion.sql + - include: + file: db/changelog/changeset/2024-10-17_alert_table_t_app_user_active.sql + diff --git a/node/src/main/resources/messages.properties b/node/src/main/resources/messages.properties index f60f79d..7f5ffa2 100644 --- a/node/src/main/resources/messages.properties +++ b/node/src/main/resources/messages.properties @@ -1,7 +1,7 @@ # Message templates message.welcome=Добро пожаловать, %s! Чтобы узнать, что может бот, нажмите на /help -message.help=Команды:

🔍 /newqueryСоздать новый запрос на вакансии
🗂 /myqueriesПоказать ваши сохранённые запросы +message.help=Команды:\n\n🔍 /newqueryСоздать новый запрос на вакансии\n🗂 /myqueriesПоказать ваши сохранённые запросы message.query.prompt=📝 Обзовите конфигурацию? Если передумали, нажмите на /cancel message.user.queries=📋 Мои конфигурации: message.no.saved.queries=ℹ️ Нет сохранённых конфигураций. Нажмите на /newquery, чтобы создать что-то новенькое! @@ -11,6 +11,8 @@ message.config.deleted=❌ Конфигурация %s была удал message.config.exists=⚠️ Конфигурация с названием %s уже у вас есть, повторки - не круто. message.config.name.updated=Название конфигурации с %s изменено на %s. message.query.set=Запрос %s установлен в конфигурацию %s. +message.exclusion.set=Исключения %s установлены в конфигурацию %s. +message.empty.exclusion.set=Теперь конфигурация %s без исключений; message.exp.set=Опыт %s установлен в конфигурацию %s. message.area.set=Регион %s установлен в конфигурацию %s. message.any.area.set=Регион больше не учитывается в конфигурации %s. @@ -20,13 +22,15 @@ message.config.not.found=❌ Конфигурация к всеобщему со message.invalid.input=⚠️ Такого быть не может! Данные надо проверить. message.enter.config.name=Введите новое название для конфигурации %s: message.enter.query=Введите запрос для конфигурации %s: -message.enter.area=Введите название региона или Любой для конфигурации %s: +message.enter.exclusion=Введите слова исключения для конфигурации %s, если хотите убрать исключения, введите `empty`: +message.enter.area=Введите название региона или `any` для конфигурации %s: message.select.experience=Выберите опыт работы для конфигурации %s: message.select.education=Выберите уровень образования для конфигурации %s: message.select.schedule=Выберите график работы для конфигурации %s: message.command.cancelled=❌ Действие отменено. Можно начать заново! -message.menu.config.name=• Конфигурации: -message.menu.config.query=• Запроса: +message.menu.config.name=• Конфигурация: +message.menu.config.query=• Запрос: +message.menu.config.exclusion=• Исключение: message.menu.config.area=• Регион: message.menu.config.experience=• Опыт работы: message.menu.config.education=• Уровень образования: @@ -47,6 +51,7 @@ button.delete.confirm=❌ Удалить button.delete.cancel=✅ Сохранить button.update.config.name=Переименовать конфигурацию button.update.query=Обновить запрос +button.update.exclusion=Исключить слова button.update.area=Обновить регион button.update.experience=Обновить опыт button.update.education=Обновить образование