Delete more deprecated frontend calls

This commit is contained in:
Tuan Dang
2023-08-09 17:55:57 +07:00
parent 2a1665a2c3
commit b47f61f1ad
19 changed files with 121 additions and 289 deletions
@@ -1,7 +1,7 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { ISecret, Secret, ServiceTokenData } from "../../models"; import { ISecret, Secret, ServiceTokenData } from "../../models";
import { IAction, SecretVersion, EventType, AuditLog } from "../../ee/models"; import { AuditLog, EventType, IAction, SecretVersion } from "../../ee/models";
import { import {
ACTION_ADD_SECRETS, ACTION_ADD_SECRETS,
ACTION_DELETE_SECRETS, ACTION_DELETE_SECRETS,
@@ -14,7 +14,7 @@ import {
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import { EventService } from "../../services"; import { EventService } from "../../services";
import { eventPushSecrets } from "../../events"; import { eventPushSecrets } from "../../events";
import { EELogService, EESecretService, EEAuditLogService } from "../../ee/services"; import { EEAuditLogService, EELogService, EESecretService } from "../../ee/services";
import { SecretService, TelemetryService } from "../../services"; import { SecretService, TelemetryService } from "../../services";
import { getUserAgentType } from "../../utils/posthog"; import { getUserAgentType } from "../../utils/posthog";
import { PERMISSION_WRITE_SECRETS } from "../../variables"; import { PERMISSION_WRITE_SECRETS } from "../../variables";
+1 -1
View File
@@ -16,7 +16,7 @@ type ValidEventScope =
| Required<EventScope> | Required<EventScope>
export default class EEAuditLogService { export default class EEAuditLogService {
static async createAuditLog(authData: AuthData, event: Event, eventScope: ValidEventScope, shouldSave: boolean = true) { static async createAuditLog(authData: AuthData, event: Event, eventScope: ValidEventScope, shouldSave = true) {
const MS_IN_DAY = 24 * 60 * 60 * 1000; const MS_IN_DAY = 24 * 60 * 60 * 1000;
+1 -1
View File
@@ -6,7 +6,7 @@ import { userActionController } from "../../controllers/v1";
import { AuthMode } from "../../variables"; import { AuthMode } from "../../variables";
// note: [userAction] will be deprecated in /v2 in favor of [action] // note: [userAction] will be deprecated in /v2 in favor of [action]
router.post( router.post( // TODO endpoint: move this into /users/me
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT], acceptedAuthModes: [AuthMode.JWT],
@@ -4,12 +4,11 @@ import { faEye, faEyeSlash, faPenToSquare, faPlus, faX } from "@fortawesome/free
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { Select, SelectItem } from "@app/components/v2"; import { Select, SelectItem } from "@app/components/v2";
import { useSubscription } from "@app/context"; import { useSubscription, useWorkspace } from "@app/context";
import updateUserProjectPermission from "@app/ee/api/memberships/UpdateUserProjectPermission"; import updateUserProjectPermission from "@app/ee/api/memberships/UpdateUserProjectPermission";
import changeUserRoleInWorkspace from "@app/pages/api/workspace/changeUserRoleInWorkspace"; import changeUserRoleInWorkspace from "@app/pages/api/workspace/changeUserRoleInWorkspace";
import deleteUserFromWorkspace from "@app/pages/api/workspace/deleteUserFromWorkspace"; import deleteUserFromWorkspace from "@app/pages/api/workspace/deleteUserFromWorkspace";
import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey"; import getLatestFileKey from "@app/pages/api/workspace/getLatestFileKey";
import getProjectInfo from "@app/pages/api/workspace/getProjectInfo";
import uploadKeys from "@app/pages/api/workspace/uploadKeys"; import uploadKeys from "@app/pages/api/workspace/uploadKeys";
import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/cryptography/crypto"; import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/cryptography/crypto";
@@ -39,6 +38,7 @@ type EnvironmentProps = {
* @returns * @returns
*/ */
const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoading }: Props) => { const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoading }: Props) => {
const { currentWorkspace } = useWorkspace();
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const [roleSelected, setRoleSelected] = useState( const [roleSelected, setRoleSelected] = useState(
Array(userData?.length).fill(userData.map((user) => user.role)) Array(userData?.length).fill(userData.map((user) => user.role))
@@ -163,10 +163,11 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
useEffect(() => { useEffect(() => {
setMyRole(userData.filter((user) => user.email === myUser)[0]?.role); setMyRole(userData.filter((user) => user.email === myUser)[0]?.role);
(async () => { (async () => {
const result = await getProjectInfo({ projectId: workspaceId }); if (currentWorkspace) {
setWorkspaceEnvs(result.environments); setWorkspaceEnvs(currentWorkspace.environments);
}
})(); })();
}, [userData, myUser]); }, [userData, myUser, currentWorkspace]);
const grantAccess = async (id: string, publicKey: string) => { const grantAccess = async (id: string, publicKey: string) => {
const result = await getLatestFileKey({ workspaceId }); const result = await getLatestFileKey({ workspaceId });
@@ -1,5 +1,5 @@
import { fetchUserAction } from "@app/hooks/api/users/queries";
import getOrganizationUsers from "@app/pages/api/organization/GetOrgUsers"; import getOrganizationUsers from "@app/pages/api/organization/GetOrgUsers";
import checkUserAction from "@app/pages/api/userActions/checkUserAction";
interface OnboardingCheckProps { interface OnboardingCheckProps {
setTotalOnboardingActionsDone?: (value: number) => void; setTotalOnboardingActionsDone?: (value: number) => void;
@@ -20,25 +20,23 @@ const onboardingCheck = async ({
setUsersInOrg setUsersInOrg
}: OnboardingCheckProps) => { }: OnboardingCheckProps) => {
let countActions = 0; let countActions = 0;
const userActionSlack = await checkUserAction({ const userActionSlack = await fetchUserAction(
action: "slack_cta_clicked" "slack_cta_clicked"
}); );
if (userActionSlack) { if (userActionSlack) {
countActions += 1; countActions += 1;
} }
if (setHasUserClickedSlack) setHasUserClickedSlack(!!userActionSlack); if (setHasUserClickedSlack) setHasUserClickedSlack(!!userActionSlack);
const userActionSecrets = await checkUserAction({ const userActionSecrets = await fetchUserAction("first_time_secrets_pushed");
action: "first_time_secrets_pushed"
});
if (userActionSecrets) { if (userActionSecrets) {
countActions += 1; countActions += 1;
} }
if (setHasUserPushedSecrets) setHasUserPushedSecrets(!!userActionSecrets); if (setHasUserPushedSecrets) setHasUserPushedSecrets(!!userActionSecrets);
const userActionIntro = await checkUserAction({ const userActionIntro = await fetchUserAction("intro_cta_clicked");
action: "intro_cta_clicked"
});
if (userActionIntro) { if (userActionIntro) {
countActions += 1; countActions += 1;
} }
+2 -2
View File
@@ -3,8 +3,8 @@ import crypto from "crypto";
import { encryptAssymmetric } from "@app/components/utilities/cryptography/crypto"; import { encryptAssymmetric } from "@app/components/utilities/cryptography/crypto";
import encryptSecrets from "@app/components/utilities/secrets/encryptSecrets"; import encryptSecrets from "@app/components/utilities/secrets/encryptSecrets";
import { createSecret } from "@app/hooks/api/secrets/queries"; import { createSecret } from "@app/hooks/api/secrets/queries";
import { fetchUserDetails } from "@app/hooks/api/users/queries";
import { createWorkspace } from "@app/hooks/api/workspace/queries"; import { createWorkspace } from "@app/hooks/api/workspace/queries";
import getUser from "@app/pages/api/user/getUser";
import uploadKeys from "@app/pages/api/workspace/uploadKeys"; import uploadKeys from "@app/pages/api/workspace/uploadKeys";
const secretsToBeAdded = [ const secretsToBeAdded = [
@@ -108,7 +108,7 @@ const initProjectHelper = async ({
if (!PRIVATE_KEY) throw new Error("Failed to find private key"); if (!PRIVATE_KEY) throw new Error("Failed to find private key");
const user = await getUser(); const user = await fetchUserDetails();
const { ciphertext, nonce } = encryptAssymmetric({ const { ciphertext, nonce } = encryptAssymmetric({
plaintext: randomBytes, plaintext: randomBytes,
+4 -2
View File
@@ -3,8 +3,10 @@ export {
useAddUserToOrg, useAddUserToOrg,
useAddUserToWs, useAddUserToWs,
useCreateAPIKey, useCreateAPIKey,
useCreateMyAction,
useDeleteAPIKey, useDeleteAPIKey,
useDeleteOrgMembership, useDeleteOrgMembership,
useGetMyActions,
useGetMyAPIKeys, useGetMyAPIKeys,
useGetMyIp, useGetMyIp,
useGetMySessions, useGetMySessions,
@@ -14,6 +16,6 @@ export {
useLogoutUser, useLogoutUser,
useRegisterUserAction, useRegisterUserAction,
useRevokeMySessions, useRevokeMySessions,
useUpdateMfaEnabled,
useUpdateOrgUserRole, useUpdateOrgUserRole,
useUpdateUserAuthProvider useUpdateUserAuthProvider} from "./queries";
} from "./queries";
+27 -3
View File
@@ -19,7 +19,8 @@ import {
RenameUserDTO, RenameUserDTO,
TokenVersion, TokenVersion,
UpdateOrgUserRoleDTO, UpdateOrgUserRoleDTO,
User} from "./types"; User
} from "./types";
const userKeys = { const userKeys = {
getUser: ["user"] as const, getUser: ["user"] as const,
@@ -27,7 +28,7 @@ const userKeys = {
getOrgUsers: (orgId: string) => [{ orgId }, "user"], getOrgUsers: (orgId: string) => [{ orgId }, "user"],
myIp: ["ip"] as const, myIp: ["ip"] as const,
myAPIKeys: ["api-keys"] as const, myAPIKeys: ["api-keys"] as const,
mySessions: ["sessions"] as const mySessions: ["sessions"] as const,
}; };
export const fetchUserDetails = async () => { export const fetchUserDetails = async () => {
@@ -38,7 +39,7 @@ export const fetchUserDetails = async () => {
export const useGetUser = () => useQuery(userKeys.getUser, fetchUserDetails); export const useGetUser = () => useQuery(userKeys.getUser, fetchUserDetails);
const fetchUserAction = async (action: string) => { export const fetchUserAction = async (action: string) => {
const { data } = await apiRequest.get<{ userAction: string }>("/api/v1/user-action", { const { data } = await apiRequest.get<{ userAction: string }>("/api/v1/user-action", {
params: { params: {
action action
@@ -303,4 +304,27 @@ export const useRevokeMySessions = () => {
queryClient.invalidateQueries(userKeys.mySessions); queryClient.invalidateQueries(userKeys.mySessions);
} }
}); });
}
export const useUpdateMfaEnabled = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
isMfaEnabled
}: {
isMfaEnabled: boolean;
}) => {
const { data: { user } } = await apiRequest.patch(
"/api/v2/users/me/mfa",
{
isMfaEnabled
}
);
return user;
},
onSuccess() {
queryClient.invalidateQueries(userKeys.getUser);
}
});
} }
+1 -1
View File
@@ -9,7 +9,7 @@ export enum AuthProvider {
export type User = { export type User = {
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
email?: string; email: string;
firstName?: string; firstName?: string;
lastName?: string; lastName?: string;
authProvider?: AuthProvider; authProvider?: AuthProvider;
-20
View File
@@ -1,20 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* This route gets the information about a specific user.
*/
const getUser = () =>
SecurityClient.fetchCall("/api/v1/user", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(async (res) => {
if (res?.status === 200) {
return (await res.json()).user;
}
console.log("Failed to get user info");
return undefined;
});
export default getUser;
@@ -1,32 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
interface Props {
isMfaEnabled: boolean;
}
/**
* Update the user's MFA-enabled status to [isMfaEnabled]
* @param {Object} obj
* @param {Boolean} obj.isMfaEnabled - whether or not MFA status should be set to enabled or not
* @returns {User} user - user with updated MFA-enabled status
*/
const updateMyMfaEnabled = async ({
isMfaEnabled
}: Props) =>
SecurityClient.fetchCall("/api/v2/users/me/mfa", {
method: "PATCH",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
isMfaEnabled,
})
}).then(async (res) => {
if (res && res.status === 200) {
return (await res.json()).user;
}
console.log("Failed to update MFA status");
return undefined;
});
export default updateMyMfaEnabled;
@@ -1,29 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* This route registers a certain action for a user
* @param {*} email
* @param {*} workspaceId
* @returns
*/
const checkUserAction = ({ action }: { action: string }) =>
SecurityClient.fetchCall(
"/api/v1/user-action" +
`?${new URLSearchParams({
action
})}`,
{
method: "GET",
headers: {
"Content-Type": "application/json"
}
}
).then(async (res) => {
if (res && res.status === 200) {
return (await res.json()).userAction;
}
console.log("Failed to check a user action");
return undefined;
});
export default checkUserAction;
@@ -1,25 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* This route registers a certain action for a user
* @param {*} action
* @returns
*/
const registerUserAction = ({ action }: { action: string }) =>
SecurityClient.fetchCall("/api/v1/user-action", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
action
})
}).then(async (res) => {
if (res && res.status === 200) {
return res;
}
console.log("Failed to register a user action");
return undefined;
});
export default registerUserAction;
@@ -1,30 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
interface Workspace {
__v: number;
_id: string;
name: string;
organization: string;
environments: Array<{ name: string; slug: string }>;
}
/**
* This route lets us get the workspaces of a certain user
* @returns
*/
const getAWorkspace = (workspaceID: string) =>
SecurityClient.fetchCall(`/api/v1/workspace/${workspaceID}`, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(async (res) => {
if (res?.status === 200) {
const data = (await res.json()) as unknown as { workspace: Workspace };
return data.workspace;
}
throw new Error("Failed to get workspace");
});
export default getAWorkspace;
@@ -1,22 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* This route lets us get the information of a certain project.
* @param {*} projectId - project ID (we renamed workspaces to projects in the app)
* @returns
*/
const getProjectInfo = ({ projectId }: { projectId: string }) =>
SecurityClient.fetchCall(`/api/v1/workspace/${projectId}`, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(async (res) => {
if (res?.status === 200) {
return (await res.json()).workspace;
}
console.log("Failed to get project info");
return undefined;
});
export default getProjectInfo;
@@ -1,22 +0,0 @@
import SecurityClient from "@app/components/utilities/SecurityClient";
/**
* This route lets us get the environments that a certain user has acess to in a certain project
* @param {string} workspaceId
* @returns
*/
const getWorkspaceEnvironments = ({ workspaceId }: { workspaceId: string }) =>
SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/environments`, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(async (res) => {
if (res?.status === 200) {
return (await res.json()).accessibleEnvironments;
}
console.log("Failed to get accessible environments");
return undefined;
});
export default getWorkspaceEnvironments;
+8 -11
View File
@@ -36,11 +36,10 @@ import {
} from "@app/components/v2"; } from "@app/components/v2";
import { TabsObject } from "@app/components/v2/Tabs"; import { TabsObject } from "@app/components/v2/Tabs";
import { useSubscription, useUser, useWorkspace } from "@app/context"; import { useSubscription, useUser, useWorkspace } from "@app/context";
import { fetchOrgUsers, useAddUserToWs, useCreateWorkspace, useUploadWsKey } from "@app/hooks/api"; import { fetchOrgUsers, useAddUserToWs, useCreateWorkspace, useRegisterUserAction,useUploadWsKey } from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
import { encryptAssymmetric } from "../../../../components/utilities/cryptography/crypto"; import { encryptAssymmetric } from "../../../../components/utilities/cryptography/crypto";
import registerUserAction from "../../../api/userActions/registerUserAction";
const features = [ const features = [
{ {
@@ -70,6 +69,7 @@ const LearningItem = ({
userAction, userAction,
link link
}: ItemProps): JSX.Element => { }: ItemProps): JSX.Element => {
const registerUserAction = useRegisterUserAction();
if (link) { if (link) {
return ( return (
<a <a
@@ -89,9 +89,9 @@ const LearningItem = ({
tabIndex={0} tabIndex={0}
onClick={async () => { onClick={async () => {
if (userAction && userAction !== "first_time_secrets_pushed") { if (userAction && userAction !== "first_time_secrets_pushed") {
await registerUserAction({ await registerUserAction.mutateAsync(
action: userAction userAction
}); );
} }
}} }}
className={`group relative flex h-[5.5rem] w-full items-center justify-between overflow-hidden rounded-md border ${ className={`group relative flex h-[5.5rem] w-full items-center justify-between overflow-hidden rounded-md border ${
@@ -130,9 +130,7 @@ const LearningItem = ({
tabIndex={0} tabIndex={0}
onClick={async () => { onClick={async () => {
if (userAction) { if (userAction) {
await registerUserAction({ await registerUserAction.mutateAsync(userAction);
action: userAction
});
} }
}} }}
className="relative my-1.5 flex h-[5.5rem] w-full cursor-pointer items-center justify-between overflow-hidden rounded-md border border-dashed border-bunker-400 bg-bunker-700 py-2 pl-2 pr-6 shadow-xl duration-200 hover:bg-bunker-500" className="relative my-1.5 flex h-[5.5rem] w-full cursor-pointer items-center justify-between overflow-hidden rounded-md border border-dashed border-bunker-400 bg-bunker-700 py-2 pl-2 pr-6 shadow-xl duration-200 hover:bg-bunker-500"
@@ -169,6 +167,7 @@ const LearningItemSquare = ({
userAction, userAction,
link link
}: ItemProps): JSX.Element => { }: ItemProps): JSX.Element => {
const registerUserAction = useRegisterUserAction();
return ( return (
<a <a
target={`${link?.includes("https") ? "_blank" : "_self"}`} target={`${link?.includes("https") ? "_blank" : "_self"}`}
@@ -187,9 +186,7 @@ const LearningItemSquare = ({
tabIndex={0} tabIndex={0}
onClick={async () => { onClick={async () => {
if (userAction && userAction !== "first_time_secrets_pushed") { if (userAction && userAction !== "first_time_secrets_pushed") {
await registerUserAction({ await registerUserAction.mutateAsync(userAction);
action: userAction
});
} }
}} }}
className={`group relative flex w-full items-center justify-between overflow-hidden rounded-md border ${ className={`group relative flex w-full items-center justify-between overflow-hidden rounded-md border ${
@@ -11,14 +11,13 @@ import AddProjectMemberDialog from "@app/components/basic/dialog/AddProjectMembe
import ProjectUsersTable from "@app/components/basic/table/ProjectUsersTable"; import ProjectUsersTable from "@app/components/basic/table/ProjectUsersTable";
import guidGenerator from "@app/components/utilities/randomId"; import guidGenerator from "@app/components/utilities/randomId";
import { Input } from "@app/components/v2"; import { Input } from "@app/components/v2";
import { useGetUser } from "@app/hooks/api";
import { import {
decryptAssymmetric, decryptAssymmetric,
encryptAssymmetric encryptAssymmetric
} from "../../../../components/utilities/cryptography/crypto"; } from "../../../../components/utilities/cryptography/crypto";
import getOrganizationUsers from "../../../api/organization/GetOrgUsers"; import getOrganizationUsers from "../../../api/organization/GetOrgUsers";
import getUser from "../../../api/user/getUser";
// import DeleteUserDialog from '@app/components/basic/dialog/DeleteUserDialog';
import addUserToWorkspace from "../../../api/workspace/addUserToWorkspace"; import addUserToWorkspace from "../../../api/workspace/addUserToWorkspace";
import getWorkspaceUsers from "../../../api/workspace/getWorkspaceUsers"; import getWorkspaceUsers from "../../../api/workspace/getWorkspaceUsers";
import uploadKeys from "../../../api/workspace/uploadKeys"; import uploadKeys from "../../../api/workspace/uploadKeys";
@@ -43,6 +42,7 @@ interface MembershipProps {
// #TODO: Update all the workspaceIds // #TODO: Update all the workspaceIds
export default function Users() { export default function Users() {
const { data: user } = useGetUser();
const [isAddOpen, setIsAddOpen] = useState(false); const [isAddOpen, setIsAddOpen] = useState(false);
// let [isDeleteOpen, setIsDeleteOpen] = useState(false); // let [isDeleteOpen, setIsDeleteOpen] = useState(false);
// let [userIdToBeDeleted, setUserIdToBeDeleted] = useState(false); // let [userIdToBeDeleted, setUserIdToBeDeleted] = useState(false);
@@ -60,46 +60,47 @@ export default function Users() {
const [orgUserList, setOrgUserList] = useState<any[]>([]); const [orgUserList, setOrgUserList] = useState<any[]>([]);
useEffect(() => { useEffect(() => {
(async () => { if (user) {
const user = await getUser(); (async () => {
setPersonalEmail(user.email); setPersonalEmail(user.email);
// This part quiries the current users of a project // This part quiries the current users of a project
const workspaceUsers = await getWorkspaceUsers({ const workspaceUsers = await getWorkspaceUsers({
workspaceId workspaceId
}); });
const tempUserList = workspaceUsers.map((membership: MembershipProps) => ({ const tempUserList = workspaceUsers.map((membership: MembershipProps) => ({
key: guidGenerator(), key: guidGenerator(),
firstName: membership.user?.firstName, firstName: membership.user?.firstName,
lastName: membership.user?.lastName, lastName: membership.user?.lastName,
email: membership.user?.email === null ? membership.inviteEmail : membership.user?.email, email: membership.user?.email === null ? membership.inviteEmail : membership.user?.email,
role: membership?.role, role: membership?.role,
status: membership?.status, status: membership?.status,
userId: membership.user?._id, userId: membership.user?._id,
membershipId: membership._id, membershipId: membership._id,
deniedPermissions: membership.deniedPermissions, deniedPermissions: membership.deniedPermissions,
publicKey: membership.user?.publicKey publicKey: membership.user?.publicKey
})); }));
setUserList(tempUserList); setUserList(tempUserList);
setIsUserListLoading(false); setIsUserListLoading(false);
// This is needed to know wha users from an org (if any), we are able to add to a certain project // This is needed to know wha users from an org (if any), we are able to add to a certain project
const orgUsers = await getOrganizationUsers({ const orgUsers = await getOrganizationUsers({
orgId: String(localStorage.getItem("orgData.id")) orgId: String(localStorage.getItem("orgData.id"))
}); });
setOrgUserList(orgUsers); setOrgUserList(orgUsers);
setEmail( setEmail(
orgUsers orgUsers
?.filter((membership: MembershipProps) => membership.status === "accepted") ?.filter((membership: MembershipProps) => membership.status === "accepted")
.map((membership: MembershipProps) => membership.user.email) .map((membership: MembershipProps) => membership.user.email)
.filter( .filter(
(usEmail: string) => (usEmail: string) =>
!tempUserList?.map((user1: UserProps) => user1.email).includes(usEmail) !tempUserList?.map((user1: UserProps) => user1.email).includes(usEmail)
)[0] )[0]
); );
})(); })();
}, []); }
}, [user]);
const closeAddModal = () => { const closeAddModal = () => {
setIsAddOpen(false); setIsAddOpen(false);
@@ -1,17 +1,14 @@
import { useEffect, useState } from "react";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { Checkbox, EmailServiceSetupModal } from "@app/components/v2"; import { Checkbox, EmailServiceSetupModal } from "@app/components/v2";
import {
useGetUser,
useUpdateMfaEnabled} from "@app/hooks/api";
import { useFetchServerStatus } from "@app/hooks/api/serverDetails"; import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
import { useGetUser } from "../../../../hooks/api";
import { User } from "../../../../hooks/api/types";
import updateMyMfaEnabled from "../../../../pages/api/user/updateMyMfaEnabled";
export const MFASection = () => { export const MFASection = () => {
const [isMfaEnabled, setIsMfaEnabled] = useState(false);
const { data: user } = useGetUser(); const { data: user } = useGetUser();
const { mutateAsync } = useUpdateMfaEnabled();
const { createNotification } = useNotificationContext(); const { createNotification } = useNotificationContext();
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp([ const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp([
"setUpEmail" "setUpEmail"
@@ -19,22 +16,12 @@ export const MFASection = () => {
const {data: serverDetails } = useFetchServerStatus() const {data: serverDetails } = useFetchServerStatus()
useEffect(() => {
if (user && typeof user.isMfaEnabled !== "undefined") {
setIsMfaEnabled(user.isMfaEnabled);
}
}, [user]);
const toggleMfa = async (state: boolean) => { const toggleMfa = async (state: boolean) => {
try { try {
const newUser: User = await updateMyMfaEnabled({ const newUser = await mutateAsync({
isMfaEnabled: state isMfaEnabled: state
}); });
if (newUser) {
setIsMfaEnabled(newUser.isMfaEnabled);
}
createNotification({ createNotification({
text: `${newUser.isMfaEnabled ? "Successfully turned on two-factor authentication." : "Successfully turned off two-factor authentication."}`, text: `${newUser.isMfaEnabled ? "Successfully turned on two-factor authentication." : "Successfully turned off two-factor authentication."}`,
type: "success" type: "success"
@@ -55,20 +42,22 @@ export const MFASection = () => {
<p className="text-xl font-semibold text-mineshaft-100 mb-8"> <p className="text-xl font-semibold text-mineshaft-100 mb-8">
Two-factor Authentication Two-factor Authentication
</p> </p>
<Checkbox {user && (
className="data-[state=checked]:bg-primary" <Checkbox
id="isTwoFAEnabled" className="data-[state=checked]:bg-primary"
isChecked={isMfaEnabled} id="isTwoFAEnabled"
onCheckedChange={(state) => { isChecked={user?.isMfaEnabled}
if (serverDetails?.emailConfigured){ onCheckedChange={(state) => {
toggleMfa(state as boolean); if (serverDetails?.emailConfigured){
} else { toggleMfa(state as boolean);
handlePopUpOpen("setUpEmail"); } else {
} handlePopUpOpen("setUpEmail");
}} }
> }}
Enable 2-factor authentication via your personal email. >
</Checkbox> Enable 2-factor authentication via your personal email.
</Checkbox>
)}
</div> </div>
</form> </form>
<EmailServiceSetupModal <EmailServiceSetupModal