Compare commits

...

170 commits

Author SHA1 Message Date
tamaina c454a44785 wip hashtags 2023-07-03 09:18:54 +00:00
tamaina 41250d997b wip gallery 2023-07-03 08:57:13 +00:00
tamaina a97d379c84 wip following 2023-07-03 08:44:25 +00:00
tamaina 535e778033 format 2023-07-03 06:15:35 +00:00
tamaina 726fdb9e93 wip 2023-07-03 06:14:32 +00:00
tamaina ae3ce71bb2 flash 2023-07-03 05:59:23 +00:00
tamaina 106062fa23 wip 2023-07-03 05:50:13 +00:00
tamaina 42990fe6b6 wip 2023-07-03 05:45:38 +00:00
tamaina dc787f7a76 nigiri tubusu 2023-07-03 05:43:01 +00:00
syuilo 83a6902997
Merge branch 'develop' into mkjs-n 2023-07-03 14:38:01 +09:00
tamaina 1c5606ca72 update schema-type 2023-07-03 05:28:38 +00:00
tamaina 02405287d1 ????????? 2023-07-03 05:06:23 +00:00
tamaina bd9c084a3a follow 2023-07-03 04:38:55 +00:00
tamaina cef5feaee2 Merge branch 'develop' into mkjs-n 2023-07-03 04:35:13 +00:00
tamaina fe16b16fc3 Merge branch 'develop' into mkjs-n 2023-07-02 03:30:52 +00:00
tamaina f4cc9e3d2e Merge branch 'develop' into mkjs-n 2023-06-30 07:16:14 +00:00
tamaina 4d021f315f wip 2023-06-20 07:38:15 +00:00
tamaina bad25a804c wip 2023-06-20 07:20:55 +00:00
tamaina 019199168e add 2023-06-20 07:17:38 +00:00
tamaina 8122cb3a86 Merge branch 'develop' into mkjs-n 2023-06-20 06:52:36 +00:00
tamaina ab02fd3ec4 drive/folders 2023-06-16 06:49:29 +00:00
tamaina 028e7c00ae 移行作業再開 2023-06-16 06:40:54 +00:00
tamaina 27b6921d3c follow upstream 2023-06-16 06:21:11 +00:00
tamaina 3ec19e0b00 Merge branch 'develop' into mkjs-n 2023-06-16 06:14:29 +00:00
tamaina 8401117293 format 2023-06-05 07:50:55 +00:00
tamaina ced5638b80 wip 2023-06-05 07:49:39 +00:00
tamaina b532ad8cd4 wip 2023-06-05 07:36:48 +00:00
tamaina b818f2308d wip 2023-06-05 07:28:11 +00:00
tamaina b697b2f651 wip 2023-06-05 07:16:21 +00:00
tamaina 0571b83978 wip 2023-06-05 06:55:13 +00:00
tamaina b519ff1e10 clean up 2023-06-05 06:39:06 +00:00
tamaina 601eb65cfb fix 2023-06-05 06:38:58 +00:00
tamaina 59f4bf2a74 wip 2023-06-05 06:35:59 +00:00
tamaina a5a9540eac wip 2023-06-05 06:09:43 +00:00
tamaina bb46030677 chartsSchemasオブジェクトに集約 2023-06-05 06:05:36 +00:00
tamaina 9530cb01b9 wip 2023-06-05 05:46:35 +00:00
tamaina fd223a8538 Merge branch 'develop' into mkjs-n 2023-06-05 05:12:03 +00:00
tamaina 4c52f3b286 SignInはcreatedAtをtoISOStringする 2023-06-04 18:42:08 +00:00
tamaina edc38fc2c7 そもそもPacked<'...'>は常にSerializedである 2023-06-04 18:39:39 +00:00
tamaina 4a104af304 Use Serialized in EntityService 2023-06-04 18:26:05 +00:00
tamaina a1b243bbda fix 2023-06-04 17:53:24 +00:00
tamaina 6bd7a0d0aa clean up 2023-06-04 17:51:14 +00:00
tamaina 80bd84932c wip 2023-06-04 17:50:42 +00:00
tamaina 7f28b7334c wip 2023-06-04 17:42:10 +00:00
tamaina 669cfb1e29 wip 2023-06-04 17:37:00 +00:00
tamaina 47fae30aba wip 2023-06-04 17:27:52 +00:00
tamaina 64bbfc2107 wip 2023-06-04 17:22:53 +00:00
tamaina 1e2178b717 wip 2023-06-04 17:20:33 +00:00
tamaina b5852f6053 clean up 2023-06-04 16:42:11 +00:00
tamaina 35b1f73b51 wip 2023-06-04 16:41:45 +00:00
tamaina f651ca4b48 wip 2023-06-04 15:39:43 +00:00
tamaina 8bad11c559 wip 2023-06-04 15:34:11 +00:00
tamaina aead5305a7 wip 2023-06-04 15:13:53 +00:00
tamaina de9a5d515d wip 2023-06-04 15:07:21 +00:00
tamaina 7f51ace0ff fix 2023-06-04 15:05:35 +00:00
tamaina 586cfbe880 clean up 2023-06-04 15:05:10 +00:00
tamaina f7f8845801 wip 2023-06-04 15:05:01 +00:00
tamaina 93d111bfb6 wip 2023-06-04 14:59:14 +00:00
tamaina 1f64b7c9ea fix 2023-06-04 14:56:59 +00:00
tamaina c4f434aa01 wip 2023-06-04 14:56:36 +00:00
tamaina 4001c974a6 region 2023-06-04 14:51:58 +00:00
tamaina 2fc2f2d616 wip 2023-06-04 14:48:23 +00:00
tamaina f81479ad05 Merge branch 'develop' into mkjs-n 2023-06-04 13:31:14 +00:00
tamaina 6198313c49 akiramemasita 2023-05-29 17:19:20 +00:00
tamaina 90a22fe32f ✌️ 2023-05-29 17:16:53 +00:00
tamaina 3918473e29 wip 2023-05-29 17:03:20 +00:00
tamaina 931cea75b6 serial 2023-05-29 16:47:49 +00:00
tamaina 68a2aa3efd wip 2023-05-29 16:39:03 +00:00
tamaina dbeb1856ac ServerInfo 2023-05-29 16:30:50 +00:00
tamaina 07bbadbbdc wip 2023-05-29 16:26:16 +00:00
tamaina 78558eb666 wip 2023-05-29 16:09:42 +00:00
tamaina bc15dde742 wip 2023-05-29 16:01:04 +00:00
tamaina 9135d2757e wip 2023-05-29 14:17:25 +00:00
tamaina a1c96d9bcb wip 2023-05-29 14:11:51 +00:00
tamaina 94f25d9cdd wip 2023-05-29 14:09:13 +00:00
tamaina e1b4a0438e RoleCondFormulaValue: property type assertion 2023-05-29 14:03:39 +00:00
tamaina 93ea327660 wip 2023-05-29 13:28:31 +00:00
tamaina 9ce6f99cad Merge branch 'develop' into mkjs-n 2023-05-29 13:05:52 +00:00
tamaina d647df7f63 Merge branch 'develop' into mkjs-n 2023-05-29 13:02:41 +00:00
tamaina 654c93b0ce wip 2023-05-27 19:17:29 +00:00
tamaina 8d36911f90 wip 2023-05-27 17:28:47 +00:00
tamaina 84835be483 wip 2023-05-27 16:42:44 +00:00
tamaina 35f90e94c9 wip 2023-05-27 16:12:42 +00:00
tamaina 5268a55996 wip 2023-05-27 16:06:42 +00:00
tamaina 53ad4b18e5 Merge branch 'develop' into mkjs-n 2023-05-27 15:44:57 +00:00
syuilo 54b6b79559 Update endpoints.ts 2023-05-26 17:11:22 +09:00
syuilo b4cfa412b0 Merge branch 'develop' into mkjs-n 2023-05-26 17:11:10 +09:00
tamaina dfdfc8fab4 wip 2023-05-26 07:53:19 +00:00
tamaina b14d3cdc32 fix 2023-05-26 07:48:48 +00:00
tamaina 82a17ea427 wip 2023-05-26 07:44:47 +00:00
tamaina a57df6f2ca wip 2023-05-26 07:39:13 +00:00
tamaina 41c353e24d wip 2023-05-26 07:32:15 +00:00
tamaina bca9c54923 wip 2023-05-26 07:20:14 +00:00
tamaina ce5faa8ff5 wip 2023-05-26 07:18:15 +00:00
tamaina 0ef7a3db0f Merge branch 'develop' into mkjs-n 2023-05-26 07:01:29 +00:00
tamaina c264b01658 fix pnpm-lock 2023-05-25 17:31:25 +00:00
tamaina e07ed1b312
Merge branch 'develop' into mkjs-n 2023-05-26 02:25:32 +09:00
tamaina c0bd1b82ab wip 2023-05-25 16:53:29 +00:00
tamaina d7fe783c46 Merge branch 'develop' into mkjs-n 2023-05-25 14:49:51 +00:00
tamaina 1b6ac7888b wip 2023-05-22 05:20:19 +00:00
tamaina 86f4e206f4 wip 2023-05-22 04:50:18 +00:00
tamaina e689dcdd73 reqに$refを許可しない 2023-05-22 03:20:49 +00:00
tamaina 810d065d21 wip 2023-05-22 01:43:00 +00:00
tamaina 8adf2701d2 fix 2023-05-21 18:53:22 +00:00
tamaina 11f41a6e8d wip 2023-05-21 18:50:32 +00:00
tamaina 8d1569567f backend endpoints wip 2023-05-21 18:49:44 +00:00
tamaina 23545bcbbb wip 2023-05-21 16:45:39 +00:00
tamaina aea6950b46 wip 2023-05-21 16:44:29 +00:00
tamaina d7d3f00488 wip 2023-05-21 16:35:48 +00:00
tamaina 307bc2a38e fix... 2023-05-21 15:15:25 +00:00
tamaina 919af7b967 ??? 2023-05-21 15:01:06 +00:00
tamaina 359f0b21b0 ? 2023-05-21 14:19:32 +00:00
tamaina 79f71acd42 wip 2023-05-21 14:15:45 +00:00
tamaina 89480d9029 wip 2023-05-21 14:06:11 +00:00
tamaina 0853b2fe42 wip 2023-05-21 13:53:55 +00:00
tamaina 13fe20d47e wip 2023-05-21 12:54:39 +00:00
tamaina 361ab296c7 Merge branch 'develop' into mkjs-n 2023-05-21 12:11:22 +00:00
tamaina e76c1d8956
Merge branch 'develop' into mkjs-n 2023-05-19 22:45:50 +09:00
tamaina 0709ec5d82 Merge branch 'develop' into mkjs-n 2023-05-19 07:37:04 +00:00
tamaina f7a0213af9 Merge branch 'develop' into mkjs-n 2023-05-19 07:26:36 +00:00
tamaina 9b27fffb0e Merge branch 'develop' into mkjs-n 2023-05-19 07:23:31 +00:00
tamaina c0cbbe6072 Merge branch 'develop' into mkjs-n 2023-05-19 07:16:42 +00:00
tamaina 13fc093602 test 2023-05-15 09:44:23 +00:00
tamaina ca29fdc795 fix 2023-05-15 09:19:36 +00:00
tamaina 03a2501b45
wip 2023-05-15 18:16:27 +09:00
tamaina 69ba41bd8d
wip 2023-05-15 17:59:30 +09:00
tamaina 5f2bbea6de
wip 2023-05-15 17:53:51 +09:00
tamaina 49dc995f1e ✌️ 2023-05-15 08:45:38 +00:00
tamaina 15ef1a082d wip 2023-05-15 08:42:47 +00:00
tamaina cdfab72b35
wip 2023-05-15 17:39:41 +09:00
tamaina 37142d7495
wip 2023-05-15 17:30:52 +09:00
tamaina b6d04f5d5b update 2023-05-12 14:12:54 +00:00
tamaina 5e268f0611 wip endpoints 2023-05-12 07:54:50 +00:00
tamaina 2afa664864 update 2023-05-12 07:42:36 +00:00
tamaina 64f4bb6a90 Merge branch 'develop' into mkjs-n 2023-05-12 07:03:20 +00:00
tamaina 00cc846729 clean up 2023-05-10 19:22:21 +00:00
tamaina 4f5d77391f wip~~ 2023-05-10 19:18:48 +00:00
tamaina ac99cdce8b wip 2023-05-10 17:48:21 +00:00
tamaina 3324f3fa15 test 2023-05-10 17:34:13 +00:00
tamaina 56a1e436f3 wip 2023-05-10 16:55:36 +00:00
tamaina ad6c5275ec wip 2023-05-10 16:22:21 +00:00
tamaina 0e08c56bc7 wip 2023-05-10 15:58:46 +00:00
tamaina 3e13bb4cd7 fix 2023-05-10 15:55:04 +00:00
tamaina d3ecb02644 wip 2023-05-10 15:50:15 +00:00
tamaina f3bc232419 wip 2023-05-10 15:12:37 +00:00
tamaina 00b1fd2ee3 wip 2023-05-10 15:07:37 +00:00
tamaina 44e819bf6a wip 2023-05-10 15:01:45 +00:00
tamaina 49e32ebf2b wip 2023-05-10 14:58:45 +00:00
tamaina 66447d13c1 wip 2023-05-10 14:53:26 +00:00
tamaina 5bb2d71231 wip 2023-05-10 14:48:12 +00:00
tamaina 32e489e536 wip 2023-05-10 14:45:31 +00:00
tamaina fc10a9026c wip 2023-05-10 14:37:01 +00:00
tamaina 9699bac704 wip 2023-05-10 14:32:46 +00:00
tamaina d328a8cefc wip 2023-05-10 14:21:54 +00:00
tamaina 34edf950ff wip 2023-05-10 14:20:52 +00:00
tamaina 7d8fa48d47 Merge branch 'develop' into mkjs-n 2023-05-10 14:20:07 +00:00
tamaina 96e04738c0 Merge branch 'develop' into mkjs-n 2023-05-10 08:04:38 +00:00
tamaina e4c36bbd7a Merge branch 'develop' into mkjs-n 2023-05-04 12:33:48 +00:00
tamaina 0ee1dab2bc fix 2023-05-04 11:13:03 +00:00
tamaina 47e3792105 update 2023-05-04 11:03:03 +00:00
tamaina 0040aca841 fix 2023-05-04 10:57:55 +00:00
tamaina 41a822c34c wip 2023-05-04 10:56:53 +00:00
tamaina 55c217da73 wip 2023-05-04 10:56:24 +00:00
tamaina ff85376306 fix 2023-05-02 17:57:56 +00:00
tamaina ef15b9c0d3 wip 2023-05-02 17:31:17 +00:00
tamaina abefddb90e Merge branch 'mkjs-n' of https://github.com/misskey-dev/misskey into mkjs-n 2023-05-02 16:51:48 +00:00
tamaina 3fcee7c4bd /schemas/Note 2023-05-02 16:51:41 +00:00
tamaina d18750cb97
Merge branch 'develop' into mkjs-n 2023-05-03 01:24:08 +09:00
tamaina 6c53d1fdb7
Merge branch 'develop' into mkjs-n 2023-05-02 21:19:38 +09:00
tamaina e9355bf918 wip 2023-05-02 12:05:17 +00:00
331 changed files with 12806 additions and 11102 deletions

