Skip to content

Commit

Permalink
feat: fixed UI and added permissions check to backend
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielHougaard committed Oct 1, 2024
1 parent 0485b56 commit f0210c2
Show file tree
Hide file tree
Showing 7 changed files with 460 additions and 232 deletions.
1 change: 1 addition & 0 deletions backend/src/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,7 @@ export const registerRoutes = async (
projectService,
orgService,
projectEnvService,
permissionService,
secretService
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { OrgMembershipRole } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ForbiddenRequestError } from "@app/lib/errors";

import { TOrgServiceFactory } from "../org/org-service";
import { TProjectServiceFactory } from "../project/project-service";
import { TProjectEnvServiceFactory } from "../project-env/project-env-service";
Expand All @@ -10,6 +14,7 @@ type TExternalMigrationServiceFactoryDep = {
orgService: TOrgServiceFactory;
projectEnvService: TProjectEnvServiceFactory;
secretService: TSecretServiceFactory;
permissionService: TPermissionServiceFactory;
};

export type TExternalMigrationServiceFactory = ReturnType<typeof externalMigrationServiceFactory>;
Expand All @@ -18,6 +23,7 @@ export const externalMigrationServiceFactory = ({
projectService,
orgService,
projectEnvService,
permissionService,
secretService
}: TExternalMigrationServiceFactoryDep) => {
const importEnvKeyData = async ({
Expand All @@ -28,6 +34,18 @@ export const externalMigrationServiceFactory = ({
actorOrgId,
actorAuthMethod
}: TImportEnvKeyDataCreate) => {
const { membership } = await permissionService.getOrgPermission(
actor,
actorId,
actorOrgId,
actorAuthMethod,
actorOrgId
);

if (membership.role !== OrgMembershipRole.Admin) {
throw new ForbiddenRequestError({ message: "Only admins can import data" });
}

const json = await decryptEnvKeyDataFn(decryptionKey, encryptedJson);
const envKeyData = await parseEnvKeyDataFn(json);
const response = await importDataIntoInfisicalFn({
Expand Down
42 changes: 23 additions & 19 deletions frontend/src/hooks/api/migration/mutations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@ import { apiRequest } from "@app/config/request";
import { workspaceKeys } from "../workspace";

export const useImportEnvKey = () => {
const queryClient = useQueryClient();
const queryClient = useQueryClient();

return useMutation({
mutationFn: async ({ encryptedJson, decryptionKey }: {
encryptedJson: {
nonce: string,
data: string
}, decryptionKey: string
}): Promise<{ success: boolean, message: string }> => {
const { data } = await apiRequest.post("/api/v3/migrate/env-key/", {
encryptedJson,
decryptionKey
});
return data;
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
}
});
};
return useMutation({
mutationFn: async ({
encryptedJson,
decryptionKey
}: {
encryptedJson: {
nonce: string;
data: string;
};
decryptionKey: string;
}) => {
const { data } = await apiRequest.post("/api/v3/migrate/env-key/", {
encryptedJson,
decryptionKey
});
return data;
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
}
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React, {
ChangeEvent,
DragEvent,
forwardRef,
useImperativeHandle,
useRef,
useState
} from "react";
import { faUpload } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { twMerge } from "tailwind-merge";

import { useToggle } from "@app/hooks";

type Props = {
accept?: string;
onData: (file: File) => void;
isSmaller: boolean;
text?: string;
isDisabled?: boolean;
};

export const GenericDropzone = forwardRef<HTMLInputElement, Props>(
({ onData, isSmaller, text, isDisabled, accept }: Props, ref): JSX.Element => {
const [isDragActive, setDragActive] = useToggle();
const [selectedFileName, setSelectedFileName] = useState<string | null>(null);
const inputRef = useRef<HTMLInputElement>(null);

useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);

const updateSelectedFileName = () => {
if (inputRef.current?.files?.[0]) {
setSelectedFileName(inputRef.current.files[0].name);
} else {
setSelectedFileName(null);
}
};

const handleDrag = (e: DragEvent) => {
e.preventDefault();
e.stopPropagation();
if (e.type === "dragenter" || e.type === "dragover") {
setDragActive.on();
} else if (e.type === "dragleave") {
setDragActive.off();
}
};

const handleDrop = (e: DragEvent) => {
e.preventDefault();
e.stopPropagation();
if (!e.dataTransfer) {
return;
}

e.dataTransfer.dropEffect = "copy";
setDragActive.off();
const file = e.dataTransfer.files[0];
onData(file);
setSelectedFileName(file.name);
};

const handleFileUpload = (e: ChangeEvent<HTMLInputElement>) => {
e.preventDefault();

if (!e.target?.files?.[0]) {
return;
}
onData(e.target.files[0]);
updateSelectedFileName();
};

React.useEffect(() => {
updateSelectedFileName();
}, []);

return (
<div>
<div
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
onDrop={handleDrop}
className={twMerge(
"relative mx-0.5 mb-4 mt-4 flex cursor-pointer items-center justify-center rounded-md bg-mineshaft-900 py-4 px-2 text-sm text-mineshaft-200 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100",
isDragActive && "opacity-100",
!isSmaller && "mx-auto w-full max-w-3xl flex-col space-y-4 py-20"
)}
>
{selectedFileName ? (
<p>{selectedFileName}</p>
) : (
<div className="flex flex-col items-center justify-center space-y-2">
<div>
<FontAwesomeIcon icon={faUpload} size={isSmaller ? "2x" : "5x"} />
</div>
<div>
<p className="">{text}</p>
</div>
<input
ref={inputRef}
disabled={isDisabled}
id="fileSelect"
type="file"
className="absolute h-full w-full cursor-pointer opacity-0"
accept={accept}
onChange={handleFileUpload}
/>
</div>
)}
</div>
</div>
);
}
);

GenericDropzone.displayName = "GenericDropzone";
Loading

0 comments on commit f0210c2

Please sign in to comment.