JavaRush /جاوا بلاگ /Random-SD /اسان گروپ مان آرٽيڪلز جي رڪنيت کي هٽائي ڇڏيو - "جاوا پروج...

اسان گروپ مان آرٽيڪلز جي رڪنيت کي هٽائي ڇڏيو - "جاوا پروجيڪٽ A کان Z تائين"

گروپ ۾ شايع ٿيل
هيلو سڀني کي، منهنجا پيارا دوست، مستقبل جي سينيئر سافٽ ويئر انجنيئرز. اسان هڪ ٽيليگرام بوٽ کي ترقي ڪرڻ جاري رکون ٿا. اسان جي پروجيڪٽ جي هن مرحلي ۾، اسان ٽن ڪمن تي غور ڪنداسين جيڪي پروگرام جي قيمت کان وڌيڪ نظر اچن ٿا. اسان کي سکڻ جي ضرورت آهي ته هڪ مخصوص گروپ مان نئين مضمونن جي رڪنيت کي ڪيئن هٽايو وڃي: بوٽ کي غير فعال ڪرڻ لاءِ /اسٽاپ ڪمانڊ استعمال ڪريو، ۽ ان کي چالو ڪرڻ لاءِ /start ڪمانڊ استعمال ڪريو . ان کان علاوه، سڀئي درخواستون ۽ تازه ڪاريون صرف بوٽ جي فعال استعمال ڪندڙن جي ڳڻتي ڪن ٿا. هميشه وانگر، اسين سڀ تبديليون حاصل ڪرڻ لاءِ مکيه شاخ کي تازه ڪاري ڪنداسين ۽ هڪ نئون ٺاهينداسين: STEP_7_JRTB-7. هن حصي ۾، اسان سبسڪرپشن کي ختم ڪرڻ بابت ڳالهائينداسين ۽ واقعن لاءِ 5 اختيارن تي غور ڪنداسين - اهو دلچسپ هوندو.

JRTB-7: گروپ مان نون مضمونن جي رڪنيت ختم ڪرڻ

اهو واضح آهي ته سڀئي صارف پنهنجي رڪنيت کي ختم ڪرڻ جي قابل ٿيڻ چاهيندا ته جيئن نون مضمونن بابت نوٽيفڪيشن حاصل نه ڪن. ان جو منطق تمام گهڻو ملندڙ جلندڙ هوندو رڪنيت شامل ڪرڻ جي منطق سان. جيڪڏهن اسان صرف هڪ حڪم موڪليندا آهيون، جواب ۾ اسان کي گروپن ۽ انهن جي سڃاڻپ جي هڪ فهرست ملندي جنهن ۾ صارف اڳ ۾ ئي سبسڪرائب ٿيل آهي، انهي ڪري اسان سمجهي سگهون ٿا ته ڇا واقعي کي ختم ڪرڻ جي ضرورت آهي. ۽ جيڪڏهن صارف ٽيم سان گڏ گروپ جي سڃاڻپ موڪلي ٿو، اسان رڪنيت ختم ڪنداسين. تنهن ڪري، اچو ته هن حڪم کي ٽيليگرام بوٽ جي پاسي کان ترقي ڪريون.
  1. اچو ته نئين ڪمانڊ جو نالو شامل ڪريون - /deleteGroupSub ، ۽ CommandName ۾ - لائن:

    DELETE_GROUP_SUB("/deleteGroupSub")

  2. اڳيون، اچو ته ٺاھيون DeleteGroupSubCommand حڪم :

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

