refactor: use ajv instead of cafy (#8324)

* wip

* wip

* Update abuse-user-reports.ts

* Update files.ts

* Update list-remote.ts

* Update list.ts

* Update show-users.ts

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update update.ts

* Update search.ts

* Update reactions.ts

* Update search.ts

* wip

* wip

* wip

* wip

* Update update.ts

* Update relation.ts

* Update available.ts

* wip

* wip

* wip

* Update packages/backend/src/server/api/define.ts

Co-authored-by: Johann150 <johann.galle@protonmail.com>

* Update define.ts

* Update define.ts

* typo

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update update.ts

* wip

* Update signup.ts

* Update call.ts

* minimum for limit

* type

* remove needless annotation

* wip

* Update signup.ts

* wip

* wip

* fix

* Update create.ts

Co-authored-by: Johann150 <johann.galle@protonmail.com>
This commit is contained in:
syuilo 2022-02-19 14:05:32 +09:00 committed by GitHub
parent 59785ea04c
commit 510de87607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
320 changed files with 4395 additions and 5939 deletions

View File

@ -70,6 +70,7 @@
"@typescript-eslint/eslint-plugin": "5.12.0",
"@typescript-eslint/parser": "5.12.0",
"abort-controller": "3.0.0",
"ajv": "8.10.0",
"archiver": "5.3.0",
"autobind-decorator": "2.4.0",
"autwh": "0.1.0",

View File

@ -65,16 +65,18 @@ export const refs = {
// Packed = SchemaTypeDef<typeof refs[x]>; とすると展開されてマウスホバー時に型表示が使い物にならなくなる
// ObjType<r['properties']>を指定するとなぜか展開されずにPacked<'Hoge'>と表示される
type PackedDef<r extends { properties?: Obj; oneOf?: ReadonlyArray<MinimumSchema>; allOf?: ReadonlyArray<MinimumSchema> }> =
r['allOf'] extends ReadonlyArray<MinimumSchema> ? UnionToIntersection<UnionSchemaType<r['allOf']>> :
r['oneOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<r['oneOf']> :
r['properties'] extends Obj ? ObjType<r['properties']> :
type PackedDef<r extends { properties?: Obj; oneOf?: ReadonlyArray<Schema>; allOf?: ReadonlyArray<Schema> }> =
r['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<r['allOf']>> :
r['oneOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<r['oneOf']> :
r['properties'] extends Obj ? ObjType<r['properties'], any> :
never;
export type Packed<x extends keyof typeof refs> = PackedDef<typeof refs[x]>;
type TypeStringef = 'boolean' | 'number' | 'string' | 'array' | 'object' | 'any';
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> :
@ -83,17 +85,18 @@ type StringDefToType<T extends TypeStringef> =
// https://swagger.io/specification/?sbsearch=optional#schema-object
type OfSchema = {
readonly anyOf?: ReadonlyArray<MinimumSchema>;
readonly oneOf?: ReadonlyArray<MinimumSchema>;
readonly allOf?: ReadonlyArray<MinimumSchema>;
readonly anyOf?: ReadonlyArray<Schema>;
readonly oneOf?: ReadonlyArray<Schema>;
readonly allOf?: ReadonlyArray<Schema>;
}
export interface MinimumSchema extends OfSchema {
export interface Schema extends OfSchema {
readonly type?: TypeStringef;
readonly nullable?: boolean;
readonly optional?: boolean;
readonly items?: MinimumSchema;
readonly items?: Schema;
readonly properties?: Obj;
readonly required?: ReadonlyArray<keyof NonNullable<this['properties']>>;
readonly description?: string;
readonly example?: any;
readonly format?: string;
@ -104,26 +107,33 @@ export interface MinimumSchema extends OfSchema {
readonly minLength?: number;
}
export interface Schema extends MinimumSchema {
readonly nullable: boolean;
readonly optional: boolean;
}
type NonUndefinedPropertyNames<T extends Obj> = {
[K in keyof T]: T[K]['optional'] extends true ? never : K
type OptionalPropertyNames<T extends Obj> = {
[K in keyof T]: T[K]['optional'] extends true ? K : never
}[keyof T];
type UndefinedPropertyNames<T extends Obj> = {
[K in keyof T]: T[K]['optional'] extends true ? K : never
type NonOptionalPropertyNames<T extends Obj> = {
[K in keyof T]: T[K]['optional'] extends false ? K : never
}[keyof T];
type DefaultPropertyNames<T extends Obj> = {
[K in keyof T]: T[K]['default'] extends null ? K :
T[K]['default'] extends string ? K :
T[K]['default'] extends number ? K :
T[K]['default'] extends boolean ? K :
T[K]['default'] extends Record<string, unknown> ? K :
never
}[keyof T];
export interface Obj { [key: string]: Schema; }
export type ObjType<s extends Obj> =
{ -readonly [P in UndefinedPropertyNames<s>]?: SchemaType<s[P]> } &
{ -readonly [P in NonUndefinedPropertyNames<s>]: SchemaType<s[P]> };
export type ObjType<s extends Obj, RequiredProps extends ReadonlyArray<keyof s>> =
{ -readonly [P in keyof s]?: SchemaType<s[P]> } &
{ -readonly [P in RequiredProps[number]]: SchemaType<s[P]> } &
{ -readonly [P in OptionalPropertyNames<s>]?: SchemaType<s[P]> } &
{ -readonly [P in NonOptionalPropertyNames<s>]: SchemaType<s[P]> } &
{ -readonly [P in DefaultPropertyNames<s>]: SchemaType<s[P]> };
type NullOrUndefined<p extends MinimumSchema, T> =
type NullOrUndefined<p extends Schema, T> =
p['nullable'] extends true
? p['optional'] extends true
? (T | null | undefined)
@ -137,10 +147,12 @@ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
// https://github.com/misskey-dev/misskey/pull/8144#discussion_r785287552
// 単純にSchemaTypeDef<X>で判定するだけではダメ
type UnionSchemaType<a extends readonly any[], X extends MinimumSchema = a[number]> = X extends any ? SchemaType<X> : never;
type UnionSchemaType<a extends readonly any[], X extends Schema = a[number]> = X extends any ? SchemaType<X> : never;
type ArrayUnion<T> = T extends any ? Array<T> : never;
export type SchemaTypeDef<p extends MinimumSchema> =
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[] ?
@ -151,22 +163,22 @@ export type SchemaTypeDef<p extends MinimumSchema> =
p['type'] extends 'boolean' ? boolean :
p['type'] extends 'object' ? (
p['ref'] extends keyof typeof refs ? Packed<p['ref']> :
p['properties'] extends NonNullable<Obj> ? ObjType<p['properties']> :
p['anyOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<p['anyOf']> & Partial<UnionToIntersection<UnionSchemaType<p['anyOf']>>> :
p['allOf'] extends ReadonlyArray<MinimumSchema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
p['properties'] extends NonNullable<Obj> ? ObjType<p['properties'], NonNullable<p['required']>> :
p['anyOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['anyOf']> & Partial<UnionToIntersection<UnionSchemaType<p['anyOf']>>> :
p['allOf'] extends ReadonlyArray<Schema> ? UnionToIntersection<UnionSchemaType<p['allOf']>> :
any
) :
p['type'] extends 'array' ? (
p['items'] extends OfSchema ? (
p['items']['anyOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<NonNullable<p['items']['anyOf']>>[] :
p['items']['oneOf'] extends ReadonlyArray<MinimumSchema> ? ArrayUnion<UnionSchemaType<NonNullable<p['items']['oneOf']>>> :
p['items']['allOf'] extends ReadonlyArray<MinimumSchema> ? UnionToIntersection<UnionSchemaType<NonNullable<p['items']['allOf']>>>[] :
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<MinimumSchema> ? SchemaTypeDef<p['items']>[] :
p['items'] extends NonNullable<Schema> ? SchemaTypeDef<p['items']>[] :
any[]
) :
p['oneOf'] extends ReadonlyArray<MinimumSchema> ? UnionSchemaType<p['oneOf']> :
p['oneOf'] extends ReadonlyArray<Schema> ? UnionSchemaType<p['oneOf']> :
any;
export type SchemaType<p extends MinimumSchema> = NullOrUndefined<p, SchemaTypeDef<p>>;
export type SchemaType<p extends Schema> = NullOrUndefined<p, SchemaTypeDef<p>>;

View File

@ -6,13 +6,6 @@ import { Packed } from '@/misc/schema';
@EntityRepository(DriveFolder)
export class DriveFolderRepository extends Repository<DriveFolder> {
public validateFolderName(name: string): boolean {
return (
(name.trim().length > 0) &&
(name.length <= 200)
);
}
public async pack(
src: DriveFolder['id'] | DriveFolder,
options?: {

View File

@ -6,10 +6,6 @@ import { User } from '@/models/entities/user';
@EntityRepository(MessagingMessage)
export class MessagingMessageRepository extends Repository<MessagingMessage> {
public validateText(text: string): boolean {
return text.trim().length <= 1000 && text.trim() != '';
}
public async pack(
src: MessagingMessage['id'] | MessagingMessage,
me?: { id: User['id'] } | null | undefined,

View File

@ -12,10 +12,6 @@ import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/popu
@EntityRepository(Note)
export class NoteRepository extends Repository<Note> {
public validateCw(x: string) {
return x.trim().length <= 100;
}
public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> {
// visibility が specified かつ自分が指定されていなかったら非表示
if (note.visibility === 'specified') {

View File

@ -1,5 +1,5 @@
import $ from 'cafy';
import { EntityRepository, Repository, In, Not } from 'typeorm';
import * as Ajv from 'ajv';
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index';
import config from '@/config/index';
@ -17,8 +17,26 @@ type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends bo
Packed<'UserDetailed'> :
Packed<'UserLite'>;
const ajv = new Ajv();
@EntityRepository(User)
export class UserRepository extends Repository<User> {
public localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
public passwordSchema = { type: 'string', minLength: 1 } as const;
public nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
public descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const;
public locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
public birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const;
//#region Validators
public validateLocalUsername = ajv.compile(this.localUsernameSchema);
public validatePassword = ajv.compile(this.passwordSchema);
public validateName = ajv.compile(this.nameSchema);
public validateDescription = ajv.compile(this.descriptionSchema);
public validateLocation = ajv.compile(this.locationSchema);
public validateBirthday = ajv.compile(this.birthdaySchema);
//#endregion
public async getRelation(me: User['id'], target: User['id']) {
const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([
Followings.findOne({
@ -351,13 +369,4 @@ export class UserRepository extends Repository<User> {
public isRemoteUser(user: User | { host: User['host'] }): boolean {
return !this.isLocalUser(user);
}
//#region Validators
public validateLocalUsername = $.str.match(/^\w{1,20}$/);
public validatePassword = $.str.min(1);
public validateName = $.str.min(1).max(50);
public validateDescription = $.str.min(1).max(500);
public validateLocation = $.str.min(1).max(50);
public validateBirthday = $.str.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/);
//#endregion
}

View File

@ -5,7 +5,7 @@ import authenticate, { AuthenticationError } from './authenticate';
import call from './call';
import { ApiError } from './error';
export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => {
export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res) => {
const body = ctx.request.body;
const reply = (x?: any, y?: ApiError) => {

View File

@ -2,7 +2,7 @@ import * as Koa from 'koa';
import { performance } from 'perf_hooks';
import { limiter } from './limiter';
import { User } from '@/models/entities/user';
import endpoints from './endpoints';
import endpoints, { IEndpoint } from './endpoints';
import { ApiError } from './error';
import { apiLogger } from './logger';
import { AccessToken } from '@/models/entities/access-token';
@ -67,7 +67,7 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac
if (ep.meta.requireCredential && ep.meta.limit && !user!.isAdmin && !user!.isModerator) {
// Rate limit
await limiter(ep, user!).catch(e => {
await limiter(ep as IEndpoint & { meta: { limit: NonNullable<IEndpoint['meta']['limit']> } }, user!).catch(e => {
throw new ApiError({
message: 'Rate limit exceeded. Please try again later.',
code: 'RATE_LIMIT_EXCEEDED',
@ -78,10 +78,10 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac
}
// Cast non JSON input
if (ep.meta.requireFile && ep.meta.params) {
for (const k of Object.keys(ep.meta.params)) {
const param = ep.meta.params[k];
if (['Boolean', 'Number'].includes(param.validator.name) && typeof data[k] === 'string') {
if (ep.meta.requireFile) {
for (const k of Object.keys(ep.params)) {
const param = ep.params.properties![k];
if (['boolean', 'number', 'integer'].includes(param.type ?? '') && typeof data[k] === 'string') {
try {
data[k] = JSON.parse(data[k]);
} catch (e) {
@ -91,8 +91,8 @@ export default async (endpoint: string, user: User | null | undefined, token: Ac
id: '0b5f1631-7c1a-41a6-b399-cce335f34d85',
}, {
param: k,
reason: `cannot cast to ${param.validator.name}`,
})
reason: `cannot cast to ${param.type}`,
});
}
}
}

View File

@ -21,13 +21,13 @@ export async function signup(opts: {
let hash = passwordHash;
// Validate username
if (!Users.validateLocalUsername.ok(username)) {
if (!Users.validateLocalUsername(username)) {
throw new Error('INVALID_USERNAME');
}
if (password != null && passwordHash == null) {
// Validate password
if (!Users.validatePassword.ok(password)) {
if (!Users.validatePassword(password)) {
throw new Error('INVALID_PASSWORD');
}

View File

@ -1,12 +1,11 @@
import * as fs from 'fs';
import * as Ajv from 'ajv';
import { ILocalUser } from '@/models/entities/user';
import { IEndpointMeta } from './endpoints';
import { ApiError } from './error';
import { SchemaType } from '@/misc/schema';
import { Schema, SchemaType } from '@/misc/schema';
import { AccessToken } from '@/models/entities/access-token';
type NonOptional<T> = T extends undefined ? never : T;
type SimpleUserInfo = {
id: ILocalUser['id'];
createdAt: ILocalUser['createdAt'];
@ -21,22 +20,24 @@ type SimpleUserInfo = {
showTimelineReplies: ILocalUser['showTimelineReplies'];
};
type Params<T extends IEndpointMeta> = {
[P in keyof T['params']]: NonNullable<T['params']>[P]['transform'] extends () => any
? ReturnType<NonNullable<T['params']>[P]['transform']>
: NonNullable<T['params']>[P]['default'] extends null | number | string
? NonOptional<ReturnType<NonNullable<T['params']>[P]['validator']['get']>[0]>
: ReturnType<NonNullable<T['params']>[P]['validator']['get']>[0];
};
export type Response = Record<string, any> | void;
type executor<T extends IEndpointMeta> =
(params: Params<T>, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any, cleanup?: () => any) =>
// TODO: paramsの型をT['params']のスキーマ定義から推論する
type executor<T extends IEndpointMeta, Ps extends Schema> =
(params: SchemaType<Ps>, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any, cleanup?: () => any) =>
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>)
const ajv = new Ajv({
useDefaults: true,
});
ajv.addFormat('misskey:id', /^[a-z0-9]+$/);
export default function <T extends IEndpointMeta, Ps extends Schema>(meta: T, paramDef: Ps, cb: executor<T, Ps>)
: (params: any, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any) => Promise<any> {
const validate = ajv.compile(paramDef);
return (params: any, user: T['requireCredential'] extends true ? SimpleUserInfo : SimpleUserInfo | null, token: AccessToken | null, file?: any) => {
function cleanup() {
fs.unlink(file.path, () => {});
@ -48,42 +49,22 @@ export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>)
id: '4267801e-70d1-416a-b011-4ee502885d8b',
}));
const [ps, pserr] = getParams(meta, params);
if (pserr) {
const valid = validate(params);
if (!valid) {
if (file) cleanup();
return Promise.reject(pserr);
}
return cb(ps, user, token, file, cleanup);
};
}
function getParams<T extends IEndpointMeta>(defs: T, params: any): [Params<T>, ApiError | null] {
if (defs.params == null) return [params, null];
const x: any = {};
let err: ApiError | null = null;
Object.entries(defs.params).some(([k, def]) => {
const [v, e] = def.validator.get(params[k]);
if (e) {
err = new ApiError({
const errors = validate.errors!;
const err = new ApiError({
message: 'Invalid param.',
code: 'INVALID_PARAM',
id: '3d81ceae-475f-4600-b2a8-2bc116157532',
}, {
param: k,
reason: e.message,
param: errors[0].schemaPath,
reason: errors[0].message,
});
return true;
} else {
if (v === undefined && Object.prototype.hasOwnProperty.call(def, 'default')) {
x[k] = def.default;
} else {
x[k] = v;
return Promise.reject(err);
}
if (def.transform) x[k] = def.transform(x[k]);
return false;
}
});
return [x, err];
return cb(params, user, token, file, cleanup);
};
}

View File

@ -1,6 +1,4 @@
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { Context } from 'cafy';
import * as path from 'path';
import * as glob from 'glob';
import { Schema } from '@/misc/schema';
@ -9,23 +7,11 @@ import { Schema } from '@/misc/schema';
const _filename = __filename;
const _dirname = dirname(_filename);
export type Param = {
validator: Context<any>;
transform?: any;
default?: any;
deprecated?: boolean;
ref?: string;
};
export interface IEndpointMeta {
readonly stability?: 'deprecated' | 'experimental' | 'stable';
readonly tags?: ReadonlyArray<string>;
readonly params?: {
readonly [key: string]: Param;
};
readonly errors?: {
readonly [key: string]: {
readonly message: string;
@ -99,12 +85,15 @@ export interface IEndpointMeta {
*
*/
readonly kind?: string;
readonly description?: string;
}
export interface IEndpoint {
name: string;
exec: any;
meta: IEndpointMeta;
params: Schema;
}
const files = glob.sync('**/*.js', {
@ -118,6 +107,7 @@ const endpoints: IEndpoint[] = files.map(f => {
name: f.replace('.js', ''),
exec: ep.default,
meta: ep.meta || {},
params: ep.paramDef,
};
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { AbuseUserReports } from '@/models/index';
import { makePaginationQuery } from '../../common/make-pagination-query';
@ -10,49 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
state: {
validator: $.optional.nullable.str,
default: null,
},
reporterOrigin: {
validator: $.optional.str.or([
'combined',
'local',
'remote',
]),
default: 'combined',
},
targetUserOrigin: {
validator: $.optional.str.or([
'combined',
'local',
'remote',
]),
default: 'combined',
},
forwarded: {
validator: $.optional.bool,
default: false,
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -115,8 +70,22 @@ export const meta = {
},
} as const;
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const query = makePaginationQuery(AbuseUserReports.createQueryBuilder('report'), ps.sinceId, ps.untilId);
switch (ps.state) {
@ -134,7 +103,7 @@ export default define(meta, async (ps) => {
case 'remote': query.andWhere('report.targetUserHost IS NOT NULL'); break;
}
const reports = await query.take(ps.limit!).getMany();
const reports = await query.take(ps.limit).getMany();
return await AbuseUserReports.packMany(reports);
});

View File

@ -5,16 +5,6 @@ import { signup } from '../../../common/signup';
export const meta = {
tags: ['admin'],
params: {
username: {
validator: Users.validateLocalUsername,
},
password: {
validator: Users.validatePassword,
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -28,8 +18,17 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
username: Users.localUsernameSchema,
password: Users.passwordSchema,
},
required: ['username', 'password'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, _me) => {
export default define(meta, paramDef, async (ps, _me) => {
const me = _me ? await Users.findOneOrFail(_me.id) : null;
const noUsers = (await Users.count({
host: null,

View File

@ -1,26 +1,26 @@
import $ from 'cafy';
import define from '../../../define';
import { Users } from '@/models/index';
import { doPostSuspend } from '@/services/suspend-user';
import { publishUserEvent } from '@/services/stream';
import { createDeleteAccountJob } from '@/queue';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId);
if (user == null) {

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { Ads } from '@/models/index';
import { genId } from '@/misc/gen-id';
@ -8,34 +7,24 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
url: {
validator: $.str.min(1),
},
memo: {
validator: $.str,
},
place: {
validator: $.str,
},
priority: {
validator: $.str,
},
ratio: {
validator: $.num.int().min(0),
},
expiresAt: {
validator: $.num.int(),
},
imageUrl: {
validator: $.str.min(1),
},
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' },
imageUrl: { type: 'string', minLength: 1 },
},
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
await Ads.insert({
id: genId(),
createdAt: new Date(),

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Ads } from '@/models/index';
import { ApiError } from '../../../error';
@ -10,12 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
id: {
validator: $.type(ID),
},
},
errors: {
noSuchAd: {
message: 'No such ad.',
@ -25,8 +17,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const ad = await Ads.findOne(ps.id);
if (ad == null) throw new ApiError(meta.errors.noSuchAd);

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { Ads } from '@/models/index';
import { makePaginationQuery } from '../../../common/make-pagination-query';
@ -9,29 +7,24 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const query = makePaginationQuery(Ads.createQueryBuilder('ad'), ps.sinceId, ps.untilId)
.andWhere('ad.expiresAt > :now', { now: new Date() });
const ads = await query.take(ps.limit!).getMany();
const ads = await query.take(ps.limit).getMany();
return ads;
});

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Ads } from '@/models/index';
import { ApiError } from '../../../error';
@ -10,33 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
id: {
validator: $.type(ID),
},
memo: {
validator: $.str,
},
url: {
validator: $.str.min(1),
},
imageUrl: {
validator: $.str.min(1),
},
place: {
validator: $.str,
},
priority: {
validator: $.str,
},
ratio: {
validator: $.num.int().min(0),
},
expiresAt: {
validator: $.num.int(),
},
},
errors: {
noSuchAd: {
message: 'No such ad.',
@ -46,8 +17,23 @@ export const meta = {
},
} as const;
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' },
},
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const ad = await Ads.findOne(ps.id);
if (ad == null) throw new ApiError(meta.errors.noSuchAd);

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { Announcements } from '@/models/index';
import { genId } from '@/misc/gen-id';
@ -9,18 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
title: {
validator: $.str.min(1),
},
text: {
validator: $.str.min(1),
},
imageUrl: {
validator: $.nullable.str.min(1),
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -57,8 +44,18 @@ export const meta = {
},
} as const;
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const announcement = await Announcements.insert({
id: genId(),
createdAt: new Date(),

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Announcements } from '@/models/index';
import { ApiError } from '../../../error';
@ -10,12 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
id: {
validator: $.type(ID),
},
},
errors: {
noSuchAnnouncement: {
message: 'No such announcement.',
@ -25,8 +17,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const announcement = await Announcements.findOne(ps.id);
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { Announcements, AnnouncementReads } from '@/models/index';
import { makePaginationQuery } from '../../../common/make-pagination-query';
@ -10,21 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -69,11 +52,21 @@ export const meta = {
},
} as const;
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
const announcements = await query.take(ps.limit!).getMany();
const announcements = await query.take(ps.limit).getMany();
for (const announcement of announcements) {
(announcement as any).reads = await AnnouncementReads.count({

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Announcements } from '@/models/index';
import { ApiError } from '../../../error';
@ -10,21 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
id: {
validator: $.type(ID),
},
title: {
validator: $.str.min(1),
},
text: {
validator: $.str.min(1),
},
imageUrl: {
validator: $.nullable.str.min(1),
},
},
errors: {
noSuchAnnouncement: {
message: 'No such announcement.',
@ -34,8 +17,19 @@ export const meta = {
},
} as const;
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: 1 },
},
required: ['id', 'title', 'text', 'imageUrl'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const announcement = await Announcements.findOne(ps.id);
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);

View File

@ -1,24 +1,24 @@
import $ from 'cafy';
import define from '../../define';
import { deleteFile } from '@/services/drive/delete-file';
import { DriveFiles } from '@/models/index';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const files = await DriveFiles.find({
userId: ps.userId,
});

View File

@ -8,7 +8,13 @@ export const meta = {
requireModerator: true,
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
createCleanRemoteFilesJob();
});

View File

@ -10,8 +10,14 @@ export const meta = {
requireModerator: true,
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const files = await DriveFiles.find({
userId: IsNull(),
});

View File

@ -1,8 +1,6 @@
import $ from 'cafy';
import define from '../../../define';
import { DriveFiles } from '@/models/index';
import { makePaginationQuery } from '../../../common/make-pagination-query';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['admin'],
@ -10,39 +8,6 @@ export const meta = {
requireCredential: false,
requireModerator: true,
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
type: {
validator: $.optional.nullable.str.match(/^[a-zA-Z0-9\/\-*]+$/),
},
origin: {
validator: $.optional.str.or([
'combined',
'local',
'remote',
]),
default: 'local',
},
hostname: {
validator: $.optional.nullable.str,
default: null,
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -54,8 +19,21 @@ export const meta = {
},
} as const;
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' },
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 },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId);
if (ps.origin === 'local') {
@ -76,7 +54,7 @@ export default define(meta, async (ps, me) => {
}
}
const files = await query.take(ps.limit!).getMany();
const files = await query.take(ps.limit).getMany();
return await DriveFiles.packMany(files, { detail: true, withUser: true, self: true });
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
import { DriveFiles } from '@/models/index';
@ -10,16 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
fileId: {
validator: $.optional.type(ID),
},
url: {
validator: $.optional.str,
},
},
errors: {
noSuchFile: {
message: 'No such file.',
@ -161,8 +149,17 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
fileId: { type: 'string', format: 'misskey:id' },
url: { type: 'string' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const file = ps.fileId ? await DriveFiles.findOne(ps.fileId) : await DriveFiles.findOne({
where: [{
url: ps.url,

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection, In } from 'typeorm';
import { ApiError } from '../../../error';
@ -10,20 +8,23 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
ids: {
validator: $.arr($.type(ID)),
},
aliases: {
validator: $.arr($.str),
},
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const emojis = await Emojis.find({
id: In(ps.ids),
});

View File

@ -1,11 +1,9 @@
import $ from 'cafy';
import define from '../../../define';
import { Emojis, DriveFiles } from '@/models/index';
import { genId } from '@/misc/gen-id';
import { getConnection } from 'typeorm';
import { insertModerationLog } from '@/services/insert-moderation-log';
import { ApiError } from '../../../error';
import { ID } from '@/misc/cafy-id';
import rndstr from 'rndstr';
import { publishBroadcastStream } from '@/services/stream';
@ -15,12 +13,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
fileId: {
validator: $.type(ID),
},
},
errors: {
noSuchFile: {
message: 'No such file.',
@ -30,8 +22,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
fileId: { type: 'string', format: 'misskey:id' },
},
required: ['fileId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const file = await DriveFiles.findOne(ps.fileId);
if (file == null) throw new ApiError(meta.errors.noSuchFile);

View File

@ -1,11 +1,9 @@
import $ from 'cafy';
import define from '../../../define';
import { Emojis } from '@/models/index';
import { genId } from '@/misc/gen-id';
import { getConnection } from 'typeorm';
import { ApiError } from '../../../error';
import { DriveFile } from '@/models/entities/drive-file';
import { ID } from '@/misc/cafy-id';
import { uploadFromUrl } from '@/services/drive/upload-from-url';
import { publishBroadcastStream } from '@/services/stream';
@ -15,12 +13,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
emojiId: {
validator: $.type(ID),
},
},
errors: {
noSuchEmoji: {
message: 'No such emoji.',
@ -42,8 +34,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
emojiId: { type: 'string', format: 'misskey:id' },
},
required: ['emojiId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const emoji = await Emojis.findOne(ps.emojiId);
if (emoji == null) {

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection, In } from 'typeorm';
import { insertModerationLog } from '@/services/insert-moderation-log';
@ -11,16 +9,20 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
ids: {
validator: $.arr($.type(ID)),
},
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
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const emojis = await Emojis.find({
id: In(ps.ids),
});

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection } from 'typeorm';
import { insertModerationLog } from '@/services/insert-moderation-log';
@ -12,12 +10,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
id: {
validator: $.type(ID),
},
},
errors: {
noSuchEmoji: {
message: 'No such emoji.',
@ -27,8 +19,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
},
required: ['id'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const emoji = await Emojis.findOne(ps.id);
if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji);

View File

@ -1,21 +1,22 @@
import $ from 'cafy';
import define from '../../../define';
import { createImportCustomEmojisJob } from '@/queue/index';
import ms from 'ms';
import { ID } from '@/misc/cafy-id';
export const meta = {
secure: true,
requireCredential: true,
requireModerator: true,
params: {
fileId: {
validator: $.type(ID),
},
} as const;
const paramDef = {
type: 'object',
properties: {
fileId: { type: 'string', format: 'misskey:id' },
},
required: ['fileId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
createImportCustomEmojisJob(user, ps.fileId);
});

View File

@ -1,9 +1,7 @@
import $ from 'cafy';
import define from '../../../define';
import { Emojis } from '@/models/index';
import { toPuny } from '@/misc/convert-host';
import { makePaginationQuery } from '../../../common/make-pagination-query';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['admin'],
@ -11,31 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
query: {
validator: $.optional.nullable.str,
default: null,
},
host: {
validator: $.optional.nullable.str,
default: null,
},
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -77,8 +50,20 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
query: { type: 'string', nullable: true, default: null },
host: { 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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId);
if (ps.host == null) {
@ -93,7 +78,7 @@ export default define(meta, async (ps) => {
const emojis = await q
.orderBy('emoji.id', 'DESC')
.take(ps.limit!)
.take(ps.limit)
.getMany();
return Emojis.packMany(emojis);

View File

@ -1,8 +1,6 @@
import $ from 'cafy';
import define from '../../../define';
import { Emojis } from '@/models/index';
import { makePaginationQuery } from '../../../common/make-pagination-query';
import { ID } from '@/misc/cafy-id';
import { Emoji } from '@/models/entities/emoji';
export const meta = {
@ -11,26 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
query: {
validator: $.optional.nullable.str,
default: null,
},
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -72,8 +50,19 @@ export const meta = {
},
} as const;
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const q = makePaginationQuery(Emojis.createQueryBuilder('emoji'), ps.sinceId, ps.untilId)
.andWhere(`emoji.host IS NULL`);
@ -81,7 +70,7 @@ export default define(meta, async (ps) => {
if (ps.query) {
//q.andWhere('emoji.name ILIKE :q', { q: `%${ps.query}%` });
//const emojis = await q.take(ps.limit!).getMany();
//const emojis = await q.take(ps.limit).getMany();
emojis = await q.getMany();
@ -90,9 +79,9 @@ export default define(meta, async (ps) => {
emoji.aliases.some(a => a.includes(ps.query!)) ||
emoji.category?.includes(ps.query!));
emojis.splice(ps.limit! + 1);
emojis.splice(ps.limit + 1);
} else {
emojis = await q.take(ps.limit!).getMany();
emojis = await q.take(ps.limit).getMany();
}
return Emojis.packMany(emojis);

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection, In } from 'typeorm';
import { ApiError } from '../../../error';
@ -10,20 +8,23 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
ids: {
validator: $.arr($.type(ID)),
},
aliases: {
validator: $.arr($.str),
},
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const emojis = await Emojis.find({
id: In(ps.ids),
});

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection, In } from 'typeorm';
import { ApiError } from '../../../error';
@ -10,20 +8,23 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
ids: {
validator: $.arr($.type(ID)),
},
aliases: {
validator: $.arr($.str),
},
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
await Emojis.update({
id: In(ps.ids),
}, {

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection, In } from 'typeorm';
import { ApiError } from '../../../error';
@ -10,20 +8,21 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
ids: {
validator: $.arr($.type(ID)),
},
category: {
validator: $.optional.nullable.str,
},
const paramDef = {
type: 'object',
properties: {
ids: { type: 'array', items: {
type: 'string', format: 'misskey:id',
} },
category: { type: 'string', nullable: true },
},
required: ['ids'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
await Emojis.update({
id: In(ps.ids),
}, {

View File

@ -1,6 +1,4 @@
import $ from 'cafy';
import define from '../../../define';
import { ID } from '@/misc/cafy-id';
import { Emojis } from '@/models/index';
import { getConnection } from 'typeorm';
import { ApiError } from '../../../error';
@ -11,24 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
id: {
validator: $.type(ID),
},
name: {
validator: $.str,
},
category: {
validator: $.optional.nullable.str,
},
aliases: {
validator: $.arr($.str),
},
},
errors: {
noSuchEmoji: {
message: 'No such emoji.',
@ -38,8 +18,21 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
id: { type: 'string', format: 'misskey:id' },
name: { type: 'string' },
category: { type: 'string', nullable: true },
aliases: { type: 'array', items: {
type: 'string',
} },
},
required: ['id', 'name', 'aliases'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const emoji = await Emojis.findOne(ps.id);
if (emoji == null) throw new ApiError(meta.errors.noSuchEmoji);

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { deleteFile } from '@/services/drive/delete-file';
import { DriveFiles } from '@/models/index';
@ -8,16 +7,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
host: {
validator: $.str,
},
const paramDef = {
type: 'object',
properties: {
host: { type: 'string' },
},
required: ['host'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const files = await DriveFiles.find({
userHost: ps.host,
});

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { Instances } from '@/models/index';
import { toPuny } from '@/misc/convert-host';
@ -9,16 +8,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
host: {
validator: $.str,
},
const paramDef = {
type: 'object',
properties: {
host: { type: 'string' },
},
required: ['host'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const instance = await Instances.findOne({ host: toPuny(ps.host) });
if (instance == null) {

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import deleteFollowing from '@/services/following/delete';
import { Followings, Users } from '@/models/index';
@ -8,16 +7,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
host: {
validator: $.str,
},
const paramDef = {
type: 'object',
properties: {
host: { type: 'string' },
},
required: ['host'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const followings = await Followings.find({
followerHost: ps.host,
});

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { Instances } from '@/models/index';
import { toPuny } from '@/misc/convert-host';
@ -8,20 +7,19 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
host: {
validator: $.str,
},
isSuspended: {
validator: $.bool,
},
const paramDef = {
type: 'object',
properties: {
host: { type: 'string' },
isSuspended: { type: 'boolean' },
},
required: ['host', 'isSuspended'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const instance = await Instances.findOne({ host: toPuny(ps.host) });
if (instance == null) {

View File

@ -6,13 +6,16 @@ export const meta = {
requireModerator: true,
tags: ['admin'],
} as const;
params: {
},
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async () => {
export default define(meta, paramDef, async () => {
const stats = await
getConnection().query(`SELECT * FROM pg_indexes;`)
.then(recs => {

View File

@ -7,9 +7,6 @@ export const meta = {
tags: ['admin'],
params: {
},
res: {
type: 'object',
optional: false, nullable: false,
@ -22,8 +19,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async () => {
export default define(meta, paramDef, async () => {
const sizes = await
getConnection().query(`
SELECT relname AS "table", reltuples as "count", pg_total_relation_size(C.oid) AS "size"

View File

@ -9,8 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {},
res: {
type: 'object',
optional: false, nullable: false,
@ -26,8 +24,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async () => {
export default define(meta, paramDef, async () => {
const code = rndstr({
length: 8,
chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns)

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { Users } from '@/models/index';
@ -8,16 +6,18 @@ export const meta = {
requireCredential: true,
requireAdmin: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { Users } from '@/models/index';
@ -8,16 +6,18 @@ export const meta = {
requireCredential: true,
requireAdmin: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
import { getNote } from '../../../common/getters';
@ -11,16 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
noteId: {
validator: $.type(ID),
},
expiresAt: {
validator: $.num.int(),
},
},
errors: {
noSuchNote: {
message: 'No such note.',
@ -36,8 +24,17 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
noteId: { type: 'string', format: 'misskey:id' },
expiresAt: { type: 'integer' },
},
required: ['noteId', 'expiresAt'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const note = await getNote(ps.noteId).catch(e => {
if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
throw e;

View File

@ -7,12 +7,16 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {},
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
destroy();
insertModerationLog(me, 'clearQueue');

View File

@ -8,9 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
},
res: {
type: 'array',
optional: false, nullable: false,
@ -35,8 +32,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const jobs = await deliverQueue.getJobs(['delayed']);
const res = [] as [string, number][];

View File

@ -8,9 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
},
res: {
type: 'array',
optional: false, nullable: false,
@ -35,8 +32,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const jobs = await inboxQueue.getJobs(['delayed']);
const res = [] as [string, number][];

View File

@ -7,8 +7,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {},
res: {
type: 'object',
optional: false, nullable: false,
@ -33,8 +31,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const deliverJobCounts = await deliverQueue.getJobCounts();
const inboxJobCounts = await inboxQueue.getJobCounts();
const dbJobCounts = await dbQueue.getJobCounts();

View File

@ -1,5 +1,4 @@
import { URL } from 'url';
import $ from 'cafy';
import define from '../../../define';
import { addRelay } from '@/services/relay';
import { ApiError } from '../../../error';
@ -10,12 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
inbox: {
validator: $.str,
},
},
errors: {
invalidUrl: {
message: 'Invalid URL',
@ -52,8 +45,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
inbox: { type: 'string' },
},
required: ['inbox'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
try {
if (new URL(ps.inbox).protocol !== 'https:') throw 'https only';
} catch {

View File

@ -7,9 +7,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
},
res: {
type: 'array',
optional: false, nullable: false,
@ -42,7 +39,13 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
return await listRelay();
});

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { removeRelay } from '@/services/relay';
@ -7,15 +6,17 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
inbox: {
validator: $.str,
},
const paramDef = {
type: 'object',
properties: {
inbox: { type: 'string' },
},
required: ['inbox'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
return await removeRelay(ps.inbox);
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import * as bcrypt from 'bcryptjs';
import rndstr from 'rndstr';
@ -11,12 +9,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
userId: {
validator: $.type(ID),
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -31,8 +23,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { AbuseUserReports, Users } from '@/models/index';
import { getInstanceActor } from '@/services/instance-actor';
@ -12,22 +10,19 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
reportId: {
validator: $.type(ID),
},
forward: {
validator: $.optional.boolean,
required: false,
default: false,
},
const paramDef = {
type: 'object',
properties: {
reportId: { type: 'string', format: 'misskey:id' },
forward: { type: 'boolean', default: false },
},
required: ['reportId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const report = await AbuseUserReports.findOne(ps.reportId);
if (report == null) {

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../define';
import { sendEmail } from '@/services/send-email';
@ -7,21 +6,19 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
to: {
validator: $.str,
},
subject: {
validator: $.str,
},
text: {
validator: $.str,
},
const paramDef = {
type: 'object',
properties: {
to: { type: 'string' },
subject: { type: 'string' },
text: { type: 'string' },
},
required: ['to', 'subject', 'text'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
await sendEmail(ps.to, ps.subject, ps.text, ps.text);
});

View File

@ -10,9 +10,6 @@ export const meta = {
tags: ['admin', 'meta'],
params: {
},
res: {
type: 'object',
optional: false, nullable: false,
@ -90,8 +87,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async () => {
export default define(meta, paramDef, async () => {
const memStats = await si.mem();
const fsStats = await si.fsSize();
const netInterface = await si.networkInterfaceDefault();

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ModerationLogs } from '@/models/index';
import { makePaginationQuery } from '../../common/make-pagination-query';
@ -10,21 +8,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -65,11 +48,21 @@ export const meta = {
},
} as const;
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
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId);
const reports = await query.take(ps.limit!).getMany();
const reports = await query.take(ps.limit).getMany();
return await ModerationLogs.packMany(reports);
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Users } from '@/models/index';
@ -9,20 +7,22 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
userId: {
validator: $.type(ID),
},
},
res: {
type: 'object',
nullable: false, optional: false,
},
} as const;
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../define';
import { Users } from '@/models/index';
@ -8,61 +7,6 @@ export const meta = {
requireCredential: true,
requireModerator: true,
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
offset: {
validator: $.optional.num.min(0),
default: 0,
},
sort: {
validator: $.optional.str.or([
'+follower',
'-follower',
'+createdAt',
'-createdAt',
'+updatedAt',
'-updatedAt',
]),
},
state: {
validator: $.optional.str.or([
'all',
'available',
'admin',
'moderator',
'adminOrModerator',
'silenced',
'suspended',
]),
default: 'all',
},
origin: {
validator: $.optional.str.or([
'combined',
'local',
'remote',
]),
default: 'local',
},
username: {
validator: $.optional.str,
default: null,
},
hostname: {
validator: $.optional.str,
default: null,
},
},
res: {
type: 'array',
nullable: false, optional: false,
@ -74,8 +18,22 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
offset: { type: 'integer', default: 0 },
sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] },
state: { type: 'string', enum: ['all', 'available', 'admin', 'moderator', 'adminOrModerator', 'silenced', 'suspended'], default: "all" },
origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" },
username: { type: 'string', default: null },
hostname: { type: 'string', default: null },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const query = Users.createQueryBuilder('user');
switch (ps.state) {
@ -111,7 +69,7 @@ export default define(meta, async (ps, me) => {
default: query.orderBy('user.id', 'ASC'); break;
}
query.take(ps.limit!);
query.take(ps.limit);
query.skip(ps.offset);
const users = await query.getMany();

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Users } from '@/models/index';
import { insertModerationLog } from '@/services/insert-moderation-log';
@ -9,16 +7,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import deleteFollowing from '@/services/following/delete';
import { Users, Followings, Notifications } from '@/models/index';
@ -13,16 +11,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Users } from '@/models/index';
import { insertModerationLog } from '@/services/insert-moderation-log';
@ -9,16 +7,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Users } from '@/models/index';
import { insertModerationLog } from '@/services/insert-moderation-log';
@ -10,16 +8,18 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
userId: {
validator: $.type(ID),
},
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const user = await Users.findOne(ps.userId as string);
if (user == null) {

View File

@ -1,310 +1,107 @@
import $ from 'cafy';
import define from '../../define';
import { getConnection } from 'typeorm';
import { Meta } from '@/models/entities/meta';
import { insertModerationLog } from '@/services/insert-moderation-log';
import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['admin'],
requireCredential: true,
requireAdmin: true,
params: {
disableRegistration: {
validator: $.optional.nullable.bool,
},
disableLocalTimeline: {
validator: $.optional.nullable.bool,
},
disableGlobalTimeline: {
validator: $.optional.nullable.bool,
},
useStarForReactionFallback: {
validator: $.optional.nullable.bool,
},
pinnedUsers: {
validator: $.optional.nullable.arr($.str),
},
hiddenTags: {
validator: $.optional.nullable.arr($.str),
},
blockedHosts: {
validator: $.optional.nullable.arr($.str),
},
themeColor: {
validator: $.optional.nullable.str,
},
mascotImageUrl: {
validator: $.optional.nullable.str,
},
bannerUrl: {
validator: $.optional.nullable.str,
},
errorImageUrl: {
validator: $.optional.nullable.str,
},
iconUrl: {
validator: $.optional.nullable.str,
},
backgroundImageUrl: {
validator: $.optional.nullable.str,
},
logoImageUrl: {
validator: $.optional.nullable.str,
},
name: {
validator: $.optional.nullable.str,
},
description: {
validator: $.optional.nullable.str,
},
maxNoteTextLength: {
validator: $.optional.num.min(0).max(DB_MAX_NOTE_TEXT_LENGTH),
},
localDriveCapacityMb: {
validator: $.optional.num.min(0),
},
remoteDriveCapacityMb: {
validator: $.optional.num.min(0),
},
cacheRemoteFiles: {
validator: $.optional.bool,
},
proxyRemoteFiles: {
validator: $.optional.bool,
},
emailRequiredForSignup: {
validator: $.optional.bool,
},
enableHcaptcha: {
validator: $.optional.bool,
},
hcaptchaSiteKey: {
validator: $.optional.nullable.str,
},
hcaptchaSecretKey: {
validator: $.optional.nullable.str,
},
enableRecaptcha: {
validator: $.optional.bool,
},
recaptchaSiteKey: {
validator: $.optional.nullable.str,
},
recaptchaSecretKey: {
validator: $.optional.nullable.str,
},
proxyAccountId: {
validator: $.optional.nullable.type(ID),
},
maintainerName: {
validator: $.optional.nullable.str,
},
maintainerEmail: {
validator: $.optional.nullable.str,
},
pinnedPages: {
validator: $.optional.arr($.str),
},
pinnedClipId: {
validator: $.optional.nullable.type(ID),
},
langs: {
validator: $.optional.arr($.str),
},
summalyProxy: {
validator: $.optional.nullable.str,
},
deeplAuthKey: {
validator: $.optional.nullable.str,
},
deeplIsPro: {
validator: $.optional.bool,
},
enableTwitterIntegration: {
validator: $.optional.bool,
},
twitterConsumerKey: {
validator: $.optional.nullable.str,
},
twitterConsumerSecret: {
validator: $.optional.nullable.str,
},
enableGithubIntegration: {
validator: $.optional.bool,
},
githubClientId: {
validator: $.optional.nullable.str,
},
githubClientSecret: {
validator: $.optional.nullable.str,
},
enableDiscordIntegration: {
validator: $.optional.bool,
},
discordClientId: {
validator: $.optional.nullable.str,
},
discordClientSecret: {
validator: $.optional.nullable.str,
},
enableEmail: {
validator: $.optional.bool,
},
email: {
validator: $.optional.nullable.str,
},
smtpSecure: {
validator: $.optional.bool,
},
smtpHost: {
validator: $.optional.nullable.str,
},
smtpPort: {
validator: $.optional.nullable.num,
},
smtpUser: {
validator: $.optional.nullable.str,
},
smtpPass: {
validator: $.optional.nullable.str,
},
enableServiceWorker: {
validator: $.optional.bool,
},
swPublicKey: {
validator: $.optional.nullable.str,
},
swPrivateKey: {
validator: $.optional.nullable.str,
},
tosUrl: {
validator: $.optional.nullable.str,
},
repositoryUrl: {
validator: $.optional.str,
},
feedbackUrl: {
validator: $.optional.str,
},
useObjectStorage: {
validator: $.optional.bool,
},
objectStorageBaseUrl: {
validator: $.optional.nullable.str,
},
objectStorageBucket: {
validator: $.optional.nullable.str,
},
objectStoragePrefix: {
validator: $.optional.nullable.str,
},
objectStorageEndpoint: {
validator: $.optional.nullable.str,
},
objectStorageRegion: {
validator: $.optional.nullable.str,
},
objectStoragePort: {
validator: $.optional.nullable.num,
},
objectStorageAccessKey: {
validator: $.optional.nullable.str,
},
objectStorageSecretKey: {
validator: $.optional.nullable.str,
},
objectStorageUseSSL: {
validator: $.optional.bool,
},
objectStorageUseProxy: {
validator: $.optional.bool,
},
objectStorageSetPublicRead: {
validator: $.optional.bool,
},
objectStorageS3ForcePathStyle: {
validator: $.optional.bool,
},
},
} as const;
const paramDef = {
type: 'object',
properties: {
disableRegistration: { type: 'boolean', nullable: true },
disableLocalTimeline: { type: 'boolean', nullable: true },
disableGlobalTimeline: { type: 'boolean', nullable: true },
useStarForReactionFallback: { type: 'boolean', nullable: true },
pinnedUsers: { type: 'array', nullable: true, items: {
type: 'string',
} },
hiddenTags: { type: 'array', nullable: true, items: {
type: 'string',
} },
blockedHosts: { type: 'array', nullable: true, items: {
type: 'string',
} },
themeColor: { type: 'string', nullable: true },
mascotImageUrl: { type: 'string', nullable: true },
bannerUrl: { type: 'string', nullable: true },
errorImageUrl: { type: 'string', nullable: true },
iconUrl: { type: 'string', nullable: true },
backgroundImageUrl: { type: 'string', nullable: true },
logoImageUrl: { type: 'string', nullable: true },
name: { type: 'string', nullable: true },
description: { type: 'string', nullable: true },
maxNoteTextLength: { type: 'integer', maximum: 8192 },
localDriveCapacityMb: { type: 'integer' },
remoteDriveCapacityMb: { type: 'integer' },
cacheRemoteFiles: { type: 'boolean' },
proxyRemoteFiles: { type: 'boolean' },
emailRequiredForSignup: { type: 'boolean' },
enableHcaptcha: { type: 'boolean' },
hcaptchaSiteKey: { type: 'string', nullable: true },
hcaptchaSecretKey: { type: 'string', nullable: true },
enableRecaptcha: { type: 'boolean' },
recaptchaSiteKey: { type: 'string', nullable: true },
recaptchaSecretKey: { type: 'string', nullable: true },
proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true },
maintainerName: { type: 'string', nullable: true },
maintainerEmail: { type: 'string', nullable: true },
pinnedPages: { type: 'array', items: {
type: 'string',
} },
pinnedClipId: { type: 'string', format: 'misskey:id', nullable: true },
langs: { type: 'array', items: {
type: 'string',
} },
summalyProxy: { type: 'string', nullable: true },
deeplAuthKey: { type: 'string', nullable: true },
deeplIsPro: { type: 'boolean' },
enableTwitterIntegration: { type: 'boolean' },
twitterConsumerKey: { type: 'string', nullable: true },
twitterConsumerSecret: { type: 'string', nullable: true },
enableGithubIntegration: { type: 'boolean' },
githubClientId: { type: 'string', nullable: true },
githubClientSecret: { type: 'string', nullable: true },
enableDiscordIntegration: { type: 'boolean' },
discordClientId: { type: 'string', nullable: true },
discordClientSecret: { type: 'string', nullable: true },
enableEmail: { type: 'boolean' },
email: { type: 'string', nullable: true },
smtpSecure: { type: 'boolean' },
smtpHost: { type: 'string', nullable: true },
smtpPort: { type: 'integer', nullable: true },
smtpUser: { type: 'string', nullable: true },
smtpPass: { type: 'string', nullable: true },
enableServiceWorker: { type: 'boolean' },
swPublicKey: { type: 'string', nullable: true },
swPrivateKey: { type: 'string', nullable: true },
tosUrl: { type: 'string', nullable: true },
repositoryUrl: { type: 'string' },
feedbackUrl: { type: 'string' },
useObjectStorage: { type: 'boolean' },
objectStorageBaseUrl: { type: 'string', nullable: true },
objectStorageBucket: { type: 'string', nullable: true },
objectStoragePrefix: { type: 'string', nullable: true },
objectStorageEndpoint: { type: 'string', nullable: true },
objectStorageRegion: { type: 'string', nullable: true },
objectStoragePort: { type: 'integer', nullable: true },
objectStorageAccessKey: { type: 'string', nullable: true },
objectStorageSecretKey: { type: 'string', nullable: true },
objectStorageUseSSL: { type: 'boolean' },
objectStorageUseProxy: { type: 'boolean' },
objectStorageSetPublicRead: { type: 'boolean' },
objectStorageS3ForcePathStyle: { type: 'boolean' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const set = {} as Partial<Meta>;
if (typeof ps.disableRegistration === 'boolean') {

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../define';
import { getConnection } from 'typeorm';
import { insertModerationLog } from '@/services/insert-moderation-log';
@ -8,19 +7,19 @@ export const meta = {
requireCredential: true,
requireModerator: true,
} as const;
params: {
full: {
validator: $.bool,
},
analyze: {
validator: $.bool,
},
const paramDef = {
type: 'object',
properties: {
full: { type: 'boolean' },
analyze: { type: 'boolean' },
},
required: ['full', 'analyze'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const params: string[] = [];
if (ps.full) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../define';
import { Announcements, AnnouncementReads } from '@/models/index';
import { makePaginationQuery } from '../common/make-pagination-query';
@ -9,26 +7,6 @@ export const meta = {
requireCredential: false,
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
withUnreads: {
validator: $.optional.boolean,
default: false,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -73,11 +51,22 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
withUnreads: { type: 'boolean', default: false },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const query = makePaginationQuery(Announcements.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
const announcements = await query.take(ps.limit!).getMany();
const announcements = await query.take(ps.limit).getMany();
if (user) {
const reads = (await AnnouncementReads.find({

View File

@ -1,8 +1,6 @@
import $ from 'cafy';
import define from '../../define';
import { genId } from '@/misc/gen-id';
import { Antennas, UserLists, UserGroupJoinings } from '@/models/index';
import { ID } from '@/misc/cafy-id';
import { ApiError } from '../../error';
import { publishInternalEvent } from '@/services/stream';
@ -13,52 +11,6 @@ export const meta = {
kind: 'write:account',
params: {
name: {
validator: $.str.range(1, 100),
},
src: {
validator: $.str.or(['home', 'all', 'users', 'list', 'group']),
},
userListId: {
validator: $.nullable.optional.type(ID),
},
userGroupId: {
validator: $.nullable.optional.type(ID),
},
keywords: {
validator: $.arr($.arr($.str)),
},
excludeKeywords: {
validator: $.arr($.arr($.str)),
},
users: {
validator: $.arr($.str),
},
caseSensitive: {
validator: $.bool,
},
withReplies: {
validator: $.bool,
},
withFile: {
validator: $.bool,
},
notify: {
validator: $.bool,
},
},
errors: {
noSuchUserList: {
message: 'No such user list.',
@ -80,8 +32,36 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
name: { type: 'string', minLength: 1, maxLength: 100 },
src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'group'] },
userListId: { type: 'string', format: 'misskey:id', nullable: true },
userGroupId: { type: 'string', format: 'misskey:id', nullable: true },
keywords: { type: 'array', items: {
type: 'array', items: {
type: 'string',
},
} },
excludeKeywords: { type: 'array', items: {
type: 'array', items: {
type: 'string',
},
} },
users: { type: 'array', items: {
type: 'string',
} },
caseSensitive: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
notify: { type: 'boolean' },
},
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
let userList;
let userGroupJoining;

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Antennas } from '@/models/index';
@ -12,12 +10,6 @@ export const meta = {
kind: 'write:account',
params: {
antennaId: {
validator: $.type(ID),
},
},
errors: {
noSuchAntenna: {
message: 'No such antenna.',
@ -27,8 +19,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
antennaId: { type: 'string', format: 'misskey:id' },
},
required: ['antennaId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const antenna = await Antennas.findOne({
id: ps.antennaId,
userId: user.id,

View File

@ -19,8 +19,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const antennas = await Antennas.find({
userId: me.id,
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import readNote from '@/services/note/read';
import { Antennas, Notes, AntennaNotes } from '@/models/index';
@ -16,33 +14,6 @@ export const meta = {
kind: 'read:account',
params: {
antennaId: {
validator: $.type(ID),
},
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
sinceDate: {
validator: $.optional.num,
},
untilDate: {
validator: $.optional.num,
},
},
errors: {
noSuchAntenna: {
message: 'No such antenna.',
@ -62,8 +33,21 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
antennaId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: ['antennaId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const antenna = await Antennas.findOne({
id: ps.antennaId,
userId: user.id,
@ -92,7 +76,7 @@ export default define(meta, async (ps, user) => {
generateBlockedUserQuery(query, user);
const notes = await query
.take(ps.limit!)
.take(ps.limit)
.getMany();
if (notes.length > 0) {

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Antennas } from '@/models/index';
@ -11,12 +9,6 @@ export const meta = {
kind: 'read:account',
params: {
antennaId: {
validator: $.type(ID),
},
},
errors: {
noSuchAntenna: {
message: 'No such antenna.',
@ -32,8 +24,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
antennaId: { type: 'string', format: 'misskey:id' },
},
required: ['antennaId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
// Fetch the antenna
const antenna = await Antennas.findOne({
id: ps.antennaId,

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Antennas, UserLists, UserGroupJoinings } from '@/models/index';
@ -12,56 +10,6 @@ export const meta = {
kind: 'write:account',
params: {
antennaId: {
validator: $.type(ID),
},
name: {
validator: $.str.range(1, 100),
},
src: {
validator: $.str.or(['home', 'all', 'users', 'list', 'group']),
},
userListId: {
validator: $.nullable.optional.type(ID),
},
userGroupId: {
validator: $.nullable.optional.type(ID),
},
keywords: {
validator: $.arr($.arr($.str)),
},
excludeKeywords: {
validator: $.arr($.arr($.str)),
},
users: {
validator: $.arr($.str),
},
caseSensitive: {
validator: $.bool,
},
withReplies: {
validator: $.bool,
},
withFile: {
validator: $.bool,
},
notify: {
validator: $.bool,
},
},
errors: {
noSuchAntenna: {
message: 'No such antenna.',
@ -89,8 +37,37 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
antennaId: { type: 'string', format: 'misskey:id' },
name: { type: 'string', minLength: 1, maxLength: 100 },
src: { type: 'string', enum: ['home', 'all', 'users', 'list', 'group'] },
userListId: { type: 'string', format: 'misskey:id', nullable: true },
userGroupId: { type: 'string', format: 'misskey:id', nullable: true },
keywords: { type: 'array', items: {
type: 'array', items: {
type: 'string',
},
} },
excludeKeywords: { type: 'array', items: {
type: 'array', items: {
type: 'string',
},
} },
users: { type: 'array', items: {
type: 'string',
} },
caseSensitive: { type: 'boolean' },
withReplies: { type: 'boolean' },
withFile: { type: 'boolean' },
notify: { type: 'boolean' },
},
required: ['antennaId', 'name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
// Fetch the antenna
const antenna = await Antennas.findOne({
id: ps.antennaId,

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../define';
import Resolver from '@/remote/activitypub/resolver';
import { ApiError } from '../../error';
@ -14,12 +13,6 @@ export const meta = {
max: 30,
},
params: {
uri: {
validator: $.str,
},
},
errors: {
},
@ -29,8 +22,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
uri: { type: 'string' },
},
required: ['uri'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const resolver = new Resolver();
const object = await resolver.resolve(ps.uri);
return object;

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../define';
import config from '@/config/index';
import { createPerson } from '@/remote/activitypub/models/person';
@ -24,12 +23,6 @@ export const meta = {
max: 30,
},
params: {
uri: {
validator: $.str,
},
},
errors: {
noSuchObject: {
message: 'No such object.',
@ -75,8 +68,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
uri: { type: 'string' },
},
required: ['uri'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
const object = await fetchAny(ps.uri);
if (object) {
return object;

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../define';
import { Apps } from '@/models/index';
import { genId } from '@/misc/gen-id';
@ -10,26 +9,6 @@ export const meta = {
requireCredential: false,
params: {
name: {
validator: $.str,
},
description: {
validator: $.str,
},
permission: {
validator: $.arr($.str).unique(),
},
// TODO: Check it is valid url
callbackUrl: {
validator: $.optional.nullable.str,
default: null,
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -37,8 +16,21 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
name: { type: 'string' },
description: { type: 'string' },
permission: { type: 'array', uniqueItems: true, items: {
type: 'string',
} },
callbackUrl: { type: 'string', nullable: true },
},
required: ['name', 'description', 'permission'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
// Generate secret
const secret = secureRndstr(32, true);

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Apps } from '@/models/index';
@ -7,12 +5,6 @@ import { Apps } from '@/models/index';
export const meta = {
tags: ['app'],
params: {
appId: {
validator: $.type(ID),
},
},
errors: {
noSuchApp: {
message: 'No such app.',
@ -28,8 +20,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
appId: { type: 'string', format: 'misskey:id' },
},
required: ['appId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user, token) => {
export default define(meta, paramDef, async (ps, user, token) => {
const isSecure = user != null && token == null;
// Lookup app

View File

@ -1,5 +1,4 @@
import * as crypto from 'crypto';
import $ from 'cafy';
import define from '../../define';
import { ApiError } from '../../error';
import { AuthSessions, AccessTokens, Apps } from '@/models/index';
@ -13,12 +12,6 @@ export const meta = {
secure: true,
params: {
token: {
validator: $.str,
},
},
errors: {
noSuchSession: {
message: 'No such session.',
@ -28,8 +21,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
token: { type: 'string' },
},
required: ['token'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
// Fetch token
const session = await AuthSessions
.findOne({ token: ps.token });

View File

@ -1,5 +1,4 @@
import { v4 as uuid } from 'uuid';
import $ from 'cafy';
import config from '@/config/index';
import define from '../../../define';
import { ApiError } from '../../../error';
@ -11,12 +10,6 @@ export const meta = {
requireCredential: false,
params: {
appSecret: {
validator: $.str,
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -42,8 +35,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
appSecret: { type: 'string' },
},
required: ['appSecret'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
// Lookup app
const app = await Apps.findOne({
secret: ps.appSecret,

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { ApiError } from '../../../error';
import { AuthSessions } from '@/models/index';
@ -8,12 +7,6 @@ export const meta = {
requireCredential: false,
params: {
token: {
validator: $.str,
},
},
errors: {
noSuchSession: {
message: 'No such session.',
@ -44,8 +37,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
token: { type: 'string' },
},
required: ['token'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
// Lookup session
const session = await AuthSessions.findOne({
token: ps.token,

View File

@ -1,4 +1,3 @@
import $ from 'cafy';
import define from '../../../define';
import { ApiError } from '../../../error';
import { Apps, AuthSessions, AccessTokens, Users } from '@/models/index';
@ -8,16 +7,6 @@ export const meta = {
requireCredential: false,
params: {
appSecret: {
validator: $.str,
},
token: {
validator: $.str,
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -56,8 +45,17 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
appSecret: { type: 'string' },
token: { type: 'string' },
},
required: ['appSecret', 'token'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
export default define(meta, paramDef, async (ps) => {
// Lookup app
const app = await Apps.findOne({
secret: ps.appSecret,

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import ms from 'ms';
import create from '@/services/blocking/create';
import define from '../../define';
@ -19,12 +17,6 @@ export const meta = {
kind: 'write:blocks',
params: {
userId: {
validator: $.type(ID),
},
},
errors: {
noSuchUser: {
message: 'No such user.',
@ -52,8 +44,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const blocker = await Users.findOneOrFail(user.id);
// 自分自身

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import ms from 'ms';
import deleteBlocking from '@/services/blocking/delete';
import define from '../../define';
@ -19,12 +17,6 @@ export const meta = {
kind: 'write:blocks',
params: {
userId: {
validator: $.type(ID),
},
},
errors: {
noSuchUser: {
message: 'No such user.',
@ -52,8 +44,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
userId: { type: 'string', format: 'misskey:id' },
},
required: ['userId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const blocker = await Users.findOneOrFail(user.id);
// Check if the blockee is yourself

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Blockings } from '@/models/index';
import { makePaginationQuery } from '../../common/make-pagination-query';
@ -11,21 +9,6 @@ export const meta = {
kind: 'read:blocks',
params: {
limit: {
validator: $.optional.num.range(1, 100),
default: 30,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -37,13 +20,23 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const query = makePaginationQuery(Blockings.createQueryBuilder('blocking'), ps.sinceId, ps.untilId)
.andWhere(`blocking.blockerId = :meId`, { meId: me.id });
const blockings = await query
.take(ps.limit!)
.take(ps.limit)
.getMany();
return await Blockings.packMany(blockings, me);

View File

@ -1,10 +1,8 @@
import $ from 'cafy';
import define from '../../define';
import { ApiError } from '../../error';
import { Channels, DriveFiles } from '@/models/index';
import { Channel } from '@/models/entities/channel';
import { genId } from '@/misc/gen-id';
import { ID } from '@/misc/cafy-id';
export const meta = {
tags: ['channels'],
@ -13,20 +11,6 @@ export const meta = {
kind: 'write:channels',
params: {
name: {
validator: $.str.range(1, 128),
},
description: {
validator: $.nullable.optional.str.range(1, 2048),
},
bannerId: {
validator: $.nullable.optional.type(ID),
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -42,8 +26,18 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
name: { type: 'string', minLength: 1, maxLength: 128 },
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
},
required: ['name'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
let banner = null;
if (ps.bannerId != null) {
banner = await DriveFiles.findOne({

View File

@ -17,8 +17,14 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const query = Channels.createQueryBuilder('channel')
.where('channel.lastNotedAt IS NOT NULL')
.orderBy('channel.lastNotedAt', 'DESC');

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Channels, ChannelFollowings } from '@/models/index';
@ -13,12 +11,6 @@ export const meta = {
kind: 'write:channels',
params: {
channelId: {
validator: $.type(ID),
},
},
errors: {
noSuchChannel: {
message: 'No such channel.',
@ -28,8 +20,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
channelId: { type: 'string', format: 'misskey:id' },
},
required: ['channelId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const channel = await Channels.findOne({
id: ps.channelId,
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Channels, ChannelFollowings } from '@/models/index';
import { makePaginationQuery } from '../../common/make-pagination-query';
@ -11,21 +9,6 @@ export const meta = {
kind: 'read:channels',
params: {
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
limit: {
validator: $.optional.num.range(1, 100),
default: 5,
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -37,13 +20,23 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const query = makePaginationQuery(ChannelFollowings.createQueryBuilder(), ps.sinceId, ps.untilId)
.andWhere({ followerId: me.id });
const followings = await query
.take(ps.limit!)
.take(ps.limit)
.getMany();
return await Promise.all(followings.map(x => Channels.pack(x.followeeId, me)));

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { Channels } from '@/models/index';
import { makePaginationQuery } from '../../common/make-pagination-query';
@ -11,21 +9,6 @@ export const meta = {
kind: 'read:channels',
params: {
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
limit: {
validator: $.optional.num.range(1, 100),
default: 5,
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -37,13 +20,23 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
},
required: [],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const query = makePaginationQuery(Channels.createQueryBuilder(), ps.sinceId, ps.untilId)
.andWhere({ userId: me.id });
const channels = await query
.take(ps.limit!)
.take(ps.limit)
.getMany();
return await Promise.all(channels.map(x => Channels.pack(x, me)));

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Channels } from '@/models/index';
@ -9,12 +7,6 @@ export const meta = {
requireCredential: false,
params: {
channelId: {
validator: $.type(ID),
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -30,8 +22,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
channelId: { type: 'string', format: 'misskey:id' },
},
required: ['channelId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const channel = await Channels.findOne({
id: ps.channelId,
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Notes, Channels } from '@/models/index';
@ -11,33 +9,6 @@ export const meta = {
requireCredential: false,
params: {
channelId: {
validator: $.type(ID),
},
limit: {
validator: $.optional.num.range(1, 100),
default: 10,
},
sinceId: {
validator: $.optional.type(ID),
},
untilId: {
validator: $.optional.type(ID),
},
sinceDate: {
validator: $.optional.num,
},
untilDate: {
validator: $.optional.num,
},
},
res: {
type: 'array',
optional: false, nullable: false,
@ -57,8 +28,21 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
channelId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: ['channelId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const channel = await Channels.findOne({
id: ps.channelId,
});
@ -78,7 +62,7 @@ export default define(meta, async (ps, user) => {
.leftJoinAndSelect('note.channel', 'channel');
//#endregion
const timeline = await query.take(ps.limit!).getMany();
const timeline = await query.take(ps.limit).getMany();
if (user) activeUsersChart.read(user);

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Channels, ChannelFollowings } from '@/models/index';
@ -12,12 +10,6 @@ export const meta = {
kind: 'write:channels',
params: {
channelId: {
validator: $.type(ID),
},
},
errors: {
noSuchChannel: {
message: 'No such channel.',
@ -27,8 +19,16 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
channelId: { type: 'string', format: 'misskey:id' },
},
required: ['channelId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, user) => {
export default define(meta, paramDef, async (ps, user) => {
const channel = await Channels.findOne({
id: ps.channelId,
});

View File

@ -1,5 +1,3 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
import { Channels, DriveFiles } from '@/models/index';
@ -11,24 +9,6 @@ export const meta = {
kind: 'write:channels',
params: {
channelId: {
validator: $.type(ID),
},
name: {
validator: $.optional.str.range(1, 128),
},
description: {
validator: $.nullable.optional.str.range(1, 2048),
},
bannerId: {
validator: $.nullable.optional.type(ID),
},
},
res: {
type: 'object',
optional: false, nullable: false,
@ -56,8 +36,19 @@ export const meta = {
},
} as const;
const paramDef = {
type: 'object',
properties: {
channelId: { type: 'string', format: 'misskey:id' },
name: { type: 'string', minLength: 1, maxLength: 128 },
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
},
required: ['channelId'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps, me) => {
export default define(meta, paramDef, async (ps, me) => {
const channel = await Channels.findOne({
id: ps.channelId,
});

View File

@ -1,31 +1,24 @@
import $ from 'cafy';
import define from '../../define';
import { convertLog } from '@/services/chart/core';
import { getJsonSchema } from '@/services/chart/core';
import { activeUsersChart } from '@/services/chart/index';
export const meta = {
tags: ['charts', 'users'],
params: {
span: {
validator: $.str.or(['day', 'hour']),
},
res: getJsonSchema(activeUsersChart.schema),
} as const;
limit: {
validator: $.optional.num.range(1, 500),
default: 30,
const paramDef = {
type: 'object',
properties: {
span: { type: 'string', enum: ['day', 'hour'] },
limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 },
offset: { type: 'integer', nullable: true, default: null },
},
offset: {
validator: $.optional.nullable.num,
default: null,
},
},
// TODO: response definition
required: ['span'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
return await activeUsersChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null);
export default define(meta, paramDef, async (ps) => {
return await activeUsersChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null);
});

View File

@ -1,31 +1,24 @@
import $ from 'cafy';
import define from '../../define';
import { convertLog } from '@/services/chart/core';
import { getJsonSchema } from '@/services/chart/core';
import { apRequestChart } from '@/services/chart/index';
export const meta = {
tags: ['charts'],
params: {
span: {
validator: $.str.or(['day', 'hour']),
},
res: getJsonSchema(apRequestChart.schema),
} as const;
limit: {
validator: $.optional.num.range(1, 500),
default: 30,
const paramDef = {
type: 'object',
properties: {
span: { type: 'string', enum: ['day', 'hour'] },
limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 },
offset: { type: 'integer', nullable: true, default: null },
},
offset: {
validator: $.optional.nullable.num,
default: null,
},
},
// TODO: response definition
required: ['span'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
return await apRequestChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null);
export default define(meta, paramDef, async (ps) => {
return await apRequestChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null);
});

View File

@ -1,31 +1,24 @@
import $ from 'cafy';
import define from '../../define';
import { convertLog } from '@/services/chart/core';
import { getJsonSchema } from '@/services/chart/core';
import { driveChart } from '@/services/chart/index';
export const meta = {
tags: ['charts', 'drive'],
params: {
span: {
validator: $.str.or(['day', 'hour']),
},
res: getJsonSchema(driveChart.schema),
} as const;
limit: {
validator: $.optional.num.range(1, 500),
default: 30,
const paramDef = {
type: 'object',
properties: {
span: { type: 'string', enum: ['day', 'hour'] },
limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 },
offset: { type: 'integer', nullable: true, default: null },
},
offset: {
validator: $.optional.nullable.num,
default: null,
},
},
// TODO: response definition
required: ['span'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
return await driveChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null);
export default define(meta, paramDef, async (ps) => {
return await driveChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null);
});

View File

@ -1,31 +1,24 @@
import $ from 'cafy';
import define from '../../define';
import { convertLog } from '@/services/chart/core';
import { getJsonSchema } from '@/services/chart/core';
import { federationChart } from '@/services/chart/index';
export const meta = {
tags: ['charts'],
params: {
span: {
validator: $.str.or(['day', 'hour']),
},
res: getJsonSchema(federationChart.schema),
} as const;
limit: {
validator: $.optional.num.range(1, 500),
default: 30,
const paramDef = {
type: 'object',
properties: {
span: { type: 'string', enum: ['day', 'hour'] },
limit: { type: 'integer', minimum: 1, maximum: 500, default: 30 },
offset: { type: 'integer', nullable: true, default: null },
},
offset: {
validator: $.optional.nullable.num,
default: null,
},
},
// TODO: response definition
required: ['span'],
} as const;
// eslint-disable-next-line import/no-default-export
export default define(meta, async (ps) => {
return await federationChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null);
export default define(meta, paramDef, async (ps) => {
return await federationChart.getChart(ps.span, ps.limit, ps.offset ? new Date(ps.offset) : null);
});

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