From a85b9fd7ee29efc76a8b47c0631a72b9a35dbc13 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Sun, 12 Jan 2025 14:18:59 +0100 Subject: [PATCH] style --- package-lock.json | 19 ++ package.json | 1 + public/stylesheets/style.css | 164 +++++++----- routes/index.js | 482 +++++++++++++++++------------------ views/index.jade | 4 + 5 files changed, 362 insertions(+), 308 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4a28d0a..04ee30f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "devDependencies": { "axios": "^1.6.7", "cheerio": "^1.0.0-rc.12", + "csv-parser": "^3.1.0", "fs": "^0.0.1-security", "https": "^1.0.0", "node-fetch": "^3.2.10", @@ -1627,6 +1628,18 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/csv-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-3.1.0.tgz", + "integrity": "sha512-egOwFF+imkpAE0gTrbzdf7c322lonHAmLPT2Ou1b5lhTSeXyfEdaMBdWuVeUJ6fsYuR0/ENonFo16kEXWKOQFw==", + "dev": true, + "bin": { + "csv-parser": "bin/csv-parser" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -6819,6 +6832,12 @@ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true }, + "csv-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-3.1.0.tgz", + "integrity": "sha512-egOwFF+imkpAE0gTrbzdf7c322lonHAmLPT2Ou1b5lhTSeXyfEdaMBdWuVeUJ6fsYuR0/ENonFo16kEXWKOQFw==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", diff --git a/package.json b/package.json index bc6c7a5..42f8deb 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "devDependencies": { "axios": "^1.6.7", "cheerio": "^1.0.0-rc.12", + "csv-parser": "^3.1.0", "fs": "^0.0.1-security", "https": "^1.0.0", "node-fetch": "^3.2.10", diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index b69fd77..b66da25 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -1,90 +1,122 @@ body { - padding: 50px; - font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; } a { - color: #00B7FF; - padding: 1em; - margin-right:1ch; + color: #00B7FF; + padding: 1em; + margin-right: 1ch; } -.post-message{ - margin: 1em; - border-left: 3px solid #ccc; - padding-left: 1em; + +.post-message { + margin: 1em; + border-left: 3px solid #ccc; + padding-left: 1em; } -select{ - padding:1rem; - margin: 1em 0; - border: solid 3px transparent; + +select { + padding: 1rem; + margin: 1em 0; + border: solid 3px transparent; } + label { - float:left; - display: block; - width: 100%; - margin-top: 0.5rem; + float: left; + display: block; + width: 100%; + margin-top: 0.5rem; } + /** inputs */ -input{ - margin-bottom: 0.5rem !important; - min-height: auto !important; -} -.cw-input, .file-input{ - min-height: 2em !important; -} -.wip{ - color: grey; - padding: 1rem; - margin-top:1em; -} -.wip input{ - background: grey; +textarea { + min-width: 300px; + min-height: 300px; } -.account__avatar-overlay{ - border: solid 3px transparent; -} -.account__avatar-overlay:hover{ - cursor:pointer; - border: solid 3px grey; -} -.images{ - clear:both; - display: flex; -} -.images .clickable{ - width: 20%; - margin-right: 1em; - cursor:pointer; - text-align: center; -} -.images .clickable:hover{ - background: #2F6FAB; +input:hover, textarea:hover { + border: solid 1px black; + cursor: pointer; } -.changed{ - box-shadow: 0 0 1em #2F6FAB; - border: solid 3px #2F6FAB; +input, textarea { + display: block; + margin-bottom: 0.5rem !important; + border-radius: 3px; + padding: 1rem 2rem; + background: white; } -.wip{ - margin: 2em; - border: solid 2px #2F6FAB; +input.button { } -fieldset.wip{ - margin-top: 12em; + +.cw-input, .file-input { + min-height: 2em !important; + background: #ccccff; } -.time_spans_choice{ - padding: 0.5rem; - display: block; - width: 10rem; - float:left; + +.wip { + color: grey; + padding: 1rem; + margin-top: 1em; + background: #ccccff; } -.time_spans_choice:hover{ - cursor: pointer; - color: dodgerblue; + +.wip input { + background: grey; +} + +.account__avatar-overlay { + border: solid 3px transparent; +} + +.account__avatar-overlay:hover { + cursor: pointer; + border: solid 3px grey; +} + +.images { + clear: both; + display: flex; +} + +.images .clickable { + width: 20%; + margin-right: 1em; + cursor: pointer; + text-align: center; +} + +.images .clickable:hover { + background: #2F6FAB; +} + +.changed { + box-shadow: 0 0 1em #2F6FAB; + border: solid 3px #2F6FAB; +} + +.wip { + margin: 2em; + border: solid 2px #2F6FAB; +} + +fieldset.wip { + margin-top: 12em; +} + +.time_spans_choice { + padding: 0.5rem; + display: block; + width: 10rem; + float: left; +} + +.time_spans_choice:hover { + cursor: pointer; + color: dodgerblue; } \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 048be9f..8e0e023 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,56 +1,54 @@ - - var express = require('express') var router = express.Router() var sqlite3 = require('sqlite3') var Masto = require('mastodon') const accounts_to_select = [ - { - label: 'tykayn', - value: 'tykayn', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/000/001/original/6388tykayn.gif' - }, - { - label: 'modominem', - value: 'modominem', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/152/770/original/c62bb94381dc1f75.png' - }, - { - label: 'qzine', - value: 'qzine', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/003/032/original/2bb8b90d21d3fdca.jpg' - }, - { - label: 'curator', - value: 'curator', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/002/974/original/8e48623291e49afe.jpg' - }, - { - label: 'kurator', - value: 'kurator', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/162/067/original/bb374d2c6a361b6d.jpg' - }, - { - label: 'voix du nucléaire', - value: 'voixdunucleaire', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/107/055/original/7dac1a35f1423b94.jpg' - }, - { - label: 'voices of nuclear', - value: 'voicesofnuclear', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/109/319/651/002/602/993/original/c7ca27d72856dc18.jpg' - }, - { - label: 'The greatest Meme', - value: 'meme', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/002/978/original/b2f2e817572c93e9.png' - }, - { - label: 'cil de gometz', - value: 'cil_gometz', - src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/107/055/original/7dac1a35f1423b94.jpg' - }, + { + label: 'tykayn', + value: 'tykayn', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/000/001/original/6388tykayn.gif' + }, + { + label: 'modominem', + value: 'modominem', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/152/770/original/c62bb94381dc1f75.png' + }, + { + label: 'qzine', + value: 'qzine', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/003/032/original/2bb8b90d21d3fdca.jpg' + }, + { + label: 'curator', + value: 'curator', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/002/974/original/8e48623291e49afe.jpg' + }, + { + label: 'kurator', + value: 'kurator', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/162/067/original/bb374d2c6a361b6d.jpg' + }, + { + label: 'voix du nucléaire', + value: 'voixdunucleaire', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/107/055/original/7dac1a35f1423b94.jpg' + }, + { + label: 'voices of nuclear', + value: 'voicesofnuclear', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/109/319/651/002/602/993/original/c7ca27d72856dc18.jpg' + }, + { + label: 'The greatest Meme', + value: 'meme', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/002/978/original/b2f2e817572c93e9.png' + }, + { + label: 'cil de gometz', + value: 'cil_gometz', + src: 'https://mastodon.cipherbliss.com/system/accounts/avatars/000/107/055/original/7dac1a35f1423b94.jpg' + }, ] // change this object to fit your multi accounts @@ -63,44 +61,44 @@ schedule_day = schedule_day.toISOString() router.get('/', function (req, res, next) { - if (!req.body.schedule_time) { - schedule_time = time_spans_choices[Math.floor(Math.random() * time_spans_choices.length)] - } - let contentVars = - { - accounts_to_select, - reqBody: req.body, - schedule_time, - schedule_day, - time_spans_choices - } - res.render('index', - contentVars - ) + if (!req.body.schedule_time) { + schedule_time = time_spans_choices[Math.floor(Math.random() * time_spans_choices.length)] + } + let contentVars = + { + accounts_to_select, + reqBody: req.body, + schedule_time, + schedule_day, + time_spans_choices + } + res.render('index', + contentVars + ) }) // publier un message avec un certain compte router.get('/publish', function (req, res, next) { - res.render('index', { title: 'Express' }) + res.render('index', {title: 'Express'}) }) const connect = require('@databases/sqlite') -const { sql } = require('@databases/sqlite') -const { runOnChangeOnly } = require('nodemon/lib/config/defaults') +const {sql} = require('@databases/sqlite') +const {runOnChangeOnly} = require('nodemon/lib/config/defaults') const fs = require('fs') const db = connect(database_masto) -function createDatabase () { - var newdb = new sqlite3.Database(database_masto, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { +function createDatabase() { + var newdb = new sqlite3.Database(database_masto, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { - createTables(newdb) - }) + createTables(newdb) + }) } -function createTables (newdb) { - async function prepare () { - await db.query(sql` +function createTables(newdb) { + async function prepare() { + await db.query(sql` create table posts_scheduled ( action_id integer @@ -119,163 +117,163 @@ function createTables (newdb) { values (NULL, "modominem", "un message d'example", NULL); `) - console.log('requête de création faite') - } + console.log('requête de création faite') + } - const prepared = prepare() + const prepared = prepare() } // ajouter un message à la file d'attente avec un certain compte router.post('/add-to-queue', function (req, res, next) { - // get account - // get content* - // add to sql DB + // get account + // get content* + // add to sql DB - // insert into posts_scheduled - // values (NULL, "modominem", "un message d'example", NULL); - var db = new sqlite3.Database(database_masto, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { - } - ) - db.serialize(() => { - db.run('INSERT INTO posts_scheduled VALUES(?,?,?,?,?)', [null, req.body.author, req.body.message, req.body.fichier, null], function (err) { - if (err) { - return console.log(err.message) - res.render('index', { message: 'erreur ' + err.message }) + // insert into posts_scheduled + // values (NULL, "modominem", "un message d'example", NULL); + var db = new sqlite3.Database(database_masto, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { + } + ) + db.serialize(() => { + db.run('INSERT INTO posts_scheduled VALUES(?,?,?,?,?)', [null, req.body.author, req.body.message, req.body.fichier, null], function (err) { + if (err) { + return console.log(err.message) + res.render('index', {message: 'erreur ' + err.message}) - } - console.log('nouveau post ajouté', req.body.author, req.body.message) + } + console.log('nouveau post ajouté', req.body.author, req.body.message) - res.render('index', { message: 'message ajouté OK' }) + res.render('index', {message: 'message ajouté OK'}) - }) - }) + }) + }) }) -function getAllPosts (db) { - return db.query(sql`SELECT * +function getAllPosts(db) { + return db.query(sql`SELECT * FROM posts_scheduled ORDER BY action_id DESC LIMIT 15;`) } router.get('/init-db', function (req, res, next) { - var db = new sqlite3.Database(database_masto, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { - console.log('got to create db') - createDatabase() - } - ) - res.render('created_db', {}) + var db = new sqlite3.Database(database_masto, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { + console.log('got to create db') + createDatabase() + } + ) + res.render('created_db', {}) }) router.get('/list', function (req, res, next) { - // let posts_list = [{ - // action_id: 1, - // post_username: "modominem", - // content: "demo post list", - // medias: "media file name from assets folder", - // date_schedule: "2022-07-07 " - // }] + // let posts_list = [{ + // action_id: 1, + // post_username: "modominem", + // content: "demo post list", + // medias: "media file name from assets folder", + // date_schedule: "2022-07-07 " + // }] - getAllPosts(db).then( - (results) => { - console.log('liste de posts ', results) - res.render('database', { posts_list: results }) - }, - (err) => console.error(err), - ) + getAllPosts(db).then( + (results) => { + console.log('liste de posts ', results) + res.render('database', {posts_list: results}) + }, + (err) => console.error(err), + ) }) router.get('/add-example', function (req, res, next) { - // let db = connect(database_masto); + // let db = connect(database_masto); - async function prepare () { - await db.query(sql` + async function prepare() { + await db.query(sql` insert into posts_scheduled values (NULL, "modominem", "un message d'example", "image.jpg", NULL) ; `).then(resp => { - console.log(resp) + console.log(resp) - let posts_list = [] - res.redirect('/list') - }, - err => { - console.log(err) - }) - } + let posts_list = [] + res.redirect('/list') + }, + err => { + console.log(err) + }) + } - const prepared = prepare() + const prepared = prepare() - } + } ) // publier le message en db dans la file router.get('/publish-last-entry', function (req, res, next) { - var OAuth2 = require('oauth').OAuth2 + var OAuth2 = require('oauth').OAuth2 - // console.log('env' , env) - var oauth = new OAuth2(env.APP_ID, env.SECRET, env.INSTANCE_MASTODON, null, '/oauth/token') - var url = oauth.getAuthorizeUrl({ - redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', - response_type: 'code', - scope: 'read write follow' - }) - console.log('url ', url) + // console.log('env' , env) + var oauth = new OAuth2(env.APP_ID, env.SECRET, env.INSTANCE_MASTODON, null, '/oauth/token') + var url = oauth.getAuthorizeUrl({ + redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', + response_type: 'code', + scope: 'read write follow' + }) + console.log('url ', url) - let status = '#mastoart of @tykayn' - let visibility = 'unlisted' // public, unlisted, private, direct. - let media_filename = 'colline.JPG' - let file_path = 'assets/not_published/' + media_filename - let accessToken = env.TOKEN - let sensitive = false - let scheduled_at = '2022-07-07T21:36:29.100Z' - let account_id = '2974' // curator bliss - let language = 'fr' + let status = '#mastoart of @tykayn' + let visibility = 'unlisted' // public, unlisted, private, direct. + let media_filename = 'colline.JPG' + let file_path = 'assets/not_published/' + media_filename + let accessToken = env.TOKEN + let sensitive = false + let scheduled_at = '2022-07-07T21:36:29.100Z' + let account_id = '2974' // curator bliss + let language = 'fr' - let enable_post = false + let enable_post = false - const masto = new Masto({ - access_token: accessToken, - api_url: env.parsed.INSTANCE_MASTODON + '/api/v1/', - }) + const masto = new Masto({ + access_token: accessToken, + api_url: env.parsed.INSTANCE_MASTODON + '/api/v1/', + }) - if (enable_post) { + if (enable_post) { - masto.post('media', { file: fs.createReadStream(file_path) }).then(resp => { - id = resp.data.id - // doc https://docs.joinmastodon.org/methods/statuses/ + masto.post('media', {file: fs.createReadStream(file_path)}).then(resp => { + id = resp.data.id + // doc https://docs.joinmastodon.org/methods/statuses/ - console.log('media id ', resp.data.id) - console.log(resp.data) - masto.post('statuses', { - status: status, - media_ids: [id], - account_id, - visibility, - language, - sensitive - }).then(resp => { - // succès, marquer le post comme fait en BDD - console.log(resp) + console.log('media id ', resp.data.id) + console.log(resp.data) + masto.post('statuses', { + status: status, + media_ids: [id], + account_id, + visibility, + language, + sensitive + }).then(resp => { + // succès, marquer le post comme fait en BDD + console.log(resp) - var oldPath = file_path - var newPath = 'assets/published/' + media_filename + var oldPath = file_path + var newPath = 'assets/published/' + media_filename - fs.rename(oldPath, newPath, function (err) { - if (err) throw err - console.log('Successfully renamed - AKA moved!') - }) + fs.rename(oldPath, newPath, function (err) { + if (err) throw err + console.log('Successfully renamed - AKA moved!') + }) - }, - err => { - console.error(err) - }) - }) - } + }, + err => { + console.error(err) + }) + }) + } - res.render('index', {}) + res.render('index', {}) }) @@ -285,89 +283,89 @@ const limit_posts_per_day = 10 router.get('/dispatch-publication-in-time', function (req, res, next) { - getAllPosts(db).then( - (results) => { - console.log('répartir', results[0]) + getAllPosts(db).then( + (results) => { + console.log('répartir', results[0]) - // on compte les posts et quel intervalle de temps mettre entre chaque pour tenir le rythme de X posts par jour + // on compte les posts et quel intervalle de temps mettre entre chaque pour tenir le rythme de X posts par jour - res.render('index', { p: results[0] }) - }, - (err) => console.error(err), - ) + res.render('index', {p: results[0]}) + }, + (err) => console.error(err), + ) }) - router.post('/direct-post', function (req, res, next) { - let env = require('dotenv').config({ path: __dirname + '/../.env' }) - console.log('dotenv', env) + let env = require('dotenv').config({path: __dirname + '/../.env'}) + console.log('dotenv', env) - // console.log('req', req) - console.log('req.body', req.body) + // console.log('req', req) + console.log('req.body', req.body) - let author = req.body.author.toUpperCase() - console.log('vérif token pour', author) - let access_token = env.parsed['TOKEN_' + author] - const masto = new Masto({ - access_token: access_token, - api_url: env.parsed.INSTANCE_MASTODON + '/api/v1/', - }) - console.log('token', access_token) - if (access_token) { + let author = req.body.author.toUpperCase() + console.log('vérif token pour', author) + let access_token = env.parsed['TOKEN_' + author] + const masto = new Masto({ + access_token: access_token, + api_url: env.parsed.INSTANCE_MASTODON + '/api/v1/', + }) + console.log('token', access_token) + if (access_token) { - let visibility = 'public' - let language = 'fr' - let sensitive = false + let visibility = 'public' + let language = 'fr' + let sensitive = false - console.log('accessToken', access_token) + console.log('accessToken', access_token) - let params = { - status: req.body.message, - visibility, - language, - sensitive - } - if (req.body.cw) { - params['spoiler_text'] = req.body.cw - } - if (req.body.scheduled_at && req.body.scheduled_at_bool) { - let dateschedule = new Date(req.body.scheduled_at) - params['scheduled_at'] = dateschedule.toISOString() - console.log('scheduled_at', params['scheduled_at']) - return - } - console.log(req.body) + let params = { + status: req.body.message, + visibility, + language, + sensitive + } + if (req.body.cw) { + params['spoiler_text'] = req.body.cw + } + if (req.body.scheduled_at && req.body.scheduled_at_bool) { + let dateschedule = new Date(req.body.scheduled_at) + params['scheduled_at'] = dateschedule.toISOString() + console.log('scheduled_at', params['scheduled_at']) + return + } + console.log(req.body) - if (!req.body.fichier) { + if (!req.body.fichier) { - console.log(' pas de fichier dans le post') - sendPostMastodon(params, masto) - res.render('index', { bodyReq: req.body }) - } + console.log(' pas de fichier dans le post') + sendPostMastodon(params, masto) + res.render('index', {bodyReq: req.body}) + } - // TODO prise en charge des fichiers joints - if (req.body.fichier) { - console.log(' envoi avec fichier') - sendPostMastodon(params, masto) - res.render('index', {bodyReq: req.body}) - } + // TODO prise en charge des fichiers joints + if (req.body.fichier) { + console.log(' envoi avec fichier') + params.image = req.body.fichier + sendPostMastodon(params, masto) + res.render('index', {bodyReq: req.body}) + } - } else { - console.error('pas de token pour ' + req.body.author) - } + } else { + console.error('pas de token pour ' + req.body.author) + } }) -function sendPostMastodon(config, masto){ - masto.post('statuses', config).then(rep => { - console.log('rep', rep) - console.log('\n message bien envoyé') - }, err => { - console.error(err) - }) +function sendPostMastodon(config, masto) { + masto.post('statuses', config).then(rep => { + console.log('rep', rep) + console.log('\n message bien envoyé') + }, err => { + console.error(err) + }) } module.exports = router diff --git a/views/index.jade b/views/index.jade index ad8fe58..ec2a08b 100644 --- a/views/index.jade +++ b/views/index.jade @@ -29,9 +29,13 @@ block content label span Content warning (optionnel) input.cw-input.autosuggest-textarea__textarea(name="cw", type="text", width="500", height="2em") + br span Qu’avez-vous en tête ? textarea.main-input.autosuggest-textarea__textarea(name="message", width="500", lines="20",autofocus="autofocus") br + div.composer--publisher + //input.button.primary(type="submit", value="ajouter à la file d'attente") + input.button.primary(type="submit", value="poster tout de suite") fieldset.wip label