ائين ڪرڻ لاءِ، اسان کي GroupSub اداري سان ڪم ڪرڻ لاءِ ٻه وڌيڪ طريقا شامل ڪرڻا پوندا - ID ذريعي ڊيٽابيس مان حاصل ڪرڻ ۽ خود اداري کي محفوظ ڪرڻ. اهي سڀئي طريقا صرف تيار ڪيل مخزن جا طريقا سڏين ٿا. مان توهان کي سبسڪرپشن کي ختم ڪرڻ بابت الڳ الڳ ٻڌائيندس. ڊيٽابيس اسڪيما ۾، هي ٽيبل آهي جيڪو ڪيترن ئي کان گھڻن عمل جي ذميوار آهي، ۽ هن رشتي کي ختم ڪرڻ لاء، توهان کي ان ۾ رڪارڊ کي ختم ڪرڻ جي ضرورت آهي. اھو آھي جيڪڏھن اسان ڊيٽابيس جي حصي تي عام سمجھ کي استعمال ڪريون. پر اسان اسپرنگ ڊيٽا استعمال ڪندا آهيون ۽ ڊفالٽ طور Hibernate هوندو آهي، جيڪو اهو مختلف طريقي سان ڪري سگهي ٿو. اسان حاصل ڪريون ٿا GroupSub ادارو، جنهن ڏانهن ان سان لاڳاپيل سڀئي صارف ٺاهيا ويندا. استعمال ڪندڙن جي هن مجموعن مان اسان هڪ کي هٽائينداسين جنهن کي اسان جي ضرورت آهي ۽ گروپسب کي واپس ڊيٽابيس ۾ محفوظ ڪنداسين، پر هن صارف کان سواء. هن طريقي سان اسپرنگ ڊيٽا سمجهي ويندي ته اسان ڇا چاهيون ٿا ۽ رڪارڊ کي حذف ڪريو. "جاوا پروجيڪٽ A کان Z تائين": گروپ مان آرٽيڪلز جي رڪنيت ختم ڪرڻ - 1"جاوا پروجيڪٽ A کان Z تائين": گروپ مان آرٽيڪلز جي رڪنيت کي ختم ڪرڻ - 2هڪ صارف کي جلدي هٽائڻ لاءِ، مون TelegramUser لاءِ EqualsAndHashCode تشريح شامل ڪئي، GroupSub لسٽ کي ڇڏي ته جيئن ڪو مسئلو نه ٿئي. ۽ استعمال ڪندڙ کي اسان جي ضرورت سان گڏ استعمال ڪندڙن جي گڏ ڪرڻ تي هٽائڻ جو طريقو سڏيو. هي اهو آهي جيڪو اهو ڏسڻ جهڙو آهي TelegramUser لاءِ:
@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;
}
نتيجي طور، هر شيء ختم ٿي وئي جيئن اسان چاهيون ٿا. هڪ ٽيم ۾ ڪيترائي ممڪن واقعا آهن، تنهنڪري انهن مان هر هڪ لاء سٺو امتحان لکڻ هڪ بهترين خيال آهي. تجربن جي ڳالهائيندي: جڏهن آئون انهن کي لکي رهيو هوس، مون کي منطق ۾ هڪ نقص مليو ۽ ان کي درست ڪيو ان کان اڳ جو اهو پيداوار ۾ جاري ڪيو ويو. جيڪڏهن ڪو امتحان نه هجي ها، اهو واضح ناهي ته اهو ڪيترو جلدي معلوم ٿئي ها. 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);
   }
}
هتي، هر ٽيسٽ هڪ الڳ منظر جي جانچ ڪري ٿو، ۽ مون کي توهان کي ياد ڏيارڻ ڏيو، انهن مان صرف پنج آهن:
  • جڏهن توهان صرف /deleteGroupSub ڪمانڊ پاس ڪيو ۽ اتي ڪو به گروپ رڪن نه آهي؛
  • جڏهن توهان صرف /deleteGroupSub ڪمانڊ پاس ڪيو ۽ گروپن جي رڪنيتون آهن؛
  • جڏهن هڪ غلط گروپ ID منظور ڪيو ويو، مثال طور، /deleteGroupSub abc ؛
  • هڪ منظر جنهن ۾ هر شيء صحيح طور تي ختم ٿي وئي آهي، جيئن توقع ڪئي وئي؛
  • هڪ منظر جڏهن گروپ ID صحيح آهي، پر اهڙو گروپ ڊيٽابيس ۾ نه آهي.
