Init commit
commit
bd5a14da19
|
@ -0,0 +1,5 @@
|
||||||
|
### Intellij Idea ###
|
||||||
|
.idea
|
||||||
|
|
||||||
|
### Maven ###
|
||||||
|
target
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Build stage
|
||||||
|
FROM maven:3.6.0-jdk-11-slim AS build
|
||||||
|
COPY src /home/app/src
|
||||||
|
COPY pom.xml /home/app
|
||||||
|
RUN mvn -f /home/app/pom.xml clean package
|
||||||
|
|
||||||
|
# Package stage
|
||||||
|
FROM openjdk:11-jre-slim
|
||||||
|
COPY --from=build /home/app/target/downloader-bot-1.0-SNAPSHOT.jar /usr/local/lib/downloader-bot-1.0-SNAPSHOT.jar
|
||||||
|
EXPOSE 8080
|
||||||
|
ENTRYPOINT ["java","-jar","/usr/local/lib/downloader-bot-1.0-SNAPSHOT.jar"]
|
|
@ -0,0 +1,22 @@
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: 'docker-spring-boot-postgres:latest'
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
container_name: app
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
environment:
|
||||||
|
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/postgres
|
||||||
|
- SPRING_DATASOURCE_USERNAME=postgres
|
||||||
|
- SPRING_DATASOURCE_PASSWORD=zPAwQpsFZC
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:14.1-alpine
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=postgres
|
||||||
|
- POSTGRES_PASSWORD=zPAwQpsFZC
|
||||||
|
ports:
|
||||||
|
- '5432:5432'
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>ru.mike.downloaderbot</groupId>
|
||||||
|
<artifactId>downloader-bot</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.pengrad</groupId>
|
||||||
|
<artifactId>java-telegram-bot-api</artifactId>
|
||||||
|
<version>6.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.28</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>42.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.liquibase</groupId>
|
||||||
|
<artifactId>liquibase-core</artifactId>
|
||||||
|
<version>4.22.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,21 @@
|
||||||
|
package ru.mike.downloaderbot;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class DownloaderBotApplication implements CommandLineRunner {
|
||||||
|
@Autowired
|
||||||
|
private UpdateProcessor updateProcessor;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(DownloaderBotApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) {
|
||||||
|
updateProcessor.processUpdates();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package ru.mike.downloaderbot;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
|
import com.pengrad.telegrambot.UpdatesListener;
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.mike.downloaderbot.processor.updatetype.UpdateTypeProcessor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class UpdateProcessor {
|
||||||
|
@Autowired
|
||||||
|
private TelegramBot telegramBot;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private List<UpdateTypeProcessor> updateTypeProcessors;
|
||||||
|
|
||||||
|
public void processUpdates() {
|
||||||
|
telegramBot.setUpdatesListener(updates -> {
|
||||||
|
|
||||||
|
for (Update update : updates) {
|
||||||
|
Optional<UpdateTypeProcessor> updateTypeProcessorOpt = updateTypeProcessors.stream()
|
||||||
|
.filter(p -> p.isSuitableProcessor(update))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (updateTypeProcessorOpt.isPresent()) {
|
||||||
|
updateTypeProcessorOpt.get().process(update);
|
||||||
|
} else {
|
||||||
|
log.warn("Unable to find suitable updateTypeProcessor. Update:{}", update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UpdatesListener.CONFIRMED_UPDATES_ALL;
|
||||||
|
}, e -> {
|
||||||
|
if (e.response() != null) {
|
||||||
|
// Ошибка из Телеграма
|
||||||
|
e.response().errorCode();
|
||||||
|
e.response().description();
|
||||||
|
} else {
|
||||||
|
// Как видно проблема сети
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.mike.downloaderbot.config;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class BotConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TelegramBot telegramBot() {
|
||||||
|
return new TelegramBot("6181387751:AAFha962O3-tK31DghfEIhW_wTfSF-JJBlk");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package ru.mike.downloaderbot.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "channel")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
public class Channel {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "link")
|
||||||
|
private String link;
|
||||||
|
|
||||||
|
@Column(name = "telegram_channel_id")
|
||||||
|
private Long telegramChannelId;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "channel_id")
|
||||||
|
private Rule rule;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package ru.mike.downloaderbot.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "link_data")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class LinkData {
|
||||||
|
@Id
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@Column(name = "resource_link")
|
||||||
|
private String resourceLink;
|
||||||
|
|
||||||
|
@Column(name = "bot_link")
|
||||||
|
private String botLink;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Имя канала, с которого пришел пользователь по ссылке {@link LinkData#botLink}
|
||||||
|
*/
|
||||||
|
@Column(name = "channel_name")
|
||||||
|
private String channelName;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package ru.mike.downloaderbot.domain;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "rule")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Rule {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@Column(name = "channel_name", unique = true)
|
||||||
|
private String channelName;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "rule", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
|
private Set<Channel> channels = new HashSet<>();
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.mike.downloaderbot.processor.command;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
|
||||||
|
public interface CommandProcessor {
|
||||||
|
|
||||||
|
boolean isSuitableCommand(String command);
|
||||||
|
|
||||||
|
void process(Update update);
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package ru.mike.downloaderbot.processor.command;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.mike.downloaderbot.domain.LinkData;
|
||||||
|
import ru.mike.downloaderbot.service.LinkDataService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class LinkCommandProcessor implements CommandProcessor {
|
||||||
|
@Autowired
|
||||||
|
private TelegramBot telegramBot;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LinkDataService linkDataService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuitableCommand(String command) {
|
||||||
|
return command.startsWith("/link");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Update update) {
|
||||||
|
List<Long> adminsIds = List.of(283573433L, 421233011L);
|
||||||
|
|
||||||
|
Long currentUserId = update.message().from().id();
|
||||||
|
Long currentChatId = update.message().chat().id();
|
||||||
|
String text = update.message().text();
|
||||||
|
|
||||||
|
if (!adminsIds.contains(currentUserId)) {
|
||||||
|
log.warn("User:'{}' trying to send link:{}, but it's not admin", currentUserId, text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] splitText = text.split(" ");
|
||||||
|
|
||||||
|
if (splitText.length != 3) {
|
||||||
|
SendMessage wrongFormatMessage = new SendMessage(currentChatId, "Неверный формат команды для генерации ссылки. " +
|
||||||
|
"Формат команды:/link <ссылка> <тег канала>");
|
||||||
|
telegramBot.execute(wrongFormatMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String linkText = splitText[1];
|
||||||
|
String channelName = splitText[2];
|
||||||
|
|
||||||
|
LinkData createdLinkData = linkDataService.createLinkData(linkText, channelName);
|
||||||
|
|
||||||
|
SendMessage generatedLinkMessage = new SendMessage(currentChatId,
|
||||||
|
"Сгенерированная ссылка:" + createdLinkData.getBotLink());
|
||||||
|
|
||||||
|
telegramBot.execute(generatedLinkMessage);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package ru.mike.downloaderbot.processor.command;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.mike.downloaderbot.domain.Rule;
|
||||||
|
import ru.mike.downloaderbot.service.RuleChannelService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RuleCommandProcessor implements CommandProcessor {
|
||||||
|
@Autowired
|
||||||
|
private TelegramBot telegramBot;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RuleChannelService ruleChannelService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuitableCommand(String command) {
|
||||||
|
return command.startsWith("/rule");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Update update) {
|
||||||
|
Long currentChatId = update.message().chat().id();
|
||||||
|
String text = update.message().text();
|
||||||
|
|
||||||
|
String[] splitText = text.split(" ");
|
||||||
|
|
||||||
|
String wrongRuleCommandFormatText = "Неверный формат команды для установки правила. " +
|
||||||
|
"Формат команды:/rule c1 c2 c3\n" +
|
||||||
|
"Где \n" +
|
||||||
|
"c1 - имя канала, для которого применяется правило подписки" +
|
||||||
|
"c2 - <имя канала, на который нужно подписаться>\n" +
|
||||||
|
"c3 - <id канала, на который нужно подписаться>\n" +
|
||||||
|
"c2 каналов может быть много, например \"/rule c1 c2 c2 c2";
|
||||||
|
|
||||||
|
if (splitText.length <= 3) {
|
||||||
|
sendCommandParseErrorMessage(currentChatId, text, wrongRuleCommandFormatText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ruleBaseChannelName = splitText[1];
|
||||||
|
|
||||||
|
String[] ruleSubscribeChannelsNames = Arrays.copyOfRange(splitText, 2, splitText.length);
|
||||||
|
|
||||||
|
if (ruleSubscribeChannelsNames.length % 2 != 0) {
|
||||||
|
sendCommandParseErrorMessage(currentChatId, text, wrongRuleCommandFormatText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> channelsNames = new ArrayList<>();
|
||||||
|
List<Long> channelsIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < ruleSubscribeChannelsNames.length; i++) {
|
||||||
|
String commandPart = ruleSubscribeChannelsNames[i];
|
||||||
|
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
channelsNames.add(commandPart);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
channelsIds.add(Long.parseLong(commandPart));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sendCommandParseErrorMessage(currentChatId, text, wrongRuleCommandFormatText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule createdRule = ruleChannelService.createRuleAndChannels(ruleBaseChannelName, channelsNames, channelsIds);
|
||||||
|
|
||||||
|
SendMessage successCreateRuleMessage = new SendMessage(currentChatId,
|
||||||
|
createSuccessCreateRuleMessage(createdRule)
|
||||||
|
);
|
||||||
|
telegramBot.execute(successCreateRuleMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCommandParseErrorMessage(Long currentChatId, String text, String wrongRuleCommandFormatText) {
|
||||||
|
log.warn("Unable to parse /rule command:'{}'", text);
|
||||||
|
|
||||||
|
SendMessage wrongFormatMessage = new SendMessage(currentChatId, wrongRuleCommandFormatText);
|
||||||
|
telegramBot.execute(wrongFormatMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createSuccessCreateRuleMessage(Rule createdRule) {
|
||||||
|
String ruleChannelName = createdRule.getChannelName();
|
||||||
|
String channelsStr = createdRule.getChannels().stream()
|
||||||
|
.map(c -> "Имя: " + c.getName() + ", ссылка: " + c.getLink())
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
|
||||||
|
return "Правило создано успешно\n" +
|
||||||
|
"Имя канала правила:" + ruleChannelName +
|
||||||
|
"\nКаналы для подписки:\n" +
|
||||||
|
channelsStr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package ru.mike.downloaderbot.processor.command;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
|
import com.pengrad.telegrambot.model.ChatMember;
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
import com.pengrad.telegrambot.request.GetChatMember;
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage;
|
||||||
|
import com.pengrad.telegrambot.response.GetChatMemberResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.mike.downloaderbot.domain.Channel;
|
||||||
|
import ru.mike.downloaderbot.domain.LinkData;
|
||||||
|
import ru.mike.downloaderbot.service.LinkDataService;
|
||||||
|
import ru.mike.downloaderbot.service.RuleChannelService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class StartCommandProcessor implements CommandProcessor {
|
||||||
|
@Autowired
|
||||||
|
private TelegramBot telegramBot;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LinkDataService linkDataService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RuleChannelService ruleChannelService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuitableCommand(String command) {
|
||||||
|
return command.startsWith("/start ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Update update) {
|
||||||
|
Long currentChatId = update.message().chat().id();
|
||||||
|
Long currentUserId = update.message().from().id();
|
||||||
|
String text = update.message().text();
|
||||||
|
|
||||||
|
String[] splitText = text.split(" ");
|
||||||
|
|
||||||
|
if (splitText.length != 2) {
|
||||||
|
log.warn("Unable to parse /start command:'{}'", text);
|
||||||
|
|
||||||
|
SendMessage wrongFormatMessage = new SendMessage(currentChatId,
|
||||||
|
"Ой, что-то пошло не так! Попробуйте еще раз!");
|
||||||
|
telegramBot.execute(wrongFormatMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String linkIdStr = splitText[1];
|
||||||
|
UUID linkId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
linkId = UUID.fromString(linkIdStr);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.warn("Unable to parse link id. Command:'{}', id='{}'", text, linkIdStr);
|
||||||
|
|
||||||
|
SendMessage wrongFormatMessage = new SendMessage(currentChatId,
|
||||||
|
"Ой, что-то пошло не так! Попробуйте еще раз!");
|
||||||
|
telegramBot.execute(wrongFormatMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<LinkData> linkDataOptional = linkDataService.findById(linkId);
|
||||||
|
|
||||||
|
if (linkDataOptional.isEmpty()) {
|
||||||
|
SendMessage linkNotFoundMessage = new SendMessage(currentChatId,
|
||||||
|
"Не нашли ссылку на ресурс... Попробуйте другой!");
|
||||||
|
telegramBot.execute(linkNotFoundMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkData linkData = linkDataOptional.get();
|
||||||
|
|
||||||
|
String channelName = linkData.getChannelName();
|
||||||
|
|
||||||
|
List<Channel> channels = ruleChannelService.findChannelsByRuleChannelName(channelName);
|
||||||
|
|
||||||
|
List<Long> channelsTgIds = channels.stream()
|
||||||
|
.map(Channel::getTelegramChannelId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
|
if (isAnyChannelNotSubscribed(currentUserId, channelsTgIds)) {
|
||||||
|
String subscribeLinks = channels.stream()
|
||||||
|
.map(Channel::getLink)
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
|
||||||
|
String subscribeMessage = "Подпишись на каналы:\n" + subscribeLinks;
|
||||||
|
|
||||||
|
telegramBot.execute(new SendMessage(currentChatId, subscribeMessage));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendMessage linkMessage = new SendMessage(currentChatId,
|
||||||
|
"Ссылка на ресурс: " + linkData.getResourceLink());
|
||||||
|
telegramBot.execute(linkMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAnyChannelNotSubscribed(Long currentUserId, List<Long> channelsTgIds) {
|
||||||
|
for (Long channelId : channelsTgIds) {
|
||||||
|
GetChatMember chatMember = new GetChatMember(channelId, currentUserId);
|
||||||
|
GetChatMemberResponse chatMemberResponse = telegramBot.execute(chatMember);
|
||||||
|
|
||||||
|
if (Objects.isNull(chatMemberResponse) || Objects.isNull(chatMemberResponse.chatMember()) ||
|
||||||
|
chatMemberResponse.chatMember().status().equals(ChatMember.Status.left)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package ru.mike.downloaderbot.processor.updatetype;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
import com.pengrad.telegrambot.request.SendMessage;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import ru.mike.downloaderbot.processor.command.CommandProcessor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MessageUpdateTypeProcessor implements UpdateTypeProcessor {
|
||||||
|
@Autowired
|
||||||
|
private TelegramBot telegramBot;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private List<CommandProcessor> commandProcessors;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuitableProcessor(Update update) {
|
||||||
|
return Objects.nonNull(update.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Update update) {
|
||||||
|
String text = update.message().text();
|
||||||
|
Optional<CommandProcessor> commandProcessorOptional = commandProcessors.stream()
|
||||||
|
.filter(cp -> cp.isSuitableCommand(text))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (commandProcessorOptional.isPresent()) {
|
||||||
|
commandProcessorOptional.get().process(update);
|
||||||
|
} else {
|
||||||
|
SendMessage sendMessage = new SendMessage(
|
||||||
|
update.message().chat().id(),
|
||||||
|
"Я не понимаю тебя, попробуй другую команду!"
|
||||||
|
);
|
||||||
|
|
||||||
|
telegramBot.execute(sendMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.mike.downloaderbot.processor.updatetype;
|
||||||
|
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
|
||||||
|
public interface UpdateTypeProcessor {
|
||||||
|
|
||||||
|
boolean isSuitableProcessor(Update update);
|
||||||
|
|
||||||
|
void process(Update update);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.mike.downloaderbot.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.mike.downloaderbot.domain.Channel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface ChannelRepository extends JpaRepository<Channel, UUID> {
|
||||||
|
|
||||||
|
void deleteAllByRuleId(UUID id);
|
||||||
|
|
||||||
|
List<Channel> findAllByRuleId(UUID id);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.mike.downloaderbot.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import ru.mike.downloaderbot.domain.LinkData;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface LinkDataRepository extends CrudRepository<LinkData, UUID> {
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.mike.downloaderbot.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.mike.downloaderbot.domain.Rule;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface RuleRepository extends JpaRepository<Rule, UUID> {
|
||||||
|
|
||||||
|
Optional<Rule> findByChannelName(String name);
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package ru.mike.downloaderbot.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mike.downloaderbot.domain.Channel;
|
||||||
|
import ru.mike.downloaderbot.repository.ChannelRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ChannelService {
|
||||||
|
@Autowired
|
||||||
|
private ChannelRepository channelRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void deleteAllByRuleId(UUID id) {
|
||||||
|
channelRepository.deleteAllByRuleId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<Channel> findAllByRuleId(UUID id) {
|
||||||
|
return channelRepository.findAllByRuleId(id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package ru.mike.downloaderbot.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mike.downloaderbot.domain.LinkData;
|
||||||
|
import ru.mike.downloaderbot.repository.LinkDataRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LinkDataService {
|
||||||
|
public static final String BOT_LINK_PREFIX = "https://t.me/new_downloaderx_bot";
|
||||||
|
@Autowired
|
||||||
|
private LinkDataRepository linkDataRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public LinkData createLinkData(String linkText, String channelName) {
|
||||||
|
UUID linkId = UUID.randomUUID();
|
||||||
|
LinkData linkData = LinkData.builder()
|
||||||
|
.id(linkId)
|
||||||
|
.resourceLink(linkText)
|
||||||
|
.botLink(BOT_LINK_PREFIX + "?start=" + linkId)
|
||||||
|
.channelName(channelName)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return linkDataRepository.save(linkData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<LinkData> findById(UUID linkId) {
|
||||||
|
return linkDataRepository.findById(linkId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package ru.mike.downloaderbot.service;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mike.downloaderbot.domain.Channel;
|
||||||
|
import ru.mike.downloaderbot.domain.Rule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class RuleChannelService {
|
||||||
|
public static final String TELEGRAM_CHANNEL_URL_PREFIX = "https://t.me/";
|
||||||
|
@Autowired
|
||||||
|
private RuleService ruleService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ChannelService channelService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Rule createRuleAndChannels(
|
||||||
|
String ruleBaseChannelName,
|
||||||
|
List<String> channelsNames,
|
||||||
|
List<Long> channelsIds
|
||||||
|
) {
|
||||||
|
Optional<Rule> ruleOptional = ruleService.findByChannelName(ruleBaseChannelName);
|
||||||
|
Rule rule;
|
||||||
|
|
||||||
|
if (ruleOptional.isEmpty()) {
|
||||||
|
rule = Rule.builder()
|
||||||
|
.channelName(ruleBaseChannelName)
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
rule = ruleOptional.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Channel> channels = createChannels(rule, channelsNames, channelsIds);
|
||||||
|
channelService.deleteAllByRuleId(rule.getId());
|
||||||
|
|
||||||
|
rule.setChannels(channels);
|
||||||
|
|
||||||
|
return ruleService.save(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Channel> findChannelsByRuleChannelName(String name) {
|
||||||
|
Optional<Rule> ruleOptional = ruleService.findByChannelName(name);
|
||||||
|
|
||||||
|
if (ruleOptional.isEmpty()) {
|
||||||
|
log.warn("Unable to find rule by name:{}", name);
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID ruleId = ruleOptional.get().getId();
|
||||||
|
List<Channel> channels = channelService.findAllByRuleId(ruleId);
|
||||||
|
|
||||||
|
if (channels.isEmpty()) {
|
||||||
|
log.info("Channels by rule id:'{}' not found", ruleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Channel> createChannels(Rule rule, List<String> channelsNames, List<Long> channelsIds) {
|
||||||
|
Set<Channel> channels = new HashSet<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < channelsNames.size(); i++) {
|
||||||
|
String channelName = channelsNames.get(i);
|
||||||
|
|
||||||
|
Channel channel = Channel.builder()
|
||||||
|
.name(channelName)
|
||||||
|
.link(TELEGRAM_CHANNEL_URL_PREFIX + channelName)
|
||||||
|
.rule(rule)
|
||||||
|
.telegramChannelId(channelsIds.get(i))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
channels.add(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package ru.mike.downloaderbot.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.mike.downloaderbot.domain.Rule;
|
||||||
|
import ru.mike.downloaderbot.repository.RuleRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RuleService {
|
||||||
|
@Autowired
|
||||||
|
private RuleRepository ruleRepository;
|
||||||
|
|
||||||
|
|
||||||
|
public Optional<Rule> findByChannelName(String channelName) {
|
||||||
|
return ruleRepository.findByChannelName(channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rule save(Rule rule) {
|
||||||
|
return ruleRepository.save(rule);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
spring:
|
||||||
|
datasource:
|
||||||
|
username: postgres
|
||||||
|
password: zPAwQpsFZC
|
||||||
|
driver-class-name: org.postgresql.Driver
|
||||||
|
url: jdbc:postgresql://localhost:5432/postgres
|
||||||
|
jpa:
|
||||||
|
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||||
|
hibernate:
|
||||||
|
ddl-auto: validate
|
||||||
|
open-in-view: false
|
||||||
|
liquibase:
|
||||||
|
change-log: classpath:db/migration/master/db.changelog-master.xml
|
||||||
|
enabled: true
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<databaseChangeLog
|
||||||
|
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||||
|
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.22.xsd">
|
||||||
|
|
||||||
|
<changeSet id="2023-06-24-init-schema" author="mgrunin">
|
||||||
|
<createTable tableName="link_data">
|
||||||
|
<column name="id" type="uuid">
|
||||||
|
<constraints primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="resource_link" type="varchar"></column>
|
||||||
|
<column name="bot_link" type="varchar"></column>
|
||||||
|
<column name="channel_name" type="varchar"></column>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<createTable tableName="rule">
|
||||||
|
<column name="id" type="uuid">
|
||||||
|
<constraints primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="channel_name" type="varchar">
|
||||||
|
<constraints unique="true"/>
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<createTable tableName="channel">
|
||||||
|
<column name="id" type="uuid">
|
||||||
|
<constraints primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="link" type="varchar"></column>
|
||||||
|
<column name="name" type="varchar"></column>
|
||||||
|
<column name="telegram_channel_id" type="bigint"></column>
|
||||||
|
<column name="channel_id" type="uuid"></column>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<addForeignKeyConstraint baseTableName="channel"
|
||||||
|
baseColumnNames="channel_id"
|
||||||
|
constraintName="fk_channel_id_rule"
|
||||||
|
referencedTableName="rule"
|
||||||
|
referencedColumnNames="id"/>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<databaseChangeLog
|
||||||
|
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.6.xsd">
|
||||||
|
|
||||||
|
<include file="db/migration/2023-06-24-init-schema.xml"/>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
Loading…
Reference in New Issue