mirror of
https://github.com/comatory/fb2iCal
synced 2025-02-26 08:27:40 +01:00
Merge branch 'add-track-endpoint-for-instrumentation' into 'master'
Add track endpoint for instrumentation See merge request ondrejsynacek/facebook-events-ical-converter!2
This commit is contained in:
commit
c4cbc3ca4c
@ -8,9 +8,9 @@ class FirebaseTransport extends Transport {
|
|||||||
this._db = options.db
|
this._db = options.db
|
||||||
}
|
}
|
||||||
|
|
||||||
log(info, callback) {
|
async log(info, callback) {
|
||||||
try {
|
try {
|
||||||
this._db.ref(`log-${new Date().getTime()}`).set(info)
|
await this._db.ref(`log-${new Date().getTime()}`).set(info)
|
||||||
callback(null, info)
|
callback(null, info)
|
||||||
this.emit('logged', info)
|
this.emit('logged', info)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -10,6 +10,7 @@ const {
|
|||||||
notFound,
|
notFound,
|
||||||
download,
|
download,
|
||||||
downloadHTML,
|
downloadHTML,
|
||||||
|
track,
|
||||||
} = require('../routes')
|
} = require('../routes')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -92,6 +93,7 @@ const configureApplication = ({
|
|||||||
|
|
||||||
app.post('/download/html', downloadHTML(appLogger || null))
|
app.post('/download/html', downloadHTML(appLogger || null))
|
||||||
app.post('/download', download(appLogger || null))
|
app.post('/download', download(appLogger || null))
|
||||||
|
app.post('/track', track(appLogger || null))
|
||||||
|
|
||||||
|
|
||||||
app.use(genericErrorHandler)
|
app.use(genericErrorHandler)
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
const { error, notFound } = require('./error')
|
const { error, notFound } = require('./error')
|
||||||
const { download, downloadHTML } = require('./download')
|
const { download, downloadHTML } = require('./download')
|
||||||
|
const { track } = require('./track')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
error,
|
error,
|
||||||
notFound,
|
notFound,
|
||||||
download,
|
download,
|
||||||
downloadHTML,
|
downloadHTML,
|
||||||
|
track,
|
||||||
}
|
}
|
||||||
|
24
lib/routes/track.js
Normal file
24
lib/routes/track.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const track = (logger) => async (req, res) => {
|
||||||
|
try {
|
||||||
|
if (!logger) {
|
||||||
|
return res.status(501)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { message, service, level, env } = req.body
|
||||||
|
|
||||||
|
await logger.log({
|
||||||
|
message,
|
||||||
|
level,
|
||||||
|
service,
|
||||||
|
env: process.env.NODE_APP || env || 'N/A',
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).send({ status: 'ok' })
|
||||||
|
} catch (err) {
|
||||||
|
next(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
track,
|
||||||
|
}
|
@ -1,4 +1,8 @@
|
|||||||
class Logger {
|
class Logger {
|
||||||
|
constructor() {
|
||||||
|
this._remote = false
|
||||||
|
}
|
||||||
|
|
||||||
log({ message, level, service }) {
|
log({ message, level, service }) {
|
||||||
console.info(
|
console.info(
|
||||||
`%c${level}\n%c${service}\n%c${message}`,
|
`%c${level}\n%c${service}\n%c${message}`,
|
||||||
@ -6,6 +10,31 @@ class Logger {
|
|||||||
'color: grey',
|
'color: grey',
|
||||||
'color: black'
|
'color: black'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!this._remote) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this._log({ message, level, service })
|
||||||
|
}
|
||||||
|
|
||||||
|
setRemoteLogging(value) {
|
||||||
|
this._remote = value
|
||||||
|
}
|
||||||
|
|
||||||
|
_log({ message, level, service }) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch('/track', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'text/html, application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ message, level, service, env: 'browser' })
|
||||||
|
})
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,21 @@ const getStorage = () => {
|
|||||||
return storage
|
return storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getConfigStorage = () => {
|
||||||
|
if (!useStorage()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage = localStorage.getItem('fb-to-ical-config')
|
||||||
|
|
||||||
|
if (!storage) {
|
||||||
|
localStorage.setItem('fb-to-ical-config', JSON.stringify({}))
|
||||||
|
return "{}"
|
||||||
|
}
|
||||||
|
|
||||||
|
return storage
|
||||||
|
}
|
||||||
|
|
||||||
const getStorageContents = (storage) => {
|
const getStorageContents = (storage) => {
|
||||||
return JSON.parse(storage)
|
return JSON.parse(storage)
|
||||||
}
|
}
|
||||||
@ -37,6 +52,15 @@ const updateStorage = (storageContents) => {
|
|||||||
localStorage.setItem('fb-to-ical-events', encodedStorage)
|
localStorage.setItem('fb-to-ical-events', encodedStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateConfigStorage = (storageContents, key, value) => {
|
||||||
|
const encodedStorage = JSON.stringify({
|
||||||
|
...storageContents,
|
||||||
|
[key]: value,
|
||||||
|
})
|
||||||
|
|
||||||
|
localStorage.setItem('fb-to-ical-config', encodedStorage)
|
||||||
|
}
|
||||||
|
|
||||||
const saveRecord = ({ id, link, createdAt, startTime, title }) => {
|
const saveRecord = ({ id, link, createdAt, startTime, title }) => {
|
||||||
if (!useStorage()) {
|
if (!useStorage()) {
|
||||||
return
|
return
|
||||||
@ -80,8 +104,10 @@ const deleteRecord = (id) => {
|
|||||||
export {
|
export {
|
||||||
migrateRecord,
|
migrateRecord,
|
||||||
getStorage,
|
getStorage,
|
||||||
|
getConfigStorage,
|
||||||
getStorageContents,
|
getStorageContents,
|
||||||
updateStorage,
|
updateStorage,
|
||||||
|
updateConfigStorage,
|
||||||
saveRecord,
|
saveRecord,
|
||||||
deleteRecord,
|
deleteRecord,
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ import { uuidv4, parseStartTimeFromiCalString, useStorage } from './app/utils'
|
|||||||
import {
|
import {
|
||||||
migrateRecord,
|
migrateRecord,
|
||||||
getStorage,
|
getStorage,
|
||||||
|
getConfigStorage,
|
||||||
getStorageContents,
|
getStorageContents,
|
||||||
updateStorage,
|
updateStorage,
|
||||||
|
updateConfigStorage,
|
||||||
saveRecord,
|
saveRecord,
|
||||||
deleteRecord,
|
deleteRecord,
|
||||||
} from './app/storage'
|
} from './app/storage'
|
||||||
@ -31,6 +33,40 @@ import generateICS from '../../lib/services/ics-generator'
|
|||||||
row.remove()
|
row.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderTrackingPanel = (storageContents) => {
|
||||||
|
const trackingPanel = document.createElement('div')
|
||||||
|
trackingPanel.id = 'tracking-panel'
|
||||||
|
|
||||||
|
const text = document.createElement('p')
|
||||||
|
text.innerText = `Can we store anonymous logs? This data is only saved to \
|
||||||
|
our internal database and is used to debug the parsing of the web pages.\n\
|
||||||
|
We'll ask you only this time and won't bother you again.`
|
||||||
|
|
||||||
|
const yesButton = document.createElement('button')
|
||||||
|
yesButton.id = 'tracking-panel__yes-button'
|
||||||
|
yesButton.innerText = 'Ok'
|
||||||
|
yesButton.addEventListener('click', () => {
|
||||||
|
updateConfigStorage(storageContents, 'track', true)
|
||||||
|
logger.setRemoteLogging(true)
|
||||||
|
trackingPanel.remove()
|
||||||
|
})
|
||||||
|
|
||||||
|
const noButton = document.createElement('button')
|
||||||
|
noButton.id = 'tracking-panel__no-button'
|
||||||
|
noButton.innerText = 'Nope'
|
||||||
|
noButton.addEventListener('click', () => {
|
||||||
|
updateConfigStorage(storageContents, 'track', false)
|
||||||
|
logger.setRemoteLogging(false)
|
||||||
|
trackingPanel.remove()
|
||||||
|
})
|
||||||
|
|
||||||
|
trackingPanel.appendChild(text)
|
||||||
|
trackingPanel.appendChild(yesButton)
|
||||||
|
trackingPanel.appendChild(noButton)
|
||||||
|
|
||||||
|
document.body.appendChild(trackingPanel)
|
||||||
|
}
|
||||||
|
|
||||||
const insertTableRow = ({ id, link, createdAt, startTime, title }) => {
|
const insertTableRow = ({ id, link, createdAt, startTime, title }) => {
|
||||||
showTable()
|
showTable()
|
||||||
|
|
||||||
@ -122,6 +158,34 @@ import generateICS from '../../lib/services/ics-generator'
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hydrateConfig = () => {
|
||||||
|
if (!useStorage()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevStorage = getConfigStorage()
|
||||||
|
const storageContents = getStorageContents(prevStorage)
|
||||||
|
|
||||||
|
const useTrackingSet = storageContents.track !== undefined
|
||||||
|
|
||||||
|
if (!useTrackingSet) {
|
||||||
|
renderTrackingPanel(storageContents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const configureLogger = (logger) => {
|
||||||
|
if (!logger || !useStorage()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevStorage = getConfigStorage()
|
||||||
|
const storageContents = getStorageContents(prevStorage)
|
||||||
|
|
||||||
|
const shouldTrack = Boolean(storageContents.track)
|
||||||
|
|
||||||
|
logger.setRemoteLogging(shouldTrack)
|
||||||
|
}
|
||||||
|
|
||||||
const clearStatuses = () => {
|
const clearStatuses = () => {
|
||||||
document.querySelectorAll('.status-item').forEach((item) => {
|
document.querySelectorAll('.status-item').forEach((item) => {
|
||||||
item.classList.remove('show')
|
item.classList.remove('show')
|
||||||
@ -235,6 +299,8 @@ import generateICS from '../../lib/services/ics-generator'
|
|||||||
}
|
}
|
||||||
|
|
||||||
hydrateList()
|
hydrateList()
|
||||||
|
hydrateConfig()
|
||||||
|
configureLogger(logger)
|
||||||
|
|
||||||
const handleHTMLResponse = (html, url) => {
|
const handleHTMLResponse = (html, url) => {
|
||||||
try {
|
try {
|
||||||
|
@ -166,3 +166,23 @@ a.delete-record {
|
|||||||
#nojs {
|
#nojs {
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tracking-panel {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
border: 3px solid navy;
|
||||||
|
background-color: lightyellow;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tracking-panel__yes-button,
|
||||||
|
#tracking-panel__no-button {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tracking-panel__yes-button {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "facebook-events-ical-converter",
|
"name": "facebook-events-ical-converter",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "facebook-events-ical-converter",
|
"name": "facebook-events-ical-converter",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"description": "App that converts events on Facebook event page to iCal file.",
|
"description": "App that converts events on Facebook event page to iCal file.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user