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

Unify Deployment Environment #50

Merged
merged 4 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 0 additions & 4 deletions src/modules/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import { normalizeValue } from "./payment-app-configuration/utils";
import { env } from "@/lib/env.mjs";
import { randomBytes } from "crypto";

export const getEnvironmentFromKey = (): string => {
return env.NEXT_PUBLIC_ENV;
};

export function generate16DigitId(): string {
return randomBytes(8).toString("hex");
}
Expand Down
40 changes: 15 additions & 25 deletions src/modules/hyperswitch/hyperswitch-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ import { HyperswitchFullyConfiguredEntry } from "../payment-app-configuration/hy
import { env } from "@/lib/env.mjs";
import { invariant } from "@/lib/invariant";
import { ConfigObject } from "@/backend-lib/api-route-utils";
import { getEnvironmentFromKey } from "@/modules/api-utils";

const getHyperswitchBaseUrl = () => {
if (getEnvironmentFromKey() == "production") {
const getHyperswitchBaseUrl = (config_env: string) => {
if (config_env == "live") {
invariant(env.HYPERSWITCH_PROD_BASE_URL, "ENV variable HYPERSWITCH_PROD_BASE_URL not set");
return env.HYPERSWITCH_PROD_BASE_URL;
} else {
Expand All @@ -35,37 +34,28 @@ const getHyperswitchBaseUrl = () => {
}
};

const fetchHyperswitchConfiguration = async (
const fetchSavedConfiguration = async (
configData: ConfigObject,
): Promise<HyperswitchFullyConfiguredEntry> => {
): Promise<PaymentAppConfigEntryFullyConfigured> => {
const appConfig = await configData.configurator.getConfig();

const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}

return getHyperswitchConfig(paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig));
return paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig);
};

export const fetchHyperswitchProfileID = async (configData: ConfigObject): Promise<string> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}
let appChannelConfig = await fetchSavedConfiguration(configData);
const HyperswitchConfig = getHyperswitchConfig(
paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig),
);
return HyperswitchConfig.profileId;
};

export const fetchHyperswitchPublishableKey = async (configData: ConfigObject): Promise<string> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}
let appChannelConfig = await fetchSavedConfiguration(configData);
const HyperswitchConfig = getHyperswitchConfig(
paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig),
);
Expand All @@ -75,22 +65,22 @@ export const fetchHyperswitchPublishableKey = async (configData: ConfigObject):
export const fetchHyperswitchPaymentResponseHashKey = async (
configData: ConfigObject,
): Promise<string> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}
let appChannelConfig = await fetchSavedConfiguration(configData);
const HyperswitchConfig = getHyperswitchConfig(
paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig),
);
return HyperswitchConfig.paymentResponseHashKey;
};

export const createHyperswitchClient = async ({ configData }: { configData: ConfigObject }) => {
const HyperswitchConfig = await fetchHyperswitchConfiguration(configData);
const SavedConfiguration = await fetchSavedConfiguration(configData);
const HyperswitchConfig = getHyperswitchConfig(
paymentAppFullyConfiguredEntrySchema.parse(SavedConfiguration),
);

const fetcher = Fetcher.for<HyperswitchPaymentPaths>();
fetcher.configure({
baseUrl: getHyperswitchBaseUrl(),
baseUrl: getHyperswitchBaseUrl(SavedConfiguration.environment),
init: {
headers: {
"api-key": HyperswitchConfig.apiKey,
Expand Down Expand Up @@ -121,6 +111,6 @@ export function getHyperswitchConfig(
if (config.hyperswitchConfiguration) {
return config.hyperswitchConfiguration;
} else {
throw new ConfigurationNotFound("Please add Hyperswitch configuration");
throw new ConfigurationNotFound("Please add a Hyperswitch configuration");
}
}
34 changes: 11 additions & 23 deletions src/modules/juspay/juspay-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import { JuspayFullyConfiguredEntry } from "../payment-app-configuration/juspay-
import { getConfigurationForChannel } from "../payment-app-configuration/payment-app-configuration";
import { intoErrorResponse } from "./juspay-api-response";
import { invariant } from "@/lib/invariant";
import { getEnvironmentFromKey } from "@/modules/api-utils";

const getJuspayBaseUrl = () => {
if (getEnvironmentFromKey() == "production") {
const getJuspayBaseUrl = (config_env: string) => {
if (config_env == "live") {
invariant(env.JUSPAY_PROD_BASE_URL, "ENV variable HYPERSWITCH_PROD_BASE_URL not set");
return env.JUSPAY_PROD_BASE_URL;
} else {
Expand All @@ -23,60 +22,49 @@ const getJuspayBaseUrl = () => {
}
};

const fetchJuspayConfiguration = async (
const fetchSavedConfiguration = async (
configData: ConfigObject,
): Promise<JuspayFullyConfiguredEntry> => {
): Promise<PaymentAppConfigEntryFullyConfigured> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}

return getJuspayConfig(paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig));
return paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig);
};

export const fetchJuspayCleintId = async (configData: ConfigObject): Promise<string> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}
const appChannelConfig = await fetchSavedConfiguration(configData);
const JuspayConfig = getJuspayConfig(
paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig),
);
return JuspayConfig.clientId;
};

export const fetchJuspayUsername = async (configData: ConfigObject): Promise<string> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}
const appChannelConfig = await fetchSavedConfiguration(configData);
const JuspayConfig = getJuspayConfig(
paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig),
);
return JuspayConfig.username;
};

export const fetchJuspayPassword = async (configData: ConfigObject): Promise<string> => {
const appConfig = await configData.configurator.getConfig();
const appChannelConfig = getConfigurationForChannel(appConfig, configData.channelId);
if (appChannelConfig == null) {
throw new ChannelNotConfigured("Please assign a channel for your configuration");
}
const appChannelConfig = await fetchSavedConfiguration(configData);
const JuspayConfig = getJuspayConfig(
paymentAppFullyConfiguredEntrySchema.parse(appChannelConfig),
);
return JuspayConfig.password;
};

export const createJuspayClient = async ({ configData }: { configData: ConfigObject }) => {
const JuspayConfig = await fetchJuspayConfiguration(configData);
const SavedConfiguration = await fetchSavedConfiguration(configData);
const JuspayConfig = getJuspayConfig(SavedConfiguration);
const fetcher = Fetcher.for<JuspayPaymentPaths>();
const apiKey = Buffer.from(JuspayConfig.apiKey).toString("base64");
fetcher.configure({
baseUrl: getJuspayBaseUrl(),
baseUrl: getJuspayBaseUrl(SavedConfiguration.environment),
init: {
headers: {
authorization: `Basic ${apiKey}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import {
hyperswitchUserVisibleConfigEntrySchema,
} from "../hyperswitch-app-configuration/config-entry";

const Environment = z.enum(["test", "live"]);

export const paymentAppConfigEntryInternalSchema = z.object({
configurationId: z.string().min(1),
configurationName: z.string().min(1),
environment: Environment,
});

export const paymentAppConfigEntryEncryptedSchema = z.object({
Expand Down Expand Up @@ -58,6 +61,7 @@ export const paymentAppFormConfigEntrySchema = z
hyperswitchConfiguration: hyperswitchFormConfigEntrySchema.nullable().optional(),
juspayConfiguration: juspayFormConfigEntrySchema.nullable().optional(),
configurationName: paymentAppConfigEntryInternalSchema.shape.configurationName,
environment: paymentAppConfigEntryInternalSchema.shape.environment,
})
.strict();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const addConfigEntry = async (
juspayConfiguration: undefined,
configurationName: newConfigEntry.configurationName,
configurationId: uuid,
environment: newConfigEntry.environment,
} satisfies PaymentAppConfigEntryFullyConfigured;
await configurator.setConfigEntry(config);
const result = obfuscateConfigEntry(config);
Expand All @@ -112,6 +113,7 @@ export const addConfigEntry = async (
},
configurationName: newConfigEntry.configurationName,
configurationId: uuid,
environment: newConfigEntry.environment,
} satisfies PaymentAppConfigEntryFullyConfigured;
await configurator.setConfigEntry(config);
return obfuscateConfigEntry(config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ export const paymentAppConfigurationRouter = router({
add: protectedClientProcedure
.input(paymentAppFormConfigEntrySchema)
.mutation(async ({ input, ctx }) => {
const { hyperswitchConfiguration, juspayConfiguration, configurationName } = input;
const { hyperswitchConfiguration, juspayConfiguration, configurationName, environment } =
input;
if (juspayConfiguration) {
const { apiKey, username, clientId, password, merchantId } = juspayConfiguration;
ctx.logger.info("appConfigurationRouter.paymentConfig.add called");
Expand All @@ -76,6 +77,7 @@ export const paymentAppConfigurationRouter = router({
merchantId: redactLogValue(merchantId),
password: redactLogValue(password),
clientId: redactLogValue(clientId),
environment: redactLogValue(environment),
},
"appConfigurationRouter.paymentConfig.add input",
);
Expand Down
11 changes: 9 additions & 2 deletions src/modules/payment-app-configuration/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ import {
export const obfuscateConfigEntry = (
entry: PaymentAppConfigEntry | PaymentAppUserVisibleConfigEntry,
): PaymentAppUserVisibleConfigEntry => {
const { configurationName, configurationId, hyperswitchConfiguration, juspayConfiguration } =
entry;
const {
configurationName,
configurationId,
hyperswitchConfiguration,
juspayConfiguration,
environment,
} = entry;

if (juspayConfiguration) {
const { apiKey, username, merchantId, password, clientId } = juspayConfiguration;
Expand All @@ -32,6 +37,7 @@ export const obfuscateConfigEntry = (
},
configurationName,
configurationId,
environment,
} satisfies PaymentAppUserVisibleConfigEntry);
} else {
invariant(hyperswitchConfiguration, "Missing Configuration Entry");
Expand All @@ -54,6 +60,7 @@ export const obfuscateConfigEntry = (
},
configurationName,
configurationId,
environment,
} satisfies PaymentAppUserVisibleConfigEntry);

return result;
Expand Down
41 changes: 40 additions & 1 deletion src/modules/ui/atoms/macaw-ui/FormInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Input as $Input, type InputProps as $InputProps } from "@saleor/macaw-ui";
import {
Input as $Input,
Select as $Select,
type InputProps as $InputProps,
type SelectProps as $SelectProps,
} from "@saleor/macaw-ui";
import {
type UseControllerProps,
type FieldPath,
Expand Down Expand Up @@ -37,3 +42,37 @@ export function FormInput<
/>
);
}

export type SelectProps<
TFieldValues extends FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TOption = any,
TValue = any,
> = UseControllerProps<TFieldValues, TName> & $SelectProps<TOption, TValue>;

export function SelectInput<
TFieldValues extends FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>(props: SelectProps<TFieldValues, TName>) {
const { field, fieldState } = useController<TFieldValues, TName>(props);

return (
<$Select
error={!!fieldState.error?.message}
{...props}
{...field}
helperText={fieldState.error?.message || props.helperText}
onChange={(e) => {
field.onChange(e.value);
props.onChange?.(e.value);
}}
onFocus={(e) => {
props.onFocus?.(e);
}}
onBlur={(e) => {
field.onBlur();
props.onBlur?.(e);
}}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Box } from "@saleor/macaw-ui";
import { ChipSuccess, ChipHyperswitchOrange, ChipInfo } from "@/modules/ui/atoms/Chip/Chip";
import { getEnvironmentFromKey } from "@/modules/api-utils";

import { appBridgeInstance } from "@/app-bridge-instance";
import { HyperswitchUserVisibleConfigEntry } from "@/modules/payment-app-configuration/hyperswitch-app-configuration/config-entry";
import { JuspayUserVisibleConfigEntry } from "@/modules/payment-app-configuration/juspay-app-configuration/config-entry";
import { env } from "@/lib/env.mjs";

export const HyperswitchConfigurationSummary = ({
config,
environment,
}: {
config: HyperswitchUserVisibleConfigEntry;
environment: string;
}) => {
return (
<Box
Expand All @@ -25,7 +26,7 @@ export const HyperswitchConfigurationSummary = ({
Environment
</Box>
<Box as="dd" marginX={4} textAlign="right">
{getEnvironmentFromKey() === "production" ? (
{environment === "live" ? (
<ChipSuccess>LIVE</ChipSuccess>
) : (
<ChipHyperswitchOrange>TESTING</ChipHyperswitchOrange>
Expand All @@ -49,8 +50,10 @@ export const HyperswitchConfigurationSummary = ({

export const JuspayConfigurationSummary = ({
config,
environment,
}: {
config: JuspayUserVisibleConfigEntry;
environment: String;
}) => {
return (
<Box
Expand All @@ -66,7 +69,7 @@ export const JuspayConfigurationSummary = ({
Environment
</Box>
<Box as="dd" marginX={4} textAlign="right">
{getEnvironmentFromKey() === "production" ? (
{environment === "live" ? (
<ChipSuccess>LIVE</ChipSuccess>
) : (
<ChipHyperswitchOrange>TESTING</ChipHyperswitchOrange>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
type ChannelMapping,
} from "@/modules/payment-app-configuration/common-app-configuration/app-config";
import { type PaymentAppConfigEntry } from "@/modules/payment-app-configuration/common-app-configuration/config-entry";
import { getEnvironmentFromKey } from "@/modules/api-utils";

const ChannelToConfigurationTableRow = ({
channel,
Expand Down Expand Up @@ -94,7 +93,7 @@ const ChannelToConfigurationTableRow = ({
<Td className={classNames(tableStyles.td, tableStyles.statusColumnTd)}>
{!selectedConfiguration ? (
<ChipNeutral>Disabled</ChipNeutral>
) : getEnvironmentFromKey() === "live" ? (
) : selectedConfiguration.environment === "live" ? (
<ChipSuccess>LIVE</ChipSuccess>
) : (
<ChipHyperswitchOrange>TESTING</ChipHyperswitchOrange>
Expand Down
Loading