mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-12-24 21:03:09 +02:00
wip
This commit is contained in:
parent
8adf2701d2
commit
810d065d21
19 changed files with 144 additions and 543 deletions
|
@ -6,6 +6,7 @@ import { ApiError } from './error.js';
|
|||
import { endpoints } from 'misskey-js/built/endpoints.js';
|
||||
import type { IEndpointMeta, ResponseOf, SchemaOrUndefined } from 'misskey-js/built/endpoints.types.js';
|
||||
import type { Endpoints } from 'misskey-js';
|
||||
import { WeakSerialized } from 'schema-type';
|
||||
|
||||
const ajv = new Ajv({
|
||||
useDefaults: true,
|
||||
|
@ -29,7 +30,7 @@ export type Executor<T extends IEndpointMeta, P = SchemaOrUndefined<T['defines']
|
|||
cleanup?: () => any,
|
||||
ip?: string | null,
|
||||
headers?: Record<string, string> | null
|
||||
) => Promise<ResponseOf<T, P>>;
|
||||
) => Promise<WeakSerialized<ResponseOf<T, P>>>;
|
||||
|
||||
// ExecutorWrapperの型はあえて緩くしておく
|
||||
export type ExecutorWrapper =
|
||||
|
|
|
@ -7,34 +7,10 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|||
import { localUsernameSchema, passwordSchema } from '@/models/entities/User.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'User',
|
||||
properties: {
|
||||
token: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
username: localUsernameSchema,
|
||||
password: passwordSchema,
|
||||
},
|
||||
required: ['username', 'password'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/accounts/create'> {
|
||||
name = 'admin/accounts/create' as const;
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
@ -42,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
private userEntityService: UserEntityService,
|
||||
private signupService: SignupService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, _me) => {
|
||||
super(async (ps, _me) => {
|
||||
const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null;
|
||||
const noUsers = (await this.usersRepository.countBy({
|
||||
host: IsNull(),
|
||||
|
@ -55,14 +31,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
ignorePreservedUsernames: true,
|
||||
});
|
||||
|
||||
const res = await this.userEntityService.pack(account, account, {
|
||||
const res = await this.userEntityService.pack<true, true>(account, account, {
|
||||
detail: true,
|
||||
includeSecrets: true,
|
||||
});
|
||||
|
||||
(res as any).token = secret;
|
||||
|
||||
return res;
|
||||
return { ...res, token: secret };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,10 @@ import { UserSuspendService } from '@/core/UserSuspendService.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireAdmin: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
userId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['userId'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/accounts/delete'> {
|
||||
name = 'admin/accounts/delete' as const;
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
@ -34,7 +20,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
private globalEventService: GlobalEventService,
|
||||
private userSuspendService: UserSuspendService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const user = await this.usersRepository.findOneBy({ id: ps.userId });
|
||||
|
||||
if (user == null) {
|
||||
|
|
|
@ -4,38 +4,17 @@ import type { AdsRepository } from '@/models/index.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: { type: 'string', minLength: 1 },
|
||||
memo: { type: 'string' },
|
||||
place: { type: 'string' },
|
||||
priority: { type: 'string' },
|
||||
ratio: { type: 'integer' },
|
||||
expiresAt: { type: 'integer' },
|
||||
startsAt: { type: 'integer' },
|
||||
imageUrl: { type: 'string', minLength: 1 },
|
||||
},
|
||||
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/ad/create'> {
|
||||
name = 'admin/ad/create' as const;
|
||||
constructor(
|
||||
@Inject(DI.adsRepository)
|
||||
private adsRepository: AdsRepository,
|
||||
|
||||
private idService: IdService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
await this.adsRepository.insert({
|
||||
id: this.idService.genId(),
|
||||
createdAt: new Date(),
|
||||
|
|
|
@ -4,40 +4,18 @@ import type { AdsRepository } from '@/models/index.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchAd: {
|
||||
message: 'No such ad.',
|
||||
code: 'NO_SUCH_AD',
|
||||
id: 'ccac9863-3a03-416e-b899-8a64041118b1',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['id'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/ad/delete'> {
|
||||
name = 'admin/ad/delete' as const;
|
||||
constructor(
|
||||
@Inject(DI.adsRepository)
|
||||
private adsRepository: AdsRepository,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const ad = await this.adsRepository.findOneBy({ id: ps.id });
|
||||
|
||||
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
|
||||
if (ad == null) throw new ApiError(this.meta.errors.noSuchAd);
|
||||
|
||||
await this.adsRepository.delete(ad.id);
|
||||
});
|
||||
|
|
|
@ -23,14 +23,15 @@ export const paramDef = {
|
|||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/ad/list'> {
|
||||
name = 'admin/ad/list' as const;
|
||||
constructor(
|
||||
@Inject(DI.adsRepository)
|
||||
private adsRepository: AdsRepository,
|
||||
|
||||
private queryService: QueryService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
|
||||
const ads = await query.take(ps.limit).getMany();
|
||||
|
||||
|
|
|
@ -4,37 +4,6 @@ import type { AdsRepository } from '@/models/index.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchAd: {
|
||||
message: 'No such ad.',
|
||||
code: 'NO_SUCH_AD',
|
||||
id: 'b7aa1727-1354-47bc-a182-3a9c3973d300',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
memo: { type: 'string' },
|
||||
url: { type: 'string', minLength: 1 },
|
||||
imageUrl: { type: 'string', minLength: 1 },
|
||||
place: { type: 'string' },
|
||||
priority: { type: 'string' },
|
||||
ratio: { type: 'integer' },
|
||||
expiresAt: { type: 'integer' },
|
||||
startsAt: { type: 'integer' },
|
||||
},
|
||||
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<'admin/ad/update'> {
|
||||
|
|
|
@ -4,68 +4,17 @@ import type { AnnouncementsRepository } from '@/models/index.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'date-time',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
text: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
imageUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
title: { type: 'string', minLength: 1 },
|
||||
text: { type: 'string', minLength: 1 },
|
||||
imageUrl: { type: 'string', nullable: true, minLength: 1 },
|
||||
},
|
||||
required: ['title', 'text', 'imageUrl'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/announcements/create'> {
|
||||
name = 'admin/announcements/create' as const;
|
||||
constructor(
|
||||
@Inject(DI.announcementsRepository)
|
||||
private announcementsRepository: AnnouncementsRepository,
|
||||
|
||||
private idService: IdService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const announcement = await this.announcementsRepository.insert({
|
||||
id: this.idService.genId(),
|
||||
createdAt: new Date(),
|
||||
|
|
|
@ -4,40 +4,18 @@ import type { AnnouncementsRepository } from '@/models/index.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchAnnouncement: {
|
||||
message: 'No such announcement.',
|
||||
code: 'NO_SUCH_ANNOUNCEMENT',
|
||||
id: 'ecad8040-a276-4e85-bda9-015a708d291e',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['id'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/announcements/delete'> {
|
||||
name = 'admin/announcements/delete' as const;
|
||||
constructor(
|
||||
@Inject(DI.announcementsRepository)
|
||||
private announcementsRepository: AnnouncementsRepository,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
|
||||
|
||||
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
|
||||
if (announcement == null) throw new ApiError(this.meta.errors.noSuchAnnouncement);
|
||||
|
||||
await this.announcementsRepository.delete(announcement.id);
|
||||
});
|
||||
|
|
|
@ -5,69 +5,10 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
|||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'date-time',
|
||||
},
|
||||
text: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
imageUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
reads: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/announcements/list'> {
|
||||
name = 'admin/announcements/list' as const;
|
||||
constructor(
|
||||
@Inject(DI.announcementsRepository)
|
||||
private announcementsRepository: AnnouncementsRepository,
|
||||
|
@ -77,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
|
||||
private queryService: QueryService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
|
||||
|
||||
const announcements = await query.take(ps.limit).getMany();
|
||||
|
|
|
@ -4,43 +4,18 @@ import type { AnnouncementsRepository } from '@/models/index.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchAnnouncement: {
|
||||
message: 'No such announcement.',
|
||||
code: 'NO_SUCH_ANNOUNCEMENT',
|
||||
id: 'd3aae5a7-6372-4cb4-b61c-f511ffc2d7cc',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
title: { type: 'string', minLength: 1 },
|
||||
text: { type: 'string', minLength: 1 },
|
||||
imageUrl: { type: 'string', nullable: true, minLength: 1 },
|
||||
},
|
||||
required: ['id', 'title', 'text', 'imageUrl'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/announcements/update'> {
|
||||
name = 'admin/announcements/update' as const;
|
||||
constructor(
|
||||
@Inject(DI.announcementsRepository)
|
||||
private announcementsRepository: AnnouncementsRepository,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const announcement = await this.announcementsRepository.findOneBy({ id: ps.id });
|
||||
|
||||
if (announcement == null) throw new ApiError(meta.errors.noSuchAnnouncement);
|
||||
if (announcement == null) throw new ApiError(this.meta.errors.noSuchAnnouncement);
|
||||
|
||||
await this.announcementsRepository.update(announcement.id, {
|
||||
updatedAt: new Date(),
|
||||
|
|
|
@ -2,26 +2,14 @@ import { Injectable } from '@nestjs/common';
|
|||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { QueueService } from '@/core/QueueService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/drive/clean-remote-files'> {
|
||||
name = 'admin/drive/clean-remote-files' as const;
|
||||
constructor(
|
||||
private queueService: QueueService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
this.queueService.createCleanRemoteFilesJob();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,29 +5,17 @@ import type { DriveFilesRepository } from '@/models/index.js';
|
|||
import { DriveService } from '@/core/DriveService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/drive/cleanup'> {
|
||||
name = 'admin/drive/cleanup' as const;
|
||||
constructor(
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private driveService: DriveService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const files = await this.driveFilesRepository.findBy({
|
||||
userId: IsNull(),
|
||||
});
|
||||
|
|
|
@ -5,45 +5,10 @@ import { QueryService } from '@/core/QueryService.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'DriveFile',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) },
|
||||
origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' },
|
||||
hostname: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
default: null,
|
||||
description: 'The local host is represented with `null`.',
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/drive/files'> {
|
||||
name = 'admin/drive/files' as const;
|
||||
constructor(
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
@ -51,7 +16,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
private driveFileEntityService: DriveFileEntityService,
|
||||
private queryService: QueryService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId);
|
||||
|
||||
if (ps.userId) {
|
||||
|
|
|
@ -5,152 +5,10 @@ import { DI } from '@/di-symbols.js';
|
|||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchFile: {
|
||||
message: 'No such file.',
|
||||
code: 'NO_SUCH_FILE',
|
||||
id: 'caf3ca38-c6e5-472e-a30c-b05377dcc240',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
userHost: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
description: 'The local host is represented with `null`.',
|
||||
},
|
||||
md5: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'md5',
|
||||
example: '15eca7fba0480996e2245f5185bf39f2',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
example: 'lenna.jpg',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
example: 'image/jpeg',
|
||||
},
|
||||
size: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
example: 51469,
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
blurhash: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
properties: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
storedInternal: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: true,
|
||||
example: true,
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'url',
|
||||
},
|
||||
thumbnailUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'url',
|
||||
},
|
||||
webpublicUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'url',
|
||||
},
|
||||
accessKey: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
thumbnailAccessKey: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
webpublicAccessKey: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
uri: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
src: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
folderId: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
isSensitive: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
isLink: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fileId: { type: 'string', format: 'misskey:id' },
|
||||
url: { type: 'string' },
|
||||
},
|
||||
anyOf: [
|
||||
{ required: ['fileId'] },
|
||||
{ required: ['url'] },
|
||||
],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
export default class extends Endpoint<'admin/drive/show-file'> {
|
||||
name = 'admin/drive/show-file' as const;
|
||||
constructor(
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
@ -160,7 +18,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
super(async (ps, me) => {
|
||||
const file = ps.fileId ? await this.driveFilesRepository.findOneBy({ id: ps.fileId }) : await this.driveFilesRepository.findOne({
|
||||
where: [{
|
||||
url: ps.url,
|
||||
|
@ -172,7 +30,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||
});
|
||||
|
||||
if (file == null) {
|
||||
throw new ApiError(meta.errors.noSuchFile);
|
||||
throw new ApiError(this.meta.errors.noSuchFile);
|
||||
}
|
||||
|
||||
const owner = file.userId ? await this.usersRepository.findOneByOrFail({
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { Endpoints, SchemaOrUndefined, IEndpointMeta, ResponseOf } from './endpoints.types.js';
|
||||
import type { Serialized, WeakSerialized } from 'schema-type';
|
||||
|
||||
const MK_API_ERROR = Symbol();
|
||||
|
||||
|
@ -42,9 +43,10 @@ export class APIClient {
|
|||
this.fetch = opts.fetch ?? ((...args) => fetch(...args));
|
||||
}
|
||||
|
||||
// WeakSerialized<P>で推論が効くかは知らない
|
||||
public request<E extends keyof Endpoints, P extends SchemaOrUndefined<M['defines'][number]['req']>, M extends IEndpointMeta = Endpoints[E], R = ResponseOf<M, P>>(
|
||||
endpoint: E, params: P, credential?: string | null | undefined,
|
||||
): Promise<R>
|
||||
endpoint: E, params: WeakSerialized<P>, credential?: string | null | undefined,
|
||||
): Promise<Serialized<R>>
|
||||
{
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this.fetch(`${this.origin}/api/${endpoint}`, {
|
||||
|
|
|
@ -269,7 +269,7 @@ export const endpoints = {
|
|||
res: undefined,
|
||||
}],
|
||||
},
|
||||
"admin/drive/clenaup": {
|
||||
"admin/drive/cleanup": {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
|
@ -354,24 +354,94 @@ export const endpoints = {
|
|||
],
|
||||
},
|
||||
res: {
|
||||
allOf: [{
|
||||
$ref: 'https://misskey-hub.net/api/schemas/DriveFile',
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
requestIp: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
requestHeaders: {
|
||||
oneOf: [{
|
||||
type: 'object',
|
||||
}, {
|
||||
type: 'null',
|
||||
}],
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { $ref: 'https://misskey-hub.net/api/schemas/Id' },
|
||||
createdAt: { type: 'string', format: 'date-time' },
|
||||
userId: {
|
||||
oneOf: [
|
||||
{ $ref: 'https://misskey-hub.net/api/schemas/Id' },
|
||||
{ type: 'null' },
|
||||
]
|
||||
},
|
||||
required: ['requestIp', 'requestHeaders'],
|
||||
}],
|
||||
userHost: { type: ['string', 'null'] },
|
||||
md5: { type: 'string', format: 'md5', examples: '1bc29b36f623ba82aaf6724fd3b16718' },
|
||||
name: { type: 'string', examples: 'lenna.jpg' },
|
||||
type: { type: 'string', examples: 'image/jpeg' },
|
||||
size: { type: 'number', examples: 51469 },
|
||||
comment: { type: ['string', 'null'] },
|
||||
blurhash: { type: ['string', 'null'] },
|
||||
properties: { type: 'object' },
|
||||
storedInternal: { type: ['boolean', 'null'], examples: true },
|
||||
url: {
|
||||
oneOf: [
|
||||
{ type: 'string', format: 'url' },
|
||||
{ type: 'null' },
|
||||
],
|
||||
},
|
||||
thumbnailUrl: {
|
||||
oneOf: [
|
||||
{ type: 'string', format: 'url' },
|
||||
{ type: 'null' },
|
||||
],
|
||||
},
|
||||
webpublicUrl: {
|
||||
oneOf: [
|
||||
{ type: 'string', format: 'url' },
|
||||
{ type: 'null' },
|
||||
],
|
||||
},
|
||||
accessKey: { type: ['string', 'null'] },
|
||||
thumbnailAccessKey: { type: ['string', 'null'] },
|
||||
webpublicAccessKey: { type: ['string', 'null'] },
|
||||
uri: { type: ['string', 'null'] },
|
||||
src: { type: ['string', 'null'] },
|
||||
folderId: {
|
||||
oneOf: [
|
||||
{ $ref: 'https://misskey-hub.net/api/schemas/Id' },
|
||||
{ type: 'null' },
|
||||
]
|
||||
},
|
||||
isSensitive: { type: 'boolean' },
|
||||
isLink: { type: 'boolean' },
|
||||
requestIp: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
requestHeaders: {
|
||||
oneOf: [{
|
||||
type: 'object',
|
||||
}, {
|
||||
type: 'null',
|
||||
}],
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'id',
|
||||
'createdAt',
|
||||
'userId',
|
||||
'userHost',
|
||||
'md5',
|
||||
'name',
|
||||
'type',
|
||||
'size',
|
||||
'comment',
|
||||
'blurhash',
|
||||
'properties',
|
||||
'storedInternal',
|
||||
'url',
|
||||
'thumbnailUrl',
|
||||
'webpublicUrl',
|
||||
'accessKey',
|
||||
'thumbnailAccessKey',
|
||||
'webpublicAccessKey',
|
||||
'uri',
|
||||
'src',
|
||||
'folderId',
|
||||
'isSensitive',
|
||||
'isLink',
|
||||
'requestIp',
|
||||
'requestHeaders',
|
||||
],
|
||||
},
|
||||
}],
|
||||
},
|
||||
|
|
|
@ -40,7 +40,6 @@ export const packedAdSchema = {
|
|||
'expiresAt',
|
||||
'startsAt',
|
||||
'place',
|
||||
'property',
|
||||
'ratio',
|
||||
'imageUrl',
|
||||
'memo',
|
||||
|
|
|
@ -626,7 +626,7 @@ importers:
|
|||
version: 29.5.0
|
||||
schema-type:
|
||||
specifier: github:misskey-dev/schema-type
|
||||
version: github.com/misskey-dev/schema-type/e24efd7bba40f638b3b687298873fa56de56aab3(typescript@5.0.4)
|
||||
version: github.com/misskey-dev/schema-type/3e1f60a3486ad51a01912bd7bb092d5bcf47473e(typescript@5.0.4)
|
||||
|
||||
packages/frontend:
|
||||
dependencies:
|
||||
|
@ -1026,7 +1026,7 @@ importers:
|
|||
version: 4.4.0
|
||||
schema-type:
|
||||
specifier: github:misskey-dev/schema-type
|
||||
version: github.com/misskey-dev/schema-type/e24efd7bba40f638b3b687298873fa56de56aab3(typescript@5.0.4)
|
||||
version: github.com/misskey-dev/schema-type/3e1f60a3486ad51a01912bd7bb092d5bcf47473e(typescript@5.0.4)
|
||||
ts-essentials:
|
||||
specifier: ^9.3.2
|
||||
version: 9.3.2(typescript@5.0.4)
|
||||
|
@ -20455,9 +20455,9 @@ packages:
|
|||
version: 0.0.0
|
||||
dev: false
|
||||
|
||||
github.com/misskey-dev/schema-type/e24efd7bba40f638b3b687298873fa56de56aab3(typescript@5.0.4):
|
||||
resolution: {tarball: https://codeload.github.com/misskey-dev/schema-type/tar.gz/e24efd7bba40f638b3b687298873fa56de56aab3}
|
||||
id: github.com/misskey-dev/schema-type/e24efd7bba40f638b3b687298873fa56de56aab3
|
||||
github.com/misskey-dev/schema-type/3e1f60a3486ad51a01912bd7bb092d5bcf47473e(typescript@5.0.4):
|
||||
resolution: {tarball: https://codeload.github.com/misskey-dev/schema-type/tar.gz/3e1f60a3486ad51a01912bd7bb092d5bcf47473e}
|
||||
id: github.com/misskey-dev/schema-type/3e1f60a3486ad51a01912bd7bb092d5bcf47473e
|
||||
name: schema-type
|
||||
version: 1.0.0
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue