Repository: javarushcommunity/javarush-telegrambot
Branch: main
Commit: 8fcb5021d636
Files: 106
Total size: 144.5 KB
Directory structure:
gitextract_6x5b_faq/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ ├── improvement-request.md
│ │ └── question.md
│ ├── pull_request_template.md
│ └── workflows/
│ └── maven.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── Find_New_Posts_WF.bpmn
├── LICENSE
├── README.md
├── RELEASE_NOTES.md
├── SET_UP_COMMANDS_BOT_FATHER
├── docker-compose-test.yml
├── docker-compose.yml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── javarushcommunity/
│ │ │ └── jrtb/
│ │ │ ├── JavarushTelegramBotApplication.java
│ │ │ ├── bot/
│ │ │ │ └── JavarushTelegramBot.java
│ │ │ ├── command/
│ │ │ │ ├── AddGroupSubCommand.java
│ │ │ │ ├── AdminHelpCommand.java
│ │ │ │ ├── Command.java
│ │ │ │ ├── CommandContainer.java
│ │ │ │ ├── CommandName.java
│ │ │ │ ├── CommandUtils.java
│ │ │ │ ├── DeleteGroupSubCommand.java
│ │ │ │ ├── HelpCommand.java
│ │ │ │ ├── ListGroupSubCommand.java
│ │ │ │ ├── NoCommand.java
│ │ │ │ ├── StartCommand.java
│ │ │ │ ├── StatCommand.java
│ │ │ │ ├── StopCommand.java
│ │ │ │ ├── UnknownCommand.java
│ │ │ │ └── annotation/
│ │ │ │ └── AdminCommand.java
│ │ │ ├── dto/
│ │ │ │ ├── GroupStatDTO.java
│ │ │ │ └── StatisticDTO.java
│ │ │ ├── javarushclient/
│ │ │ │ ├── JavaRushGroupClient.java
│ │ │ │ ├── JavaRushGroupClientImpl.java
│ │ │ │ ├── JavaRushPostClient.java
│ │ │ │ ├── JavaRushPostClientImpl.java
│ │ │ │ └── dto/
│ │ │ │ ├── BaseUserInfo.java
│ │ │ │ ├── GroupDiscussionInfo.java
│ │ │ │ ├── GroupFilter.java
│ │ │ │ ├── GroupInfo.java
│ │ │ │ ├── GroupInfoType.java
│ │ │ │ ├── GroupRequestArgs.java
│ │ │ │ ├── GroupVisibilityStatus.java
│ │ │ │ ├── GroupsCountRequestArgs.java
│ │ │ │ ├── Language.java
│ │ │ │ ├── LikeStatus.java
│ │ │ │ ├── LikesInfo.java
│ │ │ │ ├── MeGroupInfo.java
│ │ │ │ ├── MeGroupInfoStatus.java
│ │ │ │ ├── PostInfo.java
│ │ │ │ ├── PostType.java
│ │ │ │ ├── UserDiscussionInfo.java
│ │ │ │ ├── UserPublicStatus.java
│ │ │ │ └── VisibilityStatus.java
│ │ │ ├── job/
│ │ │ │ └── FindNewPostsJob.java
│ │ │ ├── repository/
│ │ │ │ ├── GroupSubRepository.java
│ │ │ │ ├── TelegramUserRepository.java
│ │ │ │ └── entity/
│ │ │ │ ├── GroupSub.java
│ │ │ │ └── TelegramUser.java
│ │ │ └── service/
│ │ │ ├── FindNewPostsService.java
│ │ │ ├── FindNewPostsServiceImpl.java
│ │ │ ├── GroupSubService.java
│ │ │ ├── GroupSubServiceImpl.java
│ │ │ ├── SendBotMessageService.java
│ │ │ ├── SendBotMessageServiceImpl.java
│ │ │ ├── StatisticsService.java
│ │ │ ├── StatisticsServiceImpl.java
│ │ │ ├── TelegramUserService.java
│ │ │ └── TelegramUserServiceImpl.java
│ │ └── resources/
│ │ ├── application-test.properties
│ │ ├── application.properties
│ │ ├── db/
│ │ │ └── migration/
│ │ │ ├── V00001__created_tg_user_table.sql
│ │ │ ├── V00002__created_groupsub_many_to_many.sql
│ │ │ ├── V00003__rename_last_article_id.sql
│ │ │ └── V00004_change_chat_Id_type_to_Long.sql
│ │ └── log4j2.xml
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── github/
│ │ └── javarushcommunity/
│ │ └── jrtb/
│ │ ├── command/
│ │ │ ├── AbstractCommandTest.java
│ │ │ ├── AdminHelpCommandTest.java
│ │ │ ├── CommandContainerTest.java
│ │ │ ├── DeleteGroupSubCommandTest.java
│ │ │ ├── HelpCommandTest.java
│ │ │ ├── ListGroupSubCommandTest.java
│ │ │ ├── NoCommandTest.java
│ │ │ ├── StartCommandTest.java
│ │ │ ├── StatCommandTest.java
│ │ │ ├── StopCommandTest.java
│ │ │ └── UnknownCommandTest.java
│ │ ├── javarushclient/
│ │ │ ├── JavaRushGroupClientTest.java
│ │ │ └── JavaRushPostClientTest.java
│ │ ├── repository/
│ │ │ ├── GroupSubRepositoryIT.java
│ │ │ └── TelegramUserRepositoryIT.java
│ │ └── service/
│ │ ├── GroupSubServiceTest.java
│ │ ├── SendBotMessageServiceTest.java
│ │ └── StatisticsServiceImplTest.java
│ └── resources/
│ └── sql/
│ ├── clearDbs.sql
│ ├── fiveGroupSubsForUser.sql
│ ├── fiveUsersForGroupSub.sql
│ └── telegram_users.sql
├── start.sh
└── stop.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: romankh3
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE]"
labels: feature
assignees: romankh3
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/improvement-request.md
================================================
---
name: Improvement request
about: Suggest an improvment for this project
title: "[IMPROVEMENT]"
labels: enhancement
assignees: romankh3
---
** Describe your idea of the improvement **
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: ask any questions, which are interested you
title: "[QUESTION]"
labels: 'question'
assignees: romankh3
---
================================================
FILE: .github/pull_request_template.md
================================================
# PR Details
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
## How Has This Been Tested
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Docs change / refactoring / dependency upgrade
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
================================================
FILE: .github/workflows/maven.yml
================================================
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up MySQL
uses: mirromutth/mysql-action@v1.1
with:
mysql version: '5.7'
mysql database: 'dev_jrtb_db'
mysql root password: 'root'
mysql user: 'dev_jrtb_db_user'
mysql password: 'dev_jrtb_db_password'
- name: Set up JDK 1.11
uses: actions/setup-java@v1
with:
java-version: 1.11
- name: Build with Maven
run: mvn -B package --file pom.xml
================================================
FILE: .gitignore
================================================
.idea/
target
build
*.iml
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at roman.beskrovnyy@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: Dockerfile
================================================
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}", "-Dspring.datasource.username=${BOT_DB_USERNAME}", "-jar", "app.jar"]
================================================
FILE: Find_New_Posts_WF.bpmn
================================================
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0pm0ags" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.8.1">
<bpmn:process id="Process_0q8qan7" isExecutable="true">
<bpmn:startEvent id="StartEvent_1" name="Find new Posts workflow started">
<bpmn:outgoing>Flow_0yrxqwq</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_0q4i3mw" name="Find New Posts Scheduler">
<bpmn:incoming>Flow_0yrxqwq</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_0yrxqwq" sourceRef="StartEvent_1" targetRef="Activity_0q4i3mw" />
<bpmn:boundaryEvent id="Event_1duo9io" name="15min" attachedToRef="Activity_0q4i3mw">
<bpmn:outgoing>Flow_150dsht</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_1jpcq10">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT24H</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
<bpmn:task id="Activity_0xf7sm3" name="Get All Groups Subscriptions">
<bpmn:incoming>Flow_150dsht</bpmn:incoming>
<bpmn:outgoing>Flow_1g56vij</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_150dsht" name="" sourceRef="Event_1duo9io" targetRef="Activity_0xf7sm3" />
<bpmn:task id="Activity_1ie0g58" name="Find new articles since last search">
<bpmn:incoming>Flow_1g56vij</bpmn:incoming>
<bpmn:outgoing>Flow_14geq43</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_1g56vij" sourceRef="Activity_0xf7sm3" targetRef="Activity_1ie0g58" />
<bpmn:endEvent id="Event_1sb4kpc" name="Find new posts workflow stopped">
<bpmn:incoming>Flow_0lqyzo8</bpmn:incoming>
<bpmn:incoming>Flow_0xev53g</bpmn:incoming>
<bpmn:terminateEventDefinition id="TerminateEventDefinition_0b0syf0" />
</bpmn:endEvent>
<bpmn:exclusiveGateway id="Gateway_16cr3lf" name="Does group subscription has new posts?">
<bpmn:incoming>Flow_14geq43</bpmn:incoming>
<bpmn:outgoing>Flow_0lqyzo8</bpmn:outgoing>
<bpmn:outgoing>Flow_0ux9vtc</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_14geq43" sourceRef="Activity_1ie0g58" targetRef="Gateway_16cr3lf" />
<bpmn:sequenceFlow id="Flow_0lqyzo8" name="No" sourceRef="Gateway_16cr3lf" targetRef="Event_1sb4kpc" />
<bpmn:task id="Activity_1unl7hc" name="Send Message to User">
<bpmn:incoming>Flow_0ux9vtc</bpmn:incoming>
<bpmn:outgoing>Flow_0xev53g</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_0ux9vtc" name="Yes" sourceRef="Gateway_16cr3lf" targetRef="Activity_1unl7hc" />
<bpmn:sequenceFlow id="Flow_0xev53g" sourceRef="Activity_1unl7hc" targetRef="Event_1sb4kpc" />
<bpmn:textAnnotation id="TextAnnotation_0e7hzky">
<bpmn:text>Runs every 15 minutes</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_0757sxs" sourceRef="Event_1duo9io" targetRef="TextAnnotation_0e7hzky" />
<bpmn:textAnnotation id="TextAnnotation_02jhypi">
<bpmn:text>Find new posts for each group subscription since last time</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_1ers88j" sourceRef="Activity_1ie0g58" targetRef="TextAnnotation_02jhypi" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0q8qan7">
<bpmndi:BPMNEdge id="Flow_0xev53g_di" bpmnElement="Flow_0xev53g">
<di:waypoint x="990" y="240" />
<di:waypoint x="1040" y="240" />
<di:waypoint x="1040" y="135" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ux9vtc_di" bpmnElement="Flow_0ux9vtc">
<di:waypoint x="815" y="240" />
<di:waypoint x="890" y="240" />
<bpmndi:BPMNLabel>
<dc:Bounds x="844" y="223" width="18" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0lqyzo8_di" bpmnElement="Flow_0lqyzo8">
<di:waypoint x="790" y="215" />
<di:waypoint x="790" y="117" />
<di:waypoint x="1022" y="117" />
<bpmndi:BPMNLabel>
<dc:Bounds x="802" y="165" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_14geq43_di" bpmnElement="Flow_14geq43">
<di:waypoint x="700" y="240" />
<di:waypoint x="765" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1g56vij_di" bpmnElement="Flow_1g56vij">
<di:waypoint x="540" y="240" />
<di:waypoint x="600" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_150dsht_di" bpmnElement="Flow_150dsht">
<di:waypoint x="370" y="175" />
<di:waypoint x="370" y="240" />
<di:waypoint x="440" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0yrxqwq_di" bpmnElement="Flow_0yrxqwq">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="158" y="66" width="80" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0q4i3mw_di" bpmnElement="Activity_0q4i3mw">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0xf7sm3_di" bpmnElement="Activity_0xf7sm3">
<dc:Bounds x="440" y="200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ie0g58_di" bpmnElement="Activity_1ie0g58">
<dc:Bounds x="600" y="200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1sb4kpc_di" bpmnElement="Event_1sb4kpc">
<dc:Bounds x="1022" y="99" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="997" y="66" width="85" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_16cr3lf_di" bpmnElement="Gateway_16cr3lf" isMarkerVisible="true">
<dc:Bounds x="765" y="215" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="751" y="272" width="80" height="40" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1unl7hc_di" bpmnElement="Activity_1unl7hc">
<dc:Bounds x="890" y="200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_0e7hzky_di" bpmnElement="TextAnnotation_0e7hzky">
<dc:Bounds x="200" y="210" width="100" height="40" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="TextAnnotation_02jhypi_di" bpmnElement="TextAnnotation_02jhypi">
<dc:Bounds x="660" y="78" width="140" height="68" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1vo0kt7_di" bpmnElement="Event_1duo9io">
<dc:Bounds x="352" y="139" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="379" y="171" width="30" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0757sxs_di" bpmnElement="Association_0757sxs">
<di:waypoint x="354" y="166" />
<di:waypoint x="276" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Association_1ers88j_di" bpmnElement="Association_1ers88j">
<di:waypoint x="677" y="200" />
<di:waypoint x="714" y="146" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Javarush Telegram Bot

