JavaRush /جاوا بلاگ /Random-UR /ہم گروپ سے مضامین کی سبسکرپشن کو ہٹا دیتے ہیں - "جاوا پرو...

ہم گروپ سے مضامین کی سبسکرپشن کو ہٹا دیتے ہیں - "جاوا پروجیکٹ A سے Z تک"

گروپ میں شائع ہوا۔
سب کو ہیلو، میرے پیارے دوست، مستقبل کے سینئر سافٹ ویئر انجینئرز۔ ہم ٹیلیگرام بوٹ تیار کرنا جاری رکھے ہوئے ہیں۔ اپنے پروجیکٹ کے اس مرحلے میں، ہم تین کاموں پر غور کریں گے جن کی قیمت پروگرام کی قیمت سے زیادہ نظر آتی ہے۔ ہمیں یہ سیکھنے کی ضرورت ہے کہ کسی مخصوص گروپ سے نئے مضامین کی رکنیت کو کیسے ہٹایا جائے: بوٹ کو غیر فعال کرنے کے لیے /stop کمانڈ استعمال کریں، اور اسے فعال کرنے کے لیے /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 entity کے ساتھ کام کرنے کے لیے مزید دو طریقے شامل کرنے ہوں گے - ID کے ذریعے ڈیٹا بیس سے بازیافت کرنا اور خود ادارے کو محفوظ کرنا۔ یہ تمام طریقے صرف ریڈی میڈ ریپوزٹری کے طریقے کہتے ہیں۔ میں آپ کو سبسکرپشن کو حذف کرنے کے بارے میں الگ سے بتاؤں گا۔ ڈیٹا بیس اسکیما میں، یہ وہ جدول ہے جو کئی سے کئی کے عمل کے لیے ذمہ دار ہے، اور اس تعلق کو حذف کرنے کے لیے، آپ کو اس میں موجود ریکارڈ کو حذف کرنا ہوگا۔ یہ ہے اگر ہم ڈیٹا بیس کے حصے پر عام فہم کا استعمال کریں۔ لیکن ہم اسپرنگ ڈیٹا استعمال کرتے ہیں اور ڈیفالٹ کے طور پر ہائبرنیٹ ہوتا ہے، جو اسے مختلف طریقے سے کر سکتا ہے۔ ہمیں GroupSub entity ملتی ہے، جس کی طرف اس سے وابستہ تمام صارفین کھینچے جائیں گے۔ صارفین کے اس مجموعہ سے ہم اسے ہٹا دیں گے جس کی ہمیں ضرورت ہے اور گروپسب کو واپس ڈیٹا بیس میں محفوظ کریں گے، لیکن اس صارف کے بغیر۔ اس طرح اسپرنگ ڈیٹا سمجھ جائے گا کہ ہم کیا چاہتے ہیں اور ریکارڈ کو حذف کر دیں گے۔ "A سے Z تک جاوا پروجیکٹ": گروپ سے مضامین کی رکنیت کو ہٹانا - 1"A سے Z تک جاوا پروجیکٹ": گروپ سے مضامین کی رکنیت کو ہٹانا - 2کسی صارف کو جلدی سے ہٹانے کے لیے، میں نے TelegramUser کے لیے EqualsAndHashCode تشریح شامل کی، گروپسب کی فہرست کو چھوڑ کر تاکہ کوئی مسئلہ نہ ہو۔ اور ہمیں ضرورت والے صارف کے ساتھ صارفین کے مجموعہ پر ہٹانے کا طریقہ کہا جاتا ہے۔ 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 کا استعمال کرتے ہوئے اپنا ڈیٹا بیس لانچ کرتے ہیں اور IDEA کے ذریعے SpringBoot لانچ کرتے ہیں۔ میں بوٹ کے ساتھ خط و کتابت کو مکمل طور پر صاف کر کے دوبارہ شروع کروں گا۔ میں اس ٹیم کے ساتھ کام کرنے کے دوران پیدا ہونے والے تمام آپشنز کو دیکھوں گا۔ "A سے Z تک جاوا پروجیکٹ": گروپ سے مضامین کی رکنیت کو ہٹانا - 4جیسا کہ آپ اسکرین شاٹ سے دیکھ سکتے ہیں، تمام آپشنز گزرے اور کامیاب رہے۔
دوستو! کیا آپ فوری طور پر جاننا چاہتے ہیں کہ جب کسی پروجیکٹ کے لیے نیا کوڈ جاری ہوتا ہے؟ نیا مضمون کب آتا ہے؟ میرا ٹیلیگرام چینل جوائن کریں ۔ وہاں میں اپنے مضامین، خیالات اور اوپن سورس ڈویلپمنٹ کو اکٹھا کرتا ہوں۔
ہم اپنے پروجیکٹ کے ورژن کو 0.6.0-SNAPSHOT میں اپ ڈیٹ کرتے ہیں ہم RELEASE_NOTES.md کو اپ ڈیٹ کرتے ہیں، نئے ورژن میں کیا کیا گیا ہے اس کی تفصیل شامل کرتے ہوئے:
## 0.6.0-اسنیپ شاٹ * JRTB-7: گروپ سبسکرپشن کو حذف کرنے کی صلاحیت کو شامل کیا۔
کوڈ کام کرتا ہے، اس کے لیے ٹیسٹ لکھے گئے ہیں: اب وقت آگیا ہے کہ کام کو مخزن میں دھکیلیں اور پل کی درخواست بنائیں۔"A سے Z تک جاوا پروجیکٹ": گروپ سے مضامین کی رکنیت کو ہٹانا - 5

ختم ہونے کے بجائے

ہم نے اپنے پراجیکٹ بورڈ کو طویل عرصے سے نہیں دیکھا، لیکن بڑی تبدیلیاں ہوئی ہیں: "A سے Z تک جاوا پروجیکٹ": گروپ سے مضامین کی رکنیت کو ہٹانا - 6صرف 5 کام باقی ہیں۔ یعنی ہم پہلے ہی سڑک کے بالکل آخر میں ہیں۔ تھوڑا سا چھوڑ دیا۔ یہ بات خاص طور پر دلچسپ ہے کہ مضامین کا یہ سلسلہ ستمبر کے وسط سے، یعنی 7 ماہ سے جاری ہے!!! جب میں اس خیال کے ساتھ آیا تھا، مجھے امید نہیں تھی کہ اس میں اتنا وقت لگے گا۔ ایک ہی وقت میں، میں نتیجہ سے زیادہ خوش ہوں! دوستو اگر یہ واضح نہ ہو کہ مضمون میں کیا ہو رہا ہے تو کمنٹس میں سوال پوچھیں۔ اس طرح میں جان جاؤں گا کہ کسی چیز کو بہتر طریقے سے بیان کرنے کی ضرورت ہے، اور کسی چیز کو مزید وضاحت کی ضرورت ہے۔ ٹھیک ہے، ہمیشہ کی طرح، جیسے - سبسکرائب کریں - گھنٹی بجائیں، ہمارے پروجیکٹ کو ستارہ دیں ، تبصرے لکھیں اور مضمون کی درجہ بندی کریں! سب کا شکریہ. اگلے حصے تک۔ ہم جلد ہی اس بارے میں بات کریں گے کہ کس طرح /stop & /start کمانڈز کے ذریعے بوٹ کو غیر فعال کرنے اور ایکٹیویشن کو شامل کیا جائے اور ان کا بہترین استعمال کیسے کیا جائے۔ بعد میں ملتے ہیں!

سیریز کے تمام مواد کی فہرست اس مضمون کے شروع میں ہے۔

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