Skip to content

Commit

Permalink
finished email verification changes
Browse files Browse the repository at this point in the history
  • Loading branch information
AlekEagle committed Nov 15, 2023
1 parent 09feda7 commit d31e8d6
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 18 deletions.
9 changes: 9 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ export const router = createRouter({
name: 'account-switcher',
component: () => import('@/views/AccountSwitcher.vue'),
},
// Email Verification page route
{
path: '/verify',
name: 'verify',
component: () => import('@/views/user-space/Verify.vue'),
meta: {
requiresAuth: true,
},
},
// User space routes
{
path: '/dashboard',
Expand Down
58 changes: 56 additions & 2 deletions src/stores/staff-space/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,57 @@ export const otherUserStore = defineStore('staff-space-user', () => {
return true;
}

async function verifyEmail() {
if (user.client === null) return false;
errored.value = false;
loading.value = true;
try {
await user.client!.verifyEmail(data.value!.id);
return true;
} catch (error) {
errored.value = true;
if (error instanceof Cumulonimbus.ResponseError) {
return error;
} else throw error;
} finally {
loading.value = false;
}
}

async function unverifyEmail() {
if (user.client === null) return false;
errored.value = false;
loading.value = true;
try {
await user.client!.unverifyEmail(data.value!.id);
return true;
} catch (error) {
errored.value = true;
if (error instanceof Cumulonimbus.ResponseError) {
return error;
} else throw error;
} finally {
loading.value = false;
}
}

async function resendVerificationEmail() {
if (user.client === null) return false;
errored.value = false;
loading.value = true;
try {
await user.client!.resendVerificationEmail(data.value!.id);
return true;
} catch (error) {
errored.value = true;
if (error instanceof Cumulonimbus.ResponseError) {
return error;
} else throw error;
} finally {
loading.value = false;
}
}

async function updatePassword(password: string, confirmPassword: string) {
if (user.client === null) return false;
errored.value = false;
Expand Down Expand Up @@ -168,12 +219,12 @@ export const otherUserStore = defineStore('staff-space-user', () => {
return true;
}

async function banUser() {
async function banUser(reason: string) {
if (user.client === null) return false;
errored.value = false;
loading.value = true;
try {
const result = await user.client!.banUser(data.value!.id);
const result = await user.client!.banUser(data.value!.id, reason);
data.value = result.result;
} catch (error) {
errored.value = true;
Expand Down Expand Up @@ -272,6 +323,9 @@ export const otherUserStore = defineStore('staff-space-user', () => {
getUser,
updateUsername,
updateEmail,
verifyEmail,
unverifyEmail,
resendVerificationEmail,
updatePassword,
updateDomain,
grantStaff,
Expand Down
50 changes: 50 additions & 0 deletions src/stores/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,54 @@ export const userStore = defineStore('user', () => {
}
}

// Verify the email of the current account.
async function verifyEmail(
token: string,
): Promise<boolean | Cumulonimbus.ResponseError> {
// Set the loading state.
loading.value = true;
// Try to verify the email.
try {
// Verify the email.
await client.value!.verifyEmail('me', token);
// If nothing went wrong:
// Return true to signify success.
return true;
} catch (error) {
// If an error occurred, and it's a Cumulonimbus ResponseError, return it.
if (error instanceof Cumulonimbus.ResponseError) return error;
// Otherwise, throw the error.
throw error;
} finally {
// Reset the loading state.
loading.value = false;
}
}

// Resend the verification email of the current account.
async function resendVerificationEmail(): Promise<
boolean | Cumulonimbus.ResponseError
> {
// Set the loading state.
loading.value = true;
// Try to resend the verification email.
try {
// Resend the verification email.
await client.value!.resendVerificationEmail();
// If nothing went wrong:
// Return true to signify success.
return true;
} catch (error) {
// If an error occurred, and it's a Cumulonimbus ResponseError, return it.
if (error instanceof Cumulonimbus.ResponseError) return error;
// Otherwise, throw the error.
throw error;
} finally {
// Reset the loading state.
loading.value = false;
}
}

// Change the password of the current account.
async function changePassword(
newPassword: string,
Expand Down Expand Up @@ -613,6 +661,8 @@ export const userStore = defineStore('user', () => {
switchAccount,
changeUsername,
changeEmail,
verifyEmail,
resendVerificationEmail,
changePassword,
changeDomain,
revokeSessions,
Expand Down
19 changes: 12 additions & 7 deletions src/views/AccountSwitcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@
<p v-if="token === false && !managingAccounts">Not logged in.</p>
<p v-if="managingAccounts">Click to remove this account.</p>
</div>
<div
v-if="Object.keys(user.accounts).length < 1"
class="account-switcher-account"
>
<img :src="profileIcon" alt="Generic account icon" />
<p>Nobody here but us chickens!</p>
<p>Click the "Add Account" button to add an account.</p>
</div>
<div
v-if="!managingAccounts"
:class="`account-switcher-account${user.loading ? ' disabled' : ''}`"
Expand Down Expand Up @@ -188,13 +196,7 @@
}
}
toast.show('All accounts removed.');
router.replace({
path: '/auth',
query: {
redirect: redirectLoc.value,
},
hash: '#login',
});
managingAccounts.value = false;
}
}
Expand All @@ -206,6 +208,9 @@
if (res === true) {
toast.show('Account removed.');
selectedAccount.value = null;
if (Object.keys(user.accounts).length < 1) {
managingAccounts.value = false;
}
removeAccountModal.value?.hide();
} else {
console.error(res);
Expand Down
85 changes: 76 additions & 9 deletions src/views/staff-space/User.vue
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@
>'s email.
</p>
</ContentBox>
<ContentBox
title="Toggle Verified Status"
:src="gearIcon"
theme-safe
@click="changeVerifiedModal!.show()"
>
<p>
Toggle <code>{{ otherUser.data.username }}</code
>'s verified status.
</p>
</ContentBox>
<ContentBox
title="Change Password"
:src="gearIcon"
Expand Down Expand Up @@ -220,6 +231,19 @@
:disabled="otherUser.loading"
/>
</FormModal>
<ConfirmModal
ref="changeVerifiedModal"
title="Change Verified Status"
@submit="updateVerified"
:disabled="otherUser.loading"
>
<p>
Are you sure you want to
{{ otherUser.data?.verifiedAt ? 'unverify' : 'verify' }}
<code>{{ otherUser.data?.username }}</code
>?
</p>
</ConfirmModal>
<FormModal
ref="changePasswordModal"
title="Change Password"
Expand Down Expand Up @@ -261,7 +285,7 @@
<code>{{ otherUser.data?.username }}</code> staff status?
</p>
</ConfirmModal>
<ConfirmModal
<FormModal
ref="changeBanModal"
title="Change Ban Status"
@submit="updateBan"
Expand All @@ -273,7 +297,13 @@
<code>{{ otherUser.data?.username }}</code
>?
</p>
</ConfirmModal>
<textarea
v-if="!otherUser.data?.bannedAt"
name="reason"
placeholder="Provide your reasoning..."
required
/>
</FormModal>
<ConfirmModal
ref="signOutModal"
title="Sign User Out Everywhere"
Expand Down Expand Up @@ -341,10 +371,11 @@
online = useOnline(),
changeUsernameModal = ref<typeof FormModal>(),
changeEmailModal = ref<typeof FormModal>(),
changeVerifiedModal = ref<typeof ConfirmModal>(),
changePasswordModal = ref<typeof FormModal>(),
changeDomainModal = ref<typeof DomainModal>(),
changeStaffModal = ref<typeof ConfirmModal>(),
changeBanModal = ref<typeof ConfirmModal>(),
changeBanModal = ref<typeof FormModal>(),
signOutModal = ref<typeof ConfirmModal>(),
deleteUserFilesModal = ref<typeof ConfirmModal>(),
deleteUserModal = ref<typeof ConfirmModal>();
Expand Down Expand Up @@ -453,6 +484,46 @@
}
}
async function updateVerified(choice: boolean) {
if (!online.value) {
toast.connectivityOffline();
return;
}
if (!choice) {
changeVerifiedModal.value!.hide();
return;
}
try {
const status = otherUser.data?.verifiedAt
? await otherUser.unverifyEmail()
: await otherUser.verifyEmail();
if (status instanceof Cumulonimbus.ResponseError) {
const handled = await defaultErrorHandler(status, router);
if (!handled) {
switch (status.code) {
case 'EMAIL_ALREADY_VERIFIED_ERROR':
toast.show('This email is already verified.');
break;
case 'EMAIL_NOT_VERIFIED_ERROR':
toast.show('This email is not verified.');
break;
case 'INVALID_USER_ERROR':
toast.show('This user does not exist.');
backWithFallback(router, '/staff/users', true);
}
}
} else if (!status) {
toast.clientError();
} else {
toast.show('Verified status updated.');
changeVerifiedModal.value!.hide();
}
} catch (error) {
toast.clientError();
console.error(error);
}
}
async function updatePassword(data: { password: string; confirm: string }) {
if (!online.value) {
toast.connectivityOffline();
Expand Down Expand Up @@ -557,19 +628,15 @@
}
}
async function updateBan(choice: boolean) {
async function updateBan(data: { reason: string }) {
if (!online.value) {
toast.connectivityOffline();
return;
}
if (!choice) {
changeBanModal.value!.hide();
return;
}
try {
const status = otherUser.data?.bannedAt
? await otherUser.unbanUser()
: await otherUser.banUser();
: await otherUser.banUser(data.reason);
if (status instanceof Cumulonimbus.ResponseError) {
const handled = await defaultErrorHandler(status, router);
if (!handled) {
Expand Down
Loading

0 comments on commit d31e8d6

Please sign in to comment.