View file

@ -210,6 +210,7 @@
"eslint-plugin-import": "2.27.5",
"execa": "6.1.0",
"jest": "29.5.0",
"jest-mock": "29.5.0"
"jest-mock": "29.5.0",
"schema-type": "github:misskey-dev/schema-type"
}
}

View file

@ -4,83 +4,7 @@ import type { User } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { NotificationService } from '@/core/NotificationService.js';
export const ACHIEVEMENT_TYPES = [
'notes1',
'notes10',
'notes100',
'notes500',
'notes1000',
'notes5000',
'notes10000',
'notes20000',
'notes30000',
'notes40000',
'notes50000',
'notes60000',
'notes70000',
'notes80000',
'notes90000',
'notes100000',
'login3',
'login7',
'login15',
'login30',
'login60',
'login100',
'login200',
'login300',
'login400',
'login500',
'login600',
'login700',
'login800',
'login900',
'login1000',
'passedSinceAccountCreated1',
'passedSinceAccountCreated2',
'passedSinceAccountCreated3',
'loggedInOnBirthday',
'loggedInOnNewYearsDay',
'noteClipped1',
'noteFavorited1',
'myNoteFavorited1',
'profileFilled',
'markedAsCat',
'following1',
'following10',
'following50',
'following100',
'following300',
'followers1',
'followers10',
'followers50',
'followers100',
'followers300',
'followers500',
'followers1000',
'collectAchievements30',
'viewAchievements3min',
'iLoveMisskey',
'foundTreasure',
'client30min',
'client60min',
'noteDeletedWithin1min',
'postedAtLateNight',
'postedAt0min0sec',
'selfQuote',
'htl20npm',
'viewInstanceChart',
'outputHelloWorldOnScratchpad',
'open3windows',
'driveFolderCircularReference',
'reactWithoutRead',
'clickedClickHere',
'justPlainLucky',
'setNameToSyuilo',
'cookieClicked',
'brainDiver',
] as const;
import { ACHIEVEMENT_TYPES } from 'misskey-js';
@Injectable()
export class AchievementService {

View file

@ -10,7 +10,7 @@ import { isUserRelated } from '@/misc/is-user-related.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { PushNotificationService } from '@/core/PushNotificationService.js';
import * as Acct from '@/misc/acct.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { DI } from '@/di-symbols.js';
import type { MutingsRepository, NotesRepository, AntennasRepository, UserListJoiningsRepository } from '@/models/index.js';
import { UtilityService } from '@/core/UtilityService.js';

View file

@ -16,7 +16,7 @@ import type {
UserListStreamTypes,
RoleTimelineStreamTypes,
} from '@/server/api/stream/types.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js';

View file

@ -3,7 +3,7 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { In } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { User } from '@/models/entities/User.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import type { Note } from '@/models/entities/Note.js';
import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';

View file

@ -3,7 +3,7 @@ import push from 'web-push';
import * as Redis from 'ioredis';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { getNoteSummary } from '@/misc/get-note-summary.js';
import type { SwSubscription, SwSubscriptionsRepository } from '@/models/index.js';
import { MetaService } from '@/core/MetaService.js';

View file

@ -8,12 +8,12 @@ import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { MetaService } from '@/core/MetaService.js';
import { CacheService } from '@/core/CacheService.js';
import type { RoleCondFormulaValue } from '@/models/entities/Role.js';
import type { RoleCondFormulaValue } from 'misskey-js/built/schemas/role.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { StreamMessages } from '@/server/api/stream/types.js';
import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import type { OnApplicationShutdown } from '@nestjs/common';
export type RolePolicies = {

View file

@ -107,7 +107,10 @@ export class UserBlockingService implements OnModuleInit {
if (this.userEntityService.isLocalUser(followee)) {
this.userEntityService.pack(followee, followee, {
detail: true,
}).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed));
}).then(packed => {
this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed);
return packed; // somehow this is needed by typescript
});
}
if (this.userEntityService.isLocalUser(follower) && !silent) {
@ -122,6 +125,8 @@ export class UserBlockingService implements OnModuleInit {
user: packed,
});
}
return packed; // somehow this is needed by typescript
});
}

View file

