Skip to content
This repository was archived by the owner on Jan 15, 2022. It is now read-only.

Commit 631cb42

Browse files
committed
first commit
0 parents  commit 631cb42

7 files changed

Lines changed: 507 additions & 0 deletions

File tree

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
TELEGRAM_BOT_TOKEN=123456789:ABCz12WQ13E13Vod-13113kXEASgEGSFYGM
2+
TELEGRAM_TARGET_CHAT_ID=@plpicompufam2018 # telegram channel
3+
GPROJECT_NAME=plpicompufam2018periodo2

.gitignore

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
2+
# Created by https://www.gitignore.io/api/vim,node
3+
4+
### Node ###
5+
# Logs
6+
logs
7+
*.log
8+
npm-debug.log*
9+
yarn-debug.log*
10+
yarn-error.log*
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
*.pid.lock
17+
18+
# Directory for instrumented libs generated by jscoverage/JSCover
19+
lib-cov
20+
21+
# Coverage directory used by tools like istanbul
22+
coverage
23+
24+
# nyc test coverage
25+
.nyc_output
26+
27+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
28+
.grunt
29+
30+
# Bower dependency directory (https://bower.io/)
31+
bower_components
32+
33+
# node-waf configuration
34+
.lock-wscript
35+
36+
# Compiled binary addons (https://nodejs.org/api/addons.html)
37+
build/Release
38+
39+
# Dependency directories
40+
node_modules/
41+
jspm_packages/
42+
43+
# TypeScript v1 declaration files
44+
typings/
45+
46+
# Optional npm cache directory
47+
.npm
48+
49+
# Optional eslint cache
50+
.eslintcache
51+
52+
# Optional REPL history
53+
.node_repl_history
54+
55+
# Output of 'npm pack'
56+
*.tgz
57+
58+
# Yarn Integrity file
59+
.yarn-integrity
60+
61+
# dotenv environment variables file
62+
.env
63+
64+
# parcel-bundler cache (https://parceljs.org/)
65+
.cache
66+
67+
# next.js build output
68+
.next
69+
70+
# nuxt.js build output
71+
.nuxt
72+
73+
# vuepress build output
74+
.vuepress/dist
75+
76+
# Serverless directories
77+
.serverless
78+
79+
### Vim ###
80+
# Swap
81+
[._]*.s[a-v][a-z]
82+
[._]*.sw[a-p]
83+
[._]s[a-rt-v][a-z]
84+
[._]ss[a-gi-z]
85+
[._]sw[a-p]
86+
87+
# Session
88+
Session.vim
89+
90+
# Temporary
91+
.netrwhist
92+
*~
93+
# Auto-generated tag files
94+
tags
95+
# Persistent undo
96+
[._]*.un~
97+
98+
99+
# End of https://www.gitignore.io/api/vim,node

fetch-last-announcement.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const fetch = require('node-fetch')
2+
const cheerio= require('cheerio')
3+
const _ = require('./utils')
4+
5+
//#region configs
6+
const SITES_GOOGLE_BASE_URL = 'https://sites.google.com'
7+
const SITES_GOOGLE_CLASSROOM_NEWS = 'classroom-news'
8+
const getURLToProjectName = projectName => `${SITES_GOOGLE_BASE_URL}/site/${projectName}`
9+
//#endregion
10+
11+
//#region handlers
12+
const titleHandler = {
13+
isPattern(e) {
14+
return _.isType(e, 'tag')
15+
&& _.isName(e, 'h4')
16+
},
17+
18+
isChildren(e) {
19+
return _.isType(e, 'tag')
20+
&& _.isName(e, 'a')
21+
&& e.hasOwnProperty('attribs')
22+
&& _.hasAttribs(e, { dir: 'ltr' })
23+
}
24+
}
25+
26+
const dateHandler = {
27+
isPattern(className) {
28+
return e => _.isType(e, 'tag')
29+
&& e.hasOwnProperty('attribs')
30+
&& _.hasAttribs(e, { class: className })
31+
},
32+
33+
isChildren(e) {
34+
return _.isType(e, 'tag')
35+
&& e.hasOwnProperty('attribs')
36+
&& _.hasAttribs(e, { dir: 'ltr' })
37+
}
38+
}
39+
//#endregion
40+
41+
function formatDate(strDate) {
42+
const {day, month, year} = _.strDateToObj(strDate)
43+
return `${day}/${month}/${year}`
44+
}
45+
46+
function scrapeLastAnnouncement(baseURL, body) {
47+
const $ = cheerio.load(body)
48+
49+
const ultimaPublicacao = $('div.announcement')[0]
50+
if (!ultimaPublicacao) {
51+
return Promise.reject(new Error('Publicação não encontrada'))
52+
}
53+
54+
const titleElement = ultimaPublicacao.children.find(titleHandler.isPattern)
55+
const publiLinkElement = titleElement.children.find(titleHandler.isChildren)
56+
const title = publiLinkElement.children.find(_.hasData).data
57+
const pageLinkPath = _.getAttribs(publiLinkElement)['href'] //.split('/').pop()
58+
59+
const timeElement = ultimaPublicacao.children.find(dateHandler.isPattern('timestamp'))
60+
const dateElement = timeElement.children.find(dateHandler.isChildren)
61+
const publish_date = dateElement.children.find(_.hasData).data
62+
63+
const response = {
64+
title: title,
65+
link: baseURL + pageLinkPath,
66+
publish_date: formatDate(publish_date)
67+
}
68+
69+
const updatedTimeElement = timeElement.children.find(dateHandler.isPattern('updatedTime'))
70+
if (updatedTimeElement) {
71+
const updatedDateElement = updatedTimeElement.children.find(dateHandler.isChildren)
72+
const updated_date = updatedDateElement.children.find(_.hasData).data
73+
74+
Object.assign(response, { updated_date: formatDate(updated_date) })
75+
}
76+
77+
return Promise.resolve(response)
78+
}
79+
80+
81+
/**
82+
*
83+
* @param {string} projectName
84+
* @returns {Promise<{title:string, link:string, publish_date:string, updated_date?:string}>}
85+
*/
86+
function fetchLastAnnouncement(projectName) {
87+
return fetch( getURLToProjectName(projectName) + '/' + SITES_GOOGLE_CLASSROOM_NEWS )
88+
.then(res => res.text())
89+
.then(body => scrapeLastAnnouncement(SITES_GOOGLE_BASE_URL, body))
90+
.catch(err => err.message)
91+
}
92+
93+
module.exports = fetchLastAnnouncement

