import rp from 'request-promise'; import Q from 'q'; import mongoose from 'mongoose'; import objectID from 'bson-objectid'; import shortid from 'shortid'; import eachSeries from 'async/eachSeries'; import User from '../models/user'; import Project from '../models/project'; const defaultHTML = `<!DOCTYPE html> <html lang="en"> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script> <link rel="stylesheet" type="text/css" href="style.css"> <meta charset="utf-8" /> </head> <body> <script src="sketch.js"></script> </body> </html> `; const defaultCSS = `html, body { margin: 0; padding: 0; } canvas { display: block; } `; const clientId = process.env.GITHUB_ID; const clientSecret = process.env.GITHUB_SECRET; const headers = { 'User-Agent': 'p5js-web-editor/0.0.1' }; const mongoConnectionString = process.env.MONGO_URL; mongoose.connect(mongoConnectionString, { useNewUrlParser: true, useUnifiedTopology: true }); mongoose.set('useCreateIndex', true); mongoose.connection.on('error', () => { console.error('MongoDB Connection Error. Please make sure that MongoDB is running.'); process.exit(1); }); function getCategories() { const categories = []; const options = { url: `https://api.github.com/repos/processing/p5.js-website/contents/src/data/examples/en?client_id=${ clientId}&client_secret=${clientSecret}`, method: 'GET', headers, json: true }; return rp(options).then((res) => { res.forEach((metadata) => { let category = ''; for (let j = 1; j < metadata.name.split('_').length; j += 1) { category += `${metadata.name.split('_')[j]} `; } categories.push({ url: metadata.url, name: category.trim() }); }); return categories; }).catch((err) => { throw err; }); } function getSketchesInCategories(categories) { return Q.all(categories.map((category) => { const options = { url: `${category.url.replace('?ref=master', '')}?client_id=${clientId}&client_secret=${clientSecret}`, method: 'GET', headers, json: true }; return rp(options).then((res) => { const projectsInOneCategory = []; res.forEach((example) => { let projectName; if (example.name === '02_Instance_Container.js') { for (let i = 1; i < 5; i += 1) { const instanceProjectName = `${category.name}: Instance Container ${i}`; projectsInOneCategory.push({ sketchUrl: example.download_url, projectName: instanceProjectName }); } } else { if (example.name.split('_')[1]) { projectName = `${category.name}: ${example.name.split('_').slice(1).join(' ').replace('.js', '')}`; } else { projectName = `${category.name}: ${example.name.replace('.js', '')}`; } projectsInOneCategory.push({ sketchUrl: example.download_url, projectName }); } }); return projectsInOneCategory; }).catch((err) => { throw err; }); })); } function getSketchContent(projectsInAllCategories) { return Q.all(projectsInAllCategories.map(projectsInOneCategory => Q.all(projectsInOneCategory.map((project) => { const options = { url: `${project.sketchUrl.replace('?ref=master', '')}?client_id=${clientId}&client_secret=${clientSecret}`, method: 'GET', headers }; return rp(options).then((res) => { const noNumberprojectName = project.projectName.replace(/(\d+)/g, ''); if (noNumberprojectName === 'Instance Mode: Instance Container ') { for (let i = 0; i < 4; i += 1) { const splitedRes = `${res.split('*/')[1].split('</html>')[i]}</html>\n`; project.sketchContent = splitedRes.replace( 'p5.js', 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js' ); } } else { project.sketchContent = res; } return project; }).catch((err) => { throw err; }); })))); } function createProjectsInP5user(projectsInAllCategories) { const options = { url: `https://api.github.com/repos/processing/p5.js-website/contents/src/data/examples/assets?client_id=${ clientId}&client_secret=${clientSecret}`, method: 'GET', headers, json: true }; rp(options).then((res) => { User.findOne({ username: 'p5' }, (err, user) => { if (err) throw err; eachSeries(projectsInAllCategories, (projectsInOneCategory, categoryCallback) => { eachSeries(projectsInOneCategory, (project, projectCallback) => { let newProject; const a = objectID().toHexString(); const b = objectID().toHexString(); const c = objectID().toHexString(); const r = objectID().toHexString(); const noNumberprojectName = project.projectName.replace(/(\d+)/g, ''); if (noNumberprojectName === 'Instance Mode: Instance Container ') { newProject = new Project({ name: project.projectName, user: user._id, files: [ { name: 'root', id: r, _id: r, children: [a, b, c], fileType: 'folder' }, { name: 'sketch.js', content: '// Instance Mode: Instance Container, please check its index.html file', id: a, _id: a, fileType: 'file', children: [] }, { name: 'index.html', content: project.sketchContent, isSelectedFile: true, id: b, _id: b, fileType: 'file', children: [] }, { name: 'style.css', content: defaultCSS, id: c, _id: c, fileType: 'file', children: [] } ], _id: shortid.generate() }); } else { newProject = new Project({ name: project.projectName, user: user._id, files: [ { name: 'root', id: r, _id: r, children: [a, b, c], fileType: 'folder' }, { name: 'sketch.js', content: project.sketchContent, id: a, _id: a, isSelectedFile: true, fileType: 'file', children: [] }, { name: 'index.html', content: defaultHTML, id: b, _id: b, fileType: 'file', children: [] }, { name: 'style.css', content: defaultCSS, id: c, _id: c, fileType: 'file', children: [] } ], _id: shortid.generate() }); } const assetsInProject = project.sketchContent.match(/assets\/[\w-]+\.[\w]*/g) || project.sketchContent.match(/asset\/[\w-]*/g) || []; assetsInProject.forEach((assetNamePath, i) => { let assetName = assetNamePath.split('assets/')[1]; res.forEach((asset) => { if (asset.name === assetName || asset.name.split('.')[0] === assetName) { assetName = asset.name; } }); if (assetName !== '') { if (i === 0) { const id = objectID().toHexString(); newProject.files.push({ name: 'assets', id, _id: id, children: [], fileType: 'folder' }); // add assets folder inside root newProject.files[0].children.push(id); } const fileID = objectID().toHexString(); newProject.files.push({ name: assetName, url: `https://cdn.jsdelivr.net/gh/processing/p5.js-website@master/src/data/examples/assets/${assetName}`, id: fileID, _id: fileID, children: [], fileType: 'file' }); console.log(`create assets: ${assetName}`); // add asset file inside the newly created assets folder at index 4 newProject.files[4].children.push(fileID); } }); newProject.save((saveErr, savedProject) => { if (saveErr) throw saveErr; console.log(`Created a new project in p5 user: ${savedProject.name}`); projectCallback(); }); }, (categoryErr) => { categoryCallback(); }); }, (examplesErr) => { process.exit(); }); }); }).catch((err) => { throw err; }); } function getp5User() { User.findOne({ username: 'p5' }, (err, user) => { if (err) throw err; let p5User = user; if (!p5User) { p5User = new User({ username: 'p5', email: process.env.EXAMPLE_USER_EMAIL, password: process.env.EXAMPLE_USER_PASSWORD }); p5User.save((saveErr) => { if (saveErr) throw saveErr; console.log(`Created a user p5 ${p5User}`); }); } Project.find({ user: p5User._id }, (projectsErr, projects) => { // if there are already some sketches, delete them console.log('Deleting old projects...'); projects.forEach((project) => { Project.remove({ _id: project._id }, (removeErr) => { if (removeErr) throw removeErr; }); }); }); return getCategories() .then(getSketchesInCategories) .then(getSketchContent) .then(createProjectsInP5user); }); } getp5User();