JavaRush /Java Blogu /Random-AZ /Bir qrup məqaləyə abunə olmaq imkanı əlavə edirik. (2-ci ...
Roman Beekeeper
Səviyyə

Bir qrup məqaləyə abunə olmaq imkanı əlavə edirik. (2-ci hissə) - "A-dan Z-yə Java layihəsi"

Qrupda dərc edilmişdir
Hamıya salam! Keçən həftə başladığımız vəzifə üzərində işləməyə davam edirik ."A-dan Z-yə Java layihəsi": Bir qrup məqaləyə abunə olmaq imkanı əlavə etmək.  Hissə 2 - 1

Biz JRTB-5 tətbiq edirik

İndi bir əmr əlavə etməliyik ki, JavaRush-dan bəzi məqalələr qrupuna abunə ola bilək. Bunu necə etmək olar? Düşündüyüm ən sadə ssenariyə əməl edəcəyik. Qrup identifikatoru ilə çıxışımız olduğu üçün onu köçürmək üçün istifadəçiyə ehtiyacımız var. Bunun üçün istifadəçi iki üsuldan biri ilə işləyəcək /addGroupSub GROUP_ID əmrini daxil edəcək: yalnız əmrin özü gəlsə: /addGroupSub , cavab olaraq bütün qrupların siyahısı və onların ID-ləri göndərilir. Sonra istifadəçi özünə lazım olan qrup identifikatorunu seçə və sorğunun ikinci versiyasını bu komandada yarada biləcək: /addGroupSub GROUP_ID - və sonra bu istifadəçi ilə bu qrupun qeydi olacaq. Düşünürəm ki, gələcəkdə daha yaxşısını edə bilərik. Məqsədimiz super sərin istifadəçi təcrübəsini deyil, inkişafı göstərməkdir (deməyə utanıram, amma rus dilində bunu ifadə edən termini bilmirəm). Bütün tətbiqdən keçən funksionallığı düzgün şəkildə əlavə etmək üçün (bizim vəziyyətimizdə teleqram bot müştərisindən verilənlər bazasına qədər) nədənsə başlamaq lazımdır. Bunu verilənlər bazası tərəfdən edəcəyik.

Verilənlər bazasına yeni miqrasiya əlavə edilməsi

Ediləcək ilk şey yeni verilənlər bazası miqrasiyası və JR-də istifadəçi qrupu abunə məlumatlarını saxlamaq imkanı əlavə etməkdir. Bunun necə olacağını xatırlamaq üçün “ Layihənin planlaşdırılması: yeddi dəfə ölçün ” məqaləsinə qayıdın . İkinci fotoşəkildə verilənlər bazasının təxmini diaqramı var. Qrup məlumatlarını saxlamaq üçün cədvəl əlavə etməliyik:
  • JavaRush-da qrup ID-si də bizim ID-miz olacaq. Biz onlara güvənirik və bu şəxsiyyət vəsiqələrinin unikal olduğuna inanırıq;
  • başlıq - şəkillərimizdə bu ad idi - qrupun qeyri-rəsmi adı; yəni JavaRush saytında gördüklərimiz;
  • last_article_id - və bu maraqlı sahədir. O, botun artıq abunəçilərinə göndərdiyi məqalənin son identifikatorunu bu qrupda saxlayacaq. Bu sahədən istifadə edərək yeni məqalələrin axtarışı mexanizmi işləyəcək. Yeni abunəçilər istifadəçi abunə olmadan əvvəl dərc edilmiş məqalələri almayacaq: yalnız qrupa abunə olduqdan sonra dərc edilmiş məqalələr.
Qruplar və istifadəçilər cədvəli arasında çoxlu-çoxlu əlaqəmiz də olacaq, çünki hər bir istifadəçinin bir çox qrup abunəsi ola bilər (bir-çox) və hər bir qrup abunəsində çoxlu istifadəçi ola bilər (birdən çox, yalnız Digər tərəfdə). Belə çıxır ki, bu bizim çoxlu-çoxumuz olacaq. Sualları olanlar üçün verilənlər bazasındakı məqalələri nəzərdən keçirin. Bəli, mən tezliklə Telegram kanalında yazı yaratmağı planlaşdırıram, burada verilənlər bazasındakı bütün məqalələri birləşdirəcəyəm. İkinci verilənlər bazası miqrasiyamız belə görünəcək.
V00002__created_groupsub_many_to_many.sql:

-- add PRIMARY KEY FOR tg_user
ALTER TABLE tg_user ADD PRIMARY KEY (chat_id);

-- ensure that the tables with these names are removed before creating a new one.
DROP TABLE IF EXISTS group_sub;
DROP TABLE IF EXISTS group_x_user;

CREATE TABLE group_sub (
   id INT,
   title VARCHAR(100),
   last_article_id INT,
   PRIMARY KEY (id)
);

CREATE TABLE group_x_user (
   group_sub_id INT NOT NULL,
   user_id VARCHAR(100) NOT NULL,
   FOREIGN KEY (user_id) REFERENCES tg_user(chat_id),
   FOREIGN KEY (group_sub_id) REFERENCES group_sub(id),
   UNIQUE(user_id, group_sub_id)
);
Qeyd etmək lazımdır ki, əvvəlcə köhnə cədvəli dəyişirəm - ona əsas açar əlavə edirəm. Mən o vaxt bunu birtəhər qaçırdım, lakin indi MySQL mənə gorup_x_user cədvəli üçün XARİCİ AÇAR əlavə etmək imkanı vermədi və bu miqrasiyanın bir hissəsi olaraq verilənlər bazasını yenilədim. Zəhmət olmasa vacib bir cəhəti qeyd edin. Verilənlər bazasının dəyişdirilməsi məhz bu şəkildə aparılmalıdır - lazım olan hər şey yeni miqrasiyadadır, lakin artıq buraxılmış miqrasiyanın yenilənməsi ilə deyil. Bəli, bizim vəziyyətimizdə heç bir şey olmayacaq, çünki bu, sınaq layihəsidir və onun yalnız bir yerdə yerləşdirildiyini bilirik, lakin bu, yanlış yanaşma olardı. Amma biz hər şeyin yolunda olmasını istəyirik. Sonra onları yaratmadan əvvəl cədvəlləri silmək gəlir. Niyə bu? Belə ki, əgər təsadüfən verilənlər bazasında belə adları olan cədvəllər olsaydı, miqrasiya uğursuz olmayacaq və gözlənilən kimi işləyəcək. Və sonra iki cədvəl əlavə edirik. Hər şey istədiyimiz kimi oldu. İndi tətbiqimizi işə salmalıyıq. Hər şey başlayırsa və pozulmazsa, miqrasiya qeydə alınır. Və bunu iki dəfə yoxlamaq üçün verilənlər bazasına gedirik ki, əmin olun: a) belə cədvəllər peyda olub; b) uçuş xəttinin texniki cədvəlində yeni qeyd var. Bu, miqrasiya işlərini tamamlayır, keçək repozitoriyalara.

