diff --git a/README.md b/README.md index c0cad415..a60cefe7 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,19 @@ -# Certificate Web UI - +# OpenCerts Legacy Templates (v1.5 & below) + [![Build Status](https://travis-ci.org/OpenCerts/opencerts-website.svg?branch=master)](https://travis-ci.org/OpenCerts/opencerts-website) See also: -* [opencerts-documentation](https://github.com/OpenCerts/opencerts-documentation) -* [open-certificate](https://github.com/OpenCerts/open-certificate) -* [certificate-contract](https://github.com/OpenCerts/certificate-store-contract) -* [certificate-cli](https://github.com/OpenCerts/certificate-cli) +- [opencerts-documentation](https://github.com/OpenCerts/opencerts-documentation) +- [open-certificate](https://github.com/OpenCerts/open-certificate) +- [certificate-contract](https://github.com/OpenCerts/certificate-store-contract) +- [certificate-cli](https://github.com/OpenCerts/certificate-cli) + +## Migrating to OpenCerts v2 +This repository is only for existing templates: no new templates will be accepted, only existing changes to current templates can be made via pull requests. + +To create a new template with OpenCerts v2, refer to the documentation at [https://docs.opencerts.io/](https://docs.opencerts.io/). ## Development @@ -22,8 +27,8 @@ There is a rudimentary interface for adding a new template for organisations tha npm run dev-cli ``` - ### OS X / Linux + ```bash npm install npm run dev @@ -43,6 +48,7 @@ npm run dev `NET` is used for setting the default network, setting it to `mainnet` uses the public Ethereum network. If it is not set it defaults to Ropsten testnet E.g: + ```bash NET=mainnet npm run dev ``` @@ -60,6 +66,7 @@ To enable debug logs in the browser, set `localStorage.debug="*"` ###### Module build failed If you see module build failure message like: + ``` Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildError: Module build failed (from ./node_modules/sass-loader/lib/loader.js): @@ -68,4 +75,3 @@ at Object.readdirSync (fs.js:783:3) ``` Try running `npm rebuild` - diff --git a/package.json b/package.json index 7ec8a729..9f6f148d 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "cname": "echo 'opencerts.io' > out/CNAME", "deploy": "rm -rf out && npm run build:static", "analyze": "BUNDLE_ANALYZE=browser npm run start", - "dev-cli": "node -r esm ./scripts/cli.js", "serve-static": "http-server out -s -p 3000", "integration": "testcafe chrome src/**/*.spec.js", "integration:headless": "testcafe chrome:headless src/**/*.spec.js", diff --git a/scripts/addNewTemplate.js b/scripts/addNewTemplate.js deleted file mode 100644 index 8d320908..00000000 --- a/scripts/addNewTemplate.js +++ /dev/null @@ -1,248 +0,0 @@ -/* eslint-disable no-console */ // because this is a cli module - -const inquirer = require("inquirer"); -const { reverse } = require("lodash"); -const fs = require("fs-extra"); -const path = require("path"); - -const TLDS_PATH = path.resolve("./src/components/CertificateTemplates/tlds/"); -const EXAMPLE_TEMPLATE_PATH = path.resolve( - TLDS_PATH, - "../example/2019-Feb-ExampleTemplate" -); - -export function reverseDnsNotation(domain) { - return path.join(...reverse(domain.split("."))); -} - -export function generatePartialChildPaths(dirPath) { - const childPaths = []; - const pathArray = path.join(dirPath).split(path.sep); - for (let i = pathArray.length; i > 0; i -= 1) { - const fragment = path.join(...pathArray.slice(0, i)); - childPaths.push(fragment); - } - return reverse(childPaths); -} - -export function getSubDirs(dirPath) { - const dirListing = fs.readdirSync(dirPath, { - withFileTypes: true - }); - return dirListing.filter(item => item.isDirectory()).map(dir => dir.name); -} - -function folderNotExists(dirPath) { - try { - getSubDirs(path.join(TLDS_PATH, dirPath)); - return undefined; - } catch (error) { - return dirPath; - } -} - -export function getDirsToMake(organisationDomain) { - const childPaths = generatePartialChildPaths( - reverseDnsNotation(organisationDomain) - ); - return childPaths.map(folderNotExists).filter(Boolean); // removes the undefineds -} - -export function organisationIndexTemplate({ - subDirectoryImports, - subDirectoryExports -}) { - return ` -import dynamic from "next/dynamic"; - -${subDirectoryImports.join("\n")} - -${subDirectoryExports} -`; -} - -function makeDynamicImportFragment(subDir, templatesChunkName) { - return `dynamic(() => import("./${subDir}" /* webpackChunkName: "${templatesChunkName}-Templates" */))`; -} -export function generateSubDirectoryDynamicImports( - subDirs, - templatesChunkName -) { - return subDirs.map(subDir => - makeDynamicImportFragment(subDir, templatesChunkName) - ); -} - -export function generateOrganisationIndexExports({ - templateTagMapping: templateNameMapping, - organisationDir -}) { - function generateExportString(templateName, subDir) { - return ` "${templateName}": ${makeDynamicImportFragment( - subDir, - organisationDir - )}`; - } - - function generateExportsObject(subDirs) { - return Object.keys(subDirs).map(templateName => - generateExportString(templateName, subDirs[templateName]) - ); - } - - return `import dynamic from "next/dynamic"; - -export default { -${generateExportsObject(templateNameMapping).join("\n")} -}; -`; -} -/** - * Replaces hyphens inside a valid domain string with an underscore because - * hyphens are not valid JS variable names so we cannot use them as - * autogenerated variables for imports - * @param {string} domainString - */ -function replaceHyphens(domainString) { - return domainString.replace("-", "_"); -} - -function makeSubdirectoryImport(subDir) { - return `import ${replaceHyphens(subDir)} from "./${subDir}";`; -} - -function makeSubdirectoryExports(subDirs) { - return subDirs.map(subDir => `...${replaceHyphens(subDir)}`).join(", "); -} - -export function validateDomainString(domainString) { - const domainRegexTest = /^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)$/; - if (domainRegexTest.test(domainString)) { - return domainString; - } - throw new Error( - `${domainString} was passed in as a subdomain but it is not a valid subdomain` - ); -} - -export function generateIntermediateIndexTemplate({ subDirs, currDir }) { - const subDirectoryImports = subDirs - .map(validateDomainString) - .map(makeSubdirectoryImport) - .join("\n"); - const subDirectoryExports = makeSubdirectoryExports(subDirs); - return `/* eslint-disable camelcase */ -/* because we need to use _ to replace hyphens in dns */ -import { addDirToTemplatePath } from "template-utils/addDirToTemplatePath"; - -${subDirectoryImports} - -export default addDirToTemplatePath("${currDir}", { ${subDirectoryExports} }); -`; -} - -export function generateTldsIndex() { - const subDirs = getSubDirs(TLDS_PATH); - const subDirectoryImports = subDirs.map(makeSubdirectoryImport).join("\n"); - const subDirectoryExports = makeSubdirectoryExports(subDirs); - return `${subDirectoryImports} - -export default { ${subDirectoryExports} }; -`; -} - -export function addNewTemplate({ templateName, organisationDomain }) { - const dirsToMake = getDirsToMake(organisationDomain); - const organisationPath = path.join( - TLDS_PATH, - reverseDnsNotation(organisationDomain) - ); - if (dirsToMake.length === 0) { - throw new Error( - "Current version of addNewTemplate does not support adding templates to existing folder" - ); - } - - fs.mkdirSync(organisationPath, { recursive: true }); - fs.copySync(EXAMPLE_TEMPLATE_PATH, path.join(organisationPath, templateName)); - - const templateDestinationFolder = path.join( - reverseDnsNotation(organisationDomain), - templateName - ); - - const organisationDir = organisationPath.split(path.sep).slice(-1); - const organisationIndex = generateOrganisationIndexExports({ - templateTagMapping: { [templateName]: templateName }, - organisationDir - }); - - fs.writeFileSync(path.join(organisationPath, "index.js"), organisationIndex); - - fs.writeFileSync(path.join(TLDS_PATH, "index.js"), generateTldsIndex()); - - const childPaths = generatePartialChildPaths(templateDestinationFolder); - - const intermediateDirs = childPaths.slice(0, -2); - - intermediateDirs.map(dir => { - const fullPath = path.resolve(TLDS_PATH, dir); - const dirName = dir.split(path.sep).slice(-1)[0]; - const index = generateIntermediateIndexTemplate({ - subDirs: getSubDirs(fullPath), - currDir: dirName - }); - return fs.writeFileSync(path.join(fullPath, "index.js"), index); - }); - - return true; -} - -export const cli = () => { - inquirer - .prompt([ - { - type: "input", - name: "organisationDomain", - message: "Organisation Domain Name? e.g: moe.edu.sg" - }, - { - type: "input", - name: "templateName", - message: - "Template Name? (this is the value that will be in your certificate file) e.g: 2019-Feb-GovTech-Opencerts-Associate" - } - ]) - .then(answers => { - const templatePath = path.join( - TLDS_PATH, - reverseDnsNotation(answers.organisationDomain), - answers.templateName - ); - inquirer - .prompt([ - { - type: "confirm", - name: "confirm", - message: `Organisation Domain Name: ${ - answers.organisationDomain - }, Template Name: ${ - answers.templateName - } \n Folder will be created at ${templatePath}` - } - ]) - .then(confirmation => { - if (confirmation.confirm) { - try { - addNewTemplate({ ...answers }); - } catch (error) { - console.error(error); - } - } else { - console.log("Operation cancelled"); - } - }); - }); -}; - -export default addNewTemplate; diff --git a/scripts/addNewTemplate.utils.test.js b/scripts/addNewTemplate.utils.test.js deleted file mode 100644 index 146a3fab..00000000 --- a/scripts/addNewTemplate.utils.test.js +++ /dev/null @@ -1,120 +0,0 @@ -import path from "path"; -import { - reverseDnsNotation, - generatePartialChildPaths, - getSubDirs, - generateIntermediateIndexTemplate, - generateOrganisationIndexExports, - getDirsToMake -} from "./addNewTemplate"; - -const EXAMPLE_DIR = "./src/components/CertificateTemplates/tlds/sg/gov/tech"; - -describe("reverseDnsNotation", () => { - test("should work correctly", () => { - expect(reverseDnsNotation("nus.edu.sg")).toBe( - `sg${path.sep}edu${path.sep}nus` - ); - expect(reverseDnsNotation("google.com")).toBe(`com${path.sep}google`); - }); -}); - -describe("generatePartialChildPaths", () => { - test("should work correctly", () => { - expect(generatePartialChildPaths("sg/edu/nus")).toEqual([ - `sg`, - `sg${path.sep}edu`, - `sg${path.sep}edu${path.sep}nus` - ]); - expect(generatePartialChildPaths("com/google")).toEqual([ - "com", - `com${path.sep}google` - ]); - }); -}); - -describe("getSubDirs", () => { - test("should return 'Govtech-Demo-Cert' when used on example dir", () => { - expect(getSubDirs(EXAMPLE_DIR)).toEqual([ - "2018-Geekout", - "2018-OpenCertsAssociate", - "Govtech-Demo-Cert" - ]); - }); -}); - -describe("getDirsToMake", () => { - test("should work", () => { - expect(getDirsToMake("blockchain-institute.edu.dev")).toEqual([ - `dev`, - `dev${path.sep}edu`, - `dev${path.sep}edu${path.sep}blockchain-institute` - ]); - expect(getDirsToMake("tech.gov.sg")).toEqual([]); - expect(getDirsToMake("nonexistent.gov.sg")).toEqual([ - `sg${path.sep}gov${path.sep}nonexistent` - ]); - }); -}); - -describe("intermediateIndexTemplate", () => { - test("should work", () => { - expect( - generateIntermediateIndexTemplate({ - subDirs: ["singaporetech", "np"], - currDir: "edu" - }) - ).toBe( - `/* eslint-disable camelcase */ -/* because we need to use _ to replace hyphens in dns */ -import { addDirToTemplatePath } from "template-utils/addDirToTemplatePath"; - -import singaporetech from "./singaporetech"; -import np from "./np"; - -export default addDirToTemplatePath("edu", { ...singaporetech, ...np }); -` - ); - }); - test("should correctly throw when given a non-dns-compliant folder name", () => { - expect(() => { - generateIntermediateIndexTemplate({ - subDirs: [".com"], - currDir: "edu" - }); - }).toThrow(); - }); - - test("should correctly replace hyphens with underscores", () => { - expect( - generateIntermediateIndexTemplate({ - subDirs: ["ssg-wsg"], - currDir: "gov" - }) - ).toBe(`/* eslint-disable camelcase */ -/* because we need to use _ to replace hyphens in dns */ -import { addDirToTemplatePath } from "template-utils/addDirToTemplatePath"; - -import ssg_wsg from "./ssg-wsg"; - -export default addDirToTemplatePath("gov", { ...ssg_wsg }); -`); - }); -}); - -describe("generateOrganisationIndexExports", () => { - test("should work", () => { - expect( - generateOrganisationIndexExports({ - templateTagMapping: { foo: "bar", qux: "baz" }, - organisationDir: "tech" - }) - ).toBe(`import dynamic from "next/dynamic"; - -export default { - "foo": dynamic(() => import("./bar" /* webpackChunkName: "tech-Templates" */)) - "qux": dynamic(() => import("./baz" /* webpackChunkName: "tech-Templates" */)) -}; -`); - }); -}); diff --git a/scripts/cli.js b/scripts/cli.js deleted file mode 100644 index bb9b1750..00000000 --- a/scripts/cli.js +++ /dev/null @@ -1,23 +0,0 @@ -const inquirer = require("inquirer"); -const addNewTemplate = require("./addNewTemplate").cli; - -/* eslint-disable no-console */ - -inquirer - .prompt([ - { - type: "list", - name: "command", - message: "Operation?", - choices: ["Add a template", "Quit"] - } - ]) - .then(answers => { - switch (answers.command) { - case "Add a template": - addNewTemplate(); - break; - default: - console.log("Good bye!"); - } - });