Skip to content

Commit

Permalink
Big update
Browse files Browse the repository at this point in the history
  • Loading branch information
XyL1GaN4eG committed Jul 26, 2024
1 parent 313c1cd commit 7e9f9ad
Show file tree
Hide file tree
Showing 14 changed files with 498 additions and 355 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@
public class TelegramBot extends TelegramLongPollingBot {

public final BotConfig botConfig;

public final CommandHandler commandsHandler;

public final CallbackHandler callbacksHandler;

public final UserServiceClient userServiceClient;

private final WeatherServiceClient weatherServiceClient;

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package weatherproject.tgbotservice.telegram.callbacks;

public enum CallBackTypes {
CITY_NAME,
LOCATION,
COMMAND
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package weatherproject.tgbotservice.telegram.callbacks;

public class Callback {
private CallbackType callbackType;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import weatherproject.tgbotservice.dto.UserDTO;
import weatherproject.tgbotservice.dto.WeatherDTO;

private String data;
public interface Callback {
String execute(UserDTO user, WeatherDTO weather);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import weatherproject.tgbotservice.clients.GeocodingClient;
import weatherproject.tgbotservice.clients.GoogleTranslateClient;
import weatherproject.tgbotservice.clients.UserServiceClient;
import weatherproject.tgbotservice.clients.WeatherServiceClient;
import weatherproject.tgbotservice.dto.UserDTO;
import weatherproject.tgbotservice.dto.WeatherDTO;
import weatherproject.tgbotservice.telegram.UserState;
import weatherproject.tgbotservice.utils.Constants;

import java.util.Map;

import static weatherproject.tgbotservice.telegram.UserState.HAVE_SETTED_CITY;
import static weatherproject.tgbotservice.utils.Constants.ILLEGAL_CITY;
import static weatherproject.tgbotservice.utils.Constants.NEW_CITY_SETTED;
import static weatherproject.tgbotservice.telegram.UserState.START;

@RequiredArgsConstructor
@Component
Expand All @@ -24,104 +29,79 @@ public class CallbackHandler {
private final WeatherServiceClient weatherServiceClient;
private final UserServiceClient userServiceClient;
private final GoogleTranslateClient translateClient;
@SuppressWarnings("FieldCanBeLocal")
private final String CITY_NAME_PATTERN = "^[A-Za-zА-Яа-яЁё]+([-\\s][A-Za-zА-Яа-яЁё]+)?$";

private final Map<UserState, Callback> callbacks;

@Autowired
public CallbackHandler(GeocodingClient geocodingClient,
WeatherServiceClient weatherServiceClient,
UserServiceClient userServiceClient,
GoogleTranslateClient translateClient,
StartCallback startCallback,
SetCityTextCallback setCityTextCallback) {
this.geocodingClient = geocodingClient;
this.weatherServiceClient = weatherServiceClient;
this.userServiceClient = userServiceClient;
this.translateClient = translateClient;
this.callbacks = Map.of(
START, startCallback,
HAVE_SETTED_CITY, setCityTextCallback
);
}


public SendMessage handleCallback(UserDTO currentUser, Update update) {

public SendMessage handleCallback(UserDTO user, Update update) {
var message = update.getMessage();
var chatId = message.getChatId().toString();
String city = "Извините, произошла ошибка";
String textToReply = "Просим прощения, город или погода в нем не найдены.";

var currentState = (UserState) UserState.valueOf(currentUser.getState());
log.info("Обрабатываем {} от пользователя {}", message, currentUser);
//TODO: вынести обработку сообщения и присваивания названия города в отдельный метод
//TODO: вынести коллбэки в отдельные классы
//TODO: делать проверку в сообщении на то, город ли это вообще
//TODO: удалить дубликаты
//TODO: пробовать перевести город из сообщения, а не из пользователя
//TODO: добавить перевод и на русский и на английский города в бд юзера и погоды (но потом)


switch (currentState) {
case START: {
if (message.hasText()) {
if (isValidCityName(message.getText())) {
city = translateClient.translateRuToEng(
message.getText())
.replace(" ", "-");
}
} else if (message.hasLocation()) {
city = translateClient.translateRuToEng(
geocodingClient.getCityByCoordinates(
message.getLocation().getLatitude(),
message.getLocation().getLongitude()));
}
log.info("Пытаемся получить погоду в городе {}", city);
var weatherCity = weatherServiceClient.getWeatherByCity(city);
if (weatherCity != null) {
log.info("Получена погода: {}", weatherCity);
userServiceClient.createOrUpdateUser(new UserDTO(currentUser.getChatId(), city, HAVE_SETTED_CITY.toString()));
textToReply = NEW_CITY_SETTED
.replace("{city}", translateClient.translateEngToRussian(weatherCity.getCity()))
.replace("{temperature}", weatherCity.getTemperature().toString())
.replace("{condition}", translateClient.translateEngToRussian(weatherCity.getCondition()));
log.info("Сообщение для отправки: {}", textToReply);
}
return new SendMessage(chatId, textToReply);
}

//Если город уже выставлен
case HAVE_SETTED_CITY: {

if (message.hasText()) {
if (!isValidCityName(message.getText())) {
return new SendMessage(update.getMessage().getChatId().toString(), ILLEGAL_CITY
.replace("{city}", translateClient.translateEngToRussian(currentUser.getCity()))
.replace("{temperature}",
weatherServiceClient.getWeatherByCity(currentUser.getCity()).getTemperature().toString())
.replace("{condition}", translateClient.translateEngToRussian(weatherServiceClient.getWeatherByCity(currentUser.getCity()).getCondition())));
}
}

//то обращаемся к апи и возвращаем название города на английском языке
if (message.hasText()) {
city = translateClient.translateRuToEng(message.getText()).replace(" ", "-");
} else if (message.hasLocation()) {
city = translateClient.translateRuToEng(geocodingClient.getCityByCoordinates(
message.getLocation().getLatitude(),
message.getLocation().getLongitude()));
}
log.info("Пытаемся получить погоду в городе {}", city);
//получаем погоду из апи микросервиса
var weatherCity = weatherServiceClient.getWeatherByCity(city);

if (weatherCity != null) { //если погода найдена то
log.info("Получена погода: {}", weatherCity);
//обновляем город пользователя
userServiceClient.createOrUpdateUser(new UserDTO(currentUser.getChatId(), city, HAVE_SETTED_CITY.toString()));
textToReply = NEW_CITY_SETTED
.replace("{city}", translateClient.translateEngToRussian(city))
.replace("{temperature}", weatherCity.getTemperature().toString())
.replace("{condition}", translateClient.translateEngToRussian(weatherCity.getCondition()));
} else {
return new SendMessage(chatId, ILLEGAL_CITY
.replace("{city}", translateClient.translateEngToRussian(currentUser.getCity()))
.replace("{temperature}",
weatherServiceClient.getWeatherByCity(currentUser.getCity()).getTemperature().toString())
.replace("{condition}", translateClient.translateEngToRussian(weatherServiceClient.getWeatherByCity(currentUser.getCity()).getCondition())));
}

}
var chatId = update.getMessage().getChatId().toString();
try {
var currentState = (UserState) UserState.valueOf(user.getState());
var weather = getWeather(message);
var commandHandler = callbacks.get(currentState);
log.info(chatId);
log.info(weather.toString());
log.info(user.toString());
var text = commandHandler.execute(user, weather);
return new SendMessage(chatId, text);
} catch (NullPointerException e) {
return new SendMessage(chatId, Constants.ERROR);
}
return new SendMessage(chatId, textToReply);
}

@SuppressWarnings("FieldCanBeLocal")
private final String CITY_NAME_PATTERN = "^[A-Za-zА-Яа-яЁё]+([-\\s][A-Za-zА-Яа-яЁё]+)?$";
private WeatherDTO getWeather(Message message) {
var city = "";
if (message.hasText()) {
city = getCityByText(message);
} else if (message.hasLocation()) {
city = getCityByLocation(message);
} else {
city = null;
}
if (city != null) {
log.info("Пытаемся получить погоду в городе обращаясь к weather service {}", city);
return weatherServiceClient.getWeatherByCity(city);
}
return null;
}

private String getCityByText(Message message) {
return isValidCityName(message.getText()) ? translateClient.translateRuToEng(message.getText()).replace(" ", "-") : null;
}

public boolean isValidCityName(String text) {
private String getCityByLocation(Message message) {
var cityName = geocodingClient.getCityByCoordinates(
message.getLocation().getLatitude(),
message.getLocation().getLongitude());
return translateClient.translateRuToEng(cityName);
}

private boolean isValidCityName(String text) {
// Регулярное выражение для проверки названия города
return text.matches(CITY_NAME_PATTERN);
}
}



This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package weatherproject.tgbotservice.telegram.callbacks;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import weatherproject.tgbotservice.clients.GoogleTranslateClient;
import weatherproject.tgbotservice.clients.UserServiceClient;
import weatherproject.tgbotservice.clients.WeatherServiceClient;
import weatherproject.tgbotservice.dto.UserDTO;
import weatherproject.tgbotservice.dto.WeatherDTO;

import static weatherproject.tgbotservice.utils.Constants.ILLEGAL_CITY;
import static weatherproject.tgbotservice.utils.Constants.NEW_CITY_SETTED;

@RequiredArgsConstructor
@Component
@Slf4j
public class SetCityTextCallback implements Callback {
public final WeatherServiceClient weatherServiceClient;
public final GoogleTranslateClient translateClient;



@Override
public String execute(UserDTO user, WeatherDTO weatherDTO) {
// log.info("Начинаем обрабатывать коллбек setCity от пользователя {} со следующей новой полученной погодой: {}", user.toString(), weatherDTO.toString());

if (weatherDTO != null) {
return String.format(NEW_CITY_SETTED,
(Object[]) weatherDtoToArray(weatherDTO));
}
WeatherDTO newWeatherDTO = weatherServiceClient.getWeatherByCity(user.getCity());
return String.format(ILLEGAL_CITY,
(Object[]) weatherDtoToArray(newWeatherDTO));

}

private String[] weatherDtoToArray(WeatherDTO weatherDTO) {
var translatedWeather = translateClient.translateEngToRussian(weatherDTO.getCity() + ", " + weatherDTO.getCondition()).split(", ");
return new String[]{
translatedWeather[0],
weatherDTO.getTemperature().toString(),
translatedWeather[1]};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package weatherproject.tgbotservice.telegram.callbacks;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import weatherproject.tgbotservice.clients.GeocodingClient;
import weatherproject.tgbotservice.clients.GoogleTranslateClient;
import weatherproject.tgbotservice.clients.UserServiceClient;
import weatherproject.tgbotservice.clients.WeatherServiceClient;
import weatherproject.tgbotservice.dto.UserDTO;
import weatherproject.tgbotservice.dto.WeatherDTO;

import static weatherproject.tgbotservice.utils.Constants.CITY_NOT_FOUND;
import static weatherproject.tgbotservice.utils.Constants.FIRST_CITY_SET;

@RequiredArgsConstructor
@Component
@Slf4j
public class StartCallback implements Callback {

private final GoogleTranslateClient translateClient;

@Override
public String execute(UserDTO user, WeatherDTO weatherDTO) {
if (weatherDTO != null) {
return String.format(FIRST_CITY_SET, (Object[]) weatherDtoToArray(weatherDTO));
}
return (CITY_NOT_FOUND);
}

private String[] weatherDtoToArray(WeatherDTO weatherDTO) {
var translatedWeather = translateClient.translateEngToRussian(weatherDTO.getCity() + ", " + weatherDTO.getCondition()).split(", ");
return new String[]{
translatedWeather[0],
weatherDTO.getTemperature().toString(),
translatedWeather[1]};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,28 @@


public class Constants {
public static final String PLEASE_SET_CITY = "Введите, пожалуйста, название города или отправьте свою геолокацию";
private static final String WEATHER_IN_CITY_IS = "{city}, погода в нем: {temperature}, {condition}. ";
public static final String PLEASE_SET_CITY = "Введите, пожалуйста, название города или отправьте свою геолокацию\n";
private static final String WEATHER_IN_CITY_IS = "%s, погода в нем: %f, %s ";
public static final String START_MESSAGE = "Приветствую! " +
"Это WeatherBot - бот, с помощью которого можно получить информацию о погоде." + PLEASE_SET_CITY;
"Это WeatherBot - бот, с помощью которого можно получить информацию о погоде." + PLEASE_SET_CITY + "Чтобы увидеть все доступные через слеш команды, отправьте /help";
public static final String HELP_MESSAGE =
"Команды:\n" +
"/start - начало работы\n" +
"/update - получить информацию о текущей погоде";
public static final String ALREADY_SET_CITY =
"Вы уже пользовались этим ботом, сейчас ваш текущий город: " + WEATHER_IN_CITY_IS +
"Если хотите сменить город, то " + PLEASE_SET_CITY.toLowerCase();
public static final String FIRST_CITY_SET = "Поздравляю, вы выбрали " + WEATHER_IN_CITY_IS;
public static final String NEW_CITY_SETTED = "Вы обновили свой город на " + WEATHER_IN_CITY_IS;
public static final String CITY_NOT_FOUND = "Город {} не найден";
public static final String CITY_NOT_FOUND = "Город не найден, " + PLEASE_SET_CITY;
public static final String CITY_NOT_SET = "Извините, не могу предоставить погоду, так как вы еще не выбрали город. " + PLEASE_SET_CITY;
public static final String UNKNOWN_COMMAND = "Извините, я не знаю такой команды";
public static final String CHANGE_AVG_WEATHER = "Погода в городе {city} за последние 2 часа изменилась на целых {diff_temp}, текущая температура: {temp_now}";
public static final String ILLEGAL_CITY = "Извините, некорректное название города. Ваш текущий город: "
+ WEATHER_IN_CITY_IS + "Если хотите получить погоду в другом городе, то "
+ PLEASE_SET_CITY.toLowerCase();
public static final String CANT_UNDERSTAND = "Извините, я не понял, что вы имеете ввиду";
public static final String ERROR = "Внутренняя ошибка";
public static final String ERROR = "Просим прощения, город или погода в нем не найдены.";

public static final String CHOSE_MESSAGE = "Поздравляем, вы выбрали %s вашим городом.";
public static final String YES = "Да";
Expand Down
Loading

0 comments on commit 7e9f9ad

Please sign in to comment.