Skip to content

Commit

Permalink
feat: fix for auth issue and added ep payment .env.local auto update
Browse files Browse the repository at this point in the history
  • Loading branch information
field123 committed Sep 29, 2023
1 parent 04fa1e9 commit ce78175
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 61 deletions.
36 changes: 15 additions & 21 deletions packages/composable-cli/src/commands/login/login-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { WelcomeNote } from "../ui/login/welcome-note"
import { render } from "ink"
import { trackCommandHandler } from "../../util/track-command-handler"
import { EpccRequester } from "../../util/command"
import { credentialsSchema } from "../../lib/authentication/credentials-schema"

/**
* Region prompts
Expand All @@ -42,24 +43,6 @@ const regionPrompts = {
default: "us-east",
} as const

/*
choices: [
{
name: "North America (free-trial region)",
value: "useast.api.elasticpath.com",
},
{
name: "Europe",
value: "euwest.api.elasticpath.com",
},
new inquirer.Separator(),
{
name: "Other",
value: "Other",
},
],
*/

function handleRegionUpdate(store: Conf, region: "eu-west" | "us-east"): void {
store.set("region", region)
}
Expand Down Expand Up @@ -224,16 +207,27 @@ async function authenticateUserPassword(
password,
)

if (checkIsErrorResponse(credentialsResp)) {
const parsedCredentialsResp = credentialsSchema.safeParse(credentialsResp)

if (!parsedCredentialsResp.success) {
return {
success: false,
code: "authentication-failure",
name: "data parsing error",
message: parsedCredentialsResp.error.message,
}
}

if (checkIsErrorResponse(parsedCredentialsResp.data)) {
return {
success: false,
code: "authentication-failure",
name: "epcc error",
message: credentialsResp.errors.toString(),
message: parsedCredentialsResp.data.errors.toString(),
}
}

storeCredentials(store, credentialsResp as any)
storeCredentials(store, parsedCredentialsResp.data)

return {
success: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ import {
EPPaymentsSetup,
epPaymentsSetupSchema,
} from "./util/setup-ep-payments-schema"
import {
callRule,
HostTree,
SchematicContext,
} from "@angular-devkit/schematics"
import { processUnknownError } from "../../../util/process-unknown-error"
import { Result } from "../../../types/results"
import { addEnvVariables } from "../../../lib/devkit/add-env-variables"
import { commitTree, createScopedHost } from "../../../lib/devkit/tree-util"

export function createEPPaymentsCommand(
ctx: CommandContext,
Expand Down Expand Up @@ -98,31 +107,132 @@ export function createEPPaymentsCommandHandler(
}

if (result.data.stripe_account !== options.accountId) {
await attemptToAddEnvVariables(ctx, spinner, {
accountId: result.data.stripe_account!,
publishableKey: options.publishableKey,
})

spinner.succeed(`EP Payments was already setup.`)

const alreadyExistingAccountId = result.data.stripe_account!

ctx.logger.warn(
boxen(
`EP Payments was already setup with account id: ${ctx.colors.bold.green(
alreadyExistingAccountId,
)}\n\nMake sure you add the correct account id NEXT_PUBLIC_STRIPE_ACCOUNT_ID=${alreadyExistingAccountId} and with the appropriate publishable key NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY to your .env.local file.`,
{ padding: 1, borderColor: "yellow" },
),
)

return {
success: true,
data: {},
}
}

await attemptToAddEnvVariables(ctx, spinner, {
accountId: result.data.stripe_account!,
publishableKey: options.publishableKey,
})

spinner.succeed(`EP Payments setup successfully.`)

return {
success: true,
data: {},
}
} catch (e) {
spinner.fail(`Failed to setup Algolia integration`)
spinner.fail(`Failed to setup EP Payment gateway.`)
ctx.logger.error(processUnknownError(e))
return {
success: false,
error: {
code: "ALGOLIA_INTEGRATION_SETUP_FAILED",
message: "Failed to setup Algolia integration",
code: "FAILED_TO_SETUP_EP_PAYMENT_GATEWAY",
message: "Failed to setup EP Payment gateway",
},
}
}
}
}