جئين توهان ڏسي سگهو ٿا، انهن سڀني منظرنامن کي ٽيسٽ سان ڍڪڻ جي ضرورت آهي. جڏهن مان لکي رهيو هوس، مون محسوس ڪيو ته بهتر ٽيسٽ لکڻ لاءِ، ڪجهه ٽيسٽنگ ڪورس وٺڻ جي قابل آهي. منهنجو خيال آهي ته هي مختلف اختيارن کي صحيح طور تي ڳولڻ ۾ مدد ڪندو. اھو صحيح آھي، مستقبل لاءِ سوچون. اڳيون، توھان کي وضاحت شامل ڪرڻ جي ضرورت آھي /help ڪمانڊ جيڪا توھان ھاڻي سبسڪرپشن کي ختم ڪري سگھو ٿا. اچو ته رڪنيت سان ڪم ڪرڻ لاء سيڪشن ۾ رکون. "جاوا پروجيڪٽ A کان Z تائين": گروپ مان آرٽيڪلز جي رڪنيت ختم ڪرڻ - 3يقينا، هن حڪم کي ڪم ڪرڻ لاء، توهان کي ان جي شروعات کي شامل ڪرڻ جي ضرورت آهي CommandContainer :
.put(DELETE_GROUP_SUB.getCommandName(),
       new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
ھاڻي توھان ٽيسٽ بٽ تي ڪارڪردگي کي جانچي سگھو ٿا. اسان پنهنجو ڊيٽابيس لانچ ڪيو docker-compose-test.yml: docker-compose-f docker-compose-test.yml up ۽ لانچ ڪيو اسپرنگ بوٽ IDEA ذريعي. مان بوٽ سان خط و ڪتابت کي مڪمل طور تي صاف ڪندس ۽ ٻيهر شروع ڪندس. مان انهن سڀني اختيارن جي ذريعي هلائيندس جيڪي پيدا ٿي سگهن ٿيون جڏهن هن ٽيم سان ڪم ڪندي. "جاوا پروجيڪٽ A کان Z تائين": گروپ مان آرٽيڪلز جي رڪنيت کي ختم ڪرڻ - 4جئين توهان اسڪرين شاٽ مان ڏسي سگهو ٿا، سڀ اختيار گذري ويا ۽ ڪامياب ٿي ويا.
دوستو! ڇا توھان فوري طور تي ڄاڻڻ چاھيو ٿا جڏھن ھڪڙي منصوبي لاء نئون ڪوڊ جاري ڪيو وڃي؟ نئون مضمون ڪڏهن نڪرندو؟ منهنجي ٽيليگرام چينل ۾ شامل ٿيو . اتي آئون گڏ ڪري پنهنجا آرٽيڪل، سوچون ۽ اوپن سورس ڊولپمينٽ گڏ ڪريان ٿو.
اسان پنهنجي پروجيڪٽ جي ورزن کي 0.6.0-SNAPSHOT تي اپڊيٽ ڪيو اسان تازه ڪاري ڪريون ٿا RELEASE_NOTES.md، ان جو تفصيل شامل ڪندي نئين ورزن ۾ ڇا ڪيو ويو آهي:
## 0.6.0-SNAPSHOT * JRTB-7: گروپ رڪنيت کي ختم ڪرڻ جي صلاحيت شامل ڪئي وئي.
ڪوڊ ڪم ڪري ٿو، ٽيسٽ ان لاءِ لکيو ويو آهي: اهو وقت آهي ڪم کي مخزن ۾ ڌڪڻ ۽ پل جي درخواست ٺاهي."جاوا پروجيڪٽ A کان Z تائين": گروپ مان آرٽيڪلز جي رڪنيت ختم ڪرڻ - 5

ختم ٿيڻ بدران

اسان گهڻو وقت تائين پنهنجي پروجيڪٽ بورڊ کي نه ڏٺو آهي، پر اتي وڏيون تبديليون آيون آهن: "جاوا پروجيڪٽ A کان Z تائين": گروپ مان آرٽيڪلز جي رڪنيت ختم ڪرڻ - 6صرف 5 ڪم رهجي ويا آهن. اھو آھي، توھان ۽ مان اڳ ۾ ئي روڊ جي بلڪل آخر ۾ آھيون. ٿورو ڇڏيو. اهو نوٽ ڪرڻ خاص طور تي دلچسپ آهي ته مضمونن جو هي سلسلو سيپٽمبر جي وچ کان هلي رهيو آهي، يعني 7 مهينن کان!!! جڏهن مان هن خيال سان آيو آهيان، مون کي اميد نه هئي ته اهو گهڻو وقت وٺندو. ساڳئي وقت، مان نتيجو کان وڌيڪ خوش آهيان! دوست، جيڪڏهن اهو واضح ناهي ته مضمون ۾ ڇا ٿي رهيو آهي، تبصرن ۾ سوال پڇو. انهي طريقي سان مان سمجهان ٿو ته ڪجهه بهتر بيان ڪرڻ جي ضرورت آهي، ۽ ڪجهه وڌيڪ وضاحت جي ضرورت آهي. خير، هميشه وانگر، پسند ڪريو - سبسڪرائب ڪريو - گھنٽي وڄايو، اسان جي پروجيڪٽ کي اسٽار ڏيو ، تبصرو لکو ۽ مضمون جي درجه بندي ڪريو! سڀني جي مهرباني. ايندڙ حصي تائين. اسان جلد ئي ڳالهائينداسين ته بوٽ کي غير فعال ڪرڻ ۽ چالو ڪرڻ کي ڪيئن شامل ڪيو وڃي /اسٽاپ ۽ /شروع حڪمن ذريعي ۽ انهن کي ڪيئن استعمال ڪجي. بعد ۾ ملون ٿا!

سيريز ۾ سڀني مواد جي هڪ فهرست هن مضمون جي شروعات ۾ آهي.

تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION