From 9e834126d88d74462fc3992af530f919d409fa56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:56:50 +0000 Subject: [PATCH 1/6] Initial plan From f81b4ea4e3484a378934968d8932895f979f1bfd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:22:01 +0000 Subject: [PATCH 2/6] Convert all src/ and test/ files from CommonJS to ESM Co-authored-by: electerious <499088+electerious@users.noreply.github.com> --- build.js | 17 +- functions/api.js | 4 +- package.json | 1 + src/aggregations/aggregateActions.js | 14 +- src/aggregations/aggregateActiveVisitors.js | 8 +- src/aggregations/aggregateDurations.js | 20 +- src/aggregations/aggregateNewActions.js | 6 +- src/aggregations/aggregateNewRecords.js | 6 +- src/aggregations/aggregateRecentActions.js | 6 +- src/aggregations/aggregateRecentRecords.js | 6 +- src/aggregations/aggregateTopActions.js | 16 +- src/aggregations/aggregateTopRecords.js | 16 +- src/aggregations/aggregateViews.js | 14 +- src/constants/browsers.js | 11 +- src/constants/devices.js | 11 +- src/constants/durations.js | 13 +- src/constants/events.js | 17 +- src/constants/intervals.js | 14 +- src/constants/ranges.js | 17 +- src/constants/referrers.js | 14 +- src/constants/sizes.js | 23 +- src/constants/sortings.js | 14 +- src/constants/systems.js | 11 +- src/constants/views.js | 11 +- src/database/actions.js | 47 ++-- src/database/browsers.js | 40 ++-- src/database/devices.js | 80 +++---- src/database/domains.js | 108 ++++----- src/database/durations.js | 109 ++++----- src/database/events.js | 108 ++++----- src/database/facts.js | 28 +-- src/database/languages.js | 64 +++-- src/database/pages.js | 62 +++-- src/database/permanentTokens.js | 108 ++++----- src/database/records.js | 184 +++++++------- src/database/referrers.js | 88 ++++--- src/database/sizes.js | 123 +++++----- src/database/systems.js | 80 +++---- src/database/tokens.js | 82 ++++--- src/database/views.js | 113 +++++---- src/healthcheck.js | 47 ++-- src/index.js | 43 ++-- src/middlewares/blockDemoMode.js | 6 +- src/middlewares/requireAuth.js | 4 +- src/models/Action.js | 8 +- src/models/Domain.js | 8 +- src/models/Event.js | 18 +- src/models/PermanentToken.js | 8 +- src/models/Record.js | 10 +- src/models/Token.js | 8 +- src/resolvers/actions.js | 134 +++++------ src/resolvers/domainStatistics.js | 126 +++++----- src/resolvers/domains.js | 128 +++++----- src/resolvers/eventStatistics.js | 38 ++- src/resolvers/events.js | 126 +++++----- src/resolvers/facts.js | 188 ++++++++------- src/resolvers/index.js | 32 ++- src/resolvers/permanentTokens.js | 116 +++++---- src/resolvers/records.js | 214 ++++++++--------- src/resolvers/tokens.js | 68 +++--- src/server.js | 239 ++++++++++--------- src/serverless.js | 98 ++++---- src/stages/matchDomains.js | 4 +- src/stages/matchEvents.js | 4 +- src/stages/matchLimit.js | 6 +- src/stages/projectDuration.js | 4 +- src/stages/projectMinInterval.js | 6 +- src/types/actions.js | 5 +- src/types/domainStatistics.js | 5 +- src/types/domains.js | 5 +- src/types/eventStatistics.js | 5 +- src/types/events.js | 5 +- src/types/facts.js | 5 +- src/types/index.js | 35 ++- src/types/miscellaneous.js | 5 +- src/types/permanentTokens.js | 5 +- src/types/records.js | 5 +- src/types/tokens.js | 5 +- src/ui/index.js | 91 +++---- src/utils/KnownError.js | 2 +- src/utils/config.js | 6 +- src/utils/connect.js | 6 +- src/utils/createApolloServer.js | 26 +- src/utils/createArray.js | 4 +- src/utils/createContext.js | 16 +- src/utils/createDate.js | 22 +- src/utils/customTracker.js | 14 +- src/utils/domainIds.js | 8 +- src/utils/findMatchingOrigin.js | 6 +- src/utils/fullyQualifiedDomainNames.js | 8 +- src/utils/identifier.js | 8 +- src/utils/ignoreCookie.js | 38 ++- src/utils/isAuthenticated.js | 12 +- src/utils/isDefined.js | 4 +- src/utils/isExpired.js | 4 +- src/utils/languageCodes.js | 4 +- src/utils/layout.js | 4 +- src/utils/matchesDate.js | 4 +- src/utils/messages.js | 4 +- src/utils/normalizeUrl.js | 6 +- src/utils/pipe.js | 4 +- src/utils/recursiveId.js | 6 +- src/utils/salt.js | 8 +- src/utils/signale.js | 6 +- src/utils/sortByProp.js | 4 +- src/utils/stripUrlAuth.js | 6 +- src/utils/timeZone.js | 4 +- src/utils/times.js | 4 +- test/aggregations/aggregateActiveVisitors.js | 16 +- test/aggregations/aggregateDurations.js | 18 +- test/aggregations/aggregateNewFields.js | 14 +- test/aggregations/aggregateRecentFields.js | 14 +- test/aggregations/aggregateTopFields.js | 16 +- test/aggregations/aggregateViews.js | 22 +- test/constants/browsers.js | 6 +- test/constants/devices.js | 6 +- test/constants/durations.js | 6 +- test/constants/intervals.js | 6 +- test/constants/ranges.js | 6 +- test/constants/referrers.js | 6 +- test/constants/sizes.js | 6 +- test/constants/sortings.js | 6 +- test/constants/systems.js | 6 +- test/constants/views.js | 6 +- test/resolvers/_utils.js | 180 +++++++------- test/resolvers/actions.js | 12 +- test/resolvers/domainStatistics/_utils.js | 8 +- test/resolvers/domainStatistics/browsers.js | 12 +- test/resolvers/domainStatistics/devices.js | 12 +- test/resolvers/domainStatistics/durations.js | 14 +- test/resolvers/domainStatistics/languages.js | 12 +- test/resolvers/domainStatistics/pages.js | 12 +- test/resolvers/domainStatistics/referrers.js | 12 +- test/resolvers/domainStatistics/sizes.js | 12 +- test/resolvers/domainStatistics/systems.js | 12 +- test/resolvers/domainStatistics/views.js | 12 +- test/resolvers/domains.js | 12 +- test/resolvers/eventStatistics/_utils.js | 8 +- test/resolvers/eventStatistics/chart.js | 12 +- test/resolvers/eventStatistics/list.js | 12 +- test/resolvers/events.js | 12 +- test/resolvers/facts.js | 10 +- test/resolvers/permanentTokens.js | 12 +- test/resolvers/records.js | 10 +- test/resolvers/tokens.js | 12 +- test/server.js | 54 ++--- test/serverWithAutoCors.js | 56 ++--- test/serverWithCors.js | 34 ++- test/serverWithMultipleCors.js | 34 ++- test/serverWithUnlistedCors.js | 34 ++- test/serverWithWildcardCors.js | 34 ++- test/serverWithoutCors.js | 34 ++- test/utils/createArray.js | 16 +- test/utils/customTrackerUrl.js | 24 +- test/utils/identifier.js | 70 +++--- test/utils/isExpired.js | 26 +- test/utils/layout.js | 38 ++- test/utils/messages.js | 26 +- test/utils/normalizeUrl.js | 34 ++- test/utils/pipe.js | 32 ++- test/utils/salt.js | 14 +- test/utils/signale.js | 12 +- test/utils/stripUrlAuth.js | 18 +- test/utils/timeZone.js | 12 +- test/utils/times.js | 16 +- 165 files changed, 2341 insertions(+), 2676 deletions(-) diff --git a/build.js b/build.js index e5fd3d76b..c5fa4e02f 100755 --- a/build.js +++ b/build.js @@ -1,18 +1,17 @@ #!/usr/bin/env node -'use strict' -require('dotenv').config() +import 'dotenv/config' -const config = require('./src/utils/config') -const customTracker = require('./src/utils/customTracker') -const { index, styles, scripts, tracker, build } = require('./src/ui/index') +import config from './src/utils/config.js' +import * as customTracker from './src/utils/customTracker.js' +import { index, styles, scripts, tracker, build } from './src/ui/index.js' // Build files that are identical on every installation if (config.isPreBuildMode === true) { - build('dist/index.css', styles) - build('dist/index.js', scripts) - build('dist/tracker.js', tracker) +build('dist/index.css', styles) +build('dist/index.js', scripts) +build('dist/tracker.js', tracker) } // Build files that depend on environment variables build(`dist/index.html`, index) -if (customTracker.exists === true) build(`dist/${ customTracker.path }`, tracker) \ No newline at end of file +if (customTracker.exists === true) build(`dist/${ customTracker.path }`, tracker) diff --git a/functions/api.js b/functions/api.js index ea43d588f..87e65ddec 100644 --- a/functions/api.js +++ b/functions/api.js @@ -1,9 +1,7 @@ -'use strict' - /** * A serverless function handler for the '/api' route, for use with Netlify. * * See: * - https://docs.netlify.com/functions/overview/ */ -exports.handler = require('../src/serverless').handler \ No newline at end of file +export { handler } from '../src/serverless.js' diff --git a/package.json b/package.json index 7f9afe7ff..59ed7133d 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "Tobias Reich " ], "description": "Self-hosted, Node.js based analytics tool for those who care about privacy", + "type": "module", "main": "src/index.js", "keywords": [ "server", diff --git a/src/aggregations/aggregateActions.js b/src/aggregations/aggregateActions.js index 8b4780e41..456ba0878 100644 --- a/src/aggregations/aggregateActions.js +++ b/src/aggregations/aggregateActions.js @@ -1,9 +1,7 @@ -'use strict' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import matchEvents from '../stages/matchEvents.js' -const intervals = require('../constants/intervals') -const matchEvents = require('../stages/matchEvents') - -module.exports = (ids, average, interval, limit, dateDetails) => { +export default (ids, average, interval, limit, dateDetails) => { const aggregation = [ matchEvents(ids), { @@ -17,9 +15,9 @@ module.exports = (ids, average, interval, limit, dateDetails) => { aggregation[1].$group.count = average === true ? { $avg: '$value' } : { $sum: '$value' } const dateExpression = { date: '$created', timezone: dateDetails.userTimeZone } - const matchDay = [ intervals.INTERVALS_DAILY ].includes(interval) - const matchMonth = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY ].includes(interval) - const matchYear = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY, intervals.INTERVALS_YEARLY ].includes(interval) + const matchDay = [ INTERVALS_DAILY ].includes(interval) + const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) + const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) if (matchDay === true) aggregation[1].$group._id.day = { $dayOfMonth: dateExpression } if (matchMonth === true) aggregation[1].$group._id.month = { $month: dateExpression } diff --git a/src/aggregations/aggregateActiveVisitors.js b/src/aggregations/aggregateActiveVisitors.js index d59f17d30..610c9b45e 100644 --- a/src/aggregations/aggregateActiveVisitors.js +++ b/src/aggregations/aggregateActiveVisitors.js @@ -1,9 +1,7 @@ -'use strict' +import { DURATIONS_LIMIT, DURATIONS_INTERVAL } from '../constants/durations.js' +import matchDomains from '../stages/matchDomains.js' -const { DURATIONS_LIMIT, DURATIONS_INTERVAL } = require('../constants/durations') -const matchDomains = require('../stages/matchDomains') - -module.exports = (ids, dateDetails) => { +export default (ids, dateDetails) => { const aggregation = [ matchDomains(ids), { diff --git a/src/aggregations/aggregateDurations.js b/src/aggregations/aggregateDurations.js index de56a97cd..83eded94c 100644 --- a/src/aggregations/aggregateDurations.js +++ b/src/aggregations/aggregateDurations.js @@ -1,12 +1,10 @@ -'use strict' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import matchDomains from '../stages/matchDomains.js' +import projectDuration from '../stages/projectDuration.js' +import projectMinInterval from '../stages/projectMinInterval.js' +import matchLimit from '../stages/matchLimit.js' -const intervals = require('../constants/intervals') -const matchDomains = require('../stages/matchDomains') -const projectDuration = require('../stages/projectDuration') -const projectMinInterval = require('../stages/projectMinInterval') -const matchLimit = require('../stages/matchLimit') - -module.exports = (ids, interval, limit, dateDetails) => { +export default (ids, interval, limit, dateDetails) => { const aggregation = [ matchDomains(ids), projectDuration(), @@ -25,9 +23,9 @@ module.exports = (ids, interval, limit, dateDetails) => { aggregation[0].$match.created = { $gte: dateDetails.includeFnByInterval(interval)(limit) } const dateExpression = { date: '$created', timezone: dateDetails.userTimeZone } - const matchDay = [ intervals.INTERVALS_DAILY ].includes(interval) - const matchMonth = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY ].includes(interval) - const matchYear = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY, intervals.INTERVALS_YEARLY ].includes(interval) + const matchDay = [ INTERVALS_DAILY ].includes(interval) + const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) + const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) if (matchDay === true) aggregation[4].$group._id.day = { $dayOfMonth: dateExpression } if (matchMonth === true) aggregation[4].$group._id.month = { $month: dateExpression } diff --git a/src/aggregations/aggregateNewActions.js b/src/aggregations/aggregateNewActions.js index 6b612f93c..5d29e6a17 100644 --- a/src/aggregations/aggregateNewActions.js +++ b/src/aggregations/aggregateNewActions.js @@ -1,8 +1,6 @@ -'use strict' +import matchEvents from '../stages/matchEvents.js' -const matchEvents = require('../stages/matchEvents') - -module.exports = (ids, limit) => { +export default (ids, limit) => { const aggregation = [ matchEvents(ids), { diff --git a/src/aggregations/aggregateNewRecords.js b/src/aggregations/aggregateNewRecords.js index 5f60ff970..35d646be2 100644 --- a/src/aggregations/aggregateNewRecords.js +++ b/src/aggregations/aggregateNewRecords.js @@ -1,8 +1,6 @@ -'use strict' +import matchDomains from '../stages/matchDomains.js' -const matchDomains = require('../stages/matchDomains') - -module.exports = (ids, properties, limit, or) => { +export default (ids, properties, limit, or) => { const aggregation = [ matchDomains(ids), { diff --git a/src/aggregations/aggregateRecentActions.js b/src/aggregations/aggregateRecentActions.js index 01b1a874c..50281a9ad 100644 --- a/src/aggregations/aggregateRecentActions.js +++ b/src/aggregations/aggregateRecentActions.js @@ -1,8 +1,6 @@ -'use strict' +import matchEvents from '../stages/matchEvents.js' -const matchEvents = require('../stages/matchEvents') - -module.exports = (ids, limit) => { +export default (ids, limit) => { const aggregation = [ matchEvents(ids), { diff --git a/src/aggregations/aggregateRecentRecords.js b/src/aggregations/aggregateRecentRecords.js index f20bf6c5b..c17c1dc68 100644 --- a/src/aggregations/aggregateRecentRecords.js +++ b/src/aggregations/aggregateRecentRecords.js @@ -1,8 +1,6 @@ -'use strict' +import matchDomains from '../stages/matchDomains.js' -const matchDomains = require('../stages/matchDomains') - -module.exports = (ids, properties, limit, or) => { +export default (ids, properties, limit, or) => { const aggregation = [ matchDomains(ids), { diff --git a/src/aggregations/aggregateTopActions.js b/src/aggregations/aggregateTopActions.js index 30b93da46..9d3932dcf 100644 --- a/src/aggregations/aggregateTopActions.js +++ b/src/aggregations/aggregateTopActions.js @@ -1,9 +1,7 @@ -'use strict' +import { RANGES_LAST_24_HOURS, RANGES_LAST_7_DAYS, RANGES_LAST_30_DAYS, RANGES_LAST_6_MONTHS } from '../constants/ranges.js' +import matchEvents from '../stages/matchEvents.js' -const ranges = require('../constants/ranges') -const matchEvents = require('../stages/matchEvents') - -module.exports = (ids, average, range, limit, dateDetails) => { +export default (ids, average, range, limit, dateDetails) => { const aggregation = [ matchEvents(ids), { @@ -26,19 +24,19 @@ module.exports = (ids, average, range, limit, dateDetails) => { aggregation[0].$match.key = { $ne: null } aggregation[1].$group.count = average === true ? { $avg: '$value' } : { $sum: '$value' } - if (range === ranges.RANGES_LAST_24_HOURS) { + if (range === RANGES_LAST_24_HOURS) { aggregation[0].$match.created = { $gte: dateDetails.lastHours(24) } } - if (range === ranges.RANGES_LAST_7_DAYS) { + if (range === RANGES_LAST_7_DAYS) { aggregation[0].$match.created = { $gte: dateDetails.lastDays(7) } } - if (range === ranges.RANGES_LAST_30_DAYS) { + if (range === RANGES_LAST_30_DAYS) { aggregation[0].$match.created = { $gte: dateDetails.lastDays(30) } } - if (range === ranges.RANGES_LAST_6_MONTHS) { + if (range === RANGES_LAST_6_MONTHS) { aggregation[0].$match.created = { $gte: dateDetails.lastMonths(6) } } diff --git a/src/aggregations/aggregateTopRecords.js b/src/aggregations/aggregateTopRecords.js index 8c1f6eff0..3034ed710 100644 --- a/src/aggregations/aggregateTopRecords.js +++ b/src/aggregations/aggregateTopRecords.js @@ -1,9 +1,7 @@ -'use strict' +import { RANGES_LAST_24_HOURS, RANGES_LAST_7_DAYS, RANGES_LAST_30_DAYS, RANGES_LAST_6_MONTHS } from '../constants/ranges.js' +import matchDomains from '../stages/matchDomains.js' -const ranges = require('../constants/ranges') -const matchDomains = require('../stages/matchDomains') - -module.exports = (ids, properties, range, limit, dateDetails, or) => { +export default (ids, properties, range, limit, dateDetails, or) => { const aggregation = [ matchDomains(ids), { @@ -36,19 +34,19 @@ module.exports = (ids, properties, range, limit, dateDetails, or) => { aggregation[1].$group._id[property] = `$${ property }` }) - if (range === ranges.RANGES_LAST_24_HOURS) { + if (range === RANGES_LAST_24_HOURS) { aggregation[0].$match.created = { $gte: dateDetails.lastHours(24) } } - if (range === ranges.RANGES_LAST_7_DAYS) { + if (range === RANGES_LAST_7_DAYS) { aggregation[0].$match.created = { $gte: dateDetails.lastDays(7) } } - if (range === ranges.RANGES_LAST_30_DAYS) { + if (range === RANGES_LAST_30_DAYS) { aggregation[0].$match.created = { $gte: dateDetails.lastDays(30) } } - if (range === ranges.RANGES_LAST_6_MONTHS) { + if (range === RANGES_LAST_6_MONTHS) { aggregation[0].$match.created = { $gte: dateDetails.lastMonths(6) } } diff --git a/src/aggregations/aggregateViews.js b/src/aggregations/aggregateViews.js index 04643984a..1af276eef 100644 --- a/src/aggregations/aggregateViews.js +++ b/src/aggregations/aggregateViews.js @@ -1,9 +1,7 @@ -'use strict' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import matchDomains from '../stages/matchDomains.js' -const intervals = require('../constants/intervals') -const matchDomains = require('../stages/matchDomains') - -module.exports = (ids, unique, interval, limit, dateDetails) => { +export default (ids, unique, interval, limit, dateDetails) => { const aggregation = [ matchDomains(ids), { @@ -24,9 +22,9 @@ module.exports = (ids, unique, interval, limit, dateDetails) => { aggregation[0].$match.created = { $gte: dateDetails.includeFnByInterval(interval)(limit) } const dateExpression = { date: '$created', timezone: dateDetails.userTimeZone } - const matchDay = [ intervals.INTERVALS_DAILY ].includes(interval) - const matchMonth = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY ].includes(interval) - const matchYear = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY, intervals.INTERVALS_YEARLY ].includes(interval) + const matchDay = [ INTERVALS_DAILY ].includes(interval) + const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) + const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) if (matchDay === true) aggregation[1].$group._id.day = { $dayOfMonth: dateExpression } if (matchMonth === true) aggregation[1].$group._id.month = { $month: dateExpression } diff --git a/src/constants/browsers.js b/src/constants/browsers.js index f34543e75..3c8ab3a63 100644 --- a/src/constants/browsers.js +++ b/src/constants/browsers.js @@ -1,9 +1,2 @@ -'use strict' - -const BROWSERS_TYPE_WITH_VERSION = 'WITH_VERSION' -const BROWSERS_TYPE_NO_VERSION = 'NO_VERSION' - -module.exports = { - BROWSERS_TYPE_WITH_VERSION, - BROWSERS_TYPE_NO_VERSION, -} \ No newline at end of file +export const BROWSERS_TYPE_WITH_VERSION = 'WITH_VERSION' +export const BROWSERS_TYPE_NO_VERSION = 'NO_VERSION' \ No newline at end of file diff --git a/src/constants/devices.js b/src/constants/devices.js index e3f7a5aab..8edf75c61 100644 --- a/src/constants/devices.js +++ b/src/constants/devices.js @@ -1,9 +1,2 @@ -'use strict' - -const DEVICES_TYPE_WITH_MODEL = 'WITH_MODEL' -const DEVICES_TYPE_NO_MODEL = 'NO_MODEL' - -module.exports = { - DEVICES_TYPE_WITH_MODEL, - DEVICES_TYPE_NO_MODEL, -} \ No newline at end of file +export const DEVICES_TYPE_WITH_MODEL = 'WITH_MODEL' +export const DEVICES_TYPE_NO_MODEL = 'NO_MODEL' \ No newline at end of file diff --git a/src/constants/durations.js b/src/constants/durations.js index f1ad75d47..f01858c8f 100644 --- a/src/constants/durations.js +++ b/src/constants/durations.js @@ -1,11 +1,4 @@ -'use strict' +import { hour } from '../utils/times.js' -const { hour } = require('../utils/times') - -const DURATIONS_INTERVAL = 15000 -const DURATIONS_LIMIT = hour / 2 - -module.exports = { - DURATIONS_INTERVAL, - DURATIONS_LIMIT, -} \ No newline at end of file +export const DURATIONS_INTERVAL = 15000 +export const DURATIONS_LIMIT = hour / 2 \ No newline at end of file diff --git a/src/constants/events.js b/src/constants/events.js index 91cd45691..fc8c3ca5f 100644 --- a/src/constants/events.js +++ b/src/constants/events.js @@ -1,13 +1,4 @@ -'use strict' - -const EVENTS_TYPE_TOTAL_CHART = 'TOTAL_CHART' -const EVENTS_TYPE_AVERAGE_CHART = 'AVERAGE_CHART' -const EVENTS_TYPE_TOTAL_LIST = 'TOTAL_LIST' -const EVENTS_TYPE_AVERAGE_LIST = 'AVERAGE_LIST' - -module.exports = { - EVENTS_TYPE_TOTAL_CHART, - EVENTS_TYPE_AVERAGE_CHART, - EVENTS_TYPE_TOTAL_LIST, - EVENTS_TYPE_AVERAGE_LIST, -} \ No newline at end of file +export const EVENTS_TYPE_TOTAL_CHART = 'TOTAL_CHART' +export const EVENTS_TYPE_AVERAGE_CHART = 'AVERAGE_CHART' +export const EVENTS_TYPE_TOTAL_LIST = 'TOTAL_LIST' +export const EVENTS_TYPE_AVERAGE_LIST = 'AVERAGE_LIST' \ No newline at end of file diff --git a/src/constants/intervals.js b/src/constants/intervals.js index 8b54438cb..c83204014 100644 --- a/src/constants/intervals.js +++ b/src/constants/intervals.js @@ -1,11 +1,3 @@ -'use strict' - -const INTERVALS_DAILY = 'DAILY' -const INTERVALS_MONTHLY = 'MONTHLY' -const INTERVALS_YEARLY = 'YEARLY' - -module.exports = { - INTERVALS_DAILY, - INTERVALS_MONTHLY, - INTERVALS_YEARLY, -} \ No newline at end of file +export const INTERVALS_DAILY = 'DAILY' +export const INTERVALS_MONTHLY = 'MONTHLY' +export const INTERVALS_YEARLY = 'YEARLY' \ No newline at end of file diff --git a/src/constants/ranges.js b/src/constants/ranges.js index 50f2fbf22..c0309e4b8 100644 --- a/src/constants/ranges.js +++ b/src/constants/ranges.js @@ -1,13 +1,4 @@ -'use strict' - -const RANGES_LAST_24_HOURS = 'LAST_24_HOURS' -const RANGES_LAST_7_DAYS = 'LAST_7_DAYS' -const RANGES_LAST_30_DAYS = 'LAST_30_DAYS' -const RANGES_LAST_6_MONTHS = 'LAST_6_MONTHS' - -module.exports = { - RANGES_LAST_24_HOURS, - RANGES_LAST_7_DAYS, - RANGES_LAST_30_DAYS, - RANGES_LAST_6_MONTHS, -} \ No newline at end of file +export const RANGES_LAST_24_HOURS = 'LAST_24_HOURS' +export const RANGES_LAST_7_DAYS = 'LAST_7_DAYS' +export const RANGES_LAST_30_DAYS = 'LAST_30_DAYS' +export const RANGES_LAST_6_MONTHS = 'LAST_6_MONTHS' \ No newline at end of file diff --git a/src/constants/referrers.js b/src/constants/referrers.js index 4ef272be0..25cee780a 100644 --- a/src/constants/referrers.js +++ b/src/constants/referrers.js @@ -1,11 +1,3 @@ -'use strict' - -const REFERRERS_TYPE_WITH_SOURCE = 'WITH_SOURCE' -const REFERRERS_TYPE_NO_SOURCE = 'NO_SOURCE' -const REFERRERS_TYPE_ONLY_SOURCE = 'ONLY_SOURCE' - -module.exports = { - REFERRERS_TYPE_WITH_SOURCE, - REFERRERS_TYPE_NO_SOURCE, - REFERRERS_TYPE_ONLY_SOURCE, -} \ No newline at end of file +export const REFERRERS_TYPE_WITH_SOURCE = 'WITH_SOURCE' +export const REFERRERS_TYPE_NO_SOURCE = 'NO_SOURCE' +export const REFERRERS_TYPE_ONLY_SOURCE = 'ONLY_SOURCE' \ No newline at end of file diff --git a/src/constants/sizes.js b/src/constants/sizes.js index bd1524a35..9d2ee701c 100644 --- a/src/constants/sizes.js +++ b/src/constants/sizes.js @@ -1,17 +1,6 @@ -'use strict' - -const SIZES_TYPE_BROWSER_HEIGHT = 'BROWSER_HEIGHT' -const SIZES_TYPE_BROWSER_RESOLUTION = 'BROWSER_RESOLUTION' -const SIZES_TYPE_BROWSER_WIDTH = 'BROWSER_WIDTH' -const SIZES_TYPE_SCREEN_HEIGHT = 'SCREEN_HEIGHT' -const SIZES_TYPE_SCREEN_RESOLUTION = 'SCREEN_RESOLUTION' -const SIZES_TYPE_SCREEN_WIDTH = 'SCREEN_WIDTH' - -module.exports = { - SIZES_TYPE_BROWSER_HEIGHT, - SIZES_TYPE_BROWSER_RESOLUTION, - SIZES_TYPE_BROWSER_WIDTH, - SIZES_TYPE_SCREEN_HEIGHT, - SIZES_TYPE_SCREEN_RESOLUTION, - SIZES_TYPE_SCREEN_WIDTH, -} \ No newline at end of file +export const SIZES_TYPE_BROWSER_HEIGHT = 'BROWSER_HEIGHT' +export const SIZES_TYPE_BROWSER_RESOLUTION = 'BROWSER_RESOLUTION' +export const SIZES_TYPE_BROWSER_WIDTH = 'BROWSER_WIDTH' +export const SIZES_TYPE_SCREEN_HEIGHT = 'SCREEN_HEIGHT' +export const SIZES_TYPE_SCREEN_RESOLUTION = 'SCREEN_RESOLUTION' +export const SIZES_TYPE_SCREEN_WIDTH = 'SCREEN_WIDTH' \ No newline at end of file diff --git a/src/constants/sortings.js b/src/constants/sortings.js index dd3ada468..bd350e58e 100644 --- a/src/constants/sortings.js +++ b/src/constants/sortings.js @@ -1,11 +1,3 @@ -'use strict' - -const SORTINGS_TOP = 'TOP' -const SORTINGS_NEW = 'NEW' -const SORTINGS_RECENT = 'RECENT' - -module.exports = { - SORTINGS_TOP, - SORTINGS_NEW, - SORTINGS_RECENT, -} \ No newline at end of file +export const SORTINGS_TOP = 'TOP' +export const SORTINGS_NEW = 'NEW' +export const SORTINGS_RECENT = 'RECENT' \ No newline at end of file diff --git a/src/constants/systems.js b/src/constants/systems.js index 9e59f8ef1..642d4fe63 100644 --- a/src/constants/systems.js +++ b/src/constants/systems.js @@ -1,9 +1,2 @@ -'use strict' - -const SYSTEMS_TYPE_WITH_VERSION = 'WITH_VERSION' -const SYSTEMS_TYPE_NO_VERSION = 'NO_VERSION' - -module.exports = { - SYSTEMS_TYPE_WITH_VERSION, - SYSTEMS_TYPE_NO_VERSION, -} \ No newline at end of file +export const SYSTEMS_TYPE_WITH_VERSION = 'WITH_VERSION' +export const SYSTEMS_TYPE_NO_VERSION = 'NO_VERSION' \ No newline at end of file diff --git a/src/constants/views.js b/src/constants/views.js index 1e6178d76..56078597b 100644 --- a/src/constants/views.js +++ b/src/constants/views.js @@ -1,9 +1,2 @@ -'use strict' - -const VIEWS_TYPE_UNIQUE = 'UNIQUE' -const VIEWS_TYPE_TOTAL = 'TOTAL' - -module.exports = { - VIEWS_TYPE_UNIQUE, - VIEWS_TYPE_TOTAL, -} \ No newline at end of file +export const VIEWS_TYPE_UNIQUE = 'UNIQUE' +export const VIEWS_TYPE_TOTAL = 'TOTAL' \ No newline at end of file diff --git a/src/database/actions.js b/src/database/actions.js index 90890b398..2f58a655e 100644 --- a/src/database/actions.js +++ b/src/database/actions.js @@ -1,17 +1,16 @@ -'use strict' - -const { utcToZonedTime } = require('date-fns-tz') - -const Action = require('../models/Action') -const aggregateTopActions = require('../aggregations/aggregateTopActions') -const aggregateNewActions = require('../aggregations/aggregateNewActions') -const aggregateRecentActions = require('../aggregations/aggregateRecentActions') -const aggregateActions = require('../aggregations/aggregateActions') -const sortings = require('../constants/sortings') -const intervals = require('../constants/intervals') -const createArray = require('../utils/createArray') -const matchesDate = require('../utils/matchesDate') -const recursiveId = require('../utils/recursiveId') +import dateFnsTz from 'date-fns-tz' +const { utcToZonedTime } = dateFnsTz + +import Action from '../models/Action.js' +import aggregateTopActions from '../aggregations/aggregateTopActions.js' +import aggregateNewActions from '../aggregations/aggregateNewActions.js' +import aggregateRecentActions from '../aggregations/aggregateRecentActions.js' +import aggregateActions from '../aggregations/aggregateActions.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import createArray from '../utils/createArray.js' +import matchesDate from '../utils/matchesDate.js' +import recursiveId from '../utils/recursiveId.js' const response = (entry) => ({ id: entry.id, @@ -60,9 +59,9 @@ const getChart = async (ids, type, interval, limit, dateDetails) => { })() const enhance = (entries) => { - const matchDay = [ intervals.INTERVALS_DAILY ].includes(interval) - const matchMonth = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY ].includes(interval) - const matchYear = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY, intervals.INTERVALS_YEARLY ].includes(interval) + const matchDay = [ INTERVALS_DAILY ].includes(interval) + const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) + const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) return createArray(limit).map((_, index) => { const date = dateDetails.lastFnByInterval(interval)(index) @@ -104,14 +103,14 @@ const getChart = async (ids, type, interval, limit, dateDetails) => { const getList = async (ids, sorting, type, range, limit, dateDetails) => { const aggregation = (() => { if (type === 'TOTAL') { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopActions(ids, false, range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewActions(ids, limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentActions(ids, limit) + if (sorting === SORTINGS_TOP) return aggregateTopActions(ids, false, range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewActions(ids, limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentActions(ids, limit) } if (type === 'AVERAGE') { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopActions(ids, true, range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewActions(ids, limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentActions(ids, limit) + if (sorting === SORTINGS_TOP) return aggregateTopActions(ids, true, range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewActions(ids, limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentActions(ids, limit) } })() @@ -143,7 +142,7 @@ const del = (eventId) => { }) } -module.exports = { +export { add, update, getChart, diff --git a/src/database/browsers.js b/src/database/browsers.js index 22ff5600a..6dd912f78 100644 --- a/src/database/browsers.js +++ b/src/database/browsers.js @@ -1,30 +1,28 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const sortings = require('../constants/sortings') -const constants = require('../constants/browsers') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import { BROWSERS_TYPE_NO_VERSION, BROWSERS_TYPE_WITH_VERSION } from '../constants/browsers.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { const aggregation = (() => { - if (type === constants.BROWSERS_TYPE_NO_VERSION) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'browserName' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'browserName' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'browserName' ], limit) + if (type === BROWSERS_TYPE_NO_VERSION) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'browserName' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'browserName' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'browserName' ], limit) } - if (type === constants.BROWSERS_TYPE_WITH_VERSION) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'browserName', 'browserVersion' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'browserName', 'browserVersion' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'browserName', 'browserVersion' ], limit) + if (type === BROWSERS_TYPE_WITH_VERSION) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'browserName', 'browserVersion' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'browserName', 'browserVersion' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'browserName', 'browserVersion' ], limit) } })() const enhanceId = (id) => { - if (type === constants.BROWSERS_TYPE_NO_VERSION) return `${ id.browserName }` - if (type === constants.BROWSERS_TYPE_WITH_VERSION) return `${ id.browserName } ${ id.browserVersion }` + if (type === BROWSERS_TYPE_NO_VERSION) return `${ id.browserName }` + if (type === BROWSERS_TYPE_WITH_VERSION) return `${ id.browserName } ${ id.browserVersion }` } const enhance = (entries) => { @@ -45,6 +43,4 @@ const get = async (ids, sorting, type, range, limit, dateDetails) => { ) } -module.exports = { - get, -} \ No newline at end of file +export default get \ No newline at end of file diff --git a/src/database/devices.js b/src/database/devices.js index b1c2f349b..5d9117565 100644 --- a/src/database/devices.js +++ b/src/database/devices.js @@ -1,50 +1,46 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const sortings = require('../constants/sortings') -const constants = require('../constants/devices') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import { DEVICES_TYPE_NO_MODEL, DEVICES_TYPE_WITH_MODEL } from '../constants/devices.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { - const aggregation = (() => { - if (type === constants.DEVICES_TYPE_NO_MODEL) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer' ], limit) - } - if (type === constants.DEVICES_TYPE_WITH_MODEL) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer', 'deviceName' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) - } - })() +const aggregation = (() => { +if (type === DEVICES_TYPE_NO_MODEL) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer' ], limit) +} +if (type === DEVICES_TYPE_WITH_MODEL) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer', 'deviceName' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) +} +})() - const enhanceId = (id) => { - if (type === constants.DEVICES_TYPE_NO_MODEL) return `${ id.deviceManufacturer }` - if (type === constants.DEVICES_TYPE_WITH_MODEL) return `${ id.deviceManufacturer } ${ id.deviceName }` - } +const enhanceId = (id) => { +if (type === DEVICES_TYPE_NO_MODEL) return `${ id.deviceManufacturer }` +if (type === DEVICES_TYPE_WITH_MODEL) return `${ id.deviceManufacturer } ${ id.deviceName }` +} - const enhance = (entries) => { - return entries.map((entry) => { - const value = enhanceId(entry._id) +const enhance = (entries) => { +return entries.map((entry) => { +const value = enhanceId(entry._id) - return { - id: recursiveId([ value, sorting, type, range, ...ids ]), - value, - count: entry.count, - created: entry.created, - } - }) - } +return { +id: recursiveId([ value, sorting, type, range, ...ids ]), +value, +count: entry.count, +created: entry.created, +} +}) +} - return enhance( - await Record.aggregate(aggregation), - ) +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/domains.js b/src/database/domains.js index 2a4eddae4..a4b4c35c0 100644 --- a/src/database/domains.js +++ b/src/database/domains.js @@ -1,78 +1,76 @@ -'use strict' - -const Domain = require('../models/Domain') -const sortByProp = require('../utils/sortByProp') +import Domain from '../models/Domain.js' +import sortByProp from '../utils/sortByProp.js' const response = (entry) => ({ - id: entry.id, - title: entry.title, - created: entry.created, - updated: entry.updated, +id: entry.id, +title: entry.title, +created: entry.created, +updated: entry.updated, }) const add = async (data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Domain.create({ - title: data.title, - }), - ) +return enhance( +await Domain.create({ +title: data.title, +}), +) } const all = async () => { - const enhance = (entries) => { - return entries - .map(response) - .sort(sortByProp('title')) - } +const enhance = (entries) => { +return entries +.map(response) +.sort(sortByProp('title')) +} - return enhance( - await Domain.find({}), - ) +return enhance( +await Domain.find({}), +) } const get = async (id) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Domain.findOne({ id }), - ) +return enhance( +await Domain.findOne({ id }), +) } const update = async (id, data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Domain.findOneAndUpdate({ - id, - }, { - $set: { - title: data.title, - updated: Date.now(), - }, - }, { - new: true, - }), - ) +return enhance( +await Domain.findOneAndUpdate({ +id, +}, { +$set: { +title: data.title, +updated: Date.now(), +}, +}, { +new: true, +}), +) } const del = (id) => { - return Domain.findOneAndDelete({ - id, - }) +return Domain.findOneAndDelete({ +id, +}) } -module.exports = { - add, - all, - get, - update, - del, -} \ No newline at end of file +export { +add, +all, +get, +update, +del, +} diff --git a/src/database/durations.js b/src/database/durations.js index ca260ef3c..3aa24e6e0 100644 --- a/src/database/durations.js +++ b/src/database/durations.js @@ -1,61 +1,58 @@ -'use strict' +import dateFnsTz from 'date-fns-tz' +const { utcToZonedTime } = dateFnsTz -const { utcToZonedTime } = require('date-fns-tz') - -const Record = require('../models/Record') -const aggregateDurations = require('../aggregations/aggregateDurations') -const intervals = require('../constants/intervals') -const createArray = require('../utils/createArray') -const matchesDate = require('../utils/matchesDate') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateDurations from '../aggregations/aggregateDurations.js' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import createArray from '../utils/createArray.js' +import matchesDate from '../utils/matchesDate.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, interval, limit, dateDetails) => { - const aggregation = (() => { - return aggregateDurations(ids, interval, limit, dateDetails) - })() - - const enhance = (entries) => { - const matchDay = [ intervals.INTERVALS_DAILY ].includes(interval) - const matchMonth = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY ].includes(interval) - const matchYear = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY, intervals.INTERVALS_YEARLY ].includes(interval) - - return createArray(limit).map((_, index) => { - const date = dateDetails.lastFnByInterval(interval)(index) - - // Database entries include the day, month and year in the - // timezone of the user. We therefore need to match it against a - // date in the timezone of the user. - const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) - - // Find a entry that matches the date - const entry = entries.find((entry) => { - return matchesDate( - matchDay === true ? entry._id.day : undefined, - matchMonth === true ? entry._id.month : undefined, - matchYear === true ? entry._id.year : undefined, - userZonedDate, - ) - }) - - const value = (() => { - if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` - if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` - if (matchYear === true) return `${ date.getFullYear() }` - })() - - return { - id: recursiveId([ value, ...ids ]), - value, - count: entry == null ? 0 : entry.count, - } - }) - } - - return enhance( - await Record.aggregate(aggregation), - ) +const aggregation = (() => { +return aggregateDurations(ids, interval, limit, dateDetails) +})() + +const enhance = (entries) => { +const matchDay = [ INTERVALS_DAILY ].includes(interval) +const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) +const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) + +return createArray(limit).map((_, index) => { +const date = dateDetails.lastFnByInterval(interval)(index) + +// Database entries include the day, month and year in the +// timezone of the user. We therefore need to match it against a +// date in the timezone of the user. +const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) + +// Find a entry that matches the date +const entry = entries.find((entry) => { +return matchesDate( +matchDay === true ? entry._id.day : undefined, +matchMonth === true ? entry._id.month : undefined, +matchYear === true ? entry._id.year : undefined, +userZonedDate, +) +}) + +const value = (() => { +if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` +if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` +if (matchYear === true) return `${ date.getFullYear() }` +})() + +return { +id: recursiveId([ value, ...ids ]), +value, +count: entry == null ? 0 : entry.count, +} +}) +} + +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/events.js b/src/database/events.js index bc0cb7f2e..1c2f3696a 100644 --- a/src/database/events.js +++ b/src/database/events.js @@ -1,78 +1,76 @@ -'use strict' - -const Event = require('../models/Event') -const sortByProp = require('../utils/sortByProp') +import Event from '../models/Event.js' +import sortByProp from '../utils/sortByProp.js' const response = (entry) => ({ - id: entry.id, - title: entry.title, - type: entry.type, - created: entry.created, - updated: entry.updated, +id: entry.id, +title: entry.title, +type: entry.type, +created: entry.created, +updated: entry.updated, }) const add = async (data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Event.create(data), - ) +return enhance( +await Event.create(data), +) } const all = async () => { - const enhance = (entries) => { - return entries - .map(response) - .sort(sortByProp('title')) - } +const enhance = (entries) => { +return entries +.map(response) +.sort(sortByProp('title')) +} - return enhance( - await Event.find({}), - ) +return enhance( +await Event.find({}), +) } const get = async (id) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Event.findOne({ id }), - ) +return enhance( +await Event.findOne({ id }), +) } const update = async (id, data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Event.findOneAndUpdate({ - id, - }, { - $set: { - title: data.title, - type: data.type, - updated: Date.now(), - }, - }, { - new: true, - }), - ) +return enhance( +await Event.findOneAndUpdate({ +id, +}, { +$set: { +title: data.title, +type: data.type, +updated: Date.now(), +}, +}, { +new: true, +}), +) } const del = (id) => { - return Event.findOneAndDelete({ - id, - }) +return Event.findOneAndDelete({ +id, +}) } -module.exports = { - add, - all, - get, - update, - del, -} \ No newline at end of file +export { +add, +all, +get, +update, +del, +} diff --git a/src/database/facts.js b/src/database/facts.js index 0afcc35ca..a205474e0 100644 --- a/src/database/facts.js +++ b/src/database/facts.js @@ -1,21 +1,17 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateActiveVisitors = require('../aggregations/aggregateActiveVisitors') +import Record from '../models/Record.js' +import aggregateActiveVisitors from '../aggregations/aggregateActiveVisitors.js' const getActiveVisitors = async (ids, dateDetails) => { - const enhance = (entries) => { - const entry = entries[0] - return entry == null ? 0 : entry.count - } +const enhance = (entries) => { +const entry = entries[0] +return entry == null ? 0 : entry.count +} - return enhance( - await Record.aggregate( - aggregateActiveVisitors(ids, dateDetails), - ), - ) +return enhance( +await Record.aggregate( +aggregateActiveVisitors(ids, dateDetails), +), +) } -module.exports = { - getActiveVisitors, -} \ No newline at end of file +export default getActiveVisitors diff --git a/src/database/languages.js b/src/database/languages.js index 885dc9909..bb6da0044 100644 --- a/src/database/languages.js +++ b/src/database/languages.js @@ -1,42 +1,38 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const sortings = require('../constants/sortings') -const languageCodes = require('../utils/languageCodes') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import languageCodes from '../utils/languageCodes.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, range, limit, dateDetails) => { - const aggregation = (() => { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLanguage' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLanguage' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLanguage' ], limit) - })() +const aggregation = (() => { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLanguage' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLanguage' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLanguage' ], limit) +})() - const enhanceId = (id) => { - return languageCodes[id.siteLanguage] || id.siteLanguage - } +const enhanceId = (id) => { +return languageCodes[id.siteLanguage] || id.siteLanguage +} - const enhance = (entries) => { - return entries.map((entry) => { - const value = enhanceId(entry._id) +const enhance = (entries) => { +return entries.map((entry) => { +const value = enhanceId(entry._id) - return { - id: recursiveId([ value, sorting, range, ...ids ]), - value, - count: entry.count, - created: entry.created, - } - }) - } +return { +id: recursiveId([ value, sorting, range, ...ids ]), +value, +count: entry.count, +created: entry.created, +} +}) +} - return enhance( - await Record.aggregate(aggregation), - ) +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/pages.js b/src/database/pages.js index 60053fe8a..3c05c85f3 100644 --- a/src/database/pages.js +++ b/src/database/pages.js @@ -1,41 +1,37 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const sortings = require('../constants/sortings') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, range, limit, dateDetails) => { - const aggregation = (() => { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLocation' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLocation' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLocation' ], limit) - })() +const aggregation = (() => { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLocation' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLocation' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLocation' ], limit) +})() - const enhanceId = (id) => { - return id.siteLocation - } +const enhanceId = (id) => { +return id.siteLocation +} - const enhance = (entries) => { - return entries.map((entry) => { - const value = enhanceId(entry._id) +const enhance = (entries) => { +return entries.map((entry) => { +const value = enhanceId(entry._id) - return { - id: recursiveId([ value, sorting, range, ...ids ]), - value, - count: entry.count, - created: entry.created, - } - }) - } +return { +id: recursiveId([ value, sorting, range, ...ids ]), +value, +count: entry.count, +created: entry.created, +} +}) +} - return enhance( - await Record.aggregate(aggregation), - ) +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/permanentTokens.js b/src/database/permanentTokens.js index 8fef60a2e..87264c4c1 100644 --- a/src/database/permanentTokens.js +++ b/src/database/permanentTokens.js @@ -1,78 +1,76 @@ -'use strict' - -const PermanentToken = require('../models/PermanentToken') -const sortByProp = require('../utils/sortByProp') +import PermanentToken from '../models/PermanentToken.js' +import sortByProp from '../utils/sortByProp.js' const response = (entry) => ({ - id: entry.id, - title: entry.title, - created: entry.created, - updated: entry.updated, +id: entry.id, +title: entry.title, +created: entry.created, +updated: entry.updated, }) const add = async (data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await PermanentToken.create({ - title: data.title, - }), - ) +return enhance( +await PermanentToken.create({ +title: data.title, +}), +) } const all = async () => { - const enhance = (entries) => { - return entries - .map(response) - .sort(sortByProp('title')) - } +const enhance = (entries) => { +return entries +.map(response) +.sort(sortByProp('title')) +} - return enhance( - await PermanentToken.find({}), - ) +return enhance( +await PermanentToken.find({}), +) } const get = async (id) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await PermanentToken.findOne({ id }), - ) +return enhance( +await PermanentToken.findOne({ id }), +) } const update = async (id, data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await PermanentToken.findOneAndUpdate({ - id, - }, { - $set: { - title: data.title, - updated: Date.now(), - }, - }, { - new: true, - }), - ) +return enhance( +await PermanentToken.findOneAndUpdate({ +id, +}, { +$set: { +title: data.title, +updated: Date.now(), +}, +}, { +new: true, +}), +) } const del = (id) => { - return PermanentToken.findOneAndDelete({ - id, - }) +return PermanentToken.findOneAndDelete({ +id, +}) } -module.exports = { - add, - all, - get, - update, - del, -} \ No newline at end of file +export { +add, +all, +get, +update, +del, +} diff --git a/src/database/records.js b/src/database/records.js index e2413e124..47d39cdf7 100644 --- a/src/database/records.js +++ b/src/database/records.js @@ -1,111 +1,109 @@ -'use strict' - -const Record = require('../models/Record') +import Record from '../models/Record.js' const response = (entry) => ({ - id: entry.id, - siteLocation: entry.siteLocation, - siteReferrer: entry.siteReferrer, - siteLanguage: entry.siteLanguage, - source: entry.source, - screenWidth: entry.screenWidth, - screenHeight: entry.screenHeight, - screenColorDepth: entry.screenColorDepth, - deviceName: entry.deviceName, - deviceManufacturer: entry.deviceManufacturer, - osName: entry.osName, - osVersion: entry.osVersion, - browserName: entry.browserName, - browserVersion: entry.browserVersion, - browserWidth: entry.browserWidth, - browserHeight: entry.browserHeight, - created: entry.created, - updated: entry.updated, +id: entry.id, +siteLocation: entry.siteLocation, +siteReferrer: entry.siteReferrer, +siteLanguage: entry.siteLanguage, +source: entry.source, +screenWidth: entry.screenWidth, +screenHeight: entry.screenHeight, +screenColorDepth: entry.screenColorDepth, +deviceName: entry.deviceName, +deviceManufacturer: entry.deviceManufacturer, +osName: entry.osName, +osVersion: entry.osVersion, +browserName: entry.browserName, +browserVersion: entry.browserVersion, +browserWidth: entry.browserWidth, +browserHeight: entry.browserHeight, +created: entry.created, +updated: entry.updated, }) const add = async (data) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Record.create({ - clientId: data.clientId, - domainId: data.domainId, - siteLocation: data.siteLocation, - siteReferrer: data.siteReferrer, - siteLanguage: data.siteLanguage, - source: data.source, - screenWidth: data.screenWidth, - screenHeight: data.screenHeight, - screenColorDepth: data.screenColorDepth, - deviceName: data.deviceName, - deviceManufacturer: data.deviceManufacturer, - osName: data.osName, - osVersion: data.osVersion, - browserName: data.browserName, - browserVersion: data.browserVersion, - browserWidth: data.browserWidth, - browserHeight: data.browserHeight, - }), - ) +return enhance( +await Record.create({ +clientId: data.clientId, +domainId: data.domainId, +siteLocation: data.siteLocation, +siteReferrer: data.siteReferrer, +siteLanguage: data.siteLanguage, +source: data.source, +screenWidth: data.screenWidth, +screenHeight: data.screenHeight, +screenColorDepth: data.screenColorDepth, +deviceName: data.deviceName, +deviceManufacturer: data.deviceManufacturer, +osName: data.osName, +osVersion: data.osVersion, +browserName: data.browserName, +browserVersion: data.browserVersion, +browserWidth: data.browserWidth, +browserHeight: data.browserHeight, +}), +) } const update = async (id) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Record.findOneAndUpdate({ - id, - }, { - $set: { - updated: Date.now(), - }, - }, { - new: true, - }), - ) +return enhance( +await Record.findOneAndUpdate({ +id, +}, { +$set: { +updated: Date.now(), +}, +}, { +new: true, +}), +) } const anonymize = (clientId, ignoreId) => { - // Don't return anything about the update - return Record.updateMany({ - $and: [ - { clientId }, - { - id: { - $ne: ignoreId, - }, - }, - ], - }, { - clientId: null, - siteLanguage: null, - screenWidth: null, - screenHeight: null, - screenColorDepth: null, - deviceName: null, - deviceManufacturer: null, - osName: null, - osVersion: null, - browserName: null, - browserVersion: null, - browserWidth: null, - browserHeight: null, - }) +// Don't return anything about the update +return Record.updateMany({ +$and: [ +{ clientId }, +{ +id: { +$ne: ignoreId, +}, +}, +], +}, { +clientId: null, +siteLanguage: null, +screenWidth: null, +screenHeight: null, +screenColorDepth: null, +deviceName: null, +deviceManufacturer: null, +osName: null, +osVersion: null, +browserName: null, +browserVersion: null, +browserWidth: null, +browserHeight: null, +}) } const del = (domainId) => { - return Record.deleteMany({ - domainId, - }) +return Record.deleteMany({ +domainId, +}) } -module.exports = { - add, - update, - anonymize, - del, -} \ No newline at end of file +export { +add, +update, +anonymize, +del, +} diff --git a/src/database/referrers.js b/src/database/referrers.js index 97335fcec..f363f9441 100644 --- a/src/database/referrers.js +++ b/src/database/referrers.js @@ -1,54 +1,50 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const sortings = require('../constants/sortings') -const constants = require('../constants/referrers') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import { REFERRERS_TYPE_WITH_SOURCE, REFERRERS_TYPE_NO_SOURCE, REFERRERS_TYPE_ONLY_SOURCE } from '../constants/referrers.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { - const aggregation = (() => { - if (type === constants.REFERRERS_TYPE_WITH_SOURCE) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source', 'siteReferrer' ], range, limit, dateDetails, true) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source', 'siteReferrer' ], limit, true) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source', 'siteReferrer' ], limit, true) - } - if (type === constants.REFERRERS_TYPE_NO_SOURCE) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteReferrer' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteReferrer' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteReferrer' ], limit) - } - if (type === constants.REFERRERS_TYPE_ONLY_SOURCE) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source' ], limit) - } - })() +const aggregation = (() => { +if (type === REFERRERS_TYPE_WITH_SOURCE) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source', 'siteReferrer' ], range, limit, dateDetails, true) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source', 'siteReferrer' ], limit, true) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source', 'siteReferrer' ], limit, true) +} +if (type === REFERRERS_TYPE_NO_SOURCE) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteReferrer' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteReferrer' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteReferrer' ], limit) +} +if (type === REFERRERS_TYPE_ONLY_SOURCE) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source' ], limit) +} +})() - const enhanceId = (id) => { - return id.source || id.siteReferrer - } +const enhanceId = (id) => { +return id.source || id.siteReferrer +} - const enhance = (entries) => { - return entries.map((entry) => { - const value = enhanceId(entry._id) +const enhance = (entries) => { +return entries.map((entry) => { +const value = enhanceId(entry._id) - return { - id: recursiveId([ value, sorting, type, range, ...ids ]), - value, - count: entry.count, - created: entry.created, - } - }) - } +return { +id: recursiveId([ value, sorting, type, range, ...ids ]), +value, +count: entry.count, +created: entry.created, +} +}) +} - return enhance( - await Record.aggregate(aggregation), - ) +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/sizes.js b/src/database/sizes.js index e0f5fe089..f8c801af6 100644 --- a/src/database/sizes.js +++ b/src/database/sizes.js @@ -1,68 +1,71 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const sortings = require('../constants/sortings') -const constants = require('../constants/sizes') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import { +SIZES_TYPE_BROWSER_HEIGHT, +SIZES_TYPE_BROWSER_RESOLUTION, +SIZES_TYPE_BROWSER_WIDTH, +SIZES_TYPE_SCREEN_HEIGHT, +SIZES_TYPE_SCREEN_RESOLUTION, +SIZES_TYPE_SCREEN_WIDTH, +} from '../constants/sizes.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { - const aggregation = (() => { - if (sorting === sortings.SORTINGS_TOP) { - if (type === constants.SIZES_TYPE_BROWSER_WIDTH) return aggregateTopRecords(ids, [ 'browserWidth' ], range, limit, dateDetails) - if (type === constants.SIZES_TYPE_BROWSER_HEIGHT) return aggregateTopRecords(ids, [ 'browserHeight' ], range, limit, dateDetails) - if (type === constants.SIZES_TYPE_BROWSER_RESOLUTION) return aggregateTopRecords(ids, [ 'browserWidth', 'browserHeight' ], range, limit, dateDetails) - if (type === constants.SIZES_TYPE_SCREEN_WIDTH) return aggregateTopRecords(ids, [ 'screenWidth' ], range, limit, dateDetails) - if (type === constants.SIZES_TYPE_SCREEN_HEIGHT) return aggregateTopRecords(ids, [ 'screenHeight' ], range, limit, dateDetails) - if (type === constants.SIZES_TYPE_SCREEN_RESOLUTION) return aggregateTopRecords(ids, [ 'screenWidth', 'screenHeight' ], range, limit, dateDetails) - } - if (sorting === sortings.SORTINGS_NEW) { - if (type === constants.SIZES_TYPE_BROWSER_WIDTH) return aggregateNewRecords(ids, [ 'browserWidth' ], limit) - if (type === constants.SIZES_TYPE_BROWSER_HEIGHT) return aggregateNewRecords(ids, [ 'browserHeight' ], limit) - if (type === constants.SIZES_TYPE_BROWSER_RESOLUTION) return aggregateNewRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) - if (type === constants.SIZES_TYPE_SCREEN_WIDTH) return aggregateNewRecords(ids, [ 'screenWidth' ], limit) - if (type === constants.SIZES_TYPE_SCREEN_HEIGHT) return aggregateNewRecords(ids, [ 'screenHeight' ], limit) - if (type === constants.SIZES_TYPE_SCREEN_RESOLUTION) return aggregateNewRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) - } - if (sorting === sortings.SORTINGS_RECENT) { - if (type === constants.SIZES_TYPE_BROWSER_WIDTH) return aggregateRecentRecords(ids, [ 'browserWidth' ], limit) - if (type === constants.SIZES_TYPE_BROWSER_HEIGHT) return aggregateRecentRecords(ids, [ 'browserHeight' ], limit) - if (type === constants.SIZES_TYPE_BROWSER_RESOLUTION) return aggregateRecentRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) - if (type === constants.SIZES_TYPE_SCREEN_WIDTH) return aggregateRecentRecords(ids, [ 'screenWidth' ], limit) - if (type === constants.SIZES_TYPE_SCREEN_HEIGHT) return aggregateRecentRecords(ids, [ 'screenHeight' ], limit) - if (type === constants.SIZES_TYPE_SCREEN_RESOLUTION) return aggregateRecentRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) - } - })() +const aggregation = (() => { +if (sorting === SORTINGS_TOP) { +if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateTopRecords(ids, [ 'browserWidth' ], range, limit, dateDetails) +if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateTopRecords(ids, [ 'browserHeight' ], range, limit, dateDetails) +if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateTopRecords(ids, [ 'browserWidth', 'browserHeight' ], range, limit, dateDetails) +if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateTopRecords(ids, [ 'screenWidth' ], range, limit, dateDetails) +if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateTopRecords(ids, [ 'screenHeight' ], range, limit, dateDetails) +if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateTopRecords(ids, [ 'screenWidth', 'screenHeight' ], range, limit, dateDetails) +} +if (sorting === SORTINGS_NEW) { +if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateNewRecords(ids, [ 'browserWidth' ], limit) +if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateNewRecords(ids, [ 'browserHeight' ], limit) +if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateNewRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) +if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateNewRecords(ids, [ 'screenWidth' ], limit) +if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateNewRecords(ids, [ 'screenHeight' ], limit) +if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateNewRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) +} +if (sorting === SORTINGS_RECENT) { +if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateRecentRecords(ids, [ 'browserWidth' ], limit) +if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateRecentRecords(ids, [ 'browserHeight' ], limit) +if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateRecentRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) +if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateRecentRecords(ids, [ 'screenWidth' ], limit) +if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateRecentRecords(ids, [ 'screenHeight' ], limit) +if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateRecentRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) +} +})() - const enhanceId = (id) => { - if (type === constants.SIZES_TYPE_BROWSER_WIDTH) return `${ id.browserWidth }px` - if (type === constants.SIZES_TYPE_BROWSER_HEIGHT) return `${ id.browserHeight }px` - if (type === constants.SIZES_TYPE_BROWSER_RESOLUTION) return `${ id.browserWidth }px x ${ id.browserHeight }px` - if (type === constants.SIZES_TYPE_SCREEN_WIDTH) return `${ id.screenWidth }px` - if (type === constants.SIZES_TYPE_SCREEN_HEIGHT) return `${ id.screenHeight }px` - if (type === constants.SIZES_TYPE_SCREEN_RESOLUTION) return `${ id.screenWidth }px x ${ id.screenHeight }px` - } +const enhanceId = (id) => { +if (type === SIZES_TYPE_BROWSER_WIDTH) return `${ id.browserWidth }px` +if (type === SIZES_TYPE_BROWSER_HEIGHT) return `${ id.browserHeight }px` +if (type === SIZES_TYPE_BROWSER_RESOLUTION) return `${ id.browserWidth }px x ${ id.browserHeight }px` +if (type === SIZES_TYPE_SCREEN_WIDTH) return `${ id.screenWidth }px` +if (type === SIZES_TYPE_SCREEN_HEIGHT) return `${ id.screenHeight }px` +if (type === SIZES_TYPE_SCREEN_RESOLUTION) return `${ id.screenWidth }px x ${ id.screenHeight }px` +} - const enhance = (entries) => { - return entries.map((entry) => { - const value = enhanceId(entry._id) +const enhance = (entries) => { +return entries.map((entry) => { +const value = enhanceId(entry._id) - return { - id: recursiveId([ value, sorting, type, range, ...ids ]), - value, - count: entry.count, - created: entry.created, - } - }) - } +return { +id: recursiveId([ value, sorting, type, range, ...ids ]), +value, +count: entry.count, +created: entry.created, +} +}) +} - return enhance( - await Record.aggregate(aggregation), - ) +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/systems.js b/src/database/systems.js index 6b1be4b24..303768342 100644 --- a/src/database/systems.js +++ b/src/database/systems.js @@ -1,50 +1,46 @@ -'use strict' - -const Record = require('../models/Record') -const aggregateTopRecords = require('../aggregations/aggregateTopRecords') -const aggregateNewRecords = require('../aggregations/aggregateNewRecords') -const aggregateRecentRecords = require('../aggregations/aggregateRecentRecords') -const sortings = require('../constants/sortings') -const constants = require('../constants/systems') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateTopRecords from '../aggregations/aggregateTopRecords.js' +import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' +import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' +import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' +import { SYSTEMS_TYPE_NO_VERSION, SYSTEMS_TYPE_WITH_VERSION } from '../constants/systems.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { - const aggregation = (() => { - if (type === constants.SYSTEMS_TYPE_NO_VERSION) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName' ], limit) - } - if (type === constants.SYSTEMS_TYPE_WITH_VERSION) { - if (sorting === sortings.SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName', 'osVersion' ], range, limit, dateDetails) - if (sorting === sortings.SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName', 'osVersion' ], limit) - if (sorting === sortings.SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName', 'osVersion' ], limit) - } - })() +const aggregation = (() => { +if (type === SYSTEMS_TYPE_NO_VERSION) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName' ], limit) +} +if (type === SYSTEMS_TYPE_WITH_VERSION) { +if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName', 'osVersion' ], range, limit, dateDetails) +if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName', 'osVersion' ], limit) +if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName', 'osVersion' ], limit) +} +})() - const enhanceId = (id) => { - if (type === constants.SYSTEMS_TYPE_NO_VERSION) return `${ id.osName }` - if (type === constants.SYSTEMS_TYPE_WITH_VERSION) return `${ id.osName } ${ id.osVersion }` - } +const enhanceId = (id) => { +if (type === SYSTEMS_TYPE_NO_VERSION) return `${ id.osName }` +if (type === SYSTEMS_TYPE_WITH_VERSION) return `${ id.osName } ${ id.osVersion }` +} - const enhance = (entries) => { - return entries.map((entry) => { - const value = enhanceId(entry._id) +const enhance = (entries) => { +return entries.map((entry) => { +const value = enhanceId(entry._id) - return { - id: recursiveId([ value, sorting, type, range, ...ids ]), - value, - count: entry.count, - created: entry.created, - } - }) - } +return { +id: recursiveId([ value, sorting, type, range, ...ids ]), +value, +count: entry.count, +created: entry.created, +} +}) +} - return enhance( - await Record.aggregate(aggregation), - ) +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/database/tokens.js b/src/database/tokens.js index b6b2e8dea..0caafdeb9 100644 --- a/src/database/tokens.js +++ b/src/database/tokens.js @@ -1,60 +1,58 @@ -'use strict' - -const Token = require('../models/Token') +import Token from '../models/Token.js' const response = (entry) => ({ - id: entry.id, - created: entry.created, - updated: entry.updated, +id: entry.id, +created: entry.created, +updated: entry.updated, }) const add = async () => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Token.create({}), - ) +return enhance( +await Token.create({}), +) } const get = async (id) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} - return enhance( - await Token.findOne({ id }), - ) +return enhance( +await Token.findOne({ id }), +) } const update = async (id) => { - const enhance = (entry) => { - return entry == null ? entry : response(entry) - } - - return enhance( - await Token.findOneAndUpdate({ - id, - }, { - $set: { - updated: Date.now(), - }, - }, { - new: true, - }), - ) +const enhance = (entry) => { +return entry == null ? entry : response(entry) +} + +return enhance( +await Token.findOneAndUpdate({ +id, +}, { +$set: { +updated: Date.now(), +}, +}, { +new: true, +}), +) } const del = (id) => { - return Token.findOneAndDelete({ - id, - }) +return Token.findOneAndDelete({ +id, +}) } -module.exports = { - add, - get, - update, - del, -} \ No newline at end of file +export { +add, +get, +update, +del, +} diff --git a/src/database/views.js b/src/database/views.js index bd6292c81..c97d449eb 100644 --- a/src/database/views.js +++ b/src/database/views.js @@ -1,63 +1,60 @@ -'use strict' +import dateFnsTz from 'date-fns-tz' +const { utcToZonedTime } = dateFnsTz -const { utcToZonedTime } = require('date-fns-tz') - -const Record = require('../models/Record') -const aggregateViews = require('../aggregations/aggregateViews') -const constants = require('../constants/views') -const intervals = require('../constants/intervals') -const createArray = require('../utils/createArray') -const matchesDate = require('../utils/matchesDate') -const recursiveId = require('../utils/recursiveId') +import Record from '../models/Record.js' +import aggregateViews from '../aggregations/aggregateViews.js' +import { VIEWS_TYPE_UNIQUE, VIEWS_TYPE_TOTAL } from '../constants/views.js' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import createArray from '../utils/createArray.js' +import matchesDate from '../utils/matchesDate.js' +import recursiveId from '../utils/recursiveId.js' const get = async (ids, type, interval, limit, dateDetails) => { - const aggregation = (() => { - if (type === constants.VIEWS_TYPE_UNIQUE) return aggregateViews(ids, true, interval, limit, dateDetails) - if (type === constants.VIEWS_TYPE_TOTAL) return aggregateViews(ids, false, interval, limit, dateDetails) - })() - - const enhance = (entries) => { - const matchDay = [ intervals.INTERVALS_DAILY ].includes(interval) - const matchMonth = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY ].includes(interval) - const matchYear = [ intervals.INTERVALS_DAILY, intervals.INTERVALS_MONTHLY, intervals.INTERVALS_YEARLY ].includes(interval) - - return createArray(limit).map((_, index) => { - const date = dateDetails.lastFnByInterval(interval)(index) - - // Database entries include the day, month and year in the - // timezone of the user. We therefore need to match it against a - // date in the timezone of the user. - const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) - - // Find a entry that matches the date - const entry = entries.find((entry) => { - return matchesDate( - matchDay === true ? entry._id.day : undefined, - matchMonth === true ? entry._id.month : undefined, - matchYear === true ? entry._id.year : undefined, - userZonedDate, - ) - }) - - const value = (() => { - if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` - if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` - if (matchYear === true) return `${ date.getFullYear() }` - })() - - return { - id: recursiveId([ value, ...ids ]), - value, - count: entry == null ? 0 : entry.count, - } - }) - } - - return enhance( - await Record.aggregate(aggregation), - ) +const aggregation = (() => { +if (type === VIEWS_TYPE_UNIQUE) return aggregateViews(ids, true, interval, limit, dateDetails) +if (type === VIEWS_TYPE_TOTAL) return aggregateViews(ids, false, interval, limit, dateDetails) +})() + +const enhance = (entries) => { +const matchDay = [ INTERVALS_DAILY ].includes(interval) +const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) +const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) + +return createArray(limit).map((_, index) => { +const date = dateDetails.lastFnByInterval(interval)(index) + +// Database entries include the day, month and year in the +// timezone of the user. We therefore need to match it against a +// date in the timezone of the user. +const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) + +// Find a entry that matches the date +const entry = entries.find((entry) => { +return matchesDate( +matchDay === true ? entry._id.day : undefined, +matchMonth === true ? entry._id.month : undefined, +matchYear === true ? entry._id.year : undefined, +userZonedDate, +) +}) + +const value = (() => { +if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` +if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` +if (matchYear === true) return `${ date.getFullYear() }` +})() + +return { +id: recursiveId([ value, ...ids ]), +value, +count: entry == null ? 0 : entry.count, +} +}) +} + +return enhance( +await Record.aggregate(aggregation), +) } -module.exports = { - get, -} \ No newline at end of file +export default get diff --git a/src/healthcheck.js b/src/healthcheck.js index 8b74e713f..f0a7d683a 100755 --- a/src/healthcheck.js +++ b/src/healthcheck.js @@ -1,50 +1,49 @@ #!/usr/bin/env node -'use strict' -require('dotenv').config() +import 'dotenv/config' -const signale = require('./utils/signale') -const config = require('./utils/config') -const checkMongoDB = require('./utils/connect') +import signale from './utils/signale.js' +import config from './utils/config.js' +import connect from './utils/connect.js' if (config.dbUrl == null) { - signale.fatal('MongoDB connection URI missing in environment') - process.exit(1) +signale.fatal('MongoDB connection URI missing in environment') +process.exit(1) } const checkServer = async (url) => { - const response = await fetch(url) +const response = await fetch(url) - if (response.ok === false) { - throw new Error(`Server is unhealthy and returned with the status '${ response.status }'`) - } +if (response.ok === false) { +throw new Error(`Server is unhealthy and returned with the status '${ response.status }'`) +} } const checkApi = async (url) => { - const response = await fetch(url) +const response = await fetch(url) - if (response.ok === false) { - throw new Error(`API is unhealthy and returned with the status '${ response.status }'`) - } +if (response.ok === false) { +throw new Error(`API is unhealthy and returned with the status '${ response.status }'`) +} } const exit = (healthy) => process.exit(healthy === true ? 0 : 1) const check = () => Promise.all([ - checkMongoDB(config.dbUrl), - checkServer(`http://localhost:${ config.port }`), - checkApi(`http://localhost:${ config.port }/.well-known/apollo/server-health`), +connect(config.dbUrl), +checkServer(`http://localhost:${ config.port }`), +checkApi(`http://localhost:${ config.port }/.well-known/apollo/server-health`), ]) const handleSuccess = () => { - signale.success('Ackee is up and running') - exit(true) +signale.success('Ackee is up and running') +exit(true) } const handleFailure = (error) => { - signale.fatal(error) - exit(false) +signale.fatal(error) +exit(false) } check() - .then(handleSuccess) - .catch(handleFailure) \ No newline at end of file +.then(handleSuccess) +.catch(handleFailure) diff --git a/src/index.js b/src/index.js index 46ccd08a1..0ed87ab12 100644 --- a/src/index.js +++ b/src/index.js @@ -1,16 +1,15 @@ #!/usr/bin/env node -'use strict' -require('dotenv').config() +import 'dotenv/config' -const server = require('./server') -const signale = require('./utils/signale') -const config = require('./utils/config') -const connect = require('./utils/connect') -const stripUrlAuth = require('./utils/stripUrlAuth') +import server from './server.js' +import signale from './utils/signale.js' +import config from './utils/config.js' +import connect from './utils/connect.js' +import stripUrlAuth from './utils/stripUrlAuth.js' if (config.dbUrl == null) { - signale.fatal('MongoDB connection URI missing in environment') - process.exit(1) +signale.fatal('MongoDB connection URI missing in environment') +process.exit(1) } server.on('listening', () => signale.watch(`Listening on http://localhost:${ config.port }`)) @@ -19,20 +18,20 @@ server.on('error', (error) => signale.fatal(error)) signale.await(`Connecting to ${ stripUrlAuth(config.dbUrl) }`) connect(config.dbUrl).then(() => { - signale.success(`Connected to ${ stripUrlAuth(config.dbUrl) }`) - signale.start(`Starting the server`) +signale.success(`Connected to ${ stripUrlAuth(config.dbUrl) }`) +signale.start(`Starting the server`) - server.listen(config.port) +server.listen(config.port) - if (config.isDevelopmentMode === true) { - signale.info('Development mode enabled') - } +if (config.isDevelopmentMode === true) { +signale.info('Development mode enabled') +} - if (config.isDemoMode === true) { - signale.info('Demo mode enabled') - } +if (config.isDemoMode === true) { +signale.info('Demo mode enabled') +} +}) +.catch((error) => { +signale.fatal(error) +process.exit(1) }) - .catch((error) => { - signale.fatal(error) - process.exit(1) - }) \ No newline at end of file diff --git a/src/middlewares/blockDemoMode.js b/src/middlewares/blockDemoMode.js index 747ac8dc7..327dda0fa 100644 --- a/src/middlewares/blockDemoMode.js +++ b/src/middlewares/blockDemoMode.js @@ -1,8 +1,6 @@ -'use strict' +import KnownError from '../utils/KnownError.js' -const KnownError = require('../utils/KnownError') - -module.exports = (parent, args, { isDemoMode }) => { +export default (parent, args, { isDemoMode }) => { if (isDemoMode === true) { throw new KnownError('Forbidden in demo mode') } diff --git a/src/middlewares/requireAuth.js b/src/middlewares/requireAuth.js index 8bf1939a8..33ff01c04 100644 --- a/src/middlewares/requireAuth.js +++ b/src/middlewares/requireAuth.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (parent, args, { isAuthenticated }) => { +export default (parent, args, { isAuthenticated }) => { if (isAuthenticated !== true) { throw isAuthenticated } diff --git a/src/models/Action.js b/src/models/Action.js index 72b7c5478..9dc696768 100644 --- a/src/models/Action.js +++ b/src/models/Action.js @@ -1,7 +1,5 @@ -'use strict' - -const mongoose = require('mongoose') -const uuid = require('crypto').randomUUID +import mongoose from 'mongoose' +import { randomUUID as uuid } from 'crypto' const schema = new mongoose.Schema({ id: { @@ -39,4 +37,4 @@ const schema = new mongoose.Schema({ }, }) -module.exports = mongoose.model('Action', schema) \ No newline at end of file +export default mongoose.model('Action', schema) \ No newline at end of file diff --git a/src/models/Domain.js b/src/models/Domain.js index 1d53ccf33..796023da4 100644 --- a/src/models/Domain.js +++ b/src/models/Domain.js @@ -1,7 +1,5 @@ -'use strict' - -const mongoose = require('mongoose') -const uuid = require('crypto').randomUUID +import mongoose from 'mongoose' +import { randomUUID as uuid } from 'crypto' const schema = new mongoose.Schema({ id: { @@ -26,4 +24,4 @@ const schema = new mongoose.Schema({ }, }) -module.exports = mongoose.model('Domain', schema) \ No newline at end of file +export default mongoose.model('Domain', schema) \ No newline at end of file diff --git a/src/models/Event.js b/src/models/Event.js index 9406e749d..1245fcf9e 100644 --- a/src/models/Event.js +++ b/src/models/Event.js @@ -1,15 +1,13 @@ -'use strict' +import mongoose from 'mongoose' +import { randomUUID as uuid } from 'crypto' -const mongoose = require('mongoose') -const uuid = require('crypto').randomUUID - -const events = require('../constants/events') +import { EVENTS_TYPE_TOTAL_CHART, EVENTS_TYPE_AVERAGE_CHART, EVENTS_TYPE_TOTAL_LIST, EVENTS_TYPE_AVERAGE_LIST } from '../constants/events.js' const isKnownType = (value) => [ - events.EVENTS_TYPE_TOTAL_CHART, - events.EVENTS_TYPE_AVERAGE_CHART, - events.EVENTS_TYPE_TOTAL_LIST, - events.EVENTS_TYPE_AVERAGE_LIST, + EVENTS_TYPE_TOTAL_CHART, + EVENTS_TYPE_AVERAGE_CHART, + EVENTS_TYPE_TOTAL_LIST, + EVENTS_TYPE_AVERAGE_LIST, ].includes(value) const schema = new mongoose.Schema({ @@ -40,4 +38,4 @@ const schema = new mongoose.Schema({ }, }) -module.exports = mongoose.model('Event', schema) \ No newline at end of file +export default mongoose.model('Event', schema) \ No newline at end of file diff --git a/src/models/PermanentToken.js b/src/models/PermanentToken.js index 619bc9789..5d00e06f3 100644 --- a/src/models/PermanentToken.js +++ b/src/models/PermanentToken.js @@ -1,7 +1,5 @@ -'use strict' - -const mongoose = require('mongoose') -const uuid = require('crypto').randomUUID +import mongoose from 'mongoose' +import { randomUUID as uuid } from 'crypto' const schema = new mongoose.Schema({ id: { @@ -26,4 +24,4 @@ const schema = new mongoose.Schema({ }, }) -module.exports = mongoose.model('PermanentToken', schema) \ No newline at end of file +export default mongoose.model('PermanentToken', schema) \ No newline at end of file diff --git a/src/models/Record.js b/src/models/Record.js index 2c6a32633..488135219 100644 --- a/src/models/Record.js +++ b/src/models/Record.js @@ -1,8 +1,6 @@ -'use strict' - -const mongoose = require('mongoose') -const uuid = require('crypto').randomUUID -const isUrl = require('is-url') +import mongoose from 'mongoose' +import { randomUUID as uuid } from 'crypto' +import isUrl from 'is-url' const isNullOrUrl = (value) => value == null || isUrl(value) @@ -96,4 +94,4 @@ const schema = new mongoose.Schema({ }, }) -module.exports = mongoose.model('Record', schema) \ No newline at end of file +export default mongoose.model('Record', schema) \ No newline at end of file diff --git a/src/models/Token.js b/src/models/Token.js index d64198560..c44727b9e 100644 --- a/src/models/Token.js +++ b/src/models/Token.js @@ -1,7 +1,5 @@ -'use strict' - -const mongoose = require('mongoose') -const uuid = require('crypto').randomUUID +import mongoose from 'mongoose' +import { randomUUID as uuid } from 'crypto' const schema = new mongoose.Schema({ id: { @@ -22,4 +20,4 @@ const schema = new mongoose.Schema({ }, }) -module.exports = mongoose.model('Token', schema) \ No newline at end of file +export default mongoose.model('Token', schema) \ No newline at end of file diff --git a/src/resolvers/actions.js b/src/resolvers/actions.js index a88f2ed83..6cdf08fdb 100644 --- a/src/resolvers/actions.js +++ b/src/resolvers/actions.js @@ -1,84 +1,82 @@ -'use strict' - -const KnownError = require('../utils/KnownError') -const messages = require('../utils/messages') -const events = require('../database/events') -const actions = require('../database/actions') +import KnownError from '../utils/KnownError.js' +import messages from '../utils/messages.js' +import * as events from '../database/events.js' +import * as actions from '../database/actions.js' const polish = (obj) => { - return Object.entries(obj).reduce((acc, [ key, value ]) => { - value = typeof value === 'string' ? value.trim() : value - value = value == null ? undefined : value - value = value === '' ? undefined : value - - acc[key] = value - return acc - }, {}) +return Object.entries(obj).reduce((acc, [ key, value ]) => { +value = typeof value === 'string' ? value.trim() : value +value = value == null ? undefined : value +value = value === '' ? undefined : value + +acc[key] = value +return acc +}, {}) } -module.exports = { - Mutation: { - createAction: async (parent, { eventId, input }, { isIgnored }) => { - // Ignore your own actions when logged in - if (isIgnored === true) { - return { - success: true, - payload: { - id: '88888888-8888-8888-8888-888888888888', - }, - } - } +export default { +Mutation: { +createAction: async (parent, { eventId, input }, { isIgnored }) => { +// Ignore your own actions when logged in +if (isIgnored === true) { +return { +success: true, +payload: { +id: '88888888-8888-8888-8888-888888888888', +}, +} +} - const data = polish({ ...input, eventId }) +const data = polish({ ...input, eventId }) - const event = await events.get(eventId) +const event = await events.get(eventId) - if (event == null) throw new KnownError('Unknown event') +if (event == null) throw new KnownError('Unknown event') - let entry +let entry - try { - entry = await actions.add(data) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +try { +entry = await actions.add(data) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - throw error - } +throw error +} - return { - success: true, - payload: entry, - } - }, - updateAction: async (parent, { id, input }, { isIgnored }) => { - // Ignore your own actions when logged in - if (isIgnored === true) { - return { - success: true, - } - } +return { +success: true, +payload: entry, +} +}, +updateAction: async (parent, { id, input }, { isIgnored }) => { +// Ignore your own actions when logged in +if (isIgnored === true) { +return { +success: true, +} +} - let entry +let entry - try { - entry = await actions.update(id, input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +try { +entry = await actions.update(id, input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - throw error - } +throw error +} - if (entry == null) { - throw new KnownError('Unknown action') - } +if (entry == null) { +throw new KnownError('Unknown action') +} - return { - success: true, - } - }, - }, -} \ No newline at end of file +return { +success: true, +} +}, +}, +} diff --git a/src/resolvers/domainStatistics.js b/src/resolvers/domainStatistics.js index 260a0fd21..6021c4d3b 100644 --- a/src/resolvers/domainStatistics.js +++ b/src/resolvers/domainStatistics.js @@ -1,67 +1,65 @@ -'use strict' +import getViews from '../database/views.js' +import getPages from '../database/pages.js' +import getReferrers from '../database/referrers.js' +import getDurations from '../database/durations.js' +import getSystems from '../database/systems.js' +import getDevices from '../database/devices.js' +import getBrowsers from '../database/browsers.js' +import getSizes from '../database/sizes.js' +import getLanguages from '../database/languages.js' +import pipe from '../utils/pipe.js' +import domainIds from '../utils/domainIds.js' +import recursiveId from '../utils/recursiveId.js' +import requireAuth from '../middlewares/requireAuth.js' -const views = require('../database/views') -const pages = require('../database/pages') -const referrers = require('../database/referrers') -const durations = require('../database/durations') -const systems = require('../database/systems') -const devices = require('../database/devices') -const browsers = require('../database/browsers') -const sizes = require('../database/sizes') -const languages = require('../database/languages') -const pipe = require('../utils/pipe') -const domainIds = require('../utils/domainIds') -const recursiveId = require('../utils/recursiveId') -const requireAuth = require('../middlewares/requireAuth') +export default { +DomainStatistics: { +id: pipe(requireAuth, async (domain) => { +const ids = await domainIds(domain) -module.exports = { - DomainStatistics: { - id: pipe(requireAuth, async (domain) => { - const ids = await domainIds(domain) +// Provide a static fallback id when there're no domains to create a recursive id from +if (ids.length === 0) return 'eaf55ae8-29b8-448f-b45c-85e17fbfc8ba' - // Provide a static fallback id when there're no domains to create a recursive id from - if (ids.length === 0) return 'eaf55ae8-29b8-448f-b45c-85e17fbfc8ba' - - return recursiveId(ids) - }), - views: pipe(requireAuth, async (domain, { type, interval, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return views.get(ids, type, interval, limit, dateDetails) - }), - pages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return pages.get(ids, sorting, range, limit, dateDetails) - }), - referrers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return referrers.get(ids, sorting, type, range, limit, dateDetails) - }), - durations: pipe(requireAuth, async (domain, { interval, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return durations.get(ids, interval, limit, dateDetails) - }), - systems: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return systems.get(ids, sorting, type, range, limit, dateDetails) - }), - devices: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return devices.get(ids, sorting, type, range, limit, dateDetails) - }), - browsers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return browsers.get(ids, sorting, type, range, limit, dateDetails) - }), - sizes: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return sizes.get(ids, sorting, type, range, limit, dateDetails) - }), - languages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { - const ids = await domainIds(domain) - return languages.get(ids, sorting, range, limit, dateDetails) - }), - }, - Query: { - statistics: () => ({}), - }, -} \ No newline at end of file +return recursiveId(ids) +}), +views: pipe(requireAuth, async (domain, { type, interval, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getViews(ids, type, interval, limit, dateDetails) +}), +pages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getPages(ids, sorting, range, limit, dateDetails) +}), +referrers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getReferrers(ids, sorting, type, range, limit, dateDetails) +}), +durations: pipe(requireAuth, async (domain, { interval, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getDurations(ids, interval, limit, dateDetails) +}), +systems: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getSystems(ids, sorting, type, range, limit, dateDetails) +}), +devices: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getDevices(ids, sorting, type, range, limit, dateDetails) +}), +browsers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getBrowsers(ids, sorting, type, range, limit, dateDetails) +}), +sizes: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getSizes(ids, sorting, type, range, limit, dateDetails) +}), +languages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { +const ids = await domainIds(domain) +return getLanguages(ids, sorting, range, limit, dateDetails) +}), +}, +Query: { +statistics: () => ({}), +}, +} diff --git a/src/resolvers/domains.js b/src/resolvers/domains.js index 9eea9e9f6..40013da86 100644 --- a/src/resolvers/domains.js +++ b/src/resolvers/domains.js @@ -1,74 +1,72 @@ -'use strict' +import * as records from '../database/records.js' +import * as domains from '../database/domains.js' +import KnownError from '../utils/KnownError.js' +import messages from '../utils/messages.js' +import pipe from '../utils/pipe.js' +import requireAuth from '../middlewares/requireAuth.js' +import blockDemoMode from '../middlewares/blockDemoMode.js' -const records = require('../database/records') -const domains = require('../database/domains') -const KnownError = require('../utils/KnownError') -const messages = require('../utils/messages') -const pipe = require('../utils/pipe') -const requireAuth = require('../middlewares/requireAuth') -const blockDemoMode = require('../middlewares/blockDemoMode') +export default { +Domain: { +facts: (parent) => parent, +statistics: (parent) => parent, +}, +Query: { +domain: pipe(requireAuth, (parent, { id }) => { +return domains.get(id) +}), +domains: pipe(requireAuth, () => { +return domains.all() +}), +}, +Mutation: { +createDomain: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { +let entry -module.exports = { - Domain: { - facts: (parent) => parent, - statistics: (parent) => parent, - }, - Query: { - domain: pipe(requireAuth, (parent, { id }) => { - return domains.get(id) - }), - domains: pipe(requireAuth, () => { - return domains.all() - }), - }, - Mutation: { - createDomain: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { - let entry +try { +entry = await domains.add(input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - try { - entry = await domains.add(input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +throw error +} - throw error - } +return { +payload: entry, +success: true, +} +}), +updateDomain: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { +let entry - return { - payload: entry, - success: true, - } - }), - updateDomain: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { - let entry +try { +entry = await domains.update(id, input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - try { - entry = await domains.update(id, input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +throw error +} - throw error - } +if (entry == null) { +throw new KnownError('Unknown domain') +} - if (entry == null) { - throw new KnownError('Unknown domain') - } +return { +payload: entry, +success: true, +} +}), +deleteDomain: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { +await records.del(id) +await domains.del(id) - return { - payload: entry, - success: true, - } - }), - deleteDomain: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { - await records.del(id) - await domains.del(id) - - return { - success: true, - } - }), - }, -} \ No newline at end of file +return { +success: true, +} +}), +}, +} diff --git a/src/resolvers/eventStatistics.js b/src/resolvers/eventStatistics.js index 313a71b01..de98587b9 100644 --- a/src/resolvers/eventStatistics.js +++ b/src/resolvers/eventStatistics.js @@ -1,21 +1,19 @@ -'use strict' +import * as actions from '../database/actions.js' +import pipe from '../utils/pipe.js' +import requireAuth from '../middlewares/requireAuth.js' -const actions = require('../database/actions') -const pipe = require('../utils/pipe') -const requireAuth = require('../middlewares/requireAuth') - -module.exports = { - EventStatistics: { - id: pipe(requireAuth, (event) => { - return event.id - }), - chart: pipe(requireAuth, (event, { type, interval, limit }, { dateDetails }) => { - const ids = [ event.id ] - return actions.getChart(ids, type, interval, limit, dateDetails) - }), - list: pipe(requireAuth, (event, { sorting, type, range, limit }, { dateDetails }) => { - const ids = [ event.id ] - return actions.getList(ids, sorting, type, range, limit, dateDetails) - }), - }, -} \ No newline at end of file +export default { +EventStatistics: { +id: pipe(requireAuth, (event) => { +return event.id +}), +chart: pipe(requireAuth, (event, { type, interval, limit }, { dateDetails }) => { +const ids = [ event.id ] +return actions.getChart(ids, type, interval, limit, dateDetails) +}), +list: pipe(requireAuth, (event, { sorting, type, range, limit }, { dateDetails }) => { +const ids = [ event.id ] +return actions.getList(ids, sorting, type, range, limit, dateDetails) +}), +}, +} diff --git a/src/resolvers/events.js b/src/resolvers/events.js index a4fffaf0d..df9dada6f 100644 --- a/src/resolvers/events.js +++ b/src/resolvers/events.js @@ -1,73 +1,71 @@ -'use strict' +import * as actions from '../database/actions.js' +import * as events from '../database/events.js' +import KnownError from '../utils/KnownError.js' +import messages from '../utils/messages.js' +import pipe from '../utils/pipe.js' +import requireAuth from '../middlewares/requireAuth.js' +import blockDemoMode from '../middlewares/blockDemoMode.js' -const actions = require('../database/actions') -const events = require('../database/events') -const KnownError = require('../utils/KnownError') -const messages = require('../utils/messages') -const pipe = require('../utils/pipe') -const requireAuth = require('../middlewares/requireAuth') -const blockDemoMode = require('../middlewares/blockDemoMode') +export default { +Event: { +statistics: (parent) => parent, +}, +Query: { +event: pipe(requireAuth, (parent, { id }) => { +return events.get(id) +}), +events: pipe(requireAuth, () => { +return events.all() +}), +}, +Mutation: { +createEvent: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { +let entry -module.exports = { - Event: { - statistics: (parent) => parent, - }, - Query: { - event: pipe(requireAuth, (parent, { id }) => { - return events.get(id) - }), - events: pipe(requireAuth, () => { - return events.all() - }), - }, - Mutation: { - createEvent: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { - let entry +try { +entry = await events.add(input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - try { - entry = await events.add(input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +throw error +} - throw error - } +return { +payload: entry, +success: true, +} +}), +updateEvent: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { +let entry - return { - payload: entry, - success: true, - } - }), - updateEvent: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { - let entry +try { +entry = await events.update(id, input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - try { - entry = await events.update(id, input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +throw error +} - throw error - } +if (entry == null) { +throw new KnownError('Unknown event') +} - if (entry == null) { - throw new KnownError('Unknown event') - } +return { +payload: entry, +success: true, +} +}), +deleteEvent: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { +await actions.del(id) +await events.del(id) - return { - payload: entry, - success: true, - } - }), - deleteEvent: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { - await actions.del(id) - await events.del(id) - - return { - success: true, - } - }), - }, -} \ No newline at end of file +return { +success: true, +} +}), +}, +} diff --git a/src/resolvers/facts.js b/src/resolvers/facts.js index 8d6ddcda9..ef09c2f6f 100644 --- a/src/resolvers/facts.js +++ b/src/resolvers/facts.js @@ -1,95 +1,93 @@ -'use strict' - -const views = require('../database/views') -const facts = require('../database/facts') -const durations = require('../database/durations') -const viewsType = require('../constants/views') -const intervals = require('../constants/intervals') -const pipe = require('../utils/pipe') -const domainIds = require('../utils/domainIds') -const recursiveId = require('../utils/recursiveId') -const requireAuth = require('../middlewares/requireAuth') - -module.exports = { - AverageViews: { - count: pipe(requireAuth, (entries) => { - const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) - - return Math.round(totalCount / 14) - }), - change: pipe(requireAuth, (entries) => { - const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) - const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) - const totalDifference = totalCountCurrent - totalCountPrevious - - if (totalCountPrevious === 0) return - - return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) - }), - }, - AverageDuration: { - count: pipe(requireAuth, (entries) => { - const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) - - return Math.round(totalCount / 14) - }), - change: pipe(requireAuth, (entries) => { - const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) - const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) - const totalDifference = totalCountCurrent - totalCountPrevious - - if (totalCountPrevious === 0) return - - return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) - }), - }, - Facts: { - id: pipe(requireAuth, async (domain) => { - const ids = await domainIds(domain) - - // Provide a static fallback id when there're domains to create a recursive id from - if (ids.length === 0) return '882b8e8a-f30b-414d-85e1-00d8ed5585a6' - - return recursiveId(ids) - }), - activeVisitors: pipe(requireAuth, async (domain, _, { dateDetails }) => { - const ids = await domainIds(domain) - const activeVisitors = await facts.getActiveVisitors(ids, dateDetails) - - return activeVisitors - }), - averageViews: pipe(requireAuth, async (domain, _, { dateDetails }) => { - const ids = await domainIds(domain) - const entries = views.get(ids, viewsType.VIEWS_TYPE_UNIQUE, intervals.INTERVALS_DAILY, 15, dateDetails) - - return entries - }), - averageDuration: pipe(requireAuth, async (domain, _, { dateDetails }) => { - const ids = await domainIds(domain) - const entries = durations.get(ids, intervals.INTERVALS_DAILY, 15, dateDetails) - - return entries - }), - viewsToday: pipe(requireAuth, async (domain, _, { dateDetails }) => { - const ids = await domainIds(domain) - const entries = await views.get(ids, viewsType.VIEWS_TYPE_UNIQUE, intervals.INTERVALS_DAILY, 1, dateDetails) - - return entries[0].count - }), - viewsMonth: pipe(requireAuth, async (domain, _, { dateDetails }) => { - const ids = await domainIds(domain) - const entries = await views.get(ids, viewsType.VIEWS_TYPE_UNIQUE, intervals.INTERVALS_MONTHLY, 1, dateDetails) - - return entries[0].count - }), - viewsYear: pipe(requireAuth, async (domain, _, { dateDetails }) => { - const ids = await domainIds(domain) - const entries = await views.get(ids, viewsType.VIEWS_TYPE_UNIQUE, intervals.INTERVALS_YEARLY, 1, dateDetails) - - return entries[0].count - }), - }, - Query: { - facts: () => ({}), - }, -} \ No newline at end of file +import getViews from '../database/views.js' +import getActiveVisitors from '../database/facts.js' +import getDurations from '../database/durations.js' +import { VIEWS_TYPE_UNIQUE } from '../constants/views.js' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' +import pipe from '../utils/pipe.js' +import domainIds from '../utils/domainIds.js' +import recursiveId from '../utils/recursiveId.js' +import requireAuth from '../middlewares/requireAuth.js' + +export default { +AverageViews: { +count: pipe(requireAuth, (entries) => { +const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) + +return Math.round(totalCount / 14) +}), +change: pipe(requireAuth, (entries) => { +const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) +const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) +const totalDifference = totalCountCurrent - totalCountPrevious + +if (totalCountPrevious === 0) return + +return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) +}), +}, +AverageDuration: { +count: pipe(requireAuth, (entries) => { +const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) + +return Math.round(totalCount / 14) +}), +change: pipe(requireAuth, (entries) => { +const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) +const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) +const totalDifference = totalCountCurrent - totalCountPrevious + +if (totalCountPrevious === 0) return + +return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) +}), +}, +Facts: { +id: pipe(requireAuth, async (domain) => { +const ids = await domainIds(domain) + +// Provide a static fallback id when there're domains to create a recursive id from +if (ids.length === 0) return '882b8e8a-f30b-414d-85e1-00d8ed5585a6' + +return recursiveId(ids) +}), +activeVisitors: pipe(requireAuth, async (domain, _, { dateDetails }) => { +const ids = await domainIds(domain) +const activeVisitors = await getActiveVisitors(ids, dateDetails) + +return activeVisitors +}), +averageViews: pipe(requireAuth, async (domain, _, { dateDetails }) => { +const ids = await domainIds(domain) +const entries = getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_DAILY, 15, dateDetails) + +return entries +}), +averageDuration: pipe(requireAuth, async (domain, _, { dateDetails }) => { +const ids = await domainIds(domain) +const entries = getDurations(ids, INTERVALS_DAILY, 15, dateDetails) + +return entries +}), +viewsToday: pipe(requireAuth, async (domain, _, { dateDetails }) => { +const ids = await domainIds(domain) +const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_DAILY, 1, dateDetails) + +return entries[0].count +}), +viewsMonth: pipe(requireAuth, async (domain, _, { dateDetails }) => { +const ids = await domainIds(domain) +const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_MONTHLY, 1, dateDetails) + +return entries[0].count +}), +viewsYear: pipe(requireAuth, async (domain, _, { dateDetails }) => { +const ids = await domainIds(domain) +const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_YEARLY, 1, dateDetails) + +return entries[0].count +}), +}, +Query: { +facts: () => ({}), +}, +} diff --git a/src/resolvers/index.js b/src/resolvers/index.js index 7a4deef5a..430aa1095 100644 --- a/src/resolvers/index.js +++ b/src/resolvers/index.js @@ -1,15 +1,23 @@ -'use strict' +import { mergeResolvers } from '@graphql-tools/merge' -const { mergeResolvers } = require('@graphql-tools/merge') +import tokens from './tokens.js' +import permanentTokens from './permanentTokens.js' +import records from './records.js' +import domains from './domains.js' +import events from './events.js' +import actions from './actions.js' +import facts from './facts.js' +import domainStatistics from './domainStatistics.js' +import eventStatistics from './eventStatistics.js' -module.exports = mergeResolvers([ - require('./tokens'), - require('./permanentTokens'), - require('./records'), - require('./domains'), - require('./events'), - require('./actions'), - require('./facts'), - require('./domainStatistics'), - require('./eventStatistics'), +export default mergeResolvers([ + tokens, + permanentTokens, + records, + domains, + events, + actions, + facts, + domainStatistics, + eventStatistics, ]) \ No newline at end of file diff --git a/src/resolvers/permanentTokens.js b/src/resolvers/permanentTokens.js index 60daf3c7f..85997fcdd 100644 --- a/src/resolvers/permanentTokens.js +++ b/src/resolvers/permanentTokens.js @@ -1,68 +1,66 @@ -'use strict' +import * as permanentTokens from '../database/permanentTokens.js' +import KnownError from '../utils/KnownError.js' +import messages from '../utils/messages.js' +import pipe from '../utils/pipe.js' +import requireAuth from '../middlewares/requireAuth.js' +import blockDemoMode from '../middlewares/blockDemoMode.js' -const permanentTokens = require('../database/permanentTokens') -const KnownError = require('../utils/KnownError') -const messages = require('../utils/messages') -const pipe = require('../utils/pipe') -const requireAuth = require('../middlewares/requireAuth') -const blockDemoMode = require('../middlewares/blockDemoMode') +export default { +Query: { +permanentToken: pipe(requireAuth, (parent, { id }) => { +return permanentTokens.get(id) +}), +permanentTokens: pipe(requireAuth, () => { +return permanentTokens.all() +}), +}, +Mutation: { +createPermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { +let entry -module.exports = { - Query: { - permanentToken: pipe(requireAuth, (parent, { id }) => { - return permanentTokens.get(id) - }), - permanentTokens: pipe(requireAuth, () => { - return permanentTokens.all() - }), - }, - Mutation: { - createPermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { - let entry +try { +entry = await permanentTokens.add(input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - try { - entry = await permanentTokens.add(input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +throw error +} - throw error - } +return { +payload: entry, +success: true, +} +}), +updatePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { +let entry - return { - payload: entry, - success: true, - } - }), - updatePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { - let entry +try { +entry = await permanentTokens.update(id, input) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} - try { - entry = await permanentTokens.update(id, input) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } +throw error +} - throw error - } +if (entry == null) { +throw new KnownError('Unknown domain') +} - if (entry == null) { - throw new KnownError('Unknown domain') - } +return { +payload: entry, +success: true, +} +}), +deletePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { +await permanentTokens.del(id) - return { - payload: entry, - success: true, - } - }), - deletePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { - await permanentTokens.del(id) - - return { - success: true, - } - }), - }, -} \ No newline at end of file +return { +success: true, +} +}), +}, +} diff --git a/src/resolvers/records.js b/src/resolvers/records.js index 092e5f1c7..107fb7c7d 100644 --- a/src/resolvers/records.js +++ b/src/resolvers/records.js @@ -1,118 +1,116 @@ -'use strict' - -const KnownError = require('../utils/KnownError') -const normalizeUrl = require('../utils/normalizeUrl') -const identifier = require('../utils/identifier') -const messages = require('../utils/messages') -const domains = require('../database/domains') -const records = require('../database/records') +import KnownError from '../utils/KnownError.js' +import normalizeUrl from '../utils/normalizeUrl.js' +import identifier from '../utils/identifier.js' +import messages from '../utils/messages.js' +import * as domains from '../database/domains.js' +import * as records from '../database/records.js' const normalizeSiteLocation = (siteLocation) => { - if (siteLocation == null) { - // Pre-validate siteLocation and imitate MongoDB error - throw new KnownError(`Path \`siteLocation\` is required`) - } +if (siteLocation == null) { +// Pre-validate siteLocation and imitate MongoDB error +throw new KnownError(`Path \`siteLocation\` is required`) +} - try { - return normalizeUrl(siteLocation.toString()) - } catch (error) { - throw new KnownError(`Failed to normalize \`siteLocation\``, error) - } +try { +return normalizeUrl(siteLocation.toString()) +} catch (error) { +throw new KnownError(`Failed to normalize \`siteLocation\``, error) +} } const normalizeSiteReferrer = (siteReferrer) => { - // The siteReferrer is optional - if (siteReferrer == null) return siteReferrer +// The siteReferrer is optional +if (siteReferrer == null) return siteReferrer - try { - return normalizeUrl(siteReferrer.toString()) - } catch (error) { - throw new KnownError(`Failed to normalize \`siteReferrer\``, error) - } +try { +return normalizeUrl(siteReferrer.toString()) +} catch (error) { +throw new KnownError(`Failed to normalize \`siteReferrer\``, error) +} } const polish = (obj) => { - return Object.entries(obj).reduce((acc, [ key, value ]) => { - value = typeof value === 'string' ? value.trim() : value - value = value == null ? undefined : value - value = value === '' ? undefined : value - - if (key === 'siteLocation') value = normalizeSiteLocation(value) - if (key === 'siteReferrer') value = normalizeSiteReferrer(value) - - acc[key] = value - return acc - }, {}) -} - -module.exports = { - Mutation: { - createRecord: async (parent, { domainId, input }, { ip, userAgent, isIgnored }) => { - // Ignore your own records when logged in - if (isIgnored === true) { - return { - success: true, - payload: { - id: '88888888-8888-8888-8888-888888888888', - }, - } - } - - const clientId = identifier(ip, userAgent, domainId) - const data = polish({ ...input, clientId, domainId }) - - const domain = await domains.get(domainId) - - if (domain == null) throw new KnownError('Unknown domain') - - let entry - - try { - entry = await records.add(data) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } - - throw error - } - - // Anonymize old entries with the same clientId to prevent that the browsing history - // of a user is reconstructible. Will be skipped when there're no previous entries. - await records.anonymize(clientId, entry.id) - - return { - success: true, - payload: entry, - } - }, - updateRecord: async (parent, { id }, { isIgnored }) => { - // Ignore your own records when logged in - if (isIgnored === true) { - return { - success: true, - } - } - - let entry - - try { - entry = await records.update(id) - } catch (error) { - if (error.name === 'ValidationError') { - throw new KnownError(messages(error.errors)) - } - - throw error - } - - if (entry == null) { - throw new KnownError('Unknown record') - } - - return { - success: true, - } - }, - }, -} \ No newline at end of file +return Object.entries(obj).reduce((acc, [ key, value ]) => { +value = typeof value === 'string' ? value.trim() : value +value = value == null ? undefined : value +value = value === '' ? undefined : value + +if (key === 'siteLocation') value = normalizeSiteLocation(value) +if (key === 'siteReferrer') value = normalizeSiteReferrer(value) + +acc[key] = value +return acc +}, {}) +} + +export default { +Mutation: { +createRecord: async (parent, { domainId, input }, { ip, userAgent, isIgnored }) => { +// Ignore your own records when logged in +if (isIgnored === true) { +return { +success: true, +payload: { +id: '88888888-8888-8888-8888-888888888888', +}, +} +} + +const clientId = identifier(ip, userAgent, domainId) +const data = polish({ ...input, clientId, domainId }) + +const domain = await domains.get(domainId) + +if (domain == null) throw new KnownError('Unknown domain') + +let entry + +try { +entry = await records.add(data) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} + +throw error +} + +// Anonymize old entries with the same clientId to prevent that the browsing history +// of a user is reconstructible. Will be skipped when there're no previous entries. +await records.anonymize(clientId, entry.id) + +return { +success: true, +payload: entry, +} +}, +updateRecord: async (parent, { id }, { isIgnored }) => { +// Ignore your own records when logged in +if (isIgnored === true) { +return { +success: true, +} +} + +let entry + +try { +entry = await records.update(id) +} catch (error) { +if (error.name === 'ValidationError') { +throw new KnownError(messages(error.errors)) +} + +throw error +} + +if (entry == null) { +throw new KnownError('Unknown record') +} + +return { +success: true, +} +}, +}, +} diff --git a/src/resolvers/tokens.js b/src/resolvers/tokens.js index 89015891e..2a919beb2 100644 --- a/src/resolvers/tokens.js +++ b/src/resolvers/tokens.js @@ -1,46 +1,44 @@ -'use strict' - -const tokens = require('../database/tokens') -const config = require('../utils/config') -const KnownError = require('../utils/KnownError') -const ignoreCookie = require('../utils/ignoreCookie') +import * as tokens from '../database/tokens.js' +import config from '../utils/config.js' +import KnownError from '../utils/KnownError.js' +import { on as ignoreCookieOn, off as ignoreCookieOff } from '../utils/ignoreCookie.js' const response = (entry) => ({ - id: entry.id, - created: entry.created, - updated: entry.updated, +id: entry.id, +created: entry.created, +updated: entry.updated, }) -module.exports = { - Mutation: { - createToken: async (parent, { input }, { setCookies }) => { - const { username, password } = input +export default { +Mutation: { +createToken: async (parent, { input }, { setCookies }) => { +const { username, password } = input - if (config.username == null) throw new KnownError('Ackee username missing in environment') - if (config.password == null) throw new KnownError('Ackee password missing in environment') +if (config.username == null) throw new KnownError('Ackee username missing in environment') +if (config.password == null) throw new KnownError('Ackee password missing in environment') - if (username !== config.username) throw new KnownError('Username or password incorrect') - if (password !== config.password) throw new KnownError('Username or password incorrect') +if (username !== config.username) throw new KnownError('Username or password incorrect') +if (password !== config.password) throw new KnownError('Username or password incorrect') - const entry = await tokens.add() +const entry = await tokens.add() - // Set cookie to avoid reporting your own visits - setCookies.push(ignoreCookie.on) +// Set cookie to avoid reporting your own visits +setCookies.push(ignoreCookieOn) - return { - success: true, - payload: response(entry), - } - }, - deleteToken: async (parent, { id }, { setCookies }) => { - await tokens.del(id) +return { +success: true, +payload: response(entry), +} +}, +deleteToken: async (parent, { id }, { setCookies }) => { +await tokens.del(id) - // Remove cookie to report your own visits, again - setCookies.push(ignoreCookie.off) +// Remove cookie to report your own visits, again +setCookies.push(ignoreCookieOff) - return { - success: true, - } - }, - }, -} \ No newline at end of file +return { +success: true, +} +}, +}, +} diff --git a/src/server.js b/src/server.js index b8bffa8c4..ebe40bec9 100644 --- a/src/server.js +++ b/src/server.js @@ -1,19 +1,24 @@ -'use strict' - -const micro = require('micro') -const { resolve } = require('path') -const { readFile } = require('fs').promises -const { send, createError } = require('micro') -const { router, get, post, put, patch, del } = require('microrouter') -const { ApolloServer } = require('apollo-server-micro') - -const KnownError = require('./utils/KnownError') -const signale = require('./utils/signale') -const config = require('./utils/config') -const findMatchingOrigin = require('./utils/findMatchingOrigin') -const customTracker = require('./utils/customTracker') -const createApolloServer = require('./utils/createApolloServer') -const { createMicroContext } = require('./utils/createContext') +import micro from 'micro' +import { resolve } from 'path' +import { readFile } from 'fs/promises' +import microrouter from 'microrouter' +import { ApolloServer } from 'apollo-server-micro' +import { fileURLToPath } from 'url' +import { dirname } from 'path' + +const { send, createError } = micro +const { router, get, post, put, patch, del } = microrouter + +import KnownError from './utils/KnownError.js' +import signale from './utils/signale.js' +import config from './utils/config.js' +import findMatchingOrigin from './utils/findMatchingOrigin.js' +import * as customTracker from './utils/customTracker.js' +import createApolloServer from './utils/createApolloServer.js' +import { createMicroContext } from './utils/createContext.js' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) const index = readFile(resolve(__dirname, '../dist/index.html')).catch(signale.fatal) const favicon = readFile(resolve(__dirname, '../dist/favicon.ico')).catch(signale.fatal) @@ -22,134 +27,134 @@ const scripts = readFile(resolve(__dirname, '../dist/index.js')).catch(signale.f const tracker = readFile(resolve(__dirname, '../dist/tracker.js')).catch(signale.fatal) const handleMicroError = (error, response) => { - // This part is for micro errors and errors outside of GraphQL. - // Most errors won't be caught here, but some error can still - // happen outside of GraphQL. In this case we distinguish - // between unknown errors and known errors. Known errors are - // created with the createError function while unknown errors - // are simply errors thrown somewhere in the application. - - const isUnknownError = error.statusCode == null - const hasOriginalError = error.originalError != null - - // Only log the full error stack when the error isn't a known response - if (isUnknownError === true) { - signale.fatal(error) - return send(response, 500, error.message) - } - - signale.warn(hasOriginalError === true ? error.originalError.message : error.message) - send(response, error.statusCode, error.message) +// This part is for micro errors and errors outside of GraphQL. +// Most errors won't be caught here, but some error can still +// happen outside of GraphQL. In this case we distinguish +// between unknown errors and known errors. Known errors are +// created with the createError function while unknown errors +// are simply errors thrown somewhere in the application. + +const isUnknownError = error.statusCode == null +const hasOriginalError = error.originalError != null + +// Only log the full error stack when the error isn't a known response +if (isUnknownError === true) { +signale.fatal(error) +return send(response, 500, error.message) +} + +signale.warn(hasOriginalError === true ? error.originalError.message : error.message) +send(response, error.statusCode, error.message) } const handleGraphError = (error) => { - // This part is for error that happen inside GraphQL resolvers. - // All known errors should be thrown as a KnownError as those - // errors will only show up in the response and as a warning - // in the console output. - - const suitableError = error.originalError || error - const isKnownError = suitableError instanceof KnownError - - // Only log the full error stack when the error isn't a known response - if (isKnownError === false) { - signale.fatal(suitableError) - return error - } - - signale.warn(suitableError.message) - return error +// This part is for error that happen inside GraphQL resolvers. +// All known errors should be thrown as a KnownError as those +// errors will only show up in the response and as a warning +// in the console output. + +const suitableError = error.originalError || error +const isKnownError = suitableError instanceof KnownError + +// Only log the full error stack when the error isn't a known response +if (isKnownError === false) { +signale.fatal(suitableError) +return error +} + +signale.warn(suitableError.message) +return error } const catchError = (fn) => async (request, response) => { - try { - return await fn(request, response) - } catch (error) { - handleMicroError(error, response) - } +try { +return await fn(request, response) +} catch (error) { +handleMicroError(error, response) +} } const attachCorsHeaders = (fn) => async (request, response) => { - const matchingOrigin = await findMatchingOrigin(request, config.allowOrigin, config.autoOrigin) - - if (matchingOrigin != null) { - response.setHeader('Access-Control-Allow-Origin', matchingOrigin) - response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS') - response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Time-Zone') - response.setHeader('Access-Control-Allow-Credentials', 'true') - response.setHeader('Access-Control-Max-Age', '3600') - } +const matchingOrigin = await findMatchingOrigin(request, config.allowOrigin, config.autoOrigin) + +if (matchingOrigin != null) { +response.setHeader('Access-Control-Allow-Origin', matchingOrigin) +response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS') +response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Time-Zone') +response.setHeader('Access-Control-Allow-Credentials', 'true') +response.setHeader('Access-Control-Max-Age', '3600') +} - return fn(request, response) +return fn(request, response) } const awaitedHandler = (fn) => async (request, response) => { - return (await fn)(request, response) +return (await fn)(request, response) } const notFound = (request) => { - const error = new Error(`\`${ request.url }\` not found`) +const error = new Error(`\`${ request.url }\` not found`) - throw createError(404, 'Not found', error) +throw createError(404, 'Not found', error) } const apolloServer = createApolloServer(ApolloServer, { - formatError: handleGraphError, - context: createMicroContext, +formatError: handleGraphError, +context: createMicroContext, }) const graphqlPath = '/api' const apolloHandler = apolloServer - .start() - .then(() => apolloServer.createHandler({ path: graphqlPath })) +.start() +.then(() => apolloServer.createHandler({ path: graphqlPath })) const routes = [ - get('/', async (request, response) => { - response.setHeader('Content-Type', 'text/html; charset=utf-8') - response.end(await index) - }), - get('/index.html', async (request, response) => { - response.setHeader('Content-Type', 'text/html; charset=utf-8') - response.end(await index) - }), - get('/favicon.ico', async (request, response) => { - response.setHeader('Content-Type', 'image/vnd.microsoft.icon') - response.end(await favicon) - }), - get('/index.css', async (request, response) => { - response.setHeader('Content-Type', 'text/css; charset=utf-8') - response.end(await styles) - }), - get('/index.js', async (request, response) => { - response.setHeader('Content-Type', 'text/javascript; charset=utf-8') - response.end(await scripts) - }), - get('/tracker.js', async (request, response) => { - response.setHeader('Content-Type', 'text/javascript; charset=utf-8') - response.end(await tracker) - }), - customTracker.exists === true ? get(customTracker.url, async (request, response) => { - response.setHeader('Content-Type', 'text/javascript; charset=utf-8') - response.end(await tracker) - }) : undefined, - - post(graphqlPath, awaitedHandler(apolloHandler)), - get(graphqlPath, awaitedHandler(apolloHandler)), - get('/.well-known/apollo/server-health', awaitedHandler(apolloHandler)), - - get('/*', notFound), - post('/*', notFound), - put('/*', notFound), - patch('/*', notFound), - del('/*', notFound), +get('/', async (request, response) => { +response.setHeader('Content-Type', 'text/html; charset=utf-8') +response.end(await index) +}), +get('/index.html', async (request, response) => { +response.setHeader('Content-Type', 'text/html; charset=utf-8') +response.end(await index) +}), +get('/favicon.ico', async (request, response) => { +response.setHeader('Content-Type', 'image/vnd.microsoft.icon') +response.end(await favicon) +}), +get('/index.css', async (request, response) => { +response.setHeader('Content-Type', 'text/css; charset=utf-8') +response.end(await styles) +}), +get('/index.js', async (request, response) => { +response.setHeader('Content-Type', 'text/javascript; charset=utf-8') +response.end(await scripts) +}), +get('/tracker.js', async (request, response) => { +response.setHeader('Content-Type', 'text/javascript; charset=utf-8') +response.end(await tracker) +}), +customTracker.exists === true ? get(customTracker.url, async (request, response) => { +response.setHeader('Content-Type', 'text/javascript; charset=utf-8') +response.end(await tracker) +}) : undefined, + +post(graphqlPath, awaitedHandler(apolloHandler)), +get(graphqlPath, awaitedHandler(apolloHandler)), +get('/.well-known/apollo/server-health', awaitedHandler(apolloHandler)), + +get('/*', notFound), +post('/*', notFound), +put('/*', notFound), +patch('/*', notFound), +del('/*', notFound), ].filter(Boolean) -module.exports = micro( - attachCorsHeaders( - catchError( - router(...routes), - ), - ), -) \ No newline at end of file +export default micro( +attachCorsHeaders( +catchError( +router(...routes), +), +), +) diff --git a/src/serverless.js b/src/serverless.js index 6a36a32c4..03bc66e61 100644 --- a/src/serverless.js +++ b/src/serverless.js @@ -1,63 +1,61 @@ -'use strict' +import { ApolloServer } from 'apollo-server-lambda' -const { ApolloServer } = require('apollo-server-lambda') - -const config = require('./utils/config') -const connect = require('./utils/connect') -const fullyQualifiedDomainNames = require('./utils/fullyQualifiedDomainNames') -const createApolloServer = require('./utils/createApolloServer') -const { createServerlessContext } = require('./utils/createContext') +import config from './utils/config.js' +import connect from './utils/connect.js' +import fullyQualifiedDomainNames from './utils/fullyQualifiedDomainNames.js' +import createApolloServer from './utils/createApolloServer.js' +import { createServerlessContext } from './utils/createContext.js' if (config.dbUrl == null) { - throw new Error('MongoDB connection URI missing in environment') +throw new Error('MongoDB connection URI missing in environment') } connect(config.dbUrl) const apolloServer = createApolloServer(ApolloServer, { - context: createServerlessContext, +context: createServerlessContext, }) const origin = (origin, callback) => { - if (config.autoOrigin === true) { - fullyQualifiedDomainNames() - .then((names) => callback( - null, - names.flatMap((name) => [ `http://${ name }`, `https://${ name }`, name ]), - )) - .catch((error) => callback(error, false)) - return - } - - if (config.allowOrigin === '*') { - callback(null, true) - return - } - - if (config.allowOrigin != null) { - callback(null, config.allowOrigin.split(',')) - return - } - - callback(null, false) - return +if (config.autoOrigin === true) { +fullyQualifiedDomainNames() +.then((names) => callback( +null, +names.flatMap((name) => [ `http://${ name }`, `https://${ name }`, name ]), +)) +.catch((error) => callback(error, false)) +return +} + +if (config.allowOrigin === '*') { +callback(null, true) +return +} + +if (config.allowOrigin != null) { +callback(null, config.allowOrigin.split(',')) +return } -exports.handler = (event, context) => { - // Set request context which is missing on Vercel: - // https://stackoverflow.com/questions/71360059/apollo-server-lambda-unable-to-determine-event-source-based-on-event - if (event.requestContext == null) event.requestContext = context - - const handler = apolloServer.createHandler({ - expressGetMiddlewareOptions: { - cors: { - origin, - credentials: true, - methods: [ 'GET', 'POST', 'PATCH', 'OPTIONS' ], - allowedHeaders: [ 'Content-Type', 'Authorization', 'Time-Zone' ], - }, - }, - }) - - return handler(event, context) -} \ No newline at end of file +callback(null, false) +return +} + +export const handler = (event, context) => { +// Set request context which is missing on Vercel: +// https://stackoverflow.com/questions/71360059/apollo-server-lambda-unable-to-determine-event-source-based-on-event +if (event.requestContext == null) event.requestContext = context + +const handler = apolloServer.createHandler({ +expressGetMiddlewareOptions: { +cors: { +origin, +credentials: true, +methods: [ 'GET', 'POST', 'PATCH', 'OPTIONS' ], +allowedHeaders: [ 'Content-Type', 'Authorization', 'Time-Zone' ], +}, +}, +}) + +return handler(event, context) +} diff --git a/src/stages/matchDomains.js b/src/stages/matchDomains.js index 8e55a52b4..614d05d92 100644 --- a/src/stages/matchDomains.js +++ b/src/stages/matchDomains.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (ids) => { +export default (ids) => { const stage = { $match: {}, } diff --git a/src/stages/matchEvents.js b/src/stages/matchEvents.js index 3c21af026..a39315792 100644 --- a/src/stages/matchEvents.js +++ b/src/stages/matchEvents.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (ids) => { +export default (ids) => { const stage = { $match: {}, } diff --git a/src/stages/matchLimit.js b/src/stages/matchLimit.js index 0c3eff637..a0191f3f2 100644 --- a/src/stages/matchLimit.js +++ b/src/stages/matchLimit.js @@ -1,8 +1,6 @@ -'use strict' +import { DURATIONS_LIMIT } from '../constants/durations.js' -const { DURATIONS_LIMIT } = require('../constants/durations') - -module.exports = () => { +export default () => { // Some visitors keep sites open in the background. Their duration is often // way above the limit. This distorts the average and should be omitted. return { diff --git a/src/stages/projectDuration.js b/src/stages/projectDuration.js index 59ed6851a..14bc2aec8 100644 --- a/src/stages/projectDuration.js +++ b/src/stages/projectDuration.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = () => { +export default () => { // The time that elapsed between the creation and updating of records. return { $project: { diff --git a/src/stages/projectMinInterval.js b/src/stages/projectMinInterval.js index 6922758b1..7ac53e05d 100644 --- a/src/stages/projectMinInterval.js +++ b/src/stages/projectMinInterval.js @@ -1,8 +1,6 @@ -'use strict' +import { DURATIONS_INTERVAL } from '../constants/durations.js' -const { DURATIONS_INTERVAL } = require('../constants/durations') - -module.exports = () => { +export default () => { // Visits below the tracking interval will have a duration of zero. That's // incorrect as visitors spent time on the site, but just not enough. This // step sets the minimum duration to the half of the tracking interval. diff --git a/src/types/actions.js b/src/types/actions.js index d3249dd80..53b23984e 100644 --- a/src/types/actions.js +++ b/src/types/actions.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` """ Event entries will be stored as actions. """ diff --git a/src/types/domainStatistics.js b/src/types/domainStatistics.js index 07d1ba209..09e3ad486 100644 --- a/src/types/domainStatistics.js +++ b/src/types/domainStatistics.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` enum ViewType { """ Unique site views. diff --git a/src/types/domains.js b/src/types/domains.js index a8b7ec81f..df542c366 100644 --- a/src/types/domains.js +++ b/src/types/domains.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` """ Domains are required to track views. You can create as many domains as you want, but it's recommended to create on domain per project/site. This allows you to view facts and statistics separately. """ diff --git a/src/types/eventStatistics.js b/src/types/eventStatistics.js index 97d2bece6..6d9f18741 100644 --- a/src/types/eventStatistics.js +++ b/src/types/eventStatistics.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` enum EventChartType { """ Total sum of values. diff --git a/src/types/events.js b/src/types/events.js index 3ee6f058b..0f50340c2 100644 --- a/src/types/events.js +++ b/src/types/events.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` enum EventType { """ The UI will display the data of this event as a bar chart with totalized values. diff --git a/src/types/facts.js b/src/types/facts.js index 704a6e913..0d89429d6 100644 --- a/src/types/facts.js +++ b/src/types/facts.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` type AverageViews { """ Average number of views per day during the last 14 days, excluding the current day. diff --git a/src/types/index.js b/src/types/index.js index 9ec0013f4..6f3584ce1 100644 --- a/src/types/index.js +++ b/src/types/index.js @@ -1,16 +1,25 @@ -'use strict' +import { mergeTypeDefs } from '@graphql-tools/merge' -const { mergeTypeDefs } = require('@graphql-tools/merge') +import tokens from './tokens.js' +import permanentTokens from './permanentTokens.js' +import records from './records.js' +import domains from './domains.js' +import events from './events.js' +import actions from './actions.js' +import facts from './facts.js' +import miscellaneous from './miscellaneous.js' +import domainStatistics from './domainStatistics.js' +import eventStatistics from './eventStatistics.js' -module.exports = mergeTypeDefs([ - require('./tokens'), - require('./permanentTokens'), - require('./records'), - require('./domains'), - require('./events'), - require('./actions'), - require('./facts'), - require('./miscellaneous'), - require('./domainStatistics'), - require('./eventStatistics'), +export default mergeTypeDefs([ + tokens, + permanentTokens, + records, + domains, + events, + actions, + facts, + miscellaneous, + domainStatistics, + eventStatistics, ], { all: true }) \ No newline at end of file diff --git a/src/types/miscellaneous.js b/src/types/miscellaneous.js index 75d68b17c..578407304 100644 --- a/src/types/miscellaneous.js +++ b/src/types/miscellaneous.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` enum Interval { """ Group by day. diff --git a/src/types/permanentTokens.js b/src/types/permanentTokens.js index 66af00a58..4735ab3f0 100644 --- a/src/types/permanentTokens.js +++ b/src/types/permanentTokens.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` type PermanentToken { """ Permanent token identifier. Use this value for authentication. diff --git a/src/types/records.js b/src/types/records.js index ae738bbc1..1c9de6247 100644 --- a/src/types/records.js +++ b/src/types/records.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` """ Page views will be stored in records. They contain data about the visit and user. Ackee tries its best to keep tracked data anonymized. Several steps are used to avoid that users are identifiable, while still providing helpful analytics. """ diff --git a/src/types/tokens.js b/src/types/tokens.js index ae9ad6cd0..44ff979aa 100644 --- a/src/types/tokens.js +++ b/src/types/tokens.js @@ -1,8 +1,7 @@ -'use strict' -const { gql } = require('apollo-server-micro') +import { gql } from 'apollo-server-micro' -module.exports = gql` +export default gql` type Token { """ Token identifier. Use this value for authentication. diff --git a/src/ui/index.js b/src/ui/index.js index 06ceed729..acb0de3b3 100644 --- a/src/ui/index.js +++ b/src/ui/index.js @@ -1,61 +1,68 @@ -'use strict' +import { resolve } from 'path' +import { writeFile, readFile } from 'fs/promises' +import { createRequire } from 'module' +import { fileURLToPath } from 'url' +import { dirname } from 'path' -const { resolve } = require('path') -const { writeFile, readFile } = require('fs').promises +import layout from '../utils/layout.js' +import config from '../utils/config.js' +import { exists, url, path } from '../utils/customTracker.js' +import signale from '../utils/signale.js' -const layout = require('../utils/layout') -const config = require('../utils/config') -const customTracker = require('../utils/customTracker') -const signale = require('../utils/signale') +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const customTracker = { exists, url, path } const index = () => { - return layout('
', 'favicon.ico', [ 'index.css' ], [ 'index.js' ], { - isDemoMode: config.isDemoMode, - customTracker, - }) +return layout('
', 'favicon.ico', [ 'index.css' ], [ 'index.js' ], { +isDemoMode: config.isDemoMode, +customTracker, +}) } -const styles = () => { - const sass = require('rosid-handler-sass') - const filePath = resolve(__dirname, './styles/index.scss') +const styles = async () => { +const { default: sass } = await import('rosid-handler-sass') +const filePath = resolve(__dirname, './styles/index.scss') - return sass(filePath, { optimize: config.isDevelopmentMode === false }) +return sass(filePath, { optimize: config.isDevelopmentMode === false }) } -const scripts = () => { - const js = require('rosid-handler-js-next') - const filePath = resolve(__dirname, './scripts/index.js') +const scripts = async () => { +const { default: js } = await import('rosid-handler-js-next') +const filePath = resolve(__dirname, './scripts/index.js') - return js(filePath, { - optimize: config.isDevelopmentMode === false, - nodeGlobals: config.isDevelopmentMode === true, - replace: { 'process.env.NODE_ENV': JSON.stringify(config.isDevelopmentMode === true ? 'development' : 'production') }, - babel: false, - }) +return js(filePath, { +optimize: config.isDevelopmentMode === false, +nodeGlobals: config.isDevelopmentMode === true, +replace: { 'process.env.NODE_ENV': JSON.stringify(config.isDevelopmentMode === true ? 'development' : 'production') }, +babel: false, +}) } const tracker = () => { - const filePath = require.resolve('ackee-tracker') +const require = createRequire(import.meta.url) +const filePath = require.resolve('ackee-tracker') - return readFile(filePath, 'utf8') +return readFile(filePath, 'utf8') } const build = async (path, fn) => { - try { - signale.await(`Building and writing '${ path }'`) - const data = await fn() - await writeFile(path, data) - signale.success(`Finished building '${ path }'`) - } catch (error) { - signale.fatal(error) - process.exit(1) - } +try { +signale.await(`Building and writing '${ path }'`) +const data = await fn() +await writeFile(path, data) +signale.success(`Finished building '${ path }'`) +} catch (error) { +signale.fatal(error) +process.exit(1) +} } -module.exports = { - index, - styles, - scripts, - tracker, - build, -} \ No newline at end of file +export { +index, +styles, +scripts, +tracker, +build, +} diff --git a/src/utils/KnownError.js b/src/utils/KnownError.js index 1921ab3a3..33b92e2be 100644 --- a/src/utils/KnownError.js +++ b/src/utils/KnownError.js @@ -1,4 +1,4 @@ -module.exports = class KnownError extends Error { +export default class KnownError extends Error { constructor(message) { super(message) this.name = 'KnownError' diff --git a/src/utils/config.js b/src/utils/config.js index 3ff3eeb61..3fdc728c7 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -1,10 +1,8 @@ -'use static' - -const { day } = require('./times') +import { day } from './times.js' // Must be a function or object that loads and returns the env variables at runtime. // Otherwise it wouldn't be possible to mock the env variables with mockedEnv. -module.exports = new Proxy({}, { +export default new Proxy({}, { get: function(target, prop) { const data = { ttl: process.env.ACKEE_TTL || day, diff --git a/src/utils/connect.js b/src/utils/connect.js index ac2103abe..538d7627b 100644 --- a/src/utils/connect.js +++ b/src/utils/connect.js @@ -1,7 +1,5 @@ -'use strict' +import mongoose from 'mongoose' -const mongoose = require('mongoose') - -module.exports = (dbUrl) => mongoose.connect(dbUrl, { +export default (dbUrl) => mongoose.connect(dbUrl, { connectTimeoutMS: 60000, }) \ No newline at end of file diff --git a/src/utils/createApolloServer.js b/src/utils/createApolloServer.js index e9869ba2c..4b20d8bfc 100644 --- a/src/utils/createApolloServer.js +++ b/src/utils/createApolloServer.js @@ -1,11 +1,9 @@ -'use strict' - -const { - ApolloServerPluginLandingPageGraphQLPlayground: apolloServerPluginLandingPageGraphQLPlayground, - ApolloServerPluginLandingPageDisabled: apolloServerPluginLandingPageDisabled, -} = require('apollo-server-core') -const httpHeadersPlugin = require('apollo-server-plugin-http-headers') -const { +import { + ApolloServerPluginLandingPageGraphQLPlayground as apolloServerPluginLandingPageGraphQLPlayground, + ApolloServerPluginLandingPageDisabled as apolloServerPluginLandingPageDisabled, +} from 'apollo-server-core' +import httpHeadersPlugin from 'apollo-server-plugin-http-headers' +import { UnsignedIntResolver, UnsignedIntTypeDefinition, DateTimeResolver, @@ -14,11 +12,13 @@ const { PositiveFloatTypeDefinition, URLResolver, URLTypeDefinition, -} = require('graphql-scalars') +} from 'graphql-scalars' -const config = require('./config') +import config from './config.js' +import typeDefs from '../types/index.js' +import resolvers from '../resolvers/index.js' -module.exports = (ApolloServer, options) => new ApolloServer({ +export default (ApolloServer, options) => new ApolloServer({ cache: 'bounded', introspection: config.isDemoMode === true || config.isDevelopmentMode === true, playground: config.isDemoMode === true || config.isDevelopmentMode === true, @@ -34,14 +34,14 @@ module.exports = (ApolloServer, options) => new ApolloServer({ DateTimeTypeDefinition, PositiveFloatTypeDefinition, URLTypeDefinition, - require('../types'), + typeDefs, ], resolvers: { UnsignedInt: UnsignedIntResolver, DateTime: DateTimeResolver, PositiveFloat: PositiveFloatResolver, URL: URLResolver, - ...require('../resolvers'), + ...resolvers, }, ...options, }) \ No newline at end of file diff --git a/src/utils/createArray.js b/src/utils/createArray.js index c9a47cc91..51267d3e2 100644 --- a/src/utils/createArray.js +++ b/src/utils/createArray.js @@ -1,3 +1 @@ -'use strict' - -module.exports = (length) => new Array(length).fill() \ No newline at end of file +export default (length) => new Array(length).fill() \ No newline at end of file diff --git a/src/utils/createContext.js b/src/utils/createContext.js index f05e9a138..f4d35f7a2 100644 --- a/src/utils/createContext.js +++ b/src/utils/createContext.js @@ -1,11 +1,9 @@ -'use strict' +import { getClientIp } from 'request-ip' -const { getClientIp } = require('request-ip') - -const config = require('./config') -const isAuthenticated = require('./isAuthenticated') -const createDate = require('./createDate') -const ignoreCookie = require('./ignoreCookie') +import config from './config.js' +import isAuthenticated from './isAuthenticated.js' +import createDate from './createDate.js' +import { isSet } from './ignoreCookie.js' const createServerlessContext = (integrationContext) => { return createContext(integrationContext.event.headers['client-ip'], integrationContext.event.headers) @@ -19,7 +17,7 @@ const createContext = async (ip, headers) => { return { isDemoMode: config.isDemoMode, isAuthenticated: await isAuthenticated(headers['authorization'], config.ttl), - isIgnored: ignoreCookie.isSet(headers['cookie']), + isIgnored: isSet(headers['cookie']), dateDetails: createDate(headers['time-zone']), userAgent: headers['user-agent'], ip, @@ -30,7 +28,7 @@ const createContext = async (ip, headers) => { } } -module.exports = { +export { createServerlessContext, createMicroContext, } \ No newline at end of file diff --git a/src/utils/createDate.js b/src/utils/createDate.js index 171bc95e1..11ef8b1b7 100644 --- a/src/utils/createDate.js +++ b/src/utils/createDate.js @@ -1,10 +1,8 @@ -'use strict' +import { subMilliseconds, subHours, subDays, subMonths, subYears, startOfDay, startOfMonth, startOfYear } from 'date-fns' +import serverTimeZone from './timeZone.js' +import { INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY } from '../constants/intervals.js' -const { subMilliseconds, subHours, subDays, subMonths, subYears, startOfDay, startOfMonth, startOfYear } = require('date-fns') -const serverTimeZone = require('./timeZone') -const intervals = require('../constants/intervals') - -module.exports = (userTimeZone = serverTimeZone) => { +export default (userTimeZone = serverTimeZone) => { const currentDate = new Date() // This is the biggest, positive timezone offset possible (starting from UTC). @@ -35,18 +33,18 @@ module.exports = (userTimeZone = serverTimeZone) => { // Get the last-function that matches the interval const lastFnByInterval = (interval) => { switch (interval) { - case intervals.INTERVALS_DAILY: return instance.lastDays - case intervals.INTERVALS_MONTHLY: return instance.lastMonths - case intervals.INTERVALS_YEARLY: return instance.lastYears + case INTERVALS_DAILY: return instance.lastDays + case INTERVALS_MONTHLY: return instance.lastMonths + case INTERVALS_YEARLY: return instance.lastYears } } // Get the include-function that matches the interval const includeFnByInterval = (interval) => { switch (interval) { - case intervals.INTERVALS_DAILY: return instance.includeDays - case intervals.INTERVALS_MONTHLY: return instance.includeMonths - case intervals.INTERVALS_YEARLY: return instance.includeYears + case INTERVALS_DAILY: return instance.includeDays + case INTERVALS_MONTHLY: return instance.includeMonths + case INTERVALS_YEARLY: return instance.includeYears } } diff --git a/src/utils/customTracker.js b/src/utils/customTracker.js index bfe33e282..5eda2ae00 100644 --- a/src/utils/customTracker.js +++ b/src/utils/customTracker.js @@ -1,12 +1,6 @@ -'use strict' - -const sanitizeFilename = require('sanitize-filename') +import sanitizeFilename from 'sanitize-filename' const name = process.env.ACKEE_TRACKER -const exists = name != null && name !== '' - -module.exports = { - exists, - url: exists === true ? `/${ encodeURIComponent(name) }.js` : undefined, - path: exists === true ? `${ sanitizeFilename(name) }.js` : undefined, -} \ No newline at end of file +export const exists = name != null && name !== '' +export const url = exists === true ? `/${ encodeURIComponent(name) }.js` : undefined +export const path = exists === true ? `${ sanitizeFilename(name) }.js` : undefined \ No newline at end of file diff --git a/src/utils/domainIds.js b/src/utils/domainIds.js index 7db013bbd..78b864dcb 100644 --- a/src/utils/domainIds.js +++ b/src/utils/domainIds.js @@ -1,15 +1,13 @@ -'use strict' +import debouncePromise from 'debounce-promise' -const debouncePromise = require('debounce-promise') - -const domains = require('../database/domains') +import * as domains from '../database/domains.js' // A zero timeout is enough to ensure that this task // runs only once on every API call. It's a task that would // otherwise execute multiple times. const loadDomains = debouncePromise(domains.all, 0) -module.exports = async (domain) => { +export default async (domain) => { if (domain.id == null) { const allDomains = await loadDomains() return allDomains.map((domain) => domain.id) diff --git a/src/utils/findMatchingOrigin.js b/src/utils/findMatchingOrigin.js index 8c560426f..3ebbfffbe 100644 --- a/src/utils/findMatchingOrigin.js +++ b/src/utils/findMatchingOrigin.js @@ -1,12 +1,10 @@ -'use strict' - -const fullyQualifiedDomainNames = require('./fullyQualifiedDomainNames') +import fullyQualifiedDomainNames from './fullyQualifiedDomainNames.js' const findOrigin = (request, origins) => { return origins.find((origin) => origin.includes(request.headers.origin) || origin.includes(request.headers.host)) } -module.exports = async (request, allowedOrigins, autoOrigin) => { +export default async (request, allowedOrigins, autoOrigin) => { if (autoOrigin === true) { const origins = await fullyQualifiedDomainNames() return findOrigin(request, origins) diff --git a/src/utils/fullyQualifiedDomainNames.js b/src/utils/fullyQualifiedDomainNames.js index 8f2cb7325..f32165ac0 100644 --- a/src/utils/fullyQualifiedDomainNames.js +++ b/src/utils/fullyQualifiedDomainNames.js @@ -1,10 +1,8 @@ -'use strict' +import isValidDomain from 'is-valid-domain' -const isValidDomain = require('is-valid-domain') +import * as domains from '../database/domains.js' -const domains = require('../database/domains') - -module.exports = async () => { +export default async () => { const allDomains = await domains.all() const allTitles = allDomains.map((domain) => domain.title) const fullyQualifiedDomainNames = allTitles.filter((title) => isValidDomain(title, { subdomain: true, wildcard: false, allowUnicode: true })) diff --git a/src/utils/identifier.js b/src/utils/identifier.js index 4c0100d74..271eda719 100644 --- a/src/utils/identifier.js +++ b/src/utils/identifier.js @@ -1,10 +1,8 @@ -'use strict' +import crypto from 'crypto' -const crypto = require('crypto') +import salt from './salt.js' -const salt = require('./salt') - -module.exports = (ip, userAgent, domainId) => { +export default (ip, userAgent, domainId) => { return crypto.createHash('sha256').update(`${ salt() }${ ip }${ userAgent }${ domainId }`) .digest('hex') } \ No newline at end of file diff --git a/src/utils/ignoreCookie.js b/src/utils/ignoreCookie.js index 017d81280..400654214 100644 --- a/src/utils/ignoreCookie.js +++ b/src/utils/ignoreCookie.js @@ -1,25 +1,23 @@ -'use static' - const COOKIE_NAME = 'ackee_ignore' -module.exports = { - isSet: (cookie = '') => cookie.includes(`${ COOKIE_NAME }=1`), - on: { - name: COOKIE_NAME, - value: '1', - options: { - maxAge: 365 * 24 * 60 * 60, - sameSite: 'none', - secure: true, - }, +export const isSet = (cookie = '') => cookie.includes(`${ COOKIE_NAME }=1`) + +export const on = { + name: COOKIE_NAME, + value: '1', + options: { + maxAge: 365 * 24 * 60 * 60, + sameSite: 'none', + secure: true, }, - off: { - name: COOKIE_NAME, - value: '0', - options: { - maxAge: -1, - sameSite: 'none', - secure: true, - }, +} + +export const off = { + name: COOKIE_NAME, + value: '0', + options: { + maxAge: -1, + sameSite: 'none', + secure: true, }, } \ No newline at end of file diff --git a/src/utils/isAuthenticated.js b/src/utils/isAuthenticated.js index edb069c17..74806ca88 100644 --- a/src/utils/isAuthenticated.js +++ b/src/utils/isAuthenticated.js @@ -1,11 +1,9 @@ -'use strict' +import KnownError from '../utils/KnownError.js' +import isExpired from '../utils/isExpired.js' +import * as tokens from '../database/tokens.js' +import * as permanentTokens from '../database/permanentTokens.js' -const KnownError = require('../utils/KnownError') -const isExpired = require('../utils/isExpired') -const tokens = require('../database/tokens') -const permanentTokens = require('../database/permanentTokens') - -module.exports = async (authorization, ttl) => { +export default async (authorization, ttl) => { // Token not in request if (authorization == null) { return new KnownError('Token missing') diff --git a/src/utils/isDefined.js b/src/utils/isDefined.js index 0065e9de6..4438892a2 100644 --- a/src/utils/isDefined.js +++ b/src/utils/isDefined.js @@ -1,3 +1 @@ -'use strict' - -module.exports = (_) => _ != null \ No newline at end of file +export default (_) => _ != null \ No newline at end of file diff --git a/src/utils/isExpired.js b/src/utils/isExpired.js index 15e176559..198c7099d 100644 --- a/src/utils/isExpired.js +++ b/src/utils/isExpired.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (timestamp, ttl) => { +export default (timestamp, ttl) => { const current = Date.now() const passed = current - timestamp diff --git a/src/utils/languageCodes.js b/src/utils/languageCodes.js index 67e3c255b..855c03750 100644 --- a/src/utils/languageCodes.js +++ b/src/utils/languageCodes.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = { +export default { aa: 'Afar', ab: 'Abkhazian', ae: 'Avestan', diff --git a/src/utils/layout.js b/src/utils/layout.js index f10037d6a..b91bc9a45 100644 --- a/src/utils/layout.js +++ b/src/utils/layout.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (body, favicon, styles, scripts, variables) => ` +export default (body, favicon, styles, scripts, variables) => ` diff --git a/src/utils/matchesDate.js b/src/utils/matchesDate.js index d08d23f91..dfd1a0b92 100644 --- a/src/utils/matchesDate.js +++ b/src/utils/matchesDate.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (day, month, year, date) => { +export default (day, month, year, date) => { const isDay = day === date.getDate() || day == null const isMonth = month === date.getMonth() + 1 || month == null const isYear = year === date.getFullYear() || year == null diff --git a/src/utils/messages.js b/src/utils/messages.js index 87ed4621d..38887405c 100644 --- a/src/utils/messages.js +++ b/src/utils/messages.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (errors) => { +export default (errors) => { // Extract message from an error const message = (key) => errors[key].message diff --git a/src/utils/normalizeUrl.js b/src/utils/normalizeUrl.js index 00b239963..2b50aa2e6 100644 --- a/src/utils/normalizeUrl.js +++ b/src/utils/normalizeUrl.js @@ -1,8 +1,6 @@ -'use strict' +import normalizeUrl from 'normalize-url' -const normalizeUrl = require('normalize-url') - -module.exports = (url) => normalizeUrl(url, { +export default (url) => normalizeUrl(url, { removeDirectoryIndex: true, removeQueryParameters: [ /^utm_\w+/i, diff --git a/src/utils/pipe.js b/src/utils/pipe.js index 55f1eb453..4865c171c 100644 --- a/src/utils/pipe.js +++ b/src/utils/pipe.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (...args) => { +export default (...args) => { return Array.prototype.slice.call(args, 1).reduce((a, b) => { return (...args) => Promise.resolve(a(...args)).then((result) => { if (result == null) return b(...args) diff --git a/src/utils/recursiveId.js b/src/utils/recursiveId.js index 7581fc5af..c6dc1514d 100644 --- a/src/utils/recursiveId.js +++ b/src/utils/recursiveId.js @@ -1,6 +1,4 @@ -'use strict' - -const uuid = require('uuid').v5 +import { v5 as uuid } from 'uuid' // Randomly generated UUID that should never change const DEFAULT_NAMESPACE = 'faea8d75-e9c5-45fe-a436-4a906d44b88e' @@ -10,4 +8,4 @@ const recursiveId = (ids) => { return uuid(current, rest.length === 0 ? DEFAULT_NAMESPACE : recursiveId(rest)) } -module.exports = recursiveId \ No newline at end of file +export default recursiveId \ No newline at end of file diff --git a/src/utils/salt.js b/src/utils/salt.js index f88ea60b1..634e6c88f 100644 --- a/src/utils/salt.js +++ b/src/utils/salt.js @@ -1,7 +1,5 @@ -'use strict' - -const crypto = require('crypto') -const schedule = require('node-schedule') +import crypto from 'crypto' +import schedule from 'node-schedule' const generate = () => crypto.randomBytes(16).toString('hex') let salt = generate() @@ -12,4 +10,4 @@ rule.hour = 0 schedule.scheduleJob(rule, () => salt = generate()) -module.exports = () => salt \ No newline at end of file +export default () => salt \ No newline at end of file diff --git a/src/utils/signale.js b/src/utils/signale.js index 1f9385000..f17912be8 100644 --- a/src/utils/signale.js +++ b/src/utils/signale.js @@ -1,7 +1,7 @@ -'use strict' +import signaleModule from 'signale' -const { Signale } = require('signale') +const { Signale } = signaleModule -module.exports = new Signale({ +export default new Signale({ scope: 'Ackee', }) \ No newline at end of file diff --git a/src/utils/sortByProp.js b/src/utils/sortByProp.js index 904095cd8..58a1185db 100644 --- a/src/utils/sortByProp.js +++ b/src/utils/sortByProp.js @@ -1,6 +1,4 @@ -'use strict' - -module.exports = (prop) => (a, b) => { +export default (prop) => (a, b) => { const _a = String(a[prop]) const _b = String(b[prop]) diff --git a/src/utils/stripUrlAuth.js b/src/utils/stripUrlAuth.js index 4406da81e..5ae837ef6 100644 --- a/src/utils/stripUrlAuth.js +++ b/src/utils/stripUrlAuth.js @@ -1,8 +1,6 @@ -'use strict' +import normalizeUrl from 'normalize-url' -const normalizeUrl = require('normalize-url') - -module.exports = (url) => normalizeUrl(url, { +export default (url) => normalizeUrl(url, { normalizeProtocol: false, stripWWW: false, removeTrailingSlash: false, diff --git a/src/utils/timeZone.js b/src/utils/timeZone.js index 6e9d094e0..7223a5564 100644 --- a/src/utils/timeZone.js +++ b/src/utils/timeZone.js @@ -1,3 +1 @@ -'use strict' - -module.exports = (new Intl.DateTimeFormat()).resolvedOptions().timeZone \ No newline at end of file +export default (new Intl.DateTimeFormat()).resolvedOptions().timeZone \ No newline at end of file diff --git a/src/utils/times.js b/src/utils/times.js index 76b94def4..cd54bb86e 100644 --- a/src/utils/times.js +++ b/src/utils/times.js @@ -1,11 +1,9 @@ -'use strict' - const second = 1000 const minute = second * 60 const hour = minute * 60 const day = hour * 24 -module.exports = { +export { second, minute, hour, diff --git a/test/aggregations/aggregateActiveVisitors.js b/test/aggregations/aggregateActiveVisitors.js index 161574690..a83ccc74b 100644 --- a/test/aggregations/aggregateActiveVisitors.js +++ b/test/aggregations/aggregateActiveVisitors.js @@ -1,13 +1,11 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const aggregateActiveVisitors = require('../../src/aggregations/aggregateActiveVisitors') -const createDate = require('../../src/utils/createDate') +import aggregateActiveVisitors from '../../src/aggregations/aggregateActiveVisitors.js' +import createDate from '../../src/utils/createDate.js' test('return aggregation', (t) => { - const result = aggregateActiveVisitors(uuid(), createDate()) +const result = aggregateActiveVisitors(uuid(), createDate()) - t.true(Array.isArray(result)) -}) \ No newline at end of file +t.true(Array.isArray(result)) +}) diff --git a/test/aggregations/aggregateDurations.js b/test/aggregations/aggregateDurations.js index db845487a..67147cd98 100644 --- a/test/aggregations/aggregateDurations.js +++ b/test/aggregations/aggregateDurations.js @@ -1,14 +1,12 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const aggregateDurations = require('../../src/aggregations/aggregateDurations') -const intervals = require('../../src/constants/intervals') -const createDate = require('../../src/utils/createDate') +import aggregateDurations from '../../src/aggregations/aggregateDurations.js' +import { INTERVALS_DAILY } from '../../src/constants/intervals.js' +import createDate from '../../src/utils/createDate.js' test('return aggregation', (t) => { - const result = aggregateDurations(uuid(), intervals.INTERVALS_DAILY, 14, createDate()) +const result = aggregateDurations(uuid(), INTERVALS_DAILY, 14, createDate()) - t.true(Array.isArray(result)) -}) \ No newline at end of file +t.true(Array.isArray(result)) +}) diff --git a/test/aggregations/aggregateNewFields.js b/test/aggregations/aggregateNewFields.js index 58972edf8..016ef8ad6 100644 --- a/test/aggregations/aggregateNewFields.js +++ b/test/aggregations/aggregateNewFields.js @@ -1,12 +1,10 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const aggregateNewRecords = require('../../src/aggregations/aggregateNewRecords') +import aggregateNewRecords from '../../src/aggregations/aggregateNewRecords.js' test('return aggregation', (t) => { - const result = aggregateNewRecords(uuid(), [ 'siteReferrer' ]) +const result = aggregateNewRecords(uuid(), [ 'siteReferrer' ]) - t.true(Array.isArray(result)) -}) \ No newline at end of file +t.true(Array.isArray(result)) +}) diff --git a/test/aggregations/aggregateRecentFields.js b/test/aggregations/aggregateRecentFields.js index 5e946028a..41fc0579b 100644 --- a/test/aggregations/aggregateRecentFields.js +++ b/test/aggregations/aggregateRecentFields.js @@ -1,12 +1,10 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const aggregateRecentRecords = require('../../src/aggregations/aggregateRecentRecords') +import aggregateRecentRecords from '../../src/aggregations/aggregateRecentRecords.js' test('return aggregation', (t) => { - const result = aggregateRecentRecords(uuid(), [ 'osName', 'osVersion' ]) +const result = aggregateRecentRecords(uuid(), [ 'osName', 'osVersion' ]) - t.true(Array.isArray(result)) -}) \ No newline at end of file +t.true(Array.isArray(result)) +}) diff --git a/test/aggregations/aggregateTopFields.js b/test/aggregations/aggregateTopFields.js index 87da2caf1..acf81661c 100644 --- a/test/aggregations/aggregateTopFields.js +++ b/test/aggregations/aggregateTopFields.js @@ -1,13 +1,11 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const aggregateTopRecords = require('../../src/aggregations/aggregateTopRecords') -const createDate = require('../../src/utils/createDate') +import aggregateTopRecords from '../../src/aggregations/aggregateTopRecords.js' +import createDate from '../../src/utils/createDate.js' test('return aggregation', (t) => { - const result = aggregateTopRecords(uuid(), [ 'osName', 'osVersion' ], createDate()) +const result = aggregateTopRecords(uuid(), [ 'osName', 'osVersion' ], createDate()) - t.true(Array.isArray(result)) -}) \ No newline at end of file +t.true(Array.isArray(result)) +}) diff --git a/test/aggregations/aggregateViews.js b/test/aggregations/aggregateViews.js index 56b89b344..8fe699eac 100644 --- a/test/aggregations/aggregateViews.js +++ b/test/aggregations/aggregateViews.js @@ -1,20 +1,18 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const aggregateViews = require('../../src/aggregations/aggregateViews') -const intervals = require('../../src/constants/intervals') -const createDate = require('../../src/utils/createDate') +import aggregateViews from '../../src/aggregations/aggregateViews.js' +import { INTERVALS_DAILY } from '../../src/constants/intervals.js' +import createDate from '../../src/utils/createDate.js' test('return unique aggregation', (t) => { - const result = aggregateViews(uuid(), true, intervals.INTERVALS_DAILY, 14, createDate()) +const result = aggregateViews(uuid(), true, INTERVALS_DAILY, 14, createDate()) - t.true(Array.isArray(result)) +t.true(Array.isArray(result)) }) test('return non-unique aggregation', (t) => { - const result = aggregateViews(uuid(), false, intervals.INTERVALS_DAILY, 14, createDate()) +const result = aggregateViews(uuid(), false, INTERVALS_DAILY, 14, createDate()) - t.true(Array.isArray(result)) -}) \ No newline at end of file +t.true(Array.isArray(result)) +}) diff --git a/test/constants/browsers.js b/test/constants/browsers.js index 6f9cd7b51..dd873169d 100644 --- a/test/constants/browsers.js +++ b/test/constants/browsers.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const browsers = require('../../src/constants/browsers') +import test from 'ava' + +import * as browsers from '../../src/constants/browsers.js' test('is an object', (t) => { t.is(typeof browsers, 'object') diff --git a/test/constants/devices.js b/test/constants/devices.js index a61dad0b9..ddd039fec 100644 --- a/test/constants/devices.js +++ b/test/constants/devices.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const devices = require('../../src/constants/devices') +import test from 'ava' + +import * as devices from '../../src/constants/devices.js' test('is an object', (t) => { t.is(typeof devices, 'object') diff --git a/test/constants/durations.js b/test/constants/durations.js index 4020cbbbf..d3167cb68 100644 --- a/test/constants/durations.js +++ b/test/constants/durations.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const durations = require('../../src/constants/durations') +import test from 'ava' + +import * as durations from '../../src/constants/durations.js' test('is an object', (t) => { t.is(typeof durations, 'object') diff --git a/test/constants/intervals.js b/test/constants/intervals.js index 58d1e9d23..a9166d46c 100644 --- a/test/constants/intervals.js +++ b/test/constants/intervals.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const intervals = require('../../src/constants/intervals') +import test from 'ava' + +import * as intervals from '../../src/constants/intervals.js' test('is an object', (t) => { t.is(typeof intervals, 'object') diff --git a/test/constants/ranges.js b/test/constants/ranges.js index 64f63be88..09307e351 100644 --- a/test/constants/ranges.js +++ b/test/constants/ranges.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const ranges = require('../../src/constants/ranges') +import test from 'ava' + +import * as ranges from '../../src/constants/ranges.js' test('is an object', (t) => { t.true(typeof ranges === 'object') diff --git a/test/constants/referrers.js b/test/constants/referrers.js index 341945c1f..76bde3666 100644 --- a/test/constants/referrers.js +++ b/test/constants/referrers.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const referrers = require('../../src/constants/referrers') +import test from 'ava' + +import * as referrers from '../../src/constants/referrers.js' test('is an object', (t) => { t.is(typeof referrers, 'object') diff --git a/test/constants/sizes.js b/test/constants/sizes.js index 8f7412eb1..1dd83a95d 100644 --- a/test/constants/sizes.js +++ b/test/constants/sizes.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const sizes = require('../../src/constants/sizes') +import test from 'ava' + +import * as sizes from '../../src/constants/sizes.js' test('is an object', (t) => { t.is(typeof sizes, 'object') diff --git a/test/constants/sortings.js b/test/constants/sortings.js index beec35d8d..85fc5e7b5 100644 --- a/test/constants/sortings.js +++ b/test/constants/sortings.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const sortings = require('../../src/constants/sortings') +import test from 'ava' + +import * as sortings from '../../src/constants/sortings.js' test('is an object', (t) => { t.is(typeof sortings, 'object') diff --git a/test/constants/systems.js b/test/constants/systems.js index dd0628f85..58230a840 100644 --- a/test/constants/systems.js +++ b/test/constants/systems.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const systems = require('../../src/constants/systems') +import test from 'ava' + +import * as systems from '../../src/constants/systems.js' test('is an object', (t) => { t.is(typeof systems, 'object') diff --git a/test/constants/views.js b/test/constants/views.js index 347568f3d..16ffe113f 100644 --- a/test/constants/views.js +++ b/test/constants/views.js @@ -1,8 +1,8 @@ -'use strict' -const test = require('ava') -const views = require('../../src/constants/views') +import test from 'ava' + +import * as views from '../../src/constants/views.js' test('is an object', (t) => { t.is(typeof views, 'object') diff --git a/test/resolvers/_utils.js b/test/resolvers/_utils.js index cba91bf36..893cd45b3 100644 --- a/test/resolvers/_utils.js +++ b/test/resolvers/_utils.js @@ -1,109 +1,107 @@ -'use strict' - -const { MongoMemoryServer } = require('mongodb-memory-server') -const mongoose = require('mongoose') - -const Token = require('../../src/models/Token') -const PermanentToken = require('../../src/models/PermanentToken') -const Domain = require('../../src/models/Domain') -const Event = require('../../src/models/Event') -const Record = require('../../src/models/Record') -const Action = require('../../src/models/Action') -const connect = require('../../src/utils/connect') -const createArray = require('../../src/utils/createArray') -const { day, minute } = require('../../src/utils/times') +import { MongoMemoryServer } from 'mongodb-memory-server' +import mongoose from 'mongoose' + +import Token from '../../src/models/Token.js' +import PermanentToken from '../../src/models/PermanentToken.js' +import Domain from '../../src/models/Domain.js' +import Event from '../../src/models/Event.js' +import Record from '../../src/models/Record.js' +import Action from '../../src/models/Action.js' +import connect from '../../src/utils/connect.js' +import createArray from '../../src/utils/createArray.js' +import { day, minute } from '../../src/utils/times.js' const mongoDb = MongoMemoryServer.create() const connectToDatabase = async () => { - const dbUrl = (await mongoDb).getUri() - return connect(dbUrl) +const dbUrl = (await mongoDb).getUri() +return connect(dbUrl) } const fillDatabase = async (t) => { - // Saves to context so tests can access ids - t.context.token = await Token.create({}) - t.context.permanentToken = await PermanentToken.create({ title: 'Example' }) - t.context.domain = await Domain.create({ title: 'Example' }) - t.context.event = await Event.create({ title: 'Example', type: 'TOTAL_CHART' }) - - const now = Date.now() - - const records = createArray(14).map((item, index) => ({ - clientId: `client-${ index }`, - domainId: t.context.domain.id, - siteLocation: 'https://example.com/', - siteReferrer: 'https://google.com/', - siteLanguage: 'en', - source: index > 4 ? 'Newsletter' : undefined, - screenWidth: index === 1 ? 0 : 414, - screenHeight: index === 1 ? 0 : 896, - screenColorDepth: 32, - deviceName: 'iPhone', - deviceManufacturer: 'Apple', - osName: 'iOS', - osVersion: index > 7 ? '13.0' : '14.0', - browserName: 'Safari', - browserVersion: index > 7 ? '13.0' : '14.0', - browserWidth: index === 1 ? 0 : 414, - browserHeight: index === 1 ? 0 : 719, - // Set fake duration - created: now - index * day - minute, - updated: now - index * day, - })) - - const actions = createArray(14).map((item, index) => ({ - eventId: t.context.event.id, - key: `Key ${ index + 1 }`, - value: index + 1, - created: now - index * day, - updated: now - index * day, - })) - - await Record.insertMany(records) - await Action.insertMany(actions) +// Saves to context so tests can access ids +t.context.token = await Token.create({}) +t.context.permanentToken = await PermanentToken.create({ title: 'Example' }) +t.context.domain = await Domain.create({ title: 'Example' }) +t.context.event = await Event.create({ title: 'Example', type: 'TOTAL_CHART' }) + +const now = Date.now() + +const records = createArray(14).map((item, index) => ({ +clientId: `client-${ index }`, +domainId: t.context.domain.id, +siteLocation: 'https://example.com/', +siteReferrer: 'https://google.com/', +siteLanguage: 'en', +source: index > 4 ? 'Newsletter' : undefined, +screenWidth: index === 1 ? 0 : 414, +screenHeight: index === 1 ? 0 : 896, +screenColorDepth: 32, +deviceName: 'iPhone', +deviceManufacturer: 'Apple', +osName: 'iOS', +osVersion: index > 7 ? '13.0' : '14.0', +browserName: 'Safari', +browserVersion: index > 7 ? '13.0' : '14.0', +browserWidth: index === 1 ? 0 : 414, +browserHeight: index === 1 ? 0 : 719, +// Set fake duration +created: now - index * day - minute, +updated: now - index * day, +})) + +const actions = createArray(14).map((item, index) => ({ +eventId: t.context.event.id, +key: `Key ${ index + 1 }`, +value: index + 1, +created: now - index * day, +updated: now - index * day, +})) + +await Record.insertMany(records) +await Action.insertMany(actions) } const cleanupDatabase = async (t) => { - await Token.findOneAndDelete({ - id: t.context.token.id, - }) - await Domain.findOneAndDelete({ - id: t.context.domain.id, - }) +await Token.findOneAndDelete({ +id: t.context.token.id, +}) +await Domain.findOneAndDelete({ +id: t.context.domain.id, +}) } const disconnectFromDatabase = async () => { - mongoose.disconnect() - ;(await mongoDb).stop() +mongoose.disconnect() +;(await mongoDb).stop() } const api = async (base, body, token, headers = {}) => { - const url = new URL('/api', await base) - - const defaultHeaders = {} - defaultHeaders['Content-Type'] = 'application/json' - defaultHeaders['Authorization'] = token == null ? undefined : `Bearer ${ token }` - - const result = await fetch(url.href, { - method: 'post', - body: JSON.stringify(body), - headers: { - ...defaultHeaders, - ...headers, - }, - }) - - return { - headers: result.headers, - json: await result.json(), - } +const url = new URL('/api', await base) + +const defaultHeaders = {} +defaultHeaders['Content-Type'] = 'application/json' +defaultHeaders['Authorization'] = token == null ? undefined : `Bearer ${ token }` + +const result = await fetch(url.href, { +method: 'post', +body: JSON.stringify(body), +headers: { +...defaultHeaders, +...headers, +}, +}) + +return { +headers: result.headers, +json: await result.json(), +} } -module.exports = { - connectToDatabase, - fillDatabase, - cleanupDatabase, - disconnectFromDatabase, - api, -} \ No newline at end of file +export { +connectToDatabase, +fillDatabase, +cleanupDatabase, +disconnectFromDatabase, +api, +} diff --git a/test/resolvers/actions.js b/test/resolvers/actions.js index 4b3efe8f1..14c3a9acb 100644 --- a/test/resolvers/actions.js +++ b/test/resolvers/actions.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const listen = require('test-listen') -const uuid = require('crypto').randomUUID - -const server = require('../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') +import server from '../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/_utils.js b/test/resolvers/domainStatistics/_utils.js index c17fed59a..363aecf33 100644 --- a/test/resolvers/domainStatistics/_utils.js +++ b/test/resolvers/domainStatistics/_utils.js @@ -1,6 +1,4 @@ -'use strict' - -const { api } = require('../_utils') +import { api } from '../_utils.js' const getStats = async ({ base, token, domainId, fragment }) => { const body = { @@ -28,6 +26,4 @@ const getStats = async ({ base, token, domainId, fragment }) => { return json.data.domain.statistics } -module.exports = { - getStats, -} \ No newline at end of file +export { getStats } \ No newline at end of file diff --git a/test/resolvers/domainStatistics/browsers.js b/test/resolvers/domainStatistics/browsers.js index ee97593cc..8494cae3f 100644 --- a/test/resolvers/domainStatistics/browsers.js +++ b/test/resolvers/domainStatistics/browsers.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/devices.js b/test/resolvers/domainStatistics/devices.js index b40019297..043e18592 100644 --- a/test/resolvers/domainStatistics/devices.js +++ b/test/resolvers/domainStatistics/devices.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/durations.js b/test/resolvers/domainStatistics/durations.js index 2e48480e0..59e6d7c19 100644 --- a/test/resolvers/domainStatistics/durations.js +++ b/test/resolvers/domainStatistics/durations.js @@ -1,12 +1,10 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { minute } = require('../../../src/utils/times') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { minute } from '../../../src/utils/times.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/languages.js b/test/resolvers/domainStatistics/languages.js index ddc4acb44..818c7192b 100644 --- a/test/resolvers/domainStatistics/languages.js +++ b/test/resolvers/domainStatistics/languages.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/pages.js b/test/resolvers/domainStatistics/pages.js index 9af770da5..390573852 100644 --- a/test/resolvers/domainStatistics/pages.js +++ b/test/resolvers/domainStatistics/pages.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/referrers.js b/test/resolvers/domainStatistics/referrers.js index 7a9497c9e..aeb2ed56c 100644 --- a/test/resolvers/domainStatistics/referrers.js +++ b/test/resolvers/domainStatistics/referrers.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/sizes.js b/test/resolvers/domainStatistics/sizes.js index f784e7693..d92b9685f 100644 --- a/test/resolvers/domainStatistics/sizes.js +++ b/test/resolvers/domainStatistics/sizes.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/systems.js b/test/resolvers/domainStatistics/systems.js index cc29af97f..d65b3df80 100644 --- a/test/resolvers/domainStatistics/systems.js +++ b/test/resolvers/domainStatistics/systems.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domainStatistics/views.js b/test/resolvers/domainStatistics/views.js index bc2acbd0d..8b4c12fab 100644 --- a/test/resolvers/domainStatistics/views.js +++ b/test/resolvers/domainStatistics/views.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/domains.js b/test/resolvers/domains.js index f4d736c89..c96bf489a 100644 --- a/test/resolvers/domains.js +++ b/test/resolvers/domains.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const listen = require('test-listen') -const uuid = require('crypto').randomUUID - -const server = require('../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') +import server from '../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/eventStatistics/_utils.js b/test/resolvers/eventStatistics/_utils.js index cb5f0e0f8..b29e6318d 100644 --- a/test/resolvers/eventStatistics/_utils.js +++ b/test/resolvers/eventStatistics/_utils.js @@ -1,6 +1,4 @@ -'use strict' - -const { api } = require('../_utils') +import { api } from '../_utils.js' const getStats = async ({ base, token, eventId, fragment }) => { const body = { @@ -28,6 +26,4 @@ const getStats = async ({ base, token, eventId, fragment }) => { return json.data.event.statistics } -module.exports = { - getStats, -} \ No newline at end of file +export { getStats } \ No newline at end of file diff --git a/test/resolvers/eventStatistics/chart.js b/test/resolvers/eventStatistics/chart.js index a92eeee28..46670eae4 100644 --- a/test/resolvers/eventStatistics/chart.js +++ b/test/resolvers/eventStatistics/chart.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/eventStatistics/list.js b/test/resolvers/eventStatistics/list.js index 6d5a2df0f..d99e66b85 100644 --- a/test/resolvers/eventStatistics/list.js +++ b/test/resolvers/eventStatistics/list.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } = require('../_utils') -const { getStats } = require('./_utils') +import server from '../../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase } from '../_utils.js' +import { getStats } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/events.js b/test/resolvers/events.js index f6701107d..08dd4ec97 100644 --- a/test/resolvers/events.js +++ b/test/resolvers/events.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const listen = require('test-listen') -const uuid = require('crypto').randomUUID - -const server = require('../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') +import server from '../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/facts.js b/test/resolvers/facts.js index 082f273e1..1f230c7a2 100644 --- a/test/resolvers/facts.js +++ b/test/resolvers/facts.js @@ -1,10 +1,8 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') +import server from '../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/permanentTokens.js b/test/resolvers/permanentTokens.js index d3abbd4ec..a16aa2fbb 100644 --- a/test/resolvers/permanentTokens.js +++ b/test/resolvers/permanentTokens.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const listen = require('test-listen') -const uuid = require('crypto').randomUUID - -const server = require('../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') +import server from '../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/records.js b/test/resolvers/records.js index 115d0aa5f..534bae40c 100644 --- a/test/resolvers/records.js +++ b/test/resolvers/records.js @@ -1,10 +1,8 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' -const test = require('ava') -const listen = require('test-listen') - -const server = require('../../src/server') -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') +import server from '../../src/server.js' +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' const base = listen(server) diff --git a/test/resolvers/tokens.js b/test/resolvers/tokens.js index 7ec26e836..d930b51c9 100644 --- a/test/resolvers/tokens.js +++ b/test/resolvers/tokens.js @@ -1,11 +1,9 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const mockedEnv = require('mocked-env') - -const { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } = require('./_utils') -const server = require('../../src/server') +import { connectToDatabase, fillDatabase, cleanupDatabase, disconnectFromDatabase, api } from './_utils.js' +import server from '../../src/server.js' const base = listen(server) diff --git a/test/server.js b/test/server.js index 52372be54..e89fec716 100644 --- a/test/server.js +++ b/test/server.js @@ -1,50 +1,48 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' +import listen from 'test-listen' -const test = require('ava') -const uuid = require('crypto').randomUUID -const listen = require('test-listen') - -const server = require('../src/server') +import server from '../src/server.js' const base = listen(server) test('return 404', async (t) => { - const url = new URL(`/${ uuid() }`, await base) - const { status } = await fetch(url.href) +const url = new URL(`/${ uuid() }`, await base) +const { status } = await fetch(url.href) - t.is(status, 404) +t.is(status, 404) }) test('return production styles', async (t) => { - const url = new URL('/index.css', await base) - const response = await fetch(url.href) - const content = await response.text() +const url = new URL('/index.css', await base) +const response = await fetch(url.href) +const content = await response.text() - t.is(typeof content, 'string') - t.false(content.includes('sourceMappingURL')) +t.is(typeof content, 'string') +t.false(content.includes('sourceMappingURL')) }) test('return production scripts', async (t) => { - const url = new URL('/index.js', await base) - const response = await fetch(url.href) - const content = await response.text() +const url = new URL('/index.js', await base) +const response = await fetch(url.href) +const content = await response.text() - t.is(typeof content, 'string') - t.false(content.includes('sourceMappingURL')) +t.is(typeof content, 'string') +t.false(content.includes('sourceMappingURL')) }) test('return tracker', async (t) => { - const url = new URL('/tracker.js', await base) - const response = await fetch(url.href) - const content = await response.text() +const url = new URL('/tracker.js', await base) +const response = await fetch(url.href) +const content = await response.text() - t.is(typeof content, 'string') - t.false(content.includes('sourceMappingURL')) +t.is(typeof content, 'string') +t.false(content.includes('sourceMappingURL')) }) test('return favicon', async (t) => { - const url = new URL('/favicon.ico', await base) - const { status } = await fetch(url.href) +const url = new URL('/favicon.ico', await base) +const { status } = await fetch(url.href) - t.is(status, 200) -}) \ No newline at end of file +t.is(status, 200) +}) diff --git a/test/serverWithAutoCors.js b/test/serverWithAutoCors.js index 532ff4f07..a7e5c2366 100644 --- a/test/serverWithAutoCors.js +++ b/test/serverWithAutoCors.js @@ -1,48 +1,44 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const fetch = require('node-fetch') -const mockedEnv = require('mocked-env') - -const server = require('../src/server') - -const Domain = require('../src/models/Domain') -const { connectToDatabase, disconnectFromDatabase } = require('./resolvers/_utils') +import server from '../src/server.js' +import Domain from '../src/models/Domain.js' +import { connectToDatabase, disconnectFromDatabase } from './resolvers/_utils.js' const base = listen(server) test.before(connectToDatabase) test.after.always(disconnectFromDatabase) test.beforeEach(async (t) => { - t.context.domain1 = await Domain.create({ title: 'fqdn.example.com' }) - t.context.domain2 = await Domain.create({ title: 'No fqdn' }) +t.context.domain1 = await Domain.create({ title: 'fqdn.example.com' }) +t.context.domain2 = await Domain.create({ title: 'No fqdn' }) }) test.afterEach.always(async (t) => { - await Domain.findOneAndDelete({ id: t.context.domain1.id }) - await Domain.findOneAndDelete({ id: t.context.domain2.id }) +await Domain.findOneAndDelete({ id: t.context.domain1.id }) +await Domain.findOneAndDelete({ id: t.context.domain2.id }) }) test('return cors headers based on fully qualifed domain names', async (t) => { - const url = new URL('/api', await base) +const url = new URL('/api', await base) - const restore = mockedEnv({ - ACKEE_AUTO_ORIGIN: 'true', - }) +const restore = mockedEnv({ +ACKEE_AUTO_ORIGIN: 'true', +}) - const { headers: fqdnHeaders } = await fetch(url.href, { headers: { Host: 'fqdn.example.com' } }) +const { headers: fqdnHeaders } = await fetch(url.href, { headers: { Host: 'fqdn.example.com' } }) - t.is(fqdnHeaders.get('Access-Control-Allow-Origin'), 'fqdn.example.com') - t.is(fqdnHeaders.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') - t.is(fqdnHeaders.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') - t.is(fqdnHeaders.get('Access-Control-Allow-Credentials'), 'true') +t.is(fqdnHeaders.get('Access-Control-Allow-Origin'), 'fqdn.example.com') +t.is(fqdnHeaders.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') +t.is(fqdnHeaders.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') +t.is(fqdnHeaders.get('Access-Control-Allow-Credentials'), 'true') - const { headers: noFqdnHeaders } = await fetch(url.href, { headers: { Host: 'No fqdn' } }) +const { headers: noFqdnHeaders } = await fetch(url.href, { headers: { Host: 'No fqdn' } }) - t.is(noFqdnHeaders.get('Access-Control-Allow-Origin'), null) - t.is(noFqdnHeaders.get('Access-Control-Allow-Methods'), null) - t.is(noFqdnHeaders.get('Access-Control-Allow-Headers'), null) - t.is(noFqdnHeaders.get('Access-Control-Allow-Credentials'), null) +t.is(noFqdnHeaders.get('Access-Control-Allow-Origin'), null) +t.is(noFqdnHeaders.get('Access-Control-Allow-Methods'), null) +t.is(noFqdnHeaders.get('Access-Control-Allow-Headers'), null) +t.is(noFqdnHeaders.get('Access-Control-Allow-Credentials'), null) - restore() -}) \ No newline at end of file +restore() +}) diff --git a/test/serverWithCors.js b/test/serverWithCors.js index 5a751572a..80107386c 100644 --- a/test/serverWithCors.js +++ b/test/serverWithCors.js @@ -1,27 +1,25 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const mockedEnv = require('mocked-env') - -const server = require('../src/server') +import server from '../src/server.js' const base = listen(server) test('return cors headers if env var specifies one', async (t) => { - const url = new URL('/api', await base) +const url = new URL('/api', await base) - const restore = mockedEnv({ - ACKEE_ALLOW_ORIGIN: url.origin, - }) +const restore = mockedEnv({ +ACKEE_ALLOW_ORIGIN: url.origin, +}) - const { headers } = await fetch(url.href) +const { headers } = await fetch(url.href) - t.is(headers.get('Access-Control-Allow-Origin'), url.origin) - t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') - t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') - t.is(headers.get('Access-Control-Allow-Credentials'), 'true') - t.is(headers.get('Access-Control-Max-Age'), '3600') +t.is(headers.get('Access-Control-Allow-Origin'), url.origin) +t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') +t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') +t.is(headers.get('Access-Control-Allow-Credentials'), 'true') +t.is(headers.get('Access-Control-Max-Age'), '3600') - restore() -}) \ No newline at end of file +restore() +}) diff --git a/test/serverWithMultipleCors.js b/test/serverWithMultipleCors.js index c6e6cb9d5..db6ce4a67 100644 --- a/test/serverWithMultipleCors.js +++ b/test/serverWithMultipleCors.js @@ -1,27 +1,25 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const mockedEnv = require('mocked-env') - -const server = require('../src/server') +import server from '../src/server.js' const base = listen(server) test('return cors headers with corresponding origin if env var specifies multiple origins', async (t) => { - const url = new URL('/api', await base) +const url = new URL('/api', await base) - const restore = mockedEnv({ - ACKEE_ALLOW_ORIGIN: `https://example.com,${ url.origin }`, - }) +const restore = mockedEnv({ +ACKEE_ALLOW_ORIGIN: `https://example.com,${ url.origin }`, +}) - const { headers } = await fetch(url.href) +const { headers } = await fetch(url.href) - t.is(headers.get('Access-Control-Allow-Origin'), url.origin) - t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') - t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') - t.is(headers.get('Access-Control-Allow-Credentials'), 'true') - t.is(headers.get('Access-Control-Max-Age'), '3600') +t.is(headers.get('Access-Control-Allow-Origin'), url.origin) +t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') +t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') +t.is(headers.get('Access-Control-Allow-Credentials'), 'true') +t.is(headers.get('Access-Control-Max-Age'), '3600') - restore() -}) \ No newline at end of file +restore() +}) diff --git a/test/serverWithUnlistedCors.js b/test/serverWithUnlistedCors.js index f8e814ad4..09391d97f 100644 --- a/test/serverWithUnlistedCors.js +++ b/test/serverWithUnlistedCors.js @@ -1,27 +1,25 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const mockedEnv = require('mocked-env') - -const server = require('../src/server') +import server from '../src/server.js' const base = listen(server) test('return cors headers with no origin if hostname not whitelisted in env var', async (t) => { - const url = new URL('/api', await base) +const url = new URL('/api', await base) - const restore = mockedEnv({ - ACKEE_ALLOW_ORIGIN: 'https://example.com', - }) +const restore = mockedEnv({ +ACKEE_ALLOW_ORIGIN: 'https://example.com', +}) - const { headers } = await fetch(url.href) +const { headers } = await fetch(url.href) - t.is(headers.get('Access-Control-Allow-Origin'), null) - t.is(headers.get('Access-Control-Allow-Methods'), null) - t.is(headers.get('Access-Control-Allow-Headers'), null) - t.is(headers.get('Access-Control-Allow-Credentials'), null) - t.is(headers.get('Access-Control-Max-Age'), null) +t.is(headers.get('Access-Control-Allow-Origin'), null) +t.is(headers.get('Access-Control-Allow-Methods'), null) +t.is(headers.get('Access-Control-Allow-Headers'), null) +t.is(headers.get('Access-Control-Allow-Credentials'), null) +t.is(headers.get('Access-Control-Max-Age'), null) - restore() -}) \ No newline at end of file +restore() +}) diff --git a/test/serverWithWildcardCors.js b/test/serverWithWildcardCors.js index c59364ba0..4383f84b1 100644 --- a/test/serverWithWildcardCors.js +++ b/test/serverWithWildcardCors.js @@ -1,27 +1,25 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const mockedEnv = require('mocked-env') - -const server = require('../src/server') +import server from '../src/server.js' const base = listen(server) test('return cors headers if env vars specify wildcard', async (t) => { - const url = new URL('/api', await base) +const url = new URL('/api', await base) - const restore = mockedEnv({ - ACKEE_ALLOW_ORIGIN: '*', - }) +const restore = mockedEnv({ +ACKEE_ALLOW_ORIGIN: '*', +}) - const { headers } = await fetch(url.href) +const { headers } = await fetch(url.href) - t.is(headers.get('Access-Control-Allow-Origin'), '*') - t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') - t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') - t.is(headers.get('Access-Control-Allow-Credentials'), 'true') - t.is(headers.get('Access-Control-Max-Age'), '3600') +t.is(headers.get('Access-Control-Allow-Origin'), '*') +t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') +t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') +t.is(headers.get('Access-Control-Allow-Credentials'), 'true') +t.is(headers.get('Access-Control-Max-Age'), '3600') - restore() -}) \ No newline at end of file +restore() +}) diff --git a/test/serverWithoutCors.js b/test/serverWithoutCors.js index 360ac600a..9f80d8f12 100644 --- a/test/serverWithoutCors.js +++ b/test/serverWithoutCors.js @@ -1,27 +1,25 @@ -'use strict' +import test from 'ava' +import listen from 'test-listen' +import mockedEnv from 'mocked-env' -const test = require('ava') -const listen = require('test-listen') -const mockedEnv = require('mocked-env') - -const server = require('../src/server') +import server from '../src/server.js' const base = listen(server) test('return no cors headers if env var specifies none', async (t) => { - const url = new URL('/api', await base) +const url = new URL('/api', await base) - const restore = mockedEnv({ - ACKEE_ALLOW_ORIGIN: undefined, - }) +const restore = mockedEnv({ +ACKEE_ALLOW_ORIGIN: undefined, +}) - const { headers } = await fetch(url.href) +const { headers } = await fetch(url.href) - t.is(headers.get('Access-Control-Allow-Origin'), null) - t.is(headers.get('Access-Control-Allow-Methods'), null) - t.is(headers.get('Access-Control-Allow-Headers'), null) - t.is(headers.get('Access-Control-Allow-Credentials'), null) - t.is(headers.get('Access-Control-Max-Age'), null) +t.is(headers.get('Access-Control-Allow-Origin'), null) +t.is(headers.get('Access-Control-Allow-Methods'), null) +t.is(headers.get('Access-Control-Allow-Headers'), null) +t.is(headers.get('Access-Control-Allow-Credentials'), null) +t.is(headers.get('Access-Control-Max-Age'), null) - restore() -}) \ No newline at end of file +restore() +}) diff --git a/test/utils/createArray.js b/test/utils/createArray.js index e38af13b0..ef7496ff2 100644 --- a/test/utils/createArray.js +++ b/test/utils/createArray.js @@ -1,13 +1,11 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const createArray = require('../../src/utils/createArray') +import createArray from '../../src/utils/createArray.js' test('return boolean', (t) => { - const length = 4 - const result = createArray(length) +const length = 4 +const result = createArray(length) - t.true(Array.isArray(result)) - t.is(result.length, length) -}) \ No newline at end of file +t.true(Array.isArray(result)) +t.is(result.length, length) +}) diff --git a/test/utils/customTrackerUrl.js b/test/utils/customTrackerUrl.js index cd4323524..43922b5a2 100644 --- a/test/utils/customTrackerUrl.js +++ b/test/utils/customTrackerUrl.js @@ -1,25 +1,23 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const customTracker = require('../../src/utils/customTracker') +import * as customTracker from '../../src/utils/customTracker.js' test('return that a custom tracker exists', (t) => { - const result = customTracker.exists +const result = customTracker.exists - t.true(result) +t.true(result) }) test('return custom URL', (t) => { - const result = customTracker.url +const result = customTracker.url - // The name is specified in the package.json ava configuration - t.is(result, `/custom%20name.js`) +// The name is specified in the package.json ava configuration +t.is(result, `/custom%20name.js`) }) test('return custom path', (t) => { - const result = customTracker.path +const result = customTracker.path - // The name is specified in the package.json ava configuration - t.is(result, `custom name.js`) -}) \ No newline at end of file +// The name is specified in the package.json ava configuration +t.is(result, `custom name.js`) +}) diff --git a/test/utils/identifier.js b/test/utils/identifier.js index b5ebcf80a..6e5c25b8f 100644 --- a/test/utils/identifier.js +++ b/test/utils/identifier.js @@ -1,45 +1,43 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const identifier = require('../../src/utils/identifier') +import identifier from '../../src/utils/identifier.js' test('return different identifiers', (t) => { - const domainId = uuid() - - const request = () => ({ - headers: { - 'user-agent': uuid(), - }, - connection: { - remoteAddress: uuid(), - }, - }) +const domainId = uuid() + +const request = () => ({ +headers: { +'user-agent': uuid(), +}, +connection: { +remoteAddress: uuid(), +}, +}) - const requestA = request() - const requestB = request() +const requestA = request() +const requestB = request() - const a = identifier(requestA, requestA.headers['user-agent'], domainId) - const b = identifier(requestB, requestB.headers['user-agent'], domainId) +const a = identifier(requestA, requestA.headers['user-agent'], domainId) +const b = identifier(requestB, requestB.headers['user-agent'], domainId) - t.not(a, b) +t.not(a, b) }) test('return same identifiers', (t) => { - const domainId = uuid() - - const request = { - headers: { - 'user-agent': uuid(), - }, - connection: { - remoteAddress: uuid(), - }, - } - - const a = identifier(request, request.headers['user-agent'], domainId) - const b = identifier(request, request.headers['user-agent'], domainId) - - t.is(a, b) -}) \ No newline at end of file +const domainId = uuid() + +const request = { +headers: { +'user-agent': uuid(), +}, +connection: { +remoteAddress: uuid(), +}, +} + +const a = identifier(request, request.headers['user-agent'], domainId) +const b = identifier(request, request.headers['user-agent'], domainId) + +t.is(a, b) +}) diff --git a/test/utils/isExpired.js b/test/utils/isExpired.js index 73bae24fa..1605d2a4c 100644 --- a/test/utils/isExpired.js +++ b/test/utils/isExpired.js @@ -1,24 +1,22 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const { day } = require('../../src/utils/times') -const isExpired = require('../../src/utils/isExpired') +import { day } from '../../src/utils/times.js' +import isExpired from '../../src/utils/isExpired.js' test('return true when `timestamp` has expired', (t) => { - const date = new Date() - date.setDate(date.getDate() - 2) - const timestamp = date.getTime() +const date = new Date() +date.setDate(date.getDate() - 2) +const timestamp = date.getTime() - const result = isExpired(timestamp, day) +const result = isExpired(timestamp, day) - t.true(result) +t.true(result) }) test('return false when `timestamp` is valid', (t) => { - const timestamp = Date.now() +const timestamp = Date.now() - const result = isExpired(timestamp, day) +const result = isExpired(timestamp, day) - t.false(result) -}) \ No newline at end of file +t.false(result) +}) diff --git a/test/utils/layout.js b/test/utils/layout.js index 8dd29e3b7..c106bacaf 100644 --- a/test/utils/layout.js +++ b/test/utils/layout.js @@ -1,36 +1,34 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const layout = require('../../src/utils/layout') +import layout from '../../src/utils/layout.js' test('return HTML with body', (t) => { - const body = uuid() - const result = layout(body, '', [], []) +const body = uuid() +const result = layout(body, '', [], []) - t.true(result.includes(body)) +t.true(result.includes(body)) }) test('return HTML with favicon', (t) => { - const favicon = uuid() - const result = layout('', favicon, [], []) +const favicon = uuid() +const result = layout('', favicon, [], []) - t.true(result.includes(favicon)) +t.true(result.includes(favicon)) }) test('return HTML with styles', (t) => { - const styles = [ uuid(), uuid() ] - const result = layout('', '', styles, []) +const styles = [ uuid(), uuid() ] +const result = layout('', '', styles, []) - t.true(result.includes(styles[0])) - t.true(result.includes(styles[1])) +t.true(result.includes(styles[0])) +t.true(result.includes(styles[1])) }) test('return HTML with scripts', (t) => { - const scripts = [ uuid(), uuid() ] - const result = layout('', '', [], scripts) +const scripts = [ uuid(), uuid() ] +const result = layout('', '', [], scripts) - t.true(result.includes(scripts[0])) - t.true(result.includes(scripts[1])) -}) \ No newline at end of file +t.true(result.includes(scripts[0])) +t.true(result.includes(scripts[1])) +}) diff --git a/test/utils/messages.js b/test/utils/messages.js index 21bd1a1fb..87e45734e 100644 --- a/test/utils/messages.js +++ b/test/utils/messages.js @@ -1,24 +1,22 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const messages = require('../../src/utils/messages') +import messages from '../../src/utils/messages.js' test('extract messages from an object with errors', (t) => { - const message = uuid() - const errors = { 0: new Error(message) } +const message = uuid() +const errors = { 0: new Error(message) } - const result = messages(errors) +const result = messages(errors) - t.is(result, message) +t.is(result, message) }) test('remove dot at the end of message', (t) => { - const message = uuid() - const errors = { 0: new Error(`${ message }.`) } +const message = uuid() +const errors = { 0: new Error(`${ message }.`) } - const result = messages(errors) +const result = messages(errors) - t.is(result, message) -}) \ No newline at end of file +t.is(result, message) +}) diff --git a/test/utils/normalizeUrl.js b/test/utils/normalizeUrl.js index 8cc9bde40..bb98bffbc 100644 --- a/test/utils/normalizeUrl.js +++ b/test/utils/normalizeUrl.js @@ -1,34 +1,32 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const normalizeUrl = require('../../src/utils/normalizeUrl') +import normalizeUrl from '../../src/utils/normalizeUrl.js' test('remove directory index', (t) => { - const url = 'https://example.com/index.html' - const result = normalizeUrl(url) +const url = 'https://example.com/index.html' +const result = normalizeUrl(url) - t.is(result, 'https://example.com') +t.is(result, 'https://example.com') }) test('remove ref query parameter', (t) => { - const url = `https://example.com/?ref=${ uuid() }` - const result = normalizeUrl(url) +const url = `https://example.com/?ref=${ uuid() }` +const result = normalizeUrl(url) - t.is(result, 'https://example.com') +t.is(result, 'https://example.com') }) test('remove fbclid query parameter', (t) => { - const url = `https://example.com/?fbclid=${ uuid() }` - const result = normalizeUrl(url) +const url = `https://example.com/?fbclid=${ uuid() }` +const result = normalizeUrl(url) - t.is(result, 'https://example.com') +t.is(result, 'https://example.com') }) test('remove source query parameter', (t) => { - const url = `https://example.com/?source=${ uuid() }` - const result = normalizeUrl(url) +const url = `https://example.com/?source=${ uuid() }` +const result = normalizeUrl(url) - t.is(result, 'https://example.com') -}) \ No newline at end of file +t.is(result, 'https://example.com') +}) diff --git a/test/utils/pipe.js b/test/utils/pipe.js index 6d908891e..2c1fdb5be 100644 --- a/test/utils/pipe.js +++ b/test/utils/pipe.js @@ -1,29 +1,27 @@ -'use strict' +import test from 'ava' +import { randomUUID as uuid } from 'crypto' -const test = require('ava') -const uuid = require('crypto').randomUUID - -const pipe = require('../../src/utils/pipe') +import pipe from '../../src/utils/pipe.js' test('return response of first function with a return value', async (t) => { - const _b = uuid() - const _c = uuid() +const _b = uuid() +const _c = uuid() - const a = () => null - const b = () => _b - const c = () => _c +const a = () => null +const b = () => _b +const c = () => _c - const result = await pipe(a, b, c)() +const result = await pipe(a, b, c)() - t.is(result, _b) +t.is(result, _b) }) test('pass parameter to functions in pipe', async (t) => { - const _a = uuid() +const _a = uuid() - const a = (param) => param +const a = (param) => param - const result = await pipe(a)(_a) +const result = await pipe(a)(_a) - t.is(result, _a) -}) \ No newline at end of file +t.is(result, _a) +}) diff --git a/test/utils/salt.js b/test/utils/salt.js index a27313d32..da7f4222c 100644 --- a/test/utils/salt.js +++ b/test/utils/salt.js @@ -1,12 +1,10 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const salt = require('../../src/utils/salt') +import salt from '../../src/utils/salt.js' test('return same result as long as it is the same day', (t) => { - const a = salt() - const b = salt() +const a = salt() +const b = salt() - t.is(a, b) -}) \ No newline at end of file +t.is(a, b) +}) diff --git a/test/utils/signale.js b/test/utils/signale.js index 3f2d798d9..28e5e8f4f 100644 --- a/test/utils/signale.js +++ b/test/utils/signale.js @@ -1,10 +1,10 @@ -'use strict' +import test from 'ava' +import signaleModule from 'signale' -const test = require('ava') -const { Signale } = require('signale') +import signale from '../../src/utils/signale.js' -const signale = require('../../src/utils/signale') +const { Signale } = signaleModule test('is a Signale instance', (t) => { - t.true(signale instanceof Signale) -}) \ No newline at end of file +t.true(signale instanceof Signale) +}) diff --git a/test/utils/stripUrlAuth.js b/test/utils/stripUrlAuth.js index 571ef9f96..3adb8a870 100644 --- a/test/utils/stripUrlAuth.js +++ b/test/utils/stripUrlAuth.js @@ -1,18 +1,16 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const stripUrlAuth = require('../../src/utils/stripUrlAuth') +import stripUrlAuth from '../../src/utils/stripUrlAuth.js' test('remove user and password', (t) => { - const url = 'mongodb://username:password@host:3000/database' - const result = 'mongodb://host:3000/database' +const url = 'mongodb://username:password@host:3000/database' +const result = 'mongodb://host:3000/database' - t.is(stripUrlAuth(url), result) +t.is(stripUrlAuth(url), result) }) test('do nothing without username or password', (t) => { - const url = 'mongodb://host:3000/database' +const url = 'mongodb://host:3000/database' - t.is(stripUrlAuth(url), url) -}) \ No newline at end of file +t.is(stripUrlAuth(url), url) +}) diff --git a/test/utils/timeZone.js b/test/utils/timeZone.js index 62aaf66fc..7b3cd0e60 100644 --- a/test/utils/timeZone.js +++ b/test/utils/timeZone.js @@ -1,10 +1,8 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const timeZone = require('../../src/utils/timeZone') +import timeZone from '../../src/utils/timeZone.js' test('returns timeZone', (t) => { - new Intl.DateTimeFormat(undefined, { timeZone }) - t.pass() -}) \ No newline at end of file +new Intl.DateTimeFormat(undefined, { timeZone }) +t.pass() +}) diff --git a/test/utils/times.js b/test/utils/times.js index 8f0e9ecbe..bc46101ff 100644 --- a/test/utils/times.js +++ b/test/utils/times.js @@ -1,21 +1,19 @@ -'use strict' +import test from 'ava' -const test = require('ava') - -const times = require('../../src/utils/times') +import * as times from '../../src/utils/times.js' test('return one second in milliseconds', (t) => { - t.is(times.second, 1000) +t.is(times.second, 1000) }) test('return one minute in milliseconds', (t) => { - t.is(times.minute, 60000) +t.is(times.minute, 60000) }) test('return one hour in milliseconds', (t) => { - t.is(times.hour, 3600000) +t.is(times.hour, 3600000) }) test('return one day in milliseconds', (t) => { - t.is(times.day, 86400000) -}) \ No newline at end of file +t.is(times.day, 86400000) +}) From e0684744de993d09288c86c18f077807330ede67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:33:59 +0000 Subject: [PATCH 3/6] Fix lint issues: indentation, eol-last, date-fns-tz ESM import, rangeLabel.js Co-authored-by: electerious <499088+electerious@users.noreply.github.com> --- build.js | 8 +- functions/api.js | 2 +- src/database/actions.js | 3 +- src/database/devices.js | 60 +++--- src/database/domains.js | 84 ++++----- src/database/durations.js | 83 ++++---- src/database/events.js | 86 ++++----- src/database/facts.js | 14 +- src/database/languages.js | 44 ++--- src/database/pages.js | 44 ++--- src/database/permanentTokens.js | 84 ++++----- src/database/records.js | 164 ++++++++-------- src/database/referrers.js | 68 +++---- src/database/sizes.js | 108 +++++------ src/database/systems.js | 60 +++--- src/database/tokens.js | 62 +++--- src/database/views.js | 85 +++++---- src/healthcheck.js | 38 ++-- src/index.js | 30 +-- src/resolvers/actions.js | 120 ++++++------ src/resolvers/domainStatistics.js | 96 +++++----- src/resolvers/domains.js | 110 +++++------ src/resolvers/eventStatistics.js | 28 +-- src/resolvers/events.js | 108 +++++------ src/resolvers/facts.js | 136 +++++++------- src/resolvers/permanentTokens.js | 100 +++++----- src/resolvers/records.js | 188 +++++++++---------- src/resolvers/tokens.js | 70 +++---- src/server.js | 161 ++++++++-------- src/serverless.js | 74 ++++---- src/ui/index.js | 69 ++++--- src/ui/scripts/utils/rangeLabel.js | 10 +- src/utils/isAuthenticated.js | 4 +- test/aggregations/aggregateActiveVisitors.js | 6 +- test/aggregations/aggregateDurations.js | 6 +- test/aggregations/aggregateNewFields.js | 6 +- test/aggregations/aggregateRecentFields.js | 6 +- test/aggregations/aggregateTopFields.js | 6 +- test/aggregations/aggregateViews.js | 10 +- test/resolvers/_utils.js | 136 +++++++------- test/server.js | 44 ++--- test/serverWithAutoCors.js | 40 ++-- test/serverWithCors.js | 24 +-- test/serverWithMultipleCors.js | 24 +-- test/serverWithUnlistedCors.js | 24 +-- test/serverWithWildcardCors.js | 24 +-- test/serverWithoutCors.js | 24 +-- test/utils/createArray.js | 10 +- test/utils/customTrackerUrl.js | 18 +- test/utils/identifier.js | 62 +++--- test/utils/isExpired.js | 18 +- test/utils/layout.js | 30 +-- test/utils/messages.js | 18 +- test/utils/normalizeUrl.js | 26 +-- test/utils/pipe.js | 24 +-- test/utils/salt.js | 8 +- test/utils/signale.js | 4 +- test/utils/stripUrlAuth.js | 12 +- test/utils/timeZone.js | 6 +- test/utils/times.js | 10 +- 60 files changed, 1511 insertions(+), 1516 deletions(-) diff --git a/build.js b/build.js index c5fa4e02f..bb4e706f3 100755 --- a/build.js +++ b/build.js @@ -7,11 +7,11 @@ import { index, styles, scripts, tracker, build } from './src/ui/index.js' // Build files that are identical on every installation if (config.isPreBuildMode === true) { -build('dist/index.css', styles) -build('dist/index.js', scripts) -build('dist/tracker.js', tracker) + build('dist/index.css', styles) + build('dist/index.js', scripts) + build('dist/tracker.js', tracker) } // Build files that depend on environment variables build(`dist/index.html`, index) -if (customTracker.exists === true) build(`dist/${ customTracker.path }`, tracker) +if (customTracker.exists === true) build(`dist/${ customTracker.path }`, tracker) \ No newline at end of file diff --git a/functions/api.js b/functions/api.js index 87e65ddec..aead1ccbb 100644 --- a/functions/api.js +++ b/functions/api.js @@ -4,4 +4,4 @@ * See: * - https://docs.netlify.com/functions/overview/ */ -export { handler } from '../src/serverless.js' +export { handler } from '../src/serverless.js' \ No newline at end of file diff --git a/src/database/actions.js b/src/database/actions.js index 2f58a655e..ca8b6cef4 100644 --- a/src/database/actions.js +++ b/src/database/actions.js @@ -1,5 +1,4 @@ -import dateFnsTz from 'date-fns-tz' -const { utcToZonedTime } = dateFnsTz +import { utcToZonedTime } from 'date-fns-tz/esm' import Action from '../models/Action.js' import aggregateTopActions from '../aggregations/aggregateTopActions.js' diff --git a/src/database/devices.js b/src/database/devices.js index 5d9117565..1061c529d 100644 --- a/src/database/devices.js +++ b/src/database/devices.js @@ -7,40 +7,40 @@ import { DEVICES_TYPE_NO_MODEL, DEVICES_TYPE_WITH_MODEL } from '../constants/dev import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { -const aggregation = (() => { -if (type === DEVICES_TYPE_NO_MODEL) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer' ], limit) -} -if (type === DEVICES_TYPE_WITH_MODEL) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer', 'deviceName' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) -} -})() + const aggregation = (() => { + if (type === DEVICES_TYPE_NO_MODEL) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer' ], limit) + } + if (type === DEVICES_TYPE_WITH_MODEL) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'deviceManufacturer', 'deviceName' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'deviceManufacturer', 'deviceName' ], limit) + } + })() -const enhanceId = (id) => { -if (type === DEVICES_TYPE_NO_MODEL) return `${ id.deviceManufacturer }` -if (type === DEVICES_TYPE_WITH_MODEL) return `${ id.deviceManufacturer } ${ id.deviceName }` -} + const enhanceId = (id) => { + if (type === DEVICES_TYPE_NO_MODEL) return `${ id.deviceManufacturer }` + if (type === DEVICES_TYPE_WITH_MODEL) return `${ id.deviceManufacturer } ${ id.deviceName }` + } -const enhance = (entries) => { -return entries.map((entry) => { -const value = enhanceId(entry._id) + const enhance = (entries) => { + return entries.map((entry) => { + const value = enhanceId(entry._id) -return { -id: recursiveId([ value, sorting, type, range, ...ids ]), -value, -count: entry.count, -created: entry.created, -} -}) -} + return { + id: recursiveId([ value, sorting, type, range, ...ids ]), + value, + count: entry.count, + created: entry.created, + } + }) + } -return enhance( + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/domains.js b/src/database/domains.js index a4b4c35c0..55d37131a 100644 --- a/src/database/domains.js +++ b/src/database/domains.js @@ -2,75 +2,75 @@ import Domain from '../models/Domain.js' import sortByProp from '../utils/sortByProp.js' const response = (entry) => ({ -id: entry.id, -title: entry.title, -created: entry.created, -updated: entry.updated, + id: entry.id, + title: entry.title, + created: entry.created, + updated: entry.updated, }) const add = async (data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Domain.create({ -title: data.title, + title: data.title, }), -) + ) } const all = async () => { -const enhance = (entries) => { -return entries -.map(response) -.sort(sortByProp('title')) -} + const enhance = (entries) => { + return entries + .map(response) + .sort(sortByProp('title')) + } -return enhance( + return enhance( await Domain.find({}), -) + ) } const get = async (id) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Domain.findOne({ id }), -) + ) } const update = async (id, data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Domain.findOneAndUpdate({ -id, + id, }, { -$set: { -title: data.title, -updated: Date.now(), -}, + $set: { + title: data.title, + updated: Date.now(), + }, }, { -new: true, + new: true, }), -) + ) } const del = (id) => { -return Domain.findOneAndDelete({ -id, -}) + return Domain.findOneAndDelete({ + id, + }) } export { -add, -all, -get, -update, -del, -} + add, + all, + get, + update, + del, +} \ No newline at end of file diff --git a/src/database/durations.js b/src/database/durations.js index 3aa24e6e0..fe9e2221b 100644 --- a/src/database/durations.js +++ b/src/database/durations.js @@ -1,5 +1,4 @@ -import dateFnsTz from 'date-fns-tz' -const { utcToZonedTime } = dateFnsTz +import { utcToZonedTime } from 'date-fns-tz/esm' import Record from '../models/Record.js' import aggregateDurations from '../aggregations/aggregateDurations.js' @@ -9,50 +8,50 @@ import matchesDate from '../utils/matchesDate.js' import recursiveId from '../utils/recursiveId.js' const get = async (ids, interval, limit, dateDetails) => { -const aggregation = (() => { -return aggregateDurations(ids, interval, limit, dateDetails) -})() - -const enhance = (entries) => { -const matchDay = [ INTERVALS_DAILY ].includes(interval) -const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) -const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) - -return createArray(limit).map((_, index) => { -const date = dateDetails.lastFnByInterval(interval)(index) - -// Database entries include the day, month and year in the -// timezone of the user. We therefore need to match it against a -// date in the timezone of the user. -const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) - -// Find a entry that matches the date -const entry = entries.find((entry) => { -return matchesDate( + const aggregation = (() => { + return aggregateDurations(ids, interval, limit, dateDetails) + })() + + const enhance = (entries) => { + const matchDay = [ INTERVALS_DAILY ].includes(interval) + const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) + const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) + + return createArray(limit).map((_, index) => { + const date = dateDetails.lastFnByInterval(interval)(index) + + // Database entries include the day, month and year in the + // timezone of the user. We therefore need to match it against a + // date in the timezone of the user. + const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) + + // Find a entry that matches the date + const entry = entries.find((entry) => { + return matchesDate( matchDay === true ? entry._id.day : undefined, matchMonth === true ? entry._id.month : undefined, matchYear === true ? entry._id.year : undefined, userZonedDate, -) -}) - -const value = (() => { -if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` -if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` -if (matchYear === true) return `${ date.getFullYear() }` -})() - -return { -id: recursiveId([ value, ...ids ]), -value, -count: entry == null ? 0 : entry.count, -} -}) -} - -return enhance( + ) + }) + + const value = (() => { + if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` + if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` + if (matchYear === true) return `${ date.getFullYear() }` + })() + + return { + id: recursiveId([ value, ...ids ]), + value, + count: entry == null ? 0 : entry.count, + } + }) + } + + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/events.js b/src/database/events.js index 1c2f3696a..d1b15c57e 100644 --- a/src/database/events.js +++ b/src/database/events.js @@ -2,75 +2,75 @@ import Event from '../models/Event.js' import sortByProp from '../utils/sortByProp.js' const response = (entry) => ({ -id: entry.id, -title: entry.title, -type: entry.type, -created: entry.created, -updated: entry.updated, + id: entry.id, + title: entry.title, + type: entry.type, + created: entry.created, + updated: entry.updated, }) const add = async (data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Event.create(data), -) + ) } const all = async () => { -const enhance = (entries) => { -return entries -.map(response) -.sort(sortByProp('title')) -} + const enhance = (entries) => { + return entries + .map(response) + .sort(sortByProp('title')) + } -return enhance( + return enhance( await Event.find({}), -) + ) } const get = async (id) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Event.findOne({ id }), -) + ) } const update = async (id, data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Event.findOneAndUpdate({ -id, + id, }, { -$set: { -title: data.title, -type: data.type, -updated: Date.now(), -}, + $set: { + title: data.title, + type: data.type, + updated: Date.now(), + }, }, { -new: true, + new: true, }), -) + ) } const del = (id) => { -return Event.findOneAndDelete({ -id, -}) + return Event.findOneAndDelete({ + id, + }) } export { -add, -all, -get, -update, -del, -} + add, + all, + get, + update, + del, +} \ No newline at end of file diff --git a/src/database/facts.js b/src/database/facts.js index a205474e0..70872b58a 100644 --- a/src/database/facts.js +++ b/src/database/facts.js @@ -2,16 +2,16 @@ import Record from '../models/Record.js' import aggregateActiveVisitors from '../aggregations/aggregateActiveVisitors.js' const getActiveVisitors = async (ids, dateDetails) => { -const enhance = (entries) => { -const entry = entries[0] -return entry == null ? 0 : entry.count -} + const enhance = (entries) => { + const entry = entries[0] + return entry == null ? 0 : entry.count + } -return enhance( + return enhance( await Record.aggregate( aggregateActiveVisitors(ids, dateDetails), ), -) + ) } -export default getActiveVisitors +export default getActiveVisitors \ No newline at end of file diff --git a/src/database/languages.js b/src/database/languages.js index bb6da0044..3289864a6 100644 --- a/src/database/languages.js +++ b/src/database/languages.js @@ -7,32 +7,32 @@ import languageCodes from '../utils/languageCodes.js' import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, range, limit, dateDetails) => { -const aggregation = (() => { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLanguage' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLanguage' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLanguage' ], limit) -})() + const aggregation = (() => { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLanguage' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLanguage' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLanguage' ], limit) + })() -const enhanceId = (id) => { -return languageCodes[id.siteLanguage] || id.siteLanguage -} + const enhanceId = (id) => { + return languageCodes[id.siteLanguage] || id.siteLanguage + } -const enhance = (entries) => { -return entries.map((entry) => { -const value = enhanceId(entry._id) + const enhance = (entries) => { + return entries.map((entry) => { + const value = enhanceId(entry._id) -return { -id: recursiveId([ value, sorting, range, ...ids ]), -value, -count: entry.count, -created: entry.created, -} -}) -} + return { + id: recursiveId([ value, sorting, range, ...ids ]), + value, + count: entry.count, + created: entry.created, + } + }) + } -return enhance( + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/pages.js b/src/database/pages.js index 3c05c85f3..da111b87a 100644 --- a/src/database/pages.js +++ b/src/database/pages.js @@ -6,32 +6,32 @@ import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortin import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, range, limit, dateDetails) => { -const aggregation = (() => { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLocation' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLocation' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLocation' ], limit) -})() + const aggregation = (() => { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteLocation' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteLocation' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteLocation' ], limit) + })() -const enhanceId = (id) => { -return id.siteLocation -} + const enhanceId = (id) => { + return id.siteLocation + } -const enhance = (entries) => { -return entries.map((entry) => { -const value = enhanceId(entry._id) + const enhance = (entries) => { + return entries.map((entry) => { + const value = enhanceId(entry._id) -return { -id: recursiveId([ value, sorting, range, ...ids ]), -value, -count: entry.count, -created: entry.created, -} -}) -} + return { + id: recursiveId([ value, sorting, range, ...ids ]), + value, + count: entry.count, + created: entry.created, + } + }) + } -return enhance( + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/permanentTokens.js b/src/database/permanentTokens.js index 87264c4c1..9bf0a2354 100644 --- a/src/database/permanentTokens.js +++ b/src/database/permanentTokens.js @@ -2,75 +2,75 @@ import PermanentToken from '../models/PermanentToken.js' import sortByProp from '../utils/sortByProp.js' const response = (entry) => ({ -id: entry.id, -title: entry.title, -created: entry.created, -updated: entry.updated, + id: entry.id, + title: entry.title, + created: entry.created, + updated: entry.updated, }) const add = async (data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await PermanentToken.create({ -title: data.title, + title: data.title, }), -) + ) } const all = async () => { -const enhance = (entries) => { -return entries -.map(response) -.sort(sortByProp('title')) -} + const enhance = (entries) => { + return entries + .map(response) + .sort(sortByProp('title')) + } -return enhance( + return enhance( await PermanentToken.find({}), -) + ) } const get = async (id) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await PermanentToken.findOne({ id }), -) + ) } const update = async (id, data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await PermanentToken.findOneAndUpdate({ -id, + id, }, { -$set: { -title: data.title, -updated: Date.now(), -}, + $set: { + title: data.title, + updated: Date.now(), + }, }, { -new: true, + new: true, }), -) + ) } const del = (id) => { -return PermanentToken.findOneAndDelete({ -id, -}) + return PermanentToken.findOneAndDelete({ + id, + }) } export { -add, -all, -get, -update, -del, -} + add, + all, + get, + update, + del, +} \ No newline at end of file diff --git a/src/database/records.js b/src/database/records.js index 47d39cdf7..cea16c7d5 100644 --- a/src/database/records.js +++ b/src/database/records.js @@ -1,109 +1,109 @@ import Record from '../models/Record.js' const response = (entry) => ({ -id: entry.id, -siteLocation: entry.siteLocation, -siteReferrer: entry.siteReferrer, -siteLanguage: entry.siteLanguage, -source: entry.source, -screenWidth: entry.screenWidth, -screenHeight: entry.screenHeight, -screenColorDepth: entry.screenColorDepth, -deviceName: entry.deviceName, -deviceManufacturer: entry.deviceManufacturer, -osName: entry.osName, -osVersion: entry.osVersion, -browserName: entry.browserName, -browserVersion: entry.browserVersion, -browserWidth: entry.browserWidth, -browserHeight: entry.browserHeight, -created: entry.created, -updated: entry.updated, + id: entry.id, + siteLocation: entry.siteLocation, + siteReferrer: entry.siteReferrer, + siteLanguage: entry.siteLanguage, + source: entry.source, + screenWidth: entry.screenWidth, + screenHeight: entry.screenHeight, + screenColorDepth: entry.screenColorDepth, + deviceName: entry.deviceName, + deviceManufacturer: entry.deviceManufacturer, + osName: entry.osName, + osVersion: entry.osVersion, + browserName: entry.browserName, + browserVersion: entry.browserVersion, + browserWidth: entry.browserWidth, + browserHeight: entry.browserHeight, + created: entry.created, + updated: entry.updated, }) const add = async (data) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Record.create({ -clientId: data.clientId, -domainId: data.domainId, -siteLocation: data.siteLocation, -siteReferrer: data.siteReferrer, -siteLanguage: data.siteLanguage, -source: data.source, -screenWidth: data.screenWidth, -screenHeight: data.screenHeight, -screenColorDepth: data.screenColorDepth, -deviceName: data.deviceName, -deviceManufacturer: data.deviceManufacturer, -osName: data.osName, -osVersion: data.osVersion, -browserName: data.browserName, -browserVersion: data.browserVersion, -browserWidth: data.browserWidth, -browserHeight: data.browserHeight, + clientId: data.clientId, + domainId: data.domainId, + siteLocation: data.siteLocation, + siteReferrer: data.siteReferrer, + siteLanguage: data.siteLanguage, + source: data.source, + screenWidth: data.screenWidth, + screenHeight: data.screenHeight, + screenColorDepth: data.screenColorDepth, + deviceName: data.deviceName, + deviceManufacturer: data.deviceManufacturer, + osName: data.osName, + osVersion: data.osVersion, + browserName: data.browserName, + browserVersion: data.browserVersion, + browserWidth: data.browserWidth, + browserHeight: data.browserHeight, }), -) + ) } const update = async (id) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Record.findOneAndUpdate({ -id, + id, }, { -$set: { -updated: Date.now(), -}, + $set: { + updated: Date.now(), + }, }, { -new: true, + new: true, }), -) + ) } const anonymize = (clientId, ignoreId) => { // Don't return anything about the update -return Record.updateMany({ -$and: [ -{ clientId }, -{ -id: { -$ne: ignoreId, -}, -}, -], -}, { -clientId: null, -siteLanguage: null, -screenWidth: null, -screenHeight: null, -screenColorDepth: null, -deviceName: null, -deviceManufacturer: null, -osName: null, -osVersion: null, -browserName: null, -browserVersion: null, -browserWidth: null, -browserHeight: null, -}) + return Record.updateMany({ + $and: [ + { clientId }, + { + id: { + $ne: ignoreId, + }, + }, + ], + }, { + clientId: null, + siteLanguage: null, + screenWidth: null, + screenHeight: null, + screenColorDepth: null, + deviceName: null, + deviceManufacturer: null, + osName: null, + osVersion: null, + browserName: null, + browserVersion: null, + browserWidth: null, + browserHeight: null, + }) } const del = (domainId) => { -return Record.deleteMany({ -domainId, -}) + return Record.deleteMany({ + domainId, + }) } export { -add, -update, -anonymize, -del, -} + add, + update, + anonymize, + del, +} \ No newline at end of file diff --git a/src/database/referrers.js b/src/database/referrers.js index f363f9441..6680db8ab 100644 --- a/src/database/referrers.js +++ b/src/database/referrers.js @@ -7,44 +7,44 @@ import { REFERRERS_TYPE_WITH_SOURCE, REFERRERS_TYPE_NO_SOURCE, REFERRERS_TYPE_ON import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { -const aggregation = (() => { -if (type === REFERRERS_TYPE_WITH_SOURCE) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source', 'siteReferrer' ], range, limit, dateDetails, true) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source', 'siteReferrer' ], limit, true) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source', 'siteReferrer' ], limit, true) -} -if (type === REFERRERS_TYPE_NO_SOURCE) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteReferrer' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteReferrer' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteReferrer' ], limit) -} -if (type === REFERRERS_TYPE_ONLY_SOURCE) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source' ], limit) -} -})() + const aggregation = (() => { + if (type === REFERRERS_TYPE_WITH_SOURCE) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source', 'siteReferrer' ], range, limit, dateDetails, true) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source', 'siteReferrer' ], limit, true) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source', 'siteReferrer' ], limit, true) + } + if (type === REFERRERS_TYPE_NO_SOURCE) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'siteReferrer' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'siteReferrer' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'siteReferrer' ], limit) + } + if (type === REFERRERS_TYPE_ONLY_SOURCE) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'source' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'source' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'source' ], limit) + } + })() -const enhanceId = (id) => { -return id.source || id.siteReferrer -} + const enhanceId = (id) => { + return id.source || id.siteReferrer + } -const enhance = (entries) => { -return entries.map((entry) => { -const value = enhanceId(entry._id) + const enhance = (entries) => { + return entries.map((entry) => { + const value = enhanceId(entry._id) -return { -id: recursiveId([ value, sorting, type, range, ...ids ]), -value, -count: entry.count, -created: entry.created, -} -}) -} + return { + id: recursiveId([ value, sorting, type, range, ...ids ]), + value, + count: entry.count, + created: entry.created, + } + }) + } -return enhance( + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/sizes.js b/src/database/sizes.js index f8c801af6..358080848 100644 --- a/src/database/sizes.js +++ b/src/database/sizes.js @@ -4,68 +4,68 @@ import aggregateNewRecords from '../aggregations/aggregateNewRecords.js' import aggregateRecentRecords from '../aggregations/aggregateRecentRecords.js' import { SORTINGS_TOP, SORTINGS_NEW, SORTINGS_RECENT } from '../constants/sortings.js' import { -SIZES_TYPE_BROWSER_HEIGHT, -SIZES_TYPE_BROWSER_RESOLUTION, -SIZES_TYPE_BROWSER_WIDTH, -SIZES_TYPE_SCREEN_HEIGHT, -SIZES_TYPE_SCREEN_RESOLUTION, -SIZES_TYPE_SCREEN_WIDTH, + SIZES_TYPE_BROWSER_HEIGHT, + SIZES_TYPE_BROWSER_RESOLUTION, + SIZES_TYPE_BROWSER_WIDTH, + SIZES_TYPE_SCREEN_HEIGHT, + SIZES_TYPE_SCREEN_RESOLUTION, + SIZES_TYPE_SCREEN_WIDTH, } from '../constants/sizes.js' import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { -const aggregation = (() => { -if (sorting === SORTINGS_TOP) { -if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateTopRecords(ids, [ 'browserWidth' ], range, limit, dateDetails) -if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateTopRecords(ids, [ 'browserHeight' ], range, limit, dateDetails) -if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateTopRecords(ids, [ 'browserWidth', 'browserHeight' ], range, limit, dateDetails) -if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateTopRecords(ids, [ 'screenWidth' ], range, limit, dateDetails) -if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateTopRecords(ids, [ 'screenHeight' ], range, limit, dateDetails) -if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateTopRecords(ids, [ 'screenWidth', 'screenHeight' ], range, limit, dateDetails) -} -if (sorting === SORTINGS_NEW) { -if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateNewRecords(ids, [ 'browserWidth' ], limit) -if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateNewRecords(ids, [ 'browserHeight' ], limit) -if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateNewRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) -if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateNewRecords(ids, [ 'screenWidth' ], limit) -if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateNewRecords(ids, [ 'screenHeight' ], limit) -if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateNewRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) -} -if (sorting === SORTINGS_RECENT) { -if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateRecentRecords(ids, [ 'browserWidth' ], limit) -if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateRecentRecords(ids, [ 'browserHeight' ], limit) -if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateRecentRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) -if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateRecentRecords(ids, [ 'screenWidth' ], limit) -if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateRecentRecords(ids, [ 'screenHeight' ], limit) -if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateRecentRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) -} -})() + const aggregation = (() => { + if (sorting === SORTINGS_TOP) { + if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateTopRecords(ids, [ 'browserWidth' ], range, limit, dateDetails) + if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateTopRecords(ids, [ 'browserHeight' ], range, limit, dateDetails) + if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateTopRecords(ids, [ 'browserWidth', 'browserHeight' ], range, limit, dateDetails) + if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateTopRecords(ids, [ 'screenWidth' ], range, limit, dateDetails) + if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateTopRecords(ids, [ 'screenHeight' ], range, limit, dateDetails) + if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateTopRecords(ids, [ 'screenWidth', 'screenHeight' ], range, limit, dateDetails) + } + if (sorting === SORTINGS_NEW) { + if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateNewRecords(ids, [ 'browserWidth' ], limit) + if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateNewRecords(ids, [ 'browserHeight' ], limit) + if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateNewRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) + if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateNewRecords(ids, [ 'screenWidth' ], limit) + if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateNewRecords(ids, [ 'screenHeight' ], limit) + if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateNewRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) + } + if (sorting === SORTINGS_RECENT) { + if (type === SIZES_TYPE_BROWSER_WIDTH) return aggregateRecentRecords(ids, [ 'browserWidth' ], limit) + if (type === SIZES_TYPE_BROWSER_HEIGHT) return aggregateRecentRecords(ids, [ 'browserHeight' ], limit) + if (type === SIZES_TYPE_BROWSER_RESOLUTION) return aggregateRecentRecords(ids, [ 'browserWidth', 'browserHeight' ], limit) + if (type === SIZES_TYPE_SCREEN_WIDTH) return aggregateRecentRecords(ids, [ 'screenWidth' ], limit) + if (type === SIZES_TYPE_SCREEN_HEIGHT) return aggregateRecentRecords(ids, [ 'screenHeight' ], limit) + if (type === SIZES_TYPE_SCREEN_RESOLUTION) return aggregateRecentRecords(ids, [ 'screenWidth', 'screenHeight' ], limit) + } + })() -const enhanceId = (id) => { -if (type === SIZES_TYPE_BROWSER_WIDTH) return `${ id.browserWidth }px` -if (type === SIZES_TYPE_BROWSER_HEIGHT) return `${ id.browserHeight }px` -if (type === SIZES_TYPE_BROWSER_RESOLUTION) return `${ id.browserWidth }px x ${ id.browserHeight }px` -if (type === SIZES_TYPE_SCREEN_WIDTH) return `${ id.screenWidth }px` -if (type === SIZES_TYPE_SCREEN_HEIGHT) return `${ id.screenHeight }px` -if (type === SIZES_TYPE_SCREEN_RESOLUTION) return `${ id.screenWidth }px x ${ id.screenHeight }px` -} + const enhanceId = (id) => { + if (type === SIZES_TYPE_BROWSER_WIDTH) return `${ id.browserWidth }px` + if (type === SIZES_TYPE_BROWSER_HEIGHT) return `${ id.browserHeight }px` + if (type === SIZES_TYPE_BROWSER_RESOLUTION) return `${ id.browserWidth }px x ${ id.browserHeight }px` + if (type === SIZES_TYPE_SCREEN_WIDTH) return `${ id.screenWidth }px` + if (type === SIZES_TYPE_SCREEN_HEIGHT) return `${ id.screenHeight }px` + if (type === SIZES_TYPE_SCREEN_RESOLUTION) return `${ id.screenWidth }px x ${ id.screenHeight }px` + } -const enhance = (entries) => { -return entries.map((entry) => { -const value = enhanceId(entry._id) + const enhance = (entries) => { + return entries.map((entry) => { + const value = enhanceId(entry._id) -return { -id: recursiveId([ value, sorting, type, range, ...ids ]), -value, -count: entry.count, -created: entry.created, -} -}) -} + return { + id: recursiveId([ value, sorting, type, range, ...ids ]), + value, + count: entry.count, + created: entry.created, + } + }) + } -return enhance( + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/systems.js b/src/database/systems.js index 303768342..73a86f64d 100644 --- a/src/database/systems.js +++ b/src/database/systems.js @@ -7,40 +7,40 @@ import { SYSTEMS_TYPE_NO_VERSION, SYSTEMS_TYPE_WITH_VERSION } from '../constants import recursiveId from '../utils/recursiveId.js' const get = async (ids, sorting, type, range, limit, dateDetails) => { -const aggregation = (() => { -if (type === SYSTEMS_TYPE_NO_VERSION) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName' ], limit) -} -if (type === SYSTEMS_TYPE_WITH_VERSION) { -if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName', 'osVersion' ], range, limit, dateDetails) -if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName', 'osVersion' ], limit) -if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName', 'osVersion' ], limit) -} -})() + const aggregation = (() => { + if (type === SYSTEMS_TYPE_NO_VERSION) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName' ], limit) + } + if (type === SYSTEMS_TYPE_WITH_VERSION) { + if (sorting === SORTINGS_TOP) return aggregateTopRecords(ids, [ 'osName', 'osVersion' ], range, limit, dateDetails) + if (sorting === SORTINGS_NEW) return aggregateNewRecords(ids, [ 'osName', 'osVersion' ], limit) + if (sorting === SORTINGS_RECENT) return aggregateRecentRecords(ids, [ 'osName', 'osVersion' ], limit) + } + })() -const enhanceId = (id) => { -if (type === SYSTEMS_TYPE_NO_VERSION) return `${ id.osName }` -if (type === SYSTEMS_TYPE_WITH_VERSION) return `${ id.osName } ${ id.osVersion }` -} + const enhanceId = (id) => { + if (type === SYSTEMS_TYPE_NO_VERSION) return `${ id.osName }` + if (type === SYSTEMS_TYPE_WITH_VERSION) return `${ id.osName } ${ id.osVersion }` + } -const enhance = (entries) => { -return entries.map((entry) => { -const value = enhanceId(entry._id) + const enhance = (entries) => { + return entries.map((entry) => { + const value = enhanceId(entry._id) -return { -id: recursiveId([ value, sorting, type, range, ...ids ]), -value, -count: entry.count, -created: entry.created, -} -}) -} + return { + id: recursiveId([ value, sorting, type, range, ...ids ]), + value, + count: entry.count, + created: entry.created, + } + }) + } -return enhance( + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/database/tokens.js b/src/database/tokens.js index 0caafdeb9..86475c165 100644 --- a/src/database/tokens.js +++ b/src/database/tokens.js @@ -1,58 +1,58 @@ import Token from '../models/Token.js' const response = (entry) => ({ -id: entry.id, -created: entry.created, -updated: entry.updated, + id: entry.id, + created: entry.created, + updated: entry.updated, }) const add = async () => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Token.create({}), -) + ) } const get = async (id) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Token.findOne({ id }), -) + ) } const update = async (id) => { -const enhance = (entry) => { -return entry == null ? entry : response(entry) -} + const enhance = (entry) => { + return entry == null ? entry : response(entry) + } -return enhance( + return enhance( await Token.findOneAndUpdate({ -id, + id, }, { -$set: { -updated: Date.now(), -}, + $set: { + updated: Date.now(), + }, }, { -new: true, + new: true, }), -) + ) } const del = (id) => { -return Token.findOneAndDelete({ -id, -}) + return Token.findOneAndDelete({ + id, + }) } export { -add, -get, -update, -del, -} + add, + get, + update, + del, +} \ No newline at end of file diff --git a/src/database/views.js b/src/database/views.js index c97d449eb..897a2a887 100644 --- a/src/database/views.js +++ b/src/database/views.js @@ -1,5 +1,4 @@ -import dateFnsTz from 'date-fns-tz' -const { utcToZonedTime } = dateFnsTz +import { utcToZonedTime } from 'date-fns-tz/esm' import Record from '../models/Record.js' import aggregateViews from '../aggregations/aggregateViews.js' @@ -10,51 +9,51 @@ import matchesDate from '../utils/matchesDate.js' import recursiveId from '../utils/recursiveId.js' const get = async (ids, type, interval, limit, dateDetails) => { -const aggregation = (() => { -if (type === VIEWS_TYPE_UNIQUE) return aggregateViews(ids, true, interval, limit, dateDetails) -if (type === VIEWS_TYPE_TOTAL) return aggregateViews(ids, false, interval, limit, dateDetails) -})() - -const enhance = (entries) => { -const matchDay = [ INTERVALS_DAILY ].includes(interval) -const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) -const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) - -return createArray(limit).map((_, index) => { -const date = dateDetails.lastFnByInterval(interval)(index) - -// Database entries include the day, month and year in the -// timezone of the user. We therefore need to match it against a -// date in the timezone of the user. -const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) - -// Find a entry that matches the date -const entry = entries.find((entry) => { -return matchesDate( + const aggregation = (() => { + if (type === VIEWS_TYPE_UNIQUE) return aggregateViews(ids, true, interval, limit, dateDetails) + if (type === VIEWS_TYPE_TOTAL) return aggregateViews(ids, false, interval, limit, dateDetails) + })() + + const enhance = (entries) => { + const matchDay = [ INTERVALS_DAILY ].includes(interval) + const matchMonth = [ INTERVALS_DAILY, INTERVALS_MONTHLY ].includes(interval) + const matchYear = [ INTERVALS_DAILY, INTERVALS_MONTHLY, INTERVALS_YEARLY ].includes(interval) + + return createArray(limit).map((_, index) => { + const date = dateDetails.lastFnByInterval(interval)(index) + + // Database entries include the day, month and year in the + // timezone of the user. We therefore need to match it against a + // date in the timezone of the user. + const userZonedDate = utcToZonedTime(date, dateDetails.userTimeZone) + + // Find a entry that matches the date + const entry = entries.find((entry) => { + return matchesDate( matchDay === true ? entry._id.day : undefined, matchMonth === true ? entry._id.month : undefined, matchYear === true ? entry._id.year : undefined, userZonedDate, -) -}) - -const value = (() => { -if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` -if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` -if (matchYear === true) return `${ date.getFullYear() }` -})() - -return { -id: recursiveId([ value, ...ids ]), -value, -count: entry == null ? 0 : entry.count, -} -}) -} - -return enhance( + ) + }) + + const value = (() => { + if (matchDay === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }` + if (matchMonth === true) return `${ date.getFullYear() }-${ date.getMonth() + 1 }` + if (matchYear === true) return `${ date.getFullYear() }` + })() + + return { + id: recursiveId([ value, ...ids ]), + value, + count: entry == null ? 0 : entry.count, + } + }) + } + + return enhance( await Record.aggregate(aggregation), -) + ) } -export default get +export default get \ No newline at end of file diff --git a/src/healthcheck.js b/src/healthcheck.js index f0a7d683a..933cabc9b 100755 --- a/src/healthcheck.js +++ b/src/healthcheck.js @@ -6,44 +6,44 @@ import config from './utils/config.js' import connect from './utils/connect.js' if (config.dbUrl == null) { -signale.fatal('MongoDB connection URI missing in environment') -process.exit(1) + signale.fatal('MongoDB connection URI missing in environment') + process.exit(1) } const checkServer = async (url) => { -const response = await fetch(url) + const response = await fetch(url) -if (response.ok === false) { -throw new Error(`Server is unhealthy and returned with the status '${ response.status }'`) -} + if (response.ok === false) { + throw new Error(`Server is unhealthy and returned with the status '${ response.status }'`) + } } const checkApi = async (url) => { -const response = await fetch(url) + const response = await fetch(url) -if (response.ok === false) { -throw new Error(`API is unhealthy and returned with the status '${ response.status }'`) -} + if (response.ok === false) { + throw new Error(`API is unhealthy and returned with the status '${ response.status }'`) + } } const exit = (healthy) => process.exit(healthy === true ? 0 : 1) const check = () => Promise.all([ -connect(config.dbUrl), -checkServer(`http://localhost:${ config.port }`), -checkApi(`http://localhost:${ config.port }/.well-known/apollo/server-health`), + connect(config.dbUrl), + checkServer(`http://localhost:${ config.port }`), + checkApi(`http://localhost:${ config.port }/.well-known/apollo/server-health`), ]) const handleSuccess = () => { -signale.success('Ackee is up and running') -exit(true) + signale.success('Ackee is up and running') + exit(true) } const handleFailure = (error) => { -signale.fatal(error) -exit(false) + signale.fatal(error) + exit(false) } check() -.then(handleSuccess) -.catch(handleFailure) + .then(handleSuccess) + .catch(handleFailure) \ No newline at end of file diff --git a/src/index.js b/src/index.js index 0ed87ab12..4a45c58cd 100644 --- a/src/index.js +++ b/src/index.js @@ -8,8 +8,8 @@ import connect from './utils/connect.js' import stripUrlAuth from './utils/stripUrlAuth.js' if (config.dbUrl == null) { -signale.fatal('MongoDB connection URI missing in environment') -process.exit(1) + signale.fatal('MongoDB connection URI missing in environment') + process.exit(1) } server.on('listening', () => signale.watch(`Listening on http://localhost:${ config.port }`)) @@ -18,20 +18,20 @@ server.on('error', (error) => signale.fatal(error)) signale.await(`Connecting to ${ stripUrlAuth(config.dbUrl) }`) connect(config.dbUrl).then(() => { -signale.success(`Connected to ${ stripUrlAuth(config.dbUrl) }`) -signale.start(`Starting the server`) + signale.success(`Connected to ${ stripUrlAuth(config.dbUrl) }`) + signale.start(`Starting the server`) -server.listen(config.port) + server.listen(config.port) -if (config.isDevelopmentMode === true) { -signale.info('Development mode enabled') -} + if (config.isDevelopmentMode === true) { + signale.info('Development mode enabled') + } -if (config.isDemoMode === true) { -signale.info('Demo mode enabled') -} -}) -.catch((error) => { -signale.fatal(error) -process.exit(1) + if (config.isDemoMode === true) { + signale.info('Demo mode enabled') + } }) + .catch((error) => { + signale.fatal(error) + process.exit(1) + }) \ No newline at end of file diff --git a/src/resolvers/actions.js b/src/resolvers/actions.js index 6cdf08fdb..117212694 100644 --- a/src/resolvers/actions.js +++ b/src/resolvers/actions.js @@ -4,79 +4,79 @@ import * as events from '../database/events.js' import * as actions from '../database/actions.js' const polish = (obj) => { -return Object.entries(obj).reduce((acc, [ key, value ]) => { -value = typeof value === 'string' ? value.trim() : value -value = value == null ? undefined : value -value = value === '' ? undefined : value + return Object.entries(obj).reduce((acc, [ key, value ]) => { + value = typeof value === 'string' ? value.trim() : value + value = value == null ? undefined : value + value = value === '' ? undefined : value -acc[key] = value -return acc -}, {}) + acc[key] = value + return acc + }, {}) } export default { -Mutation: { -createAction: async (parent, { eventId, input }, { isIgnored }) => { -// Ignore your own actions when logged in -if (isIgnored === true) { -return { -success: true, -payload: { -id: '88888888-8888-8888-8888-888888888888', -}, -} -} + Mutation: { + createAction: async (parent, { eventId, input }, { isIgnored }) => { + // Ignore your own actions when logged in + if (isIgnored === true) { + return { + success: true, + payload: { + id: '88888888-8888-8888-8888-888888888888', + }, + } + } -const data = polish({ ...input, eventId }) + const data = polish({ ...input, eventId }) -const event = await events.get(eventId) + const event = await events.get(eventId) -if (event == null) throw new KnownError('Unknown event') + if (event == null) throw new KnownError('Unknown event') -let entry + let entry -try { -entry = await actions.add(data) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await actions.add(data) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -return { -success: true, -payload: entry, -} -}, -updateAction: async (parent, { id, input }, { isIgnored }) => { -// Ignore your own actions when logged in -if (isIgnored === true) { -return { -success: true, -} -} + return { + success: true, + payload: entry, + } + }, + updateAction: async (parent, { id, input }, { isIgnored }) => { + // Ignore your own actions when logged in + if (isIgnored === true) { + return { + success: true, + } + } -let entry + let entry -try { -entry = await actions.update(id, input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await actions.update(id, input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -if (entry == null) { -throw new KnownError('Unknown action') -} + if (entry == null) { + throw new KnownError('Unknown action') + } -return { -success: true, -} -}, -}, -} + return { + success: true, + } + }, + }, +} \ No newline at end of file diff --git a/src/resolvers/domainStatistics.js b/src/resolvers/domainStatistics.js index 6021c4d3b..338700242 100644 --- a/src/resolvers/domainStatistics.js +++ b/src/resolvers/domainStatistics.js @@ -13,53 +13,53 @@ import recursiveId from '../utils/recursiveId.js' import requireAuth from '../middlewares/requireAuth.js' export default { -DomainStatistics: { -id: pipe(requireAuth, async (domain) => { -const ids = await domainIds(domain) + DomainStatistics: { + id: pipe(requireAuth, async (domain) => { + const ids = await domainIds(domain) -// Provide a static fallback id when there're no domains to create a recursive id from -if (ids.length === 0) return 'eaf55ae8-29b8-448f-b45c-85e17fbfc8ba' + // Provide a static fallback id when there're no domains to create a recursive id from + if (ids.length === 0) return 'eaf55ae8-29b8-448f-b45c-85e17fbfc8ba' -return recursiveId(ids) -}), -views: pipe(requireAuth, async (domain, { type, interval, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getViews(ids, type, interval, limit, dateDetails) -}), -pages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getPages(ids, sorting, range, limit, dateDetails) -}), -referrers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getReferrers(ids, sorting, type, range, limit, dateDetails) -}), -durations: pipe(requireAuth, async (domain, { interval, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getDurations(ids, interval, limit, dateDetails) -}), -systems: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getSystems(ids, sorting, type, range, limit, dateDetails) -}), -devices: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getDevices(ids, sorting, type, range, limit, dateDetails) -}), -browsers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getBrowsers(ids, sorting, type, range, limit, dateDetails) -}), -sizes: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getSizes(ids, sorting, type, range, limit, dateDetails) -}), -languages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { -const ids = await domainIds(domain) -return getLanguages(ids, sorting, range, limit, dateDetails) -}), -}, -Query: { -statistics: () => ({}), -}, -} + return recursiveId(ids) + }), + views: pipe(requireAuth, async (domain, { type, interval, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getViews(ids, type, interval, limit, dateDetails) + }), + pages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getPages(ids, sorting, range, limit, dateDetails) + }), + referrers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getReferrers(ids, sorting, type, range, limit, dateDetails) + }), + durations: pipe(requireAuth, async (domain, { interval, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getDurations(ids, interval, limit, dateDetails) + }), + systems: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getSystems(ids, sorting, type, range, limit, dateDetails) + }), + devices: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getDevices(ids, sorting, type, range, limit, dateDetails) + }), + browsers: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getBrowsers(ids, sorting, type, range, limit, dateDetails) + }), + sizes: pipe(requireAuth, async (domain, { sorting, type, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getSizes(ids, sorting, type, range, limit, dateDetails) + }), + languages: pipe(requireAuth, async (domain, { sorting, range, limit }, { dateDetails }) => { + const ids = await domainIds(domain) + return getLanguages(ids, sorting, range, limit, dateDetails) + }), + }, + Query: { + statistics: () => ({}), + }, +} \ No newline at end of file diff --git a/src/resolvers/domains.js b/src/resolvers/domains.js index 40013da86..54d7694e3 100644 --- a/src/resolvers/domains.js +++ b/src/resolvers/domains.js @@ -7,66 +7,66 @@ import requireAuth from '../middlewares/requireAuth.js' import blockDemoMode from '../middlewares/blockDemoMode.js' export default { -Domain: { -facts: (parent) => parent, -statistics: (parent) => parent, -}, -Query: { -domain: pipe(requireAuth, (parent, { id }) => { -return domains.get(id) -}), -domains: pipe(requireAuth, () => { -return domains.all() -}), -}, -Mutation: { -createDomain: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { -let entry + Domain: { + facts: (parent) => parent, + statistics: (parent) => parent, + }, + Query: { + domain: pipe(requireAuth, (parent, { id }) => { + return domains.get(id) + }), + domains: pipe(requireAuth, () => { + return domains.all() + }), + }, + Mutation: { + createDomain: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { + let entry -try { -entry = await domains.add(input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await domains.add(input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -return { -payload: entry, -success: true, -} -}), -updateDomain: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { -let entry + return { + payload: entry, + success: true, + } + }), + updateDomain: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { + let entry -try { -entry = await domains.update(id, input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await domains.update(id, input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -if (entry == null) { -throw new KnownError('Unknown domain') -} + if (entry == null) { + throw new KnownError('Unknown domain') + } -return { -payload: entry, -success: true, -} -}), -deleteDomain: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { -await records.del(id) -await domains.del(id) + return { + payload: entry, + success: true, + } + }), + deleteDomain: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { + await records.del(id) + await domains.del(id) -return { -success: true, -} -}), -}, -} + return { + success: true, + } + }), + }, +} \ No newline at end of file diff --git a/src/resolvers/eventStatistics.js b/src/resolvers/eventStatistics.js index de98587b9..25ec8a710 100644 --- a/src/resolvers/eventStatistics.js +++ b/src/resolvers/eventStatistics.js @@ -3,17 +3,17 @@ import pipe from '../utils/pipe.js' import requireAuth from '../middlewares/requireAuth.js' export default { -EventStatistics: { -id: pipe(requireAuth, (event) => { -return event.id -}), -chart: pipe(requireAuth, (event, { type, interval, limit }, { dateDetails }) => { -const ids = [ event.id ] -return actions.getChart(ids, type, interval, limit, dateDetails) -}), -list: pipe(requireAuth, (event, { sorting, type, range, limit }, { dateDetails }) => { -const ids = [ event.id ] -return actions.getList(ids, sorting, type, range, limit, dateDetails) -}), -}, -} + EventStatistics: { + id: pipe(requireAuth, (event) => { + return event.id + }), + chart: pipe(requireAuth, (event, { type, interval, limit }, { dateDetails }) => { + const ids = [ event.id ] + return actions.getChart(ids, type, interval, limit, dateDetails) + }), + list: pipe(requireAuth, (event, { sorting, type, range, limit }, { dateDetails }) => { + const ids = [ event.id ] + return actions.getList(ids, sorting, type, range, limit, dateDetails) + }), + }, +} \ No newline at end of file diff --git a/src/resolvers/events.js b/src/resolvers/events.js index df9dada6f..d959ffe72 100644 --- a/src/resolvers/events.js +++ b/src/resolvers/events.js @@ -7,65 +7,65 @@ import requireAuth from '../middlewares/requireAuth.js' import blockDemoMode from '../middlewares/blockDemoMode.js' export default { -Event: { -statistics: (parent) => parent, -}, -Query: { -event: pipe(requireAuth, (parent, { id }) => { -return events.get(id) -}), -events: pipe(requireAuth, () => { -return events.all() -}), -}, -Mutation: { -createEvent: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { -let entry + Event: { + statistics: (parent) => parent, + }, + Query: { + event: pipe(requireAuth, (parent, { id }) => { + return events.get(id) + }), + events: pipe(requireAuth, () => { + return events.all() + }), + }, + Mutation: { + createEvent: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { + let entry -try { -entry = await events.add(input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await events.add(input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -return { -payload: entry, -success: true, -} -}), -updateEvent: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { -let entry + return { + payload: entry, + success: true, + } + }), + updateEvent: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { + let entry -try { -entry = await events.update(id, input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await events.update(id, input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -if (entry == null) { -throw new KnownError('Unknown event') -} + if (entry == null) { + throw new KnownError('Unknown event') + } -return { -payload: entry, -success: true, -} -}), -deleteEvent: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { -await actions.del(id) -await events.del(id) + return { + payload: entry, + success: true, + } + }), + deleteEvent: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { + await actions.del(id) + await events.del(id) -return { -success: true, -} -}), -}, -} + return { + success: true, + } + }), + }, +} \ No newline at end of file diff --git a/src/resolvers/facts.js b/src/resolvers/facts.js index ef09c2f6f..fc84e8978 100644 --- a/src/resolvers/facts.js +++ b/src/resolvers/facts.js @@ -9,85 +9,85 @@ import recursiveId from '../utils/recursiveId.js' import requireAuth from '../middlewares/requireAuth.js' export default { -AverageViews: { -count: pipe(requireAuth, (entries) => { -const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) + AverageViews: { + count: pipe(requireAuth, (entries) => { + const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) -return Math.round(totalCount / 14) -}), -change: pipe(requireAuth, (entries) => { -const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) -const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) -const totalDifference = totalCountCurrent - totalCountPrevious + return Math.round(totalCount / 14) + }), + change: pipe(requireAuth, (entries) => { + const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) + const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) + const totalDifference = totalCountCurrent - totalCountPrevious -if (totalCountPrevious === 0) return + if (totalCountPrevious === 0) return -return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) -}), -}, -AverageDuration: { -count: pipe(requireAuth, (entries) => { -const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) + return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) + }), + }, + AverageDuration: { + count: pipe(requireAuth, (entries) => { + const totalCount = entries.slice(1, 15).reduce((acc, entry) => acc + entry.count, 0) -return Math.round(totalCount / 14) -}), -change: pipe(requireAuth, (entries) => { -const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) -const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) -const totalDifference = totalCountCurrent - totalCountPrevious + return Math.round(totalCount / 14) + }), + change: pipe(requireAuth, (entries) => { + const totalCountCurrent = entries.slice(1, 8).reduce((acc, entry) => acc + entry.count, 0) + const totalCountPrevious = entries.slice(8, 15).reduce((acc, entry) => acc + entry.count, 0) + const totalDifference = totalCountCurrent - totalCountPrevious -if (totalCountPrevious === 0) return + if (totalCountPrevious === 0) return -return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) -}), -}, -Facts: { -id: pipe(requireAuth, async (domain) => { -const ids = await domainIds(domain) + return Math.min(Math.max(Math.round(totalDifference / totalCountPrevious * 100), -100), 100) + }), + }, + Facts: { + id: pipe(requireAuth, async (domain) => { + const ids = await domainIds(domain) -// Provide a static fallback id when there're domains to create a recursive id from -if (ids.length === 0) return '882b8e8a-f30b-414d-85e1-00d8ed5585a6' + // Provide a static fallback id when there're domains to create a recursive id from + if (ids.length === 0) return '882b8e8a-f30b-414d-85e1-00d8ed5585a6' -return recursiveId(ids) -}), -activeVisitors: pipe(requireAuth, async (domain, _, { dateDetails }) => { -const ids = await domainIds(domain) -const activeVisitors = await getActiveVisitors(ids, dateDetails) + return recursiveId(ids) + }), + activeVisitors: pipe(requireAuth, async (domain, _, { dateDetails }) => { + const ids = await domainIds(domain) + const activeVisitors = await getActiveVisitors(ids, dateDetails) -return activeVisitors -}), -averageViews: pipe(requireAuth, async (domain, _, { dateDetails }) => { -const ids = await domainIds(domain) -const entries = getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_DAILY, 15, dateDetails) + return activeVisitors + }), + averageViews: pipe(requireAuth, async (domain, _, { dateDetails }) => { + const ids = await domainIds(domain) + const entries = getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_DAILY, 15, dateDetails) -return entries -}), -averageDuration: pipe(requireAuth, async (domain, _, { dateDetails }) => { -const ids = await domainIds(domain) -const entries = getDurations(ids, INTERVALS_DAILY, 15, dateDetails) + return entries + }), + averageDuration: pipe(requireAuth, async (domain, _, { dateDetails }) => { + const ids = await domainIds(domain) + const entries = getDurations(ids, INTERVALS_DAILY, 15, dateDetails) -return entries -}), -viewsToday: pipe(requireAuth, async (domain, _, { dateDetails }) => { -const ids = await domainIds(domain) -const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_DAILY, 1, dateDetails) + return entries + }), + viewsToday: pipe(requireAuth, async (domain, _, { dateDetails }) => { + const ids = await domainIds(domain) + const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_DAILY, 1, dateDetails) -return entries[0].count -}), -viewsMonth: pipe(requireAuth, async (domain, _, { dateDetails }) => { -const ids = await domainIds(domain) -const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_MONTHLY, 1, dateDetails) + return entries[0].count + }), + viewsMonth: pipe(requireAuth, async (domain, _, { dateDetails }) => { + const ids = await domainIds(domain) + const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_MONTHLY, 1, dateDetails) -return entries[0].count -}), -viewsYear: pipe(requireAuth, async (domain, _, { dateDetails }) => { -const ids = await domainIds(domain) -const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_YEARLY, 1, dateDetails) + return entries[0].count + }), + viewsYear: pipe(requireAuth, async (domain, _, { dateDetails }) => { + const ids = await domainIds(domain) + const entries = await getViews(ids, VIEWS_TYPE_UNIQUE, INTERVALS_YEARLY, 1, dateDetails) -return entries[0].count -}), -}, -Query: { -facts: () => ({}), -}, -} + return entries[0].count + }), + }, + Query: { + facts: () => ({}), + }, +} \ No newline at end of file diff --git a/src/resolvers/permanentTokens.js b/src/resolvers/permanentTokens.js index 85997fcdd..3972c1294 100644 --- a/src/resolvers/permanentTokens.js +++ b/src/resolvers/permanentTokens.js @@ -6,61 +6,61 @@ import requireAuth from '../middlewares/requireAuth.js' import blockDemoMode from '../middlewares/blockDemoMode.js' export default { -Query: { -permanentToken: pipe(requireAuth, (parent, { id }) => { -return permanentTokens.get(id) -}), -permanentTokens: pipe(requireAuth, () => { -return permanentTokens.all() -}), -}, -Mutation: { -createPermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { -let entry + Query: { + permanentToken: pipe(requireAuth, (parent, { id }) => { + return permanentTokens.get(id) + }), + permanentTokens: pipe(requireAuth, () => { + return permanentTokens.all() + }), + }, + Mutation: { + createPermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { input }) => { + let entry -try { -entry = await permanentTokens.add(input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await permanentTokens.add(input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -return { -payload: entry, -success: true, -} -}), -updatePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { -let entry + return { + payload: entry, + success: true, + } + }), + updatePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id, input }) => { + let entry -try { -entry = await permanentTokens.update(id, input) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} + try { + entry = await permanentTokens.update(id, input) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } -throw error -} + throw error + } -if (entry == null) { -throw new KnownError('Unknown domain') -} + if (entry == null) { + throw new KnownError('Unknown domain') + } -return { -payload: entry, -success: true, -} -}), -deletePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { -await permanentTokens.del(id) + return { + payload: entry, + success: true, + } + }), + deletePermanentToken: pipe(requireAuth, blockDemoMode, async (parent, { id }) => { + await permanentTokens.del(id) -return { -success: true, -} -}), -}, -} + return { + success: true, + } + }), + }, +} \ No newline at end of file diff --git a/src/resolvers/records.js b/src/resolvers/records.js index 107fb7c7d..3d37c572c 100644 --- a/src/resolvers/records.js +++ b/src/resolvers/records.js @@ -6,111 +6,111 @@ import * as domains from '../database/domains.js' import * as records from '../database/records.js' const normalizeSiteLocation = (siteLocation) => { -if (siteLocation == null) { -// Pre-validate siteLocation and imitate MongoDB error -throw new KnownError(`Path \`siteLocation\` is required`) -} + if (siteLocation == null) { + // Pre-validate siteLocation and imitate MongoDB error + throw new KnownError(`Path \`siteLocation\` is required`) + } -try { -return normalizeUrl(siteLocation.toString()) -} catch (error) { -throw new KnownError(`Failed to normalize \`siteLocation\``, error) -} + try { + return normalizeUrl(siteLocation.toString()) + } catch (error) { + throw new KnownError(`Failed to normalize \`siteLocation\``, error) + } } const normalizeSiteReferrer = (siteReferrer) => { // The siteReferrer is optional -if (siteReferrer == null) return siteReferrer + if (siteReferrer == null) return siteReferrer -try { -return normalizeUrl(siteReferrer.toString()) -} catch (error) { -throw new KnownError(`Failed to normalize \`siteReferrer\``, error) -} + try { + return normalizeUrl(siteReferrer.toString()) + } catch (error) { + throw new KnownError(`Failed to normalize \`siteReferrer\``, error) + } } const polish = (obj) => { -return Object.entries(obj).reduce((acc, [ key, value ]) => { -value = typeof value === 'string' ? value.trim() : value -value = value == null ? undefined : value -value = value === '' ? undefined : value + return Object.entries(obj).reduce((acc, [ key, value ]) => { + value = typeof value === 'string' ? value.trim() : value + value = value == null ? undefined : value + value = value === '' ? undefined : value -if (key === 'siteLocation') value = normalizeSiteLocation(value) -if (key === 'siteReferrer') value = normalizeSiteReferrer(value) + if (key === 'siteLocation') value = normalizeSiteLocation(value) + if (key === 'siteReferrer') value = normalizeSiteReferrer(value) -acc[key] = value -return acc -}, {}) + acc[key] = value + return acc + }, {}) } export default { -Mutation: { -createRecord: async (parent, { domainId, input }, { ip, userAgent, isIgnored }) => { -// Ignore your own records when logged in -if (isIgnored === true) { -return { -success: true, -payload: { -id: '88888888-8888-8888-8888-888888888888', -}, -} -} - -const clientId = identifier(ip, userAgent, domainId) -const data = polish({ ...input, clientId, domainId }) - -const domain = await domains.get(domainId) - -if (domain == null) throw new KnownError('Unknown domain') - -let entry - -try { -entry = await records.add(data) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} - -throw error -} - -// Anonymize old entries with the same clientId to prevent that the browsing history -// of a user is reconstructible. Will be skipped when there're no previous entries. -await records.anonymize(clientId, entry.id) - -return { -success: true, -payload: entry, -} -}, -updateRecord: async (parent, { id }, { isIgnored }) => { -// Ignore your own records when logged in -if (isIgnored === true) { -return { -success: true, -} -} - -let entry - -try { -entry = await records.update(id) -} catch (error) { -if (error.name === 'ValidationError') { -throw new KnownError(messages(error.errors)) -} - -throw error -} - -if (entry == null) { -throw new KnownError('Unknown record') -} - -return { -success: true, -} -}, -}, -} + Mutation: { + createRecord: async (parent, { domainId, input }, { ip, userAgent, isIgnored }) => { + // Ignore your own records when logged in + if (isIgnored === true) { + return { + success: true, + payload: { + id: '88888888-8888-8888-8888-888888888888', + }, + } + } + + const clientId = identifier(ip, userAgent, domainId) + const data = polish({ ...input, clientId, domainId }) + + const domain = await domains.get(domainId) + + if (domain == null) throw new KnownError('Unknown domain') + + let entry + + try { + entry = await records.add(data) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } + + throw error + } + + // Anonymize old entries with the same clientId to prevent that the browsing history + // of a user is reconstructible. Will be skipped when there're no previous entries. + await records.anonymize(clientId, entry.id) + + return { + success: true, + payload: entry, + } + }, + updateRecord: async (parent, { id }, { isIgnored }) => { + // Ignore your own records when logged in + if (isIgnored === true) { + return { + success: true, + } + } + + let entry + + try { + entry = await records.update(id) + } catch (error) { + if (error.name === 'ValidationError') { + throw new KnownError(messages(error.errors)) + } + + throw error + } + + if (entry == null) { + throw new KnownError('Unknown record') + } + + return { + success: true, + } + }, + }, +} \ No newline at end of file diff --git a/src/resolvers/tokens.js b/src/resolvers/tokens.js index 2a919beb2..3cdc2b036 100644 --- a/src/resolvers/tokens.js +++ b/src/resolvers/tokens.js @@ -4,41 +4,41 @@ import KnownError from '../utils/KnownError.js' import { on as ignoreCookieOn, off as ignoreCookieOff } from '../utils/ignoreCookie.js' const response = (entry) => ({ -id: entry.id, -created: entry.created, -updated: entry.updated, + id: entry.id, + created: entry.created, + updated: entry.updated, }) export default { -Mutation: { -createToken: async (parent, { input }, { setCookies }) => { -const { username, password } = input - -if (config.username == null) throw new KnownError('Ackee username missing in environment') -if (config.password == null) throw new KnownError('Ackee password missing in environment') - -if (username !== config.username) throw new KnownError('Username or password incorrect') -if (password !== config.password) throw new KnownError('Username or password incorrect') - -const entry = await tokens.add() - -// Set cookie to avoid reporting your own visits -setCookies.push(ignoreCookieOn) - -return { -success: true, -payload: response(entry), -} -}, -deleteToken: async (parent, { id }, { setCookies }) => { -await tokens.del(id) - -// Remove cookie to report your own visits, again -setCookies.push(ignoreCookieOff) - -return { -success: true, -} -}, -}, -} + Mutation: { + createToken: async (parent, { input }, { setCookies }) => { + const { username, password } = input + + if (config.username == null) throw new KnownError('Ackee username missing in environment') + if (config.password == null) throw new KnownError('Ackee password missing in environment') + + if (username !== config.username) throw new KnownError('Username or password incorrect') + if (password !== config.password) throw new KnownError('Username or password incorrect') + + const entry = await tokens.add() + + // Set cookie to avoid reporting your own visits + setCookies.push(ignoreCookieOn) + + return { + success: true, + payload: response(entry), + } + }, + deleteToken: async (parent, { id }, { setCookies }) => { + await tokens.del(id) + + // Remove cookie to report your own visits, again + setCookies.push(ignoreCookieOff) + + return { + success: true, + } + }, + }, +} \ No newline at end of file diff --git a/src/server.js b/src/server.js index ebe40bec9..df1101796 100644 --- a/src/server.js +++ b/src/server.js @@ -1,10 +1,9 @@ import micro from 'micro' -import { resolve } from 'path' +import { resolve, dirname } from 'path' import { readFile } from 'fs/promises' import microrouter from 'microrouter' import { ApolloServer } from 'apollo-server-micro' import { fileURLToPath } from 'url' -import { dirname } from 'path' const { send, createError } = micro const { router, get, post, put, patch, del } = microrouter @@ -34,17 +33,17 @@ const handleMicroError = (error, response) => { // created with the createError function while unknown errors // are simply errors thrown somewhere in the application. -const isUnknownError = error.statusCode == null -const hasOriginalError = error.originalError != null + const isUnknownError = error.statusCode == null + const hasOriginalError = error.originalError != null -// Only log the full error stack when the error isn't a known response -if (isUnknownError === true) { -signale.fatal(error) -return send(response, 500, error.message) -} + // Only log the full error stack when the error isn't a known response + if (isUnknownError === true) { + signale.fatal(error) + return send(response, 500, error.message) + } -signale.warn(hasOriginalError === true ? error.originalError.message : error.message) -send(response, error.statusCode, error.message) + signale.warn(hasOriginalError === true ? error.originalError.message : error.message) + send(response, error.statusCode, error.message) } const handleGraphError = (error) => { @@ -53,101 +52,101 @@ const handleGraphError = (error) => { // errors will only show up in the response and as a warning // in the console output. -const suitableError = error.originalError || error -const isKnownError = suitableError instanceof KnownError + const suitableError = error.originalError || error + const isKnownError = suitableError instanceof KnownError -// Only log the full error stack when the error isn't a known response -if (isKnownError === false) { -signale.fatal(suitableError) -return error -} + // Only log the full error stack when the error isn't a known response + if (isKnownError === false) { + signale.fatal(suitableError) + return error + } -signale.warn(suitableError.message) -return error + signale.warn(suitableError.message) + return error } const catchError = (fn) => async (request, response) => { -try { -return await fn(request, response) -} catch (error) { -handleMicroError(error, response) -} + try { + return await fn(request, response) + } catch (error) { + handleMicroError(error, response) + } } const attachCorsHeaders = (fn) => async (request, response) => { -const matchingOrigin = await findMatchingOrigin(request, config.allowOrigin, config.autoOrigin) - -if (matchingOrigin != null) { -response.setHeader('Access-Control-Allow-Origin', matchingOrigin) -response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS') -response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Time-Zone') -response.setHeader('Access-Control-Allow-Credentials', 'true') -response.setHeader('Access-Control-Max-Age', '3600') -} + const matchingOrigin = await findMatchingOrigin(request, config.allowOrigin, config.autoOrigin) + + if (matchingOrigin != null) { + response.setHeader('Access-Control-Allow-Origin', matchingOrigin) + response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS') + response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Time-Zone') + response.setHeader('Access-Control-Allow-Credentials', 'true') + response.setHeader('Access-Control-Max-Age', '3600') + } -return fn(request, response) + return fn(request, response) } const awaitedHandler = (fn) => async (request, response) => { -return (await fn)(request, response) + return (await fn)(request, response) } const notFound = (request) => { -const error = new Error(`\`${ request.url }\` not found`) + const error = new Error(`\`${ request.url }\` not found`) -throw createError(404, 'Not found', error) + throw createError(404, 'Not found', error) } const apolloServer = createApolloServer(ApolloServer, { -formatError: handleGraphError, -context: createMicroContext, + formatError: handleGraphError, + context: createMicroContext, }) const graphqlPath = '/api' const apolloHandler = apolloServer -.start() -.then(() => apolloServer.createHandler({ path: graphqlPath })) + .start() + .then(() => apolloServer.createHandler({ path: graphqlPath })) const routes = [ -get('/', async (request, response) => { -response.setHeader('Content-Type', 'text/html; charset=utf-8') -response.end(await index) -}), -get('/index.html', async (request, response) => { -response.setHeader('Content-Type', 'text/html; charset=utf-8') -response.end(await index) -}), -get('/favicon.ico', async (request, response) => { -response.setHeader('Content-Type', 'image/vnd.microsoft.icon') -response.end(await favicon) -}), -get('/index.css', async (request, response) => { -response.setHeader('Content-Type', 'text/css; charset=utf-8') -response.end(await styles) -}), -get('/index.js', async (request, response) => { -response.setHeader('Content-Type', 'text/javascript; charset=utf-8') -response.end(await scripts) -}), -get('/tracker.js', async (request, response) => { -response.setHeader('Content-Type', 'text/javascript; charset=utf-8') -response.end(await tracker) -}), -customTracker.exists === true ? get(customTracker.url, async (request, response) => { -response.setHeader('Content-Type', 'text/javascript; charset=utf-8') -response.end(await tracker) -}) : undefined, - -post(graphqlPath, awaitedHandler(apolloHandler)), -get(graphqlPath, awaitedHandler(apolloHandler)), -get('/.well-known/apollo/server-health', awaitedHandler(apolloHandler)), - -get('/*', notFound), -post('/*', notFound), -put('/*', notFound), -patch('/*', notFound), -del('/*', notFound), + get('/', async (request, response) => { + response.setHeader('Content-Type', 'text/html; charset=utf-8') + response.end(await index) + }), + get('/index.html', async (request, response) => { + response.setHeader('Content-Type', 'text/html; charset=utf-8') + response.end(await index) + }), + get('/favicon.ico', async (request, response) => { + response.setHeader('Content-Type', 'image/vnd.microsoft.icon') + response.end(await favicon) + }), + get('/index.css', async (request, response) => { + response.setHeader('Content-Type', 'text/css; charset=utf-8') + response.end(await styles) + }), + get('/index.js', async (request, response) => { + response.setHeader('Content-Type', 'text/javascript; charset=utf-8') + response.end(await scripts) + }), + get('/tracker.js', async (request, response) => { + response.setHeader('Content-Type', 'text/javascript; charset=utf-8') + response.end(await tracker) + }), + customTracker.exists === true ? get(customTracker.url, async (request, response) => { + response.setHeader('Content-Type', 'text/javascript; charset=utf-8') + response.end(await tracker) + }) : undefined, + + post(graphqlPath, awaitedHandler(apolloHandler)), + get(graphqlPath, awaitedHandler(apolloHandler)), + get('/.well-known/apollo/server-health', awaitedHandler(apolloHandler)), + + get('/*', notFound), + post('/*', notFound), + put('/*', notFound), + patch('/*', notFound), + del('/*', notFound), ].filter(Boolean) @@ -157,4 +156,4 @@ catchError( router(...routes), ), ), -) +) \ No newline at end of file diff --git a/src/serverless.js b/src/serverless.js index 03bc66e61..bf7c66696 100644 --- a/src/serverless.js +++ b/src/serverless.js @@ -7,55 +7,55 @@ import createApolloServer from './utils/createApolloServer.js' import { createServerlessContext } from './utils/createContext.js' if (config.dbUrl == null) { -throw new Error('MongoDB connection URI missing in environment') + throw new Error('MongoDB connection URI missing in environment') } connect(config.dbUrl) const apolloServer = createApolloServer(ApolloServer, { -context: createServerlessContext, + context: createServerlessContext, }) const origin = (origin, callback) => { -if (config.autoOrigin === true) { -fullyQualifiedDomainNames() -.then((names) => callback( + if (config.autoOrigin === true) { + fullyQualifiedDomainNames() + .then((names) => callback( null, names.flatMap((name) => [ `http://${ name }`, `https://${ name }`, name ]), -)) -.catch((error) => callback(error, false)) -return -} - -if (config.allowOrigin === '*') { -callback(null, true) -return -} - -if (config.allowOrigin != null) { -callback(null, config.allowOrigin.split(',')) -return -} - -callback(null, false) -return + )) + .catch((error) => callback(error, false)) + return + } + + if (config.allowOrigin === '*') { + callback(null, true) + return + } + + if (config.allowOrigin != null) { + callback(null, config.allowOrigin.split(',')) + return + } + + callback(null, false) + return } export const handler = (event, context) => { // Set request context which is missing on Vercel: // https://stackoverflow.com/questions/71360059/apollo-server-lambda-unable-to-determine-event-source-based-on-event -if (event.requestContext == null) event.requestContext = context - -const handler = apolloServer.createHandler({ -expressGetMiddlewareOptions: { -cors: { -origin, -credentials: true, -methods: [ 'GET', 'POST', 'PATCH', 'OPTIONS' ], -allowedHeaders: [ 'Content-Type', 'Authorization', 'Time-Zone' ], -}, -}, -}) - -return handler(event, context) -} + if (event.requestContext == null) event.requestContext = context + + const handler = apolloServer.createHandler({ + expressGetMiddlewareOptions: { + cors: { + origin, + credentials: true, + methods: [ 'GET', 'POST', 'PATCH', 'OPTIONS' ], + allowedHeaders: [ 'Content-Type', 'Authorization', 'Time-Zone' ], + }, + }, + }) + + return handler(event, context) +} \ No newline at end of file diff --git a/src/ui/index.js b/src/ui/index.js index acb0de3b3..58a6597b8 100644 --- a/src/ui/index.js +++ b/src/ui/index.js @@ -1,8 +1,7 @@ -import { resolve } from 'path' +import { resolve, dirname } from 'path' import { writeFile, readFile } from 'fs/promises' import { createRequire } from 'module' import { fileURLToPath } from 'url' -import { dirname } from 'path' import layout from '../utils/layout.js' import config from '../utils/config.js' @@ -15,54 +14,54 @@ const __dirname = dirname(__filename) const customTracker = { exists, url, path } const index = () => { -return layout('
', 'favicon.ico', [ 'index.css' ], [ 'index.js' ], { -isDemoMode: config.isDemoMode, -customTracker, -}) + return layout('
', 'favicon.ico', [ 'index.css' ], [ 'index.js' ], { + isDemoMode: config.isDemoMode, + customTracker, + }) } const styles = async () => { -const { default: sass } = await import('rosid-handler-sass') -const filePath = resolve(__dirname, './styles/index.scss') + const { default: sass } = await import('rosid-handler-sass') + const filePath = resolve(__dirname, './styles/index.scss') -return sass(filePath, { optimize: config.isDevelopmentMode === false }) + return sass(filePath, { optimize: config.isDevelopmentMode === false }) } const scripts = async () => { -const { default: js } = await import('rosid-handler-js-next') -const filePath = resolve(__dirname, './scripts/index.js') + const { default: js } = await import('rosid-handler-js-next') + const filePath = resolve(__dirname, './scripts/index.js') -return js(filePath, { -optimize: config.isDevelopmentMode === false, -nodeGlobals: config.isDevelopmentMode === true, -replace: { 'process.env.NODE_ENV': JSON.stringify(config.isDevelopmentMode === true ? 'development' : 'production') }, -babel: false, -}) + return js(filePath, { + optimize: config.isDevelopmentMode === false, + nodeGlobals: config.isDevelopmentMode === true, + replace: { 'process.env.NODE_ENV': JSON.stringify(config.isDevelopmentMode === true ? 'development' : 'production') }, + babel: false, + }) } const tracker = () => { -const require = createRequire(import.meta.url) -const filePath = require.resolve('ackee-tracker') + const require = createRequire(import.meta.url) + const filePath = require.resolve('ackee-tracker') -return readFile(filePath, 'utf8') + return readFile(filePath, 'utf8') } const build = async (path, fn) => { -try { -signale.await(`Building and writing '${ path }'`) -const data = await fn() -await writeFile(path, data) -signale.success(`Finished building '${ path }'`) -} catch (error) { -signale.fatal(error) -process.exit(1) -} + try { + signale.await(`Building and writing '${ path }'`) + const data = await fn() + await writeFile(path, data) + signale.success(`Finished building '${ path }'`) + } catch (error) { + signale.fatal(error) + process.exit(1) + } } export { -index, -styles, -scripts, -tracker, -build, -} + index, + styles, + scripts, + tracker, + build, +} \ No newline at end of file diff --git a/src/ui/scripts/utils/rangeLabel.js b/src/ui/scripts/utils/rangeLabel.js index 921ab76ac..130561bbb 100644 --- a/src/ui/scripts/utils/rangeLabel.js +++ b/src/ui/scripts/utils/rangeLabel.js @@ -1,10 +1,10 @@ -import ranges from '../../../constants/ranges' +import { RANGES_LAST_24_HOURS, RANGES_LAST_7_DAYS, RANGES_LAST_30_DAYS, RANGES_LAST_6_MONTHS } from '../../../constants/ranges' export default (range) => { return ({ - [ranges.RANGES_LAST_24_HOURS]: 'Last 24 hours', - [ranges.RANGES_LAST_7_DAYS]: 'Last 7 days', - [ranges.RANGES_LAST_30_DAYS]: 'Last 30 days', - [ranges.RANGES_LAST_6_MONTHS]: 'Last 6 months', + [RANGES_LAST_24_HOURS]: 'Last 24 hours', + [RANGES_LAST_7_DAYS]: 'Last 7 days', + [RANGES_LAST_30_DAYS]: 'Last 30 days', + [RANGES_LAST_6_MONTHS]: 'Last 6 months', })[range] } \ No newline at end of file diff --git a/src/utils/isAuthenticated.js b/src/utils/isAuthenticated.js index 74806ca88..a2127275d 100644 --- a/src/utils/isAuthenticated.js +++ b/src/utils/isAuthenticated.js @@ -1,5 +1,5 @@ -import KnownError from '../utils/KnownError.js' -import isExpired from '../utils/isExpired.js' +import KnownError from './KnownError.js' +import isExpired from './isExpired.js' import * as tokens from '../database/tokens.js' import * as permanentTokens from '../database/permanentTokens.js' diff --git a/test/aggregations/aggregateActiveVisitors.js b/test/aggregations/aggregateActiveVisitors.js index a83ccc74b..1c28cd9d2 100644 --- a/test/aggregations/aggregateActiveVisitors.js +++ b/test/aggregations/aggregateActiveVisitors.js @@ -5,7 +5,7 @@ import aggregateActiveVisitors from '../../src/aggregations/aggregateActiveVisit import createDate from '../../src/utils/createDate.js' test('return aggregation', (t) => { -const result = aggregateActiveVisitors(uuid(), createDate()) + const result = aggregateActiveVisitors(uuid(), createDate()) -t.true(Array.isArray(result)) -}) + t.true(Array.isArray(result)) +}) \ No newline at end of file diff --git a/test/aggregations/aggregateDurations.js b/test/aggregations/aggregateDurations.js index 67147cd98..35c702a5b 100644 --- a/test/aggregations/aggregateDurations.js +++ b/test/aggregations/aggregateDurations.js @@ -6,7 +6,7 @@ import { INTERVALS_DAILY } from '../../src/constants/intervals.js' import createDate from '../../src/utils/createDate.js' test('return aggregation', (t) => { -const result = aggregateDurations(uuid(), INTERVALS_DAILY, 14, createDate()) + const result = aggregateDurations(uuid(), INTERVALS_DAILY, 14, createDate()) -t.true(Array.isArray(result)) -}) + t.true(Array.isArray(result)) +}) \ No newline at end of file diff --git a/test/aggregations/aggregateNewFields.js b/test/aggregations/aggregateNewFields.js index 016ef8ad6..2ea3bd175 100644 --- a/test/aggregations/aggregateNewFields.js +++ b/test/aggregations/aggregateNewFields.js @@ -4,7 +4,7 @@ import { randomUUID as uuid } from 'crypto' import aggregateNewRecords from '../../src/aggregations/aggregateNewRecords.js' test('return aggregation', (t) => { -const result = aggregateNewRecords(uuid(), [ 'siteReferrer' ]) + const result = aggregateNewRecords(uuid(), [ 'siteReferrer' ]) -t.true(Array.isArray(result)) -}) + t.true(Array.isArray(result)) +}) \ No newline at end of file diff --git a/test/aggregations/aggregateRecentFields.js b/test/aggregations/aggregateRecentFields.js index 41fc0579b..8f0568b02 100644 --- a/test/aggregations/aggregateRecentFields.js +++ b/test/aggregations/aggregateRecentFields.js @@ -4,7 +4,7 @@ import { randomUUID as uuid } from 'crypto' import aggregateRecentRecords from '../../src/aggregations/aggregateRecentRecords.js' test('return aggregation', (t) => { -const result = aggregateRecentRecords(uuid(), [ 'osName', 'osVersion' ]) + const result = aggregateRecentRecords(uuid(), [ 'osName', 'osVersion' ]) -t.true(Array.isArray(result)) -}) + t.true(Array.isArray(result)) +}) \ No newline at end of file diff --git a/test/aggregations/aggregateTopFields.js b/test/aggregations/aggregateTopFields.js index acf81661c..82e9a46a7 100644 --- a/test/aggregations/aggregateTopFields.js +++ b/test/aggregations/aggregateTopFields.js @@ -5,7 +5,7 @@ import aggregateTopRecords from '../../src/aggregations/aggregateTopRecords.js' import createDate from '../../src/utils/createDate.js' test('return aggregation', (t) => { -const result = aggregateTopRecords(uuid(), [ 'osName', 'osVersion' ], createDate()) + const result = aggregateTopRecords(uuid(), [ 'osName', 'osVersion' ], createDate()) -t.true(Array.isArray(result)) -}) + t.true(Array.isArray(result)) +}) \ No newline at end of file diff --git a/test/aggregations/aggregateViews.js b/test/aggregations/aggregateViews.js index 8fe699eac..d46a7cd66 100644 --- a/test/aggregations/aggregateViews.js +++ b/test/aggregations/aggregateViews.js @@ -6,13 +6,13 @@ import { INTERVALS_DAILY } from '../../src/constants/intervals.js' import createDate from '../../src/utils/createDate.js' test('return unique aggregation', (t) => { -const result = aggregateViews(uuid(), true, INTERVALS_DAILY, 14, createDate()) + const result = aggregateViews(uuid(), true, INTERVALS_DAILY, 14, createDate()) -t.true(Array.isArray(result)) + t.true(Array.isArray(result)) }) test('return non-unique aggregation', (t) => { -const result = aggregateViews(uuid(), false, INTERVALS_DAILY, 14, createDate()) + const result = aggregateViews(uuid(), false, INTERVALS_DAILY, 14, createDate()) -t.true(Array.isArray(result)) -}) + t.true(Array.isArray(result)) +}) \ No newline at end of file diff --git a/test/resolvers/_utils.js b/test/resolvers/_utils.js index 893cd45b3..553d167a4 100644 --- a/test/resolvers/_utils.js +++ b/test/resolvers/_utils.js @@ -14,94 +14,94 @@ import { day, minute } from '../../src/utils/times.js' const mongoDb = MongoMemoryServer.create() const connectToDatabase = async () => { -const dbUrl = (await mongoDb).getUri() -return connect(dbUrl) + const dbUrl = (await mongoDb).getUri() + return connect(dbUrl) } const fillDatabase = async (t) => { // Saves to context so tests can access ids -t.context.token = await Token.create({}) -t.context.permanentToken = await PermanentToken.create({ title: 'Example' }) -t.context.domain = await Domain.create({ title: 'Example' }) -t.context.event = await Event.create({ title: 'Example', type: 'TOTAL_CHART' }) + t.context.token = await Token.create({}) + t.context.permanentToken = await PermanentToken.create({ title: 'Example' }) + t.context.domain = await Domain.create({ title: 'Example' }) + t.context.event = await Event.create({ title: 'Example', type: 'TOTAL_CHART' }) -const now = Date.now() + const now = Date.now() -const records = createArray(14).map((item, index) => ({ -clientId: `client-${ index }`, -domainId: t.context.domain.id, -siteLocation: 'https://example.com/', -siteReferrer: 'https://google.com/', -siteLanguage: 'en', -source: index > 4 ? 'Newsletter' : undefined, -screenWidth: index === 1 ? 0 : 414, -screenHeight: index === 1 ? 0 : 896, -screenColorDepth: 32, -deviceName: 'iPhone', -deviceManufacturer: 'Apple', -osName: 'iOS', -osVersion: index > 7 ? '13.0' : '14.0', -browserName: 'Safari', -browserVersion: index > 7 ? '13.0' : '14.0', -browserWidth: index === 1 ? 0 : 414, -browserHeight: index === 1 ? 0 : 719, -// Set fake duration -created: now - index * day - minute, -updated: now - index * day, -})) + const records = createArray(14).map((item, index) => ({ + clientId: `client-${ index }`, + domainId: t.context.domain.id, + siteLocation: 'https://example.com/', + siteReferrer: 'https://google.com/', + siteLanguage: 'en', + source: index > 4 ? 'Newsletter' : undefined, + screenWidth: index === 1 ? 0 : 414, + screenHeight: index === 1 ? 0 : 896, + screenColorDepth: 32, + deviceName: 'iPhone', + deviceManufacturer: 'Apple', + osName: 'iOS', + osVersion: index > 7 ? '13.0' : '14.0', + browserName: 'Safari', + browserVersion: index > 7 ? '13.0' : '14.0', + browserWidth: index === 1 ? 0 : 414, + browserHeight: index === 1 ? 0 : 719, + // Set fake duration + created: now - index * day - minute, + updated: now - index * day, + })) -const actions = createArray(14).map((item, index) => ({ -eventId: t.context.event.id, -key: `Key ${ index + 1 }`, -value: index + 1, -created: now - index * day, -updated: now - index * day, -})) + const actions = createArray(14).map((item, index) => ({ + eventId: t.context.event.id, + key: `Key ${ index + 1 }`, + value: index + 1, + created: now - index * day, + updated: now - index * day, + })) -await Record.insertMany(records) -await Action.insertMany(actions) + await Record.insertMany(records) + await Action.insertMany(actions) } const cleanupDatabase = async (t) => { -await Token.findOneAndDelete({ -id: t.context.token.id, -}) -await Domain.findOneAndDelete({ -id: t.context.domain.id, -}) + await Token.findOneAndDelete({ + id: t.context.token.id, + }) + await Domain.findOneAndDelete({ + id: t.context.domain.id, + }) } const disconnectFromDatabase = async () => { -mongoose.disconnect() -;(await mongoDb).stop() + mongoose.disconnect() + ;(await mongoDb).stop() } const api = async (base, body, token, headers = {}) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const defaultHeaders = {} -defaultHeaders['Content-Type'] = 'application/json' -defaultHeaders['Authorization'] = token == null ? undefined : `Bearer ${ token }` + const defaultHeaders = {} + defaultHeaders['Content-Type'] = 'application/json' + defaultHeaders['Authorization'] = token == null ? undefined : `Bearer ${ token }` -const result = await fetch(url.href, { -method: 'post', -body: JSON.stringify(body), -headers: { -...defaultHeaders, -...headers, -}, -}) + const result = await fetch(url.href, { + method: 'post', + body: JSON.stringify(body), + headers: { + ...defaultHeaders, + ...headers, + }, + }) -return { -headers: result.headers, -json: await result.json(), -} + return { + headers: result.headers, + json: await result.json(), + } } export { -connectToDatabase, -fillDatabase, -cleanupDatabase, -disconnectFromDatabase, -api, -} + connectToDatabase, + fillDatabase, + cleanupDatabase, + disconnectFromDatabase, + api, +} \ No newline at end of file diff --git a/test/server.js b/test/server.js index e89fec716..a17505851 100644 --- a/test/server.js +++ b/test/server.js @@ -7,42 +7,42 @@ import server from '../src/server.js' const base = listen(server) test('return 404', async (t) => { -const url = new URL(`/${ uuid() }`, await base) -const { status } = await fetch(url.href) + const url = new URL(`/${ uuid() }`, await base) + const { status } = await fetch(url.href) -t.is(status, 404) + t.is(status, 404) }) test('return production styles', async (t) => { -const url = new URL('/index.css', await base) -const response = await fetch(url.href) -const content = await response.text() + const url = new URL('/index.css', await base) + const response = await fetch(url.href) + const content = await response.text() -t.is(typeof content, 'string') -t.false(content.includes('sourceMappingURL')) + t.is(typeof content, 'string') + t.false(content.includes('sourceMappingURL')) }) test('return production scripts', async (t) => { -const url = new URL('/index.js', await base) -const response = await fetch(url.href) -const content = await response.text() + const url = new URL('/index.js', await base) + const response = await fetch(url.href) + const content = await response.text() -t.is(typeof content, 'string') -t.false(content.includes('sourceMappingURL')) + t.is(typeof content, 'string') + t.false(content.includes('sourceMappingURL')) }) test('return tracker', async (t) => { -const url = new URL('/tracker.js', await base) -const response = await fetch(url.href) -const content = await response.text() + const url = new URL('/tracker.js', await base) + const response = await fetch(url.href) + const content = await response.text() -t.is(typeof content, 'string') -t.false(content.includes('sourceMappingURL')) + t.is(typeof content, 'string') + t.false(content.includes('sourceMappingURL')) }) test('return favicon', async (t) => { -const url = new URL('/favicon.ico', await base) -const { status } = await fetch(url.href) + const url = new URL('/favicon.ico', await base) + const { status } = await fetch(url.href) -t.is(status, 200) -}) + t.is(status, 200) +}) \ No newline at end of file diff --git a/test/serverWithAutoCors.js b/test/serverWithAutoCors.js index a7e5c2366..69d7f0b60 100644 --- a/test/serverWithAutoCors.js +++ b/test/serverWithAutoCors.js @@ -11,34 +11,34 @@ const base = listen(server) test.before(connectToDatabase) test.after.always(disconnectFromDatabase) test.beforeEach(async (t) => { -t.context.domain1 = await Domain.create({ title: 'fqdn.example.com' }) -t.context.domain2 = await Domain.create({ title: 'No fqdn' }) + t.context.domain1 = await Domain.create({ title: 'fqdn.example.com' }) + t.context.domain2 = await Domain.create({ title: 'No fqdn' }) }) test.afterEach.always(async (t) => { -await Domain.findOneAndDelete({ id: t.context.domain1.id }) -await Domain.findOneAndDelete({ id: t.context.domain2.id }) + await Domain.findOneAndDelete({ id: t.context.domain1.id }) + await Domain.findOneAndDelete({ id: t.context.domain2.id }) }) test('return cors headers based on fully qualifed domain names', async (t) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const restore = mockedEnv({ -ACKEE_AUTO_ORIGIN: 'true', -}) + const restore = mockedEnv({ + ACKEE_AUTO_ORIGIN: 'true', + }) -const { headers: fqdnHeaders } = await fetch(url.href, { headers: { Host: 'fqdn.example.com' } }) + const { headers: fqdnHeaders } = await fetch(url.href, { headers: { Host: 'fqdn.example.com' } }) -t.is(fqdnHeaders.get('Access-Control-Allow-Origin'), 'fqdn.example.com') -t.is(fqdnHeaders.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') -t.is(fqdnHeaders.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') -t.is(fqdnHeaders.get('Access-Control-Allow-Credentials'), 'true') + t.is(fqdnHeaders.get('Access-Control-Allow-Origin'), 'fqdn.example.com') + t.is(fqdnHeaders.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') + t.is(fqdnHeaders.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') + t.is(fqdnHeaders.get('Access-Control-Allow-Credentials'), 'true') -const { headers: noFqdnHeaders } = await fetch(url.href, { headers: { Host: 'No fqdn' } }) + const { headers: noFqdnHeaders } = await fetch(url.href, { headers: { Host: 'No fqdn' } }) -t.is(noFqdnHeaders.get('Access-Control-Allow-Origin'), null) -t.is(noFqdnHeaders.get('Access-Control-Allow-Methods'), null) -t.is(noFqdnHeaders.get('Access-Control-Allow-Headers'), null) -t.is(noFqdnHeaders.get('Access-Control-Allow-Credentials'), null) + t.is(noFqdnHeaders.get('Access-Control-Allow-Origin'), null) + t.is(noFqdnHeaders.get('Access-Control-Allow-Methods'), null) + t.is(noFqdnHeaders.get('Access-Control-Allow-Headers'), null) + t.is(noFqdnHeaders.get('Access-Control-Allow-Credentials'), null) -restore() -}) + restore() +}) \ No newline at end of file diff --git a/test/serverWithCors.js b/test/serverWithCors.js index 80107386c..40e9cee01 100644 --- a/test/serverWithCors.js +++ b/test/serverWithCors.js @@ -7,19 +7,19 @@ import server from '../src/server.js' const base = listen(server) test('return cors headers if env var specifies one', async (t) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const restore = mockedEnv({ -ACKEE_ALLOW_ORIGIN: url.origin, -}) + const restore = mockedEnv({ + ACKEE_ALLOW_ORIGIN: url.origin, + }) -const { headers } = await fetch(url.href) + const { headers } = await fetch(url.href) -t.is(headers.get('Access-Control-Allow-Origin'), url.origin) -t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') -t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') -t.is(headers.get('Access-Control-Allow-Credentials'), 'true') -t.is(headers.get('Access-Control-Max-Age'), '3600') + t.is(headers.get('Access-Control-Allow-Origin'), url.origin) + t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') + t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') + t.is(headers.get('Access-Control-Allow-Credentials'), 'true') + t.is(headers.get('Access-Control-Max-Age'), '3600') -restore() -}) + restore() +}) \ No newline at end of file diff --git a/test/serverWithMultipleCors.js b/test/serverWithMultipleCors.js index db6ce4a67..df8ca716f 100644 --- a/test/serverWithMultipleCors.js +++ b/test/serverWithMultipleCors.js @@ -7,19 +7,19 @@ import server from '../src/server.js' const base = listen(server) test('return cors headers with corresponding origin if env var specifies multiple origins', async (t) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const restore = mockedEnv({ -ACKEE_ALLOW_ORIGIN: `https://example.com,${ url.origin }`, -}) + const restore = mockedEnv({ + ACKEE_ALLOW_ORIGIN: `https://example.com,${ url.origin }`, + }) -const { headers } = await fetch(url.href) + const { headers } = await fetch(url.href) -t.is(headers.get('Access-Control-Allow-Origin'), url.origin) -t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') -t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') -t.is(headers.get('Access-Control-Allow-Credentials'), 'true') -t.is(headers.get('Access-Control-Max-Age'), '3600') + t.is(headers.get('Access-Control-Allow-Origin'), url.origin) + t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') + t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') + t.is(headers.get('Access-Control-Allow-Credentials'), 'true') + t.is(headers.get('Access-Control-Max-Age'), '3600') -restore() -}) + restore() +}) \ No newline at end of file diff --git a/test/serverWithUnlistedCors.js b/test/serverWithUnlistedCors.js index 09391d97f..8d8a80e99 100644 --- a/test/serverWithUnlistedCors.js +++ b/test/serverWithUnlistedCors.js @@ -7,19 +7,19 @@ import server from '../src/server.js' const base = listen(server) test('return cors headers with no origin if hostname not whitelisted in env var', async (t) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const restore = mockedEnv({ -ACKEE_ALLOW_ORIGIN: 'https://example.com', -}) + const restore = mockedEnv({ + ACKEE_ALLOW_ORIGIN: 'https://example.com', + }) -const { headers } = await fetch(url.href) + const { headers } = await fetch(url.href) -t.is(headers.get('Access-Control-Allow-Origin'), null) -t.is(headers.get('Access-Control-Allow-Methods'), null) -t.is(headers.get('Access-Control-Allow-Headers'), null) -t.is(headers.get('Access-Control-Allow-Credentials'), null) -t.is(headers.get('Access-Control-Max-Age'), null) + t.is(headers.get('Access-Control-Allow-Origin'), null) + t.is(headers.get('Access-Control-Allow-Methods'), null) + t.is(headers.get('Access-Control-Allow-Headers'), null) + t.is(headers.get('Access-Control-Allow-Credentials'), null) + t.is(headers.get('Access-Control-Max-Age'), null) -restore() -}) + restore() +}) \ No newline at end of file diff --git a/test/serverWithWildcardCors.js b/test/serverWithWildcardCors.js index 4383f84b1..a7b5e183b 100644 --- a/test/serverWithWildcardCors.js +++ b/test/serverWithWildcardCors.js @@ -7,19 +7,19 @@ import server from '../src/server.js' const base = listen(server) test('return cors headers if env vars specify wildcard', async (t) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const restore = mockedEnv({ -ACKEE_ALLOW_ORIGIN: '*', -}) + const restore = mockedEnv({ + ACKEE_ALLOW_ORIGIN: '*', + }) -const { headers } = await fetch(url.href) + const { headers } = await fetch(url.href) -t.is(headers.get('Access-Control-Allow-Origin'), '*') -t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') -t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') -t.is(headers.get('Access-Control-Allow-Credentials'), 'true') -t.is(headers.get('Access-Control-Max-Age'), '3600') + t.is(headers.get('Access-Control-Allow-Origin'), '*') + t.is(headers.get('Access-Control-Allow-Methods'), 'GET, POST, PATCH, OPTIONS') + t.is(headers.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') + t.is(headers.get('Access-Control-Allow-Credentials'), 'true') + t.is(headers.get('Access-Control-Max-Age'), '3600') -restore() -}) + restore() +}) \ No newline at end of file diff --git a/test/serverWithoutCors.js b/test/serverWithoutCors.js index 9f80d8f12..0fbce47fa 100644 --- a/test/serverWithoutCors.js +++ b/test/serverWithoutCors.js @@ -7,19 +7,19 @@ import server from '../src/server.js' const base = listen(server) test('return no cors headers if env var specifies none', async (t) => { -const url = new URL('/api', await base) + const url = new URL('/api', await base) -const restore = mockedEnv({ -ACKEE_ALLOW_ORIGIN: undefined, -}) + const restore = mockedEnv({ + ACKEE_ALLOW_ORIGIN: undefined, + }) -const { headers } = await fetch(url.href) + const { headers } = await fetch(url.href) -t.is(headers.get('Access-Control-Allow-Origin'), null) -t.is(headers.get('Access-Control-Allow-Methods'), null) -t.is(headers.get('Access-Control-Allow-Headers'), null) -t.is(headers.get('Access-Control-Allow-Credentials'), null) -t.is(headers.get('Access-Control-Max-Age'), null) + t.is(headers.get('Access-Control-Allow-Origin'), null) + t.is(headers.get('Access-Control-Allow-Methods'), null) + t.is(headers.get('Access-Control-Allow-Headers'), null) + t.is(headers.get('Access-Control-Allow-Credentials'), null) + t.is(headers.get('Access-Control-Max-Age'), null) -restore() -}) + restore() +}) \ No newline at end of file diff --git a/test/utils/createArray.js b/test/utils/createArray.js index ef7496ff2..5bd7805be 100644 --- a/test/utils/createArray.js +++ b/test/utils/createArray.js @@ -3,9 +3,9 @@ import test from 'ava' import createArray from '../../src/utils/createArray.js' test('return boolean', (t) => { -const length = 4 -const result = createArray(length) + const length = 4 + const result = createArray(length) -t.true(Array.isArray(result)) -t.is(result.length, length) -}) + t.true(Array.isArray(result)) + t.is(result.length, length) +}) \ No newline at end of file diff --git a/test/utils/customTrackerUrl.js b/test/utils/customTrackerUrl.js index 43922b5a2..11fd7bf33 100644 --- a/test/utils/customTrackerUrl.js +++ b/test/utils/customTrackerUrl.js @@ -3,21 +3,21 @@ import test from 'ava' import * as customTracker from '../../src/utils/customTracker.js' test('return that a custom tracker exists', (t) => { -const result = customTracker.exists + const result = customTracker.exists -t.true(result) + t.true(result) }) test('return custom URL', (t) => { -const result = customTracker.url + const result = customTracker.url -// The name is specified in the package.json ava configuration -t.is(result, `/custom%20name.js`) + // The name is specified in the package.json ava configuration + t.is(result, `/custom%20name.js`) }) test('return custom path', (t) => { -const result = customTracker.path + const result = customTracker.path -// The name is specified in the package.json ava configuration -t.is(result, `custom name.js`) -}) + // The name is specified in the package.json ava configuration + t.is(result, `custom name.js`) +}) \ No newline at end of file diff --git a/test/utils/identifier.js b/test/utils/identifier.js index 6e5c25b8f..0b790df51 100644 --- a/test/utils/identifier.js +++ b/test/utils/identifier.js @@ -4,40 +4,40 @@ import { randomUUID as uuid } from 'crypto' import identifier from '../../src/utils/identifier.js' test('return different identifiers', (t) => { -const domainId = uuid() - -const request = () => ({ -headers: { -'user-agent': uuid(), -}, -connection: { -remoteAddress: uuid(), -}, -}) + const domainId = uuid() + + const request = () => ({ + headers: { + 'user-agent': uuid(), + }, + connection: { + remoteAddress: uuid(), + }, + }) -const requestA = request() -const requestB = request() + const requestA = request() + const requestB = request() -const a = identifier(requestA, requestA.headers['user-agent'], domainId) -const b = identifier(requestB, requestB.headers['user-agent'], domainId) + const a = identifier(requestA, requestA.headers['user-agent'], domainId) + const b = identifier(requestB, requestB.headers['user-agent'], domainId) -t.not(a, b) + t.not(a, b) }) test('return same identifiers', (t) => { -const domainId = uuid() - -const request = { -headers: { -'user-agent': uuid(), -}, -connection: { -remoteAddress: uuid(), -}, -} - -const a = identifier(request, request.headers['user-agent'], domainId) -const b = identifier(request, request.headers['user-agent'], domainId) - -t.is(a, b) -}) + const domainId = uuid() + + const request = { + headers: { + 'user-agent': uuid(), + }, + connection: { + remoteAddress: uuid(), + }, + } + + const a = identifier(request, request.headers['user-agent'], domainId) + const b = identifier(request, request.headers['user-agent'], domainId) + + t.is(a, b) +}) \ No newline at end of file diff --git a/test/utils/isExpired.js b/test/utils/isExpired.js index 1605d2a4c..c1c4f2f77 100644 --- a/test/utils/isExpired.js +++ b/test/utils/isExpired.js @@ -4,19 +4,19 @@ import { day } from '../../src/utils/times.js' import isExpired from '../../src/utils/isExpired.js' test('return true when `timestamp` has expired', (t) => { -const date = new Date() -date.setDate(date.getDate() - 2) -const timestamp = date.getTime() + const date = new Date() + date.setDate(date.getDate() - 2) + const timestamp = date.getTime() -const result = isExpired(timestamp, day) + const result = isExpired(timestamp, day) -t.true(result) + t.true(result) }) test('return false when `timestamp` is valid', (t) => { -const timestamp = Date.now() + const timestamp = Date.now() -const result = isExpired(timestamp, day) + const result = isExpired(timestamp, day) -t.false(result) -}) + t.false(result) +}) \ No newline at end of file diff --git a/test/utils/layout.js b/test/utils/layout.js index c106bacaf..b4c671bfd 100644 --- a/test/utils/layout.js +++ b/test/utils/layout.js @@ -4,31 +4,31 @@ import { randomUUID as uuid } from 'crypto' import layout from '../../src/utils/layout.js' test('return HTML with body', (t) => { -const body = uuid() -const result = layout(body, '', [], []) + const body = uuid() + const result = layout(body, '', [], []) -t.true(result.includes(body)) + t.true(result.includes(body)) }) test('return HTML with favicon', (t) => { -const favicon = uuid() -const result = layout('', favicon, [], []) + const favicon = uuid() + const result = layout('', favicon, [], []) -t.true(result.includes(favicon)) + t.true(result.includes(favicon)) }) test('return HTML with styles', (t) => { -const styles = [ uuid(), uuid() ] -const result = layout('', '', styles, []) + const styles = [ uuid(), uuid() ] + const result = layout('', '', styles, []) -t.true(result.includes(styles[0])) -t.true(result.includes(styles[1])) + t.true(result.includes(styles[0])) + t.true(result.includes(styles[1])) }) test('return HTML with scripts', (t) => { -const scripts = [ uuid(), uuid() ] -const result = layout('', '', [], scripts) + const scripts = [ uuid(), uuid() ] + const result = layout('', '', [], scripts) -t.true(result.includes(scripts[0])) -t.true(result.includes(scripts[1])) -}) + t.true(result.includes(scripts[0])) + t.true(result.includes(scripts[1])) +}) \ No newline at end of file diff --git a/test/utils/messages.js b/test/utils/messages.js index 87e45734e..5f55d0bca 100644 --- a/test/utils/messages.js +++ b/test/utils/messages.js @@ -4,19 +4,19 @@ import { randomUUID as uuid } from 'crypto' import messages from '../../src/utils/messages.js' test('extract messages from an object with errors', (t) => { -const message = uuid() -const errors = { 0: new Error(message) } + const message = uuid() + const errors = { 0: new Error(message) } -const result = messages(errors) + const result = messages(errors) -t.is(result, message) + t.is(result, message) }) test('remove dot at the end of message', (t) => { -const message = uuid() -const errors = { 0: new Error(`${ message }.`) } + const message = uuid() + const errors = { 0: new Error(`${ message }.`) } -const result = messages(errors) + const result = messages(errors) -t.is(result, message) -}) + t.is(result, message) +}) \ No newline at end of file diff --git a/test/utils/normalizeUrl.js b/test/utils/normalizeUrl.js index bb98bffbc..143e956d0 100644 --- a/test/utils/normalizeUrl.js +++ b/test/utils/normalizeUrl.js @@ -4,29 +4,29 @@ import { randomUUID as uuid } from 'crypto' import normalizeUrl from '../../src/utils/normalizeUrl.js' test('remove directory index', (t) => { -const url = 'https://example.com/index.html' -const result = normalizeUrl(url) + const url = 'https://example.com/index.html' + const result = normalizeUrl(url) -t.is(result, 'https://example.com') + t.is(result, 'https://example.com') }) test('remove ref query parameter', (t) => { -const url = `https://example.com/?ref=${ uuid() }` -const result = normalizeUrl(url) + const url = `https://example.com/?ref=${ uuid() }` + const result = normalizeUrl(url) -t.is(result, 'https://example.com') + t.is(result, 'https://example.com') }) test('remove fbclid query parameter', (t) => { -const url = `https://example.com/?fbclid=${ uuid() }` -const result = normalizeUrl(url) + const url = `https://example.com/?fbclid=${ uuid() }` + const result = normalizeUrl(url) -t.is(result, 'https://example.com') + t.is(result, 'https://example.com') }) test('remove source query parameter', (t) => { -const url = `https://example.com/?source=${ uuid() }` -const result = normalizeUrl(url) + const url = `https://example.com/?source=${ uuid() }` + const result = normalizeUrl(url) -t.is(result, 'https://example.com') -}) + t.is(result, 'https://example.com') +}) \ No newline at end of file diff --git a/test/utils/pipe.js b/test/utils/pipe.js index 2c1fdb5be..7542f5bcc 100644 --- a/test/utils/pipe.js +++ b/test/utils/pipe.js @@ -4,24 +4,24 @@ import { randomUUID as uuid } from 'crypto' import pipe from '../../src/utils/pipe.js' test('return response of first function with a return value', async (t) => { -const _b = uuid() -const _c = uuid() + const _b = uuid() + const _c = uuid() -const a = () => null -const b = () => _b -const c = () => _c + const a = () => null + const b = () => _b + const c = () => _c -const result = await pipe(a, b, c)() + const result = await pipe(a, b, c)() -t.is(result, _b) + t.is(result, _b) }) test('pass parameter to functions in pipe', async (t) => { -const _a = uuid() + const _a = uuid() -const a = (param) => param + const a = (param) => param -const result = await pipe(a)(_a) + const result = await pipe(a)(_a) -t.is(result, _a) -}) + t.is(result, _a) +}) \ No newline at end of file diff --git a/test/utils/salt.js b/test/utils/salt.js index da7f4222c..6af631055 100644 --- a/test/utils/salt.js +++ b/test/utils/salt.js @@ -3,8 +3,8 @@ import test from 'ava' import salt from '../../src/utils/salt.js' test('return same result as long as it is the same day', (t) => { -const a = salt() -const b = salt() + const a = salt() + const b = salt() -t.is(a, b) -}) + t.is(a, b) +}) \ No newline at end of file diff --git a/test/utils/signale.js b/test/utils/signale.js index 28e5e8f4f..7a4767136 100644 --- a/test/utils/signale.js +++ b/test/utils/signale.js @@ -6,5 +6,5 @@ import signale from '../../src/utils/signale.js' const { Signale } = signaleModule test('is a Signale instance', (t) => { -t.true(signale instanceof Signale) -}) + t.true(signale instanceof Signale) +}) \ No newline at end of file diff --git a/test/utils/stripUrlAuth.js b/test/utils/stripUrlAuth.js index 3adb8a870..6605810f0 100644 --- a/test/utils/stripUrlAuth.js +++ b/test/utils/stripUrlAuth.js @@ -3,14 +3,14 @@ import test from 'ava' import stripUrlAuth from '../../src/utils/stripUrlAuth.js' test('remove user and password', (t) => { -const url = 'mongodb://username:password@host:3000/database' -const result = 'mongodb://host:3000/database' + const url = 'mongodb://username:password@host:3000/database' + const result = 'mongodb://host:3000/database' -t.is(stripUrlAuth(url), result) + t.is(stripUrlAuth(url), result) }) test('do nothing without username or password', (t) => { -const url = 'mongodb://host:3000/database' + const url = 'mongodb://host:3000/database' -t.is(stripUrlAuth(url), url) -}) + t.is(stripUrlAuth(url), url) +}) \ No newline at end of file diff --git a/test/utils/timeZone.js b/test/utils/timeZone.js index 7b3cd0e60..f1fdc9714 100644 --- a/test/utils/timeZone.js +++ b/test/utils/timeZone.js @@ -3,6 +3,6 @@ import test from 'ava' import timeZone from '../../src/utils/timeZone.js' test('returns timeZone', (t) => { -new Intl.DateTimeFormat(undefined, { timeZone }) -t.pass() -}) + new Intl.DateTimeFormat(undefined, { timeZone }) + t.pass() +}) \ No newline at end of file diff --git a/test/utils/times.js b/test/utils/times.js index bc46101ff..af51e0d5d 100644 --- a/test/utils/times.js +++ b/test/utils/times.js @@ -3,17 +3,17 @@ import test from 'ava' import * as times from '../../src/utils/times.js' test('return one second in milliseconds', (t) => { -t.is(times.second, 1000) + t.is(times.second, 1000) }) test('return one minute in milliseconds', (t) => { -t.is(times.minute, 60000) + t.is(times.minute, 60000) }) test('return one hour in milliseconds', (t) => { -t.is(times.hour, 3600000) + t.is(times.hour, 3600000) }) test('return one day in milliseconds', (t) => { -t.is(times.day, 86400000) -}) + t.is(times.day, 86400000) +}) \ No newline at end of file From ff22ee8b88b8d761037245ec8bd8128402e7e439 Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 21 Feb 2026 09:53:20 +0100 Subject: [PATCH 4/6] Export const directly --- src/database/actions.js | 18 +++++------------- src/database/domains.js | 18 +++++------------- src/database/events.js | 18 +++++------------- src/database/permanentTokens.js | 18 +++++------------- src/database/records.js | 15 ++++----------- src/database/tokens.js | 15 ++++----------- src/ui/index.js | 18 +++++------------- src/utils/createContext.js | 9 ++------- src/utils/times.js | 15 ++++----------- test/resolvers/_utils.js | 18 +++++------------- test/resolvers/domainStatistics/_utils.js | 6 ++---- test/resolvers/eventStatistics/_utils.js | 6 ++---- 12 files changed, 48 insertions(+), 126 deletions(-) diff --git a/src/database/actions.js b/src/database/actions.js index ca8b6cef4..1b455fd14 100644 --- a/src/database/actions.js +++ b/src/database/actions.js @@ -20,7 +20,7 @@ const response = (entry) => ({ updated: entry.updated, }) -const add = async (data) => { +export const add = async (data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -30,7 +30,7 @@ const add = async (data) => { ) } -const update = async (id, data) => { +export const update = async (id, data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -51,7 +51,7 @@ const update = async (id, data) => { ) } -const getChart = async (ids, type, interval, limit, dateDetails) => { +export const getChart = async (ids, type, interval, limit, dateDetails) => { const aggregation = (() => { if (type === 'TOTAL') return aggregateActions(ids, false, interval, limit, dateDetails) if (type === 'AVERAGE') return aggregateActions(ids, true, interval, limit, dateDetails) @@ -99,7 +99,7 @@ const getChart = async (ids, type, interval, limit, dateDetails) => { ) } -const getList = async (ids, sorting, type, range, limit, dateDetails) => { +export const getList = async (ids, sorting, type, range, limit, dateDetails) => { const aggregation = (() => { if (type === 'TOTAL') { if (sorting === SORTINGS_TOP) return aggregateTopActions(ids, false, range, limit, dateDetails) @@ -135,16 +135,8 @@ const getList = async (ids, sorting, type, range, limit, dateDetails) => { ) } -const del = (eventId) => { +export const del = (eventId) => { return Action.deleteMany({ eventId, }) -} - -export { - add, - update, - getChart, - getList, - del, } \ No newline at end of file diff --git a/src/database/domains.js b/src/database/domains.js index 55d37131a..01161476e 100644 --- a/src/database/domains.js +++ b/src/database/domains.js @@ -8,7 +8,7 @@ const response = (entry) => ({ updated: entry.updated, }) -const add = async (data) => { +export const add = async (data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -20,7 +20,7 @@ await Domain.create({ ) } -const all = async () => { +export const all = async () => { const enhance = (entries) => { return entries .map(response) @@ -32,7 +32,7 @@ await Domain.find({}), ) } -const get = async (id) => { +export const get = async (id) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -42,7 +42,7 @@ await Domain.findOne({ id }), ) } -const update = async (id, data) => { +export const update = async (id, data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -61,16 +61,8 @@ await Domain.findOneAndUpdate({ ) } -const del = (id) => { +export const del = (id) => { return Domain.findOneAndDelete({ id, }) -} - -export { - add, - all, - get, - update, - del, } \ No newline at end of file diff --git a/src/database/events.js b/src/database/events.js index d1b15c57e..6741fbe22 100644 --- a/src/database/events.js +++ b/src/database/events.js @@ -9,7 +9,7 @@ const response = (entry) => ({ updated: entry.updated, }) -const add = async (data) => { +export const add = async (data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -19,7 +19,7 @@ await Event.create(data), ) } -const all = async () => { +export const all = async () => { const enhance = (entries) => { return entries .map(response) @@ -31,7 +31,7 @@ await Event.find({}), ) } -const get = async (id) => { +export const get = async (id) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -41,7 +41,7 @@ await Event.findOne({ id }), ) } -const update = async (id, data) => { +export const update = async (id, data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -61,16 +61,8 @@ await Event.findOneAndUpdate({ ) } -const del = (id) => { +export const del = (id) => { return Event.findOneAndDelete({ id, }) -} - -export { - add, - all, - get, - update, - del, } \ No newline at end of file diff --git a/src/database/permanentTokens.js b/src/database/permanentTokens.js index 9bf0a2354..b87cfee7d 100644 --- a/src/database/permanentTokens.js +++ b/src/database/permanentTokens.js @@ -8,7 +8,7 @@ const response = (entry) => ({ updated: entry.updated, }) -const add = async (data) => { +export const add = async (data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -20,7 +20,7 @@ await PermanentToken.create({ ) } -const all = async () => { +export const all = async () => { const enhance = (entries) => { return entries .map(response) @@ -32,7 +32,7 @@ await PermanentToken.find({}), ) } -const get = async (id) => { +export const get = async (id) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -42,7 +42,7 @@ await PermanentToken.findOne({ id }), ) } -const update = async (id, data) => { +export const update = async (id, data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -61,16 +61,8 @@ await PermanentToken.findOneAndUpdate({ ) } -const del = (id) => { +export const del = (id) => { return PermanentToken.findOneAndDelete({ id, }) -} - -export { - add, - all, - get, - update, - del, } \ No newline at end of file diff --git a/src/database/records.js b/src/database/records.js index cea16c7d5..da2a9ed89 100644 --- a/src/database/records.js +++ b/src/database/records.js @@ -21,7 +21,7 @@ const response = (entry) => ({ updated: entry.updated, }) -const add = async (data) => { +export const add = async (data) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -49,7 +49,7 @@ await Record.create({ ) } -const update = async (id) => { +export const update = async (id) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -67,7 +67,7 @@ await Record.findOneAndUpdate({ ) } -const anonymize = (clientId, ignoreId) => { +export const anonymize = (clientId, ignoreId) => { // Don't return anything about the update return Record.updateMany({ $and: [ @@ -95,15 +95,8 @@ const anonymize = (clientId, ignoreId) => { }) } -const del = (domainId) => { +export const del = (domainId) => { return Record.deleteMany({ domainId, }) -} - -export { - add, - update, - anonymize, - del, } \ No newline at end of file diff --git a/src/database/tokens.js b/src/database/tokens.js index 86475c165..87d46665d 100644 --- a/src/database/tokens.js +++ b/src/database/tokens.js @@ -6,7 +6,7 @@ const response = (entry) => ({ updated: entry.updated, }) -const add = async () => { +export const add = async () => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -16,7 +16,7 @@ await Token.create({}), ) } -const get = async (id) => { +export const get = async (id) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -26,7 +26,7 @@ await Token.findOne({ id }), ) } -const update = async (id) => { +export const update = async (id) => { const enhance = (entry) => { return entry == null ? entry : response(entry) } @@ -44,15 +44,8 @@ await Token.findOneAndUpdate({ ) } -const del = (id) => { +export const del = (id) => { return Token.findOneAndDelete({ id, }) -} - -export { - add, - get, - update, - del, } \ No newline at end of file diff --git a/src/ui/index.js b/src/ui/index.js index 58a6597b8..e858dc195 100644 --- a/src/ui/index.js +++ b/src/ui/index.js @@ -13,21 +13,21 @@ const __dirname = dirname(__filename) const customTracker = { exists, url, path } -const index = () => { +export const index = () => { return layout('
', 'favicon.ico', [ 'index.css' ], [ 'index.js' ], { isDemoMode: config.isDemoMode, customTracker, }) } -const styles = async () => { +export const styles = async () => { const { default: sass } = await import('rosid-handler-sass') const filePath = resolve(__dirname, './styles/index.scss') return sass(filePath, { optimize: config.isDevelopmentMode === false }) } -const scripts = async () => { +export const scripts = async () => { const { default: js } = await import('rosid-handler-js-next') const filePath = resolve(__dirname, './scripts/index.js') @@ -39,14 +39,14 @@ const scripts = async () => { }) } -const tracker = () => { +export const tracker = () => { const require = createRequire(import.meta.url) const filePath = require.resolve('ackee-tracker') return readFile(filePath, 'utf8') } -const build = async (path, fn) => { +export const build = async (path, fn) => { try { signale.await(`Building and writing '${ path }'`) const data = await fn() @@ -56,12 +56,4 @@ const build = async (path, fn) => { signale.fatal(error) process.exit(1) } -} - -export { - index, - styles, - scripts, - tracker, - build, } \ No newline at end of file diff --git a/src/utils/createContext.js b/src/utils/createContext.js index f4d35f7a2..d5872341f 100644 --- a/src/utils/createContext.js +++ b/src/utils/createContext.js @@ -5,11 +5,11 @@ import isAuthenticated from './isAuthenticated.js' import createDate from './createDate.js' import { isSet } from './ignoreCookie.js' -const createServerlessContext = (integrationContext) => { +export const createServerlessContext = (integrationContext) => { return createContext(integrationContext.event.headers['client-ip'], integrationContext.event.headers) } -const createMicroContext = (integrationContext) => { +export const createMicroContext = (integrationContext) => { return createContext(getClientIp(integrationContext.req), integrationContext.req.headers) } @@ -26,9 +26,4 @@ const createContext = async (ip, headers) => { setCookies: [], setHeaders: [], } -} - -export { - createServerlessContext, - createMicroContext, } \ No newline at end of file diff --git a/src/utils/times.js b/src/utils/times.js index cd54bb86e..70bdb17dd 100644 --- a/src/utils/times.js +++ b/src/utils/times.js @@ -1,11 +1,4 @@ -const second = 1000 -const minute = second * 60 -const hour = minute * 60 -const day = hour * 24 - -export { - second, - minute, - hour, - day, -} \ No newline at end of file +export const second = 1000 +export const minute = second * 60 +export const hour = minute * 60 +export const day = hour * 24 \ No newline at end of file diff --git a/test/resolvers/_utils.js b/test/resolvers/_utils.js index 553d167a4..4bf093928 100644 --- a/test/resolvers/_utils.js +++ b/test/resolvers/_utils.js @@ -13,12 +13,12 @@ import { day, minute } from '../../src/utils/times.js' const mongoDb = MongoMemoryServer.create() -const connectToDatabase = async () => { +export const connectToDatabase = async () => { const dbUrl = (await mongoDb).getUri() return connect(dbUrl) } -const fillDatabase = async (t) => { +export const fillDatabase = async (t) => { // Saves to context so tests can access ids t.context.token = await Token.create({}) t.context.permanentToken = await PermanentToken.create({ title: 'Example' }) @@ -62,7 +62,7 @@ const fillDatabase = async (t) => { await Action.insertMany(actions) } -const cleanupDatabase = async (t) => { +export const cleanupDatabase = async (t) => { await Token.findOneAndDelete({ id: t.context.token.id, }) @@ -71,12 +71,12 @@ const cleanupDatabase = async (t) => { }) } -const disconnectFromDatabase = async () => { +export const disconnectFromDatabase = async () => { mongoose.disconnect() ;(await mongoDb).stop() } -const api = async (base, body, token, headers = {}) => { +export const api = async (base, body, token, headers = {}) => { const url = new URL('/api', await base) const defaultHeaders = {} @@ -96,12 +96,4 @@ const api = async (base, body, token, headers = {}) => { headers: result.headers, json: await result.json(), } -} - -export { - connectToDatabase, - fillDatabase, - cleanupDatabase, - disconnectFromDatabase, - api, } \ No newline at end of file diff --git a/test/resolvers/domainStatistics/_utils.js b/test/resolvers/domainStatistics/_utils.js index 363aecf33..f1776e72a 100644 --- a/test/resolvers/domainStatistics/_utils.js +++ b/test/resolvers/domainStatistics/_utils.js @@ -1,6 +1,6 @@ import { api } from '../_utils.js' -const getStats = async ({ base, token, domainId, fragment }) => { +export const getStats = async ({ base, token, domainId, fragment }) => { const body = { query: ` query fetchStatistics($id: ID!) { @@ -24,6 +24,4 @@ const getStats = async ({ base, token, domainId, fragment }) => { } return json.data.domain.statistics -} - -export { getStats } \ No newline at end of file +} \ No newline at end of file diff --git a/test/resolvers/eventStatistics/_utils.js b/test/resolvers/eventStatistics/_utils.js index b29e6318d..0b5c27160 100644 --- a/test/resolvers/eventStatistics/_utils.js +++ b/test/resolvers/eventStatistics/_utils.js @@ -1,6 +1,6 @@ import { api } from '../_utils.js' -const getStats = async ({ base, token, eventId, fragment }) => { +export const getStats = async ({ base, token, eventId, fragment }) => { const body = { query: ` query fetchStatistics($id: ID!) { @@ -24,6 +24,4 @@ const getStats = async ({ base, token, eventId, fragment }) => { } return json.data.event.statistics -} - -export { getStats } \ No newline at end of file +} \ No newline at end of file From 1a6f9aa7fa58e2911bce9f953db709b76a35ea71 Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 21 Feb 2026 09:55:55 +0100 Subject: [PATCH 5/6] Use node-fetch to make requests with different Host headers as the built-in fetch does not support modifying the Host header --- test/serverWithAutoCors.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/serverWithAutoCors.js b/test/serverWithAutoCors.js index 69d7f0b60..08e5981da 100644 --- a/test/serverWithAutoCors.js +++ b/test/serverWithAutoCors.js @@ -1,6 +1,7 @@ import test from 'ava' import listen from 'test-listen' import mockedEnv from 'mocked-env' +import fetch from 'node-fetch' import server from '../src/server.js' import Domain from '../src/models/Domain.js' @@ -26,6 +27,7 @@ test('return cors headers based on fully qualifed domain names', async (t) => { ACKEE_AUTO_ORIGIN: 'true', }) + // Use node-fetch to make requests with different Host headers as the built-in fetch does not support modifying the Host header const { headers: fqdnHeaders } = await fetch(url.href, { headers: { Host: 'fqdn.example.com' } }) t.is(fqdnHeaders.get('Access-Control-Allow-Origin'), 'fqdn.example.com') @@ -33,6 +35,7 @@ test('return cors headers based on fully qualifed domain names', async (t) => { t.is(fqdnHeaders.get('Access-Control-Allow-Headers'), 'Content-Type, Authorization, Time-Zone') t.is(fqdnHeaders.get('Access-Control-Allow-Credentials'), 'true') + // Use node-fetch to make requests with different Host headers as the built-in fetch does not support modifying the Host header const { headers: noFqdnHeaders } = await fetch(url.href, { headers: { Host: 'No fqdn' } }) t.is(noFqdnHeaders.get('Access-Control-Allow-Origin'), null) From 2b1baf3d2d8d28b7b3b1cb6ed06d902027c710c7 Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 21 Feb 2026 11:52:22 +0100 Subject: [PATCH 6/6] Install dependencies --- package-lock.json | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f3617547..a6eca52c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,6 @@ "integrity": "sha512-0YQKKRIxiMlIou+SekQqdCo0ZTHxOcES+K8vKB53cIDpwABNR0P0yRzPgsbgcj3zRJniD93S/ontsnZsCLZrxQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", @@ -307,7 +306,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2803,7 +2801,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3515,7 +3512,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4411,7 +4407,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -5323,7 +5318,6 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -5880,7 +5874,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -6467,7 +6460,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -7162,7 +7154,6 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==", "license": "MIT", - "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -8559,7 +8550,6 @@ "resolved": "https://registry.npmjs.org/micro/-/micro-9.4.1.tgz", "integrity": "sha512-Lpjcbp6Y9GJIfewxDfTmu9eW0rt0MGo+Gs1d3yJLFa7mhErtKkCngGhDbA/O1gqUjEwsHh+jWPg8BJ0Bx4AgFA==", "license": "MIT", - "peer": true, "dependencies": { "arg": "4.1.0", "content-type": "1.0.4", @@ -9886,7 +9876,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -10512,7 +10501,6 @@ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -10538,7 +10526,6 @@ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -10976,7 +10963,6 @@ "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -12656,8 +12642,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0",