feat: user can check purge drive files when truncate
This commit is contained in:
parent
7ded94a280
commit
39e668bb9f
|
@ -1932,6 +1932,13 @@ _accountDelete:
|
|||
requestAccountDelete: "Request account deletion"
|
||||
started: "Deletion has been started."
|
||||
inProgress: "Deletion is currently in progress"
|
||||
_accountTruncate:
|
||||
accountTruncate: "Truncate account"
|
||||
purgeDriveFiles: "Also purge drive's files"
|
||||
mayTakeTime: "As account deletion is a resource-heavy process, it may take some time to complete depending on how much content you have created and how many files you have uploaded."
|
||||
requestAccountTruncate: "Request to truncate my account"
|
||||
started: "Truncate task has been started."
|
||||
inProgress: "Your account is currently being truncated"
|
||||
_ad:
|
||||
back: "Back"
|
||||
reduceFrequencyOfThisAd: "Show this ad less"
|
||||
|
|
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
|
@ -7537,6 +7537,10 @@ export interface Locale extends ILocale {
|
|||
* アカウントの整理
|
||||
*/
|
||||
"accountDelete": string;
|
||||
/**
|
||||
* ドライブのファイルもすべて消去
|
||||
*/
|
||||
"purgeDriveFiles": string;
|
||||
/**
|
||||
* アカウントの整理は負荷のかかる処理であるため、作成したコンテンツの数やアップロードしたファイルの数が多いと完了までに時間がかかることがあります。
|
||||
*/
|
||||
|
|
|
@ -1962,6 +1962,7 @@ _accountDelete:
|
|||
|
||||
_accountTruncate:
|
||||
accountDelete: "アカウントの整理"
|
||||
purgeDriveFiles: "ドライブのファイルもすべて消去"
|
||||
mayTakeTime: "アカウントの整理は負荷のかかる処理であるため、作成したコンテンツの数やアップロードしたファイルの数が多いと完了までに時間がかかることがあります。"
|
||||
requestAccountTruncate: "アカウント整理をリクエスト"
|
||||
started: "整理処理が開始されました。"
|
||||
|
|
|
@ -995,7 +995,7 @@ followingVisibility: "팔로우 목록의 공개 범위"
|
|||
followersVisibility: "팔로워 목록의 공개 범위"
|
||||
continueThread: "대화 이어서 보기"
|
||||
deleteAccountConfirm: "계정이 삭제되고 복구할 수 없습니다. 그래도 계속하시겠습니까?"
|
||||
truncateAccountConfirm: "다이렉트 및 프로필 상단에 고정된 노트를 제외한 모든 노트와 파일을 제거하고 복구할 수 없습니다. 그래도 계속하시겠습니까?"
|
||||
truncateAccountConfirm: "다이렉트 및 프로필 상단에 고정된 노트를 제외한 모든 노트가 (드라이브 정리 옵션을 켠 경우 모든 파일도) 삭제되고 이는 복구할 수 없습니다. 그래도 계속하시겠습니까?"
|
||||
incorrectPassword: "올바르지 않은 계정 정보입니다."
|
||||
voteConfirm: "\"{choice}\"에 투표하시겠습니까?"
|
||||
hide: "숨기기"
|
||||
|
@ -1944,17 +1944,18 @@ _signup:
|
|||
emailSent: "입력한 메일 주소({email})로 확인 메일을 보내드렸어요! 가입을 완료하려면 보내드린 메일에 있는 링크로 접속해 주세요.\n만약 메일이 오지 않는다면 스팸 메일함을 확인해 주세요!"
|
||||
_accountDelete:
|
||||
accountDelete: "계정 삭제"
|
||||
mayTakeTime: "계정 삭제는 서버에 부하를 가하기 때문에, 작성한 콘텐츠나 업로드한 파일의 수가 많으면 완료까지 시간이 걸릴 수 있어요."
|
||||
sendEmail: "계정 삭제가 완료되면 등록된 메일 주소로 알림을 보내드려요."
|
||||
requestAccountDelete: "계정 삭제 요청"
|
||||
started: "삭제 작업이 시작되었어요."
|
||||
inProgress: "삭제 진행 중"
|
||||
mayTakeTime: "계정 삭제는 서버에 부하를 가하기 때문에, 서버에서 시간을 들여 느리게 처리합니다. 만약 업로드한 컨텐츠가 많으면 시간이 오래 걸릴 수 있습니다."
|
||||
sendEmail: "계정 삭제가 완료되면 등록되어 있는 이메일 주소로 완료 알림을 전송해드립니다."
|
||||
requestAccountDelete: "계정 삭제를 요청하기"
|
||||
started: "계정 삭제가 시작되었습니다. 안녕히 가세요!"
|
||||
inProgress: "삭제 작업이 진행 중입니다..."
|
||||
_accountTruncate:
|
||||
accountTruncate: "계정 청소"
|
||||
mayTakeTime: "계정 청소는 서버에 부하를 가하기 때문에, 작성한 콘텐츠나 업로드한 파일의 수가 많으면 완료까지 시간이 걸릴 수 있습니다."
|
||||
requestAccountTruncate: "계정 청소 요청"
|
||||
purgeDriveFiles: "드라이브의 파일도 정리하기"
|
||||
mayTakeTime: "계정 청소는 서버에 부하를 가하기 때문에, 서버에서 시간을 들여 느리게 처리합니다. 만약 업로드한 컨텐츠가 많으면 시간이 오래 걸릴 수 있습니다."
|
||||
requestAccountTruncate: "계정 청소를 요청하기"
|
||||
started: "청소 작업이 시작되었습니다."
|
||||
inProgress: "청소 진행 중"
|
||||
inProgress: "청소 작업이 진행 중입니다..."
|
||||
_ad:
|
||||
back: "뒤로"
|
||||
reduceFrequencyOfThisAd: "이 광고의 표시 빈도 낮추기"
|
||||
|
|
|
@ -367,9 +367,10 @@ export class QueueService {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
public createTruncateAccountJob(user: ThinUser, opts = {}) {
|
||||
public createTruncateAccountJob(user: ThinUser, purgeDrive: boolean, opts = {}) {
|
||||
return this.dbQueue.add('truncateAccount', {
|
||||
user: { id: user.id },
|
||||
purgeDrive: purgeDrive,
|
||||
}, {
|
||||
removeOnComplete: true,
|
||||
removeOnFail: true,
|
||||
|
|
|
@ -23,10 +23,10 @@ export class TruncateAccountService {
|
|||
public async truncateAccount(user: {
|
||||
id: string;
|
||||
host: string | null;
|
||||
}): Promise<void> {
|
||||
}, purgeDrive: boolean | false): Promise<void> {
|
||||
const _user = await this.usersRepository.findOneByOrFail({ id: user.id });
|
||||
|
||||
this.queueService.createTruncateAccountJob(user, {
|
||||
this.queueService.createTruncateAccountJob(user, purgeDrive, {
|
||||
soft: false,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ export class TruncateAccountProcessorService {
|
|||
|
||||
@bindThis
|
||||
public async process(job: Bull.Job<DbUserTruncateJobData>): Promise<string | void> {
|
||||
this.logger.info(`Truncate notes and drives account of ${job.data.user.id} ...`);
|
||||
this.logger.info(`Truncate account of ${job.data.user.id} ...`);
|
||||
|
||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||
if (user == null) {
|
||||
|
@ -98,7 +98,7 @@ export class TruncateAccountProcessorService {
|
|||
this.logger.succ('All of notes deleted');
|
||||
}
|
||||
|
||||
{ // Delete files
|
||||
if (job.data.purgeDrive) { // Delete files
|
||||
let cursor: MiDriveFile['id'] | null = null;
|
||||
|
||||
while (true) {
|
||||
|
@ -124,13 +124,13 @@ export class TruncateAccountProcessorService {
|
|||
cursor = files.at(-1)?.id ?? null;
|
||||
|
||||
for (const file of files) {
|
||||
await this.driveService.deleteFileSync(file);
|
||||
await this.driveService.deleteFileSync(file, false, false, user);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.succ('All of files deleted');
|
||||
}
|
||||
|
||||
return 'Account notes and drives are truncated';
|
||||
return 'Account truncate job completed';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ export type DbUserDeleteJobData = {
|
|||
|
||||
export type DbUserTruncateJobData = {
|
||||
user: ThinUser;
|
||||
purgeDrive: boolean;
|
||||
};
|
||||
|
||||
export type DbUserImportJobData = {
|
||||
|
|
|
@ -79,7 +79,7 @@ export class StreamingApiServerService {
|
|||
if (e instanceof AuthenticationError) {
|
||||
socket.write([
|
||||
'HTTP/1.1 401 Unauthorized',
|
||||
'WWW-Authenticate: Bearer realm="CherryPick", error="invalid_token", error_description="Failed to authenticate"',
|
||||
'WWW-Authenticate: Bearer realm="LycheeBridge", error="invalid_token", error_description="Failed to authenticate"',
|
||||
].join('\r\n') + '\r\n\r\n');
|
||||
} else {
|
||||
socket.write('HTTP/1.1 500 Internal Server Error\r\n\r\n');
|
||||
|
|
|
@ -22,6 +22,7 @@ export const paramDef = {
|
|||
properties: {
|
||||
password: { type: 'string' },
|
||||
token: { type: 'string', nullable: true },
|
||||
purgeDrive: { type: 'boolean', nullable: true },
|
||||
},
|
||||
required: ['password'],
|
||||
} as const;
|
||||
|
@ -40,6 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const token = ps.token;
|
||||
const purgeDrive = ps.purgeDrive ? true : false;
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: me.id });
|
||||
|
||||
if (profile.twoFactorEnabled) {
|
||||
|
@ -64,7 +66,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
throw new Error('incorrect password');
|
||||
}
|
||||
|
||||
await this.truncateAccountService.truncateAccount(me);
|
||||
await this.truncateAccountService.truncateAccount(me, purgeDrive);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<div class="_gaps_m">
|
||||
<FormInfo warn>{{ i18n.ts._accountTruncate.mayTakeTime }}</FormInfo>
|
||||
<MkSwitch v-model="purgeDrive">
|
||||
<template #label>{{ i18n.ts._accountTruncate.purgeDriveFiles }}</template>
|
||||
</MkSwitch>
|
||||
<MkButton v-if="!$i.isDeleted" danger @click="truncateAccount">{{ i18n.ts._accountTruncate.requestAccountTruncate }}</MkButton>
|
||||
<MkButton v-else disabled>{{ i18n.ts._accountTruncate.inProgress }}</MkButton>
|
||||
</div>
|
||||
|
@ -98,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormLink from '@/components/form/link.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
|
@ -117,6 +120,7 @@ import { globalEvents } from '@/events.js';
|
|||
|
||||
const $i = signinRequired();
|
||||
|
||||
const purgeDrive = ref<boolean>(false);
|
||||
const reportError = computed(defaultStore.makeGetterSetter('reportError'));
|
||||
const enableCondensedLineForAcct = computed(defaultStore.makeGetterSetter('enableCondensedLineForAcct'));
|
||||
const devMode = computed(defaultStore.makeGetterSetter('devMode'));
|
||||
|
@ -161,6 +165,7 @@ async function truncateAccount() {
|
|||
await os.apiWithDialog('i/truncate-account', {
|
||||
password: auth.result.password,
|
||||
token: auth.result.token,
|
||||
purgeDrive: purgeDrive.value,
|
||||
});
|
||||
|
||||
await os.alert({
|
||||
|
|
Loading…
Reference in a new issue