@ -7,7 +7,7 @@ import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { IdService } from '@/core/IdService.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import InstanceChart from '@/core/chart/charts/instance.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { WebhookService } from '@/core/WebhookService.js';
@ -267,7 +267,7 @@ export class UserFollowingService implements OnModuleInit {
this.userEntityService.pack(followee.id, follower, {
detail: true,
}).then(async packed => {
this.globalEventService.publishMainStream(follower.id, 'follow', packed as Packed<'UserDetailedNotMe'>);
this.globalEventService.publishMainStream(follower.id, 'follow', packed);
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow'));
for (const webhook of webhooks) {

View file

@ -1,17 +1,7 @@
import Chart from '../../core.js';
export const name = 'activeUsers';
export const schema = {
'readWrite': { intersection: ['read', 'write'] },
'read': { uniqueIncrement: true },
'write': { uniqueIncrement: true },
'registeredWithinWeek': { uniqueIncrement: true },
'registeredWithinMonth': { uniqueIncrement: true },
'registeredWithinYear': { uniqueIncrement: true },
'registeredOutsideWeek': { uniqueIncrement: true },
'registeredOutsideMonth': { uniqueIncrement: true },
'registeredOutsideYear': { uniqueIncrement: true },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'activeUsers' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,11 +1,7 @@
import Chart from '../../core.js';
export const name = 'apRequest';
export const schema = {
'deliverFailed': { },
'deliverSucceeded': { },
'inboxReceived': { },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'apRequest' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,16 +1,7 @@
import Chart from '../../core.js';
export const name = 'drive';
export const schema = {
'local.incCount': {},
'local.incSize': {}, // in kilobyte
'local.decCount': {},
'local.decSize': {}, // in kilobyte
'remote.incCount': {},
'remote.incSize': {}, // in kilobyte
'remote.decCount': {},
'remote.decSize': {}, // in kilobyte
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'drive' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,16 +1,7 @@
import Chart from '../../core.js';
export const name = 'federation';
export const schema = {
'deliveredInstances': { uniqueIncrement: true, range: 'small' },
'inboxInstances': { uniqueIncrement: true, range: 'small' },
'stalled': { uniqueIncrement: true, range: 'small' },
'sub': { accumulate: true, range: 'small' },
'pub': { accumulate: true, range: 'small' },
'pubsub': { accumulate: true, range: 'small' },
'subActive': { accumulate: true, range: 'small' },
'pubActive': { accumulate: true, range: 'small' },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'federation' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,32 +1,7 @@
import Chart from '../../core.js';
export const name = 'instance';
export const schema = {
'requests.failed': { range: 'small' },
'requests.succeeded': { range: 'small' },
'requests.received': { range: 'small' },
'notes.total': { accumulate: true },
'notes.inc': {},
'notes.dec': {},
'notes.diffs.normal': {},
'notes.diffs.reply': {},
'notes.diffs.renote': {},
'notes.diffs.withFile': {},
'users.total': { accumulate: true },
'users.inc': { range: 'small' },
'users.dec': { range: 'small' },
'following.total': { accumulate: true },
'following.inc': { range: 'small' },
'following.dec': { range: 'small' },
'followers.total': { accumulate: true },
'followers.inc': { range: 'small' },
'followers.dec': { range: 'small' },
'drive.totalFiles': { accumulate: true },
'drive.incFiles': {},
'drive.decFiles': {},
'drive.incUsage': {}, // in kilobyte
'drive.decUsage': {}, // in kilobyte
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'instance' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,22 +1,7 @@
import Chart from '../../core.js';
export const name = 'notes';
export const schema = {
'local.total': { accumulate: true },
'local.inc': {},
'local.dec': {},
'local.diffs.normal': {},
'local.diffs.reply': {},
'local.diffs.renote': {},
'local.diffs.withFile': {},
'remote.total': { accumulate: true },
'remote.inc': {},
'remote.dec': {},
'remote.diffs.normal': {},
'remote.diffs.reply': {},
'remote.diffs.renote': {},
'remote.diffs.withFile': {},
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'notes' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,14 +1,7 @@
import Chart from '../../core.js';
export const name = 'perUserDrive';
export const schema = {
'totalCount': { accumulate: true },
'totalSize': { accumulate: true }, // in kilobyte
'incCount': { range: 'small' },
'incSize': {}, // in kilobyte
'decCount': { range: 'small' },
'decSize': {}, // in kilobyte
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'perUserDrive' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,20 +1,7 @@
import Chart from '../../core.js';
export const name = 'perUserFollowing';
export const schema = {
'local.followings.total': { accumulate: true },
'local.followings.inc': { range: 'small' },
'local.followings.dec': { range: 'small' },
'local.followers.total': { accumulate: true },
'local.followers.inc': { range: 'small' },
'local.followers.dec': { range: 'small' },
'remote.followings.total': { accumulate: true },
'remote.followings.inc': { range: 'small' },
'remote.followings.dec': { range: 'small' },
'remote.followers.total': { accumulate: true },
'remote.followers.inc': { range: 'small' },
'remote.followers.dec': { range: 'small' },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'perUserFollowing' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,15 +1,7 @@
import Chart from '../../core.js';
export const name = 'perUserNotes';
export const schema = {
'total': { accumulate: true },
'inc': { range: 'small' },
'dec': { range: 'small' },
'diffs.normal': { range: 'small' },
'diffs.reply': { range: 'small' },
'diffs.renote': { range: 'small' },
'diffs.withFile': { range: 'small' },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'perUserNotes' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,12 +1,7 @@
import Chart from '../../core.js';
export const name = 'perUserPv';
export const schema = {
'upv.user': { uniqueIncrement: true, range: 'small' },
'pv.user': { range: 'small' },
'upv.visitor': { uniqueIncrement: true, range: 'small' },
'pv.visitor': { range: 'small' },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'perUserPv' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,10 +1,7 @@
import Chart from '../../core.js';
export const name = 'perUserReaction';
export const schema = {
'local.count': { range: 'small' },
'remote.count': { range: 'small' },
} as const;
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'perUserReactions' as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,11 +1,7 @@
import Chart from '../../core.js';
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'testGrouped';
export const schema = {
'foo.total': { accumulate: true },
'foo.inc': {},
'foo.dec': {},
} as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema, true);

View file

@ -1,11 +1,7 @@
import Chart from '../../core.js';
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'testIntersection';
export const schema = {
'a': { uniqueIncrement: true },
'b': { uniqueIncrement: true },
'aAndB': { intersection: ['a', 'b'] },
} as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,9 +1,7 @@
import Chart from '../../core.js';
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'testUnique';
export const schema = {
'foo': { uniqueIncrement: true },
} as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,11 +1,7 @@
import Chart from '../../core.js';
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'test';
export const schema = {
'foo.total': { accumulate: true },
'foo.inc': {},
'foo.dec': {},
} as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -1,14 +1,7 @@
import Chart from '../../core.js';
import { chartsSchemas } from 'misskey-js/built/schemas/charts.js';
export const name = 'users';
export const schema = {
'local.total': { accumulate: true },
'local.inc': { range: 'small' },
'local.dec': { range: 'small' },
'remote.total': { accumulate: true },
'remote.inc': { range: 'small' },
'remote.dec': { range: 'small' },
} as const;
export const schema = chartsSchemas[name];
export const entity = Chart.schemaToEntity(name, schema);

View file

@ -10,22 +10,12 @@ import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import type { Repository, DataSource } from 'typeorm';
import type { ChartSchema as Schema, ChartResult, Unflatten } from 'misskey-js/built/schemas';
const COLUMN_PREFIX = '___' as const;
const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const;
const COLUMN_DELIMITER = '_' as const;
type Schema = Record<string, {
uniqueIncrement?: boolean;
intersection?: string[] | ReadonlyArray<string>;
range?: 'big' | 'small' | 'medium';
// previousな値を引き継ぐかどうか
accumulate?: boolean;
}>;
type KeyToColumnName<T extends string> = T extends `${infer R1}.${infer R2}` ? `${R1}${typeof COLUMN_DELIMITER}${KeyToColumnName<R2>}` : T;
type Columns<S extends Schema> = {
@ -64,47 +54,6 @@ export type KVs<S extends Schema> = {
[K in keyof S]: number;
};
type ChartResult<T extends Schema> = {
[P in keyof T]: number[];
};
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
type UnflattenSingleton<K extends string, V> = K extends `${infer A}.${infer B}`
? { [_ in A]: UnflattenSingleton<B, V>; }
: { [_ in K]: V; };
type Unflatten<T extends Record<string, any>> = UnionToIntersection<
{
[K in Extract<keyof T, string>]: UnflattenSingleton<K, T[K]>;
}[Extract<keyof T, string>]
>;
type ToJsonSchema<S> = {
type: 'object';
properties: {
[K in keyof S]: S[K] extends number[] ? { type: 'array'; items: { type: 'number'; }; } : ToJsonSchema<S[K]>;
},
required: (keyof S)[];
};
export function getJsonSchema<S extends Schema>(schema: S): ToJsonSchema<Unflatten<ChartResult<S>>> {
const jsonSchema = {
type: 'object',
properties: {} as Record<string, unknown>,
required: [],
};
for (const k in schema) {
jsonSchema.properties[k] = {
type: 'array',
items: { type: 'number' },
};
}
return jsonSchema as ToJsonSchema<Unflatten<ChartResult<S>>>;
}
/**
*
*/

View file

@ -5,6 +5,7 @@ import { awaitAll } from '@/misc/prelude/await-all.js';
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js';
import type { Packed } from 'misskey-js';
@Injectable()
export class AbuseUserReportEntityService {
@ -19,7 +20,7 @@ export class AbuseUserReportEntityService {
@bindThis
public async pack(
src: AbuseUserReport['id'] | AbuseUserReport,
) {
): Promise<Packed<'AbuseUserReport'>> {
const report = typeof src === 'object' ? src : await this.abuseUserReportsRepository.findOneByOrFail({ id: src });
return await awaitAll({
@ -46,7 +47,7 @@ export class AbuseUserReportEntityService {
@bindThis
public packMany(
reports: any[],
) {
): Promise<Packed<'AbuseUserReport'>[]> {
return Promise.all(reports.map(x => this.pack(x)));
}
}

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { AntennasRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import type { Antenna } from '@/models/entities/Antenna.js';
import { bindThis } from '@/decorators.js';

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { AccessTokensRepository, AppsRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import type { App } from '@/models/entities/App.js';
import type { User } from '@/models/entities/User.js';
import { bindThis } from '@/decorators.js';

View file

@ -6,6 +6,7 @@ import type { AuthSession } from '@/models/entities/AuthSession.js';
import type { User } from '@/models/entities/User.js';
import { AppEntityService } from './AppEntityService.js';
import { bindThis } from '@/decorators.js';
import type { Packed } from 'misskey-js';
@Injectable()
export class AuthSessionEntityService {
@ -21,7 +22,7 @@ export class AuthSessionEntityService {
public async pack(
src: AuthSession['id'] | AuthSession,
me?: { id: User['id'] } | null | undefined,
) {
): Promise<Packed<'AuthSession'>> {
const session = typeof src === 'object' ? src : await this.authSessionsRepository.findOneByOrFail({ id: src });
return await awaitAll({

View file

@ -2,11 +2,12 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { BlockingsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import type { Blocking } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js';
import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
import type { Serialized } from 'schema-type';
@Injectable()
export class BlockingEntityService {
@ -39,7 +40,7 @@ export class BlockingEntityService {
public packMany(
blockings: any[],
me: { id: User['id'] },
) {
): Promise<Packed<'Blocking'>[]> {
return Promise.all(blockings.map(x => this.pack(x, me)));
}
}

View file

@ -1,8 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { ChannelFavoritesRepository, ChannelFollowingsRepository, ChannelsRepository, DriveFilesRepository, NoteUnreadsRepository, NotesRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { Channel } from '@/models/entities/Channel.js';
import { bindThis } from '@/decorators.js';

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { ClipFavoritesRepository, ClipsRepository, User } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { Clip } from '@/models/entities/Clip.js';
import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@ -47,7 +46,7 @@ export class ClipEntityService {
public packMany(
clips: Clip[],
me?: { id: User['id'] } | null | undefined,
) {
): Promise<Packed<'Clip'>[]> {
return Promise.all(clips.map(x => this.pack(x, me)));
}
}

View file

@ -3,7 +3,7 @@ import { DataSource, In } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { NotesRepository, DriveFilesRepository } from '@/models/index.js';
import type { Config } from '@/config.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { User } from '@/models/entities/User.js';
import type { DriveFile } from '@/models/entities/DriveFile.js';
@ -265,11 +265,11 @@ export class DriveFileEntityService {
public async packManyByIdsMap(
fileIds: DriveFile['id'][],
options?: PackOptions,
): Promise<Map<Packed<'DriveFile'>['id'], Packed<'DriveFile'> | null>> {
): Promise<Map<Packed<'DriveFile'>>['id'], Serialized<Packed<'DriveFile'> | null>> {
if (fileIds.length === 0) return new Map();
const files = await this.driveFilesRepository.findBy({ id: In(fileIds) });
const packedFiles = await this.packMany(files, options);
const map = new Map<Packed<'DriveFile'>['id'], Packed<'DriveFile'> | null>(packedFiles.map(f => [f.id, f]));
const map = new Map<Packed<'DriveFile'>>['id'], Serialized<Packed<'DriveFile'> | null>(packedFiles.map(f => [f.id, f]));
for (const id of fileIds) {
if (!map.has(id)) map.set(id, null);
}

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { DriveFilesRepository, DriveFoldersRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { DriveFolder } from '@/models/entities/DriveFolder.js';
import { bindThis } from '@/decorators.js';

View file

@ -1,8 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { EmojisRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { Emoji } from '@/models/entities/Emoji.js';
import { bindThis } from '@/decorators.js';

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { FlashsRepository, FlashLikesRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { Flash } from '@/models/entities/Flash.js';
import { bindThis } from '@/decorators.js';

View file

@ -1,7 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { FlashLikesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js';
import type { FlashLike } from '@/models/entities/FlashLike.js';
import { bindThis } from '@/decorators.js';

View file

@ -1,11 +1,11 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { FollowRequestsRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js';
import type { FollowRequest } from '@/models/entities/FollowRequest.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js';
import { Packed } from 'misskey-js';
@Injectable()
export class FollowRequestEntityService {
@ -21,7 +21,7 @@ export class FollowRequestEntityService {
public async pack(
src: FollowRequest['id'] | FollowRequest,
me?: { id: User['id'] } | null | undefined,
) {
): Promise<Packed<'FollowRequest'>> {
const request = typeof src === 'object' ? src : await this.followRequestsRepository.findOneByOrFail({ id: src });
return {

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { FollowingsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { Following } from '@/models/entities/Following.js';
import { bindThis } from '@/decorators.js';

View file

@ -1,7 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { GalleryLikesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js';
import type { GalleryLike } from '@/models/entities/GalleryLike.js';
import { GalleryPostEntityService } from './GalleryPostEntityService.js';
import { bindThis } from '@/decorators.js';

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { GalleryLikesRepository, GalleryPostsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { GalleryPost } from '@/models/entities/GalleryPost.js';
import { bindThis } from '@/decorators.js';

View file

@ -1,8 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { HashtagsRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { Hashtag } from '@/models/entities/Hashtag.js';
import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';

View file

@ -1,8 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { InstancesRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { Instance } from '@/models/entities/Instance.js';
import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js';

View file

@ -2,10 +2,10 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { ModerationLogsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { } from '@/models/entities/Blocking.js';
import type { ModerationLog } from '@/models/entities/ModerationLog.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js';
import type { Packed } from 'misskey-js';
@Injectable()
export class ModerationLogEntityService {
@ -20,7 +20,7 @@ export class ModerationLogEntityService {
@bindThis
public async pack(
src: ModerationLog['id'] | ModerationLog,
) {
): Promise<Packed<'ModerationLog'>> {
const log = typeof src === 'object' ? src : await this.moderationLogsRepository.findOneByOrFail({ id: src });
return await awaitAll({
@ -38,8 +38,7 @@ export class ModerationLogEntityService {
@bindThis
public packMany(
reports: any[],
) {
): Promise<Packed<'ModerationLog'>[]> {
return Promise.all(reports.map(x => this.pack(x)));
}
}

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { MutingsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { Muting } from '@/models/entities/Muting.js';
import { bindThis } from '@/decorators.js';

View file

@ -3,7 +3,7 @@ import { DataSource, In } from 'typeorm';
import * as mfm from 'mfm-js';
import { ModuleRef } from '@nestjs/core';
import { DI } from '@/di-symbols.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { nyaize } from '@/misc/nyaize.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { User } from '@/models/entities/User.js';

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { NoteFavoritesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { NoteFavorite } from '@/models/entities/NoteFavorite.js';
import { NoteEntityService } from './NoteEntityService.js';
@ -21,7 +21,7 @@ export class NoteFavoriteEntityService {
public async pack(
src: NoteFavorite['id'] | NoteFavorite,
me?: { id: User['id'] } | null | undefined,
) {
): Promise<Packed<'NoteFavorite'>> {
const favorite = typeof src === 'object' ? src : await this.noteFavoritesRepository.findOneByOrFail({ id: src });
return {

View file

@ -1,10 +1,9 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { NoteReactionsRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { bindThis } from '@/decorators.js';
import type { OnModuleInit } from '@nestjs/common';
import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js';
import type { NoteReaction } from '@/models/entities/NoteReaction.js';
import type { ReactionService } from '../ReactionService.js';

View file

@ -6,10 +6,10 @@ import type { AccessTokensRepository, FollowRequestsRepository, NoteReactionsRep
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Notification } from '@/models/entities/Notification.js';
import type { Note } from '@/models/entities/Note.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import { bindThis } from '@/decorators.js';
import { isNotNull } from '@/misc/is-not-null.js';
import { notificationTypes } from '@/types.js';
import { notificationTypes } from 'misskey-js';
import type { OnModuleInit } from '@nestjs/common';
import type { CustomEmojiService } from '../CustomEmojiService.js';
import type { UserEntityService } from './UserEntityService.js';

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { DriveFilesRepository, PagesRepository, PageLikesRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { Page } from '@/models/entities/Page.js';
import type { DriveFile } from '@/models/entities/DriveFile.js';

View file

@ -1,7 +1,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { PageLikesRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js';
import type { User } from '@/models/entities/User.js';
import type { PageLike } from '@/models/entities/PageLike.js';
import { PageEntityService } from './PageEntityService.js';

View file

@ -2,8 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { RenoteMutingsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { User } from '@/models/entities/User.js';
import type { RenoteMuting } from '@/models/entities/RenoteMuting.js';
import { bindThis } from '@/decorators.js';

View file

@ -8,6 +8,7 @@ import type { Role } from '@/models/entities/Role.js';
import { bindThis } from '@/decorators.js';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
import { UserEntityService } from './UserEntityService.js';
import type { Packed } from 'misskey-js';
@Injectable()
export class RoleEntityService {
@ -26,7 +27,7 @@ export class RoleEntityService {
public async pack(
src: Role['id'] | Role,
me?: { id: User['id'] } | null | undefined,
) {
): Promise<Packed<'Role'>> {
const role = typeof src === 'object' ? src : await this.rolesRepository.findOneByOrFail({ id: src });
const assignedCount = await this.roleAssignmentsRepository.createQueryBuilder('assign')
@ -37,7 +38,7 @@ export class RoleEntityService {
}))
.getCount();
const policies = { ...role.policies };
const policies: { [x: string]: Packed<'RolePolicy'> } = { ...role.policies };
for (const [k, v] of Object.entries(DEFAULT_POLICIES)) {
if (policies[k] == null) policies[k] = {
useDefault: true,
@ -72,8 +73,7 @@ export class RoleEntityService {
public packMany(
roles: any[],
me: { id: User['id'] },
) {
): Promise<Packed<'Role'>[]> {
return Promise.all(roles.map(x => this.pack(x, me)));
}
}

View file

@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { SigninsRepository } from '@/models/index.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { Signin } from '@/models/entities/Signin.js';
import { UserEntityService } from './UserEntityService.js';
import { bindThis } from '@/decorators.js';
@ -19,8 +19,10 @@ export class SigninEntityService {
@bindThis
public async pack(
src: Signin,
) {
return src;
): Promise<Packed<'SignIn'>> {
return {
...src,
createdAt: src.createdAt.toISOString(),
};
}
}

View file

@ -5,7 +5,7 @@ import _Ajv from 'ajv';
import { ModuleRef } from '@nestjs/core';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Packed } from 'misskey-js';
import type { Promiseable } from '@/misc/prelude/await-all.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js';
@ -28,7 +28,7 @@ type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends bo
Detailed extends true ?
ExpectsMe extends true ? Packed<'MeDetailed'> :
ExpectsMe extends false ? Packed<'UserDetailedNotMe'> :
Packed<'UserDetailed'> :
(Packed<'MeDetailed'> | Packed<'UserDetailedNotMe'>) :
Packed<'UserLite'>;
const Ajv = _Ajv.default;
@ -291,7 +291,7 @@ export class UserEntityService implements OnModuleInit {
return `${this.config.url}/users/${userId}`;
}
public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>(
public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false, R = IsMeAndIsUserDetailed<ExpectsMe, D>>(
src: User['id'] | User,
me?: { id: User['id']; } | null | undefined,
options?: {
@ -299,7 +299,7 @@ export class UserEntityService implements OnModuleInit {
includeSecrets?: boolean,
userProfile?: UserProfile,
},
): Promise<IsMeAndIsUserDetailed<ExpectsMe, D>> {
): Promise<R> {
const opts = Object.assign({
detail: false,
includeSecrets: false,
@ -499,19 +499,19 @@ export class UserEntityService implements OnModuleInit {
isMuted: relation.isMuted,
isRenoteMuted: relation.isRenoteMuted,
} : {}),
} as Promiseable<Packed<'User'>> as Promiseable<IsMeAndIsUserDetailed<ExpectsMe, D>>;
} as Promiseable<R>;
return await awaitAll(packed);
}
public packMany<D extends boolean = false>(
public packMany<D extends boolean = false, R = IsUserDetailed<D>>(
users: (User['id'] | User)[],
me?: { id: User['id'] } | null | undefined,
options?: {
detail?: D,
includeSecrets?: boolean,
},
): Promise<IsUserDetailed<D>[]> {
return Promise.all(users.map(u => this.pack(u, me, options)));
): Promise<R[]> {
return Promise.all(users.map(u => this.pack<null, D, R>(u, me, options)));
}
}

View file

@ -1,8 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
import type { UserListJoiningsRepository, UserListsRepository } from '@/models/index.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/entities/Blocking.js';
import type { Packed } from 'misskey-js';
import type { UserList } from '@/models/entities/UserList.js';
import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js';
@ -39,4 +38,3 @@ export class UserListEntityService {
};
}
}

View file

@ -1,4 +1,4 @@
import type { Packed } from './json-schema.js';
import type { Packed } from 'misskey-js';
/**
* 稿

View file

@ -1,4 +1,4 @@
import type { Packed } from './json-schema.js';
import type { Packed } from 'misskey-js';
export function isInstanceMuted(note: Packed<'Note'>, mutedInstances: Set<string>): boolean {
if (mutedInstances.has(note.user.host ?? '')) return true;

View file

@ -1,185 +0,0 @@
import {
packedUserLiteSchema,
packedUserDetailedNotMeOnlySchema,
packedMeDetailedOnlySchema,
packedUserDetailedNotMeSchema,
packedMeDetailedSchema,
packedUserDetailedSchema,
packedUserSchema,
} from '@/models/json-schema/user.js';
import { packedNoteSchema } from '@/models/json-schema/note.js';
import { packedUserListSchema } from '@/models/json-schema/user-list.js';
import { packedAppSchema } from '@/models/json-schema/app.js';
import { packedNotificationSchema } from '@/models/json-schema/notification.js';
import { packedDriveFileSchema } from '@/models/json-schema/drive-file.js';
import { packedDriveFolderSchema } from '@/models/json-schema/drive-folder.js';
import { packedFollowingSchema } from '@/models/json-schema/following.js';
import { packedMutingSchema } from '@/models/json-schema/muting.js';
import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js';
import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
import { packedPageSchema } from '@/models/json-schema/page.js';
import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js';
import { packedChannelSchema } from '@/models/json-schema/channel.js';
import { packedAntennaSchema } from '@/models/json-schema/antenna.js';
import { packedClipSchema } from '@/models/json-schema/clip.js';
import { packedFederationInstanceSchema } from '@/models/json-schema/federation-instance.js';
import { packedQueueCountSchema } from '@/models/json-schema/queue.js';
import { packedGalleryPostSchema } from '@/models/json-schema/gallery-post.js';
import { packedEmojiDetailedSchema, packedEmojiSimpleSchema } from '@/models/json-schema/emoji.js';
import { packedFlashSchema } from '@/models/json-schema/flash.js';
export const refs = {
UserLite: packedUserLiteSchema,
UserDetailedNotMeOnly: packedUserDetailedNotMeOnlySchema,
MeDetailedOnly: packedMeDetailedOnlySchema,
UserDetailedNotMe: packedUserDetailedNotMeSchema,
MeDetailed: packedMeDetailedSchema,
UserDetailed: packedUserDetailedSchema,
User: packedUserSchema,
UserList: packedUserListSchema,
App: packedAppSchema,
Note: packedNoteSchema,
NoteReaction: packedNoteReactionSchema,
NoteFavorite: packedNoteFavoriteSchema,
Notification: packedNotificationSchema,
DriveFile: packedDriveFileSchema,
DriveFolder: packedDriveFolderSchema,
Following: packedFollowingSchema,
Muting: packedMutingSchema,
RenoteMuting: packedRenoteMutingSchema,
Blocking: packedBlockingSchema,
Hashtag: packedHashtagSchema,
Page: packedPageSchema,
Channel: packedChannelSchema,
QueueCount: packedQueueCountSchema,
Antenna: packedAntennaSchema,
Clip: packedClipSchema,
FederationInstance: packedFederationInstanceSchema,
GalleryPost: packedGalleryPostSchema,
EmojiSimple: packedEmojiSimpleSchema,
EmojiDetailed: packedEmojiDetailedSchema,
Flash: packedFlashSchema,
};
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any';
type StringDefToType<T extends TypeStringef> =
T extends 'null' ? null :
T extends 'boolean' ? boolean :
T extends 'integer' ? number :
T extends 'number' ? number :
T extends 'string' ? string | Date :
T extends 'array' ? ReadonlyArray<any> :
T extends 'object' ? Record<string, any> :
any;
// https://swagger.io/specification/?sbsearch=optional#schema-object
type OfSchema = {
readonly anyOf?: ReadonlyArray<Schema>;
readonly oneOf?: ReadonlyArray<Schema>;
readonly allOf?: ReadonlyArray<Schema>;
}
export interface Schema extends OfSchema {
readonly type?: TypeStringef;
readonly nullable?: boolean;
readonly optional?: boolean;
readonly items?: Schema;
readonly properties?: Obj;
readonly required?: ReadonlyArray<Extract<keyof NonNullable<this['properties']>, string>>;
readonly description?: string;
readonly example?: any;
readonly format?: string;
readonly ref?: keyof typeof refs;
readonly enum?: ReadonlyArray<string | null>;
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
readonly maxLength?: number;
readonly minLength?: number;
readonly maximum?: number;
readonly minimum?: number;
readonly pattern?: string;
}
type RequiredPropertyNames<s extends Obj> = {
[K in keyof s]:
// K is not optional
s[K]['optional'] extends false ? K :
// K has default value
s[K]['default'] extends null | string | number | boolean | Record<string, unknown> ? K :
never
}[keyof s];
export type Obj = Record<string, Schema>;
// https://github.com/misskey-dev/misskey/issues/8535
// To avoid excessive stack depth error,
// deceive TypeScript with UnionToIntersection (or more precisely, `infer` expression within it).
export type ObjType<s extends Obj, RequiredProps extends ReadonlyArray<keyof s>> =
UnionToIntersection<
{ -readonly [R in RequiredPropertyNames<s>]-?: SchemaType<s[R]> } &
{ -readonly [R in RequiredProps[number]]-?: SchemaType<s[R]> } &
{ -readonly [P in keyof s]?: SchemaType<s[P]> }
>;
type NullOrUndefined<p extends Schema, T> =
| (p['nullable'] extends true ? null : never)
| (p['optional'] extends true ? undefined : never)
| T;
// https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
// Get intersection from union
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type PartialIntersection<T> = Partial<UnionToIntersection<T>>;
// https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552
// To get union, we use `Foo extends any ? Hoge<Foo> : never`
type UnionSchemaType<a extends readonly any[], X extends Schema = a[number]> = X extends any ? SchemaType<X> : never;
//type UnionObjectSchemaType<a extends readonly any[], X extends Schema = a[number]> = X extends any ? ObjectSchemaType<X> : never;
type UnionObjType<s extends Obj, a extends readonly any[], X extends ReadonlyArray<keyof s> = a[number]> = X extends any ? ObjType<s, X> : never;
type ArrayUnion<T> = T extends any ? Array<T> : never;
type ObjectSchemaTypeDef<p extends Schema> =
p['ref'] extends keyof typeof refs ? Packed<p['ref']> :
p['properties'] extends NonNullable<Obj> ?
p['anyOf'] extends ReadonlyArray<Schema> ? p['anyOf'][number]['required'] extends ReadonlyArray<keyof p['properties']> ?
UnionObjType<p['properties'], NonNullable<p['anyOf'][number]['required']>> & ObjType<p['properties'], NonNullable<p['required']>>
: never
: ObjType<p['properties'], NonNullable<p['required']>>
:
p['anyOf'] extends ReadonlyArray<Schema> ? never : // see CONTRIBUTING.md
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
any
type ObjectSchemaType<p extends Schema> = NullOrUndefined<p, ObjectSchemaTypeDef<p>>;
export type SchemaTypeDef<p extends Schema> =
p['type'] extends 'null' ? null :
p['type'] extends 'integer' ? number :
p['type'] extends 'number' ? number :
p['type'] extends 'string' ? (
p['enum'] extends readonly (string | null)[] ?
p['enum'][number] :
p['format'] extends 'date-time' ? string : // Dateにする
string
) :
p['type'] extends 'boolean' ? boolean :
p['type'] extends 'object' ? ObjectSchemaTypeDef<p> :
p['type'] extends 'array' ? (
p['items'] extends OfSchema ? (
p['items']['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<NonNullable<p['items']['anyOf']>>[] :
p['items']['oneOf'] extends ReadonlyArray<Schema> ? ArrayUnion<UnionSchemaType<NonNullable<p['items']['oneOf']>>> :
p['items']['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] :
never
) :
p['items'] extends NonNullable<Schema> ? SchemaTypeDef<p['items']>[] :
any[]
) :
p['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['anyOf']> & PartialIntersection<UnionSchemaType<p['anyOf']>> :
p['oneOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['oneOf']> :
any;
export type SchemaType<p extends Schema> = NullOrUndefined<p, SchemaTypeDef<p>>;

View file

@ -1,6 +1,6 @@
import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm';
import { id } from '../id.js';
import { mutedNoteReasons } from '../../types.js';
import { mutedNoteReasons } from 'misskey-js';
import { Note } from './Note.js';
import { User } from './User.js';

View file

@ -1,6 +1,6 @@
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
import { id } from '../id.js';
import { noteVisibilities } from '../../types.js';
import { noteVisibilities } from 'misskey-js';
import { User } from './User.js';
import { Channel } from './Channel.js';
import type { DriveFile } from './DriveFile.js';

View file

@ -1,4 +1,4 @@
import { notificationTypes } from '@/types.js';
import { ACHIEVEMENT_TYPES, notificationTypes } from 'misskey-js';
import { User } from './User.js';
import { Note } from './Note.js';
import { FollowRequest } from './FollowRequest.js';
@ -39,7 +39,7 @@ export type Notification = {
choice: number | null;
achievement: string | null;
achievement: typeof ACHIEVEMENT_TYPES[number] | null;
/**
* body

View file

@ -1,6 +1,6 @@
import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm';
import { id } from '../id.js';
import { noteVisibilities } from '../../types.js';
import { noteVisibilities } from 'misskey-js';
import { Note } from './Note.js';
import type { User } from './User.js';

View file

@ -1,83 +1,6 @@
import { Entity, Column, PrimaryColumn } from 'typeorm';
import { id } from '../id.js';
type CondFormulaValueAnd = {
type: 'and';
values: RoleCondFormulaValue[];
};
type CondFormulaValueOr = {
type: 'or';
values: RoleCondFormulaValue[];
};
type CondFormulaValueNot = {
type: 'not';
value: RoleCondFormulaValue;
};
type CondFormulaValueIsLocal = {
type: 'isLocal';
};
type CondFormulaValueIsRemote = {
type: 'isRemote';
};
type CondFormulaValueCreatedLessThan = {
type: 'createdLessThan';
sec: number;
};
type CondFormulaValueCreatedMoreThan = {
type: 'createdMoreThan';
sec: number;
};
type CondFormulaValueFollowersLessThanOrEq = {
type: 'followersLessThanOrEq';
value: number;
};
type CondFormulaValueFollowersMoreThanOrEq = {
type: 'followersMoreThanOrEq';
value: number;
};
type CondFormulaValueFollowingLessThanOrEq = {
type: 'followingLessThanOrEq';
value: number;
};
type CondFormulaValueFollowingMoreThanOrEq = {
type: 'followingMoreThanOrEq';
value: number;
};
type CondFormulaValueNotesLessThanOrEq = {
type: 'notesLessThanOrEq';
value: number;
};
type CondFormulaValueNotesMoreThanOrEq = {
type: 'notesMoreThanOrEq';
value: number;
};
export type RoleCondFormulaValue =
CondFormulaValueAnd |
CondFormulaValueOr |
CondFormulaValueNot |
CondFormulaValueIsLocal |
CondFormulaValueIsRemote |
CondFormulaValueCreatedLessThan |
CondFormulaValueCreatedMoreThan |
CondFormulaValueFollowersLessThanOrEq |
CondFormulaValueFollowersMoreThanOrEq |
CondFormulaValueFollowingLessThanOrEq |
CondFormulaValueFollowingMoreThanOrEq |
CondFormulaValueNotesLessThanOrEq |
CondFormulaValueNotesMoreThanOrEq;
import type { RoleCondFormulaValue } from 'misskey-js/built/schemas/role.js';
@Entity()
export class Role {

View file

@ -1,5 +1,5 @@
import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
import { obsoleteNotificationTypes, ffVisibility, notificationTypes } from '@/types.js';
import { obsoleteNotificationTypes, ffVisibility, notificationTypes } from 'misskey-js';
import { id } from '../id.js';
import { User } from './User.js';
import { Page } from './Page.js';

View file

@ -1,4 +1,4 @@
import { notificationTypes } from '@/types.js';
import { notificationTypes } from 'misskey-js';
export const packedNotificationSchema = {
type: 'object',

View file

@ -19,7 +19,8 @@ import { ApiLoggerService } from './ApiLoggerService.js';
import { AuthenticateService, AuthenticationError } from './AuthenticateService.js';
import type { FastifyRequest, FastifyReply } from 'fastify';
import type { OnApplicationShutdown } from '@nestjs/common';
import type { IEndpointMeta, IEndpoint } from './endpoints.js';
import type { IEndpointMeta } from 'misskey-js/built/endpoints.types.js';
import { ExecutorWrapper } from './endpoint-base.js';
const pump = promisify(pipeline);
@ -88,7 +89,7 @@ export class ApiCallService implements OnApplicationShutdown {
@bindThis
public handleRequest(
endpoint: IEndpoint & { exec: any },
endpoint: { name: string, meta: IEndpointMeta, exec: ExecutorWrapper },
request: FastifyRequest<{ Body: Record<string, unknown> | undefined, Querystring: Record<string, unknown> }>,
reply: FastifyReply,
): void {
@ -124,7 +125,7 @@ export class ApiCallService implements OnApplicationShutdown {
@bindThis
public async handleMultipartRequest(
endpoint: IEndpoint & { exec: any },
endpoint: { name: string, meta: IEndpointMeta, exec: ExecutorWrapper },
request: FastifyRequest<{ Body: Record<string, unknown>, Querystring: Record<string, unknown> }>,
reply: FastifyReply,
): Promise<void> {
@ -219,7 +220,7 @@ export class ApiCallService implements OnApplicationShutdown {
@bindThis
private async call(
ep: IEndpoint & { exec: any },
ep: { name: string, meta: IEndpointMeta, exec: ExecutorWrapper },
user: LocalUser | null | undefined,
token: AccessToken | null | undefined,
data: any,
@ -337,10 +338,13 @@ export class ApiCallService implements OnApplicationShutdown {
}
// Cast non JSON input
if ((ep.meta.requireFile || request.method === 'GET') && ep.params.properties) {
for (const k of Object.keys(ep.params.properties)) {
const param = ep.params.properties![k];
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
if ((ep.meta.requireFile || request.method === 'GET') && ep.meta.defines[0]?.req?.properties) {
for (const k of Object.keys(ep.meta.defines[0].req.properties)) {
const param = ep.meta.defines[0].req.properties[k];
if (typeof param === 'object' && (
(typeof param.type === 'string' && ['boolean', 'number', 'integer'].includes(param.type ?? '')) ||
(Array.isArray(param.type) && param.type.every(t => ['boolean', 'number', 'integer'].includes(t)))
) && typeof data[k] === 'string') {
try {
data[k] = JSON.parse(data[k]);
} catch (e) {

View file

@ -8,11 +8,12 @@ import type { UsersRepository, InstancesRepository, AccessTokensRepository } fro
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import endpoints from './endpoints.js';
import { endpoints } from 'misskey-js/built/endpoints.js';
import { ApiCallService } from './ApiCallService.js';
import { SignupApiService } from './SignupApiService.js';
import { SigninApiService } from './SigninApiService.js';
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
import { ExecutorWrapper } from './endpoint-base.js';
@Injectable()
export class ApiServerService {
@ -60,21 +61,20 @@ export class ApiServerService {
done();
});
for (const endpoint of endpoints) {
for (const [name, meta] of Object.entries(endpoints)) {
const ep = {
name: endpoint.name,
meta: endpoint.meta,
params: endpoint.params,
exec: this.moduleRef.get('ep:' + endpoint.name, { strict: false }).exec,
name,
meta,
exec: this.moduleRef.get('ep:' + name, { strict: false }).exec as ExecutorWrapper,
};
if (endpoint.meta.requireFile) {
if (meta.requireFile) {
fastify.all<{
Params: { endpoint: string; },
Body: Record<string, unknown>,
Querystring: Record<string, unknown>,
}>('/' + endpoint.name, async (request, reply) => {
if (request.method === 'GET' && !endpoint.meta.allowGet) {
}>('/' + name, async (request, reply) => {
if (request.method === 'GET' && !meta.allowGet) {
reply.code(405);
reply.send();
return;
@ -89,8 +89,8 @@ export class ApiServerService {
Params: { endpoint: string; },
Body: Record<string, unknown>,
Querystring: Record<string, unknown>,
}>('/' + endpoint.name, { bodyLimit: 1024 * 1024 }, async (request, reply) => {
if (request.method === 'GET' && !endpoint.meta.allowGet) {
}>('/' + name, { bodyLimit: 1024 * 1024 }, async (request, reply) => {
if (request.method === 'GET' && !meta.allowGet) {
reply.code(405);
reply.send();
return;

View file

@ -5,7 +5,7 @@ import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
import type { IEndpointMeta } from './endpoints.js';
import type { IEndpointMeta } from 'misskey-js/built/endpoints.types.js';
@Injectable()
export class RateLimiterService {

View file

@ -1,10 +1,12 @@
import * as fs from 'node:fs';
import _Ajv from 'ajv';
import type { Schema, SchemaType } from '@/misc/json-schema.js';
import type { LocalUser } from '@/models/entities/User.js';
import type { AccessToken } from '@/models/entities/AccessToken.js';
import { ApiError } from './error.js';
import type { IEndpointMeta } from './endpoints.js';
import { endpoints, getEndpointSchema } from 'misskey-js/built/endpoints.js';
import type { IEndpointMeta, ResponseOf, SchemaOrUndefined } from 'misskey-js/built/endpoints.types.js';
import type { Endpoints } from 'misskey-js';
import { WeakSerialized } from 'schema-type';
const Ajv = _Ajv.default;
@ -21,21 +23,42 @@ type File = {
path: string;
};
// TODO: paramsの型をT['params']のスキーマ定義から推論する
type Executor<T extends IEndpointMeta, Ps extends Schema> =
(params: SchemaType<Ps>, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, cleanup?: () => any, ip?: string | null, headers?: Record<string, string> | null) =>
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
export type Executor<T extends IEndpointMeta, P = SchemaOrUndefined<T['defines'][number]['req'], true>> =
(
params: P,
user: LocalUser | (T['requireCredential'] extends true ? never : null),
token: AccessToken | null,
file?: File,
cleanup?: () => any,
ip?: string | null,
headers?: Record<string, string> | null
) => Promise<WeakSerialized<ResponseOf<T, P, true>>>;
export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
public exec: (params: any, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record<string, string> | null) => Promise<any>;
// ExecutorWrapperの型はあえて緩くしておく
export type ExecutorWrapper =
(
params: any,
user: LocalUser | null,
token: AccessToken | null,
file?: File,
ip?: string | null,
headers?: Record<string, string> | null
) => Promise<any>;
constructor(meta: T, paramDef: Ps, cb: Executor<T, Ps>) {
const validate = ajv.compile(paramDef);
export abstract class Endpoint<E extends keyof Endpoints, T extends IEndpointMeta = Endpoints[E]> {
public readonly name: E;
public readonly meta: Endpoints[E];
public exec: ExecutorWrapper;
this.exec = (params: any, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record<string, string> | null) => {
constructor(cb: Executor<T>) {
this.meta = endpoints[this.name];
const req = getEndpointSchema('req', this.name);
const validate = req ? ajv.compile(req) : null;
this.exec = (params, user, token, file, ip, headers) => {
let cleanup: undefined | (() => void) = undefined;
if (meta.requireFile) {
if (this.meta.requireFile) {
cleanup = () => {
if (file) fs.unlink(file.path, () => {});
};
@ -47,7 +70,9 @@ export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
}));
}
if (validate) {
const valid = validate(params);
if (!valid) {
if (file) cleanup!();
@ -62,8 +87,12 @@ export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
});
return Promise.reject(err);
}
} else {
// validateがnullである場合、paramsがnullや空オブジェクトであるべきではあるが、
// 特にチェックはしない
}
return cb(params as SchemaType<Ps>, user, token, file, cleanup, ip, headers);
return cb(params as any, user as any, token, file, cleanup, ip, headers);
};
}
}

View file

@ -1,793 +0,0 @@
import type { Schema } from '@/misc/json-schema.js';
import { RolePolicies } from '@/core/RoleService.js';
import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
import * as ep___admin_ad_create from './endpoints/admin/ad/create.js';
import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js';
import * as ep___admin_ad_list from './endpoints/admin/ad/list.js';
import * as ep___admin_ad_update from './endpoints/admin/ad/update.js';
import * as ep___admin_announcements_create from './endpoints/admin/announcements/create.js';
import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js';
import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js';
import * as ep___admin_announcements_update from './endpoints/admin/announcements/update.js';
import * as ep___admin_deleteAllFilesOfAUser from './endpoints/admin/delete-all-files-of-a-user.js';
import * as ep___admin_drive_cleanRemoteFiles from './endpoints/admin/drive/clean-remote-files.js';
import * as ep___admin_drive_cleanup from './endpoints/admin/drive/cleanup.js';
import * as ep___admin_drive_files from './endpoints/admin/drive/files.js';
import * as ep___admin_drive_showFile from './endpoints/admin/drive/show-file.js';
import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-aliases-bulk.js';
import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js';
import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js';
import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js';
import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js';
import * as ep___admin_emoji_importZip from './endpoints/admin/emoji/import-zip.js';
import * as ep___admin_emoji_listRemote from './endpoints/admin/emoji/list-remote.js';
import * as ep___admin_emoji_list from './endpoints/admin/emoji/list.js';
import * as ep___admin_emoji_removeAliasesBulk from './endpoints/admin/emoji/remove-aliases-bulk.js';
import * as ep___admin_emoji_setAliasesBulk from './endpoints/admin/emoji/set-aliases-bulk.js';
import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-category-bulk.js';
import * as ep___admin_emoji_setLicenseBulk from './endpoints/admin/emoji/set-license-bulk.js';
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_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';
import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js';
import * as ep___invite from './endpoints/invite.js';
import * as ep___admin_promo_create from './endpoints/admin/promo/create.js';
import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js';
import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js';
import * as ep___admin_queue_inboxDelayed from './endpoints/admin/queue/inbox-delayed.js';
import * as ep___admin_queue_promote from './endpoints/admin/queue/promote.js';
import * as ep___admin_queue_stats from './endpoints/admin/queue/stats.js';
import * as ep___admin_relays_add from './endpoints/admin/relays/add.js';
import * as ep___admin_relays_list from './endpoints/admin/relays/list.js';
import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js';
import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js';
import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js';
import * as ep___admin_sendEmail from './endpoints/admin/send-email.js';
import * as ep___admin_serverInfo from './endpoints/admin/server-info.js';
import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js';
import * as ep___admin_showUser from './endpoints/admin/show-user.js';
import * as ep___admin_showUsers from './endpoints/admin/show-users.js';
import * as ep___admin_suspendUser from './endpoints/admin/suspend-user.js';
import * as ep___admin_unsuspendUser from './endpoints/admin/unsuspend-user.js';
import * as ep___admin_updateMeta from './endpoints/admin/update-meta.js';
import * as ep___admin_deleteAccount from './endpoints/admin/delete-account.js';
import * as ep___admin_updateUserNote from './endpoints/admin/update-user-note.js';
import * as ep___admin_roles_create from './endpoints/admin/roles/create.js';
import * as ep___admin_roles_delete from './endpoints/admin/roles/delete.js';
import * as ep___admin_roles_list from './endpoints/admin/roles/list.js';
import * as ep___admin_roles_show from './endpoints/admin/roles/show.js';
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
import * as ep___announcements from './endpoints/announcements.js';
import * as ep___antennas_create from './endpoints/antennas/create.js';
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
import * as ep___antennas_list from './endpoints/antennas/list.js';
import * as ep___antennas_notes from './endpoints/antennas/notes.js';
import * as ep___antennas_show from './endpoints/antennas/show.js';
import * as ep___antennas_update from './endpoints/antennas/update.js';
import * as ep___ap_get from './endpoints/ap/get.js';
import * as ep___ap_show from './endpoints/ap/show.js';
import * as ep___app_create from './endpoints/app/create.js';
import * as ep___app_show from './endpoints/app/show.js';
import * as ep___auth_accept from './endpoints/auth/accept.js';
import * as ep___auth_session_generate from './endpoints/auth/session/generate.js';
import * as ep___auth_session_show from './endpoints/auth/session/show.js';
import * as ep___auth_session_userkey from './endpoints/auth/session/userkey.js';
import * as ep___blocking_create from './endpoints/blocking/create.js';
import * as ep___blocking_delete from './endpoints/blocking/delete.js';
import * as ep___blocking_list from './endpoints/blocking/list.js';
import * as ep___channels_create from './endpoints/channels/create.js';
import * as ep___channels_featured from './endpoints/channels/featured.js';
import * as ep___channels_follow from './endpoints/channels/follow.js';
import * as ep___channels_followed from './endpoints/channels/followed.js';
import * as ep___channels_owned from './endpoints/channels/owned.js';
import * as ep___channels_show from './endpoints/channels/show.js';
import * as ep___channels_timeline from './endpoints/channels/timeline.js';
import * as ep___channels_unfollow from './endpoints/channels/unfollow.js';
import * as ep___channels_update from './endpoints/channels/update.js';
import * as ep___channels_favorite from './endpoints/channels/favorite.js';
import * as ep___channels_unfavorite from './endpoints/channels/unfavorite.js';
import * as ep___channels_myFavorites from './endpoints/channels/my-favorites.js';
import * as ep___channels_search from './endpoints/channels/search.js';
import * as ep___charts_activeUsers from './endpoints/charts/active-users.js';
import * as ep___charts_apRequest from './endpoints/charts/ap-request.js';
import * as ep___charts_drive from './endpoints/charts/drive.js';
import * as ep___charts_federation from './endpoints/charts/federation.js';
import * as ep___charts_instance from './endpoints/charts/instance.js';
import * as ep___charts_notes from './endpoints/charts/notes.js';
import * as ep___charts_user_drive from './endpoints/charts/user/drive.js';
import * as ep___charts_user_following from './endpoints/charts/user/following.js';
import * as ep___charts_user_notes from './endpoints/charts/user/notes.js';
import * as ep___charts_user_pv from './endpoints/charts/user/pv.js';
import * as ep___charts_user_reactions from './endpoints/charts/user/reactions.js';
import * as ep___charts_users from './endpoints/charts/users.js';
import * as ep___clips_addNote from './endpoints/clips/add-note.js';
import * as ep___clips_removeNote from './endpoints/clips/remove-note.js';
import * as ep___clips_create from './endpoints/clips/create.js';
import * as ep___clips_delete from './endpoints/clips/delete.js';
import * as ep___clips_list from './endpoints/clips/list.js';
import * as ep___clips_notes from './endpoints/clips/notes.js';
import * as ep___clips_show from './endpoints/clips/show.js';
import * as ep___clips_update from './endpoints/clips/update.js';
import * as ep___clips_favorite from './endpoints/clips/favorite.js';
import * as ep___clips_unfavorite from './endpoints/clips/unfavorite.js';
import * as ep___clips_myFavorites from './endpoints/clips/my-favorites.js';
import * as ep___drive from './endpoints/drive.js';
import * as ep___drive_files from './endpoints/drive/files.js';
import * as ep___drive_files_attachedNotes from './endpoints/drive/files/attached-notes.js';
import * as ep___drive_files_checkExistence from './endpoints/drive/files/check-existence.js';
import * as ep___drive_files_create from './endpoints/drive/files/create.js';
import * as ep___drive_files_delete from './endpoints/drive/files/delete.js';
import * as ep___drive_files_findByHash from './endpoints/drive/files/find-by-hash.js';
import * as ep___drive_files_find from './endpoints/drive/files/find.js';
import * as ep___drive_files_show from './endpoints/drive/files/show.js';
import * as ep___drive_files_update from './endpoints/drive/files/update.js';
import * as ep___drive_files_uploadFromUrl from './endpoints/drive/files/upload-from-url.js';
import * as ep___drive_folders from './endpoints/drive/folders.js';
import * as ep___drive_folders_create from './endpoints/drive/folders/create.js';
import * as ep___drive_folders_delete from './endpoints/drive/folders/delete.js';
import * as ep___drive_folders_find from './endpoints/drive/folders/find.js';
import * as ep___drive_folders_show from './endpoints/drive/folders/show.js';
import * as ep___drive_folders_update from './endpoints/drive/folders/update.js';
import * as ep___drive_stream from './endpoints/drive/stream.js';
import * as ep___emailAddress_available from './endpoints/email-address/available.js';
import * as ep___endpoint from './endpoints/endpoint.js';
import * as ep___endpoints from './endpoints/endpoints.js';
import * as ep___exportCustomEmojis from './endpoints/export-custom-emojis.js';
import * as ep___federation_followers from './endpoints/federation/followers.js';
import * as ep___federation_following from './endpoints/federation/following.js';
import * as ep___federation_instances from './endpoints/federation/instances.js';
import * as ep___federation_showInstance from './endpoints/federation/show-instance.js';
import * as ep___federation_updateRemoteUser from './endpoints/federation/update-remote-user.js';
import * as ep___federation_users from './endpoints/federation/users.js';
import * as ep___federation_stats from './endpoints/federation/stats.js';
import * as ep___following_create from './endpoints/following/create.js';
import * as ep___following_delete from './endpoints/following/delete.js';
import * as ep___following_invalidate from './endpoints/following/invalidate.js';
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
import * as ep___following_requests_list from './endpoints/following/requests/list.js';
import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
import * as ep___gallery_featured from './endpoints/gallery/featured.js';
import * as ep___gallery_popular from './endpoints/gallery/popular.js';
import * as ep___gallery_posts from './endpoints/gallery/posts.js';
import * as ep___gallery_posts_create from './endpoints/gallery/posts/create.js';
import * as ep___gallery_posts_delete from './endpoints/gallery/posts/delete.js';
import * as ep___gallery_posts_like from './endpoints/gallery/posts/like.js';
import * as ep___gallery_posts_show from './endpoints/gallery/posts/show.js';
import * as ep___gallery_posts_unlike from './endpoints/gallery/posts/unlike.js';
import * as ep___gallery_posts_update from './endpoints/gallery/posts/update.js';
import * as ep___getOnlineUsersCount from './endpoints/get-online-users-count.js';
import * as ep___hashtags_list from './endpoints/hashtags/list.js';
import * as ep___hashtags_search from './endpoints/hashtags/search.js';
import * as ep___hashtags_show from './endpoints/hashtags/show.js';
import * as ep___hashtags_trend from './endpoints/hashtags/trend.js';
import * as ep___hashtags_users from './endpoints/hashtags/users.js';
import * as ep___i from './endpoints/i.js';
import * as ep___i_2fa_done from './endpoints/i/2fa/done.js';
import * as ep___i_2fa_keyDone from './endpoints/i/2fa/key-done.js';
import * as ep___i_2fa_passwordLess from './endpoints/i/2fa/password-less.js';
import * as ep___i_2fa_registerKey from './endpoints/i/2fa/register-key.js';
import * as ep___i_2fa_register from './endpoints/i/2fa/register.js';
import * as ep___i_2fa_updateKey from './endpoints/i/2fa/update-key.js';
import * as ep___i_2fa_removeKey from './endpoints/i/2fa/remove-key.js';
import * as ep___i_2fa_unregister from './endpoints/i/2fa/unregister.js';
import * as ep___i_apps from './endpoints/i/apps.js';
import * as ep___i_authorizedApps from './endpoints/i/authorized-apps.js';
import * as ep___i_claimAchievement from './endpoints/i/claim-achievement.js';
import * as ep___i_changePassword from './endpoints/i/change-password.js';
import * as ep___i_deleteAccount from './endpoints/i/delete-account.js';
import * as ep___i_exportBlocking from './endpoints/i/export-blocking.js';
import * as ep___i_exportFollowing from './endpoints/i/export-following.js';
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';
import * as ep___i_getWordMutedNotesCount from './endpoints/i/get-word-muted-notes-count.js';
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';
import * as ep___i_pin from './endpoints/i/pin.js';
import * as ep___i_readAllUnreadNotes from './endpoints/i/read-all-unread-notes.js';
import * as ep___i_readAnnouncement from './endpoints/i/read-announcement.js';
import * as ep___i_regenerateToken from './endpoints/i/regenerate-token.js';
import * as ep___i_registry_getAll from './endpoints/i/registry/get-all.js';
import * as ep___i_registry_getDetail from './endpoints/i/registry/get-detail.js';
import * as ep___i_registry_get from './endpoints/i/registry/get.js';
import * as ep___i_registry_keysWithType from './endpoints/i/registry/keys-with-type.js';
import * as ep___i_registry_keys from './endpoints/i/registry/keys.js';
import * as ep___i_registry_remove from './endpoints/i/registry/remove.js';
import * as ep___i_registry_scopes from './endpoints/i/registry/scopes.js';
import * as ep___i_registry_set from './endpoints/i/registry/set.js';
import * as ep___i_revokeToken from './endpoints/i/revoke-token.js';
import * as ep___i_signinHistory from './endpoints/i/signin-history.js';
import * as ep___i_unpin from './endpoints/i/unpin.js';
import * as ep___i_updateEmail from './endpoints/i/update-email.js';
import * as ep___i_update from './endpoints/i/update.js';
import * as ep___i_move from './endpoints/i/move.js';
import * as ep___i_webhooks_create from './endpoints/i/webhooks/create.js';
import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js';
import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js';
import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js';
import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js';
import * as ep___meta from './endpoints/meta.js';
import * as ep___emojis from './endpoints/emojis.js';
import * as ep___emoji from './endpoints/emoji.js';
import * as ep___miauth_genToken from './endpoints/miauth/gen-token.js';
import * as ep___mute_create from './endpoints/mute/create.js';
import * as ep___mute_delete from './endpoints/mute/delete.js';
import * as ep___mute_list from './endpoints/mute/list.js';
import * as ep___renoteMute_create from './endpoints/renote-mute/create.js';
import * as ep___renoteMute_delete from './endpoints/renote-mute/delete.js';
import * as ep___renoteMute_list from './endpoints/renote-mute/list.js';
import * as ep___my_apps from './endpoints/my/apps.js';
import * as ep___notes from './endpoints/notes.js';
import * as ep___notes_children from './endpoints/notes/children.js';
import * as ep___notes_clips from './endpoints/notes/clips.js';
import * as ep___notes_conversation from './endpoints/notes/conversation.js';
import * as ep___notes_create from './endpoints/notes/create.js';
import * as ep___notes_delete from './endpoints/notes/delete.js';
import * as ep___notes_favorites_create from './endpoints/notes/favorites/create.js';
import * as ep___notes_favorites_delete from './endpoints/notes/favorites/delete.js';
import * as ep___notes_featured from './endpoints/notes/featured.js';
import * as ep___notes_globalTimeline from './endpoints/notes/global-timeline.js';
import * as ep___notes_hybridTimeline from './endpoints/notes/hybrid-timeline.js';
import * as ep___notes_localTimeline from './endpoints/notes/local-timeline.js';
import * as ep___notes_mentions from './endpoints/notes/mentions.js';
import * as ep___notes_polls_recommendation from './endpoints/notes/polls/recommendation.js';
import * as ep___notes_polls_vote from './endpoints/notes/polls/vote.js';
import * as ep___notes_reactions from './endpoints/notes/reactions.js';
import * as ep___notes_reactions_create from './endpoints/notes/reactions/create.js';
import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js';
import * as ep___notes_renotes from './endpoints/notes/renotes.js';
import * as ep___notes_replies from './endpoints/notes/replies.js';
import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js';
import * as ep___notes_search from './endpoints/notes/search.js';
import * as ep___notes_show from './endpoints/notes/show.js';
import * as ep___notes_state from './endpoints/notes/state.js';
import * as ep___notes_threadMuting_create from './endpoints/notes/thread-muting/create.js';
import * as ep___notes_threadMuting_delete from './endpoints/notes/thread-muting/delete.js';
import * as ep___notes_timeline from './endpoints/notes/timeline.js';
import * as ep___notes_translate from './endpoints/notes/translate.js';
import * as ep___notes_unrenote from './endpoints/notes/unrenote.js';
import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js';
import * as ep___notifications_create from './endpoints/notifications/create.js';
import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js';
import * as ep___pagePush from './endpoints/page-push.js';
import * as ep___pages_create from './endpoints/pages/create.js';
import * as ep___pages_delete from './endpoints/pages/delete.js';
import * as ep___pages_featured from './endpoints/pages/featured.js';
import * as ep___pages_like from './endpoints/pages/like.js';
import * as ep___pages_show from './endpoints/pages/show.js';
import * as ep___pages_unlike from './endpoints/pages/unlike.js';
import * as ep___pages_update from './endpoints/pages/update.js';
import * as ep___flash_create from './endpoints/flash/create.js';
import * as ep___flash_delete from './endpoints/flash/delete.js';
import * as ep___flash_featured from './endpoints/flash/featured.js';
import * as ep___flash_like from './endpoints/flash/like.js';
import * as ep___flash_show from './endpoints/flash/show.js';
import * as ep___flash_unlike from './endpoints/flash/unlike.js';
import * as ep___flash_update from './endpoints/flash/update.js';
import * as ep___flash_my from './endpoints/flash/my.js';
import * as ep___flash_myLikes from './endpoints/flash/my-likes.js';
import * as ep___ping from './endpoints/ping.js';
import * as ep___pinnedUsers from './endpoints/pinned-users.js';
import * as ep___promo_read from './endpoints/promo/read.js';
import * as ep___roles_list from './endpoints/roles/list.js';
import * as ep___roles_show from './endpoints/roles/show.js';
import * as ep___roles_users from './endpoints/roles/users.js';
import * as ep___roles_notes from './endpoints/roles/notes.js';
import * as ep___requestResetPassword from './endpoints/request-reset-password.js';
import * as ep___resetDb from './endpoints/reset-db.js';
import * as ep___resetPassword from './endpoints/reset-password.js';
import * as ep___serverInfo from './endpoints/server-info.js';
import * as ep___stats from './endpoints/stats.js';
import * as ep___sw_show_registration from './endpoints/sw/show-registration.js';
import * as ep___sw_update_registration from './endpoints/sw/update-registration.js';
import * as ep___sw_register from './endpoints/sw/register.js';
import * as ep___sw_unregister from './endpoints/sw/unregister.js';
import * as ep___test from './endpoints/test.js';
import * as ep___username_available from './endpoints/username/available.js';
import * as ep___users from './endpoints/users.js';
import * as ep___users_clips from './endpoints/users/clips.js';
import * as ep___users_followers from './endpoints/users/followers.js';
import * as ep___users_following from './endpoints/users/following.js';
import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js';
import * as ep___users_getFrequentlyRepliedUsers from './endpoints/users/get-frequently-replied-users.js';
import * as ep___users_lists_create from './endpoints/users/lists/create.js';
import * as ep___users_lists_delete from './endpoints/users/lists/delete.js';
import * as ep___users_lists_list from './endpoints/users/lists/list.js';
import * as ep___users_lists_pull from './endpoints/users/lists/pull.js';
import * as ep___users_lists_push from './endpoints/users/lists/push.js';
import * as ep___users_lists_show from './endpoints/users/lists/show.js';
import * as ep___users_lists_favorite from './endpoints/users/lists/favorite.js';
import * as ep___users_lists_unfavorite from './endpoints/users/lists/unfavorite.js';
import * as ep___users_lists_create_from_public from './endpoints/users/lists/create-from-public.js';
import * as ep___users_lists_update from './endpoints/users/lists/update.js';
import * as ep___users_notes from './endpoints/users/notes.js';
import * as ep___users_pages from './endpoints/users/pages.js';
import * as ep___users_reactions from './endpoints/users/reactions.js';
import * as ep___users_recommendation from './endpoints/users/recommendation.js';
import * as ep___users_relation from './endpoints/users/relation.js';
import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js';
import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js';
import * as ep___users_search from './endpoints/users/search.js';
import * as ep___users_show from './endpoints/users/show.js';
import * as ep___users_achievements from './endpoints/users/achievements.js';
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
import * as ep___fetchRss from './endpoints/fetch-rss.js';
import * as ep___retention from './endpoints/retention.js';
const eps = [
['admin/meta', ep___admin_meta],
['admin/abuse-user-reports', ep___admin_abuseUserReports],
['admin/accounts/create', ep___admin_accounts_create],
['admin/accounts/delete', ep___admin_accounts_delete],
['admin/ad/create', ep___admin_ad_create],
['admin/ad/delete', ep___admin_ad_delete],
['admin/ad/list', ep___admin_ad_list],
['admin/ad/update', ep___admin_ad_update],
['admin/announcements/create', ep___admin_announcements_create],
['admin/announcements/delete', ep___admin_announcements_delete],
['admin/announcements/list', ep___admin_announcements_list],
['admin/announcements/update', ep___admin_announcements_update],
['admin/delete-all-files-of-a-user', ep___admin_deleteAllFilesOfAUser],
['admin/drive/clean-remote-files', ep___admin_drive_cleanRemoteFiles],
['admin/drive/cleanup', ep___admin_drive_cleanup],
['admin/drive/files', ep___admin_drive_files],
['admin/drive/show-file', ep___admin_drive_showFile],
['admin/emoji/add-aliases-bulk', ep___admin_emoji_addAliasesBulk],
['admin/emoji/add', ep___admin_emoji_add],
['admin/emoji/copy', ep___admin_emoji_copy],
['admin/emoji/delete-bulk', ep___admin_emoji_deleteBulk],
['admin/emoji/delete', ep___admin_emoji_delete],
['admin/emoji/import-zip', ep___admin_emoji_importZip],
['admin/emoji/list-remote', ep___admin_emoji_listRemote],
['admin/emoji/list', ep___admin_emoji_list],
['admin/emoji/remove-aliases-bulk', ep___admin_emoji_removeAliasesBulk],
['admin/emoji/set-aliases-bulk', ep___admin_emoji_setAliasesBulk],
['admin/emoji/set-category-bulk', ep___admin_emoji_setCategoryBulk],
['admin/emoji/set-license-bulk', ep___admin_emoji_setLicenseBulk],
['admin/emoji/update', ep___admin_emoji_update],
['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/update-instance', ep___admin_federation_updateInstance],
['admin/get-index-stats', ep___admin_getIndexStats],
['admin/get-table-stats', ep___admin_getTableStats],
['admin/get-user-ips', ep___admin_getUserIps],
['invite', ep___invite],
['admin/promo/create', ep___admin_promo_create],
['admin/queue/clear', ep___admin_queue_clear],
['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed],
['admin/queue/inbox-delayed', ep___admin_queue_inboxDelayed],
['admin/queue/promote', ep___admin_queue_promote],
['admin/queue/stats', ep___admin_queue_stats],
['admin/relays/add', ep___admin_relays_add],
['admin/relays/list', ep___admin_relays_list],
['admin/relays/remove', ep___admin_relays_remove],
['admin/reset-password', ep___admin_resetPassword],
['admin/resolve-abuse-user-report', ep___admin_resolveAbuseUserReport],
['admin/send-email', ep___admin_sendEmail],
['admin/server-info', ep___admin_serverInfo],
['admin/show-moderation-logs', ep___admin_showModerationLogs],
['admin/show-user', ep___admin_showUser],
['admin/show-users', ep___admin_showUsers],
['admin/suspend-user', ep___admin_suspendUser],
['admin/unsuspend-user', ep___admin_unsuspendUser],
['admin/update-meta', ep___admin_updateMeta],
['admin/delete-account', ep___admin_deleteAccount],
['admin/update-user-note', ep___admin_updateUserNote],
['admin/roles/create', ep___admin_roles_create],
['admin/roles/delete', ep___admin_roles_delete],
['admin/roles/list', ep___admin_roles_list],
['admin/roles/show', ep___admin_roles_show],
['admin/roles/update', ep___admin_roles_update],
['admin/roles/assign', ep___admin_roles_assign],
['admin/roles/unassign', ep___admin_roles_unassign],
['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
['admin/roles/users', ep___admin_roles_users],
['announcements', ep___announcements],
['antennas/create', ep___antennas_create],
['antennas/delete', ep___antennas_delete],
['antennas/list', ep___antennas_list],
['antennas/notes', ep___antennas_notes],
['antennas/show', ep___antennas_show],
['antennas/update', ep___antennas_update],
['ap/get', ep___ap_get],
['ap/show', ep___ap_show],
['app/create', ep___app_create],
['app/show', ep___app_show],
['auth/accept', ep___auth_accept],
['auth/session/generate', ep___auth_session_generate],
['auth/session/show', ep___auth_session_show],
['auth/session/userkey', ep___auth_session_userkey],
['blocking/create', ep___blocking_create],
['blocking/delete', ep___blocking_delete],
['blocking/list', ep___blocking_list],
['channels/create', ep___channels_create],
['channels/featured', ep___channels_featured],
['channels/follow', ep___channels_follow],
['channels/followed', ep___channels_followed],
['channels/owned', ep___channels_owned],
['channels/show', ep___channels_show],
['channels/timeline', ep___channels_timeline],
['channels/unfollow', ep___channels_unfollow],
['channels/update', ep___channels_update],
['channels/favorite', ep___channels_favorite],
['channels/unfavorite', ep___channels_unfavorite],
['channels/my-favorites', ep___channels_myFavorites],
['channels/search', ep___channels_search],
['charts/active-users', ep___charts_activeUsers],
['charts/ap-request', ep___charts_apRequest],
['charts/drive', ep___charts_drive],
['charts/federation', ep___charts_federation],
['charts/instance', ep___charts_instance],
['charts/notes', ep___charts_notes],
['charts/user/drive', ep___charts_user_drive],
['charts/user/following', ep___charts_user_following],
['charts/user/notes', ep___charts_user_notes],
['charts/user/pv', ep___charts_user_pv],
['charts/user/reactions', ep___charts_user_reactions],
['charts/users', ep___charts_users],
['clips/add-note', ep___clips_addNote],
['clips/remove-note', ep___clips_removeNote],
['clips/create', ep___clips_create],
['clips/delete', ep___clips_delete],
['clips/list', ep___clips_list],
['clips/notes', ep___clips_notes],
['clips/show', ep___clips_show],
['clips/update', ep___clips_update],
['clips/favorite', ep___clips_favorite],
['clips/unfavorite', ep___clips_unfavorite],
['clips/my-favorites', ep___clips_myFavorites],
['drive', ep___drive],
['drive/files', ep___drive_files],
['drive/files/attached-notes', ep___drive_files_attachedNotes],
['drive/files/check-existence', ep___drive_files_checkExistence],
['drive/files/create', ep___drive_files_create],
['drive/files/delete', ep___drive_files_delete],
['drive/files/find-by-hash', ep___drive_files_findByHash],
['drive/files/find', ep___drive_files_find],
['drive/files/show', ep___drive_files_show],
['drive/files/update', ep___drive_files_update],
['drive/files/upload-from-url', ep___drive_files_uploadFromUrl],
['drive/folders', ep___drive_folders],
['drive/folders/create', ep___drive_folders_create],
['drive/folders/delete', ep___drive_folders_delete],
['drive/folders/find', ep___drive_folders_find],
['drive/folders/show', ep___drive_folders_show],
['drive/folders/update', ep___drive_folders_update],
['drive/stream', ep___drive_stream],
['email-address/available', ep___emailAddress_available],
['endpoint', ep___endpoint],
['endpoints', ep___endpoints],
['export-custom-emojis', ep___exportCustomEmojis],
['federation/followers', ep___federation_followers],
['federation/following', ep___federation_following],
['federation/instances', ep___federation_instances],
['federation/show-instance', ep___federation_showInstance],
['federation/update-remote-user', ep___federation_updateRemoteUser],
['federation/users', ep___federation_users],
['federation/stats', ep___federation_stats],
['following/create', ep___following_create],
['following/delete', ep___following_delete],
['following/invalidate', ep___following_invalidate],
['following/requests/accept', ep___following_requests_accept],
['following/requests/cancel', ep___following_requests_cancel],
['following/requests/list', ep___following_requests_list],
['following/requests/reject', ep___following_requests_reject],
['gallery/featured', ep___gallery_featured],
['gallery/popular', ep___gallery_popular],
['gallery/posts', ep___gallery_posts],
['gallery/posts/create', ep___gallery_posts_create],
['gallery/posts/delete', ep___gallery_posts_delete],
['gallery/posts/like', ep___gallery_posts_like],
['gallery/posts/show', ep___gallery_posts_show],
['gallery/posts/unlike', ep___gallery_posts_unlike],
['gallery/posts/update', ep___gallery_posts_update],
['get-online-users-count', ep___getOnlineUsersCount],
['hashtags/list', ep___hashtags_list],
['hashtags/search', ep___hashtags_search],
['hashtags/show', ep___hashtags_show],
['hashtags/trend', ep___hashtags_trend],
['hashtags/users', ep___hashtags_users],
['i', ep___i],
['i/2fa/done', ep___i_2fa_done],
['i/2fa/key-done', ep___i_2fa_keyDone],
['i/2fa/password-less', ep___i_2fa_passwordLess],
['i/2fa/register-key', ep___i_2fa_registerKey],
['i/2fa/register', ep___i_2fa_register],
['i/2fa/update-key', ep___i_2fa_updateKey],
['i/2fa/remove-key', ep___i_2fa_removeKey],
['i/2fa/unregister', ep___i_2fa_unregister],
['i/apps', ep___i_apps],
['i/authorized-apps', ep___i_authorizedApps],
['i/claim-achievement', ep___i_claimAchievement],
['i/change-password', ep___i_changePassword],
['i/delete-account', ep___i_deleteAccount],
['i/export-blocking', ep___i_exportBlocking],
['i/export-following', ep___i_exportFollowing],
['i/export-mute', ep___i_exportMute],
['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],
['i/get-word-muted-notes-count', ep___i_getWordMutedNotesCount],
['i/import-blocking', ep___i_importBlocking],
['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],
['i/pin', ep___i_pin],
['i/read-all-unread-notes', ep___i_readAllUnreadNotes],
['i/read-announcement', ep___i_readAnnouncement],
['i/regenerate-token', ep___i_regenerateToken],
['i/registry/get-all', ep___i_registry_getAll],
['i/registry/get-detail', ep___i_registry_getDetail],
['i/registry/get', ep___i_registry_get],
['i/registry/keys-with-type', ep___i_registry_keysWithType],
['i/registry/keys', ep___i_registry_keys],
['i/registry/remove', ep___i_registry_remove],
['i/registry/scopes', ep___i_registry_scopes],
['i/registry/set', ep___i_registry_set],
['i/revoke-token', ep___i_revokeToken],
['i/signin-history', ep___i_signinHistory],
['i/unpin', ep___i_unpin],
['i/update-email', ep___i_updateEmail],
['i/update', ep___i_update],
['i/move', ep___i_move],
['i/webhooks/create', ep___i_webhooks_create],
['i/webhooks/list', ep___i_webhooks_list],
['i/webhooks/show', ep___i_webhooks_show],
['i/webhooks/update', ep___i_webhooks_update],
['i/webhooks/delete', ep___i_webhooks_delete],
['meta', ep___meta],
['emojis', ep___emojis],
['emoji', ep___emoji],
['miauth/gen-token', ep___miauth_genToken],
['mute/create', ep___mute_create],
['mute/delete', ep___mute_delete],
['mute/list', ep___mute_list],
['renote-mute/create', ep___renoteMute_create],
['renote-mute/delete', ep___renoteMute_delete],
['renote-mute/list', ep___renoteMute_list],
['my/apps', ep___my_apps],
['notes', ep___notes],
['notes/children', ep___notes_children],
['notes/clips', ep___notes_clips],
['notes/conversation', ep___notes_conversation],
['notes/create', ep___notes_create],
['notes/delete', ep___notes_delete],
['notes/favorites/create', ep___notes_favorites_create],
['notes/favorites/delete', ep___notes_favorites_delete],
['notes/featured', ep___notes_featured],
['notes/global-timeline', ep___notes_globalTimeline],
['notes/hybrid-timeline', ep___notes_hybridTimeline],
['notes/local-timeline', ep___notes_localTimeline],
['notes/mentions', ep___notes_mentions],
['notes/polls/recommendation', ep___notes_polls_recommendation],
['notes/polls/vote', ep___notes_polls_vote],
['notes/reactions', ep___notes_reactions],
['notes/reactions/create', ep___notes_reactions_create],
['notes/reactions/delete', ep___notes_reactions_delete],
['notes/renotes', ep___notes_renotes],
['notes/replies', ep___notes_replies],
['notes/search-by-tag', ep___notes_searchByTag],
['notes/search', ep___notes_search],
['notes/show', ep___notes_show],
['notes/state', ep___notes_state],
['notes/thread-muting/create', ep___notes_threadMuting_create],
['notes/thread-muting/delete', ep___notes_threadMuting_delete],
['notes/timeline', ep___notes_timeline],
['notes/translate', ep___notes_translate],
['notes/unrenote', ep___notes_unrenote],
['notes/user-list-timeline', ep___notes_userListTimeline],
['notifications/create', ep___notifications_create],
['notifications/mark-all-as-read', ep___notifications_markAllAsRead],
['page-push', ep___pagePush],
['pages/create', ep___pages_create],
['pages/delete', ep___pages_delete],
['pages/featured', ep___pages_featured],
['pages/like', ep___pages_like],
['pages/show', ep___pages_show],
['pages/unlike', ep___pages_unlike],
['pages/update', ep___pages_update],
['flash/create', ep___flash_create],
['flash/delete', ep___flash_delete],
['flash/featured', ep___flash_featured],
['flash/like', ep___flash_like],
['flash/show', ep___flash_show],
['flash/unlike', ep___flash_unlike],
['flash/update', ep___flash_update],
['flash/my', ep___flash_my],
['flash/my-likes', ep___flash_myLikes],
['ping', ep___ping],
['pinned-users', ep___pinnedUsers],
['promo/read', ep___promo_read],
['roles/list', ep___roles_list],
['roles/show', ep___roles_show],
['roles/users', ep___roles_users],
['roles/notes', ep___roles_notes],
['request-reset-password', ep___requestResetPassword],
['reset-db', ep___resetDb],
['reset-password', ep___resetPassword],
['server-info', ep___serverInfo],
['stats', ep___stats],
['sw/show-registration', ep___sw_show_registration],
['sw/update-registration', ep___sw_update_registration],
['sw/register', ep___sw_register],
['sw/unregister', ep___sw_unregister],
['test', ep___test],
['username/available', ep___username_available],
['users', ep___users],
['users/clips', ep___users_clips],
['users/followers', ep___users_followers],
['users/following', ep___users_following],
['users/gallery/posts', ep___users_gallery_posts],
['users/get-frequently-replied-users', ep___users_getFrequentlyRepliedUsers],
['users/lists/create', ep___users_lists_create],
['users/lists/delete', ep___users_lists_delete],
['users/lists/list', ep___users_lists_list],
['users/lists/pull', ep___users_lists_pull],
['users/lists/push', ep___users_lists_push],
['users/lists/show', ep___users_lists_show],
['users/lists/favorite', ep___users_lists_favorite],
['users/lists/unfavorite', ep___users_lists_unfavorite],
['users/lists/update', ep___users_lists_update],
['users/lists/create-from-public', ep___users_lists_create_from_public],
['users/notes', ep___users_notes],
['users/pages', ep___users_pages],
['users/reactions', ep___users_reactions],
['users/recommendation', ep___users_recommendation],
['users/relation', ep___users_relation],
['users/report-abuse', ep___users_reportAbuse],
['users/search-by-username-and-host', ep___users_searchByUsernameAndHost],
['users/search', ep___users_search],
['users/show', ep___users_show],
['users/achievements', ep___users_achievements],
['users/update-memo', ep___users_updateMemo],
['fetch-rss', ep___fetchRss],
['retention', ep___retention],
];
export interface IEndpointMeta {
readonly stability?: 'deprecated' | 'experimental' | 'stable';
readonly tags?: ReadonlyArray<string>;
readonly errors?: {
readonly [key: string]: {
readonly message: string;
readonly code: string;
readonly id: string;
};
};
readonly res?: Schema;
/**
*
* false
*/
readonly requireCredential?: boolean;
/**
* isModeratorなロールを必要とするか
*/
readonly requireModerator?: boolean;
/**
* isAdministratorなロールを必要とするか
*/
readonly requireAdmin?: boolean;
readonly requireRolePolicy?: keyof RolePolicies;
/**
*
* false
*/
readonly prohibitMoved?: boolean;
/**
*
*
*/
readonly limit?: {
/**
*
*/
readonly key?: string;
/**
* (ms)
* max
*/
readonly duration?: number;
/**
* durationで指定した期間内にいくつまでリクエストできるのか
* duration
*/
readonly max?: number;
/**
* (ms)
*/
readonly minInterval?: number;
};
/**
*
* false
*/
readonly requireFile?: boolean;
/**
*
* false
*/
readonly secure?: boolean;
/**
*
*
*/
readonly kind?: string;
readonly description?: string;
/**
* GETでのリクエストを許容するか否か
*/
readonly allowGet?: boolean;
/**
* (Cache-Control: public)
*/
readonly cacheSec?: number;
}
export interface IEndpoint {
name: string;
meta: IEndpointMeta;
params: Schema;
}
const endpoints: IEndpoint[] = (eps as [string, any]).map(([name, ep]) => {
return {
name: name,
get meta() { return ep.meta ?? {}; },
get params() { return ep.paramDef; },
};
});
export default endpoints;

View file

@ -5,91 +5,10 @@ import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { AbuseUserReportEntityService } from '@/core/entities/AbuseUserReportEntityService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
nullable: false, optional: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
nullable: false, optional: false,
format: 'date-time',
},
comment: {
type: 'string',
nullable: false, optional: false,
},
resolved: {
type: 'boolean',
nullable: false, optional: false,
example: false,
},
reporterId: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
targetUserId: {
type: 'string',
nullable: false, optional: false,
format: 'id',
},
assigneeId: {
type: 'string',
nullable: true, optional: false,
format: 'id',
},
reporter: {
type: 'object',
nullable: false, optional: false,
ref: 'User',
},
targetUser: {
type: 'object',
nullable: false, optional: false,
ref: 'User',
},
assignee: {
type: 'object',
nullable: true, optional: true,
ref: 'User',
},
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
state: { type: 'string', nullable: true, default: null },
reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
forwarded: { type: 'boolean', default: false },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/abuse-user-reports'> {
name = 'admin/abuse-user-reports' as const;
constructor(
@Inject(DI.abuseUserReportsRepository)
private abuseUserReportsRepository: AbuseUserReportsRepository,
@ -97,7 +16,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private abuseUserReportEntityService: AbuseUserReportEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId);
switch (ps.state) {

View file

@ -7,34 +7,10 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { localUsernameSchema, passwordSchema } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
res: {
type: 'object',
optional: false, nullable: false,
ref: 'User',
properties: {
token: {
type: 'string',
optional: false, nullable: false,
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
username: localUsernameSchema,
password: passwordSchema,
},
required: ['username', 'password'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/accounts/create'> {
name = 'admin/accounts/create' as const;
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@ -42,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private userEntityService: UserEntityService,
private signupService: SignupService,
) {
super(meta, paramDef, async (ps, _me) => {
super(async (ps, _me) => {
const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null;
const noUsers = (await this.usersRepository.countBy({
host: IsNull(),
@ -55,14 +31,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
ignorePreservedUsernames: true,
});
const res = await this.userEntityService.pack(account, account, {
const res = await this.userEntityService.pack<true, true>(account, account, {
detail: true,
includeSecrets: true,
});
(res as any).token = secret;
return res;
return { ...res, token: secret };
});
}
}

View file

@ -7,24 +7,10 @@ import { UserSuspendService } from '@/core/UserSuspendService.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireAdmin: true,
} as const;
export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/accounts/delete'> {
name = 'admin/accounts/delete' as const;
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@ -34,7 +20,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService,
private userSuspendService: UserSuspendService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });
if (user == null) {

View file

@ -4,38 +4,17 @@ import type { AdsRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
export const paramDef = {
type: 'object',
properties: {
url: { type: 'string', minLength: 1 },
memo: { type: 'string' },
place: { type: 'string' },
priority: { type: 'string' },
ratio: { type: 'integer' },
expiresAt: { type: 'integer' },
startsAt: { type: 'integer' },
imageUrl: { type: 'string', minLength: 1 },
},
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/ad/create'> {
name = 'admin/ad/create' as const;
constructor(
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.adsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),

View file

@ -4,40 +4,18 @@ import type { AdsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: {
noSuchAd: {
message: 'No such ad.',
code: 'NO_SUCH_AD',
id: 'ccac9863-3a03-416e-b899-8a64041118b1',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/ad/delete'> {
name = 'admin/ad/delete' as const;
constructor(
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const ad = await this.adsRepository.findOneBy({ id: ps.id });
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
if (ad == null) throw new ApiError(this.meta.errors.noSuchAd);
await this.adsRepository.delete(ad.id);
});

View file

@ -23,14 +23,15 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/ad/list'> {
name = 'admin/ad/list' as const;
constructor(
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
const ads = await query.take(ps.limit).getMany();

View file

@ -4,48 +4,18 @@ import type { AdsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: {
noSuchAd: {
message: 'No such ad.',
code: 'NO_SUCH_AD',
id: 'b7aa1727-1354-47bc-a182-3a9c3973d300',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
memo: { type: 'string' },
url: { type: 'string', minLength: 1 },
imageUrl: { type: 'string', minLength: 1 },
place: { type: 'string' },
priority: { type: 'string' },
ratio: { type: 'integer' },
expiresAt: { type: 'integer' },
startsAt: { type: 'integer' },
},
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/ad/update'> {
name = 'admin/ad/update' as const;
constructor(
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const ad = await this.adsRepository.findOneBy({ id: ps.id });
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
if (ad == null) throw new ApiError(this.meta.errors.noSuchAd);
await this.adsRepository.update(ad.id, {
url: ps.url,

View file

@ -4,68 +4,17 @@ import type { AnnouncementsRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
res: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
title: {
type: 'string',
optional: false, nullable: false,
},
text: {
type: 'string',
optional: false, nullable: false,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
title: { type: 'string', minLength: 1 },
text: { type: 'string', minLength: 1 },
imageUrl: { type: 'string', nullable: true, minLength: 1 },
},
required: ['title', 'text', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/announcements/create'> {
name = 'admin/announcements/create' as const;
constructor(
@Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository,
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const announcement = await this.announcementsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),

View file

@ -4,40 +4,18 @@ import type { AnnouncementsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: {
noSuchAnnouncement: {
message: 'No such announcement.',
code: 'NO_SUCH_ANNOUNCEMENT',
id: 'ecad8040-a276-4e85-bda9-015a708d291e',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/announcements/delete'> {
name = 'admin/announcements/delete' as const;
constructor(
@Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
if (announcement == null) throw new ApiError(this.meta.errors.noSuchAnnouncement);
await this.announcementsRepository.delete(announcement.id);
});

View file

@ -5,69 +5,10 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
updatedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
text: {
type: 'string',
optional: false, nullable: false,
},
title: {
type: 'string',
optional: false, nullable: false,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
},
reads: {
type: 'number',
optional: false, nullable: false,
},
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/announcements/list'> {
name = 'admin/announcements/list' as const;
constructor(
@Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository,
@ -77,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
const announcements = await query.take(ps.limit).getMany();

View file

@ -4,43 +4,18 @@ import type { AnnouncementsRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: {
noSuchAnnouncement: {
message: 'No such announcement.',
code: 'NO_SUCH_ANNOUNCEMENT',
id: 'd3aae5a7-6372-4cb4-b61c-f511ffc2d7cc',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
title: { type: 'string', minLength: 1 },
text: { type: 'string', minLength: 1 },
imageUrl: { type: 'string', nullable: true, minLength: 0 },
},
required: ['id', 'title', 'text', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/announcements/update'> {
name = 'admin/announcements/update' as const;
constructor(
@Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
if (announcement == null) throw new ApiError(this.meta.errors.noSuchAnnouncement);
await this.announcementsRepository.update(announcement.id, {
updatedAt: new Date(),

View file

@ -4,34 +4,17 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { DeleteAccountService } from '@/core/DeleteAccountService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireAdmin: true,
res: {
},
} as const;
export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/delete-account'> {
name = 'admin/delete-account' as const;
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private deleteAccountService: DeleteAccountService,
) {
super(meta, paramDef, async (ps) => {
super(async (ps) => {
const user = await this.usersRepository.findOneByOrFail({ id: ps.userId });
if (user.isDeleted) {
return;

View file

@ -4,31 +4,17 @@ import type { DriveFilesRepository } from '@/models/index.js';
import { DriveService } from '@/core/DriveService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireAdmin: true,
} as const;
export const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/delete-all-files-of-a-user'> {
name = 'admin/delete-all-files-of-a-user' as const;
constructor(
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
private driveService: DriveService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const files = await this.driveFilesRepository.findBy({
userId: ps.userId,
});

View file

@ -2,26 +2,14 @@ import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
export const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/drive/clean-remote-files'> {
name = 'admin/drive/clean-remote-files' as const;
constructor(
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
this.queueService.createCleanRemoteFilesJob();
});
}

View file

@ -5,29 +5,17 @@ import type { DriveFilesRepository } from '@/models/index.js';
import { DriveService } from '@/core/DriveService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
export const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/drive/cleanup'> {
name = 'admin/drive/cleanup' as const;
constructor(
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
private driveService: DriveService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const files = await this.driveFilesRepository.findBy({
userId: IsNull(),
});

View file

@ -5,45 +5,10 @@ import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
ref: 'DriveFile',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
userId: { type: 'string', format: 'misskey:id', nullable: true },
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) },
origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' },
hostname: {
type: 'string',
nullable: true,
default: null,
description: 'The local host is represented with `null`.',
},
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/drive/files'> {
name = 'admin/drive/files' as const;
constructor(
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@ -51,7 +16,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private driveFileEntityService: DriveFileEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId);
if (ps.userId) {

View file

@ -5,152 +5,10 @@ import { DI } from '@/di-symbols.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: 'caf3ca38-c6e5-472e-a30c-b05377dcc240',
},
},
res: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
userId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
userHost: {
type: 'string',
optional: false, nullable: true,
description: 'The local host is represented with `null`.',
},
md5: {
type: 'string',
optional: false, nullable: false,
format: 'md5',
example: '15eca7fba0480996e2245f5185bf39f2',
},
name: {
type: 'string',
optional: false, nullable: false,
example: 'lenna.jpg',
},
type: {
type: 'string',
optional: false, nullable: false,
example: 'image/jpeg',
},
size: {
type: 'number',
optional: false, nullable: false,
example: 51469,
},
comment: {
type: 'string',
optional: false, nullable: true,
},
blurhash: {
type: 'string',
optional: false, nullable: true,
},
properties: {
type: 'object',
optional: false, nullable: false,
},
storedInternal: {
type: 'boolean',
optional: false, nullable: true,
example: true,
},
url: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
thumbnailUrl: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
webpublicUrl: {
type: 'string',
optional: false, nullable: true,
format: 'url',
},
accessKey: {
type: 'string',
optional: false, nullable: true,
},
thumbnailAccessKey: {
type: 'string',
optional: false, nullable: true,
},
webpublicAccessKey: {
type: 'string',
optional: false, nullable: true,
},
uri: {
type: 'string',
optional: false, nullable: true,
},
src: {
type: 'string',
optional: false, nullable: true,
},
folderId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
example: 'xxxxxxxxxx',
},
isSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
isLink: {
type: 'boolean',
optional: false, nullable: false,
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
fileId: { type: 'string', format: 'misskey:id' },
url: { type: 'string' },
},
anyOf: [
{ required: ['fileId'] },
{ required: ['url'] },
],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/drive/show-file'> {
name = 'admin/drive/show-file' as const;
constructor(
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@ -160,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const file = ps.fileId ? await this.driveFilesRepository.findOneBy({ id: ps.fileId }) : await this.driveFilesRepository.findOne({
where: [{
url: ps.url,
@ -172,7 +30,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
if (file == null) {
throw new ApiError(meta.errors.noSuchFile);
throw new ApiError(this.meta.errors.noSuchFile);
}
const owner = file.userId ? await this.usersRepository.findOneByOrFail({

View file

@ -2,33 +2,14 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
} as const;
export const paramDef = {
type: 'object',
properties: {
ids: { type: 'array', items: {
type: 'string', format: 'misskey:id',
} },
aliases: { type: 'array', items: {
type: 'string',
} },
},
required: ['ids', 'aliases'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/add-aliases-bulk'> {
name = 'admin/emoji/add-aliases-bulk' as const;
constructor(
private customEmojiService: CustomEmojiService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.customEmojiService.addAliasesBulk(ps.ids, ps.aliases);
});
}

View file

@ -6,49 +6,12 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: 'fc46b5a4-6b92-4c33-ac66-b806659bb5cf',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
name: { type: 'string', pattern: '^[a-zA-Z0-9_]+$' },
fileId: { type: 'string', format: 'misskey:id' },
category: {
type: 'string',
nullable: true,
description: 'Use `null` to reset the category.',
},
aliases: { type: 'array', items: {
type: 'string',
} },
license: { type: 'string', nullable: true },
isSensitive: { type: 'boolean' },
localOnly: { type: 'boolean' },
roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: {
type: 'string',
} },
},
required: ['name', 'fileId'],
} as const;
// TODO: ロジックをサービスに切り出す
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/add'> {
name = 'admin/emoji/add' as const;
constructor(
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
@ -57,9 +20,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
if (driveFile == null) throw new ApiError(meta.errors.noSuchFile);
if (driveFile == null) throw new ApiError(this.meta.errors.noSuchFile);
const emoji = await this.customEmojiService.add({
driveFile,

View file

@ -10,46 +10,12 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { ApiError } from '../../../error.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
errors: {
noSuchEmoji: {
message: 'No such emoji.',
code: 'NO_SUCH_EMOJI',
id: 'e2785b66-dca3-4087-9cac-b93c541cc425',
},
},
res: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
emojiId: { type: 'string', format: 'misskey:id' },
},
required: ['emojiId'],
} as const;
// TODO: ロジックをサービスに切り出す
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/copy'> {
name = 'admin/emoji/copy' as const;
constructor(
@Inject(DI.db)
private db: DataSource,
@ -62,11 +28,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService,
private driveService: DriveService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const emoji = await this.emojisRepository.findOneBy({ id: ps.emojiId });
if (emoji == null) {
throw new ApiError(meta.errors.noSuchEmoji);
throw new ApiError(this.meta.errors.noSuchEmoji);
}
let driveFile: DriveFile;

View file

@ -3,29 +3,19 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
} as const;
export const paramDef = {
type: 'object',
properties: {
ids: { type: 'array', items: {
type: 'string', format: 'misskey:id',
} },
},
required: ['ids'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/delete-bulk'> {
name = 'admin/emoji/delete-bulk' as const;
constructor(
private customEmojiService: CustomEmojiService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.customEmojiService.deleteBulk(ps.ids);
});
}

View file

@ -2,36 +2,14 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
errors: {
noSuchEmoji: {
message: 'No such emoji.',
code: 'NO_SUCH_EMOJI',
id: 'be83669b-773a-44b7-b1f8-e5e5170ac3c2',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/delete'> {
name = 'admin/emoji/delete' as const;
constructor(
private customEmojiService: CustomEmojiService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.customEmojiService.delete(ps.id);
});
}

View file

@ -18,11 +18,12 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/import-zip'> {
name = 'admin/emoji/import-zip' as const;
constructor(
private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
this.queueService.createImportCustomEmojisJob(me, ps.fileId);
});
}

View file

@ -7,74 +7,10 @@ import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { DI } from '@/di-symbols.js';
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
aliases: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
name: {
type: 'string',
optional: false, nullable: false,
},
category: {
type: 'string',
optional: false, nullable: true,
},
host: {
type: 'string',
optional: false, nullable: true,
description: 'The local host is represented with `null`.',
},
url: {
type: 'string',
optional: false, nullable: false,
},
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
query: { type: 'string', nullable: true, default: null },
host: {
type: 'string',
nullable: true,
default: null,
description: 'Use `null` to represent the local host.',
},
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/list-remote'> {
name = 'admin/emoji/list-remote' as const;
constructor(
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
@ -83,7 +19,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private queryService: QueryService,
private emojiEntityService: EmojiEntityService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId);
if (ps.host == null) {

View file

@ -7,68 +7,10 @@ import { DI } from '@/di-symbols.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
//import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
res: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
aliases: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
name: {
type: 'string',
optional: false, nullable: false,
},
category: {
type: 'string',
optional: false, nullable: true,
},
host: {
type: 'string',
optional: false, nullable: true,
description: 'The local host is represented with `null`. The field exists for compatibility with other API endpoints that return files.',
},
url: {
type: 'string',
optional: false, nullable: false,
},
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
query: { type: 'string', nullable: true, default: null },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/list'> {
name = 'admin/emoji/list' as const;
constructor(
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
@ -76,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private emojiEntityService: EmojiEntityService,
private queryService: QueryService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId)
.andWhere('emoji.host IS NULL');

View file

@ -24,11 +24,12 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/remove-aliases-bulk'> {
name = 'admin/emoji/remove-aliases-bulk' as const;
constructor(
private customEmojiService: CustomEmojiService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.customEmojiService.removeAliasesBulk(ps.ids, ps.aliases);
});
}

View file

@ -2,33 +2,14 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
} as const;
export const paramDef = {
type: 'object',
properties: {
ids: { type: 'array', items: {
type: 'string', format: 'misskey:id',
} },
aliases: { type: 'array', items: {
type: 'string',
} },
},
required: ['ids', 'aliases'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/set-aliases-bulk'> {
name = 'admin/emoji/set-aliases-bulk' as const;
constructor(
private customEmojiService: CustomEmojiService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.customEmojiService.setAliasesBulk(ps.ids, ps.aliases);
});
}

View file

@ -2,35 +2,14 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
} as const;
export const paramDef = {
type: 'object',
properties: {
ids: { type: 'array', items: {
type: 'string', format: 'misskey:id',
} },
category: {
type: 'string',
nullable: true,
description: 'Use `null` to reset the category.',
},
},
required: ['ids'],
} as const;
// eslint-disable-next-line import/no-default-export
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
export default class extends Endpoint<'admin/emoji/set-category-bulk'> {
name = 'admin/emoji/set-category-bulk' as const;
constructor(
private customEmojiService: CustomEmojiService,
) {
super(meta, paramDef, async (ps, me) => {
super(async (ps, me) => {
await this.customEmojiService.setCategoryBulk(ps.ids, ps.category ?? null);
});
}

Some files were not shown because too many files have changed in this diff Show more