async function attemptToAddEnvVariables(
ctx: CommandContext,
spinner: ora.Ora,
{ accountId, publishableKey }: EpPaymentEnvVariableRecord,
): Promise<Result<{}, { code: string; message: string }>> {
const { workspaceRoot, composableRc } = ctx

if (!composableRc) {
return {
success: false,
error: {
code: "NO_COMPOSABLE_RC",
message: "Could not detect workspace root - missing composable.rc file",
},
}
}

spinner.start(
`Adding EP Payments environment variables to .env.local file...`,
)

if (!workspaceRoot) {
spinner.fail(
`Failed to add environment variables to .env.local file - missing workspace root`,
)
return {
success: false,
error: {
code: "EP",
message:
"Setup of EP Payment gateway succeeded but failed to add env variables to .env.local file",
},
}
}

await addEpPaymentEnvVariables(workspaceRoot, {
accountId,
publishableKey,
})

spinner.succeed(`Added EP Payments environment variables to .env.local file.`)

return {
success: true,
data: {},
}
}

type EpPaymentEnvVariableRecord = { accountId: string; publishableKey: string }

async function addEpPaymentEnvVariables(
workspaceRoot: string,
{ accountId, publishableKey }: EpPaymentEnvVariableRecord,
): Promise<void> {
const host = createScopedHost(workspaceRoot)

const initialTree = new HostTree(host)

if (!initialTree.exists(".env.local")) {
initialTree.create(".env.local", "")
}

const context = {} as unknown as SchematicContext

const rule = addEnvVariables(
{
NEXT_PUBLIC_STRIPE_ACCOUNT_ID: accountId,
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: publishableKey,
},
".env.local",
)

const tree = await callRule(rule, initialTree, context).toPromise()

await commitTree(host, tree)
}

async function resolveOptions(
args: EPPaymentsCommandArguments,
logger: logging.Logger,
Expand Down
9 changes: 5 additions & 4 deletions packages/composable-cli/src/commands/store/store-command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from "../../util/epcc-error"
import { trackCommandHandler } from "../../util/track-command-handler"
import { EpccRequester } from "../../util/command"
import { storeUserStore } from "../../util/conf-store/store-credentials"

export function createStoreCommand(
ctx: CommandContext,
Expand Down Expand Up @@ -121,14 +122,14 @@ export function createSetStoreCommandHandler(
}

export function createStoreCommandHandler(
_ctx: CommandContext,
ctx: CommandContext,
): CommandHandlerFunction<
StoreCommandData,
StoreCommandError,
StoreCommandArguments
> {
return async function storeCommandHandler(_args) {
console.warn("command not recognized")
ctx.logger.warn("command not recognized")
return {
success: false,
error: {
Expand Down Expand Up @@ -184,7 +185,7 @@ export async function selectStoreById(
}
}

store.set("store", parsedResultData)
storeUserStore(store, parsedResultData)

return {
success: true,
Expand Down Expand Up @@ -235,7 +236,7 @@ export async function storeSelectPrompt(
}
}

store.set("store", answers.store)
storeUserStore(store, answers.store)

return {
success: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { MiddlewareFunction } from "yargs"
import { getCredentials, getToken } from "./get-token"
import { gateway, MemoryStorageFactory, Moltin } from "@moltin/sdk"
import Conf from "conf"
import { getRegion, resolveHostFromRegion } from "../../util/resolve-region"
import {
getRegion,
resolveHostFromRegion,
resolveHostNameFromRegion,
} from "../../util/resolve-region"

export function createEpClientMiddleware(
ctx: CommandContext,
Expand All @@ -22,14 +26,19 @@ export function createEpClientMiddleware(
}

function createEpccClient(store: Conf): Moltin {
const regionResult = getRegion(store)
if (!regionResult.success) {
throw new Error(
"No region found - ep client custom authenticator - are you authetnicated? - `composable-cli login`",
)
}

const hostname = resolveHostNameFromRegion(regionResult.data)
const resolvedRegion = resolveHostFromRegion(regionResult.data)

return gateway({
host: hostname,
custom_authenticator: async () => {
const regionResult = getRegion(store)
if (!regionResult.success) {
throw new Error("No region found - ep client custom authenticator")
}

const resolvedRegion = resolveHostFromRegion(regionResult.data)
await getToken(resolvedRegion, store)

const credentialsResult = getCredentials(store)
Expand Down
22 changes: 16 additions & 6 deletions packages/composable-cli/src/lib/authentication/get-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import {
checkIsErrorResponse,
resolveEPCCErrorMessage,
} from "../../util/epcc-error"
import { handleClearCredentials } from "../../util/conf-store/store-credentials"
import {
handleClearCredentials,
storeCredentials,
storeUserStore,
} from "../../util/conf-store/store-credentials"
import { getStore } from "../stores/get-store"
import { userSwitchStoreResponseSchema } from "../stores/switch-store-schema"
import {
UserSwitchStoreResponse,
userSwitchStoreResponseSchema,
} from "../stores/switch-store-schema"
import { encodeObjectToQueryString } from "../../util/encode-object-to-query-str"

export function getCredentials(store: Conf): Result<Credentials, Error> {
Expand Down Expand Up @@ -63,6 +70,9 @@ export async function getToken(
return handleExpiredToken(store, apiUrl, refresh_token)
}

// Switch EP store if there is an active store
await switchStoreIfActive(store, apiUrl, credentialsResult.data.access_token)

return {
success: true,
data: access_token,
Expand Down Expand Up @@ -94,7 +104,7 @@ async function handleExpiredToken(
}

// Set credentials in conf store
store.set("credentials", renewedToken.data)
storeCredentials(store, renewedToken.data)

// Switch EP store if there is an active store
await switchStoreIfActive(store, apiUrl, renewedToken.data.access_token)
Expand All @@ -115,7 +125,7 @@ async function switchStoreIfActive(store: Conf, apiUrl: string, token: string) {
)

if (switchStoreResponse.success) {
store.set("store", switchStoreResponse.data)
storeUserStore(store, activeStoreResult.data)
}
} else {
store.delete("store")
Expand Down Expand Up @@ -161,7 +171,7 @@ export async function switchUserStore(
apiUrl: string,
token: string,
storeId: string,
): Promise<Result<{}, Error>> {
): Promise<Result<UserSwitchStoreResponse, Error>> {
const switchResult = await postSwitchUserStore(apiUrl, token, storeId)

const parsedResult = userSwitchStoreResponseSchema.safeParse(switchResult)
Expand All @@ -175,7 +185,7 @@ export async function switchUserStore(

return {
success: true,
data: {},
data: parsedResult.data,
}
}

Expand Down
18 changes: 2 additions & 16 deletions packages/composable-cli/src/lib/config-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { promises } from "node:fs"
import { composableRcSchema } from "./composable-rc-schema"
import findUp from "find-up"
import path from "path"
import { processUnknownError } from "../util/process-unknown-error"

export function createConfigMiddleware(
ctx: CommandContext,
Expand All @@ -16,6 +17,7 @@ export function createConfigMiddleware(

if (!configPath) {
ctx.logger.debug("No .composablerc file found")
ctx.workspaceRoot = process.cwd()
return
}

Expand Down Expand Up @@ -43,19 +45,3 @@ export function createConfigMiddleware(
}
}
}

function processUnknownError(error: unknown): string {
let errorMessage = "An unknown error occurred"

if (error instanceof Error) {
if (error.message) {
errorMessage += `: ${error.message}`
}

if (error.stack) {
errorMessage += `\nStack Trace:\n${error.stack}`
}
}

return errorMessage
}
Loading

0 comments on commit ce78175

Please sign in to comment.