Repozitor qatının əlavə edilməsi

Spring Boot Data sayəsində burada hər şey çox sadədir: biz GroupSub obyektini əlavə etməliyik, TelegramUser-i bir az yeniləməli və demək olar ki, boş GroupSubRepository əlavə etməliyik: GroupSub obyektini TelegramUser ilə eyni paketə əlavə edirik:
package com.github.javarushcommunity.jrtb.repository.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.isNull;

@Data
@Entity
@Table(name = "group_sub")
@EqualsAndHashCode
public class GroupSub {

   @Id
   private Integer id;

   @Column(name = "title")
   private String title;

   @Column(name = "last_article_id")
   private Integer lastArticleId;

   @ManyToMany(fetch = FetchType.EAGER)
   @JoinTable(
           name = "group_x_user",
           joinColumns = @JoinColumn(name = "group_sub_id"),
           inverseJoinColumns = @JoinColumn(name = "user_id")
   )
   private List<TelegramUser> users;

   public void addUser(TelegramUser telegramUser) {
       if (isNull(users)) {
           users = new ArrayList<>();
       }
       users.add(telegramUser);
   }
}
Diqqət yetirməyə dəyər bir şey odur ki, qrupa abunə olan bütün istifadəçilərin toplusunu ehtiva edən əlavə istifadəçilər sahəsimiz var. Və iki annotasiya - ManyToMany və JoinTable - bunun üçün bizə lazım olan şeydir. Eyni sahə TelegramUser üçün əlavə edilməlidir:
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
Bu sahə GroupSub obyektində yazılmış birləşmələrdən istifadə edir. Və əslində, GroupSub üçün repozitor sinifimiz GroupSubRepository -dir :
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
* {@link Repository} for {@link GroupSub} entity.
*/
@Repository
public interface GroupSubRepository extends JpaRepository<GroupSub, Integer> {
}
Bu mərhələdə bizə əlavə üsullar lazım deyil: JpaRepository əcdadında həyata keçirilənlər bizim üçün kifayətdir. Gəlin TelegramUserRepositoryIT-də bir test yazaq ki, bizim çoxlu-çox-a işləyirik. Testin ideyası ondan ibarətdir ki, biz sql skripti vasitəsilə verilənlər bazasına hər bir istifadəçiyə 5 qrup abunə əlavə edəcəyik, bu istifadəçini şəxsiyyət vəsiqəsi ilə alacağıq və tam olaraq həmin qrupları və eyni dəyərləri aldığımızı yoxlayacağıq. Bunu necə etmək olar? Siz verilənlərin içinə sayğac yerləşdirə bilərsiniz, sonra onu keçib yoxlaya bilərik. BeşGroupSubsForUser.sql skripti budur:
INSERT INTO tg_user VALUES (1, 1);

INSERT INTO group_sub VALUES
(1, 'g1', 1),
(2, 'g2', 2),
(3, 'g3', 3),
(4, 'g4', 4),
(5, 'g5', 5);

INSERT INTO group_x_user VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);
Və testin özü:
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveGroupSubsForUser.sql"})
@Test
public void shouldProperlyGetAllGroupSubsForUser() {
   //when
   Optional<TelegramUser> userFromDB = telegramUserRepository.findById("1");

   //then
   Assertions.assertTrue(userFromDB.isPresent());
   List<GroupSub> groupSubs = userFromDB.get().getGroupSubs();
   for (int i = 0; i < groupSubs.size(); i++) {
       Assertions.assertEquals(String.format("g%s", (i + 1)), groupSubs.get(i).getTitle());
       Assertions.assertEquals(i + 1, groupSubs.get(i).getId());
       Assertions.assertEquals(i + 1, groupSubs.get(i).getLastArticleId());
   }
}
İndi GroupSub obyekti üçün eyni mənalı testi əlavə edək. Bunu etmək üçün, groupSubRepositoryIT ilə eyni paketdə groupSubRepositoryIT test sinifini yaradaq :
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;

import java.util.List;
import java.util.Optional;

import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;

/**
* Integration-level testing for {@link GroupSubRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class GroupSubRepositoryIT {

   @Autowired
   private GroupSubRepository groupSubRepository;

   @Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveUsersForGroupSub.sql"})
   @Test
   public void shouldProperlyGetAllUsersForGroupSub() {
       //when
       Optional<GroupSub> groupSubFromDB = groupSubRepository.findById(1);

       //then
       Assertions.assertTrue(groupSubFromDB.isPresent());
       Assertions.assertEquals(1, groupSubFromDB.get().getId());
       List<TelegramUser> users = groupSubFromDB.get().getUsers();
       for(int i=0; i<users.size(); i++) {
           Assertions.assertEquals(String.valueOf(i + 1), users.get(i).getChatId());
           Assertions.assertTrue(users.get(i).isActive());
       }
   }
}
Və çatışmayan beşUsersForGroupSub.sql skripti:
INSERT INTO tg_user VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);

INSERT INTO group_sub VALUES (1, 'g1', 1);

INSERT INTO group_x_user VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5);
Bu nöqtədə depo ilə işin bir hissəsini tamamlanmış hesab etmək olar. İndi isə xidmət qatını yazaq.

Biz GroupSubService yazırıq

Bu mərhələdə abunə qrupları ilə işləmək üçün sadəcə onları saxlaya bilməliyik, ona görə də problem yoxdur: biz GroupSubService xidmətini yaradırıq və onun GroupSubServiceImpl-in həyata keçirilməsini özündə digər xidmətlərin - xidməti olan paketdə həyata keçiririk:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;

/**
* Service for manipulating with {@link GroupSub}.
*/
public interface GroupSubService {

   GroupSub save(String chatId, GroupDiscussionInfo groupDiscussionInfo);
}
Və onun həyata keçirilməsi:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.GroupSubRepository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.ws.rs.NotFoundException;
import java.util.Optional;

@Service
public class GroupSubServiceImpl implements GroupSubService {

   private final GroupSubRepository groupSubRepository;
   private final TelegramUserService telegramUserService;

   @Autowired
   public GroupSubServiceImpl(GroupSubRepository groupSubRepository, TelegramUserService telegramUserService) {
       this.groupSubRepository = groupSubRepository;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public GroupSub save(String chatId, GroupDiscussionInfo groupDiscussionInfo) {
       TelegramUser telegramUser = telegramUserService.findByChatId(chatId).orElseThrow(NotFoundException::new);
       //TODO add exception handling
       GroupSub groupSub;
       Optional<GroupSub> groupSubFromDB = groupSubRepository.findById(groupDiscussionInfo.getId());
       if(groupSubFromDB.isPresent()) {
           groupSub = groupSubFromDB.get();
           Optional<TelegramUser> first = groupSub.getUsers().stream()
                   .filter(it -> it.getChatId().equalsIgnoreCase(chatId))
                   .findFirst();
           if(first.isEmpty()) {
               groupSub.addUser(telegramUser);
           }
       } else {
           groupSub = new GroupSub();
           groupSub.addUser(telegramUser);
           groupSub.setId(groupDiscussionInfo.getId());
           groupSub.setTitle(groupDiscussionInfo.getTitle());
       }
       return groupSubRepository.save(groupSub);
   }
}
Spring Data-nın düzgün işləməsi və çoxlu-çox qeydinin yaradılması üçün biz yaratdığımız abunə qrupu üçün verilənlər bazamızdan istifadəçini götürüb GroupSub obyektinə əlavə etməliyik. Beləliklə, biz bu abunəni saxlamağa köçürdükdə, qrup_x_user cədvəli vasitəsilə də əlaqə yaradılacaq. Belə bir abunə qrupunun artıq yaradıldığı bir vəziyyət ola bilər və sadəcə ona başqa bir istifadəçi əlavə etməlisiniz. Bunun üçün ilk olaraq verilənlər bazasından qrup identifikatorunu alırıq və qeyd varsa onunla işləyirik, yoxsa yenisini yaradırıq. Qeyd etmək vacibdir ki, TelegramUser ilə işləmək üçün biz TelegramUserService-dən SOLID prinsiplərinin sonuncusuna əməl etmək üçün istifadə edirik. Hal-hazırda, şəxsiyyət vəsiqəsinə görə bir qeyd tapmasaq, sadəcə bir istisna atıram. İndi heç bir şəkildə işlənmir: biz bunu ən sonunda, MVP-dən əvvəl edəcəyik. GroupSubServiceTest sinfi üçün iki vahid testi yazaq . Hansılar bizə lazımdır? Əmin olmaq istəyirəm ki, saxlama metodu GroupSubRepository-də çağırılacaq və bir istifadəçisi olan qurum GroupSub-a ötürüləcək - təqdim olunan ID-dən istifadə edərək TelegramUserService-i bizə qaytaracaq. İkinci seçim, eyni identifikatoru olan bir qrup artıq verilənlər bazasında olduqda və bu qrupun artıq bir istifadəçisi olduqda və bu qrupa başqa bir istifadəçinin əlavə olunacağını və bu obyektin saxlanacağını yoxlamaq lazımdır. Budur həyata keçirmə:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.GroupSubRepository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Optional;

@DisplayName("Unit-level testing for GroupSubService")
public class GroupSubServiceTest {

   private GroupSubService groupSubService;
   private GroupSubRepository groupSubRepository;
   private TelegramUser newUser;

   private final static String CHAT_ID = "1";

   @BeforeEach
   public void init() {
       TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
       groupSubRepository = Mockito.mock(GroupSubRepository.class);
       groupSubService = new GroupSubServiceImpl(groupSubRepository, telegramUserService);

       newUser = new TelegramUser();
       newUser.setActive(true);
       newUser.setChatId(CHAT_ID);

       Mockito.when(telegramUserService.findByChatId(CHAT_ID)).thenReturn(Optional.of(newUser));
   }

   @Test
   public void shouldProperlySaveGroup() {
       //given

       GroupDiscussionInfo groupDiscussionInfo = new GroupDiscussionInfo();
       groupDiscussionInfo.setId(1);
       groupDiscussionInfo.setTitle("g1");

       GroupSub expectedGroupSub = new GroupSub();
       expectedGroupSub.setId(groupDiscussionInfo.getId());
       expectedGroupSub.setTitle(groupDiscussionInfo.getTitle());
       expectedGroupSub.addUser(newUser);

       //when
       groupSubService.save(CHAT_ID, groupDiscussionInfo);

       //then
       Mockito.verify(groupSubRepository).save(expectedGroupSub);
   }

