-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* style(ms2/signin): shift signin modal up * style(ms2/signin): sign in as guest * style(ms2/signin): changed sorting of providers * style(ms2/signin): new layout * style(ms2/signin): continue in as guest * style(ms2/signin) * style(ms2): changed info color to gray * feat(ms2): show guests a warning * typos * feat(ms2): show new guests modal for creating process * lint * fix: missing dependency * feat(ms2): update email if user is signed in and is verifying email * feat(ms2/profile): modal to change email * feat(ms2): verificationToken store * fix(ms2/signin): remove dangerous sign in code * feat(ms2): verificationToken server actions * feat(ms2/profile): request email change * feat(ms2/change-email): page for confirming email change * refactor(ms2): moved signin-email template to lib/email * refactor(ms2/signin-link-email): changed parameter format * feat(ms2/profile): close modal after email change request * feat(ms2/change-email): send change email link * style(ms2/change-email): better feedback * feat(ms2/change-email): cancel email change * fix(ms2/e2e-tests): sign in as guest * fix(ms2/signin): use callbackUrl if there is one * fix(ms2/e2e-tests): use new sign in * fix(ms2/signin): check if verification request before this if a guest tries to sign in to a email, his email was automatically updated to the email he submitted, without him having to get the email. * fix(ms2/environments): remove folders when removing environment * feat(ms2/users): update guest users * feat(ms2/folders): get all folders * feat(ms2/folder): move folders to other environments * feat(ms2/processes): get processes without ability * typo * feat(ms2): transfer guest processes to account * fix(ms2/signin): allow guests to sign in to dev users * refactor(ms2): get processes takes in an spaceId and an ability This change was needed, because the function was redundant and was implemented in a way that caused it to fail. It is redundant to use a userId and an ability, because both tell you for which user we're supposed to get the processes. And it fails because, it returns the processes where the creator was the user, this is wrong, because it doesn't take into consideration abilities. For me is better that the function takes in a spaceId, and returns all processes for a spaceId, and if you want to get the processes for a user you can provide his ability. * fix: merge conflict * feat(ms2/DTOs): updateProcess, moveFolder, updateFolderMetaData * refactor(ms2/transfer-processes): now works with JWT for passing the guestId * ms2: type fix * fix(ms2/user): type fix + only allow users to update their data if they aren't guests * typo * fix: added key * fix: typo in filename * fix(ms2/process-transfer-page): combined buttons + changed invalid token message * fix: import from DTOs --------- Co-authored-by: Kai Rohwer <[email protected]>
- Loading branch information
1 parent
0d81afe
commit 93517e2
Showing
20 changed files
with
386 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { getCurrentUser } from '@/components/auth'; | ||
import Content from '@/components/content'; | ||
import { getProcesses, getUserById } from '@/lib/data/DTOs'; | ||
import { Card, Result } from 'antd'; | ||
import { redirect } from 'next/navigation'; | ||
import ProcessTransferButtons from './transfer-processes-confirmation-buttons'; | ||
import { getGuestReference } from '@/lib/reference-guest-user-token'; | ||
|
||
export default async function TransferProcessesPage({ | ||
searchParams, | ||
}: { | ||
searchParams: { | ||
callbackUrl?: string; | ||
referenceToken?: string; | ||
}; | ||
}) { | ||
const { userId, session } = await getCurrentUser(); | ||
if (!session) redirect('api/auth/signin'); | ||
if (session.user.isGuest) redirect('/'); | ||
|
||
const callbackUrl = decodeURIComponent(searchParams.callbackUrl || '/'); | ||
|
||
const token = decodeURIComponent(searchParams.referenceToken || ''); | ||
const referenceToken = getGuestReference(token); | ||
if ('error' in referenceToken) { | ||
let message = 'Invalid link'; | ||
if (referenceToken.error === 'TokenExpiredError') message = 'Link expired'; | ||
|
||
return ( | ||
<Content title="Transfer Processes"> | ||
<Result | ||
status="error" | ||
title={message} | ||
subTitle="If you want to transfer the processes from your guest account, you need to sign in with your email from your guest account again." | ||
/> | ||
</Content> | ||
); | ||
} | ||
const guestId = referenceToken.guestId; | ||
|
||
// guestId === userId if the user signed in with a non existing account, and the guest user was | ||
// turned into an authenticated user | ||
if (!guestId || guestId === userId) redirect(callbackUrl); | ||
|
||
const possibleGuest = await getUserById(guestId); | ||
// possibleGuest might be a normal user, this would happen if the user signed in with an existing | ||
// accocunt, generating the token above, and before using it, he signed in with a new account. | ||
// We only go further then this redirect, if the user signed in with an account that was | ||
// already linked to an existing user | ||
if (!possibleGuest || !possibleGuest.isGuest) redirect(callbackUrl); | ||
|
||
// NOTE: this ignores folders | ||
const guestProcesses = await getProcesses(guestId); | ||
|
||
// If the guest has no processes -> nothing to do | ||
if (guestProcesses.length === 0) redirect(callbackUrl); | ||
|
||
return ( | ||
<Content title="Transfer Processes"> | ||
<Card | ||
title="Would you like to transfer your processes?" | ||
style={{ maxWidth: '70ch', margin: 'auto' }} | ||
> | ||
Your guest account had {guestProcesses.length} process{guestProcesses.length !== 1 && 'es'}. | ||
<br /> | ||
Would you like to transfer them to your account? | ||
<ProcessTransferButtons referenceToken={token} callbackUrl={callbackUrl} /> | ||
</Card> | ||
</Content> | ||
); | ||
} |
88 changes: 88 additions & 0 deletions
88
src/management-system-v2/app/transfer-processes/server-actions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
'use server'; | ||
|
||
import { getCurrentUser } from '@/components/auth'; | ||
import { Folder } from '@/lib/data/folder-schema'; | ||
import { | ||
getProcesses, | ||
getFolders, | ||
getRootFolder, | ||
moveFolder, | ||
updateFolderMetaData, | ||
updateProcess, | ||
getUserById, | ||
deleteUser, | ||
} from '@/lib/data/DTOs'; | ||
import { Process } from '@/lib/data/process-schema'; | ||
import { getGuestReference } from '@/lib/reference-guest-user-token'; | ||
import { UserErrorType, userError } from '@/lib/user-error'; | ||
import { redirect } from 'next/navigation'; | ||
|
||
export async function transferProcesses(referenceToken: string, callbackUrl: string = '/') { | ||
const { session } = await getCurrentUser(); | ||
if (!session) return userError("You're not signed in", UserErrorType.PermissionError); | ||
if (session.user.isGuest) | ||
return userError("You can't be a guest to transfer processes", UserErrorType.PermissionError); | ||
|
||
const reference = getGuestReference(referenceToken); | ||
if ('error' in reference) return userError(reference.error); | ||
const guestId = reference.guestId; | ||
|
||
if (guestId === session.user.id) redirect(callbackUrl); | ||
|
||
const possibleGuest = await getUserById(guestId); | ||
if (!possibleGuest || !possibleGuest.isGuest) | ||
return userError('Invalid guest id', UserErrorType.PermissionError); | ||
|
||
// Processes and folders under root folder of guest space guet their folderId changed to the | ||
// root folder of the new owner space, for the rest we just update the environmentId | ||
const userRootFolderId = (await getRootFolder(session.user.id)).id; | ||
const guestRootFolderId = (await getRootFolder(guestId)).id; | ||
|
||
// no ability check necessary, owners of personal spaces can do anything | ||
const guestProcesses = await getProcesses(guestId); | ||
for (const process of guestProcesses) { | ||
const processUpdate: Partial<Process> = { | ||
environmentId: session.user.id, | ||
creatorId: session.user.id, | ||
}; | ||
if (process.folderId === guestRootFolderId) processUpdate.folderId = userRootFolderId; | ||
await updateProcess(process.id, processUpdate); | ||
} | ||
|
||
const guestFolders = await getFolders(guestId); | ||
for (const folder of guestFolders) { | ||
if (folder.id === guestRootFolderId) continue; | ||
|
||
const folderData: Partial<Folder> = { createdBy: session.user.id }; | ||
|
||
if (folder.parentId === guestRootFolderId) moveFolder(folder.id, userRootFolderId); | ||
else folderData.environmentId = session.user.id; | ||
|
||
updateFolderMetaData(folder.id, folderData); | ||
} | ||
|
||
deleteUser(guestId); | ||
|
||
redirect(callbackUrl); | ||
} | ||
|
||
export async function discardProcesses(referenceToken: string, redirectUrl: string = '/') { | ||
const { session } = await getCurrentUser(); | ||
if (!session) return userError("You're not signed in", UserErrorType.PermissionError); | ||
if (session.user.isGuest) | ||
return userError("You can't be a guest to transfer processes", UserErrorType.PermissionError); | ||
|
||
const reference = getGuestReference(referenceToken); | ||
if ('error' in reference) return userError(reference.error); | ||
const guestId = reference.guestId; | ||
|
||
if (guestId === session.user.id) redirect(redirectUrl); | ||
|
||
const possibleGuest = await getUserById(guestId); | ||
if (!possibleGuest || !possibleGuest.isGuest) | ||
return userError('Invalid guest id', UserErrorType.PermissionError); | ||
|
||
deleteUser(guestId); | ||
|
||
redirect(redirectUrl); | ||
} |
47 changes: 47 additions & 0 deletions
47
src/management-system-v2/app/transfer-processes/transfer-processes-confirmation-buttons.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
'use client'; | ||
|
||
import { Space, Button } from 'antd'; | ||
import { ReactNode, useTransition } from 'react'; | ||
import { | ||
transferProcesses as serverTransferProcesses, | ||
discardProcesses as serverDiscardProcesses, | ||
} from './server-actions'; | ||
|
||
export default function ProcessTransferButtons({ | ||
referenceToken, | ||
callbackUrl, | ||
}: { | ||
referenceToken: string; | ||
callbackUrl?: string; | ||
children?: ReactNode; | ||
}) { | ||
const [discardingProcesses, startDiscardingProcesses] = useTransition(); | ||
function discardProcesses() { | ||
startDiscardingProcesses(async () => { | ||
await serverDiscardProcesses(referenceToken, callbackUrl); | ||
}); | ||
} | ||
|
||
const [transferring, startTransfer] = useTransition(); | ||
function transferProcesses() { | ||
startTransfer(async () => { | ||
await serverTransferProcesses(referenceToken, callbackUrl); | ||
}); | ||
} | ||
|
||
return ( | ||
<Space style={{ width: '100%', justifyContent: 'right' }}> | ||
<Button onClick={discardProcesses} loading={discardingProcesses} disabled={transferring}> | ||
No | ||
</Button> | ||
<Button | ||
type="primary" | ||
onClick={transferProcesses} | ||
loading={transferring} | ||
disabled={discardingProcesses} | ||
> | ||
Yes | ||
</Button> | ||
</Space> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.