Skip to content

Commit

Permalink
Merge pull request #505 from auth0/DXCDT-48-branding-support
Browse files Browse the repository at this point in the history
DXCDT-48: Directory branding support
  • Loading branch information
willvedd authored Apr 25, 2022
2 parents fefbbf6 + 501ee34 commit dc6d66b
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 42 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
54 changes: 46 additions & 8 deletions src/context/directory/handlers/branding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);

Expand All @@ -30,24 +35,37 @@ 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 }: DirectoryContext): void => {
if (!assets || !assets.branding) return;

const {
branding: { templates = [] },
} = assets;

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(
Expand All @@ -67,7 +85,27 @@ async function dump(context) {
templateDefinition
);
});
}
};

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, brandingWithoutTemplates);
};

const brandingHandler: DirectoryHandler<ParsedBranding> = {
parse,
Expand Down
43 changes: 31 additions & 12 deletions src/context/yaml/handlers/branding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,54 @@ 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<ParsedBranding> {
// Load the HTML file for each page
if (!context.assets.branding)
return {
branding: {
templates: [],
},
};

const { branding } = context.assets;
const {
branding: { templates, ...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);
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,
},
};
}

async function dump(context: YAMLContext): Promise<ParsedBranding> {
const { branding } = context.assets || { branding: undefined };
const { branding } = context.assets;

branding.templates = branding.templates || [];

// create templates folder
Expand Down
2 changes: 1 addition & 1 deletion src/tools/auth0/handlers/branding.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand Down
66 changes: 49 additions & 17 deletions test/context/directory/branding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,30 @@ import { cleanThenMkdir, mockMgmtClient, testDataDir } from '../../utils';
const html = '<html>##foo##</html>';
const htmlTransformed = '<html>bar</html>';

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 () => {
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,
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` })
);

Expand All @@ -40,12 +50,19 @@ 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());

context.assets.branding = {
colors: {
primary: '#F8F8F2',
page_background: '#112',
},
font: {
url: 'https://mycompany.org/font/myfont.ttf',
},
templates: [
{
body: html,
Expand All @@ -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`,
Expand Down
7 changes: 4 additions & 3 deletions test/context/yaml/branding.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ const html = '<html>##foo##</html>';
const htmlTransformed = '<html>bar</html>';

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);

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);
Expand All @@ -38,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(
Expand Down
1 change: 1 addition & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export function mockMgmtClient() {
getBruteForceConfig: () => ({}),
getSuspiciousIpThrottlingConfig: () => ({}),
},
branding: { getSettings: () => ({}) },
logStreams: { getAll: () => [] },
};
}
Expand Down

0 comments on commit dc6d66b

Please sign in to comment.