enhance: Improve account deletion experience
This commit is contained in:
parent
fd1ef4a62d
commit
a53e1e4ec3
5 changed files with 88 additions and 19 deletions
|
@ -779,6 +779,14 @@ translate: "翻訳"
|
||||||
translatedFrom: "{x}から翻訳"
|
translatedFrom: "{x}から翻訳"
|
||||||
accountDeletionInProgress: "アカウントの削除が進行中です"
|
accountDeletionInProgress: "アカウントの削除が進行中です"
|
||||||
|
|
||||||
|
_accountDelete:
|
||||||
|
accountDelete: "アカウントの削除"
|
||||||
|
mayTakeTime: "アカウントの削除は負荷のかかる処理であるため、作成したコンテンツの数やアップロードしたファイルの数が多いと完了までに時間がかかることがあります。"
|
||||||
|
sendEmail: "アカウントの削除が完了する際は、登録してあったメールアドレス宛に通知を送信します。"
|
||||||
|
requestAccountDelete: "アカウント削除をリクエスト"
|
||||||
|
started: "削除処理が開始されました。"
|
||||||
|
inProgress: "削除が進行中"
|
||||||
|
|
||||||
_docs:
|
_docs:
|
||||||
continueReading: "続きを読む"
|
continueReading: "続きを読む"
|
||||||
features: "機能"
|
features: "機能"
|
||||||
|
|
67
src/client/pages/settings/delete-account.vue
Normal file
67
src/client/pages/settings/delete-account.vue
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<template>
|
||||||
|
<FormBase>
|
||||||
|
<FormInfo warn>{{ $ts._accountDelete.mayTakeTime }}</FormInfo>
|
||||||
|
<FormInfo>{{ $ts._accountDelete.sendEmail }}</FormInfo>
|
||||||
|
<FormButton @click="deleteAccount" danger v-if="!$i.isDeleted">{{ $ts._accountDelete.requestAccountDelete }}</FormButton>
|
||||||
|
<FormButton disabled v-else>{{ $ts._accountDelete.inProgress }}</FormButton>
|
||||||
|
</FormBase>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||||
|
import FormInfo from '@client/components/form/info.vue';
|
||||||
|
import FormBase from '@client/components/form/base.vue';
|
||||||
|
import FormGroup from '@client/components/form/group.vue';
|
||||||
|
import FormButton from '@client/components/form/button.vue';
|
||||||
|
import * as os from '@client/os';
|
||||||
|
import { debug } from '@client/config';
|
||||||
|
import { signout } from '@client/account';
|
||||||
|
import * as symbols from '@client/symbols';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
FormBase,
|
||||||
|
FormButton,
|
||||||
|
FormGroup,
|
||||||
|
FormInfo,
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['info'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
[symbols.PAGE_INFO]: {
|
||||||
|
title: this.$ts._accountDelete.accountDelete,
|
||||||
|
icon: 'fas fa-exclamation-triangle'
|
||||||
|
},
|
||||||
|
debug,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.$emit('info', this[symbols.PAGE_INFO]);
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async deleteAccount() {
|
||||||
|
const { canceled, result: password } = await os.dialog({
|
||||||
|
title: this.$ts.password,
|
||||||
|
input: {
|
||||||
|
type: 'password'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
await os.apiWithDialog('i/delete-account', {
|
||||||
|
password: password
|
||||||
|
});
|
||||||
|
|
||||||
|
await os.dialog({
|
||||||
|
title: this.$ts._accountDelete.started,
|
||||||
|
});
|
||||||
|
|
||||||
|
signout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -132,6 +132,7 @@ export default defineComponent({
|
||||||
case 'account-info': return defineAsyncComponent(() => import('./account-info.vue'));
|
case 'account-info': return defineAsyncComponent(() => import('./account-info.vue'));
|
||||||
case 'update': return defineAsyncComponent(() => import('./update.vue'));
|
case 'update': return defineAsyncComponent(() => import('./update.vue'));
|
||||||
case 'registry': return defineAsyncComponent(() => import('./registry.vue'));
|
case 'registry': return defineAsyncComponent(() => import('./registry.vue'));
|
||||||
|
case 'delete-account': return defineAsyncComponent(() => import('./delete-account.vue'));
|
||||||
case 'experimental-features': return defineAsyncComponent(() => import('./experimental-features.vue'));
|
case 'experimental-features': return defineAsyncComponent(() => import('./experimental-features.vue'));
|
||||||
}
|
}
|
||||||
if (page.value.startsWith('registry/keys/system/')) {
|
if (page.value.startsWith('registry/keys/system/')) {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<FormLink to="/bios" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>BIOS</FormLink>
|
<FormLink to="/bios" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>BIOS</FormLink>
|
||||||
<FormLink to="/cli" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>CLI</FormLink>
|
<FormLink to="/cli" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>CLI</FormLink>
|
||||||
|
|
||||||
<FormButton @click="closeAccount" danger>{{ $ts.closeAccount }}</FormButton>
|
<FormLink to="./delete-account"><template #icon><i class="fas fa-exclamation-triangle"></i></template>{{ $ts.closeAccount }}</FormLink>
|
||||||
</FormBase>
|
</FormBase>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -41,7 +41,6 @@ import FormButton from '@client/components/form/button.vue';
|
||||||
import * as os from '@client/os';
|
import * as os from '@client/os';
|
||||||
import { debug } from '@client/config';
|
import { debug } from '@client/config';
|
||||||
import { defaultStore } from '@client/store';
|
import { defaultStore } from '@client/store';
|
||||||
import { signout } from '@client/account';
|
|
||||||
import { unisonReload } from '@client/scripts/unison-reload';
|
import { unisonReload } from '@client/scripts/unison-reload';
|
||||||
import * as symbols from '@client/symbols';
|
import * as symbols from '@client/symbols';
|
||||||
|
|
||||||
|
@ -92,22 +91,6 @@ export default defineComponent({
|
||||||
os.popup(import('@client/components/taskmanager.vue'), {
|
os.popup(import('@client/components/taskmanager.vue'), {
|
||||||
}, {}, 'closed');
|
}, {}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
closeAccount() {
|
|
||||||
os.dialog({
|
|
||||||
title: this.$ts.password,
|
|
||||||
input: {
|
|
||||||
type: 'password'
|
|
||||||
}
|
|
||||||
}).then(({ canceled, result: password }) => {
|
|
||||||
if (canceled) return;
|
|
||||||
os.api('i/delete-account', {
|
|
||||||
password: password
|
|
||||||
}).then(() => {
|
|
||||||
signout();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import * as Bull from 'bull';
|
import * as Bull from 'bull';
|
||||||
import { queueLogger } from '../../logger';
|
import { queueLogger } from '../../logger';
|
||||||
import { DriveFiles, Notes, Users } from '@/models/index';
|
import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index';
|
||||||
import { DbUserJobData } from '@/queue/types';
|
import { DbUserJobData } from '@/queue/types';
|
||||||
import { Note } from '@/models/entities/note';
|
import { Note } from '@/models/entities/note';
|
||||||
import { DriveFile } from '@/models/entities/drive-file';
|
import { DriveFile } from '@/models/entities/drive-file';
|
||||||
import { MoreThan } from 'typeorm';
|
import { MoreThan } from 'typeorm';
|
||||||
import { deleteFileSync } from '@/services/drive/delete-file';
|
import { deleteFileSync } from '@/services/drive/delete-file';
|
||||||
|
import { sendEmail } from '@/services/send-email';
|
||||||
|
|
||||||
const logger = queueLogger.createSubLogger('delete-account');
|
const logger = queueLogger.createSubLogger('delete-account');
|
||||||
|
|
||||||
|
@ -73,6 +74,15 @@ export async function deleteAccount(job: Bull.Job<DbUserJobData>): Promise<strin
|
||||||
logger.succ(`All of files deleted`);
|
logger.succ(`All of files deleted`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // Send email notification
|
||||||
|
const profile = await UserProfiles.findOneOrFail(user.id);
|
||||||
|
if (profile.email && profile.emailVerified) {
|
||||||
|
sendEmail(profile.email, 'Account deleted',
|
||||||
|
`Your account has been deleted.`,
|
||||||
|
`Your account has been deleted.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await Users.delete(job.data.user.id);
|
await Users.delete(job.data.user.id);
|
||||||
|
|
||||||
return 'Account deleted';
|
return 'Account deleted';
|
||||||
|
|
Loading…
Reference in a new issue