From f2ade6f9c0fc3e92442c8703a2bb778b18306099 Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Mon, 18 Apr 2022 13:31:23 -0400 Subject: [PATCH 1/5] Fixing branding loading bug --- src/context/yaml/handlers/branding.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/context/yaml/handlers/branding.ts b/src/context/yaml/handlers/branding.ts index 9b4c5f1f7..310383814 100644 --- a/src/context/yaml/handlers/branding.ts +++ b/src/context/yaml/handlers/branding.ts @@ -11,13 +11,12 @@ type ParsedBranding = { async function parse(context: YAMLContext): Promise { // Load the HTML file for each page - const { branding } = context.assets; - if (!branding || !branding.templates) return { branding }; + if (!branding && !branding['templates']) return { branding }; const templates = branding.templates.map((templateDefinition) => { - const markupFile = path.join(templateDefinition.body); + const markupFile = path.join(context.basePath, templateDefinition.body); return { template: templateDefinition.template, body: loadFileAndReplaceKeywords(markupFile, context.mappings), @@ -33,7 +32,7 @@ async function parse(context: YAMLContext): Promise { } async function dump(context: YAMLContext): Promise { - const { branding } = context.assets || { branding: undefined }; + const { branding } = context.assets.branding; branding.templates = branding.templates || []; // create templates folder From 4c9b2a9295374b279f0e1c949cb369e7ab31fc93 Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Mon, 18 Apr 2022 16:08:40 -0400 Subject: [PATCH 2/5] Adding directory support for branding --- src/context/directory/handlers/branding.ts | 48 ++++++++++++++++++---- src/context/yaml/handlers/branding.ts | 32 ++++++++++----- src/tools/auth0/handlers/branding.ts | 2 +- 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/context/directory/handlers/branding.ts b/src/context/directory/handlers/branding.ts index 47d8307c1..58e6b518c 100644 --- a/src/context/directory/handlers/branding.ts +++ b/src/context/directory/handlers/branding.ts @@ -10,9 +10,14 @@ type ParsedBranding = { }; function parse(context: DirectoryContext): ParsedBranding { + const brandingDirectory = path.join(context.filePath, constants.BRANDING_DIRECTORY); + + if (!existsMustBeDir(brandingDirectory)) return { branding: undefined }; + + const branding = loadJSON(path.join(brandingDirectory, 'branding.json'), context.mappings); + const brandingTemplatesFolder = path.join( - context.filePath, - constants.BRANDING_DIRECTORY, + brandingDirectory, constants.BRANDING_TEMPLATES_DIRECTORY ); @@ -30,24 +35,36 @@ function parse(context: DirectoryContext): ParsedBranding { return { branding: { + ...branding, templates, }, }; } -async function dump(context) { - const { branding } = context.assets; +async function dump(context: DirectoryContext) { + const { + branding: { templates = [], ...branding }, + } = context.assets; - if (!branding || !branding.templates || !branding.templates) return; // Skip, nothing to dump + if (!!branding) dumpBranding(context); + if (!!templates) dumpBrandingTemplates(context); +} + +const dumpBrandingTemplates = ({ + filePath, + assets: { + branding: { templates = [] }, + }, +}: DirectoryContext): void => { const brandingTemplatesFolder = path.join( - context.filePath, + filePath, constants.BRANDING_DIRECTORY, constants.BRANDING_TEMPLATES_DIRECTORY ); fs.ensureDirSync(brandingTemplatesFolder); - branding.templates.forEach((templateDefinition) => { + templates.forEach((templateDefinition) => { const markup = templateDefinition.body; try { fs.writeFileSync( @@ -67,7 +84,22 @@ async function dump(context) { templateDefinition ); }); -} +}; + +const dumpBranding = ({ + filePath, + assets: { + branding: { templates: _templates, ...branding }, + }, +}: DirectoryContext): void => { + const brandingDirectory = path.join(filePath, constants.BRANDING_DIRECTORY); + + fs.ensureDirSync(brandingDirectory); + + const brandingFilePath = path.join(brandingDirectory, 'branding.json'); + + dumpJSON(brandingFilePath, branding); +}; const brandingHandler: DirectoryHandler = { parse, diff --git a/src/context/yaml/handlers/branding.ts b/src/context/yaml/handlers/branding.ts index 310383814..33f4949d5 100644 --- a/src/context/yaml/handlers/branding.ts +++ b/src/context/yaml/handlers/branding.ts @@ -5,28 +5,40 @@ import { constants, loadFileAndReplaceKeywords } from '../../../tools'; import { YAMLHandler } from '.'; import YAMLContext from '..'; +type BrandingTemplate = { + template: string; + body: string; +}; + type ParsedBranding = { - branding: unknown; + branding: { + templates?: BrandingTemplate[]; + [key: string]: unknown; + }; }; async function parse(context: YAMLContext): Promise { // Load the HTML file for each page - const { branding } = context.assets; + const { + branding: { templates, ...branding }, + } = context.assets; if (!branding && !branding['templates']) return { branding }; - const templates = branding.templates.map((templateDefinition) => { - const markupFile = path.join(context.basePath, templateDefinition.body); - return { - template: templateDefinition.template, - body: loadFileAndReplaceKeywords(markupFile, context.mappings), - }; - }); + const parsedTemplates: BrandingTemplate[] = templates.map( + (templateDefinition: BrandingTemplate): BrandingTemplate => { + const markupFile = path.join(context.basePath, templateDefinition.body); + return { + template: templateDefinition.template, + body: loadFileAndReplaceKeywords(markupFile, context.mappings), + }; + } + ); return { branding: { ...branding, - templates, + templates: parsedTemplates, }, }; } diff --git a/src/tools/auth0/handlers/branding.ts b/src/tools/auth0/handlers/branding.ts index 2f98dae00..936339952 100644 --- a/src/tools/auth0/handlers/branding.ts +++ b/src/tools/auth0/handlers/branding.ts @@ -1,7 +1,7 @@ import DefaultHandler from './default'; import constants from '../../constants'; import log from '../../../logger'; -import { Assets, Asset } from '../../../types'; +import { Asset } from '../../../types'; export const schema = { type: 'object', From 4bfa0b9eabbf69e729f80e70e9354d3b9fd565fa Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Mon, 18 Apr 2022 16:09:32 -0400 Subject: [PATCH 3/5] Updating readme to show support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1440f6a9e..d1c293417 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The `auth0-deploy-cli` tool supports the importing and exporting of Auth0 Tenant Supported Auth0 Management API resources - [x] [Actions](https://auth0.com/docs/api/management/v2/#!/Actions/get_actions) -- [ ] [Branding](https://auth0.com/docs/api/management/v2/#!/Branding/get_branding) +- [x] [Branding](https://auth0.com/docs/api/management/v2/#!/Branding/get_branding) - [x] [Clients (Applications)](https://auth0.com/docs/api/management/v2#!/Clients/get_clients) - [x] [Client Grants](https://auth0.com/docs/api/management/v2#!/Client_Grants/get_client_grants) - [x] [Connections](https://auth0.com/docs/api/management/v2#!/Connections/get_connections) From 8dfca9e4b6637c9c80a0d2611d3d66b4f39c9eb9 Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Tue, 19 Apr 2022 11:40:41 -0400 Subject: [PATCH 4/5] Tests passing --- src/context/directory/handlers/branding.ts | 30 ++++++----- src/context/yaml/handlers/branding.ts | 6 ++- test/context/directory/branding.test.js | 62 ++++++++++++++++------ test/context/yaml/branding.test.js | 3 +- test/utils.js | 1 + 5 files changed, 73 insertions(+), 29 deletions(-) diff --git a/src/context/directory/handlers/branding.ts b/src/context/directory/handlers/branding.ts index 58e6b518c..1af5d0b5c 100644 --- a/src/context/directory/handlers/branding.ts +++ b/src/context/directory/handlers/branding.ts @@ -51,12 +51,13 @@ async function dump(context: DirectoryContext) { if (!!templates) dumpBrandingTemplates(context); } -const dumpBrandingTemplates = ({ - filePath, - assets: { +const dumpBrandingTemplates = ({ filePath, assets }: DirectoryContext): void => { + if (!assets || !assets.branding) return; + + const { branding: { templates = [] }, - }, -}: DirectoryContext): void => { + } = assets; + const brandingTemplatesFolder = path.join( filePath, constants.BRANDING_DIRECTORY, @@ -86,19 +87,24 @@ const dumpBrandingTemplates = ({ }); }; -const dumpBranding = ({ - filePath, - assets: { - branding: { templates: _templates, ...branding }, - }, -}: DirectoryContext): void => { +const dumpBranding = ({ filePath, assets }: DirectoryContext): void => { + if (!assets || !assets.branding) return; + + const { branding } = assets; + + const brandingWithoutTemplates = (() => { + const newBranding = { ...branding }; + delete newBranding.templates; + return newBranding; + })(); + const brandingDirectory = path.join(filePath, constants.BRANDING_DIRECTORY); fs.ensureDirSync(brandingDirectory); const brandingFilePath = path.join(brandingDirectory, 'branding.json'); - dumpJSON(brandingFilePath, branding); + dumpJSON(brandingFilePath, brandingWithoutTemplates); }; const brandingHandler: DirectoryHandler = { diff --git a/src/context/yaml/handlers/branding.ts b/src/context/yaml/handlers/branding.ts index 33f4949d5..77efa1e8d 100644 --- a/src/context/yaml/handlers/branding.ts +++ b/src/context/yaml/handlers/branding.ts @@ -19,6 +19,9 @@ type ParsedBranding = { async function parse(context: YAMLContext): Promise { // Load the HTML file for each page + //@ts-ignore + if (!context.assets.branding) return { branding: undefined }; + const { branding: { templates, ...branding }, } = context.assets; @@ -44,7 +47,8 @@ async function parse(context: YAMLContext): Promise { } async function dump(context: YAMLContext): Promise { - const { branding } = context.assets.branding; + const { branding } = context.assets; + branding.templates = branding.templates || []; // create templates folder diff --git a/test/context/directory/branding.test.js b/test/context/directory/branding.test.js index f6ccb268d..c04e00714 100644 --- a/test/context/directory/branding.test.js +++ b/test/context/directory/branding.test.js @@ -10,20 +10,30 @@ import { cleanThenMkdir, mockMgmtClient, testDataDir } from '../../utils'; const html = '##foo##'; const htmlTransformed = 'bar'; +const brandingSettings = JSON.stringify({ + colors: { + primary: '#FFFFFF', + page_background: '#000000', + }, + font: { + url: 'https://mycompany.org/font/myfont.ttf', + }, +}); + describe('#directory context branding', () => { it('should process templates', async () => { const dir = path.join(testDataDir, 'directory', 'branding-process'); cleanThenMkdir(dir); - const brandingDir = path.join( - dir, - constants.BRANDING_DIRECTORY, - constants.BRANDING_TEMPLATES_DIRECTORY - ); + const brandingDir = path.join(dir, constants.BRANDING_DIRECTORY); cleanThenMkdir(brandingDir); - const markupFile = path.join(brandingDir, 'universal_login.html'); - fs.writeFileSync(markupFile, html); + const brandingTemplatesDir = path.join(brandingDir, constants.BRANDING_TEMPLATES_DIRECTORY); + cleanThenMkdir(brandingTemplatesDir); + + fs.writeFileSync(path.join(brandingDir, 'branding.json'), brandingSettings); + + fs.writeFileSync(path.join(brandingTemplatesDir, 'universal_login.html'), html); fs.writeFileSync( - path.join(brandingDir, 'universal_login.json'), + path.join(brandingTemplatesDir, 'universal_login.json'), JSON.stringify({ template: 'universal_login', body: `.${path.sep}universal_login.html` }) ); @@ -46,6 +56,13 @@ describe('#directory context branding', () => { const context = new Context({ AUTH0_INPUT_FILE: repoDir }, mockMgmtClient()); context.assets.branding = { + colors: { + primary: '#F8F8F2', + page_background: '#112', + }, + font: { + url: 'https://mycompany.org/font/myfont.ttf', + }, templates: [ { body: html, @@ -56,14 +73,29 @@ describe('#directory context branding', () => { await handler.dump(context); - const brandingDir = path.join( - repoDir, - constants.BRANDING_DIRECTORY, - constants.BRANDING_TEMPLATES_DIRECTORY - ); - const markup = fs.readFileSync(path.join(brandingDir, 'universal_login.html')).toString(); + const brandingDir = path.join(repoDir, constants.BRANDING_DIRECTORY); + const brandingTemplatesDir = path.join(brandingDir, constants.BRANDING_TEMPLATES_DIRECTORY); + + const brandingSettingsFile = fs + .readFileSync(path.join(brandingDir, 'branding.json')) + .toString(); + + expect(JSON.parse(brandingSettingsFile)).to.deep.equal({ + colors: { + primary: '#F8F8F2', + page_background: '#112', + }, + font: { + url: 'https://mycompany.org/font/myfont.ttf', + }, + }); + + const markup = fs + .readFileSync(path.join(brandingTemplatesDir, 'universal_login.html')) + .toString(); + expect(markup).to.equal(html); - const templateDefinition = loadJSON(path.join(brandingDir, 'universal_login.json')); + const templateDefinition = loadJSON(path.join(brandingTemplatesDir, 'universal_login.json')); expect(templateDefinition).to.deep.equal({ template: 'universal_login', body: `.${path.sep}universal_login.html`, diff --git a/test/context/yaml/branding.test.js b/test/context/yaml/branding.test.js index f28e74b2a..a862ac597 100644 --- a/test/context/yaml/branding.test.js +++ b/test/context/yaml/branding.test.js @@ -15,13 +15,14 @@ describe('#YAML context branding templates', () => { cleanThenMkdir(dir); const htmlFile = path.join(dir, 'universalLogin.html'); + fs.writeFileSync(htmlFile, html); const yaml = ` branding: templates: - template: universal_login - body: ${htmlFile} + body: universalLogin.html `; const yamlFile = path.join(dir, 'config.yaml'); fs.writeFileSync(yamlFile, yaml); diff --git a/test/utils.js b/test/utils.js index 61cb9f81c..98ac674a5 100644 --- a/test/utils.js +++ b/test/utils.js @@ -105,6 +105,7 @@ export function mockMgmtClient() { getBruteForceConfig: () => ({}), getSuspiciousIpThrottlingConfig: () => ({}), }, + branding: { getSettings: () => ({}) }, }; } From 678eb06d50cf4a8b2e34646fd0f22ae241ffe558 Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Tue, 19 Apr 2022 13:29:56 -0400 Subject: [PATCH 5/5] Removing ts ignore, correcting test names --- src/context/yaml/handlers/branding.ts | 8 ++++++-- test/context/directory/branding.test.js | 4 ++-- test/context/yaml/branding.test.js | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/context/yaml/handlers/branding.ts b/src/context/yaml/handlers/branding.ts index 77efa1e8d..44f9711f0 100644 --- a/src/context/yaml/handlers/branding.ts +++ b/src/context/yaml/handlers/branding.ts @@ -19,8 +19,12 @@ type ParsedBranding = { async function parse(context: YAMLContext): Promise { // Load the HTML file for each page - //@ts-ignore - if (!context.assets.branding) return { branding: undefined }; + if (!context.assets.branding) + return { + branding: { + templates: [], + }, + }; const { branding: { templates, ...branding }, diff --git a/test/context/directory/branding.test.js b/test/context/directory/branding.test.js index c04e00714..47eea6738 100644 --- a/test/context/directory/branding.test.js +++ b/test/context/directory/branding.test.js @@ -21,7 +21,7 @@ const brandingSettings = JSON.stringify({ }); describe('#directory context branding', () => { - it('should process templates', async () => { + it('should process branding settings, including templates', async () => { const dir = path.join(testDataDir, 'directory', 'branding-process'); cleanThenMkdir(dir); const brandingDir = path.join(dir, constants.BRANDING_DIRECTORY); @@ -50,7 +50,7 @@ describe('#directory context branding', () => { ]); }); - it('should dump templates', async () => { + it('should dump branding settings, including templates', async () => { const repoDir = path.join(testDataDir, 'directory', 'branding-dump'); cleanThenMkdir(repoDir); const context = new Context({ AUTH0_INPUT_FILE: repoDir }, mockMgmtClient()); diff --git a/test/context/yaml/branding.test.js b/test/context/yaml/branding.test.js index a862ac597..fc90ffa16 100644 --- a/test/context/yaml/branding.test.js +++ b/test/context/yaml/branding.test.js @@ -10,7 +10,7 @@ const html = '##foo##'; const htmlTransformed = 'bar'; describe('#YAML context branding templates', () => { - it('should process branding templates', async () => { + it('should process branding settings, including templates', async () => { const dir = path.join(testDataDir, 'yaml', 'branding-process'); cleanThenMkdir(dir); @@ -39,7 +39,7 @@ describe('#YAML context branding templates', () => { ]); }); - it('should dump branding templates', async () => { + it('should dump branding settings, including templates', async () => { const dir = path.join(testDataDir, 'yaml', 'branding-dump'); cleanThenMkdir(dir); const context = new Context(