Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ on: [push]

jobs:
build:
runs-on: ubuntu-latest
runs-on: macos-latest

steps:
- uses: actions/checkout@v4

- name: Set up JDK 21
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
java-version: '17'
cache: 'maven'

- name: Build with Maven
Expand Down
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:17-jdk-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
43 changes: 43 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
version: '3.8'

services:
postgres:
image: postgres:15
container_name: postgres
environment:
POSTGRES_DB: $POSTGRES_DATABASE
POSTGRES_USER: $POSTGRES_USERNAME
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- $POSTGRES_LOCAL_PORT:$POSTGRES_DOCKER_PORT
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USERNAME} -d ${POSTGRES_DATABASE}"]
interval: 5s
timeout: 5s
retries: 5

telegram-bot:
build: .
env_file: .env
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- $SPRING_LOCAL_PORT:$SPRING_DOCKER_PORT
environment:
SPRING_APPLICATION_JSON: '{
"spring.datasource.url": "jdbc:postgresql://postgres:${POSTGRES_DOCKER_PORT}/${POSTGRES_DATABASE}",
"spring.datasource.username": "${POSTGRES_USERNAME}",
"spring.datasource.password": "${POSTGRES_PASSWORD}",
"spring.datasource.driver-class-name": "org.postgresql.Driver",
"spring.jpa.properties.hibernate.dialect": "org.hibernate.dialect.PostgreSQLDialect",
"spring.liquibase.enabled": true,
"spring.liquibase.change-log": "classpath:db/changelog/db.changelog-master.yaml"
}'
JAVA_TOOL_OPTIONS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:${DEBUG_PORT}"

volumes:
postgres_data:
62 changes: 37 additions & 25 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,9 @@
<version>0.0.1-SNAPSHOT</version>
<name>solscanbot</name>
<description>solscanbot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<maven.checkstyle.plugin.configLocation>checkstyle.xml</maven.checkstyle.plugin.configLocation>
<java.version>21</java.version>
<java.version>17</java.version>
<org.mapstruct.version>1.6.3</org.mapstruct.version>
<lombok.mapstruct.binding.version>0.2.0</lombok.mapstruct.binding.version>
</properties>
Expand All @@ -42,14 +29,13 @@
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
Expand All @@ -62,16 +48,42 @@
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>

<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

Expand Down
125 changes: 125 additions & 0 deletions src/main/java/ivan/solscanbot/bot/TelegramBot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package ivan.solscanbot.bot;

import ivan.solscanbot.exception.AddressAlreadyExistsException;
import ivan.solscanbot.exception.AddressNotMonitoredException;
import ivan.solscanbot.exception.ExceedsAmountOfAddressesException;
import ivan.solscanbot.exception.InvalidAddressException;
import ivan.solscanbot.exception.UserNotHaveAnyMonitoredAddressesException;
import ivan.solscanbot.service.TelegramService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

@Component
public class TelegramBot extends TelegramLongPollingBot {
private final String token;
private final String username;
private final TelegramService telegramService;

public TelegramBot(
@Value("${telegram.bot.token}") String token,
@Value("${telegram.bot.username}") String username,
TelegramService telegramService
) {
this.token = token;
this.username = username;
this.telegramService = telegramService;
}

@Override
public String getBotUsername() {
return username;
}

@Override
public String getBotToken() {
return token;
}

@Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String messageText = update.getMessage().getText();
long chatId = update.getMessage().getChatId();

if (messageText.startsWith("/help")) {
handleHelp(chatId);
} else if (messageText.startsWith("/add")) {
handleAddAddresses(chatId, messageText);
} else if (messageText.startsWith("/list")) {
handleListAddresses(chatId);
} else if (messageText.startsWith("/remove")) {
handleRemoveAddress(chatId, messageText);
} else if (messageText.startsWith("/portfolio")) {
handleGetPortfolios(chatId, messageText);
} else {
sendMessage(
chatId, "Unknown command. Use /help to get clarifications");
}
}
}

public void sendNotification(long chatId, String notification) {
sendMessage(chatId, notification);
}

