Merge branch 'develop' into swn

This commit is contained in:
tamaina 2021-09-22 22:00:50 +09:00
commit 0563fa6f56
11 changed files with 357 additions and 323 deletions

View file

@ -90,7 +90,26 @@ export const menuDef = {
title: 'antennas',
icon: 'fas fa-satellite',
show: computed(() => $i != null),
to: '/my/antennas',
active: computed(() => router.currentRoute.value.path.startsWith('/timeline/antenna/') || router.currentRoute.value.path === '/my/antennas' || router.currentRoute.value.path.startsWith('/my/antennas/')),
action: (ev) => {
const items = ref([{
type: 'pending'
}]);
os.api('antennas/list').then(antennas => {
const _items = [...antennas.map(antenna => ({
type: 'link',
text: antenna.name,
to: `/timeline/antenna/${antenna.id}`
})), null, {
type: 'link',
to: '/my/antennas',
text: i18n.locale.manageAntennas,
icon: 'fas fa-cog',
}];
items.value = _items;
});
os.popupMenu(items, ev.currentTarget || ev.target);
},
},
mentions: {
title: 'mentions',

View file

@ -28,14 +28,14 @@
<span v-if="!tab.iconOnly" class="title">{{ tab.title }}</span>
</button>
</div>
<div class="buttons right">
<template v-if="info.actions && !narrow">
<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
</template>
<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" @touchstart="preventDrag" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
</div>
</template>
<div class="buttons right">
<template v-if="info && info.actions && !narrow">
<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
</template>
<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" @touchstart="preventDrag" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
</div>
</div>
</template>
@ -83,6 +83,7 @@ export default defineComponent({
},
shouldShowMenu() {
if (this.info == null) return false;
if (this.info.actions != null && this.narrow) return true;
if (this.info.menu != null) return true;
if (this.info.share != null) return true;

View file

@ -263,7 +263,7 @@ export default defineComponent({
> .item {
padding-left: 0;
padding: 10px 0;
padding: 18px 0;
width: 100%;
text-align: center;
font-size: $ui-font-size * 1.1;
@ -280,14 +280,7 @@ export default defineComponent({
}
> .text {
display: inline-block;
font-size: 0.5em;
line-height: initial;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
opacity: 0.7;
display: none;
}
&:hover, &.active {

View file

@ -173,9 +173,10 @@ export function createImportUserListsJob(user: ThinUser, fileId: DriveFile['id']
});
}
export function createDeleteAccountJob(user: ThinUser) {
export function createDeleteAccountJob(user: ThinUser, opts: { soft?: boolean; }) {
return dbQueue.add('deleteAccount', {
user: user
user: user,
soft: opts.soft
}, {
removeOnComplete: true,
removeOnFail: true

View file

@ -1,7 +1,7 @@
import * as Bull from 'bull';
import { queueLogger } from '../../logger';
import { DriveFiles, Notes, UserProfiles, Users } from '@/models/index';
import { DbUserJobData } from '@/queue/types';
import { DbUserDeleteJobData } from '@/queue/types';
import { Note } from '@/models/entities/note';
import { DriveFile } from '@/models/entities/drive-file';
import { MoreThan } from 'typeorm';
@ -10,7 +10,7 @@ import { sendEmail } from '@/services/send-email';
const logger = queueLogger.createSubLogger('delete-account');
export async function deleteAccount(job: Bull.Job<DbUserJobData>): Promise<string | void> {
export async function deleteAccount(job: Bull.Job<DbUserDeleteJobData>): Promise<string | void> {
logger.info(`Deleting account of ${job.data.user.id} ...`);
const user = await Users.findOne(job.data.user.id);
@ -83,7 +83,12 @@ export async function deleteAccount(job: Bull.Job<DbUserJobData>): Promise<strin
}
}
await Users.delete(job.data.user.id);
// soft指定されている場合は物理削除しない
if (job.data.soft) {
// nop
} else {
await Users.delete(job.data.user.id);
}
return 'Account deleted';
}

View file

@ -17,12 +17,17 @@ export type InboxJobData = {
signature: httpSignature.IParsedSignature;
};
export type DbJobData = DbUserJobData | DbUserImportJobData;
export type DbJobData = DbUserJobData | DbUserImportJobData | DbUserDeleteJobData;
export type DbUserJobData = {
user: ThinUser;
};
export type DbUserDeleteJobData = {
user: ThinUser;
soft?: boolean;
};
export type DbUserImportJobData = {
user: ThinUser;
fileId: DriveFile['id'];

View file

@ -0,0 +1,58 @@
import $ from 'cafy';
import define from '../../../define';
import { Users } from '@/models/index';
import { doPostSuspend } from '@/services/suspend-user';
import { publishUserEvent } from '@/services/stream';
import { createDeleteAccountJob } from '@/queue';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['admin'],
requireCredential: true as const,
requireModerator: true,
params: {
userId: {
validator: $.type(ID),
},
}
};
export default define(meta, async (ps, me) => {
const user = await Users.findOne(ps.userId);
if (user == null) {
throw new Error('user not found');
}
if (user.isAdmin) {
throw new Error('cannot suspend admin');
}
if (user.isModerator) {
throw new Error('cannot suspend moderator');
}
if (Users.isLocalUser(user)) {
// 物理削除する前にDelete activityを送信する
await doPostSuspend(user).catch(e => {});
createDeleteAccountJob(user, {
soft: false
});
} else {
createDeleteAccountJob(user, {
soft: true // リモートユーザーの削除は、完全にDBから物理削除してしまうと再度連合してきてアカウントが復活する可能性があるため、soft指定する
});
}
await Users.update(user.id, {
isDeleted: true,
});
if (Users.isLocalUser(user)) {
// Terminate streaming
publishUserEvent(user.id, 'terminate', {});
}
});

View file

@ -35,7 +35,9 @@ export default define(meta, async (ps, user) => {
// 物理削除する前にDelete activityを送信する
await doPostSuspend(user).catch(e => {});
createDeleteAccountJob(user);
createDeleteAccountJob(user, {
soft: false
});
await Users.update(user.id, {
isDeleted: true,