Skip to content

Commit 58867f3

Browse files
committed
Added basic functionality: Global and Contests statistics monitoring and /track command to start tracking user on CodeForces
1 parent a4dea09 commit 58867f3

28 files changed

+1316
-21
lines changed

.github/workflows/main-branch.yml

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
name: Main Branch Workflow
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
build-jar:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
16+
- name: Set up JDK 21
17+
uses: actions/setup-java@v4
18+
with:
19+
java-version: '21'
20+
distribution: 'corretto'
21+
22+
- name: Setup Gradle
23+
uses: gradle/actions/setup-gradle@v4
24+
25+
- name: Change wrapper permissions
26+
run: chmod +x ./gradlew
27+
28+
- name: Build with Gradle Wrapper
29+
run: ./gradlew build
30+
31+
- name: Extract project name from Gradle
32+
id: extract_name
33+
run: |
34+
PROJECT_NAME=$(./gradlew -q printProjectName)
35+
echo "PROJECT_NAME=${PROJECT_NAME}" >> $GITHUB_ENV
36+
37+
- name: Extract version from Gradle
38+
id: get-version
39+
run: |
40+
VERSION=$(./gradlew -q printProjectVersion)
41+
echo "VERSION=${VERSION}" >> $GITHUB_ENV
42+
43+
- name: Upload jars
44+
uses: actions/upload-artifact@v4
45+
with:
46+
name: ${{ env.PROJECT_NAME }}-${{ env.VERSION }}
47+
path: build/libs/
48+
49+
build-and-push-docker:
50+
runs-on: ubuntu-latest
51+
permissions:
52+
packages: write
53+
id-token: write
54+
attestations: write
55+
env:
56+
REGISTRY: ghcr.io
57+
IMAGE_NAME: ${{ github.repository }}
58+
59+
steps:
60+
- name: Checkout repository
61+
uses: actions/checkout@v4
62+
63+
- name: Log in to GitHub Container Registry
64+
uses: docker/login-action@v2
65+
with:
66+
registry: ${{ env.REGISTRY }}
67+
username: ${{ github.actor }}
68+
password: ${{ secrets.GITHUB_TOKEN }}
69+
70+
- name: Extract version from file
71+
id: get-version
72+
run: |
73+
VERSION=$(./gradlew -q printProjectVersion)
74+
echo "VERSION=${VERSION}" >> $GITHUB_ENV
75+
76+
- name: Extract metadata (tags, labels) for Docker
77+
id: meta
78+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
79+
with:
80+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
81+
82+
- name: Change wrapper permissions
83+
run: chmod +x ./gradlew
84+
85+
- name: Build and push Docker image
86+
id: push
87+
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
88+
with:
89+
context: .
90+
push: true
91+
tags: ${{ steps.meta.outputs.tags }}
92+
labels: ${{ steps.meta.outputs.labels }}
93+
94+
- name: Generate artifact attestation
95+
uses: actions/attest-build-provenance@v1
96+
with:
97+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
98+
subject-digest: ${{ steps.push.outputs.digest }}
99+
push-to-registry: true
100+
101+
package-and-push-helm:
102+
runs-on: ubuntu-latest
103+
permissions:
104+
contents: write
105+
106+
steps:
107+
- name: Checkout repository
108+
uses: actions/checkout@v4
109+
110+
- name: Configure Git
111+
run: |
112+
git config user.name "$GITHUB_ACTOR"
113+
git config user.email "[email protected]"
114+
115+
- name: Install Helm
116+
uses: azure/setup-helm@v4
117+
env:
118+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
119+
120+
- name: Run chart-releaser
121+
uses: helm/[email protected]
122+
with:
123+
charts_dir: helm
124+
packages_with_index: true
125+
env:
126+
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
127+
128+
dependency-submission:
129+
runs-on: ubuntu-latest
130+
permissions:
131+
contents: write
132+
133+
steps:
134+
- name: Checkout repository
135+
uses: actions/checkout@v4
136+
137+
- name: Set up JDK 21
138+
uses: actions/setup-java@v4
139+
with:
140+
java-version: '21'
141+
distribution: 'corretto'
142+
143+
- name: Generate and submit dependency graph
144+
uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0

.gitignore

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,45 @@
1-
# Compiled class file
2-
*.class
1+
.gradle
2+
build/
3+
!gradle/wrapper/gradle-wrapper.jar
4+
!**/src/main/**/build/
5+
!**/src/test/**/build/
36

4-
# Log file
5-
*.log
7+
### IntelliJ IDEA ###
8+
.idea/modules.xml
9+
.idea/jarRepositories.xml
10+
.idea/compiler.xml
11+
.idea/libraries/
12+
*.iws
13+
*.iml
14+
*.ipr
15+
out/
16+
!**/src/main/**/out/
17+
!**/src/test/**/out/
618

7-
# BlueJ files
8-
*.ctxt
19+
### Kotlin ###
20+
.kotlin
921

10-
# Mobile Tools for Java (J2ME)
11-
.mtj.tmp/
22+
### Eclipse ###
23+
.apt_generated
24+
.classpath
25+
.factorypath
26+
.project
27+
.settings
28+
.springBeans
29+
.sts4-cache
30+
bin/
31+
!**/src/main/**/bin/
32+
!**/src/test/**/bin/
1233

13-
# Package Files #
14-
*.jar
15-
*.war
16-
*.nar
17-
*.ear
18-
*.zip
19-
*.tar.gz
20-
*.rar
34+
### NetBeans ###
35+
/nbproject/private/
36+
/nbbuild/
37+
/dist/
38+
/nbdist/
39+
/.nb-gradle/
2140

22-
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23-
hs_err_pid*
24-
replay_pid*
41+
### VS Code ###
42+
.vscode/
43+
44+
### Mac OS ###
45+
.DS_Store

.idea/.gitignore

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/kotlinc.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM gradle:jdk21 AS build
2+
3+
WORKDIR /app
4+
5+
COPY . .
6+
7+
RUN gradle build --no-daemon
8+
9+
FROM amazoncorretto:21
10+
11+
WORKDIR /app
12+
13+
COPY --from=build /app/build/libs/*-fat-*.jar app.jar
14+
15+
CMD ["java", "-jar", "app.jar"]

README.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,58 @@
1-
# collaborative-algo-training-discord-bot
2-
A Discord bot for automatizing collaborative algo training
1+
<p align="center">
2+
<img width="100px" src="https://github.com/likespro.png" align="center" alt="Competitive Template" />
3+
<h2 align="center">Competitive Programming Statistics Bot</h2>
4+
<p align="center">A Discord bot to track users on competitive programming platforms</p>
5+
</p>
6+
<p align="center">
7+
<a href="https://github.com/anuraghazra/github-readme-stats/actions">
8+
<img alt="Build Passing" src="https://github.com/likespro/cp-programming-stats-bot/workflows/Main Branch Workflow/badge.svg" />
9+
</a>
10+
<a href="https://github.com/likespro/cp-programming-stats-bot/graphs/contributors">
11+
<img alt="GitHub Contributors" src="https://img.shields.io/github/contributors/likespro/cp-programming-stats-bot" />
12+
</a>
13+
<a href="https://github.com/likespro/cp-programming-stats-bot/issues">
14+
<img alt="Issues" src="https://img.shields.io/github/issues/likespro/cp-programming-stats-bot?color=0088ff" />
15+
</a>
16+
<a href="https://github.com/likespro/cp-programming-stats-bot/pulls">
17+
<img alt="GitHub pull requests" src="https://img.shields.io/github/issues-pr/likespro/cp-programming-stats-bot?color=0088ff" />
18+
</a>
19+
</p>
20+
21+
22+
23+
24+
25+
## Overview
26+
The goal of this Discord bot is to bring users' statistics from different competitive programming platforms right to Discord.
27+
## How it works
28+
* Bot uses 2 text channels in your Guild to publish statistics: one (by default named `statistics`) to publish global leaderboard of tracked users, ranked by their rating, and another one (by default named `contests-statistics`) to publish current tracked users standings for each contest that is going on or ended no earlier than one week before.
29+
* Bot automatically updates statistics nearly each 60 seconds and edits messages with outdated statistics
30+
* To track new user just execute `/track <platform> <username> <track_this_user_just_for_fun_or_not?>` in Discord Guild where the bot was installed
31+
32+
**Currently supported platforms:**
33+
* CodeForces
34+
## Requirements
35+
* Running MongoDB server - you can download it on www.mongodb.com or use free cluster from MongoDB Atlas - https://cloud.mongodb.com
36+
* Discord bot token - you can create it on https://discord.com/developers/applications. The bot need to be installed to your Guild and need to have scopes `applications.commands`, `bot` and permissions `Manage Channels`, `Send Messages`. You can set they in your dashboard before bot installation to Guild.
37+
## How to install (traditional)
38+
* Build jars with `./gradlew build` or download already built fat jar artifact from the last successful action on https://github.com/likespro/cp-programming-stats-bot/actions
39+
* Ensure you have set all needed environment variables (see the list below)
40+
* Run fat jar with Java 21+: `java -jar cp-programming-stats-bot-fat-<version>.jar`. If you built jars manually, they will be located in `build/libs/`
41+
## How to install (docker)
42+
* Pull image: `docker image pull ghcr.io/likespro/cp-programming-stats-bot:main`
43+
* Run the image with `docker run ghcr.io/likespro/cp-programming-stats-bot:main`. You can set environment variables by `-e <VARIABLE>=<VALUE>`, for example: `docker run -e MONGODB_URL="mongodb+srv://example.com" -e MONGODB_DATABASE="stats-database" ghcr.io/likespro/cp-programming-stats-bot:main`
44+
## How to install (helm)
45+
* Add repository with `helm repo add cp-programming-stats-bot https://likespro.github.io/cp-programming-stats-bot` or update it (if you already added it earlier) with `helm repo update cp-programming-stats-bot`
46+
* Deploy Helm Chart: `helm install cp-programming-stats-bot/cp-programming-stats-bot`. You can set environment variables by `--set env.<VARIABLE>=<VALUE>`, for example: `helm install cp-programming-stats-bot/cp-programming-stats-bot --set env.MONGODB_URL="mongodb+srv://example.com" --set env.MONGODB_DATABASE="stats-database"`
47+
## Environment variables
48+
* Set `MONGODB_URL` environment variable to valid URL of your MongoDB server, for example: `mongodb+srv://[username:password@]host[/[defaultauthdb][?options]]`
49+
* [ Optional ] Set `MONGODB_DATABASE` environment variable to valid MongoDB database name. If not specified, `cp-programming-stats-bot` will be used as name
50+
* [ Optional ] Set `DISCORD_BOT_TOKEN` environment variable to valid Discord bot token. If not specified, you will need to set `<database>/misc/config/discordBotToken` field manually after the first launch
51+
* [ Optional ] Set `DISCORD_GUILD_ID` environment variable to valid Discord Guild ID. You can get ID of any guild by enabling Developer mode in `Discord/Settings/Advanced` and then right-click on the Guild you want to use and copy its ID. If not specified, you will need to set `<database>/misc/config/discordGuildId` field manually after the first launch
52+
* [ Optional ] Set `DISCORD_GLOBAL_STATISTICS_CHANNEL_ID` environment variable to valid ID of Discord text channel where to publish global statistics. You can get ID of any text channel by enabling Developer mode in `Discord/Settings/Advanced` and then right-click on the text channel you want to use and copy its ID. If not specified, bot will try to automatically find a text channel with name "statistics". If no such channels were found, bot will create a new text channel with this name
53+
* [ Optional ] Set `DISCORD_CONTESTS_STATISTICS_CHANNEL_ID` environment variable to valid ID of Discord text channel where to publish contests statistics. You can get ID of any text channel by enabling Developer mode in `Discord/Settings/Advanced` and then right-click on the text channel you want to use and copy its ID. If not specified, bot will try to automatically find a text channel with name "contests-statistics". If no such channels were found, bot will create a new text channel with this name
54+
## Screenshots
55+
Global Statistics
56+
![Global Statistics](https://github.com/likespro/cp-programming-stats-bot/blob/main/screenshots/global_statistics.png?raw=true)
57+
Contest Statistics
58+
![Contest Statistics](https://github.com/likespro/cp-programming-stats-bot/blob/main/screenshots/contest_statistics.png?raw=true)

build.gradle

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
plugins {
2+
id 'org.jetbrains.kotlin.jvm' version '2.0.20'
3+
}
4+
5+
group = 'eth.likespro'
6+
version = '1.0.0'
7+
8+
repositories {
9+
mavenCentral()
10+
}
11+
dependencies {
12+
implementation 'de.vandermeer:asciitable:0.3.2'
13+
implementation 'org.json:json:20231013'
14+
implementation 'io.projectreactor:reactor-core:3.6.10'
15+
implementation 'org.mongodb:mongodb-driver-reactivestreams:5.1.4'
16+
implementation 'io.github.microutils:kotlin-logging-jvm:2.0.11'
17+
implementation 'ch.qos.logback:logback-classic:1.4.12'
18+
implementation "net.dv8tion:JDA:5.2.1"
19+
testImplementation 'org.jetbrains.kotlin:kotlin-test'
20+
}
21+
22+
test {
23+
useJUnitPlatform()
24+
}
25+
kotlin {
26+
jvmToolchain(21)
27+
}
28+
tasks.jar{
29+
manifest {
30+
attributes 'Main-Class': 'eth.likespro.MainKt'
31+
}
32+
}
33+
tasks.register('fatJar', Jar) {
34+
manifest {
35+
attributes 'Main-Class': 'eth.likespro.MainKt'
36+
}
37+
archiveBaseName = rootProject.name + '-fat'
38+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
39+
from { configurations.runtimeClasspath.collect { println("Packing "+it.name+" into fatJar"); it.isDirectory() ? it : zipTree(it) } } {
40+
exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
41+
}
42+
exclude("META-INF/*.RSA", "META-INF/*.DSA", "META-INF/*.SF")
43+
with jar
44+
exclude("META-INF/*.RSA", "META-INF/*.DSA", "META-INF/*.SF")
45+
}
46+
tasks.build{
47+
dependsOn(fatJar)
48+
}
49+
tasks.register('printProjectName') {
50+
doLast {
51+
println rootProject.name
52+
}
53+
}
54+
tasks.register('printProjectVersion') {
55+
doLast {
56+
println version
57+
}
58+
}

0 commit comments

Comments
 (0)