Skip to content

Commit

Permalink
feat: add custom prompts partials
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-hamilton committed Feb 1, 2024
1 parent 69b8cef commit 74c5e41
Show file tree
Hide file tree
Showing 12 changed files with 391 additions and 1,061 deletions.
1,075 changes: 35 additions & 1,040 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"homepage": "https://github.com/auth0/auth0-deploy-cli#readme",
"dependencies": {
"ajv": "^6.12.6",
"auth0": "^3.0.0",
"auth0": "^4.3.0",
"dot-prop": "^5.2.0",
"fs-extra": "^10.1.0",
"global-agent": "^2.1.12",
Expand Down
34 changes: 33 additions & 1 deletion src/context/directory/handlers/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Prompts,
PromptSettings,
AllPromptsByLanguage,
CustomPromptsConfig,
} from '../../../tools/auth0/handlers/prompts';

type ParsedPrompts = ParsedAsset<'prompts', Prompts>;
Expand All @@ -25,6 +26,10 @@ const getCustomTextFile = (promptsDirectory: string) => {
return path.join(promptsDirectory, 'custom-text.json');
};

const getPartialsFile = (promptsDirectory: string) => {
return path.join(promptsDirectory, 'partials.json');
};

function parse(context: DirectoryContext): ParsedPrompts {
const promptsDirectory = getPromptsDirectory(context.filePath);
if (!existsMustBeDir(promptsDirectory)) return { prompts: null }; // Skip
Expand All @@ -47,10 +52,33 @@ function parse(context: DirectoryContext): ParsedPrompts {
}) as AllPromptsByLanguage;
})();

const partials = (() => {
const partialsFile = getPartialsFile(promptsDirectory);
if (!isFile(partialsFile)) return {};
const partialsFileContent = loadJSON(partialsFile, {
mappings: context.mappings,
disableKeywordReplacement: context.disableKeywordReplacement,
}) as CustomPromptsConfig;

Object.entries(partialsFileContent).forEach(([promptName, partialsArray]) => {
partialsArray.forEach((partialConfig, i) => {
if (partialConfig.template) {
partialsFileContent[promptName][i].template = context.loadFile(
path.join(promptsDirectory, partialConfig.template),
promptsDirectory
);
}
});
});

return partialsFileContent;
})();

return {
prompts: {
...promptsSettings,
customText,
partials,
},
};
}
Expand All @@ -60,7 +88,7 @@ async function dump(context: DirectoryContext): Promise<void> {

if (!prompts) return;

const { customText, ...promptsSettings } = prompts;
const { customText, partials, ...promptsSettings } = prompts;

const promptsDirectory = getPromptsDirectory(context.filePath);
ensureDirSync(promptsDirectory);
Expand All @@ -72,6 +100,10 @@ async function dump(context: DirectoryContext): Promise<void> {
if (!customText) return;
const customTextFile = getCustomTextFile(promptsDirectory);
dumpJSON(customTextFile, customText);

if (!partials) return;
const partialsFile = getPartialsFile(promptsDirectory);
dumpJSON(partialsFile, partials);
}

const promptsHandler: DirectoryHandler<ParsedPrompts> = {
Expand Down
2 changes: 1 addition & 1 deletion src/context/directory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class DirectoryContext {
assets: Assets;
disableKeywordReplacement: boolean;

constructor(config: Config, mgmtClient: Auth0APIClient) {
constructor(config: Config, mgmtClient) {
this.filePath = config.AUTH0_INPUT_FILE;
this.config = config;
this.mappings = config.AUTH0_KEYWORD_REPLACE_MAPPINGS || {};
Expand Down
8 changes: 4 additions & 4 deletions src/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,19 +161,19 @@ export const setupContext = async (
return new AuthenticationClient({
domain: AUTH0_DOMAIN,
clientId: AUTH0_CLIENT_ID,
clientAssertionSigningKey: readFileSync(AUTH0_CLIENT_SIGNING_KEY_PATH),
clientAssertionSigningKey: readFileSync(AUTH0_CLIENT_SIGNING_KEY_PATH, 'utf-8'),
clientAssertionSigningAlg: !!AUTH0_CLIENT_SIGNING_ALGORITHM
? AUTH0_CLIENT_SIGNING_ALGORITHM
: undefined,
});
})();

const clientCredentials = await authClient.clientCredentialsGrant({
const clientCredentials = await authClient.oauth.clientCredentialsGrant({
audience: config.AUTH0_AUDIENCE
? config.AUTH0_AUDIENCE
: `https://${config.AUTH0_DOMAIN}/api/v2/`,
});
return clientCredentials.access_token;
return clientCredentials.data.access_token;
})();

const mgmtClient = new ManagementClient({
Expand Down
113 changes: 112 additions & 1 deletion src/tools/auth0/handlers/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,63 @@ export type PromptsCustomText = {
export type Prompts = Partial<
PromptSettings & {
customText: AllPromptsByLanguage;
partials: CustomPromptPartials;
}
>;

export type AllPromptsByLanguage = Partial<{
[key in Language]: Partial<PromptsCustomText>;
}>;

const customPromptsPromptTypes = [
'login',
'login-id',
'login-password',
'signup',
'signup-id',
'signup-password',
] as const;

export type CustomPromptsPromptTypes = typeof customPromptsPromptTypes[number];

const customPromptsScreenTypes = [
'login',
'login-id',
'login-password',
'signup',
'signup-id',
'signup-password',
] as const;

export type CustomPromptsScreenTypes = typeof customPromptsPromptTypes[number];

export type CustomPromptsInsertionPoints =
| 'form-content-start'
| 'form-content-end'
| 'form-footer-start'
| 'form-footer-end'
| 'secondary-actions-start'
| 'secondary-actions-end';

export type CustomPromptPartialsScreens = Partial<{
[screen in CustomPromptsScreenTypes]: Partial<{
[insertionPoint in CustomPromptsInsertionPoints]: string;
}>;
}>;

export type CustomPromptPartials = Partial<{
[prompt in CustomPromptsPromptTypes]: CustomPromptPartialsScreens;
}>;

export type CustomPromptsConfig = {
[prompt in CustomPromptsPromptTypes]: [
{
name: string;
template: string;
}
];
};

export default class PromptsHandler extends DefaultHandler {
existing: Prompts;

Expand All @@ -179,9 +229,12 @@ export default class PromptsHandler extends DefaultHandler {

const customText = await this.getCustomTextSettings();

const partials = await this.getCustomPromptsPartials();

return {
...promptsSettings,
customText,
partials,
};
}

Expand Down Expand Up @@ -236,19 +289,57 @@ export default class PromptsHandler extends DefaultHandler {
});
}

async getCustomPromptsPartials(): Promise<CustomPromptPartials> {
return this.client.pool
.addEachTask({
data: customPromptsPromptTypes.map((promptType) => ({ promptType })),
generator: ({ promptType }) =>
this.client.prompts
.getPartials({
prompt: promptType,
})
.then((partialsData: CustomPromptPartials) => {
if (isEmpty(partialsData)) return null;
return {
[promptType]: {
...partialsData,
},
};
}),
})
.promise()
.then((partialsDataWithNulls) =>
partialsDataWithNulls
.filter(Boolean)
.reduce(
(
acc: CustomPromptPartials,
partialsData: { [prompt: string]: CustomPromptPartials }
) => {
const [promptName] = Object.keys(partialsData);
acc[promptName] = partialsData[promptName];
return acc;
},
{}
)
);
}

async processChanges(assets: Assets): Promise<void> {
const { prompts } = assets;

if (!prompts) return;

const { customText, ...promptSettings } = prompts;
const { partials, customText, ...promptSettings } = prompts;

if (!isEmpty(promptSettings)) {
await this.client.prompts.updateSettings({}, promptSettings);
}

await this.updateCustomTextSettings(customText);

await this.updateCustomPromptsPartials(partials);

this.updated += 1;
this.didUpdate(prompts);
}
Expand Down Expand Up @@ -284,4 +375,24 @@ export default class PromptsHandler extends DefaultHandler {
})
.promise();
}

async updateCustomPromptsPartials(partials: Prompts['partials']): Promise<void> {
/*
Note: deletes are not currently supported
*/
if (!partials) return;

await this.client.pool
.addEachTask({
data: Object.keys(partials).map((prompt: CustomPromptsPromptTypes) => {
const body = partials[prompt] || {};
return {
body,
prompt,
};
}),
generator: ({ prompt, body }) => this.client.prompts.updatePartials({ prompt }, body),
})
.promise();
}
}
11 changes: 11 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
Prompts,
PromptsCustomText,
PromptSettings,
CustomPromptPartials,
CustomPromptsPromptTypes,
CustomPromptPartialsScreens,
} from './tools/auth0/handlers/prompts';
import { Tenant } from './tools/auth0/handlers/tenant';
import { Theme } from './tools/auth0/handlers/themes';
Expand Down Expand Up @@ -159,6 +162,14 @@ export type BaseAuth0APIClient = {
prompt: PromptTypes;
language: Language;
}) => Promise<Partial<PromptsCustomText>>;
updatePartials: (arg0: {
prompt: CustomPromptsPromptTypes;
},
body: CustomPromptPartialsScreens
) => Promise<void>;
getPartials: (arg0: {
prompt: CustomPromptsPromptTypes;
}) => Promise<CustomPromptPartials>;
getSettings: () => Promise<PromptSettings>;
updateSettings: (arg0: {}, arg1: Partial<PromptSettings>) => Promise<void>;
};
Expand Down
Loading

0 comments on commit 74c5e41

Please sign in to comment.