feat: アンテナのエクスポート・インポート (#10754)

* feat: アンテナのエクスポートに対応 (misskey-dev/misskey#10690)

* feat: アンテナのインポートに対応 (misskey-dev/misskey#10690)

* fix: タイポを修正

* feat: ユーザーリストをサポート

* fix: バグを直した

* fix: バグを直した

* fix: 適当に決めた変数名を変更

* fix

* fix: 変数の変更、リファクタリング
This commit is contained in:
Chocolate Pie 2023-05-06 08:17:55 +09:00 committed by GitHub
parent 5dfbce7571
commit 39748ea0c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 384 additions and 1 deletions

View file

@ -194,6 +194,7 @@ import * as ep___i_exportMute from './endpoints/i/export-mute.js';
import * as ep___i_exportNotes from './endpoints/i/export-notes.js';
import * as ep___i_exportFavorites from './endpoints/i/export-favorites.js';
import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js';
import * as ep___i_exportAntennas from './endpoints/i/export-antennas.js';
import * as ep___i_favorites from './endpoints/i/favorites.js';
import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js';
import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js';
@ -202,6 +203,7 @@ import * as ep___i_importBlocking from './endpoints/i/import-blocking.js';
import * as ep___i_importFollowing from './endpoints/i/import-following.js';
import * as ep___i_importMuting from './endpoints/i/import-muting.js';
import * as ep___i_importUserLists from './endpoints/i/import-user-lists.js';
import * as ep___i_importAntennas from './endpoints/i/import-antennas.js';
import * as ep___i_notifications from './endpoints/i/notifications.js';
import * as ep___i_pageLikes from './endpoints/i/page-likes.js';
import * as ep___i_pages from './endpoints/i/pages.js';
@ -530,6 +532,7 @@ const $i_exportMute: Provider = { provide: 'ep:i/export-mute', useClass: ep___i_
const $i_exportNotes: Provider = { provide: 'ep:i/export-notes', useClass: ep___i_exportNotes.default };
const $i_exportFavorites: Provider = { provide: 'ep:i/export-favorites', useClass: ep___i_exportFavorites.default };
const $i_exportUserLists: Provider = { provide: 'ep:i/export-user-lists', useClass: ep___i_exportUserLists.default };
const $i_exportAntennas: Provider = { provide: 'ep:i/export-antennas', useClass: ep___i_exportAntennas.default };
const $i_favorites: Provider = { provide: 'ep:i/favorites', useClass: ep___i_favorites.default };
const $i_gallery_likes: Provider = { provide: 'ep:i/gallery/likes', useClass: ep___i_gallery_likes.default };
const $i_gallery_posts: Provider = { provide: 'ep:i/gallery/posts', useClass: ep___i_gallery_posts.default };
@ -538,6 +541,7 @@ const $i_importBlocking: Provider = { provide: 'ep:i/import-blocking', useClass:
const $i_importFollowing: Provider = { provide: 'ep:i/import-following', useClass: ep___i_importFollowing.default };
const $i_importMuting: Provider = { provide: 'ep:i/import-muting', useClass: ep___i_importMuting.default };
const $i_importUserLists: Provider = { provide: 'ep:i/import-user-lists', useClass: ep___i_importUserLists.default };
const $i_importAntennas: Provider = { provide: 'ep:i/import-antennas', useClass: ep___i_importAntennas.default };
const $i_notifications: Provider = { provide: 'ep:i/notifications', useClass: ep___i_notifications.default };
const $i_pageLikes: Provider = { provide: 'ep:i/page-likes', useClass: ep___i_pageLikes.default };
const $i_pages: Provider = { provide: 'ep:i/pages', useClass: ep___i_pages.default };
@ -870,6 +874,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$i_exportNotes,
$i_exportFavorites,
$i_exportUserLists,
$i_exportAntennas,
$i_favorites,
$i_gallery_likes,
$i_gallery_posts,
@ -878,6 +883,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$i_importFollowing,
$i_importMuting,
$i_importUserLists,
$i_importAntennas,
$i_notifications,
$i_pageLikes,
$i_pages,
@ -1204,6 +1210,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$i_exportNotes,
$i_exportFavorites,
$i_exportUserLists,
$i_exportAntennas,
$i_favorites,
$i_gallery_likes,
$i_gallery_posts,
@ -1212,6 +1219,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$i_importFollowing,
$i_importMuting,
$i_importUserLists,
$i_importAntennas,
$i_notifications,
$i_pageLikes,
$i_pages,

View file

@ -194,6 +194,7 @@ import * as ep___i_exportMute from './endpoints/i/export-mute.js';
import * as ep___i_exportNotes from './endpoints/i/export-notes.js';
import * as ep___i_exportFavorites from './endpoints/i/export-favorites.js';
import * as ep___i_exportUserLists from './endpoints/i/export-user-lists.js';
import * as ep___i_exportAntennas from './endpoints/i/export-antennas.js';
import * as ep___i_favorites from './endpoints/i/favorites.js';
import * as ep___i_gallery_likes from './endpoints/i/gallery/likes.js';
import * as ep___i_gallery_posts from './endpoints/i/gallery/posts.js';
@ -202,6 +203,7 @@ import * as ep___i_importBlocking from './endpoints/i/import-blocking.js';
import * as ep___i_importFollowing from './endpoints/i/import-following.js';
import * as ep___i_importMuting from './endpoints/i/import-muting.js';
import * as ep___i_importUserLists from './endpoints/i/import-user-lists.js';
import * as ep___i_importAntennas from './endpoints/i/import-antennas.js';
import * as ep___i_notifications from './endpoints/i/notifications.js';
import * as ep___i_pageLikes from './endpoints/i/page-likes.js';
import * as ep___i_pages from './endpoints/i/pages.js';
@ -528,6 +530,7 @@ const eps = [
['i/export-notes', ep___i_exportNotes],
['i/export-favorites', ep___i_exportFavorites],
['i/export-user-lists', ep___i_exportUserLists],
['i/export-antennas', ep___i_exportAntennas],
['i/favorites', ep___i_favorites],
['i/gallery/likes', ep___i_gallery_likes],
['i/gallery/posts', ep___i_gallery_posts],
@ -536,6 +539,7 @@ const eps = [
['i/import-following', ep___i_importFollowing],
['i/import-muting', ep___i_importMuting],
['i/import-user-lists', ep___i_importUserLists],
['i/import-antennas', ep___i_importAntennas],
['i/notifications', ep___i_notifications],
['i/page-likes', ep___i_pageLikes],
['i/pages', ep___i_pages],

View file

@ -0,0 +1,30 @@
import { Injectable } from '@nestjs/common';
import ms from 'ms';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueueService } from '@/core/QueueService.js';
export const meta = {
secure: true,
requireCredential: true,
limit: {
duration: ms('1hour'),
max: 1,
},
} as const;
export const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor (
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
this.queueService.createExportAntennasJob(me);
});
}
}

View file

@ -0,0 +1,81 @@
import { Inject, Injectable } from '@nestjs/common';
import ms from 'ms';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueueService } from '@/core/QueueService.js';
import type { AntennasRepository, DriveFilesRepository, UsersRepository, Antenna as _Antenna } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { RoleService } from '@/core/RoleService.js';
import { DownloadService } from '@/core/DownloadService.js';
export const meta = {
secure: true,
requireCredential: true,
prohibitMoved: true,
limit: {
duration: ms('1hour'),
max: 1,
},
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: '3b71d086-c3fa-431c-b01d-ded65a777172',
},
noSuchUser: {
message: 'No such user.',
code: 'NO_SUCH_USER',
id: 'e842c379-8ac7-4cf7-b07a-4d4de7e4671c',
},
emptyFile: {
message: 'That file is empty.',
code: 'EMPTY_FILE',
id: '7f60115d-8d93-4b0f-bd0e-3815dcbb389f',
},
tooManyAntennas: {
message: 'You cannot create antenna any more.',
code: 'TOO_MANY_ANTENNAS',
id: '600917d4-a4cb-4cc5-8ba8-7ac8ea3c7779',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
fileId: { type: 'string', format: 'misskey:id' },
},
required: ['fileId'],
} as const;
@Injectable() // eslint-disable-next-line import/no-default-export
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor (
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@Inject(DI.antennasRepository)
private antennasRepository: AntennasRepository,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private roleService: RoleService,
private queueService: QueueService,
private downloadService: DownloadService
) {
super(meta, paramDef, async (ps, me) => {
const users = await this.usersRepository.findOneBy({ id: me.id });
if (users === null) throw new ApiError(meta.errors.noSuchUser);
const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
if (file === null) throw new ApiError(meta.errors.noSuchFile);
if (file.size === 0) throw new ApiError(meta.errors.emptyFile);
const antennas: (_Antenna & { userListAcct: string[] | null })[] = JSON.parse(await this.downloadService.downloadTextFile(file.url));
const currentAntennasCount = await this.antennasRepository.countBy({ userId: me.id });
if (currentAntennasCount + antennas.length > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
throw new ApiError(meta.errors.tooManyAntennas);
}
this.queueService.createImportAntennasJob(me, antennas);
});
}
}
export type Antenna = (_Antenna & { userListAcct: string[] | null })[];