diff --git a/Makefile b/Makefile index 3eebbf716..37659eb1c 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ deploy: install yarn ts-node server/migrate.ts ln -sfn ../data/img ./static/img-local ln -sfn ../data/docs ./static/docs-local + yarn ts-node server/sentry.ts switch: rm -rf cache diff --git a/nuxt.config.ts b/nuxt.config.ts index 3f74166ec..21dc2b4f3 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -226,6 +226,7 @@ const nuxtConfig: NuxtConfig = { telemetry: false, }, config: { + environment: process.env.NODE_ENV === 'production' ? config.locale : process.env.NODE_ENV!, attachStacktrace: true, initialScope(scope) { scope.setTag('locale', process.env.LOCALE); diff --git a/server/routes/banner.js b/server/routes/banner.js index 9d70ca870..533aa42e5 100644 --- a/server/routes/banner.js +++ b/server/routes/banner.js @@ -40,7 +40,7 @@ router.get('/banner/:pronounName*.png', handleErrorAsync(async (req, res) => { const imageSize = 200; let leftRatio = 4; - const pronounName = req.params.pronounName + req.params[0]; + const pronounName = (req.params.pronounName + req.params[0]).replace(/(&)+$/, ''); const result = await new CacheObject('banner', `${pronounName}.png`, 24 * 60).fetch(async () => { const fontName = registerLocaleFont('fontHeadings', ['regular', 'bold']); diff --git a/server/routes/calendar.js b/server/routes/calendar.js index 704304e1a..39b497d3f 100644 --- a/server/routes/calendar.js +++ b/server/routes/calendar.js @@ -105,6 +105,10 @@ const eventsSummary = (day, locale) => { }; }; +const generateURIEncodedPathAlternative = (path) => { + return [path, path.replace('@', encodeURIComponent('@'))]; +}; + const router = Router(); router.get('/calendar/today', handleErrorAsync(async (req, res) => { @@ -132,7 +136,7 @@ router.get(`${routeBase}.ics`, handleErrorAsync(async (req, res) => { renderEvents(events, res, req.query.only_first_days !== undefined); })); -router.get(`${routeBase}-@:username.ics`, handleErrorAsync(async (req, res) => { +router.get(generateURIEncodedPathAlternative(`${routeBase}-@:username.ics`), handleErrorAsync(async (req, res) => { const profiles = await req.db.all(SQL` SELECT events, customEvents FROM profiles p LEFT JOIN users u ON p.userId = u.id diff --git a/server/sentry.ts b/server/sentry.ts new file mode 100644 index 000000000..f2d50b90d --- /dev/null +++ b/server/sentry.ts @@ -0,0 +1,34 @@ +import fs from 'fs'; + +import SentryCli from '@sentry/cli'; + +import './setup.ts'; +import { loadSuml } from './loader.ts'; +import allLocales from '../locale/locales.ts'; +import type { Config } from '../locale/config.ts'; + +const __dirname = new URL('.', import.meta.url).pathname; + +async function notifyDeployment(): Promise { + if (!process.env.SENTRY_DSN) { + process.stdout.write('SENTRY_DSN is not defined, skipping deployment information to Sentry'); + return; + } + + const version = fs.readFileSync(`${__dirname}/../cache/version`, 'utf-8'); + const config = loadSuml('config') as Config; + + const sentryCli = new SentryCli(); + await sentryCli.releases.setCommits(version, { + auto: true, + }); + await sentryCli.releases.finalize(version); + const environment = process.env.NODE_ENV === 'production' ? config.locale : process.env.NODE_ENV!; + await sentryCli.releases.newDeploy(version, { + env: environment, + url: allLocales.find((locale) => locale.code === config.locale)?.url, + }); + process.stdout.write(`Sent deployment information for environment ${environment} to Sentry`); +} + +await notifyDeployment(); diff --git a/src/calendar/helpers.js b/src/calendar/helpers.js index 0ac78ffbf..ffddf4f1f 100644 --- a/src/calendar/helpers.js +++ b/src/calendar/helpers.js @@ -331,7 +331,7 @@ export class Calendar { getYear(year) { year = parseInt(year); - if (year < this._minYear || year > this._maxYear) { + if (year < this._minYear || year > this._maxYear || Number.isNaN(year)) { return null; }