JavaRush /Java Blog /Random EN /We add the ability to subscribe to a group of articles. (...

We add the ability to subscribe to a group of articles. (Part 3) - "Java project from A to Z"

Published in the Random EN group
Hi again. This is the final article from STEP_6 where we will talk about adding JRTB-6 task functionality . In those two previous articles ( part 1 , part 2 ) we have already prepared almost everything that is needed. This part is the culmination of the process. To everyone who has read this series of articles up to this point from the very beginning - great respect. This means that the motivation is enough to find a great job. And now let's get down to business."Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 1

Implementing JRTB-6

This time we will do the task on the part of the telegram bot, because the work on updating the database is all done, the database entities are configured and ready to go. Let's add a new value to CommandName - LIST_GROUP_SUB:
LIST_GROUP_SUB("/listGroupSub");
Let's create a ListGroupSubCommand command :
package com.github.codegymcommunity.jrtb.command;

import com.github.codegymcommunity.jrtb.repository.entity.GroupSub;
import com.github.codegymcommunity.jrtb.repository.entity.TelegramUser;
import com.github.codegymcommunity.jrtb.service.SendBotMessageService;
import com.github.codegymcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;

import javax.ws.rs.NotFoundException;
import java.util.stream.Collectors;

import static com.github.codegymcommunity.jrtb.command.CommandUtils.getChatId;

/**
* {@link Command} for getting list of {@link GroupSub}.
*/
public class ListGroupSubCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final TelegramUserService telegramUserService;

   public ListGroupSubCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       //todo add exception handling
       TelegramUser telegramUser = telegramUserService.findByChatId(getChatId(update))
               .orElseThrow(NotFoundException::new);

       String message = "Я нашел все подписки на группы: \n\n";
       String collectedGroups = telegramUser.getGroupSubs().stream()
               .map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
               .collect(Collectors.joining());

       sendBotMessageService.sendMessage(telegramUser.getChatId(), message + collectedGroups);
   }
}
Here everything is as simple as possible - we get the user from the existing chat_id, and all his subscriptions to groups will be collected in the object. We set it up in the second part. Again, I added //todo so as not to forget to add exception handling that may appear during operation. The next step is to update the CommandContainer by adding a new command to it:
put(LIST_GROUP_SUB.getCommandName(), new GroupSubListCommand(sendBotMessageService, telegramUserService))
In fact, everything: now you need to write more tests, update the /help command (add a description for new commands) and test the new functionality through Telegram. Let's write a test for ListGroupSubCommand . Since the logic of the command is not typical, we will write a test without being tied to the AbstractCommandTest class, as we did before:
package com.github.codegymcommunity.jrtb.command;

import com.github.codegymcommunity.jrtb.repository.entity.GroupSub;
import com.github.codegymcommunity.jrtb.repository.entity.TelegramUser;
import com.github.codegymcommunity.jrtb.service.SendBotMessageService;
import com.github.codegymcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.github.codegymcommunity.jrtb.command.CommandName.LIST_GROUP_SUB;

@DisplayName("Unit-level testing for ListGroupSubCommand")
public class ListGroupSubCommandTest {

   @Test
   public void shouldProperlyShowsListGroupSub() {
       //given
       TelegramUser telegramUser = new TelegramUser();
       telegramUser.setActive(true);
       telegramUser.setChatId("1");

       List<GroupSub> groupSubList = new ArrayList<>();
       groupSubList.add(populateGroupSub(1, "gs1"));
       groupSubList.add(populateGroupSub(2, "gs2"));
       groupSubList.add(populateGroupSub(3, "gs3"));
       groupSubList.add(populateGroupSub(4, "gs4"));

       telegramUser.setGroupSubs(groupSubList);

       SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
       TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);

       Mockito.when(telegramUserService.findByChatId(telegramUser.getChatId())).thenReturn(Optional.of(telegramUser));

       ListGroupSubCommand command = new ListGroupSubCommand(sendBotMessageService, telegramUserService);

       Update update = new Update();
       Message message = Mockito.mock(Message.class);
       Mockito.when(message.getChatId()).thenReturn(Long.valueOf(telegramUser.getChatId()));
       Mockito.when(message.getText()).thenReturn(LIST_GROUP_SUB.getCommandName());
       update.setMessage(message);

       String collectedGroups = "Я нашел все подписки на группы: \n\n" +
               telegramUser.getGroupSubs().stream()
                       .map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
                       .collect(Collectors.joining());

       //when
       command.execute(update);

       //then
       Mockito.verify(sendBotMessageService).sendMessage(telegramUser.getChatId(), collectedGroups);
   }

   private GroupSub populateGroupSub(Integer id, String title) {
       GroupSub gs = new GroupSub();
       gs.setId(id);
       gs.setTitle(title);
       return gs;
   }
}

Update /help command

