From f99fda131256443d9ab9e003980873e800b6cd78 Mon Sep 17 00:00:00 2001 From: Max Patiiuk Date: Sun, 14 Apr 2024 10:58:47 -0700 Subject: [PATCH] feat(backend): host privacy policy on the back-end Since I am forced by Google's OAuth2 to have a back-end, I might as well host the README.md policy there. Otherwise, I would have to separately maintain GitHub pages, and separate domains (because it would be tricky to host GitHub pages and auth backend endpoint on the same domain). --- README.md | 2 +- {auth-backend => backend}/.gitignore | 0 {auth-backend => backend}/README.md | 9 ++- .../app/api/auth/route.ts | 0 backend/app/docs/privacy/page.tsx | 7 +++ backend/app/error.tsx | 14 +++++ backend/app/icon.png | Bin 0 -> 13922 bytes backend/app/layout.tsx | 42 +++++++++++++ backend/app/not-found.tsx | 12 ++++ backend/app/page.tsx | 7 +++ backend/const/localization.ts | 10 ++++ backend/const/siteConfig.ts | 10 ++++ {auth-backend => backend}/example.config.js | 2 +- {auth-backend => backend}/next-env.d.ts | 0 {auth-backend => backend}/package-lock.json | 28 ++++++++- {auth-backend => backend}/package.json | 4 +- {auth-backend => backend}/tsconfig.json | 6 +- backend/utils/markdownToHtml.tsx | 46 ++++++++++++++ index.html | 56 ------------------ src/webpack.config.js | 2 +- 20 files changed, 185 insertions(+), 72 deletions(-) rename {auth-backend => backend}/.gitignore (100%) rename {auth-backend => backend}/README.md (85%) rename {auth-backend => backend}/app/api/auth/route.ts (100%) create mode 100644 backend/app/docs/privacy/page.tsx create mode 100644 backend/app/error.tsx create mode 100644 backend/app/icon.png create mode 100644 backend/app/layout.tsx create mode 100644 backend/app/not-found.tsx create mode 100644 backend/app/page.tsx create mode 100644 backend/const/localization.ts create mode 100644 backend/const/siteConfig.ts rename {auth-backend => backend}/example.config.js (91%) rename {auth-backend => backend}/next-env.d.ts (100%) rename {auth-backend => backend}/package-lock.json (97%) rename {auth-backend => backend}/package.json (89%) rename {auth-backend => backend}/tsconfig.json (70%) create mode 100644 backend/utils/markdownToHtml.tsx delete mode 100644 index.html diff --git a/README.md b/README.md index ccbf204..3b0ea75 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,6 @@ Editing the layout Npm 8 ``` -2. Complete installation steps in [./auth-backend](./auth-backend/) +2. Complete installation steps in [./backend](./backend/) 3. Complete installation steps in [./src](./src/) diff --git a/auth-backend/.gitignore b/backend/.gitignore similarity index 100% rename from auth-backend/.gitignore rename to backend/.gitignore diff --git a/auth-backend/README.md b/backend/README.md similarity index 85% rename from auth-backend/README.md rename to backend/README.md index 00107be..bd409c9 100644 --- a/auth-backend/README.md +++ b/backend/README.md @@ -13,7 +13,7 @@ This backend is used to generate a more-persistent token. ```sh git clone https://github.com/maxpatiiuk/calendar-plus cd calendar-plus - cd auth-backend + cd backend ``` 2. Create @@ -26,8 +26,8 @@ This backend is used to generate a more-persistent token. - For development set: - Authorized redirect URIs: `https://calendar-plus.patii.uk/api/route` - For production set: - - Authorized JavaScript origins: set to domain on which `auth-backend` will - be hosted (`https://calendar-plus.patii.uk`) + - Authorized JavaScript origins: set to domain on which `backend` will be + hosted (`https://calendar-plus.patii.uk`) 3. Copy [./example.config.js](./example.config.js) into `./config.js` and fill it in according to instructions in that file and the credentials you received @@ -47,5 +47,4 @@ This backend is used to generate a more-persistent token. ### Production 1. Create new vercel.com project from this repository -2. Change the "Root Directory" setting to current directory - (/packages/auth-backend) +2. Change the "Root Directory" setting to current directory (/packages/backend) diff --git a/auth-backend/app/api/auth/route.ts b/backend/app/api/auth/route.ts similarity index 100% rename from auth-backend/app/api/auth/route.ts rename to backend/app/api/auth/route.ts diff --git a/backend/app/docs/privacy/page.tsx b/backend/app/docs/privacy/page.tsx new file mode 100644 index 0000000..9087096 --- /dev/null +++ b/backend/app/docs/privacy/page.tsx @@ -0,0 +1,7 @@ +'use server'; + +import { markdownToJsx } from '../../../utils/markdownToHtml'; + +export default async function MainPage(): Promise { + return markdownToJsx('../docs/privacy/README.md'); +} diff --git a/backend/app/error.tsx b/backend/app/error.tsx new file mode 100644 index 0000000..8d9bbcc --- /dev/null +++ b/backend/app/error.tsx @@ -0,0 +1,14 @@ +'use client'; + +import React from 'react'; + +import { Metadata } from 'next'; +import { localization } from '../const/localization'; + +export default function Error({ error }: { error: Error }): JSX.Element { + return

