Skip to content

Commit

Permalink
fix: 管理用APIの追加 (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
nacika-ins authored Oct 4, 2024
2 parents dadf84e + 9a4805a commit 59972a7
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 79 deletions.
30 changes: 15 additions & 15 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
version: "3"

services:
web:
build: .
restart: unless-stopped
links:
- db
- redis
# - es
ports:
- "3000:3000"
networks:
- internal_network
- external_network
volumes:
- ./files:/misskey/files
- ./.config:/misskey/.config:ro
# web:
# build: .
# restart: unless-stopped
# links:
# - db
# - redis
## - es
# ports:
# - "3000:3000"
# networks:
# - internal_network
# - external_network
# volumes:
# - ./files:/misskey/files
# - ./.config:/misskey/.config:ro

redis:
restart: unless-stopped
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/server/api/EndpointsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js';
import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js';
import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js';
import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js';
import * as ep___admin_federation_removeAllFollowingByUserId from './endpoints/admin/federation/remove-all-following-by-user-id.js';
import * as ep___admin_federation_updateInstance from './endpoints/admin/federation/update-instance.js';
import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js';
import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js';
Expand Down Expand Up @@ -384,6 +385,7 @@ const $admin_emoji_update: Provider = { provide: 'ep:admin/emoji/update', useCla
const $admin_federation_deleteAllFiles: Provider = { provide: 'ep:admin/federation/delete-all-files', useClass: ep___admin_federation_deleteAllFiles.default };
const $admin_federation_refreshRemoteInstanceMetadata: Provider = { provide: 'ep:admin/federation/refresh-remote-instance-metadata', useClass: ep___admin_federation_refreshRemoteInstanceMetadata.default };
const $admin_federation_removeAllFollowing: Provider = { provide: 'ep:admin/federation/remove-all-following', useClass: ep___admin_federation_removeAllFollowing.default };
const $admin_federation_removeAllFollowingByUserId: Provider = { provide: 'ep:admin/federation/remove-all-following-by-user-id', useClass: ep___admin_federation_removeAllFollowingByUserId.default };
const $admin_federation_updateInstance: Provider = { provide: 'ep:admin/federation/update-instance', useClass: ep___admin_federation_updateInstance.default };
const $admin_getIndexStats: Provider = { provide: 'ep:admin/get-index-stats', useClass: ep___admin_getIndexStats.default };
const $admin_getTableStats: Provider = { provide: 'ep:admin/get-table-stats', useClass: ep___admin_getTableStats.default };
Expand Down Expand Up @@ -739,6 +741,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_federation_deleteAllFiles,
$admin_federation_refreshRemoteInstanceMetadata,
$admin_federation_removeAllFollowing,
$admin_federation_removeAllFollowingByUserId,
$admin_federation_updateInstance,
$admin_getIndexStats,
$admin_getTableStats,
Expand Down Expand Up @@ -1088,6 +1091,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_federation_deleteAllFiles,
$admin_federation_refreshRemoteInstanceMetadata,
$admin_federation_removeAllFollowing,
$admin_federation_removeAllFollowingByUserId,
$admin_federation_updateInstance,
$admin_getIndexStats,
$admin_getTableStats,
Expand Down
2 changes: 2 additions & 0 deletions packages/backend/src/server/api/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js';
import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js';
import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js';
import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js';
import * as ep___admin_federation_removeAllFollowingByUserId from './endpoints/admin/federation/remove-all-following-by-user-id.js';
import * as ep___admin_federation_updateInstance from './endpoints/admin/federation/update-instance.js';
import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js';
import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js';
Expand Down Expand Up @@ -382,6 +383,7 @@ const eps = [
['admin/federation/delete-all-files', ep___admin_federation_deleteAllFiles],
['admin/federation/refresh-remote-instance-metadata', ep___admin_federation_refreshRemoteInstanceMetadata],
['admin/federation/remove-all-following', ep___admin_federation_removeAllFollowing],
['admin/federation/remove-all-following-by-user-id', ep___admin_federation_removeAllFollowingByUserId],
['admin/federation/update-instance', ep___admin_federation_updateInstance],
['admin/get-index-stats', ep___admin_getIndexStats],
['admin/get-table-stats', ep___admin_getTableStats],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { FollowingsRepository, User, UsersRepository } from '@/models/index.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';

export const meta = {
tags: ['admin'],

requireCredential: true,
requireModerator: true,
} as const;

export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string' },
},
required: ['userId'],
} as const;

// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,

@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,

private userFollowingService: UserFollowingService,
) {
super(meta, paramDef, async (ps, me) => {
const follower = await this.usersRepository.findOne({ where: { id: ps.userId } });

if (!follower) {
throw new Error(`User not found: ${ps.userId}`);
}

await this.unFollowAll(follower);
});
}

