diff --git a/Dockerfile b/Dockerfile index bdc678da..e0c7e8c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,8 @@ RUN yarn install --frozen-lockfile FROM node:18-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules -COPY docker/middleware.js . COPY . . +COPY docker/middleware.js ./src ARG DATABASE_TYPE ARG BASE_PATH diff --git a/src/components/common/UpdateNotice.js b/src/components/common/UpdateNotice.js index e3edc70c..23907948 100644 --- a/src/components/common/UpdateNotice.js +++ b/src/components/common/UpdateNotice.js @@ -1,4 +1,5 @@ import { useEffect, useCallback, useState } from 'react'; +import { createPortal } from 'react-dom'; import { Button, Row, Column } from 'react-basics'; import { setItem } from 'next-basics'; import useStore, { checkVersion } from 'store/version'; @@ -44,7 +45,7 @@ export function UpdateNotice({ user, config }) { return null; } - return ( + return createPortal( {formatMessage(messages.newVersionAvailable, { version: `v${latest}` })} @@ -55,7 +56,8 @@ export function UpdateNotice({ user, config }) { - + , + document.body, ); } diff --git a/src/components/common/UpdateNotice.module.css b/src/components/common/UpdateNotice.module.css index db7a0abd..261a3169 100644 --- a/src/components/common/UpdateNotice.module.css +++ b/src/components/common/UpdateNotice.module.css @@ -2,13 +2,14 @@ position: absolute; max-width: 800px; gap: 20px; - margin: 20px auto; - justify-self: center; + margin: 80px auto; + align-self: center; background: var(--base50); padding: 20px; border: 1px solid var(--base300); border-radius: var(--border-radius); z-index: var(--z-index-popup); + box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1); } .message { diff --git a/src/pages/api/send.ts b/src/pages/api/send.ts index e220711c..00d72104 100644 --- a/src/pages/api/send.ts +++ b/src/pages/api/send.ts @@ -7,7 +7,7 @@ import { getIpAddress } from 'lib/detect'; import { useCors, useSession, useValidate } from 'lib/middleware'; import { CollectionType, YupRequest } from 'lib/types'; import { NextApiRequest, NextApiResponse } from 'next'; -import { badRequest, createToken, forbidden, ok, send } from 'next-basics'; +import { badRequest, createToken, forbidden, methodNotAllowed, ok, send } from 'next-basics'; import { saveEvent, saveSessionData } from 'queries'; import * as yup from 'yup'; @@ -73,75 +73,75 @@ const schema = { export default async (req: NextApiRequestCollect, res: NextApiResponse) => { await useCors(req, res); - if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) { - return ok(res); - } - - const { type, payload } = req.body; - - if (!type || !payload) { - return badRequest(res); - } - - req.yup = schema; - await useValidate(req, res); - - if (await hasBlockedIp(req)) { - return forbidden(res); - } - - const { url, referrer, name: eventName, data: eventData, title: pageTitle } = payload; - - await useSession(req, res); - - const session = req.session; - - if (type === COLLECTION_TYPE.event) { - // eslint-disable-next-line prefer-const - let [urlPath, urlQuery] = url?.split('?') || []; - let [referrerPath, referrerQuery] = referrer?.split('?') || []; - let referrerDomain; - - if (!urlPath) { - urlPath = '/'; + if (req.method === 'POST') { + if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) { + return ok(res); } - if (referrerPath?.startsWith('http')) { - const refUrl = new URL(referrer); - referrerPath = refUrl.pathname; - referrerQuery = refUrl.search.substring(1); - referrerDomain = refUrl.hostname.replace(/www\./, ''); + const { type, payload } = req.body; + + req.yup = schema; + await useValidate(req, res); + + if (await hasBlockedIp(req)) { + return forbidden(res); } - if (process.env.REMOVE_TRAILING_SLASH) { - urlPath = urlPath.replace(/.+\/$/, ''); + const { url, referrer, name: eventName, data: eventData, title: pageTitle } = payload; + + await useSession(req, res); + + const session = req.session; + + if (type === COLLECTION_TYPE.event) { + // eslint-disable-next-line prefer-const + let [urlPath, urlQuery] = url?.split('?') || []; + let [referrerPath, referrerQuery] = referrer?.split('?') || []; + let referrerDomain; + + if (!urlPath) { + urlPath = '/'; + } + + if (referrerPath?.startsWith('http')) { + const refUrl = new URL(referrer); + referrerPath = refUrl.pathname; + referrerQuery = refUrl.search.substring(1); + referrerDomain = refUrl.hostname.replace(/www\./, ''); + } + + if (process.env.REMOVE_TRAILING_SLASH) { + urlPath = urlPath.replace(/.+\/$/, ''); + } + + await saveEvent({ + urlPath, + urlQuery, + referrerPath, + referrerQuery, + referrerDomain, + pageTitle, + eventName, + eventData, + ...session, + sessionId: session.id, + }); } - await saveEvent({ - urlPath, - urlQuery, - referrerPath, - referrerQuery, - referrerDomain, - pageTitle, - eventName, - eventData, - ...session, - sessionId: session.id, - }); + if (type === COLLECTION_TYPE.identify) { + if (!eventData) { + return badRequest(res, 'Data required.'); + } + + await saveSessionData({ ...session, sessionData: eventData, sessionId: session.id }); + } + + const token = createToken(session, secret()); + + return send(res, token); } - if (type === COLLECTION_TYPE.identify) { - if (!eventData) { - return badRequest(res, 'Data required.'); - } - - await saveSessionData({ ...session, sessionData: eventData, sessionId: session.id }); - } - - const token = createToken(session, secret()); - - return send(res, token); + return methodNotAllowed(res); }; async function hasBlockedIp(req: NextApiRequestCollect) {