JavaRush Telegram bot from community for community. Written by developers, who learned in [Javarush](https://javarush.ru).
## Idea
The main idea is to show how to create real application, which can be used by someone else.
There are [set of posts](https://javarush.ru/groups/posts/2935-java-proekt-ot-a-do-ja-pishem-realjhnihy-proekt-dlja-portfolio), which are describing step by step guidelines of how it was created.
## MVP Scope
As a user, I want to subscribe on group of posts and get notification via telegram-bot every time,
when new post, related to group subscriptions, has come.
# How it works
Based on MVP Scope, we can specify next behaviours (here and after Telegram User, which is using JavaRush Telgegram bot will call User):
- User can subscribe on group of posts
- User can view list of group subscriptions on which user subscribes
- User can unsubscribe from group of posts
- User can set an inactive bot and do not receive notifications
- User can restart getting notifications
## Find new posts workflow
The workflow of finding new posts and send them to subscribers can be viewed here:

## Deployment
Deployment process as easy as possible:
Required software:
- terminal for running bash scripts
- docker
- docker-compose
to deploy application, switch to needed branch and run bash script:
$ bash start.sh ${bot_username} ${bot_token}
That's all.
# Local development
For local development and testing, use `docker-compose-test.yml`.
Run command:
```shell
docker-compose -f docker-compose-test.yml up
```
Next step, is to run SpringBoot app with configured **Edit Configuration** in which two env vars are provided:
`bot.token=${BOT_TOKEN};bot.username=${BOT_USERNAME}`
And add VM Options:
`-Dspring.profiles.active=test `
With these configurations - run SpringBoot main method.
# Technological stack
- SpringBoot as a skeleton framework
- Spring Scheduler as a task manager
- MySQL database as a database for saving user and subscription info
- Flyway database migration tool
- Telegram-bot SpringBoot starter
- Spring Data starter
- Unirest - lib for working with REST calls
## Code of Conduct
Please, follow [Code of Conduct](CODE_OF_CONDUCT.md) page.
## License
This project is Apache License 2.0 - see the [LICENSE](LICENSE) file for details
# Contributions
Feel free to suggest new features via [github issue](https://github.com/javarushcommunity/javarush-telegrambot/issues/new).
Note, that new features must be approved before start implement it to avoid the situation, when the time was spent, but the changes wouldn't added to the project.
================================================
FILE: RELEASE_NOTES.md
================================================
# Release Notes
## 1.0.0
Implemented all the logic, planned up to MVP:
* User can subscribe on group of posts
* User can view list of group subscriptions on which user subscribes
* User can unsubscribe from group of posts
* User can set an inactive bot and do not receive notifications
* User can restart getting notifications
* Admin has ability to see bot statistics
## 0.8.0-SNAPSHOT
* JRTB-10: extended bot statistics for admins.
## 0.7.0-SNAPSHOT
* JRTB-4: added ability to send notifications about new articles
* JRTB-8: added ability to set inactive telegram user
* JRTB-9: added ability to set active user and/or start using it.
## 0.6.0-SNAPSHOT
* JRTB-7: added the ability to delete group subscription.
## 0.5.0-SNAPSHOT
* JRTB-5: added ability to subscribe on group
* JRTB-6: added ability to get a list of group subscriptions.
## 0.4.0-SNAPSHOT
* JRTB-1: added repository layer.
## 0.3.0-SNAPSHOT
* JRTB-13: added deployment process to the project
## 0.2.0-SNAPSHOT
* JRTB-3: implemented Command pattern for handling Telegram Bot commands
## 0.1.0-SNAPSHOT
* JRTB-2: added stub telegram bot
* JRTB-0: added SpringBoot skeleton project
================================================
FILE: SET_UP_COMMANDS_BOT_FATHER
================================================
start - начать/восстановить работу с ботом
stop - приостановить работу с ботом
addgroupsub - подписаться на группу статей
deletegroupsub - отписаться от группы статей
listgroupsub - список групп, на которые подписан
help - получить помощь в работе со мной
================================================
FILE: docker-compose-test.yml
================================================
version: '3.1'
services:
jrtb-db-dev:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: 'dev_jrtb_db'
# So you don't have to use root, but you can if you like
MYSQL_USER: 'dev_jrtb_db_user'
# You can use whatever password you like
MYSQL_PASSWORD: 'dev_jrtb_db_password'
# Password for root access
MYSQL_ROOT_PASSWORD: 'root'
ports:
# <Port exposed> : < MySQL Port running inside container>
- '3306:3306'
expose:
# Opens port 3306 on the container
- '3306'
command: --character-set-server=utf8 --collation-server=utf8_general_ci
================================================
FILE: docker-compose.yml
================================================
version: '3.1'
services:
jrtb-bot:
depends_on:
- jrtb-db
build:
context: .
environment:
BOT_NAME: ${BOT_NAME}
BOT_TOKEN: ${BOT_TOKEN}
BOT_DB_USERNAME: ${BOT_DB_USERNAME}
BOT_DB_PASSWORD: ${BOT_DB_PASSWORD}
restart: always
jrtb-db:
image: mysql:5.7
restart: always
environment:
MYSQL_USER: ${BOT_DB_USERNAME}
MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
MYSQL_DATABASE: 'jrtb_db'
MYSQL_ROOT_PASSWORD: 'root'
ports:
- '3306:3306'
expose:
- '3306'
command: --character-set-server=utf8 --collation-server=utf8_general_ci
================================================
FILE: mvnw
================================================
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
================================================
FILE: mvnw.cmd
================================================
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
================================================
FILE: pom.xml
================================================
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.github.javarushcommunity</groupId>
<artifactId>javarush-telegrambot</artifactId>
<version>1.0.0</version>
<name>Javarush TelegramBot</name>
<description>Telegram bot for Javarush from community to community</description>
<properties>
<java.version>11</java.version>
<telegrambot.starter.version>5.0.1</telegrambot.starter.version>
<unirest.version>3.11.01</unirest.version>
<apache.commons.version>3.11</apache.commons.version>
</properties>
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-spring-boot-starter</artifactId>
<version>${telegrambot.starter.version}</version>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>${unirest.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache.commons.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/JavarushTelegramBotApplication.java
================================================
package com.github.javarushcommunity.jrtb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
public class JavarushTelegramBotApplication {
public static void main(String[] args) {
SpringApplication.run(JavarushTelegramBotApplication.class, args);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/bot/JavarushTelegramBot.java
================================================
package com.github.javarushcommunity.jrtb.bot;
import com.github.javarushcommunity.jrtb.command.CommandContainer;
import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageServiceImpl;
import com.github.javarushcommunity.jrtb.service.StatisticsService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.List;
import static com.github.javarushcommunity.jrtb.command.CommandName.NO;
/**
* Telegram bot for Javarush Community from Javarush community.
*/
@Component
public class JavarushTelegramBot extends TelegramLongPollingBot {
public static String COMMAND_PREFIX = "/";
@Value("${bot.username}")
private String username;
@Value("${bot.token}")
private String token;
private final CommandContainer commandContainer;
@Autowired
public JavarushTelegramBot(TelegramUserService telegramUserService, JavaRushGroupClient groupClient, GroupSubService groupSubService,
@Value("#{'${bot.admins}'.split(',')}") List<String> admins, StatisticsService statisticsService) {
this.commandContainer =
new CommandContainer(new SendBotMessageServiceImpl(this),
telegramUserService, groupClient, groupSubService, admins, statisticsService);
}
@Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String message = update.getMessage().getText().trim();
String username = update.getMessage().getFrom().getUserName();
if (message.startsWith(COMMAND_PREFIX)) {
String commandIdentifier = message.split(" ")[0].toLowerCase();
commandContainer.findCommand(commandIdentifier, username).execute(update);
} else {
commandContainer.findCommand(NO.getCommandName(), username).execute(update);
}
}
}
@Override
public String getBotUsername() {
return username;
}
@Override
public String getBotToken() {
return token;
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/AddGroupSubCommand.java
================================================
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}.
*/
//todo add unit test for the command logic.
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];
Long 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 {
sendNotValidGroupID(chatId, groupId);
}
}
private void sendGroupNotFound(Long chatId, String groupId) {
String groupNotFoundMessage = "Нет группы с ID = \"%s\"";
sendBotMessageService.sendMessage(chatId, String.format(groupNotFoundMessage, groupId));
}
private void sendNotValidGroupID(Long chatId, String groupId) {
String groupNotFoundMessage = "Неправильный ID группы = \"%s\"";
sendBotMessageService.sendMessage(chatId, String.format(groupNotFoundMessage, groupId));
; }
private void sendGroupIdList(Long 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 = "Чтобы подписаться на группу - передай команду вместе с ID группы. \n" +
"Например: /addGroupSub 30 \n\n" +
"я подготовил список всех групп - выбирай какую хочешь :) \n\n" +
"имя группы - ID группы \n\n" +
"%s";
sendBotMessageService.sendMessage(chatId, String.format(message, groupIds));
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/AdminHelpCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;
import static com.github.javarushcommunity.jrtb.command.CommandName.STAT;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
import static java.lang.String.format;
/**
* Admin Help {@link Command}.
*/
public class AdminHelpCommand implements Command {
public static final String ADMIN_HELP_MESSAGE = format("✨<b>Доступные команды админа</b>✨\n\n"
+ "<b>Получить статистику</b>\n"
+ "%s - статистика бота\n",
STAT.getCommandName());
private final SendBotMessageService sendBotMessageService;
public AdminHelpCommand(SendBotMessageService sendBotMessageService) {
this.sendBotMessageService = sendBotMessageService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(getChatId(update), ADMIN_HELP_MESSAGE);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/Command.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Command interface for handling telegram-bot commands.
*/
public interface Command {
/**
* Main method, which is executing command logic.
*
* @param update provided {@link Update} object with all the needed data for command.
*/
void execute(Update update);
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/CommandContainer.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.command.annotation.AdminCommand;
import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.StatisticsService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import static com.github.javarushcommunity.jrtb.command.CommandName.*;
import static java.util.Objects.nonNull;
/**
* Container of the {@link Command}s, which are using for handling telegram commands.
*/
public class CommandContainer {
private final ImmutableMap<String, Command> commandMap;
private final Command unknownCommand;
private final List<String> admins;
public CommandContainer(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService,
JavaRushGroupClient javaRushGroupClient, GroupSubService groupSubService,
List<String> admins, StatisticsService statisticsService) {
this.admins = admins;
commandMap = ImmutableMap.<String, Command>builder()
.put(START.getCommandName(), new StartCommand(sendBotMessageService, telegramUserService))
.put(STOP.getCommandName(), new StopCommand(sendBotMessageService, telegramUserService))
.put(HELP.getCommandName(), new HelpCommand(sendBotMessageService))
.put(NO.getCommandName(), new NoCommand(sendBotMessageService))
.put(STAT.getCommandName(), new StatCommand(sendBotMessageService, statisticsService))
.put(ADD_GROUP_SUB.getCommandName(),
new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
.put(LIST_GROUP_SUB.getCommandName(),
new ListGroupSubCommand(sendBotMessageService, telegramUserService))
.put(DELETE_GROUP_SUB.getCommandName(),
new DeleteGroupSubCommand(sendBotMessageService, groupSubService, telegramUserService))
.put(ADMIN_HELP.getCommandName(), new AdminHelpCommand(sendBotMessageService))
.build();
unknownCommand = new UnknownCommand(sendBotMessageService);
}
public Command findCommand(String commandIdentifier, String username) {
Command orDefault = commandMap.getOrDefault(commandIdentifier, unknownCommand);
if (isAdminCommand(orDefault)) {
if (admins.contains(username)) {
return orDefault;
} else {
return unknownCommand;
}
}
return orDefault;
}
private boolean isAdminCommand(Command command) {
return nonNull(command.getClass().getAnnotation(AdminCommand.class));
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/CommandName.java
================================================
package com.github.javarushcommunity.jrtb.command;
/**
* Enumeration for {@link Command}'s.
*/
public enum CommandName {
START("/start"),
STOP("/stop"),
HELP("/help"),
ADMIN_HELP("/ahelp"),
STAT("/stat"),
NO("nocommand"),
ADD_GROUP_SUB("/addgroupsub"),
DELETE_GROUP_SUB("/deletegroupsub"),
LIST_GROUP_SUB("/listgroupsub");
private final String commandName;
CommandName(String commandName) {
this.commandName = commandName;
}
public String getCommandName() {
return commandName;
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/CommandUtils.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Utils class for Commands.
*/
public class CommandUtils {
/**
* Get chatId from {@link Update} object.
*
* @param update provided {@link Update}
* @return chatID from the provided {@link Update} object.
*/
public static Long getChatId(Update update) {
return update.getMessage().getChatId();
}
/**
* Get text of the message from {@link Update} object.
*
* @param update provided {@link Update}
* @return the text of the message from the provided {@link Update} object.
*/
public static String getMessage(Update update) {
return update.getMessage().getText();
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/DeleteGroupSubCommand.java
================================================
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];
Long 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(Long chatId) {
String message;
List<GroupSub> groupSubs = telegramUserService.findByChatId(chatId)
.orElseThrow(NotFoundException::new)
.getGroupSubs();
if (CollectionUtils.isEmpty(groupSubs)) {
message = "Пока нет подписок на группы. Чтобы добавить подписку напиши /addGroupSub";
} else {
String userGroupSubData = groupSubs.stream()
.map(group -> format("%s - %s \n", group.getTitle(), group.getId()))
.collect(Collectors.joining());
message = String.format("Чтобы удалить подписку на группу - передай комадну вместе с ID группы. \n" +
"Например: /deleteGroupSub 16 \n\n" +
"я подготовил список всех групп, на которые ты подписан) \n\n" +
"имя группы - ID группы \n\n" +
"%s", userGroupSubData);
}
sendBotMessageService.sendMessage(chatId, message);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/HelpCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;
import static com.github.javarushcommunity.jrtb.command.CommandName.*;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* Help {@link Command}.
*/
public class HelpCommand implements Command {
private final SendBotMessageService sendBotMessageService;
public static final String HELP_MESSAGE = String.format("✨Дотупные команды✨\n\n"
+ "Начать\\закончить работу с ботом:\n"
+ "%s - начать работу со мной\n"
+ "%s - приостановить работу со мной\n\n"
+ "Работа с подписками на группы:\n"
+ "%s - подписаться на группу статей\n"
+ "%s - отписаться от группы статей\n"
+ "%s - получить список групп, на которые подписан\n\n"
+ "%s - получить помощь в работе со мной\n",
START.getCommandName(), STOP.getCommandName(), ADD_GROUP_SUB.getCommandName(),
DELETE_GROUP_SUB.getCommandName(), LIST_GROUP_SUB.getCommandName(), HELP.getCommandName());
public HelpCommand(SendBotMessageService sendBotMessageService) {
this.sendBotMessageService = sendBotMessageService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(getChatId(update), HELP_MESSAGE);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/ListGroupSubCommand.java
================================================
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.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.stream.Collectors;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* {@link Command} for getting list of {@link GroupSub}.
*/
public class ListGroupSubCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public ListGroupSubCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
//todo add exception handling
TelegramUser telegramUser = telegramUserService.findByChatId(getChatId(update))
.orElseThrow(NotFoundException::new);
String message;
if(CollectionUtils.isEmpty(telegramUser.getGroupSubs())) {
message = "Пока нет подписок на группы. Чтобы добавить подписку напиши /addGroupSub";
} else {
String collectedGroups = telegramUser.getGroupSubs().stream()
.map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
.collect(Collectors.joining());
message = String.format("Я нашел все подписки на группы: \n\n %s", collectedGroups);
}
sendBotMessageService.sendMessage(telegramUser.getChatId(), message);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/NoCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* No {@link Command}.
*/
public class NoCommand implements Command {
private final SendBotMessageService sendBotMessageService;
public static final String NO_MESSAGE = "Я поддерживаю команды, начинающиеся со слеша(/).\n"
+ "Чтобы посмотреть список комманд введи /help";
public NoCommand(SendBotMessageService sendBotMessageService) {
this.sendBotMessageService = sendBotMessageService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(getChatId(update), NO_MESSAGE);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/StartCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* Start {@link Command}.
*/
public class StartCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public final static String START_MESSAGE = "Привет. Я Javarush Telegram Bot.\n " +
"Я помогу тебе быть в курсе последних статей тех авторов, которые тебе интересны.\n\n" +
"Нажимай /addGroupSub чтобы подписаться на группу статей в JavaRush.\n" +
"Не знаешь о чем я? Напиши /help, чтобы узнать что я умею.";
public StartCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
Long chatId = getChatId(update);
telegramUserService.findByChatId(chatId).ifPresentOrElse(
user -> {
user.setActive(true);
telegramUserService.save(user);
},
() -> {
TelegramUser telegramUser = new TelegramUser();
telegramUser.setActive(true);
telegramUser.setChatId(chatId);
telegramUserService.save(telegramUser);
});
sendBotMessageService.sendMessage(chatId, START_MESSAGE);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/StatCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.command.annotation.AdminCommand;
import com.github.javarushcommunity.jrtb.dto.StatisticDTO;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.StatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.stream.Collectors;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* Statistics {@link Command}.
*/
@AdminCommand
public class StatCommand implements Command {
private final StatisticsService statisticsService;
private final SendBotMessageService sendBotMessageService;
public final static String STAT_MESSAGE = "✨<b>Подготовил статистику</b>✨\n" +
"- Количество активных пользователей: %s\n" +
"- Количество неактивных пользователей: %s\n" +
"- Среднее количество групп на одного пользователя: %s\n\n" +
"<b>Информация по активным группам</b>:\n" +
"%s";
@Autowired
public StatCommand(SendBotMessageService sendBotMessageService, StatisticsService statisticsService) {
this.sendBotMessageService = sendBotMessageService;
this.statisticsService = statisticsService;
}
@Override
public void execute(Update update) {
StatisticDTO statisticDTO = statisticsService.countBotStatistic();
String collectedGroups = statisticDTO.getGroupStatDTOs().stream()
.map(it -> String.format("%s (id = %s) - %s подписчиков", it.getTitle(), it.getId(), it.getActiveUserCount()))
.collect(Collectors.joining("\n"));
sendBotMessageService.sendMessage(getChatId(update), String.format(STAT_MESSAGE,
statisticDTO.getActiveUserCount(),
statisticDTO.getInactiveUserCount(),
statisticDTO.getAverageGroupCountByUser(),
collectedGroups));
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/StopCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.Optional;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* Stop {@link Command}.
*/
public class StopCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public static final String STOP_MESSAGE = "Деактивировал все твои подписки \uD83D\uDE1F.\n" +
"Ты всегда можешь вернуться нажав /start";
public StopCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(getChatId(update), STOP_MESSAGE);
telegramUserService.findByChatId(getChatId(update))
.ifPresent(it -> {
it.setActive(false);
telegramUserService.save(it);
});
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/UnknownCommand.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* Unknown {@link Command}.
*/
public class UnknownCommand implements Command {
public static final String UNKNOWN_MESSAGE = "Не понимаю тебя \uD83D\uDE1F, напиши /help чтобы узнать что я понимаю.";
private final SendBotMessageService sendBotMessageService;
public UnknownCommand(SendBotMessageService sendBotMessageService) {
this.sendBotMessageService = sendBotMessageService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(getChatId(update), UNKNOWN_MESSAGE);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/annotation/AdminCommand.java
================================================
package com.github.javarushcommunity.jrtb.command.annotation;
import com.github.javarushcommunity.jrtb.command.Command;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Mark if {@link Command} can be viewed only by admins.
*/
@Retention(RUNTIME)
public @interface AdminCommand {
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/dto/GroupStatDTO.java
================================================
package com.github.javarushcommunity.jrtb.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* DTO for showing group id and title without data
*/
@Data
@EqualsAndHashCode(exclude = {"title", "activeUserCount"})
public class GroupStatDTO {
private final Integer id;
private final String title;
private final Integer activeUserCount;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/dto/StatisticDTO.java
================================================
package com.github.javarushcommunity.jrtb.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* DTO for getting bot statistics.
*/
@Data
@EqualsAndHashCode
public class StatisticDTO {
private final int activeUserCount;
private final int inactiveUserCount;
private final List<GroupStatDTO> groupStatDTOs;
private final double averageGroupCountByUser;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClient.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import java.util.List;
/**
* Client for Javarush Open API corresponds to Groups.
*/
public interface JavaRushGroupClient {
/**
* Get all the {@link GroupInfo} filtered by provided {@link GroupRequestArgs}.
*
* @param requestArgs provided {@link GroupRequestArgs}.
* @return the collection of the {@link GroupInfo} objects.
*/
List<GroupInfo> getGroupList(GroupRequestArgs requestArgs);
/**
* Get all the {@link GroupDiscussionInfo} filtered by provided {@link GroupRequestArgs}.
*
* @param requestArgs provided {@link GroupRequestArgs}
* @return the collection of the {@link GroupDiscussionInfo} objects.
*/
List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requestArgs);
/**
* Get count of groups filtered by provided {@link GroupRequestArgs}.
*
* @param countRequestArgs provided {@link GroupsCountRequestArgs}.
* @return the count of the groups.
*/
Integer getGroupCount(GroupsCountRequestArgs countRequestArgs);
/**
* Get {@link GroupDiscussionInfo} by provided ID.
*
* @param id provided ID.
* @return {@link GroupDiscussionInfo} object.
*/
GroupDiscussionInfo getGroupById(Integer id);
Integer findLastPostId(Integer groupSub);
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClientImpl.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.*;
import kong.unirest.GenericType;
import kong.unirest.Unirest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
import static org.springframework.util.CollectionUtils.isEmpty;
/**
* Implementation of the {@link JavaRushGroupClient} interface.
*/
@Component
public class JavaRushGroupClientImpl implements JavaRushGroupClient {
private final String javarushApiGroupPath;
private final String getJavarushApiPostPath;
public JavaRushGroupClientImpl(@Value("${javarush.api.path}") String javarushApi) {
this.javarushApiGroupPath = javarushApi + "/groups";
this.getJavarushApiPostPath = javarushApi + "/posts";
}
@Override
public List<GroupInfo> getGroupList(GroupRequestArgs requestArgs) {
return Unirest.get(javarushApiGroupPath)
.queryString(requestArgs.populateQueries())
.asObject(new GenericType<List<GroupInfo>>() {
})
.getBody();
}
@Override
public List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requestArgs) {
return Unirest.get(javarushApiGroupPath)
.queryString(requestArgs.populateQueries())
.asObject(new GenericType<List<GroupDiscussionInfo>>() {
})
.getBody();
}
@Override
public Integer getGroupCount(GroupsCountRequestArgs countRequestArgs) {
return Integer.valueOf(
Unirest.get(String.format("%s/count", javarushApiGroupPath))
.queryString(countRequestArgs.populateQueries())
.asString()
.getBody()
);
}
@Override
public GroupDiscussionInfo getGroupById(Integer id) {
return Unirest.get(String.format("%s/group%s", javarushApiGroupPath, id.toString()))
.asObject(GroupDiscussionInfo.class)
.getBody();
}
@Override
public Integer findLastPostId(Integer groupSubId) {
List<PostInfo> posts = Unirest.get(getJavarushApiPostPath)
.queryString("order", "NEW")
.queryString("groupKid", groupSubId.toString())
.queryString("limit", "1")
.asObject(new GenericType<List<PostInfo>>() {
})
.getBody();
return isEmpty(posts) ? 0 : Optional.ofNullable(posts.get(0)).map(PostInfo::getId).orElse(0);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClient.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
import java.util.List;
/**
* Client for Javarush Open API corresponds to Posts.
*/
public interface JavaRushPostClient {
/**
* Find new posts since lastPostId in provided group.
*
* @param groupId provided group ID.
* @param lastPostId provided last post ID.
* @return the collection of the new {@link PostInfo}.
*/
List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId);
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClientImpl.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
import kong.unirest.GenericType;
import kong.unirest.Unirest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class JavaRushPostClientImpl implements JavaRushPostClient {
private final String javarushApiPostPath;
public JavaRushPostClientImpl(@Value("${javarush.api.path}") String javarushApi) {
this.javarushApiPostPath = javarushApi + "/posts";
}
@Override
public List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId) {
List<PostInfo> lastPostsByGroup = Unirest.get(javarushApiPostPath)
.queryString("order", "NEW")
.queryString("groupKid", groupId)
.queryString("limit", 15)
.asObject(new GenericType<List<PostInfo>>() {
}).getBody();
List<PostInfo> newPosts = new ArrayList<>();
for (PostInfo post : lastPostsByGroup) {
if (lastPostId.equals(post.getId())) {
return newPosts;
}
newPosts.add(post);
}
return newPosts;
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/BaseUserInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
/**
* DTO, which represents base user information.
*/
@Data
public class BaseUserInfo {
private String city;
private String country;
private String displayName;
private Integer id;
private String job;
private String key;
private Integer level;
private String pictureUrl;
private String position;
private UserPublicStatus publicStatus;
private String publicStatusMessage;
private Integer rating;
private Integer userId;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupDiscussionInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* Group discussion info class.
*/
@EqualsAndHashCode(callSuper = true)
@Data
@ToString(callSuper = true)
public class GroupDiscussionInfo extends GroupInfo {
private UserDiscussionInfo userDiscussionInfo;
private Integer commentsCount;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupFilter.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* Filters for group requests.
*/
public enum GroupFilter {
UNKNOWN, MY, ALL
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
import lombok.ToString;
/**
* Group Info DTO class.
*/
@Data
@ToString
public class GroupInfo {
private Integer id;
private String avatarUrl;
private String createTime;
private String description;
private String key;
private Integer levelToEditor;
private MeGroupInfo meGroupInfo;
private String pictureUrl;
private String title;
private GroupInfoType type;
private Integer userCount;
private GroupVisibilityStatus visibilityStatus;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupInfoType.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* Group Info type;
*/
public enum GroupInfoType {
UNKNOWN, CITY, COMPANY, COLLEGE, TECH, SPECIAL, COUNTRY
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupRequestArgs.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.*;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.nonNull;
/**
* Request arguments for group requests.
*/
@Builder
@Getter
public class GroupRequestArgs {
private final String query;
private final GroupInfoType type;
private final GroupFilter filter;
/**
* specified where to start getting groups
*/
private final Integer offset;
/**
* Limited number of groups.
*/
private final Integer limit;
public Map<String, Object> populateQueries() {
Map<String, Object> queries = new HashMap<>();
if(nonNull(query)) {
queries.put("query", query);
}
if(nonNull(type)) {
queries.put("type", type);
}
if(nonNull(filter)) {
queries.put("filter", filter);
}
if(nonNull(offset)) {
queries.put("offset", offset);
}
if(nonNull(limit)) {
queries.put("limit", limit);
}
return queries;
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupVisibilityStatus.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* Group Visibility status.
*/
public enum GroupVisibilityStatus {
UNKNOWN, RESTRICTED, PUBLIC, PROTECTED, PRIVATE, DISABLED, DELETED
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupsCountRequestArgs.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Builder;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.nonNull;
/**
* Request arguments for group count requests.
*/
@Builder
@Getter
public class GroupsCountRequestArgs {
private final String query;
private final GroupInfoType type;
private final GroupFilter filter;
public Map<String, Object> populateQueries() {
Map<String, Object> queries = new HashMap<>();
if (nonNull(query)) {
queries.put("query", query);
}
if (nonNull(type)) {
queries.put("type", type);
}
if (nonNull(filter)) {
queries.put("filter", filter);
}
return queries;
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/Language.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* DTO, which represents languages.
*/
public enum Language {
UNKNOWN,
ENGLISH,
GERMAN,
SPANISH,
HINDI,
FRENCH,
PORTUGUESE,
POLISH,
BENGALI,
PUNJABI,
CHINESE,
ITALIAN,
INDONESIAN,
MARATHI,
TAMIL,
TELUGU,
JAPANESE,
KOREAN,
URDU,
TAIWANESE,
NETHERLANDS,
RUSSIAN,
UKRAINIAN
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/LikeStatus.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* DTO, which represents like's status.
*/
public enum LikeStatus {
UNKNOWN,
LIKE,
HOT,
FOLLOW,
FAVORITE,
SOLUTION,
HELPFUL,
ARTICLE,
OSCAR,
DISLIKE,
WRONG,
SPAM,
ABUSE,
FOUL,
TROLLING,
OFFTOPIC,
DUPLICATE,
DIRTY,
OUTDATED,
BORING,
UNCLEAR,
HARD,
EASY,
FAKE,
SHAM,
AWFUL
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/LikesInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* DTO, which represents like's information.
*/
public class LikesInfo {
private Integer count;
private LikeStatus status;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/MeGroupInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
/**
* Group information related to authorized user. If there is no user - will be null.
*/
@Data
public class MeGroupInfo {
private MeGroupInfoStatus status;
private Integer userGroupId;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/MeGroupInfoStatus.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* Member group status.
*/
public enum MeGroupInfoStatus {
UNKNOWN, CANDIDATE, INVITEE, MEMBER, EDITOR, MODERATOR, ADMINISTRATOR, BANNED
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/PostInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
/**
* DTO, which represents post information.
*/
@Data
public class PostInfo {
private BaseUserInfo authorInfo;
private Integer commentsCount;
private String content;
private Long createdTime;
private String description;
private GroupInfo groupInfo;
private Integer id;
private String key;
private Language language;
private LikesInfo likesInfo;
private GroupInfo originalGroupInfo;
private String pictureUrl;
private Double rating;
private Integer ratingCount;
private String title;
private PostType type;
private Long updatedTime;
private UserDiscussionInfo userDiscussionInfo;
private Integer views;
private VisibilityStatus visibilityStatus;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/PostType.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* DTO, which represents post types.
*/
public enum PostType {
UNKNOWN, USUAL, INNER_LINK, OUTER_LINK
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/UserDiscussionInfo.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
import lombok.Data;
/**
* DTO for User discussion info.
*/
@Data
public class UserDiscussionInfo {
private Boolean isBookmarked;
private Integer lastTime;
private Integer newCommentsCount;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/UserPublicStatus.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* DTO, which represents user public status.
*/
public enum UserPublicStatus {
UNKNOWN,
BEGINNER,
ACTIVE,
STRONG,
GRADUATED,
INTERNSHIP_IN_PROGRESS,
INTERNSHIP_COMPLETED,
RESUME_COMPLETED,
LOOKING_FOR_JOB,
HAVE_JOB;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/VisibilityStatus.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient.dto;
/**
* DTO, which represents visibility status.
*/
public enum VisibilityStatus {
UNKNOWN,
RESTRICTED,
PUBLIC,
PROTECTED,
PRIVATE,
DISABLED,
DELETED
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/job/FindNewPostsJob.java
================================================
package com.github.javarushcommunity.jrtb.job;
import com.github.javarushcommunity.jrtb.service.FindNewPostsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
* Job for finding new posts.
*/
@Slf4j
@Component
public class FindNewPostsJob {
private final FindNewPostsService findNewPostsService;
@Autowired
public FindNewPostsJob(FindNewPostsService findNewPostsService) {
this.findNewPostsService = findNewPostsService;
}
@Scheduled(fixedRateString = "${bot.recountNewPostFixedRate}")
public void findNewPosts() {
LocalDateTime start = LocalDateTime.now();
log.info("Find new posts job started.");
findNewPostsService.findNewPosts();
LocalDateTime end = LocalDateTime.now();
log.info("Find new posts job finished. Took seconds: {}",
end.toEpochSecond(ZoneOffset.UTC) - start.toEpochSecond(ZoneOffset.UTC));
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/GroupSubRepository.java
================================================
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> {
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/TelegramUserRepository.java
================================================
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, Long> {
List<TelegramUser> findAllByActiveTrue();
List<TelegramUser> findAllByActiveFalse();
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/entity/GroupSub.java
================================================
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(exclude = "users")
public class GroupSub {
@Id
private Integer id;
@Column(name = "title")
private String title;
@Column(name = "last_post_id")
private Integer lastPostId;
@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);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/entity/TelegramUser.java
================================================
package com.github.javarushcommunity.jrtb.repository.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.*;
import java.util.List;
/**
* Telegram User entity.
*/
@Data
@Entity
@Table(name = "tg_user")
@EqualsAndHashCode(exclude = "groupSubs")
public class TelegramUser {
@Id
@Column(name = "chat_id")
private Long chatId;
@Column(name = "active")
private boolean active;
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/FindNewPostsService.java
================================================
package com.github.javarushcommunity.jrtb.service;
/**
* Service for finding new posts.
*/
public interface FindNewPostsService {
/**
* Find new posts and notify subscribers about it.
*/
void findNewPosts();
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/FindNewPostsServiceImpl.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.javarushclient.JavaRushPostClient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
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 java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class FindNewPostsServiceImpl implements FindNewPostsService {
public static final String JAVARUSH_WEB_POST_FORMAT = "https://javarush.ru/groups/posts/%s";
private final GroupSubService groupSubService;
private final JavaRushPostClient javaRushPostClient;
private final SendBotMessageService sendMessageService;
@Autowired
public FindNewPostsServiceImpl(GroupSubService groupSubService,
JavaRushPostClient javaRushPostClient,
SendBotMessageService sendMessageService) {
this.groupSubService = groupSubService;
this.javaRushPostClient = javaRushPostClient;
this.sendMessageService = sendMessageService;
}
@Override
public void findNewPosts() {
groupSubService.findAll().forEach(gSub -> {
List<PostInfo> newPosts = javaRushPostClient.findNewPosts(gSub.getId(), gSub.getLastPostId());
setNewLastPostId(gSub, newPosts);
notifySubscribersAboutNewPosts(gSub, newPosts);
});
}
private void notifySubscribersAboutNewPosts(GroupSub gSub, List<PostInfo> newPosts) {
Collections.reverse(newPosts);
List<String> messagesWithNewPosts = newPosts.stream()
.map(post -> String.format("✨Вышла новая статья <b>%s</b> в группе <b>%s</b>.✨\n\n" +
"<b>Описание:</b> %s\n\n" +
"<b>Ссылка:</b> %s\n",
post.getTitle(), gSub.getTitle(), post.getDescription(), getPostUrl(post.getKey())))
.collect(Collectors.toList());
gSub.getUsers().stream()
.filter(TelegramUser::isActive)
.forEach(it -> sendMessageService.sendMessage(it.getChatId(), messagesWithNewPosts));
}
private void setNewLastPostId(GroupSub gSub, List<PostInfo> newPosts) {
newPosts.stream().mapToInt(PostInfo::getId).max()
.ifPresent(id -> {
gSub.setLastPostId(id);
groupSubService.save(gSub);
});
}
private String getPostUrl(String key) {
return String.format(JAVARUSH_WEB_POST_FORMAT, key);
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/GroupSubService.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import java.util.List;
import java.util.Optional;
/**
* Service for manipulating with {@link GroupSub}.
*/
public interface GroupSubService {
GroupSub save(Long chatId, GroupDiscussionInfo groupDiscussionInfo);
GroupSub save(GroupSub groupSub);
Optional<GroupSub> findById(Integer id);
List<GroupSub> findAll();
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/GroupSubServiceImpl.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
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.List;
import java.util.Optional;
@Service
public class GroupSubServiceImpl implements GroupSubService {
private final GroupSubRepository groupSubRepository;
private final TelegramUserService telegramUserService;
private final JavaRushGroupClient javaRushGroupClient;
@Autowired
public GroupSubServiceImpl(GroupSubRepository groupSubRepository, TelegramUserService telegramUserService, JavaRushGroupClient javaRushGroupClient) {
this.groupSubRepository = groupSubRepository;
this.telegramUserService = telegramUserService;
this.javaRushGroupClient = javaRushGroupClient;
}
@Override
public GroupSub save(Long 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().equals(chatId))
.findFirst();
if (first.isEmpty()) {
groupSub.addUser(telegramUser);
}
} else {
groupSub = new GroupSub();
groupSub.addUser(telegramUser);
groupSub.setLastPostId(javaRushGroupClient.findLastPostId(groupDiscussionInfo.getId()));
groupSub.setId(groupDiscussionInfo.getId());
groupSub.setTitle(groupDiscussionInfo.getTitle());
}
return groupSubRepository.save(groupSub);
}
@Override
public GroupSub save(GroupSub groupSub) {
return groupSubRepository.save(groupSub);
}
@Override
public Optional<GroupSub> findById(Integer id) {
return groupSubRepository.findById(id);
}
@Override
public List<GroupSub> findAll() {
return groupSubRepository.findAll();
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/SendBotMessageService.java
================================================
package com.github.javarushcommunity.jrtb.service;
import java.util.List;
/**
* Service for sending messages via telegram-bot.
*/
public interface SendBotMessageService {
/**
* Send message via telegram bot.
*
* @param chatId provided chatId in which would be sent.
* @param message provided message to be sent.
*/
void sendMessage(Long chatId, String message);
/**
* Send messages via telegram bot.
*
* @param chatId provided chatId in which would be sent.
* @param message collection of provided messages to be sent.
*/
void sendMessage(Long chatId, List<String> message);
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/SendBotMessageServiceImpl.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.springframework.util.CollectionUtils.isEmpty;
/**
* Implementation of {@link SendBotMessageService} interface.
*/
@Service
public class SendBotMessageServiceImpl implements SendBotMessageService {
private final JavarushTelegramBot javarushBot;
@Autowired
public SendBotMessageServiceImpl(JavarushTelegramBot javarushBot) {
this.javarushBot = javarushBot;
}
@Override
public void sendMessage(Long chatId, String message) {
if (isBlank(message)) return;
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId.toString());
sendMessage.enableHtml(true);
sendMessage.setText(message);
try {
javarushBot.execute(sendMessage);
} catch (TelegramApiException e) {
//todo add logging to the project.
e.printStackTrace();
}
}
@Override
public void sendMessage(Long chatId, List<String> messages) {
if (isEmpty(messages)) return;
messages.forEach(m -> sendMessage(chatId, m));
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/StatisticsService.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.dto.StatisticDTO;
/**
* Service for getting bot statistics.
*/
public interface StatisticsService {
StatisticDTO countBotStatistic();
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/StatisticsServiceImpl.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.dto.GroupStatDTO;
import com.github.javarushcommunity.jrtb.dto.StatisticDTO;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.util.CollectionUtils.isEmpty;
@Service
public class StatisticsServiceImpl implements StatisticsService {
private final GroupSubService groupSubService;
private final TelegramUserService telegramUserService;
public StatisticsServiceImpl(GroupSubService groupSubService, TelegramUserService telegramUserService) {
this.groupSubService = groupSubService;
this.telegramUserService = telegramUserService;
}
@Override
public StatisticDTO countBotStatistic() {
List<GroupStatDTO> groupStatDTOS = groupSubService.findAll().stream()
.filter(it -> !isEmpty(it.getUsers()))
.map(groupSub -> new GroupStatDTO(groupSub.getId(), groupSub.getTitle(), groupSub.getUsers().size()))
.collect(Collectors.toList());
List<TelegramUser> allInActiveUsers = telegramUserService.findAllInActiveUsers();
List<TelegramUser> allActiveUsers = telegramUserService.findAllActiveUsers();
double groupsPerUser = getGroupsPerUser(allActiveUsers);
return new StatisticDTO(allActiveUsers.size(), allInActiveUsers.size(), groupStatDTOS, groupsPerUser);
}
private double getGroupsPerUser(List<TelegramUser> allActiveUsers) {
return (double) allActiveUsers.stream().mapToInt(it -> it.getGroupSubs().size()).sum() / allActiveUsers.size();
}
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/TelegramUserService.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* {@link Service} for handling {@link TelegramUser} entity.
*/
public interface TelegramUserService {
/**
* Save provided {@link TelegramUser} entity.
*
* @param telegramUser provided telegram user.
*/
void save(TelegramUser telegramUser);
/**
* Find all active {@link TelegramUser}.
*
* @return the collection of the active {@link TelegramUser} objects.
*/
List<TelegramUser> findAllActiveUsers();
/**
* Find all inactive {@link TelegramUser}
*
* @return the collection of the inactive {@link TelegramUser} objects.
*/
List<TelegramUser> findAllInActiveUsers();
/**
* Find {@link TelegramUser} by chatId.
*
* @param chatId provided Chat ID
* @return {@link TelegramUser} with provided chat ID or null otherwise.
*/
Optional<TelegramUser> findByChatId(Long chatId);
}
================================================
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/TelegramUserServiceImpl.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.repository.TelegramUserRepository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* Implementation of {@link TelegramUserService}.
*/
@Service
public class TelegramUserServiceImpl implements TelegramUserService {
private final TelegramUserRepository telegramUserRepository;
@Autowired
public TelegramUserServiceImpl(TelegramUserRepository telegramUserRepository) {
this.telegramUserRepository = telegramUserRepository;
}
@Override
public void save(TelegramUser telegramUser) {
telegramUserRepository.save(telegramUser);
}
@Override
public List<TelegramUser> findAllActiveUsers() {
return telegramUserRepository.findAllByActiveTrue();
}
@Override
public List<TelegramUser> findAllInActiveUsers() {
return telegramUserRepository.findAllByActiveFalse();
}
@Override
public Optional<TelegramUser> findByChatId(Long chatId) {
return telegramUserRepository.findById(chatId);
}
}
================================================
FILE: src/main/resources/application-test.properties
================================================
# MySQL configurations:
spring.datasource.url=jdbc:mysql://localhost:3306/dev_jrtb_db?characterEncoding=UTF-8
spring.datasource.username=dev_jrtb_db_user
spring.datasource.password=dev_jrtb_db_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# TelegramBot configurations:
bot.username=tes
bot.token=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
================================================
FILE: src/main/resources/application.properties
================================================
# MySQL configurations:
spring.datasource.url=jdbc:mysql://jrtb-db:3306/jrtb_db?characterEncoding=UTF-8
spring.datasource.username=jrtb_db_user
spring.datasource.password=jrtb_db_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
javarush.api.path=https://javarush.ru/api/1.0/rest
# TelegramBot configurations:
bot.username=test.javarush_community_bot
bot.token=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
bot.recountNewPostFixedRate = 900000
bot.admins: robeskman,romankh3
================================================
FILE: src/main/resources/db/migration/V00001__created_tg_user_table.sql
================================================
-- ensure that the table with this name is removed before creating a new one.
DROP TABLE IF EXISTS tg_user;
-- Create tg_user table
CREATE TABLE tg_user (
chat_id VARCHAR(100),
active BOOLEAN
);
================================================
FILE: src/main/resources/db/migration/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)
);
================================================
FILE: src/main/resources/db/migration/V00003__rename_last_article_id.sql
================================================
ALTER TABLE group_sub CHANGE COLUMN last_article_id last_post_id INT;
================================================
FILE: src/main/resources/db/migration/V00004_change_chat_Id_type_to_Long.sql
================================================
ALTER TABLE tg_user MODIFY chat_id INT;
================================================
FILE: src/main/resources/log4j2.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout
pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug" additivity="false">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/AbstractCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageServiceImpl;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
/**
* Abstract class for testing {@link Command}s.
*/
abstract class AbstractCommandTest {
protected JavarushTelegramBot javarushBot = Mockito.mock(JavarushTelegramBot.class);
protected SendBotMessageService sendBotMessageService = new SendBotMessageServiceImpl(javarushBot);
protected TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
abstract String getCommandName();
abstract String getCommandMessage();
abstract Command getCommand();
@Test
public void shouldProperlyExecuteCommand() throws TelegramApiException {
//given
Long chatId = 1234567824356L;
Update update = prepareUpdate(chatId, getCommandName());
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId.toString());
sendMessage.setText(getCommandMessage());
sendMessage.enableHtml(true);
//when
getCommand().execute(update);
//then
Mockito.verify(javarushBot).execute(sendMessage);
}
public static Update prepareUpdate(Long chatId, String commandName) {
Update update = new Update();
Message message = Mockito.mock(Message.class);
Mockito.when(message.getChatId()).thenReturn(chatId);
Mockito.when(message.getText()).thenReturn(commandName);
update.setMessage(message);
return update;
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/AdminHelpCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.AdminHelpCommand.ADMIN_HELP_MESSAGE;
import static com.github.javarushcommunity.jrtb.command.CommandName.ADMIN_HELP;
@DisplayName("Unit-level testing for AdminHelpCommand")
public class AdminHelpCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return ADMIN_HELP.getCommandName();
}
@Override
String getCommandMessage() {
return ADMIN_HELP_MESSAGE;
}
@Override
Command getCommand() {
return new AdminHelpCommand(sendBotMessageService);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/CommandContainerTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.StatisticsService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.Assertions;
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.Arrays;
import static java.util.Collections.singletonList;
@DisplayName("Unit-level testing for CommandContainer")
class CommandContainerTest {
private CommandContainer commandContainer;
@BeforeEach
public void init() {
SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
JavaRushGroupClient groupClient = Mockito.mock(JavaRushGroupClient.class);
GroupSubService groupSubService = Mockito.mock(GroupSubService.class);
StatisticsService statisticsService = Mockito.mock(StatisticsService.class);
commandContainer = new CommandContainer(sendBotMessageService,
telegramUserService,
groupClient,
groupSubService,
singletonList("username"),
statisticsService);
}
@Test
public void shouldGetAllTheExistingCommands() {
//when-then
Arrays.stream(CommandName.values())
.forEach(commandName -> {
Command command = commandContainer.findCommand(commandName.getCommandName(), "username");
Assertions.assertNotEquals(UnknownCommand.class, command.getClass());
});
}
@Test
public void shouldReturnUnknownCommand() {
//given
String unknownCommand = "/fgjhdfgdfg";
//when
Command command = commandContainer.findCommand(unknownCommand, "username");
//then
Assertions.assertEquals(UnknownCommand.class, command.getClass());
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/DeleteGroupSubCommandTest.java
================================================
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(chatId))
.thenReturn(Optional.of(new TelegramUser()));
String expectedMessage = "Пока нет подписок на группы. Чтобы добавить подписку напиши /addGroupSub";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId, 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(chatId))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "Чтобы удалить подписку на группу - передай комадну вместе с ID группы. \n" +
"Например: /deleteGroupSub 16 \n\n" +
"я подготовил список всех групп, на которые ты подписан) \n\n" +
"имя группы - ID группы \n\n" +
"GS1 Title - 123 \n";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId, 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(chatId))
.thenReturn(Optional.of(telegramUser));
String expectedMessage = "неправильный формат ID группы.\n " +
"ID должно быть целым положительным числом";
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId, 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);
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(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, 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, expectedMessage);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/HelpCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.HELP;
import static com.github.javarushcommunity.jrtb.command.HelpCommand.HELP_MESSAGE;
@DisplayName("Unit-level testing for HelpCommand")
public class HelpCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return HELP.getCommandName();
}
@Override
String getCommandMessage() {
return HELP_MESSAGE;
}
@Override
Command getCommand() {
return new HelpCommand(sendBotMessageService);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/ListGroupSubCommandTest.java
================================================
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.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.github.javarushcommunity.jrtb.command.AbstractCommandTest.prepareUpdate;
import static com.github.javarushcommunity.jrtb.command.CommandName.LIST_GROUP_SUB;
@DisplayName("Unit-level testing for ListGroupSubCommand")
public class ListGroupSubCommandTest {
@Test
public void shouldProperlyShowsListGroupSub() {
//given
TelegramUser telegramUser = new TelegramUser();
telegramUser.setActive(true);
telegramUser.setChatId(1L);
List<GroupSub> groupSubList = new ArrayList<>();
groupSubList.add(populateGroupSub(1, "gs1"));
groupSubList.add(populateGroupSub(2, "gs2"));
groupSubList.add(populateGroupSub(3, "gs3"));
groupSubList.add(populateGroupSub(4, "gs4"));
telegramUser.setGroupSubs(groupSubList);
SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
Mockito.when(telegramUserService.findByChatId(telegramUser.getChatId())).thenReturn(Optional.of(telegramUser));
ListGroupSubCommand command = new ListGroupSubCommand(sendBotMessageService, telegramUserService);
Update update = prepareUpdate(Long.valueOf(telegramUser.getChatId()), LIST_GROUP_SUB.getCommandName());
String joinedGroups = telegramUser.getGroupSubs().stream()
.map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
.collect(Collectors.joining());
String collectedGroups = String.format("Я нашел все подписки на группы: \n\n %s", joinedGroups);
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(telegramUser.getChatId(), collectedGroups);
}
private GroupSub populateGroupSub(Integer id, String title) {
GroupSub gs = new GroupSub();
gs.setId(id);
gs.setTitle(title);
return gs;
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/NoCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.NO;
import static com.github.javarushcommunity.jrtb.command.NoCommand.NO_MESSAGE;
@DisplayName("Unit-level testing for NoCommand")
public class NoCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return NO.getCommandName();
}
@Override
String getCommandMessage() {
return NO_MESSAGE;
}
@Override
Command getCommand() {
return new NoCommand(sendBotMessageService);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/StartCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.START;
import static com.github.javarushcommunity.jrtb.command.StartCommand.START_MESSAGE;
@DisplayName("Unit-level testing for StartCommand")
class StartCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return START.getCommandName();
}
@Override
String getCommandMessage() {
return START_MESSAGE;
}
@Override
Command getCommand() {
return new StartCommand(sendBotMessageService, telegramUserService);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/StatCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.dto.GroupStatDTO;
import com.github.javarushcommunity.jrtb.dto.StatisticDTO;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.StatisticsService;
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.Collections;
import static com.github.javarushcommunity.jrtb.command.AbstractCommandTest.prepareUpdate;
import static com.github.javarushcommunity.jrtb.command.StatCommand.STAT_MESSAGE;
import static java.lang.String.format;
@DisplayName("Unit-level testing for StatCommand")
public class StatCommandTest {
private SendBotMessageService sendBotMessageService;
private StatisticsService statisticsService;
private Command statCommand;
@BeforeEach
public void init() {
sendBotMessageService = Mockito.mock(SendBotMessageService.class);
statisticsService = Mockito.mock(StatisticsService.class);
statCommand = new StatCommand(sendBotMessageService, statisticsService);
}
@Test
public void shouldProperlySendMessage() {
//given
Long chatId = 1234567L;
GroupStatDTO groupDto = new GroupStatDTO(1, "group", 1);
StatisticDTO statisticDTO = new StatisticDTO(1, 1, Collections.singletonList(groupDto), 2.5);
Mockito.when(statisticsService.countBotStatistic())
.thenReturn(statisticDTO);
//when
statCommand.execute(prepareUpdate(chatId, CommandName.STAT.getCommandName()));
//then
Mockito.verify(sendBotMessageService).sendMessage(chatId, format(STAT_MESSAGE,
statisticDTO.getActiveUserCount(),
statisticDTO.getInactiveUserCount(),
statisticDTO.getAverageGroupCountByUser(),
format("%s (id = %s) - %s подписчиков", groupDto.getTitle(), groupDto.getId(), groupDto.getActiveUserCount())));
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/StopCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.CommandName.STOP;
import static com.github.javarushcommunity.jrtb.command.StopCommand.STOP_MESSAGE;
@DisplayName("Unit-level testing for StopCommand")
public class StopCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return STOP.getCommandName();
}
@Override
String getCommandMessage() {
return STOP_MESSAGE;
}
@Override
Command getCommand() {
return new StopCommand(sendBotMessageService, telegramUserService);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/UnknownCommandTest.java
================================================
package com.github.javarushcommunity.jrtb.command;
import org.junit.jupiter.api.DisplayName;
import static com.github.javarushcommunity.jrtb.command.UnknownCommand.UNKNOWN_MESSAGE;
@DisplayName("Unit-level testing for UnknownCommand")
public class UnknownCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return "/fdgdfgdfgdbd";
}
@Override
String getCommandMessage() {
return UNKNOWN_MESSAGE;
}
@Override
Command getCommand() {
return new UnknownCommand(sendBotMessageService);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClientTest.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupsCountRequestArgs;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static com.github.javarushcommunity.jrtb.javarushclient.dto.GroupInfoType.TECH;
@DisplayName("Integration-level testing for JavaRushGroupClientImplTest")
class JavaRushGroupClientTest {
public static final String JAVARUSH_API_PATH = "https://javarush.ru/api/1.0/rest";
private final JavaRushGroupClient groupClient = new JavaRushGroupClientImpl(JAVARUSH_API_PATH);
@Test
public void shouldProperlyGetGroupsWithEmptyArgs() {
//given
GroupRequestArgs args = GroupRequestArgs.builder().build();
//when
List<GroupInfo> groupList = groupClient.getGroupList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertFalse(groupList.isEmpty());
}
@Test
public void shouldProperlyGetWithOffSetAndLimit() {
//given
GroupRequestArgs args = GroupRequestArgs.builder()
.offset(1)
.limit(3)
.build();
//when
List<GroupInfo> groupList = groupClient.getGroupList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertEquals(3, groupList.size());
}
@Test
public void shouldProperlyGetGroupsDiscWithEmptyArgs() {
//given
GroupRequestArgs args = GroupRequestArgs.builder().build();
//when
List<GroupDiscussionInfo> groupList = groupClient.getGroupDiscussionList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertFalse(groupList.isEmpty());
}
@Test
public void shouldProperlyGetGroupDiscWithOffSetAndLimit() {
//given
GroupRequestArgs args = GroupRequestArgs.builder()
.offset(1)
.limit(3)
.build();
//when
List<GroupDiscussionInfo> groupList = groupClient.getGroupDiscussionList(args);
//then
Assertions.assertNotNull(groupList);
Assertions.assertEquals(3, groupList.size());
}
@Test
public void shouldProperlyGetGroupCount() {
//given
GroupsCountRequestArgs args = GroupsCountRequestArgs.builder().build();
//when
Integer groupCount = groupClient.getGroupCount(args);
//then
Assertions.assertEquals(30, groupCount);
}
@Test
public void shouldProperlyGetGroupTECHCount() {
//given
GroupsCountRequestArgs args = GroupsCountRequestArgs.builder()
.type(TECH)
.build();
//when
Integer groupCount = groupClient.getGroupCount(args);
//then
Assertions.assertEquals(7, groupCount);
}
@Test
public void shouldProperlyGetGroupById() {
//given
Integer androidGroupId = 16;
//when
GroupDiscussionInfo groupById = groupClient.getGroupById(androidGroupId);
//then
Assertions.assertNotNull(groupById);
Assertions.assertEquals(16, groupById.getId());
Assertions.assertEquals(TECH, groupById.getType());
Assertions.assertEquals("android", groupById.getKey());
}
@Test
public void shouldNotProperlyGetGroupById() {
//given
Integer androidGroupId = Integer.MAX_VALUE;
//when
GroupDiscussionInfo groupById = groupClient.getGroupById(androidGroupId);
//then
Assertions.assertNull(groupById.getKey());
Assertions.assertNull(groupById.getId());
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClientTest.java
================================================
package com.github.javarushcommunity.jrtb.javarushclient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClientTest.JAVARUSH_API_PATH;
@DisplayName("Integration-level testing for JavaRushPostClient")
class JavaRushPostClientTest {
private final JavaRushPostClient postClient = new JavaRushPostClientImpl(JAVARUSH_API_PATH);
@Test
public void shouldProperlyGetNew15Posts() {
//when
List<PostInfo> newPosts = postClient.findNewPosts(30, 2935);
//then
Assertions.assertEquals(15, newPosts.size());
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/repository/GroupSubRepositoryIT.java
================================================
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(Long.valueOf(i + 1), users.get(i).getChatId());
Assertions.assertTrue(users.get(i).isActive());
}
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/repository/TelegramUserRepositoryIT.java
================================================
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 TelegramUserRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class TelegramUserRepositoryIT {
@Autowired
private TelegramUserRepository telegramUserRepository;
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
@Test
public void shouldProperlyFindAllActiveUsers() {
//when
List<TelegramUser> users = telegramUserRepository.findAllByActiveTrue();
//then
Assertions.assertEquals(5, users.size());
}
@Sql(scripts = {"/sql/clearDbs.sql"})
@Test
public void shouldProperlySaveTelegramUser() {
//given
TelegramUser telegramUser = new TelegramUser();
telegramUser.setChatId(1234567890L);
telegramUser.setActive(false);
telegramUserRepository.save(telegramUser);
//when
Optional<TelegramUser> saved = telegramUserRepository.findById(telegramUser.getChatId());
//then
Assertions.assertTrue(saved.isPresent());
Assertions.assertEquals(telegramUser, saved.get());
}
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveGroupSubsForUser.sql"})
@Test
public void shouldProperlyGetAllGroupSubsForUser() {
//when
Optional<TelegramUser> userFromDB = telegramUserRepository.findById(1L);
//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).getLastPostId());
}
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/service/GroupSubServiceTest.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
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 JavaRushGroupClient javaRushGroupClient;
private TelegramUser newUser;
private final static Long CHAT_ID = 1234234L;
private final static Integer GROUP_ID = 1123;
private final static Integer LAST_POST_ID = 310;
@BeforeEach
public void init() {
TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
groupSubRepository = Mockito.mock(GroupSubRepository.class);
javaRushGroupClient = Mockito.mock(JavaRushGroupClient.class);
groupSubService = new GroupSubServiceImpl(groupSubRepository, telegramUserService, javaRushGroupClient);
newUser = new TelegramUser();
newUser.setActive(true);
newUser.setChatId(CHAT_ID);
Mockito.when(telegramUserService.findByChatId(CHAT_ID)).thenReturn(Optional.of(newUser));
Mockito.when(javaRushGroupClient.findLastPostId(GROUP_ID)).thenReturn(LAST_POST_ID);
}
@Test
public void shouldProperlySaveGroup() {
//given
GroupDiscussionInfo groupDiscussionInfo = new GroupDiscussionInfo();
groupDiscussionInfo.setId(GROUP_ID);
groupDiscussionInfo.setTitle("g1");
GroupSub expectedGroupSub = new GroupSub();
expectedGroupSub.setId(groupDiscussionInfo.getId());
expectedGroupSub.setTitle(groupDiscussionInfo.getTitle());
expectedGroupSub.setLastPostId(LAST_POST_ID);
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(2L);
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);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/service/SendBotMessageServiceTest.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;
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.methods.send.SendMessage;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
@DisplayName("Unit-level testing for SendBotMessageService")
public class SendBotMessageServiceTest {
private SendBotMessageService sendBotMessageService;
private JavarushTelegramBot javarushBot;
@BeforeEach
public void init() {
javarushBot = Mockito.mock(JavarushTelegramBot.class);
sendBotMessageService = new SendBotMessageServiceImpl(javarushBot);
}
@Test
public void shouldProperlySendMessage() throws TelegramApiException {
//given
Long chatId = 123L;
String message = "test_message";
SendMessage sendMessage = new SendMessage();
sendMessage.setText(message);
sendMessage.setChatId(chatId.toString());
sendMessage.enableHtml(true);
//when
sendBotMessageService.sendMessage(chatId, message);
//then
Mockito.verify(javarushBot).execute(sendMessage);
}
}
================================================
FILE: src/test/java/com/github/javarushcommunity/jrtb/service/StatisticsServiceImplTest.java
================================================
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.dto.GroupStatDTO;
import com.github.javarushcommunity.jrtb.dto.StatisticDTO;
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.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static java.util.Collections.singletonList;
@DisplayName("Unit-level testing for StatisticsService")
class StatisticsServiceTest {
private GroupSubService groupSubService;
private TelegramUserService telegramUserService;
private StatisticsService statisticsService;
@BeforeEach
public void init() {
groupSubService = Mockito.mock(GroupSubService.class);
telegramUserService = Mockito.mock(TelegramUserService.class);
statisticsService = new StatisticsServiceImpl(groupSubService, telegramUserService);
}
@Test
public void shouldProperlySendStatDTO() {
//given
Mockito.when(telegramUserService.findAllInActiveUsers()).thenReturn(singletonList(new TelegramUser()));
TelegramUser activeUser = new TelegramUser();
activeUser.setGroupSubs(singletonList(new GroupSub()));
Mockito.when(telegramUserService.findAllActiveUsers()).thenReturn(singletonList(activeUser));
GroupSub groupSub = new GroupSub();
groupSub.setTitle("group");
groupSub.setId(1);
groupSub.setUsers(singletonList(new TelegramUser()));
Mockito.when(groupSubService.findAll()).thenReturn(singletonList(groupSub));
//when
StatisticDTO statisticDTO = statisticsService.countBotStatistic();
//then
Assertions.assertNotNull(statisticDTO);
Assertions.assertEquals(1, statisticDTO.getActiveUserCount());
Assertions.assertEquals(1, statisticDTO.getInactiveUserCount());
Assertions.assertEquals(1.0, statisticDTO.getAverageGroupCountByUser());
Assertions.assertEquals(singletonList(new GroupStatDTO(groupSub.getId(), groupSub.getTitle(), groupSub.getUsers().size())),
statisticDTO.getGroupStatDTOs());
}
}
================================================
FILE: src/test/resources/sql/clearDbs.sql
================================================
DELETE FROM group_x_user;
DELETE FROM group_sub;
DELETE FROM tg_user;
================================================
FILE: src/test/resources/sql/fiveGroupSubsForUser.sql
================================================
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);
================================================
FILE: src/test/resources/sql/fiveUsersForGroupSub.sql
================================================
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);
================================================
FILE: src/test/resources/sql/telegram_users.sql
================================================
INSERT INTO tg_user VALUES ("123456789", 1);
INSERT INTO tg_user VALUES ("123456788", 1);
INSERT INTO tg_user VALUES ("123456787", 1);
INSERT INTO tg_user VALUES ("123456786", 1);
INSERT INTO tg_user VALUES ("123456785", 1);
INSERT INTO tg_user VALUES ("123456784", 0);
INSERT INTO tg_user VALUES ("123456782", 0);
INSERT INTO tg_user VALUES ("123456781", 0);
================================================
FILE: start.sh
================================================
#!/bin/bash
# Pull new changes
git pull
# Prepare Jar
mvn clean
mvn package
# Ensure, that docker-compose stopped
docker-compose stop
# Add environment variables
export BOT_NAME=$1
export BOT_TOKEN=$2
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
# Start new deployment
docker-compose up --build -d
================================================
FILE: stop.sh
================================================
#!/bin/bash
# Ensure, that docker-compose stopped
docker-compose stop
# Ensure, that the old application won't be deployed again.
mvn clean
gitextract_6x5b_faq/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ ├── improvement-request.md │ │ └── question.md │ ├── pull_request_template.md │ └── workflows/ │ └── maven.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── Find_New_Posts_WF.bpmn ├── LICENSE ├── README.md ├── RELEASE_NOTES.md ├── SET_UP_COMMANDS_BOT_FATHER ├── docker-compose-test.yml ├── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── github/ │ │ │ └── javarushcommunity/ │ │ │ └── jrtb/ │ │ │ ├── JavarushTelegramBotApplication.java │ │ │ ├── bot/ │ │ │ │ └── JavarushTelegramBot.java │ │ │ ├── command/ │ │ │ │ ├── AddGroupSubCommand.java │ │ │ │ ├── AdminHelpCommand.java │ │ │ │ ├── Command.java │ │ │ │ ├── CommandContainer.java │ │ │ │ ├── CommandName.java │ │ │ │ ├── CommandUtils.java │ │ │ │ ├── DeleteGroupSubCommand.java │ │ │ │ ├── HelpCommand.java │ │ │ │ ├── ListGroupSubCommand.java │ │ │ │ ├── NoCommand.java │ │ │ │ ├── StartCommand.java │ │ │ │ ├── StatCommand.java │ │ │ │ ├── StopCommand.java │ │ │ │ ├── UnknownCommand.java │ │ │ │ └── annotation/ │ │ │ │ └── AdminCommand.java │ │ │ ├── dto/ │ │ │ │ ├── GroupStatDTO.java │ │ │ │ └── StatisticDTO.java │ │ │ ├── javarushclient/ │ │ │ │ ├── JavaRushGroupClient.java │ │ │ │ ├── JavaRushGroupClientImpl.java │ │ │ │ ├── JavaRushPostClient.java │ │ │ │ ├── JavaRushPostClientImpl.java │ │ │ │ └── dto/ │ │ │ │ ├── BaseUserInfo.java │ │ │ │ ├── GroupDiscussionInfo.java │ │ │ │ ├── GroupFilter.java │ │ │ │ ├── GroupInfo.java │ │ │ │ ├── GroupInfoType.java │ │ │ │ ├── GroupRequestArgs.java │ │ │ │ ├── GroupVisibilityStatus.java │ │ │ │ ├── GroupsCountRequestArgs.java │ │ │ │ ├── Language.java │ │ │ │ ├── LikeStatus.java │ │ │ │ ├── LikesInfo.java │ │ │ │ ├── MeGroupInfo.java │ │ │ │ ├── MeGroupInfoStatus.java │ │ │ │ ├── PostInfo.java │ │ │ │ ├── PostType.java │ │ │ │ ├── UserDiscussionInfo.java │ │ │ │ ├── UserPublicStatus.java │ │ │ │ └── VisibilityStatus.java │ │ │ ├── job/ │ │ │ │ └── FindNewPostsJob.java │ │ │ ├── repository/ │ │ │ │ ├── GroupSubRepository.java │ │ │ │ ├── TelegramUserRepository.java │ │ │ │ └── entity/ │ │ │ │ ├── GroupSub.java │ │ │ │ └── TelegramUser.java │ │ │ └── service/ │ │ │ ├── FindNewPostsService.java │ │ │ ├── FindNewPostsServiceImpl.java │ │ │ ├── GroupSubService.java │ │ │ ├── GroupSubServiceImpl.java │ │ │ ├── SendBotMessageService.java │ │ │ ├── SendBotMessageServiceImpl.java │ │ │ ├── StatisticsService.java │ │ │ ├── StatisticsServiceImpl.java │ │ │ ├── TelegramUserService.java │ │ │ └── TelegramUserServiceImpl.java │ │ └── resources/ │ │ ├── application-test.properties │ │ ├── application.properties │ │ ├── db/ │ │ │ └── migration/ │ │ │ ├── V00001__created_tg_user_table.sql │ │ │ ├── V00002__created_groupsub_many_to_many.sql │ │ │ ├── V00003__rename_last_article_id.sql │ │ │ └── V00004_change_chat_Id_type_to_Long.sql │ │ └── log4j2.xml │ └── test/ │ ├── java/ │ │ └── com/ │ │ └── github/ │ │ └── javarushcommunity/ │ │ └── jrtb/ │ │ ├── command/ │ │ │ ├── AbstractCommandTest.java │ │ │ ├── AdminHelpCommandTest.java │ │ │ ├── CommandContainerTest.java │ │ │ ├── DeleteGroupSubCommandTest.java │ │ │ ├── HelpCommandTest.java │ │ │ ├── ListGroupSubCommandTest.java │ │ │ ├── NoCommandTest.java │ │ │ ├── StartCommandTest.java │ │ │ ├── StatCommandTest.java │ │ │ ├── StopCommandTest.java │ │ │ └── UnknownCommandTest.java │ │ ├── javarushclient/ │ │ │ ├── JavaRushGroupClientTest.java │ │ │ └── JavaRushPostClientTest.java │ │ ├── repository/ │ │ │ ├── GroupSubRepositoryIT.java │ │ │ └── TelegramUserRepositoryIT.java │ │ └── service/ │ │ ├── GroupSubServiceTest.java │ │ ├── SendBotMessageServiceTest.java │ │ └── StatisticsServiceImplTest.java │ └── resources/ │ └── sql/ │ ├── clearDbs.sql │ ├── fiveGroupSubsForUser.sql │ ├── fiveUsersForGroupSub.sql │ └── telegram_users.sql ├── start.sh └── stop.sh
SYMBOL INDEX (223 symbols across 75 files)
FILE: src/main/java/com/github/javarushcommunity/jrtb/JavarushTelegramBotApplication.java
class JavarushTelegramBotApplication (line 7) | @EnableScheduling
method main (line 11) | public static void main(String[] args) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/bot/JavarushTelegramBot.java
class JavarushTelegramBot (line 22) | @Component
method JavarushTelegramBot (line 36) | @Autowired
method onUpdateReceived (line 44) | @Override
method getBotUsername (line 58) | @Override
method getBotToken (line 63) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/AddGroupSubCommand.java
class AddGroupSubCommand (line 24) | public class AddGroupSubCommand implements Command {
method AddGroupSubCommand (line 30) | public AddGroupSubCommand(SendBotMessageService sendBotMessageService,...
method execute (line 37) | @Override
method sendGroupNotFound (line 57) | private void sendGroupNotFound(Long chatId, String groupId) {
method sendNotValidGroupID (line 62) | private void sendNotValidGroupID(Long chatId, String groupId) {
method sendGroupIdList (line 67) | private void sendGroupIdList(Long chatId) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/AdminHelpCommand.java
class AdminHelpCommand (line 13) | public class AdminHelpCommand implements Command {
method AdminHelpCommand (line 22) | public AdminHelpCommand(SendBotMessageService sendBotMessageService) {
method execute (line 26) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/Command.java
type Command (line 8) | public interface Command {
method execute (line 15) | void execute(Update update);
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/CommandContainer.java
class CommandContainer (line 19) | public class CommandContainer {
method CommandContainer (line 25) | public CommandContainer(SendBotMessageService sendBotMessageService, T...
method findCommand (line 48) | public Command findCommand(String commandIdentifier, String username) {
method isAdminCommand (line 60) | private boolean isAdminCommand(Command command) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/CommandName.java
type CommandName (line 6) | public enum CommandName {
method CommandName (line 20) | CommandName(String commandName) {
method getCommandName (line 24) | public String getCommandName() {
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/CommandUtils.java
class CommandUtils (line 8) | public class CommandUtils {
method getChatId (line 16) | public static Long getChatId(Update update) {
method getMessage (line 26) | public static String getMessage(Update update) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/DeleteGroupSubCommand.java
class DeleteGroupSubCommand (line 26) | public class DeleteGroupSubCommand implements Command {
method DeleteGroupSubCommand (line 32) | public DeleteGroupSubCommand(SendBotMessageService sendBotMessageServi...
method execute (line 39) | @Override
method sendGroupIdList (line 64) | private void sendGroupIdList(Long chatId) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/HelpCommand.java
class HelpCommand (line 12) | public class HelpCommand implements Command {
method HelpCommand (line 31) | public HelpCommand(SendBotMessageService sendBotMessageService) {
method execute (line 35) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/ListGroupSubCommand.java
class ListGroupSubCommand (line 18) | public class ListGroupSubCommand implements Command {
method ListGroupSubCommand (line 23) | public ListGroupSubCommand(SendBotMessageService sendBotMessageService...
method execute (line 28) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/NoCommand.java
class NoCommand (line 11) | public class NoCommand implements Command {
method NoCommand (line 18) | public NoCommand(SendBotMessageService sendBotMessageService) {
method execute (line 22) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/StartCommand.java
class StartCommand (line 13) | public class StartCommand implements Command {
method StartCommand (line 23) | public StartCommand(SendBotMessageService sendBotMessageService, Teleg...
method execute (line 28) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/StatCommand.java
class StatCommand (line 17) | @AdminCommand
method StatCommand (line 30) | @Autowired
method execute (line 36) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/StopCommand.java
class StopCommand (line 15) | public class StopCommand implements Command {
method StopCommand (line 23) | public StopCommand(SendBotMessageService sendBotMessageService, Telegr...
method execute (line 28) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/command/UnknownCommand.java
class UnknownCommand (line 11) | public class UnknownCommand implements Command {
method UnknownCommand (line 17) | public UnknownCommand(SendBotMessageService sendBotMessageService) {
method execute (line 21) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/dto/GroupStatDTO.java
class GroupStatDTO (line 9) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/dto/StatisticDTO.java
class StatisticDTO (line 11) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClient.java
type JavaRushGroupClient (line 13) | public interface JavaRushGroupClient {
method getGroupList (line 21) | List<GroupInfo> getGroupList(GroupRequestArgs requestArgs);
method getGroupDiscussionList (line 29) | List<GroupDiscussionInfo> getGroupDiscussionList(GroupRequestArgs requ...
method getGroupCount (line 37) | Integer getGroupCount(GroupsCountRequestArgs countRequestArgs);
method getGroupById (line 45) | GroupDiscussionInfo getGroupById(Integer id);
method findLastPostId (line 47) | Integer findLastPostId(Integer groupSub);
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClientImpl.java
class JavaRushGroupClientImpl (line 17) | @Component
method JavaRushGroupClientImpl (line 23) | public JavaRushGroupClientImpl(@Value("${javarush.api.path}") String j...
method getGroupList (line 29) | @Override
method getGroupDiscussionList (line 38) | @Override
method getGroupCount (line 47) | @Override
method getGroupById (line 57) | @Override
method findLastPostId (line 64) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClient.java
type JavaRushPostClient (line 10) | public interface JavaRushPostClient {
method findNewPosts (line 19) | List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId);
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClientImpl.java
class JavaRushPostClientImpl (line 12) | @Component
method JavaRushPostClientImpl (line 17) | public JavaRushPostClientImpl(@Value("${javarush.api.path}") String ja...
method findNewPosts (line 21) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/BaseUserInfo.java
class BaseUserInfo (line 8) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupDiscussionInfo.java
class GroupDiscussionInfo (line 10) | @EqualsAndHashCode(callSuper = true)
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupFilter.java
type GroupFilter (line 6) | public enum GroupFilter {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupInfo.java
class GroupInfo (line 9) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupInfoType.java
type GroupInfoType (line 6) | public enum GroupInfoType {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupRequestArgs.java
class GroupRequestArgs (line 13) | @Builder
method populateQueries (line 30) | public Map<String, Object> populateQueries() {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupVisibilityStatus.java
type GroupVisibilityStatus (line 6) | public enum GroupVisibilityStatus {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/GroupsCountRequestArgs.java
class GroupsCountRequestArgs (line 14) | @Builder
method populateQueries (line 21) | public Map<String, Object> populateQueries() {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/Language.java
type Language (line 6) | public enum Language {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/LikeStatus.java
type LikeStatus (line 6) | public enum LikeStatus {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/LikesInfo.java
class LikesInfo (line 6) | public class LikesInfo {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/MeGroupInfo.java
class MeGroupInfo (line 8) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/MeGroupInfoStatus.java
type MeGroupInfoStatus (line 6) | public enum MeGroupInfoStatus {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/PostInfo.java
class PostInfo (line 8) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/PostType.java
type PostType (line 6) | public enum PostType {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/UserDiscussionInfo.java
class UserDiscussionInfo (line 8) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/UserPublicStatus.java
type UserPublicStatus (line 6) | public enum UserPublicStatus {
FILE: src/main/java/com/github/javarushcommunity/jrtb/javarushclient/dto/VisibilityStatus.java
type VisibilityStatus (line 6) | public enum VisibilityStatus {
FILE: src/main/java/com/github/javarushcommunity/jrtb/job/FindNewPostsJob.java
class FindNewPostsJob (line 15) | @Slf4j
method FindNewPostsJob (line 21) | @Autowired
method findNewPosts (line 26) | @Scheduled(fixedRateString = "${bot.recountNewPostFixedRate}")
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/GroupSubRepository.java
type GroupSubRepository (line 10) | @Repository
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/TelegramUserRepository.java
type TelegramUserRepository (line 12) | @Repository
method findAllByActiveTrue (line 14) | List<TelegramUser> findAllByActiveTrue();
method findAllByActiveFalse (line 15) | List<TelegramUser> findAllByActiveFalse();
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/entity/GroupSub.java
class GroupSub (line 12) | @Data
method addUser (line 35) | public void addUser(TelegramUser telegramUser) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/repository/entity/TelegramUser.java
class TelegramUser (line 12) | @Data
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/FindNewPostsService.java
type FindNewPostsService (line 6) | public interface FindNewPostsService {
method findNewPosts (line 11) | void findNewPosts();
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/FindNewPostsServiceImpl.java
class FindNewPostsServiceImpl (line 14) | @Service
method FindNewPostsServiceImpl (line 23) | @Autowired
method findNewPosts (line 33) | @Override
method notifySubscribersAboutNewPosts (line 44) | private void notifySubscribersAboutNewPosts(GroupSub gSub, List<PostIn...
method setNewLastPostId (line 58) | private void setNewLastPostId(GroupSub gSub, List<PostInfo> newPosts) {
method getPostUrl (line 66) | private String getPostUrl(String key) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/GroupSubService.java
type GroupSubService (line 12) | public interface GroupSubService {
method save (line 14) | GroupSub save(Long chatId, GroupDiscussionInfo groupDiscussionInfo);
method save (line 16) | GroupSub save(GroupSub groupSub);
method findById (line 18) | Optional<GroupSub> findById(Integer id);
method findAll (line 20) | List<GroupSub> findAll();
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/GroupSubServiceImpl.java
class GroupSubServiceImpl (line 15) | @Service
method GroupSubServiceImpl (line 22) | @Autowired
method save (line 29) | @Override
method save (line 53) | @Override
method findById (line 58) | @Override
method findAll (line 63) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/SendBotMessageService.java
type SendBotMessageService (line 8) | public interface SendBotMessageService {
method sendMessage (line 16) | void sendMessage(Long chatId, String message);
method sendMessage (line 24) | void sendMessage(Long chatId, List<String> message);
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/SendBotMessageServiceImpl.java
class SendBotMessageServiceImpl (line 17) | @Service
method SendBotMessageServiceImpl (line 22) | @Autowired
method sendMessage (line 27) | @Override
method sendMessage (line 44) | @Override
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/StatisticsService.java
type StatisticsService (line 8) | public interface StatisticsService {
method countBotStatistic (line 9) | StatisticDTO countBotStatistic();
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/StatisticsServiceImpl.java
class StatisticsServiceImpl (line 13) | @Service
method StatisticsServiceImpl (line 19) | public StatisticsServiceImpl(GroupSubService groupSubService, Telegram...
method countBotStatistic (line 24) | @Override
method getGroupsPerUser (line 37) | private double getGroupsPerUser(List<TelegramUser> allActiveUsers) {
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/TelegramUserService.java
type TelegramUserService (line 12) | public interface TelegramUserService {
method save (line 19) | void save(TelegramUser telegramUser);
method findAllActiveUsers (line 26) | List<TelegramUser> findAllActiveUsers();
method findAllInActiveUsers (line 33) | List<TelegramUser> findAllInActiveUsers();
method findByChatId (line 41) | Optional<TelegramUser> findByChatId(Long chatId);
FILE: src/main/java/com/github/javarushcommunity/jrtb/service/TelegramUserServiceImpl.java
class TelegramUserServiceImpl (line 14) | @Service
method TelegramUserServiceImpl (line 19) | @Autowired
method save (line 24) | @Override
method findAllActiveUsers (line 29) | @Override
method findAllInActiveUsers (line 34) | @Override
method findByChatId (line 39) | @Override
FILE: src/main/resources/db/migration/V00001__created_tg_user_table.sql
type tg_user (line 5) | CREATE TABLE tg_user (
FILE: src/main/resources/db/migration/V00002__created_groupsub_many_to_many.sql
type group_sub (line 8) | CREATE TABLE group_sub (
type group_x_user (line 15) | CREATE TABLE group_x_user (
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/AbstractCommandTest.java
class AbstractCommandTest (line 17) | abstract class AbstractCommandTest {
method getCommandName (line 23) | abstract String getCommandName();
method getCommandMessage (line 25) | abstract String getCommandMessage();
method getCommand (line 27) | abstract Command getCommand();
method shouldProperlyExecuteCommand (line 29) | @Test
method prepareUpdate (line 48) | public static Update prepareUpdate(Long chatId, String commandName) {
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/AdminHelpCommandTest.java
class AdminHelpCommandTest (line 8) | @DisplayName("Unit-level testing for AdminHelpCommand")
method getCommandName (line 11) | @Override
method getCommandMessage (line 16) | @Override
method getCommand (line 21) | @Override
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/CommandContainerTest.java
class CommandContainerTest (line 18) | @DisplayName("Unit-level testing for CommandContainer")
method init (line 23) | @BeforeEach
method shouldGetAllTheExistingCommands (line 38) | @Test
method shouldReturnUnknownCommand (line 48) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/DeleteGroupSubCommandTest.java
class DeleteGroupSubCommandTest (line 21) | @DisplayName("Unit-level testing for DeleteGroupSubCommand")
method init (line 30) | @BeforeEach
method shouldProperlyReturnEmptySubscriptionList (line 39) | @Test
method shouldProperlyReturnSubscriptionLit (line 57) | @Test
method shouldRejectByInvalidGroupId (line 83) | @Test
method shouldProperlyDeleteByGroupId (line 106) | @Test
method shouldDoesNotExistByGroupId (line 140) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/HelpCommandTest.java
class HelpCommandTest (line 8) | @DisplayName("Unit-level testing for HelpCommand")
method getCommandName (line 11) | @Override
method getCommandMessage (line 16) | @Override
method getCommand (line 21) | @Override
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/ListGroupSubCommandTest.java
class ListGroupSubCommandTest (line 21) | @DisplayName("Unit-level testing for ListGroupSubCommand")
method shouldProperlyShowsListGroupSub (line 24) | @Test
method populateGroupSub (line 60) | private GroupSub populateGroupSub(Integer id, String title) {
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/NoCommandTest.java
class NoCommandTest (line 8) | @DisplayName("Unit-level testing for NoCommand")
method getCommandName (line 11) | @Override
method getCommandMessage (line 16) | @Override
method getCommand (line 21) | @Override
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/StartCommandTest.java
class StartCommandTest (line 8) | @DisplayName("Unit-level testing for StartCommand")
method getCommandName (line 11) | @Override
method getCommandMessage (line 16) | @Override
method getCommand (line 21) | @Override
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/StatCommandTest.java
class StatCommandTest (line 18) | @DisplayName("Unit-level testing for StatCommand")
method init (line 25) | @BeforeEach
method shouldProperlySendMessage (line 32) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/StopCommandTest.java
class StopCommandTest (line 8) | @DisplayName("Unit-level testing for StopCommand")
method getCommandName (line 11) | @Override
method getCommandMessage (line 16) | @Override
method getCommand (line 21) | @Override
FILE: src/test/java/com/github/javarushcommunity/jrtb/command/UnknownCommandTest.java
class UnknownCommandTest (line 7) | @DisplayName("Unit-level testing for UnknownCommand")
method getCommandName (line 10) | @Override
method getCommandMessage (line 15) | @Override
method getCommand (line 20) | @Override
FILE: src/test/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClientTest.java
class JavaRushGroupClientTest (line 15) | @DisplayName("Integration-level testing for JavaRushGroupClientImplTest")
method shouldProperlyGetGroupsWithEmptyArgs (line 22) | @Test
method shouldProperlyGetWithOffSetAndLimit (line 35) | @Test
method shouldProperlyGetGroupsDiscWithEmptyArgs (line 51) | @Test
method shouldProperlyGetGroupDiscWithOffSetAndLimit (line 64) | @Test
method shouldProperlyGetGroupCount (line 80) | @Test
method shouldProperlyGetGroupTECHCount (line 92) | @Test
method shouldProperlyGetGroupById (line 106) | @Test
method shouldNotProperlyGetGroupById (line 121) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClientTest.java
class JavaRushPostClientTest (line 12) | @DisplayName("Integration-level testing for JavaRushPostClient")
method shouldProperlyGetNew15Posts (line 17) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/repository/GroupSubRepositoryIT.java
class GroupSubRepositoryIT (line 21) | @ActiveProfiles("test")
method shouldProperlyGetAllUsersForGroupSub (line 29) | @Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveUsersForGroupSub.sql"})
FILE: src/test/java/com/github/javarushcommunity/jrtb/repository/TelegramUserRepositoryIT.java
class TelegramUserRepositoryIT (line 21) | @ActiveProfiles("test")
method shouldProperlyFindAllActiveUsers (line 29) | @Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
method shouldProperlySaveTelegramUser (line 39) | @Sql(scripts = {"/sql/clearDbs.sql"})
method shouldProperlyGetAllGroupSubsForUser (line 56) | @Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveGroupSubsForUser.sql"})
FILE: src/test/java/com/github/javarushcommunity/jrtb/service/GroupSubServiceTest.java
class GroupSubServiceTest (line 15) | @DisplayName("Unit-level testing for GroupSubService")
method init (line 27) | @BeforeEach
method shouldProperlySaveGroup (line 43) | @Test
method shouldProperlyAddUserToExistingGroup (line 64) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/service/SendBotMessageServiceTest.java
class SendBotMessageServiceTest (line 11) | @DisplayName("Unit-level testing for SendBotMessageService")
method init (line 17) | @BeforeEach
method shouldProperlySendMessage (line 23) | @Test
FILE: src/test/java/com/github/javarushcommunity/jrtb/service/StatisticsServiceImplTest.java
class StatisticsServiceTest (line 15) | @DisplayName("Unit-level testing for StatisticsService")
method init (line 23) | @BeforeEach
method shouldProperlySendStatDTO (line 30) | @Test
Condensed preview — 106 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (166K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 846,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: romankh3\n\n---\n\n**De"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 615,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[FEATURE]\"\nlabels: feature\nassignees: romankh3"
},
{
"path": ".github/ISSUE_TEMPLATE/improvement-request.md",
"chars": 189,
"preview": "---\nname: Improvement request\nabout: Suggest an improvment for this project\ntitle: \"[IMPROVEMENT]\"\nlabels: enhancement\na"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 136,
"preview": "---\nname: Question\nabout: ask any questions, which are interested you\ntitle: \"[QUESTION]\"\nlabels: 'question'\nassignees: "
},
{
"path": ".github/pull_request_template.md",
"chars": 1175,
"preview": "# PR Details\n\n<!--- Provide a general summary of your changes in the Title above -->\n\n## Description\n\n<!--- Describe you"
},
{
"path": ".github/workflows/maven.yml",
"chars": 805,
"preview": "# This workflow will build a Java project with Maven\n# For more information see: https://help.github.com/actions/languag"
},
{
"path": ".gitignore",
"chars": 26,
"preview": ".idea/\ntarget\nbuild\n*.iml\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3358,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "Dockerfile",
"chars": 452,
"preview": "FROM adoptopenjdk/openjdk11:ubi\nARG JAR_FILE=target/*.jar\nENV BOT_NAME=test.javarush_community_bot\nENV BOT_TOKEN=1375780"
},
{
"path": "Find_New_Posts_WF.bpmn",
"chars": 7889,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bpmn:definitions xmlns:bpmn=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 2857,
"preview": "# Javarush Telegram Bot\n;\n\n-- ensure that the tables with these name"
},
{
"path": "src/main/resources/db/migration/V00003__rename_last_article_id.sql",
"chars": 69,
"preview": "ALTER TABLE group_sub CHANGE COLUMN last_article_id last_post_id INT;"
},
{
"path": "src/main/resources/db/migration/V00004_change_chat_Id_type_to_Long.sql",
"chars": 39,
"preview": "ALTER TABLE tg_user MODIFY chat_id INT;"
},
{
"path": "src/main/resources/log4j2.xml",
"chars": 445,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"INFO\">\n <Appenders>\n <Console name=\"console\" tar"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/AbstractCommandTest.java",
"chars": 2053,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;\nim"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/AdminHelpCommandTest.java",
"chars": 682,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static com.github."
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/CommandContainerTest.java",
"chars": 2250,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport com.github.javarushcommunity.jrtb.javarushclient.JavaRushGrou"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/DeleteGroupSubCommandTest.java",
"chars": 5766,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport com.github.javarushcommunity.jrtb.repository.entity.GroupSub;"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/HelpCommandTest.java",
"chars": 639,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static com.github."
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/ListGroupSubCommandTest.java",
"chars": 2676,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport com.github.javarushcommunity.jrtb.repository.entity.GroupSub;"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/NoCommandTest.java",
"chars": 623,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static com.github."
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/StartCommandTest.java",
"chars": 660,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static com.github."
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/StatCommandTest.java",
"chars": 2076,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport com.github.javarushcommunity.jrtb.dto.GroupStatDTO;\nimport co"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/StopCommandTest.java",
"chars": 660,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static com.github."
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/command/UnknownCommandTest.java",
"chars": 577,
"preview": "package com.github.javarushcommunity.jrtb.command;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static com.github."
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushGroupClientTest.java",
"chars": 3979,
"preview": "package com.github.javarushcommunity.jrtb.javarushclient;\n\nimport com.github.javarushcommunity.jrtb.javarushclient.dto.G"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/javarushclient/JavaRushPostClientTest.java",
"chars": 793,
"preview": "package com.github.javarushcommunity.jrtb.javarushclient;\n\nimport com.github.javarushcommunity.jrtb.javarushclient.dto.P"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/repository/GroupSubRepositoryIT.java",
"chars": 1654,
"preview": "package com.github.javarushcommunity.jrtb.repository;\n\nimport com.github.javarushcommunity.jrtb.repository.entity.GroupS"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/repository/TelegramUserRepositoryIT.java",
"chars": 2573,
"preview": "package com.github.javarushcommunity.jrtb.repository;\n\nimport com.github.javarushcommunity.jrtb.repository.entity.GroupS"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/service/GroupSubServiceTest.java",
"chars": 3638,
"preview": "package com.github.javarushcommunity.jrtb.service;\n\nimport com.github.javarushcommunity.jrtb.javarushclient.JavaRushGrou"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/service/SendBotMessageServiceTest.java",
"chars": 1304,
"preview": "package com.github.javarushcommunity.jrtb.service;\n\nimport com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;\nim"
},
{
"path": "src/test/java/com/github/javarushcommunity/jrtb/service/StatisticsServiceImplTest.java",
"chars": 2292,
"preview": "package com.github.javarushcommunity.jrtb.service;\n\nimport com.github.javarushcommunity.jrtb.dto.GroupStatDTO;\nimport co"
},
{
"path": "src/test/resources/sql/clearDbs.sql",
"chars": 70,
"preview": "DELETE FROM group_x_user;\nDELETE FROM group_sub;\nDELETE FROM tg_user;\n"
},
{
"path": "src/test/resources/sql/fiveGroupSubsForUser.sql",
"chars": 207,
"preview": "INSERT INTO tg_user VALUES (1, 1);\n\nINSERT INTO group_sub VALUES\n(1, 'g1', 1),\n(2, 'g2', 2),\n(3, 'g3', 3),\n(4, 'g4', 4),"
},
{
"path": "src/test/resources/sql/fiveUsersForGroupSub.sql",
"chars": 183,
"preview": "INSERT INTO tg_user VALUES\n(1, 1),\n(2, 1),\n(3, 1),\n(4, 1),\n(5, 1);\n\nINSERT INTO group_sub VALUES (1, 'g1', 1);\n\nINSERT I"
},
{
"path": "src/test/resources/sql/telegram_users.sql",
"chars": 359,
"preview": "INSERT INTO tg_user VALUES (\"123456789\", 1);\nINSERT INTO tg_user VALUES (\"123456788\", 1);\nINSERT INTO tg_user VALUES (\"1"
},
{
"path": "start.sh",
"chars": 351,
"preview": "#!/bin/bash\n\n# Pull new changes\ngit pull\n\n# Prepare Jar\nmvn clean\nmvn package\n\n# Ensure, that docker-compose stopped\ndoc"
},
{
"path": "stop.sh",
"chars": 141,
"preview": "#!/bin/bash\n\n# Ensure, that docker-compose stopped\ndocker-compose stop\n\n# Ensure, that the old application won't be depl"
}
]
About this extraction
This page contains the full source code of the javarushcommunity/javarush-telegrambot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 106 files (144.5 KB), approximately 39.0k tokens, and a symbol index with 223 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.