In our case, the /help command acts as documentation for working with the bot, so you need to remember to update it so that the user can use it. We have added two commands, so we will update the text that will come:
public static final String HELP_MESSAGE = String.format("✨Дотупные команды✨\n\n"

               + "Начать\\закончить работу с ботом:\n"
               + "%s - начать работу со мной\n"
               + "%s - приостановить работу со мной\n\n"

               + "Работа с подписками на группы:\n"
               + "%s - подписаться на группу статей\n"
               + "%s - получить список групп, на которые подписан\n\n"

               + "%s - получить помощь в работе со мной\n"
               + "%s - получить мою статистику использования\n",
       START.getCommandName(), STOP.getCommandName(), ADD_GROUP_SUB.getCommandName(),
       LIST_GROUP_SUB.getCommandName(), HELP.getCommandName(), STAT.getCommandName());
I also updated the text of the bot’s responses: I made it so that it was always on “you” with the user, otherwise there was both “you” and “you” ... Now it will be possible to create at least some connection in the work of the bot.

Testing the work of the updated bot

Run our bot locally and do the following:
  1. We execute the /start command - to be sure that the user in the test case is added to the database.
  2. We execute the /help command - we check that everything is OK, as we wanted.
  3. Next, execute the /addGroupSub command.
  4. From the proposed list of group IDs, we add a few to the discord.
  5. Run the /listGroupSub command to make sure that the groups are written to the user.
Go! We start the database through docker-compose-test.yml and start our SpringBoot. Next, we go into our test bot and execute the /start command, followed by /help : "Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 2Next, enter the /addGroupSub command : "Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 3The drop-down list says that the Java client is working as it should: we have all the groups with their IDs, a description of the command helps (hopefully) understand what we need next, so we add some groups to the subscription: "Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 4Now we have 5 subscriptions, so we can run the command /listGroupSub : "Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 5And then we get some kind of game... It is not clear why the title was just showing without any problems, but not here. Let's go to the database to see what's there:"Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 6The database contains the same questions, but only for those in Cyrillic. So there is some problem with the encoding. It is necessary to configure, apparently, the database and the driver for connecting to the database. We need UTF-8. But how to add it? After a few minutes of searching the Internet, I found : for the driver, you need to update the url variable. And to configure the docker image in docker-compose, in general, the very first link , but the answer is not the first)) Therefore, knowing this, we will update the properties and docker-compose files.
application.properties:
spring.datasource.url=jdbc:mysql://jrtb-db:3306/jrtb_db?characterEncoding=UTF-8

application-test.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/dev_jrtb_db?characterEncoding=UTF-8

docker-compose.yml (добавил последнюю строку):
jrtb-db:
 image: mysql:5.7
 restart: always
 environment:
   MYSQL_USER: ${BOT_DB_USERNAME}
   MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
   MYSQL_DATABASE: 'jrtb_db'
   MYSQL_ROOT_PASSWORD: 'root'
 ports:
   - '3306:3306'
 expose:
   - '3306'
 command: --character-set-server=utf8 --collation-server=utf8_general_ci

docker-compose-test.yml (добавил последнюю строку)
jrtb-db-dev:
 image: mysql:5.7
 restart: always
 environment:
   MYSQL_DATABASE: 'dev_jrtb_db'
   # So you don't have to use root, but you can if you like
   MYSQL_USER: 'dev_jrtb_db_user'
   # You can use whatever password you like
   MYSQL_PASSWORD: 'dev_jrtb_db_password'
   # Password for root access
   MYSQL_ROOT_PASSWORD: 'root'
 ports:
   # <Port exposed> : < MySQL Port running inside container>
   - '3306:3306'
 expose:
   # Opens port 3306 on the container
     - '3306'
 command: --character-set-server=utf8 --collation-server=utf8_general_ci
After these updates, you need to erase all the data in the database and start over. Deleting is very simple: you need to run the command: docker-compose -f docker-compose-test.yml down after which all data and the database are deleted. And run again, with the updated encoding: docker-compose -f docker-compose-test.uml up The database is ready. We launch the updated application and look. I'll run quickly and show the result: "Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 7And now we got exactly what we wanted. This already looks like the truth.

Ending

Now I think that it is possible to complete the work on this step. A lot has been done, really a lot. Let's update the application version to 0.5.0-SNAPSHOT and RELEASE_NOTES.
# Release Notes ## 0.5.0-SNAPSHOT * JRTB-5: added ability to subscribe on group * JRTB-6: added ability to get a list of group subscriptions.
Then everything is as usual: we create a new commit with all the changes. The main thing is to add a description of the two tasks that were done during this step for reporting. So here is the comment:
STEP_6 JRTB-5: added ability to subscribe on group JRTB-6: added ability to see the list of the group subscription.
As a result, 47 modified files came out ... This is a big change. Although you can't tell from the description of the functionality. After all, in order to understand the full depth, you need to know that you need to write a Java client for the API, update the entire application in essence. This is how it is, work on the server - there is a lot of work, and visibility from the client side is small ...)) Friends, I traditionally offer you a way to show interest in my work - subscribe to a github account , join the telegram channel and write a question about the article, if something is not clear! Here is a link to a pull request with changes for this STEP_6 . Thank you all for reading. Further more - let's talk about deleting a subscription, deactivating a profile, and more. Don't switch))"Java project from A to Z": Adding the ability to subscribe to a group of articles.  Part 3 - 8

List of all materials in the series at the beginning of this article.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION