Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Auth0 integration #334

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions packages/cli/src/cli/commands/config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import nunjucks from "nunjucks";
import ora from "ora";
import { getApiConfig } from "../../lib/apiConfig";
import {
deleteConfigDetails,
getLocalConfigDetails,
persistConfigDetails,
} from "../../lib/localStorage";
import * as LocalStorage from "../../lib/localStorage";
import { errorHandler } from "../exceptions";

nunjucks.configure({ autoescape: true });
Expand All @@ -17,7 +13,7 @@ export const setTargetEnvironment = errorHandler<"production" | "staging">(
async (resolve, reject) => {
const spinner = ora("Updating config file").start();
try {
await persistConfigDetails({
await LocalStorage.persistConfigDetails({
targetEnvironment: target,
});

Expand All @@ -38,7 +34,7 @@ export const resetTargetEnvironment = errorHandler<void>((): Promise<void> => {
async (resolve, reject) => {
const spinner = ora("Deleting config file").start();
try {
await deleteConfigDetails();
await LocalStorage.deleteConfigDetails();
spinner.succeed(`Successfully deleted config file`);
resolve();
} catch (e) {
Expand All @@ -56,7 +52,7 @@ export const printConfigurationData = errorHandler<void>(
async (resolve, reject) => {
const spinner = ora("Retrieving configuration data").start();
try {
const localConfig = await getLocalConfigDetails();
const localConfig = await LocalStorage.getConfigDetails();
const apiConfig = await getApiConfig();
console.log(JSON.stringify({ localConfig, apiConfig }, null, 4));
spinner.succeed(`Successfully retrieved configuration data`);
Expand Down
23 changes: 18 additions & 5 deletions packages/cli/src/cli/commands/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { exit } from "process";
import chalk from "chalk";
import AddOnApiHelper from "../../lib/addonApiHelper";
import { Logger, SpinnerLogger } from "../../lib/logger";
import { errorHandler } from "../exceptions";
import { errorHandler, IncorrectAccount } from "../exceptions";

type GeneratePreviewParam = {
documentId: string;
baseUrl: string;
domain: string;
};

const GDOCS_URL_REGEX =
/^(https|http):\/\/(www.)?docs.google.com\/document\/d\/(?<id>[^/]+).*$/;

export const generatePreviewLink = errorHandler<GeneratePreviewParam>(
async ({ documentId, baseUrl }: GeneratePreviewParam) => {
async ({ documentId, baseUrl, domain }: GeneratePreviewParam) => {
const logger = new Logger();

let cleanedId = documentId.trim();
Expand Down Expand Up @@ -45,9 +46,21 @@ export const generatePreviewLink = errorHandler<GeneratePreviewParam>(
const generateLinkLogger = new SpinnerLogger("Generating preview link");
generateLinkLogger.start();

const previewLink = await AddOnApiHelper.previewFile(cleanedId, {
baseUrl,
});
let previewLink: string;
try {
// TODO: Check if we can derive domain from the document
previewLink = await AddOnApiHelper.previewFile(cleanedId, domain, {
baseUrl,
});
} catch (e) {
if (e instanceof IncorrectAccount) {
generateLinkLogger.fail(
"Selected account doesn't belong to domain of the site.",
);
return;
}
throw e;
}

generateLinkLogger.succeed(
"Successfully generated preview link. Please copy it below:",
Expand Down
33 changes: 28 additions & 5 deletions packages/cli/src/cli/commands/import/drupal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import type { GaxiosResponse } from "gaxios";
import type { drive_v3 } from "googleapis";
import queryString from "query-string";
import AddOnApiHelper from "../../../lib/addonApiHelper";
import { PersistedTokens } from "../../../lib/auth";
import { Logger } from "../../../lib/logger";
import { errorHandler } from "../../exceptions";
import { errorHandler, IncorrectAccount } from "../../exceptions";
import { createFolder, getAuthedDrive, preprocessBaseURL } from "./utils";

type DrupalImportParams = {
Expand Down Expand Up @@ -85,7 +86,29 @@ export const importFromDrupal = errorHandler<DrupalImportParams>(
exit(1);
}

const drive = await getAuthedDrive(logger);
// Get site details
const site = await AddOnApiHelper.getSite(siteId);

let tokens: PersistedTokens;
try {
tokens = await AddOnApiHelper.getGoogleTokens({
scopes: ["https://www.googleapis.com/auth/drive.file"],
domain: site.domain,
});
} catch (e) {
if (e instanceof IncorrectAccount) {
logger.error(
chalk.red(
"ERROR: Selected account doesn't belong to domain of the site.",
),
);
return;
}
throw e;
}

const drive = getAuthedDrive(tokens);

const folder = await createFolder(
drive,
`PCC Import from Drupal on ${new Date().toLocaleDateString()} unique id: ${randomUUID()}`,
Expand Down Expand Up @@ -166,12 +189,12 @@ export const importFromDrupal = errorHandler<DrupalImportParams>(
}

// Add it to the PCC site.
await AddOnApiHelper.getDocument(fileId, true);
await AddOnApiHelper.getDocument(fileId, true, site.domain);

try {
await AddOnApiHelper.updateDocument(
fileId,
siteId,
site,
post.attributes.title,
post.relationships.field_topics?.data
?.map(
Expand All @@ -188,7 +211,7 @@ export const importFromDrupal = errorHandler<DrupalImportParams>(
);

if (publish) {
await AddOnApiHelper.publishDocument(fileId);
await AddOnApiHelper.publishDocument(fileId, site.domain);
}
} catch (e) {
console.error(e instanceof AxiosError ? e.response?.data : e);
Expand Down
58 changes: 30 additions & 28 deletions packages/cli/src/cli/commands/import/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { exit } from "process";
import chalk from "chalk";
import { parseFromString } from "dom-parser";
import type { GaxiosResponse } from "gaxios";
import { OAuth2Client } from "google-auth-library";
import { drive_v3, google } from "googleapis";
import { drive_v3 } from "googleapis";
import ora from "ora";
import showdown from "showdown";
import AddOnApiHelper from "../../../lib/addonApiHelper";
import { getLocalAuthDetails } from "../../../lib/localStorage";
import { PersistedTokens } from "../../../lib/auth";
import { Logger } from "../../../lib/logger";
import { errorHandler } from "../../exceptions";
import { errorHandler, IncorrectAccount } from "../../exceptions";
import { getAuthedDrive } from "./utils";

const HEADING_TAGS = ["h1", "h2", "h3", "title"];

Expand All @@ -37,24 +37,33 @@ export const importFromMarkdown = errorHandler<MarkdownImportParams>(
// Prepare article content and title
const content = fs.readFileSync(filePath).toString();

// Get site details
const site = await AddOnApiHelper.getSite(siteId);

// Check user has required permission to create drive file
await AddOnApiHelper.getIdToken([
"https://www.googleapis.com/auth/drive.file",
]);
const authDetails = await getLocalAuthDetails();
if (!authDetails) {
logger.error(chalk.red(`ERROR: Failed to retrieve login details.`));
exit(1);
let tokens: PersistedTokens;
try {
tokens = await AddOnApiHelper.getGoogleTokens({
scopes: ["https://www.googleapis.com/auth/drive"],
domain: site.domain,
});
} catch (e) {
if (e instanceof IncorrectAccount) {
logger.error(
chalk.red(
"ERROR: Selected account doesn't belong to domain of the site.",
),
);
return;
}
throw e;
}

// Create Google Doc
const spinner = ora("Creating document on the Google Drive...").start();
const oauth2Client = new OAuth2Client();
oauth2Client.setCredentials(authDetails);
const drive = google.drive({
version: "v3",
auth: oauth2Client,
});

const drive = getAuthedDrive(tokens);

const converter = new showdown.Converter();
const html = converter.makeHtml(content);
const dom = parseFromString(html);
Expand Down Expand Up @@ -89,22 +98,15 @@ export const importFromMarkdown = errorHandler<MarkdownImportParams>(
}

// Create PCC document
await AddOnApiHelper.getDocument(fileId, true, title);
await AddOnApiHelper.getDocument(fileId, true, site.domain, title);
// Cannot set metadataFields(title,slug) in the same request since we reset metadataFields
// when changing the siteId.
await AddOnApiHelper.updateDocument(
fileId,
siteId,
title,
[],
null,
verbose,
);
await AddOnApiHelper.getDocument(fileId, false, title);
await AddOnApiHelper.updateDocument(fileId, site, title, [], null, verbose);
await AddOnApiHelper.getDocument(fileId, false, site.domain, title);

// Publish PCC document
if (publish) {
await AddOnApiHelper.publishDocument(fileId);
await AddOnApiHelper.publishDocument(fileId, site.domain);
}
spinner.succeed(
`Successfully created document at below path${
Expand Down
21 changes: 3 additions & 18 deletions packages/cli/src/cli/commands/import/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { exit } from "process";
import chalk from "chalk";
import type { GaxiosResponse } from "gaxios";
import { OAuth2Client } from "google-auth-library";
import { drive_v3, google } from "googleapis";
import AddOnApiHelper from "../../../lib/addonApiHelper";
import { getLocalAuthDetails } from "../../../lib/localStorage";
import { Logger } from "../../../lib/logger";
import { PersistedTokens } from "../../../lib/auth";

export function preprocessBaseURL(originalBaseURL: string) {
let baseURL: string | null = originalBaseURL;
Expand All @@ -32,20 +28,9 @@ export function preprocessBaseURL(originalBaseURL: string) {
}
}

export async function getAuthedDrive(logger: Logger) {
await AddOnApiHelper.getIdToken([
"https://www.googleapis.com/auth/drive.file",
]);

const authDetails = await getLocalAuthDetails();

if (!authDetails) {
logger.error(chalk.red(`ERROR: Failed to retrieve login details. `));
exit(1);
}

export function getAuthedDrive(tokens: PersistedTokens) {
const oauth2Client = new OAuth2Client();
oauth2Client.setCredentials(authDetails);
oauth2Client.setCredentials(tokens);
return google.drive({
version: "v3",
auth: oauth2Client,
Expand Down
32 changes: 27 additions & 5 deletions packages/cli/src/cli/commands/import/wordpress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import type { GaxiosResponse } from "gaxios";
import { drive_v3 } from "googleapis";
import queryString from "query-string";
import AddOnApiHelper from "../../../lib/addonApiHelper";
import { PersistedTokens } from "../../../lib/auth";
import { Logger } from "../../../lib/logger";
import { errorHandler } from "../../exceptions";
import { errorHandler, IncorrectAccount } from "../../exceptions";
import { createFolder, getAuthedDrive, preprocessBaseURL } from "./utils";

const DEFAULT_PAGE_SIZE = 50;
Expand Down Expand Up @@ -128,7 +129,28 @@ export const importFromWordPress = errorHandler<WordPressImportParams>(
exit(1);
}

const drive = await getAuthedDrive(logger);
// Get site details
const site = await AddOnApiHelper.getSite(siteId);

let tokens: PersistedTokens;
try {
tokens = await AddOnApiHelper.getGoogleTokens({
scopes: ["https://www.googleapis.com/auth/drive.file"],
domain: site.domain,
});
} catch (e) {
if (e instanceof IncorrectAccount) {
logger.error(
chalk.red(
"ERROR: Selected account doesn't belong to domain of the site.",
),
);
return;
}
throw e;
}

const drive = getAuthedDrive(tokens);
const folder = await createFolder(
drive,
`PCC Import from WordPress on ${new Date().toLocaleDateString()} unique id: ${randomUUID()}`,
Expand Down Expand Up @@ -204,12 +226,12 @@ export const importFromWordPress = errorHandler<WordPressImportParams>(
}

// Add it to the PCC site.
await AddOnApiHelper.getDocument(fileId, true);
await AddOnApiHelper.getDocument(fileId, true, site.domain);

try {
await AddOnApiHelper.updateDocument(
fileId,
siteId,
site,
post.title.rendered,
(await getTagInfo(processedBaseURL, post.tags)).map((x) => x.name),
{
Expand All @@ -220,7 +242,7 @@ export const importFromWordPress = errorHandler<WordPressImportParams>(
);

if (publish) {
await AddOnApiHelper.publishDocument(fileId);
await AddOnApiHelper.publishDocument(fileId, site.domain);
}
} catch (e) {
console.error(e instanceof AxiosError ? e.response?.data : e);
Expand Down
Loading