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…
	
	Add table
		Add a link
		
	
		Reference in a new issue