@bindThis
private async unFollowAll(follower: User) {
const followings = await this.followingsRepository.findBy({
followerId: follower.id,
});

for (const following of followings) {
const followee = await this.usersRepository.findOneBy({
id: following.followeeId,
});

if (followee == null) {
throw `Cant find followee ${following.followeeId}`;
}

await this.userFollowingService.unfollow(follower, followee, true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,

@Inject(DI.notesRepository)
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,

private userFollowingService: UserFollowingService,
Expand Down
25 changes: 25 additions & 0 deletions packages/frontend/src/pages/user-info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
<MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px" @click="resetPassword">
<i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}
</MkButton>
<MkButton v-if="$i.isAdmin" inline danger @click="unfollowAll">{{ i18n.ts.unfollowAll }}</MkButton>
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
</div>

Expand Down Expand Up @@ -401,6 +402,30 @@ async function deleteAccount() {
}
}
async function unfollowAll() {
const confirm = await os.confirm({
type: 'warning',
text: i18n.ts.unfollowAllConfirm,
});
if (confirm.canceled) return;
const typed = await os.inputText({
text: i18n.t('typeToConfirm', { x: user?.username }),
});
if (typed.canceled) return;
if (typed.result === user?.username) {
await os.apiWithDialog('admin/federation/remove-all-following-by-user-id', {
userId: user.id,
});
} else {
os.alert({
type: 'error',
text: 'input not match',
});
}
}
async function assignRole() {
const roles = await os.api('admin/roles/list');
Expand Down
123 changes: 60 additions & 63 deletions packages/frontend/src/scripts/get-user-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,59 @@ export function getUserMenu(user: misskey.entities.UserDetailed, router: Router
});
}

async function assignRole() {
const roles = await os.api('admin/roles/list');

const { canceled, result: roleId } = await os.select({
title: i18n.ts._role.chooseRoleToAssign,
items: roles.map((r) => ({ text: r.name, value: r.id })),
});
if (canceled) return;

const { canceled: canceled2, result: period } = await os.select({
title: i18n.ts.period,
items: [
{
value: 'indefinitely',
text: i18n.ts.indefinitely,
},
{
value: 'oneHour',
text: i18n.ts.oneHour,
},
{
value: 'oneDay',
text: i18n.ts.oneDay,
},
{
value: 'oneWeek',
text: i18n.ts.oneWeek,
},
{
value: 'oneMonth',
text: i18n.ts.oneMonth,
},
],
default: 'indefinitely',
});
if (canceled2) return;

const expiresAt =
period === 'indefinitely'
? null
: period === 'oneHour'
? Date.now() + 1000 * 60 * 60
: period === 'oneDay'
? Date.now() + 1000 * 60 * 60 * 24
: period === 'oneWeek'
? Date.now() + 1000 * 60 * 60 * 24 * 7
: period === 'oneMonth'
? Date.now() + 1000 * 60 * 60 * 24 * 30
: null;

await os.apiWithDialog('admin/roles/assign', { roleId, userId: user.id, expiresAt });
}

async function toggleMute() {
if (user.isMuted) {
os.apiWithDialog('mute/delete', {
Expand Down Expand Up @@ -216,6 +269,13 @@ export function getUserMenu(user: misskey.entities.UserDetailed, router: Router
action: inviteGroup,
}
: undefined,
iAmModerator
? {
icon: 'ti ti-users',
text: i18n.ts.assignRole,
action: assignRole,
}
: undefined,
null,
{
type: 'parent',
Expand All @@ -238,69 +298,6 @@ export function getUserMenu(user: misskey.entities.UserDetailed, router: Router
] as any;

if ($i && meId !== user.id) {
if (iAmModerator) {
menu = menu.concat([
{
type: 'parent',
icon: 'ti ti-badges',
text: i18n.ts.roles,
children: async () => {
const roles = await os.api('admin/roles/list');

return roles
.filter((r) => r.target === 'manual')
.map((r) => ({
text: r.name,
action: async () => {
const { canceled, result: period } = await os.select({
title: i18n.ts.period,
items: [
{
value: 'indefinitely',
text: i18n.ts.indefinitely,
},
{
value: 'oneHour',
text: i18n.ts.oneHour,
},
{
value: 'oneDay',
text: i18n.ts.oneDay,
},
{
value: 'oneWeek',
text: i18n.ts.oneWeek,
},
{
value: 'oneMonth',
text: i18n.ts.oneMonth,
},
],
default: 'indefinitely',
});
if (canceled) return;

const expiresAt =
period === 'indefinitely'
? null
: period === 'oneHour'
? Date.now() + 1000 * 60 * 60
: period === 'oneDay'
? Date.now() + 1000 * 60 * 60 * 24
: period === 'oneWeek'
? Date.now() + 1000 * 60 * 60 * 24 * 7
: period === 'oneMonth'
? Date.now() + 1000 * 60 * 60 * 24 * 30
: null;

os.apiWithDialog('admin/roles/assign', { roleId: r.id, userId: user.id, expiresAt });
},
}));
},
},
]);
}

menu = menu.concat([
null,
{
Expand Down

0 comments on commit 59972a7

Please sign in to comment.