123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- import TelegramBot, { SendMessageOptions } from "node-telegram-bot-api";
- import * as dotenv from "dotenv";
- import axios from "axios";
- import moment from "moment";
- import { Client } from "discord.js";
- // import { Client, Intents, Options } from "discord.js";
- interface ScoringPeriodData {
- currentScoringPeriod: {
- scoringPeriodId: number;
- started: string;
- ends: string;
- referralCode: number;
- };
- lastPeriod: {
- scoringPeriodId: number;
- started: string;
- ends: string;
- referralCode: number;
- totalDirectScore: number;
- totalReferralScore: number;
- highlights: string[];
- };
- }
- dotenv.config();
- const tgApiKey = process.env.TG_API_KEY_EN || "";
- const bot = new TelegramBot(tgApiKey, { polling: true });
- const discordToken = process.env.DISCORD_TOKEN || "";
- const client = new Client();
- let nextSyncDate = moment();
- let scoringData = {} as ScoringPeriodData;
- let lastGradedPeriod = null as number | null;
- const messageDeletionTimeout = 60000;
- client.login(discordToken);
- client.on("ready", async () => {
- if (!client.user) return;
- console.log(`Logged in to discord as ${client.user.tag}!`);
- });
- moment.locale("en");
- const loadScoringPeriodData = async () => {
- const url =
- "https://raw.githubusercontent.com/Joystream/founding-members/main/data/fm-info.json";
- const { data } = await axios.get(url);
- return data.scoringPeriodsFull;
- };
- client.on("message", async (message) => {
- await reloadScoringData();
- if (message.content === "!help") {
- const helpMessage = `Hello ${message.author.username}, I can help you with the status of Joystream Scoring Periods.\nIn channels I delete my messages after 30 seconds, but in DM they will be kept.\nSupported commands:\n!scoring - Get the scoring period information\n!help - Get this help`;
- message.channel.send({content: helpMessage}).then( (msg: { delete: () => void; }) => {
- if (message.channel.type !== "dm") {
- message.delete()
- setTimeout(() => {
- msg.delete()
- }, messageDeletionTimeout)
- }
- });
- }
- if (message.content === "!scoring") {
- const leaderboardLink = `\nCheck scores here: https://t.me/JoystreamLeaderboardBot\nSubmit your report here: https://www.joystream.org/founding-members/form`;
- const submitReportLink = "submit your report";
- const messageContent = generateScoringPeriodMessage(
- message.author.username,
- submitReportLink,
- leaderboardLink
- );
- message.channel.send({content: messageContent}).then( (msg: { suppressEmbeds: (arg0: boolean) => void; delete: () => void; }) => {
- msg.suppressEmbeds(true)
- if (message.channel.type !== "dm") {
- message.delete()
- setTimeout(() => {
- msg.delete()
- }, messageDeletionTimeout)
- }
- });
- }
- });
- bot.on("message", async (msg: TelegramBot.Message) => {
- await reloadScoringData();
- if (msg && msg.from) {
- console.log(msg.chat);
- const chatId = msg.chat.id;
- const username = `${msg.from.first_name} ${
- msg.from.last_name || ""
- }`.trim();
- const userParsed = `[${username}](tg://user?id=${msg.from.id})`;
- const leaderboardLink = ` - [Check scores](https://t.me/JoystreamLeaderboardBot)`;
- const options: SendMessageOptions = {
- parse_mode: "Markdown",
- disable_web_page_preview: true,
- };
- if (msg.text?.startsWith("/scoring")) {
- const submitReportLink = "[submit your report](https://www.joystream.org/founding-members/form)";
- const messageContent = generateScoringPeriodMessage(
- userParsed,
- submitReportLink,
- leaderboardLink
- );
- bot.sendMessage(chatId, messageContent, options).then((message) => {
- try {
- bot.deleteMessage(chatId, msg.message_id.toString());
- } catch (e) {}
- setTimeout(() => {
- try {
- bot.deleteMessage(chatId, message.message_id.toString());
- } catch (e) {}
- }, messageDeletionTimeout);
- });
- }
- }
- });
- const generateScoringPeriodMessage = (
- userParsed: string,
- submitReportLink: string,
- leaderboardLink: string
- ) => {
- const startDate = moment.parseZone(scoringData.currentScoringPeriod.started);
- const endDate = moment.parseZone(scoringData.currentScoringPeriod.ends);
- const duration = moment.duration(endDate.diff(moment()));
- const daysDuration = duration.asDays().toFixed();
- let dayText = "days";
- if (daysDuration === "1") {
- dayText = "day";
- }
- const daysLeft = `***${duration
- .asDays()
- .toFixed()} ${dayText} on ${endDate.format(
- "dddd DD MMM"
- )} at ${endDate.format("HH:mm")}***`;
- const deadline = endDate.add(5, "d").format("dddd DD MMM HH:mm");
- const prevDeadline = startDate.add(5, "d").format("dddd DD MMM HH:mm");
- const hello = `Hello ${userParsed}!\n`;
- const currentPeriodId = scoringData.currentScoringPeriod.scoringPeriodId;
- const prevPeriodId = scoringData.currentScoringPeriod.scoringPeriodId - 1;
- const currentScoring = `The current scoring period ***#${currentPeriodId}*** ends in ${daysLeft}\n`;
- const currentDeadline = `Please make sure to ${submitReportLink} for period ***#${currentPeriodId}*** before the deadline ***${deadline}***\n`;
- const isLastScoringClosed = endDate
- .add(5, "d")
- .subtract(2, "w")
- .isAfter(moment());
- const previousPeriodDeadline = isLastScoringClosed
- ? `Reports for the previous period ***#${prevPeriodId}*** are closed\n`
- : `Reports for the previous period ***#${prevPeriodId}*** can be submitted before ***${prevDeadline}***\n`;
- const latestGradedPeriod = `Latest graded period - ***#${lastGradedPeriod}***${leaderboardLink}`;
- const messageContent = `${hello}${currentScoring}${currentDeadline}${previousPeriodDeadline}${latestGradedPeriod}`;
- return messageContent;
- };
- async function reloadScoringData() {
- if (nextSyncDate.isBefore(moment())) {
- scoringData = await loadScoringPeriodData();
- lastGradedPeriod = scoringData.lastPeriod.scoringPeriodId;
- nextSyncDate = moment.parseZone(scoringData.currentScoringPeriod.ends);
- }
- }
|