   @Test
   public void shouldProperlyAddUserToExistingGroup() {
       //given
       TelegramUser oldTelegramUser = new TelegramUser();
       oldTelegramUser.setChatId("2");
       oldTelegramUser.setActive(true);

       GroupDiscussionInfo groupDiscussionInfo = new GroupDiscussionInfo();
       groupDiscussionInfo.setId(1);
       groupDiscussionInfo.setTitle("g1");

       GroupSub groupFromDB = new GroupSub();
       groupFromDB.setId(groupDiscussionInfo.getId());
       groupFromDB.setTitle(groupDiscussionInfo.getTitle());
       groupFromDB.addUser(oldTelegramUser);

       Mockito.when(groupSubRepository.findById(groupDiscussionInfo.getId())).thenReturn(Optional.of(groupFromDB));

       GroupSub expectedGroupSub = new GroupSub();
       expectedGroupSub.setId(groupDiscussionInfo.getId());
       expectedGroupSub.setTitle(groupDiscussionInfo.getTitle());
       expectedGroupSub.addUser(oldTelegramUser);
       expectedGroupSub.addUser(newUser);

       //when
       groupSubService.save(CHAT_ID, groupDiscussionInfo);

       //then
       Mockito.verify(groupSubRepository).findById(groupDiscussionInfo.getId());
       Mockito.verify(groupSubRepository).save(expectedGroupSub);
   }

}
Mən init() metodunu da BeforeEach annotasiyası ilə əlavə etdim. Bu yolla onlar adətən hər sınaqdan əvvəl yerinə yetiriləcək bir üsul yaradırlar və bütün testlər üçün ona ümumi məntiq qoymaq mümkündür. Bizim vəziyyətimizdə bu sinifin bütün testləri üçün TelegramUserService-i eyni şəkildə kilidləməliyik, ona görə də bu məntiqi ümumi metoda köçürməyin mənası var. Burada istifadə olunan iki mokito dizaynı var:
  • Mockito.when(o1.m1(a1)).thenReturn(o2) - orada deyirik ki, m1 metodu a1 arqumenti ilə o1 obyektinə çağırılanda metod o2 obyektini qaytaracaq . Bu, mokitonun demək olar ki, ən vacib funksionallığıdır - istehza obyektini tam olaraq bizə lazım olanı qaytarmağa məcbur etmək;

  • Mockito.verify(o1).m1(a1) - m1 metodunun a1 arqumenti ilə o1 obyektində çağırıldığını yoxlayır . Saxlama metodunun qaytarılmış obyektindən istifadə etmək təbii ki mümkün idi, lakin mən başqa mümkün metodu göstərərək onu bir az daha mürəkkəbləşdirməyə qərar verdim. Nə vaxt faydalı ola bilər? Sınaq dərslərinin metodları ləğv edildiyi hallarda. Onda Mockito.verify olmadan heç bir iş olmayacaq)))

Testlərin yazılmalı və bir çoxunun yazılması lazım olduğu fikrinə sadiq qalırıq. Növbəti mərhələ telegram bot komandası ilə işləyir.

/addGroupSub əmrini yaradın

Burada aşağıdakı məntiqi yerinə yetirməliyik: heç bir kontekst olmadan sadəcə bir əmr alsaq, istifadəçiyə kömək edirik və ona lazımi məlumatları bota ötürə bilməsi üçün ID-ləri ilə birlikdə bütün qrupların siyahısını veririk. Və əgər istifadəçi başqa söz(lər) ilə bota əmr göndərirsə, həmin identifikatoru olan qrup tapın və ya belə bir qrupun olmadığını yazın. Enamemizə yeni bir dəyər əlavə edək - CommandName:
ADD_GROUP_SUB("/addgroupsub")
Gəlin verilənlər bazasından teleqram botuna keçək - komanda paketində AddGroupSubCommand sinfini yaradın:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.util.stream.Collectors;

import static com.github.javarushcommunity.jrtb.command.CommandName.ADD_GROUP_SUB;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getMessage;
import static java.util.Objects.isNull;
import static org.apache.commons.lang3.StringUtils.SPACE;
import static org.apache.commons.lang3.StringUtils.isNumeric;

