JavaRush /Java Blog /Random-TK /Topardan makalalara abunalygy aýyrýarys - "Java taslamasy...

Topardan makalalara abunalygy aýyrýarys - "Java taslamasy A-dan Z"

Toparda çap edildi
Hemmelere salam, gadyrly dostlarym, geljekki uly programma inersenerleri. Telegram botyny ösdürmegi dowam etdirýäris. Taslamamyzyň bu ädiminde, programma bahasyndan has göze görünýän üç meseläni göz öňünde tutarys. Belli bir topardan täze makalalara abunalygy nädip aýyrmalydygyny öwrenmeli: boty ýapmak üçin / stop buýrugyny ulanyň we işjeňleşdirmek üçin / start buýrugyny ulanyň. Mundan başga-da, ähli haýyşlar we täzelenmeler diňe botyň işjeň ulanyjylaryna degişlidir. Hemişe bolşy ýaly, ähli üýtgeşmeleri almak we täzesini döretmek üçin esasy şahany täzeläris : STEP_7_JRTB-7. Bu bölümde, abunalygy pozmak barada gürleşeris we wakalar üçin 5 warianty gözden geçireris - gyzykly bolar.

JRTB-7: topardan täze makalalara abunalygy aýyrmak

Usershli ulanyjylaryň täze makalalar barada habarnamalar almazlygy üçin abunalyklaryny pozmak islejekdikleri düşnüklidir. Onuň logikasy, abuna ýazmagyň logikasyna gaty meňzeýär. Diňe bir buýruk ibersek, jogap hökmünde ulanyjynyň eýýäm abuna ýazylan toparlarynyň we şahsyýetnamalarynyň sanawyny alarys, şonuň üçin nämäniň ýok edilmelidigine düşüneris. Ulanyjy topar bilen bilelikde topar ID-ni iberse, abunalygy pozarys. Şonuň üçin geliň, bu buýrugy telegramma bot tarapyndan ösdüreliň.
  1. Täze buýrugyň adyny goşalyň - / deleteGroupSub , we CommandName - setirde:

    DELETE_GROUP_SUB("/deleteGroupSub")

  2. Ondan soň, DeleteGroupSubCommand buýrugyny döredeliň :

    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));
       }
    }

Munuň üçin GroupSub guramasy bilen işlemek üçin ýene iki usul goşmaly bolduk - maglumatlar bazasyndan ID-den almak we guramanyň özüni halas etmek. Bu usullaryň hemmesi diňe taýýar ammar usullary diýilýär. Abunalygy pozmak barada size aýratyn aýdaryn. Maglumatlar bazasynyň shemasynda bu köp sanly prosese jogap berýän tablisadyr we bu gatnaşygy pozmak üçin içindäki ýazgyny pozmaly. Maglumat bazasynyň umumy düşünjesini ulanýan bolsak. Springöne “Bahar maglumatlary” ulanýarys we muny başgaça edip bilýän “Gibernate” bar. “GroupSub” guramasyny alýarys, oňa degişli ähli ulanyjylar çekiler. Ulanyjylaryň bu ýygyndysyndan zerur birini aýyrarys we groupSub-y maglumatlar bazasyna ýazdyrarys, ýöne bu ulanyjy bolmasa. Şeýlelik bilen Bahar maglumatlary islän zadymyza düşüner we ýazgyny pozar. "Java taslamasy A-dan Z": Topardaky makalalara abunalygy aýyrmak - 1"Java taslamasy A-dan Z": Topardaky makalalara abunalygy aýyrmak - 2Ulanyjyny çalt aýyrmak üçin, TelegramUser üçin EqualsAndHashCode düşündirişini goşdum, kynçylyk bolmazlygy üçin GroupSub sanawyndan başga. Gerekli ulanyjy bilen ulanyjylary ýygnamakda aýyrmak usuly diýilýär. TelegramUser üçin görnüşi:
@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;
}
Netijede, hemme zat isleýşimiz ýaly aýryldy. Toparda birnäçe bolup biljek wakalar bar, şonuň üçin olaryň her biri üçin gowy synag ýazmak gaty gowy pikir. Synaglar barada aýdanymda: ýazýan wagtym logikada bir kemçilik tapdym we önümçilige çykmazdan ozal düzedipdim. Synag bolmadyk bolsa, nädip çalt tapylandygy belli däl. 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);
   }
}
Ynha, her synag aýratyn bir ssenariýany barlaýar we size ýatladýaryn, olaryň diňe bäşisi bar:
  • ýönekeý / deleteGroupSub buýrugyny geçeniňizde we topar abunalygy ýok bolsa;
  • ýönekeý / deleteGroupSub buýrugyny geçeniňizde we toparlara abuna ýazylanda;
  • nädogry topar ID-si geçensoň, mysal üçin / deleteGroupSub abc ;
  • garaşylyşy ýaly hemme zat dogry pozulýan ssenariýa;
  • topar ID-si dogry bolan ssenariýa, ýöne beýle topar maglumatlar bazasynda ýok.
Görşüňiz ýaly, bu ssenariýalaryň hemmesi synaglar bilen örtülmeli. Writingazýarkam, has gowy synag ýazmak üçin käbir synag kurslaryny geçmegiň zerurdygyna düşündim. Bu dürli wariantlary dogry gözlemäge kömek eder diýip pikir edýärin. Dogry, geljek hakda pikirler. Ondan soň, abunalygy pozup boljak / kömek buýrugyna düşündiriş goşmaly . Abunalar bilen işlemek üçin bölüme ýerleşdireliň. Elbetde, bu buýrugyň işlemegi üçin, onuň başlangyjyny CommandContainer"Java taslamasy A-dan Z": Topardaky makalalara abunalygy aýyrmak - 3 -e goşmaly :
.put(DELETE_GROUP_SUB.getCommandName(),
       new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
Indi synag botunda işlemegi synap bilersiňiz. Maglumatlar bazamyzy docker-compose-test.yml: docker-compose -f docker-compose-test.yml ulanyp ulanýarys we IDEA arkaly SpringBoot-y işe girizýäris. Bot bilen hat alyşmagy doly aýyraryn we täzeden başlaryn. Bu topar bilen işleşenimde ýüze çykyp biljek ähli wariantlary öwrenerin. "Java taslamasy A-dan Z": Topardaky makalalara abunalygy aýyrmak - 4Skrinshotdan görnüşi ýaly, ähli wariantlar geçdi we üstünlikli boldy.
Dostlar! Taslama üçin täze kod çykanda derrew bilmek isleýärsiňizmi? Täze makala haçan çykýar? Telegram kanalyma goşulyň . Şol ýerde makalalarymy, pikirlerimi we açyk çeşmäni ösdürmegi bilelikde ýygnaýaryn.
Taslamamyzyň wersiýasyny 0.6.0-SNAPSHOT-a täzeleýäris, täze wersiýada edilen zatlaryň beýanyny goşup, RELEASE_NOTES.md täzeleýäris:
## 0.6.0-SNAPSHOT * JRTB-7: topara abuna ýazylmak mümkinçiligini goşdy.
Kod işleýär, synaglar ýazyldy: meseläni ammara itergi bermek we çekmek haýyşyny döretmegiň wagty geldi."Java taslamasy A-dan Z-a": Topardan makalalara abunalygy aýyrmak - 5

Soňunyň ýerine

Uzak wagt bäri taslama tagtamyza seredip görmedik, ýöne uly üýtgeşmeler boldy: "Java taslamasy A-dan Z": Topardan makalalara abunalygy aýyrmak - 6bary-ýogy 5 mesele galdy. Youagny, siz we men eýýäm ýoluň iň soňunda. Az salym Bu makalalaryň tapgyrynyň sentýabryň ortalaryndan bäri, ýagny 7 aý bäri işleýändigini bellemek gyzykly! Bu pikiri orta atanymda, munuň gaty uzaga çekmegine garaşmaýardym. Şol bir wagtyň özünde, netijeden has hoşal! Dostlar, makalada nämeleriň bolup geçýändigi düşnüksiz bolsa, teswirlerde sorag beriň. Şeýdip, bir zadyň has gowy düşündirilmelidigini we bir zadyň has giňişleýin düşündirilmeginiň zerurdygyny bilerin. Bolýar, hemişeki ýaly, ýazylmak - jaňy jaň etmek, taslamamyza ýyldyz bermek , teswir ýazmak we makala baha bermek! Hemmäňize sag bolsun aýdýaryn. Indiki bölüme çenli. Botlary öçürmek we işjeňleşdirmek / stop & / start buýruklary arkaly nädip goşmalydygy we olary nädip has gowy ulanmalydygy barada ýakyn wagtda gürleşeris . Soň görüşeris!

Tapgyryň ähli materiallarynyň sanawy bu makalanyň başynda.

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