private void handleHelp(long chatId) {
String message = telegramService.getHelp();
sendMessage(chatId, message);
}

private void handleGetPortfolios(long chatId, String messageText) {
try {
String message = telegramService.getPortfolios(chatId, messageText);
sendMessage(chatId, message);
} catch (InvalidAddressException | AddressNotMonitoredException
| ExceedsAmountOfAddressesException e) {
sendMessage(chatId, e.getMessage());
}
}

private void handleAddAddresses(long chatId, String messageText) {
try {
String message = telegramService.addAddresses(chatId, messageText);
sendMessage(chatId, message);
} catch (InvalidAddressException | AddressAlreadyExistsException
| ExceedsAmountOfAddressesException e) {
sendMessage(chatId, e.getMessage());
}
}

private void handleListAddresses(long chatId) {
try {
String message = telegramService.listAddresses(chatId);
sendMessage(chatId, message);
} catch (UserNotHaveAnyMonitoredAddressesException e) {
sendMessage(chatId, e.getMessage());
}
}

private void handleRemoveAddress(long chatId, String messageText) {
try {
String message = telegramService.removeAddresses(chatId, messageText);
sendMessage(chatId, message);
} catch (InvalidAddressException | AddressNotMonitoredException
| ExceedsAmountOfAddressesException e) {
sendMessage(chatId, e.getMessage());
}
}

private void sendMessage(long chatId, String text) {
SendMessage message = new SendMessage();
message.setChatId(String.valueOf(chatId));
message.setText(text);
message.enableMarkdown(true);
message.disableWebPagePreview();
try {
execute(message);
} catch (TelegramApiException e) {
throw new RuntimeException("Error while sending a message.", e);
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/ivan/solscanbot/config/MapperConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
componentModel = "spring",
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
implementationPackage = "<PACKAGE_NAME>.impl"
)public class MapperConfig {
implementationPackage = "<PACKAGE_NAME>.impl")
public class MapperConfig {
}
4 changes: 2 additions & 2 deletions src/main/java/ivan/solscanbot/config/TelegramBotConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ivan.solscanbot.config;

import ivan.solscanbot.service.DeFiMonitorBot;
import ivan.solscanbot.bot.TelegramBot;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.meta.TelegramBotsApi;
Expand All @@ -10,7 +10,7 @@
@Configuration
public class TelegramBotConfig {
@Bean
public TelegramBotsApi telegramBotsApi(DeFiMonitorBot bot) throws TelegramApiException {
public TelegramBotsApi telegramBotsApi(TelegramBot bot) throws TelegramApiException {
TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class);
botsApi.registerBot(bot);
return botsApi;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ivan.solscanbot.dto.external;
package ivan.solscanbot.dto.external.activity;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Set;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ivan.solscanbot.dto.external;
package ivan.solscanbot.dto.external.activity;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ivan.solscanbot.dto.external.meta;

import lombok.Data;

@Data
public class DataResponseDto {
private TokenMetaResponseDto data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ivan.solscanbot.dto.external.meta;

import java.util.Set;
import lombok.Data;

@Data
public class MultiDataResponseDto {
private Set<TokenMetaResponseDto> data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ivan.solscanbot.dto.external.meta;

import java.math.BigDecimal;
import lombok.Data;

@Data
public class TokenMetaResponseDto {
private String name;
private String symbol;
private String address;
private int decimals;
private BigDecimal price;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ivan.solscanbot.dto.external.portfolio;

import lombok.Data;

@Data
public class PortfolioWrapperDto {
private TokenPortfoliosResponseDto data;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package ivan.solscanbot.dto.external;
package ivan.solscanbot.dto.external.portfolio;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
import lombok.Data;

@Data
public class SingleTokenPortfolioResponseDto {
@JsonProperty("token_name")
private String tokenName;
@JsonProperty("token_symbol")
private String tokenSymbol;
@JsonProperty("token_address")
private String tokenAddress;
@JsonProperty("token_balance")
@JsonProperty("balance")
private String tokenBalance;
@JsonProperty("value")
private BigDecimal tokenValue;
Expand Down
Loading