/**
* Add Group subscription {@link Command}.
*/
public class AddGroupSubCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final JavaRushGroupClient javaRushGroupClient;
   private final GroupSubService groupSubService;

   public AddGroupSubCommand(SendBotMessageService sendBotMessageService, JavaRushGroupClient javaRushGroupClient,
                             GroupSubService groupSubService) {
       this.sendBotMessageService = sendBotMessageService;
       this.javaRushGroupClient = javaRushGroupClient;
       this.groupSubService = groupSubService;
   }

   @Override
   public void execute(Update update) {
       if (getMessage(update).equalsIgnoreCase(ADD_GROUP_SUB.getCommandName())) {
           sendGroupIdList(getChatId(update));
           return;
       }
       String groupId = getMessage(update).split(SPACE)[1];
       String chatId = getChatId(update);
       if (isNumeric(groupId)) {
           GroupDiscussionInfo groupById = javaRushGroupClient.getGroupById(Integer.parseInt(groupId));
           if (isNull(groupById.getId())) {
               sendGroupNotFound(chatId, groupId);
           }
           GroupSub savedGroupSub = groupSubService.save(chatId, groupById);
           sendBotMessageService.sendMessage(chatId, "Подписал на группу " + savedGroupSub.getTitle());
       } else {
           sendGroupNotFound(chatId, groupId);
       }
   }

   private void sendGroupNotFound(String chatId, String groupId) {
       String groupNotFoundMessage = "Нет группы с ID = \"%s\"";
       sendBotMessageService.sendMessage(chatId, String.format(groupNotFoundMessage, groupId));
   }

   private void sendGroupIdList(String chatId) {
       String groupIds = javaRushGroupClient.getGroupList(GroupRequestArgs.builder().build()).stream()
               .map(group -> String.format("%s - %s \n", group.getTitle(), group.getId()))
               .collect(Collectors.joining());

       String message = "Whatбы подписаться на группу - передай комадну вместе с ID группы. \n" +
               "Например: /addGroupSub 16. \n\n" +
               "я подготовил список всех групп - выберай Howую хочешь :) \n\n" +
               "Name группы - ID группы \n\n" +
               "%s";

       sendBotMessageService.sendMessage(chatId, String.format(message, groupIds));
   }
}
Bu sinif apache-commons kitabxanasındakı isNumeric metodundan istifadə edir , ona görə də onu yaddaşımıza əlavə edək:
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>${apache.commons.version}</version>
</dependency>
Və xüsusiyyətlər blokunda:
<apache.commons.version>3.11</apache.commons.version>
Bütün bu məntiq sinifdə var. Diqqətlə oxuyun. Hər hansı bir sualınız/təklifiniz varsa, şərhlərdə yazın. Bundan sonra komanda xəritəmizdə CommandContainer-ə əmr əlavə etməliyik:
.put(ADD_GROUP_SUB.getCommandName(), new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
Və bu komanda üçün hər şey. Mən birtəhər bu funksionallığı sınamaq istərdim, amma indiyə qədər ona verilənlər bazasında həqiqətən baxa bilərəm. Üçüncü hissədə JRTB-6-dan dəyişikliklər əlavə edəcəyəm ki, istifadəçinin abunə olduğu qrupların siyahısına baxa bilək. İndi bütün bunları yoxlamaq yaxşı olardı. Bunun üçün biz Telegram-da bütün hərəkətləri yerinə yetirib verilənlər bazasında yoxlayacağıq. Testlər yazdığımız üçün hər şey yaxşı olmalıdır. Məqalə artıq kifayət qədər uzundur, ona görə də daha sonra AddGroupSubCommand üçün test yazacağıq və unutmamaq üçün kodda TODO əlavə edəcəyik.

nəticələr

Bu yazıda verilənlər bazasından başlayaraq botdan istifadə edən müştəri ilə işləməyə qədər bütün proqram vasitəsilə funksionallıq əlavə etmək işinə baxdıq. Adətən belə tapşırıqlar layihəni başa düşməyə və onun mahiyyətini anlamağa kömək edir. Bunun necə işlədiyini anlayın. Bu günlərdə mövzular asan deyil, ona görə də utanmayın: suallarınızı şərhlərdə yazın, mən onlara cavab verməyə çalışacağam. Layihəni bəyəndinizmi? Github-da bir ulduz verin : bu şəkildə onların layihə ilə maraqlandıqları aydın olacaq və mən xoşbəxt olacağam. Necə deyərlər, ustad əməyi qiymətləndiriləndə həmişə sevinər. Kod STEP_6-nın hər üç hissəsini ehtiva edəcək və bu məqalədən əvvəl əlçatan olacaq. Bunu necə öyrənmək olar? Bu asandır - teleqram botu haqqında məqalələrim haqqında bütün məlumatları dərc etdiyim teleqram kanalına qoşulun. Oxuduğunuz üçün təşəkkür edirik! 3-cü hissə artıq buradadır .

Serialdakı bütün materialların siyahısı bu məqalənin əvvəlindədir.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION