Skip to content

Commit

Permalink
[dsync] Sdk tweaks (boxyhq#765)
Browse files Browse the repository at this point in the history
Co-authored-by: Deepak Prabhakara <[email protected]>
  • Loading branch information
niwsa and deepakprabhakara authored Dec 11, 2023
1 parent ceb0ebb commit d307c34
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 163 deletions.
113 changes: 75 additions & 38 deletions lib/jackson/dsync.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { z } from 'zod';
import { Directory, DirectoryType } from '@boxyhq/saml-jackson';

import env from '@/lib/env';
Expand All @@ -7,35 +6,29 @@ import { ApiResponse } from 'types';
import { ApiError } from '@/lib/errors';
import { options } from './config';

export const createDirectorySchema = z.object({
name: z.string(),
provider: z.string(),
});

export const deleteDirectorySchema = z.object({
dsyncId: z.string(),
});

// Fetch DSync connections for a team
export const getDirectoryConnections = async ({
tenant,
dsyncId,
}: {
tenant: string;
tenant?: string;
dsyncId?: string;
}) => {
if (env.jackson.selfHosted) {
const query = new URLSearchParams({
tenant,
product: env.jackson.productId,
let query;
if (tenant) {
query = `?${new URLSearchParams({
tenant,
product: env.jackson.productId,
}).toString()}`;
} else {
query = `/${dsyncId}`;
}
const response = await fetch(`${env.jackson.url}/api/v1/dsync${query}`, {
...options,
method: 'GET',
});

const response = await fetch(
`${env.jackson.url}/api/v1/dsync?${query.toString()}`,
{
...options,
method: 'GET',
}
);

const json = (await response.json()) as ApiResponse<Directory[]>;

if (!response.ok) {
Expand All @@ -47,10 +40,12 @@ export const getDirectoryConnections = async ({

const { directorySync } = await jackson();

const { data, error } = await directorySync.directories.getByTenantAndProduct(
tenant,
env.jackson.productId
);
const { data, error } = tenant
? await directorySync.directories.getByTenantAndProduct(
tenant,
env.jackson.productId
)
: await directorySync.directories.get(dsyncId!);

if (error) {
throw new ApiError(error.code, error.message);
Expand All @@ -63,12 +58,16 @@ export const getDirectoryConnections = async ({
export const createDirectoryConnection = async ({
name,
tenant,
provider,
}: z.infer<typeof createDirectorySchema> & { tenant: string }) => {
type,
}: {
name: string;
type: string;
tenant: string;
}) => {
const body = {
name,
tenant,
type: provider as DirectoryType,
type: type as DirectoryType,
product: env.jackson.productId,
};

Expand Down Expand Up @@ -103,17 +102,53 @@ export const createDirectoryConnection = async ({
return data;
};

export const patchDirectoryConnection = async (params) => {
const body = { ...params };
if (env.jackson.selfHosted) {
const response = await fetch(
`${env.jackson.url}/api/v1/dsync/${body.directoryId}`,
{
...options,
method: 'PATCH',
body: JSON.stringify(body),
}
);

const json = (await response.json()) as ApiResponse<Directory>;

if (!response.ok) {
throw new ApiError(response.status, json.error.message);
}

return json.data;
}
const { directorySync } = await jackson();

const { data, error } = await directorySync.directories.update(
body.directoryId,
body
);

if (error) {
throw new ApiError(error.code, error.message);
}

return data;
};

// Delete DSync connection for a team
export const deleteDirectoryConnection = async ({
dsyncId,
}: z.infer<typeof deleteDirectorySchema>) => {
export const deleteDirectoryConnection = async (params) => {
const body = { ...params };
if (env.jackson.selfHosted) {
const response = await fetch(`${env.jackson.url}/api/v1/dsync/${dsyncId}`, {
...options,
method: 'DELETE',
});
const response = await fetch(
`${env.jackson.url}/api/v1/dsync/${body.directoryId}`,
{
...options,
method: 'DELETE',
}
);

const json = (await response.json()) as ApiResponse<Directory[]>;
const json = (await response.json()) as ApiResponse<object>;

if (!response.ok) {
throw new ApiError(response.status, json.error.message);
Expand All @@ -124,7 +159,9 @@ export const deleteDirectoryConnection = async ({

const { directorySync } = await jackson();

const { data, error } = await directorySync.directories.delete(dsyncId);
const { data, error } = await directorySync.directories.delete(
body.directoryId
);

if (error) {
throw new ApiError(error.code, error.message);
Expand Down
34 changes: 17 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"dependencies": {
"@boxyhq/metrics": "0.2.6",
"@boxyhq/react-ui": "3.3.21",
"@boxyhq/react-ui": "3.3.23",
"@boxyhq/saml-jackson": "1.15.2",
"@heroicons/react": "2.0.18",
"@hookform/resolvers": "3.3.2",
Expand Down
91 changes: 91 additions & 0 deletions pages/api/teams/[slug]/dsync/[directoryId].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import env from '@/lib/env';
import { throwIfNoTeamAccess } from 'models/team';
import { throwIfNotAllowed } from 'models/user';
import type { NextApiRequest, NextApiResponse } from 'next';
import { ApiError } from '@/lib/errors';
import {
deleteDirectoryConnection,
getDirectoryConnections,
patchDirectoryConnection,
} from '@/lib/jackson/dsync';
import { sendAudit } from '@/lib/retraced';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { method } = req;

try {
if (!env.teamFeatures.dsync) {
throw new ApiError(404, 'Not Found');
}

switch (method) {
case 'GET':
await handleGET(req, res);
break;
case 'PATCH':
await handlePATCH(req, res);
break;
case 'DELETE':
await handleDELETE(req, res);
break;
default:
res.setHeader('Allow', 'GET, PATCH, DELETE');
res.status(405).json({
error: { message: `Method ${method} Not Allowed` },
});
}
} catch (error: any) {
console.error(error);

const message = error.message || 'Something went wrong';
const status = error.status || 500;

res.status(status).json({ error: { message } });
}
}

const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const teamMember = await throwIfNoTeamAccess(req, res);

throwIfNotAllowed(teamMember, 'team_dsync', 'read');

const connection = await getDirectoryConnections({
dsyncId: req.query.directoryId as string,
});

res.status(200).json({ data: connection });
};

const handlePATCH = async (req: NextApiRequest, res: NextApiResponse) => {
const teamMember = await throwIfNoTeamAccess(req, res);

throwIfNotAllowed(teamMember, 'team_dsync', 'read');

const body = { ...req.query, ...req.body };

const connection = await patchDirectoryConnection(body);

res.status(200).json({ data: connection });
};

const handleDELETE = async (req: NextApiRequest, res: NextApiResponse) => {
const teamMember = await throwIfNoTeamAccess(req, res);

throwIfNotAllowed(teamMember, 'team_dsync', 'delete');

const params = req.query;

await deleteDirectoryConnection(params);

sendAudit({
action: 'dsync.connection.delete',
crud: 'd',
user: teamMember.user,
team: teamMember.team,
});

res.status(200).json({ data: {} });
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { ApiError } from '@/lib/errors';
import {
createDirectoryConnection,
createDirectorySchema,
deleteDirectoryConnection,
deleteDirectorySchema,
getDirectoryConnections,
} from '@/lib/jackson/dsync';

Expand All @@ -30,11 +27,9 @@ export default async function handler(
case 'POST':
await handlePOST(req, res);
break;
case 'DELETE':
await handleDELETE(req, res);
break;

default:
res.setHeader('Allow', 'GET, POST, DELETE');
res.setHeader('Allow', 'GET, POST');
res.status(405).json({
error: { message: `Method ${method} Not Allowed` },
});
Expand Down Expand Up @@ -66,7 +61,7 @@ const handlePOST = async (req: NextApiRequest, res: NextApiResponse) => {

throwIfNotAllowed(teamMember, 'team_dsync', 'create');

const body = createDirectorySchema.parse(req.body);
const body = req.body;

const connection = await createDirectoryConnection({
...body,
Expand All @@ -82,22 +77,3 @@ const handlePOST = async (req: NextApiRequest, res: NextApiResponse) => {

res.status(201).json({ data: connection });
};

const handleDELETE = async (req: NextApiRequest, res: NextApiResponse) => {
const teamMember = await throwIfNoTeamAccess(req, res);

throwIfNotAllowed(teamMember, 'team_dsync', 'delete');

const params = deleteDirectorySchema.parse(req.query);

await deleteDirectoryConnection(params);

sendAudit({
action: 'dsync.connection.delete',
crud: 'd',
user: teamMember.user,
team: teamMember.team,
});

res.status(200).json({ data: {} });
};
Loading

0 comments on commit d307c34

Please sign in to comment.