{String(error)}

; +} + +export const metadata: Metadata = { + title: localization.unexpectedErrorHasOccurred, +}; diff --git a/backend/app/icon.png b/backend/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..95b83569a9ce49df67ae8c1fe4543035aaf52d2e GIT binary patch literal 13922 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 + + {children} + + + ); +} + +export const metadata: Metadata = { + title: { + default: localization.siteTitle, + template: `%s | ${localization.siteTitle}`, + }, + description: localization.siteDescription, + applicationName: localization.siteTitle, + keywords: localization.siteKeywords, + creator: localization.siteAuthor, + generator: 'Next.js', + robots, + twitter: { + card: 'summary_large_image', + site: twitter, + creator: twitter, + }, + metadataBase: new URL(baseUrl), +}; + +export const viewport: Viewport = { + colorScheme: 'light', +}; diff --git a/backend/app/not-found.tsx b/backend/app/not-found.tsx new file mode 100644 index 0000000..61c7fe6 --- /dev/null +++ b/backend/app/not-found.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { localization } from '../const/localization'; +import { Metadata } from 'next'; + +export default function NotFound(): JSX.Element { + return

{localization.notFound}

; +} + +export const metadata: Metadata = { + title: localization.notFound, +}; diff --git a/backend/app/page.tsx b/backend/app/page.tsx new file mode 100644 index 0000000..588cf39 --- /dev/null +++ b/backend/app/page.tsx @@ -0,0 +1,7 @@ +'use server'; + +import { markdownToJsx } from '../utils/markdownToHtml'; + +export default async function MainPage(): Promise { + return markdownToJsx('../README.md'); +} diff --git a/backend/const/localization.ts b/backend/const/localization.ts new file mode 100644 index 0000000..efdccfe --- /dev/null +++ b/backend/const/localization.ts @@ -0,0 +1,10 @@ +export const localization = { + siteTitle: 'Calendar Plus', + siteDescription: + 'Google Calendar extension that provides insights into where your time goes. Includes power user tools, data export and customization', + siteKeywords: + 'Calendar Plus, Google Calendar, Google Chrome, productivity, time management, time tracking, data export, insights, analytics, power user, customization', + siteAuthor: 'Max Patiiuk', + notFound: 'Page not found', + unexpectedErrorHasOccurred: 'An unexpected error has occurred', +}; diff --git a/backend/const/siteConfig.ts b/backend/const/siteConfig.ts new file mode 100644 index 0000000..07dbb73 --- /dev/null +++ b/backend/const/siteConfig.ts @@ -0,0 +1,10 @@ +export const robots = { index: true, follow: true } as const; +export const privatePage = { index: false, follow: false } as const; +export const twitter = '@maxpatiiuk'; +export const githubRepository = 'maxpatiiuk/calendar-plus'; + +export const baseUrl = + typeof process.env.VERCEL_URL === 'string' && + process.env.VERCEL_URL.length > 0 + ? `https://${process.env.VERCEL_URL}` + : 'http://localhost:3000'; diff --git a/auth-backend/example.config.js b/backend/example.config.js similarity index 91% rename from auth-backend/example.config.js rename to backend/example.config.js index 95dd026..ab2424f 100644 --- a/auth-backend/example.config.js +++ b/backend/example.config.js @@ -11,6 +11,6 @@ export const googleClientRedirectUrl='https://kgbbebdcmdgkbopcffmpgkgcmcoomhmh.c // origins by setting ACCESS_CONTROL_ALLOW_ORIGIN=* export const accessControlAllowOrigin='chrome-extension://kgbbebdcmdgkbopcffmpgkgcmcoomhmh'; -// The URL at which the /api/auth endpoint from the auth-backend is hosted +// The URL at which the /api/auth endpoint from the backend is hosted export const productionAuthUrl = 'https://calendar-plus.patii.uk/api/auth'; export const developmentAuthUrl = 'http://localhost:3000/api/auth'; \ No newline at end of file diff --git a/auth-backend/next-env.d.ts b/backend/next-env.d.ts similarity index 100% rename from auth-backend/next-env.d.ts rename to backend/next-env.d.ts diff --git a/auth-backend/package-lock.json b/backend/package-lock.json similarity index 97% rename from auth-backend/package-lock.json rename to backend/package-lock.json index 9c05455..cc9bd8c 100644 --- a/auth-backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,14 @@ { - "name": "calendar-stats-auth-backend", + "name": "calendar-stats-backend", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "calendar-stats-auth-backend", + "name": "calendar-stats-backend", "license": "MIT", "dependencies": { + "github-markdown-css": "^5.5.1", + "marked": "^12.0.1", "next": "^14.2.1" }, "devDependencies": { @@ -638,6 +640,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/github-markdown-css": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.5.1.tgz", + "integrity": "sha512-2osyhNgFt7DEHnGHbgIifWawAqlc68gjJiGwO1xNw/S48jivj8kVaocsVkyJqUi3fm7fdYIDi4C6yOtcqR/aEQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -768,6 +781,17 @@ "loose-envify": "cli.js" } }, + "node_modules/marked": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.1.tgz", + "integrity": "sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "dev": true, diff --git a/auth-backend/package.json b/backend/package.json similarity index 89% rename from auth-backend/package.json rename to backend/package.json index 5c7a319..5ef65d0 100644 --- a/auth-backend/package.json +++ b/backend/package.json @@ -1,5 +1,5 @@ { - "name": "calendar-stats-auth-backend", + "name": "calendar-stats-backend", "private": true, "license": "MIT", "type": "module", @@ -21,6 +21,8 @@ "type-check": "tsc" }, "dependencies": { + "github-markdown-css": "^5.5.1", + "marked": "^12.0.1", "next": "^14.2.1" }, "devDependencies": { diff --git a/auth-backend/tsconfig.json b/backend/tsconfig.json similarity index 70% rename from auth-backend/tsconfig.json rename to backend/tsconfig.json index 98417d8..7e3bcce 100644 --- a/auth-backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,9 +1,5 @@ { - "include": [ - "**/*.ts", - ".next/types/**/*.ts", - "next-env.d.ts" - ], + "include": ["**/*.ts", ".next/types/**/*.ts", "next-env.d.ts"], "extends": "../tsconfig.json", "compilerOptions": { "incremental": true, diff --git a/backend/utils/markdownToHtml.tsx b/backend/utils/markdownToHtml.tsx new file mode 100644 index 0000000..7177559 --- /dev/null +++ b/backend/utils/markdownToHtml.tsx @@ -0,0 +1,46 @@ +import { githubRepository } from '../const/siteConfig'; +import { marked } from 'marked'; +import fs from 'node:fs/promises'; + +import 'github-markdown-css'; + +// Make relative URLs be relative to the GitHub repository +marked.use({ + renderer: { + image(href, title, text) { + const url = new URL( + href, + `https://github.com/${githubRepository}/raw/main/`, + ); + return `${text}`; + }, + link(href, title, text) { + const url = new URL( + href, + `https://github.com/${githubRepository}/tree/main/`, + ); + return `${text}`; + }, + }, +}); + +export async function markdownToHtml(path: string): Promise { + const content = await fs.readFile(path, 'utf8'); + return marked(content, { gfm: true, breaks: false }); +} + +export async function markdownToJsx(path: string): Promise { + const content = await markdownToHtml(path); + return ( +
+
+
+ ); +} diff --git a/index.html b/index.html deleted file mode 100644 index bb23c80..0000000 --- a/index.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - Calendar Plus - - - - - - - - - -
- - - diff --git a/src/webpack.config.js b/src/webpack.config.js index b395dc5..7b0a21b 100644 --- a/src/webpack.config.js +++ b/src/webpack.config.js @@ -8,7 +8,7 @@ import { developmentAuthUrl, productionAuthUrl, googleClientId, -} from '../auth-backend/config.js'; +} from '../backend/config.js'; import { fileURLToPath } from 'url'; const outputPath = path.resolve(