Hər kəsə salam, əziz dostlarım, gələcəyin Baş Proqram Mühəndisləri. Biz teleqram botunu inkişaf etdirməyə davam edirik. Layihəmizin bu addımında proqram dəyərindən daha çox görünən dəyəri olan üç tapşırığı nəzərdən keçirəcəyik. Müəyyən bir qrupdan yeni məqalələrə abunəni necə silməyi öyrənməliyik: botu deaktiv etmək üçün /stop əmrindən istifadə edin və onu aktivləşdirmək üçün /start əmrindən istifadə edin. Üstəlik, bütün sorğular və yeniləmələr yalnız botun aktiv istifadəçilərinə aiddir. Həmişə olduğu kimi, bütün dəyişiklikləri əldə etmək və yenisini yaratmaq üçün əsas filialı yeniləyəcəyik : STEP_7_JRTB-7. Bu hissədə abunəni silmək haqqında danışacağıq və hadisələr üçün 5 variantı nəzərdən keçirəcəyik - maraqlı olacaq.
Layihəmizin versiyasını 0.6.0-SNAPSHOT-a yeniləyirik, yeni versiyada görülənlərin təsvirini əlavə etməklə RELEASE_NOTES.md-ni yeniləyirik:
bəyənin - abunə olun - zəngi vurun, layihəmizə ulduz verin , şərh yazın və məqaləni qiymətləndirin! Hamıya təşəkkürlər. Növbəti hissəyə qədər. Tezliklə /stop & /start əmrləri vasitəsilə botun deaktivasiyası və aktivləşdirilməsini necə əlavə etmək və onlardan ən yaxşı şəkildə necə istifadə etmək barədə danışacağıq . Sonra görüşənədək!
JRTB-7: qrupdan yeni məqalələrə abunəliyin silinməsi
Aydındır ki, bütün istifadəçilər yeni məqalələr haqqında bildiriş almamaq üçün abunəliklərini silmək istəyəcəklər. Onun məntiqi abunə əlavə etmək məntiqinə çox oxşar olacaq. Yalnız bir əmr göndərsək, cavab olaraq istifadəçinin artıq abunə olduğu qrupların siyahısını və onların identifikatorlarını alacağıq ki, dəqiq nəyin silinməli olduğunu başa düşək. İstifadəçi qrup ID-ni komanda ilə birlikdə göndərərsə, abunəni siləcəyik. Buna görə də gəlin telegram bot tərəfindən bu əmri inkişaf etdirək.-
Gəlin yeni əmrin adını əlavə edək - /deleteGroupSub , və CommandName -ə - sətri:
DELETE_GROUP_SUB("/deleteGroupSub")
-
Sonra, DeleteGroupSubCommand əmrini yaradaq :
package com.github.javarushcommunity.jrtb.command; import com.github.javarushcommunity.jrtb.repository.entity.GroupSub; import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser; import com.github.javarushcommunity.jrtb.service.GroupSubService; import com.github.javarushcommunity.jrtb.service.SendBotMessageService; import com.github.javarushcommunity.jrtb.service.TelegramUserService; import org.springframework.util.CollectionUtils; import org.telegram.telegrambots.meta.api.objects.Update; import javax.ws.rs.NotFoundException; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import static com.github.javarushcommunity.jrtb.command.CommandName.DELETE_GROUP_SUB; import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId; import static com.github.javarushcommunity.jrtb.command.CommandUtils.getMessage; import static java.lang.String.format; import static org.apache.commons.lang3.StringUtils.SPACE; import static org.apache.commons.lang3.StringUtils.isNumeric; /** * Delete Group subscription {@link Command}. */ public class DeleteGroupSubCommand implements Command { private final SendBotMessageService sendBotMessageService; private final TelegramUserService telegramUserService; private final GroupSubService groupSubService; public DeleteGroupSubCommand(SendBotMessageService sendBotMessageService, GroupSubService groupSubService, TelegramUserService telegramUserService) { this.sendBotMessageService = sendBotMessageService; this.groupSubService = groupSubService; this.telegramUserService = telegramUserService; } @Override public void execute(Update update) { if (getMessage(update).equalsIgnoreCase(DELETE_GROUP_SUB.getCommandName())) { sendGroupIdList(getChatId(update)); return; } String groupId = getMessage(update).split(SPACE)[1]; String chatId = getChatId(update); if (isNumeric(groupId)) { Optional<GroupSub> optionalGroupSub = groupSubService.findById(Integer.valueOf(groupId)); if (optionalGroupSub.isPresent()) { GroupSub groupSub = optionalGroupSub.get(); TelegramUser telegramUser = telegramUserService.findByChatId(chatId).orElseThrow(NotFoundException::new); groupSub.getUsers().remove(telegramUser); groupSubService.save(groupSub); sendBotMessageService.sendMessage(chatId, format("Удалил подписку на группу: %s", groupSub.getTitle())); } else { sendBotMessageService.sendMessage(chatId, "Не нашел такой группы =/"); } } else { sendBotMessageService.sendMessage(chatId, "неправильный формат ID группы.\n " + "ID должно быть целым положительным числом"); } } private void sendGroupIdList(String chatId) { String message; List<GroupSub> groupSubs = telegramUserService.findByChatId(chatId) .orElseThrow(NotFoundException::new) .getGroupSubs(); if (CollectionUtils.isEmpty(groupSubs)) { message = "Пока нет подписок на группы. Whatбы добавить подписку напиши /addGroupSub"; } else { message = "Whatбы удалить подписку на группу - передай комадну вместе с ID группы. \n" + "Например: /deleteGroupSub 16 \n\n" + "я подготовил список всех групп, на которые ты подписан) \n\n" + "Name группы - ID группы \n\n" + "%s"; } String userGroupSubData = groupSubs.stream() .map(group -> format("%s - %s \n", group.getTitle(), group.getId())) .collect(Collectors.joining()); sendBotMessageService.sendMessage(chatId, format(message, userGroupSubData)); } }
@Data
@Entity
@Table(name = "tg_user")
@EqualsAndHashCode(exclude = "groupSubs")
public class TelegramUser {
@Id
@Column(name = "chat_id")
private String chatId;
@Column(name = "active")
private boolean active;
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
}
Nəticədə hər şey istədiyimiz kimi alındı. Komandada bir neçə mümkün hadisə var, ona görə də onların hər biri üçün yaxşı bir test yazmaq əla fikirdir. Testlərdən söz düşmüşkən: onları yazarkən məntiqdə bir qüsur tapdım və istehsala buraxılmamışdan əvvəl düzəltdim. Əgər test olmasaydı, onun nə qədər tez aşkar ediləcəyi bəlli deyil. DeleteGroupSubCommandTest:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.ArrayList;
import java.util.Optional;
import static com.github.javarushcommunity.jrtb.command.AbstractCommandTest.prepareUpdate;
import static com.github.javarushcommunity.jrtb.command.CommandName.DELETE_GROUP_SUB;
import static java.util.Collections.singletonList;
@DisplayName("Unit-level testing for DeleteGroupSubCommand")
class DeleteGroupSubCommandTest {
private Command command;
private SendBotMessageService sendBotMessageService;
GroupSubService groupSubService;
TelegramUserService telegramUserService;
@BeforeEach
public void init() {
sendBotMessageService = Mockito.mock(SendBotMessageService.class);
groupSubService = Mockito.mock(GroupSubService.class);
telegramUserService = Mockito.mock(TelegramUserService.class);
command = new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService);
}
@Test
public void shouldProperlyReturnEmptySubscriptionList() {
//given
Long chatId = 23456L;
Update update = prepareUpdate(chatId, DELETE_GROUP_SUB.getCommandName());
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(new TelegramUser()));
String expectedMessage = "Пока нет подписок на группы. Whatбы добавить подписку напиши /addGroupSub";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldProperlyReturnSubscriptionLit() {
//given
Long chatId = 23456L;
Update update = prepareUpdate(chatId, DELETE_GROUP_SUB.getCommandName());
TelegramUser telegramUser = new TelegramUser();
GroupSub gs1 = new GroupSub();
gs1.setId(123);
gs1.setTitle("GS1 Title");
telegramUser.setGroupSubs(singletonList(gs1));
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "Whatбы удалить подписку на группу - передай комадну вместе с ID группы. \n" +
"Например: /deleteGroupSub 16 \n\n" +
"я подготовил список всех групп, на которые ты подписан) \n\n" +
"Name группы - ID группы \n\n" +
"GS1 Title - 123 \n";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldRejectByInvalidGroupId() {
//given
Long chatId = 23456L;
Update update = prepareUpdate(chatId, String.format("%s %s", DELETE_GROUP_SUB.getCommandName(), "groupSubId"));
TelegramUser telegramUser = new TelegramUser();
GroupSub gs1 = new GroupSub();
gs1.setId(123);
gs1.setTitle("GS1 Title");
telegramUser.setGroupSubs(singletonList(gs1));
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "неправильный формат ID группы.\n " +
"ID должно быть целым положительным числом";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldProperlyDeleteByGroupId() {
//given
/// prepare update object
Long chatId = 23456L;
Integer groupId = 1234;
Update update = prepareUpdate(chatId, String.format("%s %s", DELETE_GROUP_SUB.getCommandName(), groupId));
GroupSub gs1 = new GroupSub();
gs1.setId(123);
gs1.setTitle("GS1 Title");
TelegramUser telegramUser = new TelegramUser();
telegramUser.setChatId(chatId.toString());
telegramUser.setGroupSubs(singletonList(gs1));
ArrayList<TelegramUser> users = new ArrayList<>();
users.add(telegramUser);
gs1.setUsers(users);
Mockito.when(groupSubService.findById(groupId)).thenReturn(Optional.of(gs1));
Mockito.when(telegramUserService.findByChatId(String.valueOf(chatId)))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "Удалил подписку на группу: GS1 Title";
//when
command.execute(update);
//then
users.remove(telegramUser);
Mockito.verify(groupSubService).save(gs1);
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
@Test
public void shouldDoesNotExistByGroupId() {
//given
Long chatId = 23456L;
Integer groupId = 1234;
Update update = prepareUpdate(chatId, String.format("%s %s", DELETE_GROUP_SUB.getCommandName(), groupId));
Mockito.when(groupSubService.findById(groupId)).thenReturn(Optional.empty());
String expectedMessage = "Не нашел такой группы =/";
//when
command.execute(update);
//then
Mockito.verify(groupSubService).findById(groupId);
Mockito.verify(sendBotMessageService).sendMessage(chatId.toString(), expectedMessage);
}
}
Burada hər test ayrı bir ssenarini yoxlayır və sizə xatırlatmağa icazə verin, onlardan yalnız beşi var:
- siz sadəcə /deleteGroupSub əmrini keçdiyiniz zaman və qrup abunələri olmadıqda;
- sadəcə /deleteGroupSub əmrini keçdiyiniz zaman və qruplara abunə olduqda;
- etibarsız qrup ID-si ötürüldükdə, məsələn, /deleteGroupSub abc ;
- gözlənildiyi kimi hər şeyin düzgün silindiyi bir ssenari;
- qrup identifikatorunun etibarlı olduğu, lakin belə bir qrup verilənlər bazasında olmadığı bir ssenari.
.put(DELETE_GROUP_SUB.getCommandName(),
new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
İndi siz test botunda funksionallığı yoxlaya bilərsiniz. Biz verilənlər bazamızı docker-compose-test.yml istifadə edərək işə salırıq: docker-compose -f docker-compose-test.yml up Və IDEA vasitəsilə SpringBoot-u işə salın. Mən botla yazışmaları tamamilə təmizləyib yenidən başlayacağam. Bu komanda ilə işləyərkən yarana biləcək bütün variantları nəzərdən keçirəcəyəm. Ekran görüntüsündən göründüyü kimi, bütün seçimlər keçdi və uğurlu oldu.
Dostlar! Layihə üçün yeni kodun nə vaxt buraxıldığını dərhal bilmək istəyirsiniz? Yeni məqalə nə vaxt çıxır? Telegram kanalıma qoşulun . Orada məqalələrimi, düşüncələrimi və açıq mənbə inkişafımı bir yerdə toplayıram. |
## 0.6.0-SNAPSHOT * JRTB-7: qrup abunəliyini silmək imkanı əlavə edildi.
Kod işləyir, bunun üçün testlər yazılmışdır: tapşırığı depoya yerləşdirmək və çəkmə sorğusu yaratmaq vaxtıdır.
GO TO FULL VERSION