From e1e1fa7336e7a4fc0294814c1a0cd3ac0f450dcb Mon Sep 17 00:00:00 2001 From: Andrea Date: Mon, 3 Jan 2022 19:22:10 +0100 Subject: [PATCH] [calendar][bot] threads --- nuxt.config.js | 3 +- server/calendarBot.js | 109 +++++++++++++++++++++-------------------- server/index.js | 3 +- server/routes/admin.js | 3 +- server/routes/home.js | 3 +- server/routes/user.js | 3 +- server/stats.js | 19 +------ src/buildLocaleList.js | 11 +++++ src/helpers.js | 13 +---- 9 files changed, 79 insertions(+), 88 deletions(-) create mode 100644 src/buildLocaleList.js diff --git a/nuxt.config.js b/nuxt.config.js index 1e8b2fe4..ebe84c90 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -2,7 +2,8 @@ require('./src/dotenv')(); import { loadSuml } from './server/loader'; import fs from 'fs'; -import {buildDict, buildList, buildLocaleList} from "./src/helpers"; +import {buildDict, buildList} from "./src/helpers"; +import buildLocaleList from "./src/buildLocaleList"; const config = loadSuml('config'); const translations = loadSuml('translations'); diff --git a/server/calendarBot.js b/server/calendarBot.js index 994bd2f2..066e9bb4 100644 --- a/server/calendarBot.js +++ b/server/calendarBot.js @@ -1,34 +1,14 @@ require('../src/dotenv')(); const Twitter = require('twitter'); const Mastodon = require('mastodon'); -const Suml = require('suml'); -const fs = require('fs'); -const { calendar } = require('../src/calendar/calendar'); -const { Day } = require('../src/calendar/helpers'); -const locales = require('../src/locales'); const fetch = require('node-fetch'); +const fs = require('fs'); +const buildLocaleList = require('../src/buildLocaleList'); -const loadSuml = name => new Suml().parse(fs.readFileSync(`${__dirname}/../data/${name}.suml`).toString()); -const translations = loadSuml('translations'); -const config = loadSuml('config'); - -let domain = null; -let language = null; -for (let [code, name, url, ] of locales) { - if (code === config.locale) { - domain = url; - language = name; - } -} - -const getEventName = (name) => { - name = translations.calendar.events[name] || name; - name = name.replace(/{.*?=(.*?)}/g, '$1') - return name; -} +const locales = buildLocaleList('_'); const publishers = { - async twitter(tweet, image) { + async twitter(tweet, image, previousId) { const client = new Twitter({ consumer_key: process.env.TWITTER_CALENDAR_CONSUMER_KEY, consumer_secret: process.env.TWITTER_CALENDAR_CONSUMER_SECRET, @@ -37,13 +17,18 @@ const publishers = { }); try { - const tweetResponse = await client.post('statuses/update', {status: tweet}); + const tweetResponse = await client.post('statuses/update', { + status: tweet, + ...(previousId ? {in_reply_to_status_id: previousId} : {}), + }); console.log(tweetResponse); + + return tweetResponse.id_str; } catch (error) { console.error(error); } }, - async mastodon(tweet, image) { + async mastodon(tweet, image, previousId) { const client = new Mastodon({ access_token: process.env.MASTODON_ACCESS_TOKEN, api_url: `https://${process.env.MASTODON_INSTANCE}/api/v1/` @@ -52,7 +37,10 @@ const publishers = { const mediaIds = []; if (image) { try { - const mediaResponse = await client.post('media', { file: image, description: 'Screenshot of the link above' }); + const mediaResponse = await client.post('media', { + file: image, + description: 'Screenshot of the link above' + }); console.log(mediaResponse); mediaIds.push(mediaResponse.data.id); } catch (error) { @@ -61,41 +49,56 @@ const publishers = { } try { - const tweetResponse = await client.post('statuses', { status: tweet, media_ids: mediaIds, visibility: 'unlisted' }); - console.log(tweetResponse); + const tweetResponse = await client.post('statuses', { + status: tweet, + media_ids: mediaIds, + visibility: 'unlisted', + ...(previousId ? {in_reply_to_id: previousId} : {}), + }); + console.log(tweetResponse.data); + return tweetResponse.data.id; } catch (error) { console.error(error); } }, }; -(async () => { - const day = Day.today(); - const events = calendar.getCurrentYear().eventsByDate[day.toString()]; - console.log(events); +const tmpDir = `${__dirname}/../cache/tmp`; +fs.mkdirSync(tmpDir, {recursive: true}); +const imageTmpPath = `${tmpDir}/calendar-tmp.png`; - if (events === undefined || events.length === 0) { +const lastPostId = {}; + +const timer = ms => new Promise( res => setTimeout(res, ms)); + +(async () => { + if (process.argv.length !== 4) { + console.error('Missing parameters. Usage: node server/calendarBot.js '); return; } - - let tweet = `[${language}] ${day.toString()}\n\n${translations.calendar.banner}:\n`; - for (let event of events) { - tweet += ` - ${getEventName(event.name)}\n`; - } - tweet += `\n${domain}/${encodeURIComponent(config.calendar.route)}/${day}`; - - let image = null; - try { - image = fs.createReadStream(`${__dirname}/../static/calendar/${day}.png`); - } catch {} - - console.log('------------'); - console.log(tweet); - console.log('------------'); - - for (let publisher of process.argv.slice(2)) { - console.log('Publishing: ' + publisher); - publishers[publisher](tweet, image); + for (let locale of process.argv[2].split(',')) { console.log('------------'); + console.log(locales[locale].name); + + const { day, message, image } = await (await fetch(locales[locale].url + '/api/calendar/today')).json(); + console.log('<<<', message, '>>>'); + if (!message) { continue; } + + fs.writeFileSync(imageTmpPath, Buffer.from(await (await fetch(image)).arrayBuffer()), {encoding: 'binary'}); + let imageStream = null; + try { + imageStream = fs.createReadStream(imageTmpPath); + } catch {} + + for (let publisher of process.argv[3].split(',')) { + console.log('Publishing: ' + publisher); + const postId = await publishers[publisher]( + message, + imageStream, + lastPostId[publisher] + ); + console.log(postId); + lastPostId[publisher] = postId; + } } })(); diff --git a/server/index.js b/server/index.js index 999760b8..977dbf97 100644 --- a/server/index.js +++ b/server/index.js @@ -6,7 +6,8 @@ import cookieParser from 'cookie-parser'; import grant from "grant"; import router from "./routes/user"; import { loadSuml } from './loader'; -import {isGranted, buildLocaleList} from "../src/helpers"; +import {isGranted} from "../src/helpers"; +import buildLocaleList from "../src/buildLocaleList"; import cookieSettings from "../src/cookieSettings"; import SQL from "sql-template-strings"; diff --git a/server/routes/admin.js b/server/routes/admin.js index a98edad4..08ea023c 100644 --- a/server/routes/admin.js +++ b/server/routes/admin.js @@ -1,13 +1,14 @@ import { Router } from 'express'; import SQL from 'sql-template-strings'; import avatar from '../avatar'; -import {buildDict, now, shuffle, handleErrorAsync, buildLocaleList} from "../../src/helpers"; +import {buildDict, now, shuffle, handleErrorAsync} from "../../src/helpers"; import locales from '../../src/locales'; import {calculateStats, statsFile} from '../../src/stats'; import fs from 'fs'; import { caches } from "../../src/cache"; import mailer from "../../src/mailer"; import {profilesSnapshot} from "./profile"; +import buildLocaleList from "../../src/buildLocaleList"; const router = Router(); diff --git a/server/routes/home.js b/server/routes/home.js index 925093c2..fc95ffc3 100644 --- a/server/routes/home.js +++ b/server/routes/home.js @@ -1,5 +1,6 @@ import { Router } from 'express'; -import {buildLocaleList, handleErrorAsync} from "../../src/helpers"; +import {handleErrorAsync} from "../../src/helpers"; +import buildLocaleList from "../../src/buildLocaleList"; const router = Router(); diff --git a/server/routes/user.js b/server/routes/user.js index 20877fd4..59174acd 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -1,7 +1,7 @@ import { Router } from 'express'; import SQL from 'sql-template-strings'; import {ulid} from "ulid"; -import {buildDict, makeId, now, handleErrorAsync, buildLocaleList} from "../../src/helpers"; +import {buildDict, makeId, now, handleErrorAsync} from "../../src/helpers"; import jwt from "../../src/jwt"; import mailer from "../../src/mailer"; import { loadSuml } from '../loader'; @@ -11,6 +11,7 @@ import cookieSettings from "../../src/cookieSettings"; import {validateCaptcha} from "../captcha"; import assert from "assert"; import {addMfaInfo} from './mfa'; +import buildLocaleList from "../../src/buildLocaleList"; const config = loadSuml('config'); const translations = loadSuml('translations'); diff --git a/server/stats.js b/server/stats.js index 1e98fb6b..a6ed92e2 100644 --- a/server/stats.js +++ b/server/stats.js @@ -4,24 +4,7 @@ const dbConnection = require('./db'); const {calculateStats, statsFile} = require('../src/stats'); const locales = require('../src/locales'); const fs = require('fs'); - -// TODO duplication -const buildDict = (fn, ...args) => { - const dict = {}; - for (let [key, value] of fn(...args)) { - dict[key] = value; - } - return dict; -} -const buildLocaleList = () => { - return buildDict(function* () { - for (let [code, name, url, published] of locales) { - if (published) { - yield [code, {name, url, published}]; - } - } - }) -} +const buildLocaleList = require('../src/buildLocaleList'); async function calculate() { const db = await dbConnection(); diff --git a/src/buildLocaleList.js b/src/buildLocaleList.js new file mode 100644 index 00000000..15850061 --- /dev/null +++ b/src/buildLocaleList.js @@ -0,0 +1,11 @@ +const locales = require('./locales') + +module.exports = (current, includeUnpublished = false) => { + const d = {}; + for (let [code, name, url, published] of locales) { + if (published || current === code || includeUnpublished) { + d[code] = {name, url, published, code}; + } + } + return d; +} diff --git a/src/helpers.js b/src/helpers.js index 9d20dacc..7aaeccf1 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1,7 +1,6 @@ import md5 from 'js-md5'; -import { Base64 } from 'js-base64'; +import {Base64} from 'js-base64'; import _ from 'lodash'; -import locales from './locales'; export const buildDict = (fn, ...args) => { const dict = {}; @@ -150,16 +149,6 @@ export const isTroll = (body) => { return ['cipeusz', 'feminazi', 'bruksela', 'zboczeń'].some(t => body.indexOf(t) > -1); } -export const buildLocaleList = (current, includeUnpublished = false) => { - return buildDict(function* () { - for (let [code, name, url, published] of locales) { - if (published || current === code || includeUnpublished) { - yield [code, {name, url, published, code}]; - } - } - }) -} - export const zip = (list, reverse) => { return buildDict(function* () { for (let [k, v] of list) {