get-daily-plp.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const fetch = require('node-fetch');
2+
const fetchLastAnnouncement = require('./fetch-last-announcement');
3+
4+
function sendMessageToTelegram(token, chatId, text, parseMode = 'HTML') {
5+
const url = `https://api.telegram.org/bot${token}/sendMessage?parse_mode=${parseMode}&chat_id=${chatId}&text=${text}`;
6+
return fetch(url);
7+
}
8+
9+
//#region Webtask.io API
10+
11+
function saveToStorage(ctx, data, cb) {
12+
ctx.storage.set(data, { force: 1 }, function (error) {
13+
if (typeof cb !== 'function') return;
14+
15+
if (error) return cb(error);
16+
return cb(null, error);
17+
});
18+
}
19+
20+
function retriveFromStorage(ctx, cb) {
21+
ctx.storage.get((error, data) => {
22+
if (error) return cb(error);
23+
cb(null, data);
24+
});
25+
}
26+
27+
28+
function saveLastAnnouncement(ctx, lastAnnouncementFetched) {
29+
return new Promise((resolve, reject) => {
30+
31+
const onRetrived = (error, lastAnnouncementSaved) => {
32+
if (error) return;
33+
if (!lastAnnouncementSaved || lastAnnouncementSaved !== lastAnnouncementFetched) {
34+
saveToStorage(ctx, lastAnnouncementFetched);
35+
resolve();
36+
} else {
37+
reject();
38+
}
39+
};
40+
41+
retriveFromStorage(ctx, onRetrived);
42+
43+
});
44+
}
45+
46+
47+
/**
48+
*
49+
* @param {WebtaskContext} ctx https://webtask.io/docs/context
50+
* @param {Function} cb Callback
51+
*/
52+
function getLastAnnouncement(ctx, cb) {
53+
const { TELEGRAM_BOT_TOKEN, TELEGRAM_TARGET_CHAT_ID, GPROJECT_NAME } = ctx.secrets;
54+
55+
fetchLastAnnouncement(GPROJECT_NAME)
56+
.then((dadosUltimoAnuncio) => {
57+
const {title, link, publish_date, updated_date} = dadosUltimoAnuncio;
58+
const msgFormatada = (updated_date)
59+
? `<b>${publish_date}</b> ~ <code>${updated_date}</code>\n<a href="${link}">${title}</a>`
60+
: `<b>${publish_date}</b>\n<a href="${link}">${title}</a>`;
61+
62+
saveLastAnnouncement(ctx, msgFormatada)
63+
.then(() => {
64+
sendMessageToTelegram(TELEGRAM_BOT_TOKEN, TELEGRAM_TARGET_CHAT_ID, msgFormatada)
65+
.then(response => cb(null, response))
66+
.catch(() => cb('something wrong'));
67+
})
68+
.catch(() => {
69+
cb(null, `[nada de novo] > "${title}"`);
70+
})
71+
})
72+
.catch(errMessage => cb(errMessage));
73+
}
74+
75+
//#endregion
76+
77+
module.exports = getLastAnnouncement;

0 commit comments

Comments
 (0)