Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
"lib": ["DOM", "ESNext"],
"jsx": "react",
},
"include": ["./**/*"],
"exclude": ["../node_modules", "../server"]
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
"storybook:build:css": "sass client/styles/main.scss client/styles/storybook.css",
"storybook": "npm run storybook:build:css && storybook dev -p 6006",
"build-storybook": "storybook build",
"typecheck": "npm run typecheck:client",
"typecheck:client": "npx tsc --noEmit -p ./client/tsconfig.json"
"typecheck": "npm run typecheck:client && npm run typecheck:server",
"typecheck:client": "npx tsc --noEmit -p ./client/tsconfig.json",
"typecheck:server": "npx tsc --noEmit -p ./server/tsconfig.json"
},
"husky": {
"hooks": {
Expand Down
3 changes: 2 additions & 1 deletion server/controllers/project.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import slugify from 'slugify';
import Project from '../models/project';
import User from '../models/user';
import { resolvePathToFile } from '../utils/filePath';
import generateFileSystemSafeName from '../utils/generateFileSystemSafeName';
// eslint-disable-next-line import/extensions
import { generateFileSystemSafeName } from '../utils/generateFileSystemSafeName.ts';

export {
default as createProject,
Expand Down
2 changes: 1 addition & 1 deletion server/previewServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import webpackHotMiddleware from '@gatsbyjs/webpack-hot-middleware';
import config from '../webpack/config.dev';
import embedRoutes from './routes/embed.routes';
import assetRoutes from './routes/asset.routes';
import renderPreviewIndex from './views/previewIndex';
import { renderPreviewIndex } from './views/previewIndex';

const app = new Express();

Expand Down
2 changes: 1 addition & 1 deletion server/routes/server.routes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router } from 'express';
import sendHtml, { renderIndex, renderProjectIndex } from '../views/index';
import { renderIndex, renderProjectIndex, sendHtml } from '../views/index';
import { userExists } from '../controllers/user.controller';
import {
projectExists,
Expand Down
11 changes: 11 additions & 0 deletions server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"types": ["node"],
},
"include": ["./**/*"],
"exclude": ["../node_modules", "../client"]
}
41 changes: 41 additions & 0 deletions server/types/mail.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
interface BaseMailTemplate {
domain: string;
headingText: string;
greetingText: string;
messageText: string;
directLinkText: string;
noteText: string;
meta: { keywords: string; description: string };
}

/** Email template for account consolidation, when user has previously registered with another account */
export interface AccountConsolidationMailTemplate extends BaseMailTemplate {
username: string;
email: string;
message2Text: string;
resetPasswordLink: string;
resetPasswordText: string;
}
/** Email options for account consolidation, when user has previously registered with another account */
export interface AccountConsolidationMailOptions {
body: {
domain: string;
username: string;
email: string;
};
to: string;
}

/** Standard email template, used for email confirmation & password reset */
export interface MailTemplate extends BaseMailTemplate {
link: string;
buttonText: string;
}
/** Standard email options, used for email confirmation & password reset */
export interface MailOptions {
body: {
domain: string;
link: string;
};
to: string;
}
8 changes: 8 additions & 0 deletions server/types/project.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface ProjectFile {
name: string;
content: string;
url: string;
children: string[];
fileType: string;
isSelectedFile: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
* @param {String} string
* @param {String} replacer (optional) character to replace invalid characters
*/
function generateFileSystemSafeName(string, replacer) {
export function generateFileSystemSafeName(string: string, replacer: string) {
// from here https://serverfault.com/a/242134
const INVALID_CHARS_REGEX = /[*/?:\\<>|"\u0000-\u001F]/g; // eslint-disable-line
const slug = string.replace(INVALID_CHARS_REGEX, replacer || '');

return slug;
}

export default generateFileSystemSafeName;
31 changes: 18 additions & 13 deletions server/views/404Page.js → server/views/404Page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import User from '../models/user';
import Project from '../models/project';
import { ProjectFile } from '../types/project.type';

const insertErrorMessage = (htmlFile) => {
const insertErrorMessage = (htmlFile: string) => {
const html = htmlFile.split('</head>');
const metaDescription = 'A web editor for p5.js, a JavaScript library with the goal of making coding accessible to artists, designers, educators, and beginners.'; // eslint-disable-line
html[0] = `
Expand Down Expand Up @@ -84,7 +85,10 @@ export const get404Sketch = async () => {
return errorMessage;
}

const projects = await Project.find({ user: p5User._id }).exec();
const projects = await Project.find({
// eslint-disable-next-line no-underscore-dangle
user: p5User._id
}).exec();

if (!projects.length) {
return errorMessage;
Expand All @@ -94,33 +98,36 @@ export const get404Sketch = async () => {
const sketch = projects[randomIndex];

// Get sketch files
let htmlFile = sketch.files.find((file) => file.name.match(/.*\.html$/i))
.content;
const jsFiles = sketch.files.filter((file) => file.name.match(/.*\.js$/i));
const cssFiles = sketch.files.filter((file) =>
let htmlFile = sketch.files.find((file: ProjectFile) =>
file.name.match(/.*\.html$/i)
).content;
const jsFiles = sketch.files.filter((file: ProjectFile) =>
file.name.match(/.*\.js$/i)
);
const cssFiles = sketch.files.filter((file: ProjectFile) =>
file.name.match(/.*\.css$/i)
);
const linkedFiles = sketch.files.filter((file) => file.url);
const linkedFiles = sketch.files.filter((file: ProjectFile) => file.url);

const instanceMode = jsFiles
.find((file) => file.name === 'sketch.js')
.find((file: ProjectFile) => file.name === 'sketch.js')
.content.includes('Instance Mode');

jsFiles.forEach((file) => {
jsFiles.forEach((file: ProjectFile) => {
// Add js files as script tags
const html = htmlFile.split('</body>');
html[0] = `${html[0]}<script>${file.content}</script>`;
htmlFile = html.join('</body>');
});

cssFiles.forEach((file) => {
cssFiles.forEach((file: ProjectFile) => {
// Add css files as style tags
const html = htmlFile.split('</head>');
html[0] = `${html[0]}<style>${file.content}</style>`;
htmlFile = html.join('</head>');
});

linkedFiles.forEach((file) => {
linkedFiles.forEach((file: ProjectFile) => {
// Add linked files as link tags
const html = htmlFile.split('<head>');
html[1] = `<link href=${file.url}>${html[1]}`;
Expand Down Expand Up @@ -153,5 +160,3 @@ export const get404Sketch = async () => {
throw err;
}
};

export default get404Sketch;
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export default ({
import { AccountConsolidationMailTemplate } from '../types/mail.type';

export const consolidationMailLayout = ({
domain,
headingText,
greetingText,
Expand All @@ -11,7 +13,7 @@ export default ({
resetPasswordText,
noteText,
meta
}) =>
}: AccountConsolidationMailTemplate) =>
`
<mjml>
<mj-head>
Expand Down
112 changes: 86 additions & 26 deletions server/views/index.js → server/views/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import get404Sketch from './404Page';
/* eslint-disable no-unneeded-ternary */
import { Request, Response } from 'express';
import { get404Sketch } from './404Page';

export function renderIndex() {
const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
const assetsManifest =
process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
return `
<!DOCTYPE html>
<html lang="en">
Expand All @@ -11,7 +14,11 @@ export function renderIndex() {
<meta name="keywords" content="p5.js, p5.js web editor, web editor, processing, code editor" />
<meta name="description" content="A web editor for p5.js, a JavaScript library with the goal of making coding accessible to artists, designers, educators, and beginners." />
<title>p5.js Web Editor</title>
${process.env.NODE_ENV === 'production' ? `<link rel='stylesheet' href='${assetsManifest['/app.css']}' />` : ''}
${
process.env.NODE_ENV === 'production'
? `<link rel='stylesheet' href='${assetsManifest['/app.css']}' />`
: ''
}
<link href='https://fonts.googleapis.com/css?family=Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Montserrat:400,700' rel='stylesheet' type='text/css'>
<link rel='shortcut icon' href='/favicon.ico' type='image/x-icon' / >
Expand All @@ -25,31 +32,54 @@ export function renderIndex() {
window.process.env.API_URL = '${process.env.API_URL}';
window.process.env.NODE_ENV = '${process.env.NODE_ENV}';
window.process.env.S3_BUCKET = '${process.env.S3_BUCKET}';
window.process.env.S3_BUCKET_URL_BASE = ${process.env.S3_BUCKET_URL_BASE ? `'${process.env.S3_BUCKET_URL_BASE}'` : undefined};
window.process.env.S3_BUCKET_URL_BASE = ${
process.env.S3_BUCKET_URL_BASE
? `'${process.env.S3_BUCKET_URL_BASE}'`
: undefined
};
window.process.env.AWS_REGION = '${process.env.AWS_REGION}';
window.process.env.FORCE_TO_HTTPS = ${process.env.FORCE_TO_HTTPS === 'false' ? false : undefined};
window.process.env.FORCE_TO_HTTPS = ${
process.env.FORCE_TO_HTTPS === 'false' ? false : undefined
};
window.process.env.CLIENT = true;
window.process.env.LOGIN_ENABLED = ${process.env.LOGIN_ENABLED === 'false' ? false : true};
window.process.env.EXAMPLES_ENABLED = ${process.env.EXAMPLES_ENABLED === 'false' ? false : true};
window.process.env.UI_ACCESS_TOKEN_ENABLED = ${process.env.UI_ACCESS_TOKEN_ENABLED === 'false' ? false : true};
window.process.env.UI_COLLECTIONS_ENABLED = ${process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true};
window.process.env.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
window.process.env.TRANSLATIONS_ENABLED = ${process.env.TRANSLATIONS_ENABLED === 'true' ? true : false};
window.process.env.LOGIN_ENABLED = ${
process.env.LOGIN_ENABLED === 'false' ? false : true
};
window.process.env.EXAMPLES_ENABLED = ${
process.env.EXAMPLES_ENABLED === 'false' ? false : true
};
window.process.env.UI_ACCESS_TOKEN_ENABLED = ${
process.env.UI_ACCESS_TOKEN_ENABLED === 'false' ? false : true
};
window.process.env.UI_COLLECTIONS_ENABLED = ${
process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true
};
window.process.env.UPLOAD_LIMIT = ${
process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined
};
window.process.env.TRANSLATIONS_ENABLED = ${
process.env.TRANSLATIONS_ENABLED === 'true' ? true : false
};
window.process.env.PREVIEW_URL = '${process.env.PREVIEW_URL}';
window.process.env.GA_MEASUREMENT_ID='${process.env.GA_MEASUREMENT_ID}';
</script>
</head>
<body>
<div id="root" class="root-app">
</div>
<script src='${process.env.NODE_ENV === 'production' ? `${assetsManifest['/app.js']}` : '/app.js'}'></script>
<script src='${
process.env.NODE_ENV === 'production'
? `${assetsManifest['/app.js']}`
: '/app.js'
}'></script>
</body>
</html>
`;
}

export function renderProjectIndex(username, projectName) {
const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
export function renderProjectIndex(username: string, projectName: string) {
const assetsManifest =
process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
return `
<!DOCTYPE html>
<html lang="en">
Expand All @@ -59,7 +89,11 @@ export function renderProjectIndex(username, projectName) {
<meta name="keywords" content="p5.js, p5.js web editor, web editor, processing, code editor" />
<meta name="description" content="A web editor for p5.js, a JavaScript library with the goal of making coding accessible to artists, designers, educators, and beginners." />
<title>${`${projectName} by ${username} -`}p5.js Web Editor</title>
${process.env.NODE_ENV === 'production' ? `<link rel='stylesheet' href='${assetsManifest['/app.css']}' />` : ''}
${
process.env.NODE_ENV === 'production'
? `<link rel='stylesheet' href='${assetsManifest['/app.css']}' />`
: ''
}
<link href='https://fonts.googleapis.com/css?family=Inconsolata' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Montserrat:400,700' rel='stylesheet' type='text/css'>
<link rel='shortcut icon' href='/favicon.ico' type='image/x-icon' / >
Expand All @@ -73,24 +107,46 @@ export function renderProjectIndex(username, projectName) {
window.process.env.API_URL = '${process.env.API_URL}';
window.process.env.NODE_ENV = '${process.env.NODE_ENV}';
window.process.env.S3_BUCKET = '${process.env.S3_BUCKET}';
window.process.env.S3_BUCKET_URL_BASE = ${process.env.S3_BUCKET_URL_BASE ? `'${process.env.S3_BUCKET_URL_BASE}'` : undefined};
window.process.env.S3_BUCKET_URL_BASE = ${
process.env.S3_BUCKET_URL_BASE
? `'${process.env.S3_BUCKET_URL_BASE}'`
: undefined
};
window.process.env.AWS_REGION = '${process.env.AWS_REGION}';
window.process.env.FORCE_TO_HTTPS = ${process.env.FORCE_TO_HTTPS === 'false' ? false : undefined};
window.process.env.FORCE_TO_HTTPS = ${
process.env.FORCE_TO_HTTPS === 'false' ? false : undefined
};
window.process.env.CLIENT = true;
window.process.env.LOGIN_ENABLED = ${process.env.LOGIN_ENABLED === 'false' ? false : true};
window.process.env.EXAMPLES_ENABLED = ${process.env.EXAMPLES_ENABLED === 'false' ? false : true};
window.process.env.UI_ACCESS_TOKEN_ENABLED = ${process.env.UI_ACCESS_TOKEN_ENABLED === 'false' ? false : true};
window.process.env.UI_COLLECTIONS_ENABLED = ${process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true};
window.process.env.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
window.process.env.TRANSLATIONS_ENABLED = ${process.env.TRANSLATIONS_ENABLED === 'true' ? true : false};
window.process.env.LOGIN_ENABLED = ${
process.env.LOGIN_ENABLED === 'false' ? false : true
};
window.process.env.EXAMPLES_ENABLED = ${
process.env.EXAMPLES_ENABLED === 'false' ? false : true
};
window.process.env.UI_ACCESS_TOKEN_ENABLED = ${
process.env.UI_ACCESS_TOKEN_ENABLED === 'false' ? false : true
};
window.process.env.UI_COLLECTIONS_ENABLED = ${
process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true
};
window.process.env.UPLOAD_LIMIT = ${
process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined
};
window.process.env.TRANSLATIONS_ENABLED = ${
process.env.TRANSLATIONS_ENABLED === 'true' ? true : false
};
window.process.env.PREVIEW_URL = '${process.env.PREVIEW_URL}';
window.process.env.GA_MEASUREMENT_ID='${process.env.GA_MEASUREMENT_ID}';
</script>
</head>
<body>
<div id="root" class="root-app">
</div>
<script src='${process.env.NODE_ENV === 'production' ? `${assetsManifest['/app.js']}` : '/app.js'}'></script>
<script src='${
process.env.NODE_ENV === 'production'
? `${assetsManifest['/app.js']}`
: '/app.js'
}'></script>
</body>
</html>
`;
Expand All @@ -102,12 +158,16 @@ export function renderProjectIndex(username, projectName) {
* @param {import('express').e.Response} res
* @param {boolean} [exists]
*/
export default async function sendHtml(req, res, exists = true) {
export async function sendHtml(
req: Request,
res: Response,
exists: boolean = true
) {
if (!exists) {
res.status(404);
const html = await get404Sketch();
res.send(html);
} else {
res.send(renderIndex());
}
};
}
Loading
Loading