|
import axios from 'axios'; |
|
import {startOfWeek, addDays, format} from 'date-fns'; |
|
import {sendMessage, sendPhoto} from './telegram'; |
|
|
|
const SITE_URL = process.env.SITE_URL || 'codewithhugo.com'; |
|
|
|
const SIMPLE_ANALYTICS_BASE_URL = |
|
`https://simpleanalytics.io/${SITE_URL}.json`; |
|
|
|
function weekStartDate(date) { |
|
return startOfWeek(date, {weekStartsOn: 1}); |
|
} |
|
|
|
const saFormat = date => format(date, 'YYYY-MM-DD'); |
|
|
|
async function getAnalyticsData(startDate, endDate) { |
|
const start = saFormat(startDate); |
|
const end = saFormat(endDate); |
|
const res = await axios.get( |
|
`${SIMPLE_ANALYTICS_BASE_URL}?start=${start}&end=${end}` |
|
); |
|
return res.data && res.data.visits; |
|
} |
|
|
|
async function makeReport() { |
|
const today = new Date(); |
|
const twoWeeksAgo = addDays(today, -14); |
|
const data = await getAnalyticsData(twoWeeksAgo, today); |
|
const dateToData = data.reduce((acc, curr) => { |
|
acc[curr.date] = curr; |
|
return acc; |
|
}, {}); |
|
|
|
const weekAgo = addDays(today, -7); |
|
const saFormattedToday = saFormat(today); |
|
const saFormattedWeekAgo = saFormat(weekAgo); |
|
|
|
const {pageviews: visitsToday} = dateToData[saFormattedToday]; |
|
const {pageviews: visitsSameDayLastWeek} = dateToData[saFormattedWeekAgo]; |
|
|
|
const weekStart = saFormat(weekStartDate(today)); |
|
const lastWeekStart = saFormat(weekStartDate(weekAgo)); |
|
|
|
const viewsPerDayThisWeek = data |
|
.filter(({date}) => date >= weekStart && date <= saFormattedToday) |
|
.map(({pageviews}) => pageviews); |
|
const viewsPerDayLastWeek = data |
|
.filter(({date}) => date >= lastWeekStart && date < weekStart) |
|
.map(({pageviews}) => pageviews); |
|
|
|
const visitsThisWeek = viewsPerDayThisWeek.reduce( |
|
(acc, curr) => acc + curr, |
|
0 |
|
); |
|
const visitsLastWeek = viewsPerDayLastWeek.reduce( |
|
(acc, curr) => acc + curr, |
|
0 |
|
); |
|
|
|
const chartBaseUrl = 'https://quickchart.io/chart'; |
|
const weekChartConfig = { |
|
type: 'bar', |
|
data: { |
|
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], |
|
datasets: [ |
|
{ |
|
label: 'Last Week', |
|
backgroundColor: 'lightgrey', |
|
data: viewsPerDayLastWeek |
|
}, |
|
{ |
|
label: 'This Week', |
|
backgroundColor: 'chartreuse', |
|
data: viewsPerDayThisWeek |
|
} |
|
] |
|
} |
|
}; |
|
const dayChartConfig = { |
|
type: 'bar', |
|
data: { |
|
labels: [], |
|
datasets: [ |
|
{ |
|
label: saFormattedWeekAgo, |
|
backgroundColor: 'lightgrey', |
|
data: [visitsSameDayLastWeek] |
|
}, |
|
{ |
|
label: 'Today', |
|
backgroundColor: 'chartreuse', |
|
data: [visitsToday] |
|
} |
|
] |
|
}, |
|
options: { |
|
legend: { |
|
display: false |
|
} |
|
} |
|
}; |
|
|
|
const dayChartUrl = `${chartBaseUrl}?c=${encodeURIComponent( |
|
JSON.stringify(dayChartConfig) |
|
)}&w=200`; |
|
const weekChartUrl = `${chartBaseUrl}?c=${encodeURIComponent( |
|
JSON.stringify(weekChartConfig) |
|
)}`; |
|
|
|
return { |
|
visitsToday, |
|
visitsSameDayLastWeek, |
|
visitsThisWeek, |
|
visitsLastWeek, |
|
dayChartUrl, |
|
weekChartUrl |
|
}; |
|
} |
|
|
|
const displayPercent = ratio => { |
|
const percentageDifference = -100 + Math.floor(ratio * 100); |
|
const sign = percentageDifference > 0 ? '+' : ''; |
|
return `${sign}${percentageDifference}%`; |
|
}; |
|
|
|
const makeReportCaptions = ({ |
|
visitsToday, |
|
visitsSameDayLastWeek, |
|
visitsThisWeek, |
|
visitsLastWeek |
|
}) => ({ |
|
dayCaption: `Today vs same day last week, ${visitsToday.toLocaleString()} vs ${visitsSameDayLastWeek.toLocaleString()} (${displayPercent( |
|
visitsToday / visitsSameDayLastWeek |
|
)})`, |
|
weekCaption: `This week vs last, ${visitsThisWeek.toLocaleString()} vs ${visitsLastWeek.toLocaleString()} (${displayPercent( |
|
visitsThisWeek / visitsLastWeek |
|
)})` |
|
}); |
|
|
|
export async function handler(event) { |
|
if (event.httpMethod !== 'POST') { |
|
console.log(event.headers && event.headers.referer); |
|
return {statusCode: 404}; |
|
} |
|
|
|
try { |
|
const report = await makeReport(); |
|
const {dayCaption, weekCaption} = makeReportCaptions(report); |
|
console.log(`Sending daily report message: "${dayCaption}"`); |
|
await sendMessage(`${dayCaption} [See chart](${report.dayChartUrl}`, { |
|
parse_mode: 'Markdown', |
|
disable_web_page_preview: true |
|
}); |
|
console.log( |
|
`Sending weekly analytics chart with caption: "${weekCaption}"` |
|
); |
|
await sendPhoto(report.weekChartUrl, weekCaption); |
|
|
|
return { |
|
statusCode: 200, |
|
body: JSON.stringify({ |
|
...report, |
|
dayCaption, |
|
weekCaption |
|
}) |
|
}; |
|
} catch (error) { |
|
console.error(error.stack); |
|
console.log(error.response); |
|
return { |
|
statusCode: 500, |
|
body: JSON.stringify({message: error.toString()}) |
|
}; |
|
} |
|
} |