Merge tag '2023.12.0' into merge-upstream
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class bannedEmailDomains1703209889304 {
|
||||
constructor() {
|
||||
this.name = 'bannedEmailDomains1703209889304';
|
||||
}
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "bannedEmailDomains" character varying(1024) array NOT NULL DEFAULT '{}'`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "bannedEmailDomains"`);
|
||||
}
|
||||
}
|
@@ -9,6 +9,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { validate as validateEmail } from 'deep-email-validator';
|
||||
import { SubOutputFormat } from 'deep-email-validator/dist/output/output.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type Logger from '@/logger.js';
|
||||
@@ -30,6 +31,7 @@ export class EmailService {
|
||||
|
||||
private metaService: MetaService,
|
||||
private loggerService: LoggerService,
|
||||
private utilityService: UtilityService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
) {
|
||||
this.logger = this.loggerService.getLogger('email');
|
||||
@@ -155,7 +157,7 @@ export class EmailService {
|
||||
@bindThis
|
||||
public async validateEmailForAccount(emailAddress: string): Promise<{
|
||||
available: boolean;
|
||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp';
|
||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned';
|
||||
}> {
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
@@ -164,32 +166,35 @@ export class EmailService {
|
||||
email: emailAddress,
|
||||
});
|
||||
|
||||
const verifymailApi = meta.enableVerifymailApi && meta.verifymailAuthKey != null;
|
||||
let validated;
|
||||
|
||||
if (meta.enableActiveEmailValidation && meta.verifymailAuthKey) {
|
||||
if (verifymailApi) {
|
||||
if (meta.enableActiveEmailValidation) {
|
||||
if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
|
||||
validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
|
||||
} else {
|
||||
validated = meta.enableActiveEmailValidation ? await validateEmail({
|
||||
validated = await validateEmail({
|
||||
email: emailAddress,
|
||||
validateRegex: true,
|
||||
validateMx: true,
|
||||
validateTypo: false, // TLDを見ているみたいだけどclubとか弾かれるので
|
||||
validateDisposable: true, // 捨てアドかどうかチェック
|
||||
validateSMTP: false, // 日本だと25ポートが殆どのプロバイダーで塞がれていてタイムアウトになるので
|
||||
}) : { valid: true, reason: null };
|
||||
});
|
||||
}
|
||||
} else {
|
||||
validated = { valid: true, reason: null };
|
||||
}
|
||||
|
||||
const available = exist === 0 && validated.valid;
|
||||
const emailDomain: string = emailAddress.split('@')[1];
|
||||
const isBanned = this.utilityService.isBlockedHost(meta.bannedEmailDomains, emailDomain);
|
||||
|
||||
const available = exist === 0 && validated.valid && !isBanned;
|
||||
|
||||
return {
|
||||
available,
|
||||
reason: available ? null :
|
||||
exist !== 0 ? 'used' :
|
||||
isBanned ? 'banned' :
|
||||
validated.reason === 'regex' ? 'format' :
|
||||
validated.reason === 'disposable' ? 'disposable' :
|
||||
validated.reason === 'mx' ? 'mx' :
|
||||
|
@@ -293,7 +293,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
// Check blocking
|
||||
if (data.renote && this.isQuote(data)) {
|
||||
if (data.renote && !this.isQuote(data)) {
|
||||
if (data.renote.userHost === null) {
|
||||
if (data.renote.userId !== user.id) {
|
||||
const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id);
|
||||
@@ -731,8 +731,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private isQuote(note: Option): boolean {
|
||||
return !!note.text || !!note.cw || !!note.files || !!note.poll;
|
||||
private isQuote(note: Option): note is Option & { renote: MiNote } {
|
||||
// sync with misc/is-quote.ts
|
||||
return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
@@ -801,7 +802,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
|
||||
if (data.localOnly) return null;
|
||||
|
||||
const content = data.renote && this.isQuote(data)
|
||||
const content = data.renote && !this.isQuote(data)
|
||||
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
|
||||
: this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
|
||||
|
||||
|
@@ -3,8 +3,9 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||
import { Inject, Injectable, OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
|
||||
import * as Redis from 'ioredis';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import type { UserListMembershipsRepository } from '@/models/_.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import type { MiUserList } from '@/models/UserList.js';
|
||||
@@ -21,12 +22,15 @@ import { RedisKVCache } from '@/misc/cache.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserListService implements OnApplicationShutdown {
|
||||
export class UserListService implements OnApplicationShutdown, OnModuleInit {
|
||||
public static TooManyUsersError = class extends Error {};
|
||||
|
||||
public membersCache: RedisKVCache<Set<string>>;
|
||||
private roleService: RoleService;
|
||||
|
||||
constructor(
|
||||
private moduleRef: ModuleRef,
|
||||
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
|
||||
@@ -38,7 +42,6 @@ export class UserListService implements OnApplicationShutdown {
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private idService: IdService,
|
||||
private roleService: RoleService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private proxyAccountService: ProxyAccountService,
|
||||
private queueService: QueueService,
|
||||
@@ -54,6 +57,10 @@ export class UserListService implements OnApplicationShutdown {
|
||||
this.redisForSub.on('message', this.onMessage);
|
||||
}
|
||||
|
||||
async onModuleInit() {
|
||||
this.roleService = this.moduleRef.get(RoleService.name);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async onMessage(_: string, data: string): Promise<void> {
|
||||
const obj = JSON.parse(data);
|
||||
|
@@ -7,5 +7,6 @@ import type { MiNote } from '@/models/Note.js';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function(note: MiNote): boolean {
|
||||
// sync with NoteCreateService.isQuote
|
||||
return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0));
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@ import { packedUserListMembershipSchema, packedUserListSchema } from '@/models/j
|
||||
import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js';
|
||||
import { packedSigninSchema } from '@/models/json-schema/signin.js';
|
||||
import { packedRoleLiteSchema, packedRoleSchema } from '@/models/json-schema/role.js';
|
||||
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
||||
|
||||
export const refs = {
|
||||
UserLite: packedUserLiteSchema,
|
||||
@@ -52,6 +53,7 @@ export const refs = {
|
||||
|
||||
UserList: packedUserListSchema,
|
||||
UserListMembership: packedUserListMembershipSchema,
|
||||
Ad: packedAdSchema,
|
||||
Announcement: packedAnnouncementSchema,
|
||||
App: packedAppSchema,
|
||||
Note: packedNoteSchema,
|
||||
|
@@ -495,6 +495,13 @@ export class MiMeta {
|
||||
})
|
||||
public manifestJsonOverride: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
array: true,
|
||||
default: '{}',
|
||||
})
|
||||
public bannedEmailDomains: string[];
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, array: true, default: '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }',
|
||||
})
|
||||
|
64
packages/backend/src/models/json-schema/ad.ts
Normal file
64
packages/backend/src/models/json-schema/ad.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export const packedAdSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
format: 'id',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
expiresAt: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
startsAt: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
place: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
priority: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
ratio: {
|
||||
type: 'number',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
imageUrl: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
memo: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
dayOfWeek: {
|
||||
type: 'integer',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
@@ -25,6 +25,11 @@ export const meta = {
|
||||
id: 'cb865949-8af5-4062-a88c-ef55e8786d1d',
|
||||
},
|
||||
},
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'User',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -17,6 +17,12 @@ export const meta = {
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
ref: 'Ad',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -63,7 +69,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
ad: ad,
|
||||
});
|
||||
|
||||
return ad;
|
||||
return {
|
||||
id: ad.id,
|
||||
expiresAt: ad.expiresAt.toISOString(),
|
||||
startsAt: ad.startsAt.toISOString(),
|
||||
dayOfWeek: ad.dayOfWeek,
|
||||
url: ad.url,
|
||||
imageUrl: ad.imageUrl,
|
||||
priority: ad.priority,
|
||||
ratio: ad.ratio,
|
||||
place: ad.place,
|
||||
memo: ad.memo,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,17 @@ export const meta = {
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
ref: 'Ad',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -46,7 +57,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
}
|
||||
const ads = await query.limit(ps.limit).getMany();
|
||||
|
||||
return ads;
|
||||
return ads.map(ad => ({
|
||||
id: ad.id,
|
||||
expiresAt: ad.expiresAt.toISOString(),
|
||||
startsAt: ad.startsAt.toISOString(),
|
||||
dayOfWeek: ad.dayOfWeek,
|
||||
url: ad.url,
|
||||
imageUrl: ad.imageUrl,
|
||||
memo: ad.memo,
|
||||
place: ad.place,
|
||||
priority: ad.priority,
|
||||
ratio: ad.ratio,
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,8 @@ export const meta = {
|
||||
id: 'f7a3462c-4e6e-4069-8421-b9bd4f4c3975',
|
||||
},
|
||||
},
|
||||
|
||||
ref: 'EmojiDetailed',
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -15,6 +15,16 @@ export const meta = {
|
||||
kind: 'read:admin',
|
||||
|
||||
tags: ['admin'],
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
tablename: { type: 'string' },
|
||||
indexname: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -16,6 +16,25 @@ export const meta = {
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
properties: {
|
||||
ip: { type: 'string' },
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -145,6 +145,14 @@ export const meta = {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
bannedEmailDomains: {
|
||||
type: 'array',
|
||||
optional: true, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
preservedUsernames: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
@@ -521,6 +529,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
||||
enableServerMachineStats: instance.enableServerMachineStats,
|
||||
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
||||
bannedEmailDomains: instance.bannedEmailDomains,
|
||||
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||
manifestJsonOverride: instance.manifestJsonOverride,
|
||||
enableFanoutTimeline: instance.enableFanoutTimeline,
|
||||
|
@@ -28,6 +28,20 @@ export const meta = {
|
||||
id: '224eff5e-2488-4b18-b3e7-f50d94421648',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
createdAt: { type: 'string', format: 'date-time' },
|
||||
user: { ref: 'UserDetailed' },
|
||||
expiresAt: { type: 'string', format: 'date-time', nullable: true },
|
||||
},
|
||||
required: ['id', 'createdAt', 'user'],
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -80,7 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
id: assign.id,
|
||||
createdAt: this.idService.parse(assign.id).date.toISOString(),
|
||||
user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
|
||||
expiresAt: assign.expiresAt,
|
||||
expiresAt: assign.expiresAt?.toISOString() ?? null,
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
@@ -122,6 +122,7 @@ export const paramDef = {
|
||||
enableServerMachineStats: { type: 'boolean' },
|
||||
enableIdenticonGeneration: { type: 'boolean' },
|
||||
serverRules: { type: 'array', items: { type: 'string' } },
|
||||
bannedEmailDomains: { type: 'array', items: { type: 'string' } },
|
||||
preservedUsernames: { type: 'array', items: { type: 'string' } },
|
||||
manifestJsonOverride: { type: 'string' },
|
||||
enableFanoutTimeline: { type: 'boolean' },
|
||||
@@ -534,6 +535,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
set.notesPerOneAd = ps.notesPerOneAd;
|
||||
}
|
||||
|
||||
if (ps.bannedEmailDomains !== undefined) {
|
||||
set.bannedEmailDomains = ps.bannedEmailDomains;
|
||||
}
|
||||
|
||||
const before = await this.metaService.fetch(true);
|
||||
|
||||
await this.metaService.update(set);
|
||||
|
@@ -11,6 +11,23 @@ export const meta = {
|
||||
requireCredential: false,
|
||||
|
||||
tags: ['meta'],
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
params: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
type: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -18,6 +18,92 @@ export const meta = {
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 60,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
properties: {
|
||||
topSubInstances: {
|
||||
type: 'array',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
items: {
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
firstRetrievedAt: { type: 'string' },
|
||||
host: { type: 'string' },
|
||||
usersCount: { type: 'number' },
|
||||
notesCount: { type: 'number' },
|
||||
followingCount: { type: 'number' },
|
||||
followersCount: { type: 'number' },
|
||||
isNotResponding: { type: 'boolean' },
|
||||
isSuspended: { type: 'boolean' },
|
||||
isBlocked: { type: 'boolean' },
|
||||
softwareName: { type: 'string' },
|
||||
softwareVersion: { type: 'string' },
|
||||
openRegistrations: { type: 'boolean' },
|
||||
name: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
maintainerName: { type: 'string' },
|
||||
maintainerEmail: { type: 'string' },
|
||||
isSilenced: { type: 'boolean' },
|
||||
iconUrl: { type: 'string' },
|
||||
faviconUrl: { type: 'string' },
|
||||
themeColor: { type: 'string' },
|
||||
infoUpdatedAt: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
latestRequestReceivedAt: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
otherFollowersCount: { type: 'number' },
|
||||
topPubInstances: {
|
||||
type: 'array',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
items: {
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
firstRetrievedAt: { type: 'string' },
|
||||
host: { type: 'string' },
|
||||
usersCount: { type: 'number' },
|
||||
notesCount: { type: 'number' },
|
||||
followingCount: { type: 'number' },
|
||||
followersCount: { type: 'number' },
|
||||
isNotResponding: { type: 'boolean' },
|
||||
isSuspended: { type: 'boolean' },
|
||||
isBlocked: { type: 'boolean' },
|
||||
softwareName: { type: 'string' },
|
||||
softwareVersion: { type: 'string' },
|
||||
openRegistrations: { type: 'boolean' },
|
||||
name: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
maintainerName: { type: 'string' },
|
||||
maintainerEmail: { type: 'string' },
|
||||
isSilenced: { type: 'boolean' },
|
||||
iconUrl: { type: 'string' },
|
||||
faviconUrl: { type: 'string' },
|
||||
themeColor: { type: 'string' },
|
||||
infoUpdatedAt: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
latestRequestReceivedAt: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
otherFollowingCount: { type: 'number' },
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -32,6 +32,18 @@ export const meta = {
|
||||
id: '693ba8ba-b486-40df-a174-72f8279b56a4',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
},
|
||||
data: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -16,6 +16,18 @@ export const meta = {
|
||||
requireCredential: false,
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 3,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -28,6 +28,12 @@ export const meta = {
|
||||
|
||||
errors: {
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
ref: 'Flash',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -16,6 +16,16 @@ export const meta = {
|
||||
requireCredential: false,
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 1,
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
count: {
|
||||
type: 'number',
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -38,6 +38,16 @@ export const meta = {
|
||||
id: '798d6847-b1ed-4f9c-b1f9-163c42655995',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
optional: false,
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -42,6 +42,140 @@ export const meta = {
|
||||
id: 'bf32b864-449b-47b8-974e-f9a5468546f1',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
optional: false,
|
||||
properties: {
|
||||
rp: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
displayName: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
challenge: {
|
||||
type: 'string',
|
||||
},
|
||||
pubKeyCredParams: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
},
|
||||
alg: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
timeout: {
|
||||
type: 'number',
|
||||
nullable: true,
|
||||
},
|
||||
excludeCredentials: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
},
|
||||
transports: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
"ble",
|
||||
"cable",
|
||||
"hybrid",
|
||||
"internal",
|
||||
"nfc",
|
||||
"smart-card",
|
||||
"usb",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
authenticatorSelection: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
authenticatorAttachment: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
"cross-platform",
|
||||
"platform",
|
||||
],
|
||||
},
|
||||
requireResidentKey: {
|
||||
type: 'boolean',
|
||||
},
|
||||
userVerification: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
"discouraged",
|
||||
"preferred",
|
||||
"required",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
attestation: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
enum: [
|
||||
"direct",
|
||||
"enterprise",
|
||||
"indirect",
|
||||
"none",
|
||||
],
|
||||
},
|
||||
extensions: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
appid: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
credProps: {
|
||||
type: 'boolean',
|
||||
nullable: true,
|
||||
},
|
||||
hmacCreateSecret: {
|
||||
type: 'boolean',
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -32,6 +32,19 @@ export const meta = {
|
||||
id: 'e428f177-c6ae-4e91-9c7e-334b1836f9aa',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
optional: false,
|
||||
properties: {
|
||||
qr: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
secret: { type: 'string' },
|
||||
label: { type: 'string' },
|
||||
issuer: { type: 'string' },
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -13,6 +13,37 @@ export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
secure: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
lastUsedAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
permission: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -50,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
id: token.id,
|
||||
name: token.name ?? token.app?.name,
|
||||
createdAt: this.idService.parse(token.id).date.toISOString(),
|
||||
lastUsedAt: token.lastUsedAt,
|
||||
lastUsedAt: token.lastUsedAt?.toISOString(),
|
||||
permission: token.permission,
|
||||
})));
|
||||
});
|
||||
|
@@ -14,6 +14,36 @@ export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
secure: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
callbackUrl: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
permission: {
|
||||
type: 'array',
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
},
|
||||
isAuthorized: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -67,6 +67,10 @@ export const meta = {
|
||||
id: 'b234a14e-9ebe-4581-8000-074b3c215962',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -9,6 +9,10 @@ import { RegistryApiService } from '@/core/RegistryApiService.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -18,6 +18,10 @@ export const meta = {
|
||||
id: '97a1e8e7-c0f7-47d2-957a-92e61256e01a',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -18,6 +18,10 @@ export const meta = {
|
||||
id: 'ac3ed68a-62f0-422b-a7bc-d5e09e8f6a6a',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -9,6 +9,10 @@ import { RegistryApiService } from '@/core/RegistryApiService.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -10,6 +10,28 @@ import { RegistryApiService } from '@/core/RegistryApiService.js';
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
secure: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
scopes: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
}
|
||||
}
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -47,6 +47,11 @@ export const meta = {
|
||||
id: 'a2defefb-f220-8849-0af6-17f816099323',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
ref: 'UserDetailed',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -28,6 +28,33 @@ export const meta = {
|
||||
id: '87a9bb19-111e-4e37-81d3-a3e7426453b0',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id'
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
name: { type: 'string' },
|
||||
on: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: webhookEventTypes,
|
||||
}
|
||||
},
|
||||
url: { type: 'string' },
|
||||
secret: { type: 'string' },
|
||||
active: { type: 'boolean' },
|
||||
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
|
||||
latestStatus: { type: 'integer', nullable: true },
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -74,7 +101,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
|
||||
this.globalEventService.publishInternalEvent('webhookCreated', webhook);
|
||||
|
||||
return webhook;
|
||||
return {
|
||||
id: webhook.id,
|
||||
userId: webhook.userId,
|
||||
name: webhook.name,
|
||||
on: webhook.on,
|
||||
url: webhook.url,
|
||||
secret: webhook.secret,
|
||||
active: webhook.active,
|
||||
latestSentAt: webhook.latestSentAt?.toISOString(),
|
||||
latestStatus: webhook.latestStatus,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { webhookEventTypes } from '@/models/Webhook.js';
|
||||
import type { WebhooksRepository } from '@/models/_.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
@@ -14,6 +15,36 @@ export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
kind: 'read:account',
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id'
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
name: { type: 'string' },
|
||||
on: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: webhookEventTypes,
|
||||
}
|
||||
},
|
||||
url: { type: 'string' },
|
||||
secret: { type: 'string' },
|
||||
active: { type: 'boolean' },
|
||||
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
|
||||
latestStatus: { type: 'integer', nullable: true },
|
||||
},
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -33,7 +64,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
userId: me.id,
|
||||
});
|
||||
|
||||
return webhooks;
|
||||
return webhooks.map(webhook => (
|
||||
{
|
||||
id: webhook.id,
|
||||
userId: webhook.userId,
|
||||
name: webhook.name,
|
||||
on: webhook.on,
|
||||
url: webhook.url,
|
||||
secret: webhook.secret,
|
||||
active: webhook.active,
|
||||
latestSentAt: webhook.latestSentAt?.toISOString(),
|
||||
latestStatus: webhook.latestStatus,
|
||||
}
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { webhookEventTypes } from '@/models/Webhook.js';
|
||||
import type { WebhooksRepository } from '@/models/_.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
@@ -23,6 +24,33 @@ export const meta = {
|
||||
id: '50f614d9-3047-4f7e-90d8-ad6b2d5fb098',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id'
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
name: { type: 'string' },
|
||||
on: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: webhookEventTypes,
|
||||
}
|
||||
},
|
||||
url: { type: 'string' },
|
||||
secret: { type: 'string' },
|
||||
active: { type: 'boolean' },
|
||||
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
|
||||
latestStatus: { type: 'integer', nullable: true },
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
@@ -49,7 +77,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
throw new ApiError(meta.errors.noSuchWebhook);
|
||||
}
|
||||
|
||||
return webhook;
|
||||
return {
|
||||
id: webhook.id,
|
||||
userId: webhook.userId,
|
||||
name: webhook.name,
|
||||
on: webhook.on,
|
||||
url: webhook.url,
|
||||
secret: webhook.secret,
|
||||
active: webhook.active,
|
||||
latestSentAt: webhook.latestSentAt?.toISOString(),
|
||||
latestStatus: webhook.latestStatus,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,25 @@ export const meta = {
|
||||
id: '30aaaee3-4792-48dc-ab0d-cf501a575ac5',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id'
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'User'
|
||||
},
|
||||
},
|
||||
required: ['id', 'user'],
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -15,6 +15,53 @@ export const meta = {
|
||||
cacheSec: 60 * 1,
|
||||
|
||||
tags: ['meta'],
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
machine: {
|
||||
type: 'string',
|
||||
nullable: false,
|
||||
},
|
||||
cpu: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
properties: {
|
||||
model: {
|
||||
type: 'string',
|
||||
nullable: false,
|
||||
},
|
||||
cores: {
|
||||
type: 'number',
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
mem: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
total: {
|
||||
type: 'number',
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
fs: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
properties: {
|
||||
total: {
|
||||
type: 'number',
|
||||
nullable: false,
|
||||
},
|
||||
used: {
|
||||
type: 'number',
|
||||
nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -12,6 +12,30 @@ export const meta = {
|
||||
description: 'Endpoint for testing input validation.',
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id'
|
||||
},
|
||||
required: {
|
||||
type: 'boolean',
|
||||
},
|
||||
string: {
|
||||
type: 'string',
|
||||
},
|
||||
default: {
|
||||
type: 'string',
|
||||
},
|
||||
nullableDefault: {
|
||||
type: 'string',
|
||||
default: 'hello',
|
||||
nullable: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -10,6 +10,21 @@ import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
unlockedAt: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -25,6 +25,35 @@ export const meta = {
|
||||
id: '7bc05c21-1d7a-41ae-88f1-66820f4dc686',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
format: 'misskey:id',
|
||||
},
|
||||
user: {
|
||||
type: 'object',
|
||||
ref: 'User',
|
||||
},
|
||||
withReplies: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
@@ -10,9 +10,8 @@ process.env.NODE_ENV = 'test';
|
||||
process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING = 'true';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, post, react, startServer, waitFire, sleep, uploadUrl, randomString } from '../utils.js';
|
||||
import { api, post, randomString, signup, sleep, startServer, uploadUrl } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
import type * as misskey from 'misskey-js';
|
||||
|
||||
function genHost() {
|
||||
return randomString() + '.example.com';
|
||||
@@ -366,8 +365,8 @@ describe('Timelines', () => {
|
||||
await api('/following/create', { userId: bob.id }, alice);
|
||||
await sleep(1000);
|
||||
const [bobFile, carolFile] = await Promise.all([
|
||||
uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'),
|
||||
uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'),
|
||||
uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'),
|
||||
uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'),
|
||||
]);
|
||||
const bobNote1 = await post(bob, { text: 'hi' });
|
||||
const bobNote2 = await post(bob, { fileIds: [bobFile.id] });
|
||||
@@ -666,7 +665,7 @@ describe('Timelines', () => {
|
||||
test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => {
|
||||
const [alice, bob] = await Promise.all([signup(), signup()]);
|
||||
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png');
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png');
|
||||
const bobNote1 = await post(bob, { text: 'hi' });
|
||||
const bobNote2 = await post(bob, { fileIds: [file.id] });
|
||||
|
||||
@@ -804,7 +803,7 @@ describe('Timelines', () => {
|
||||
test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => {
|
||||
const [alice, bob] = await Promise.all([signup(), signup()]);
|
||||
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png');
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png');
|
||||
const bobNote1 = await post(bob, { text: 'hi' });
|
||||
const bobNote2 = await post(bob, { fileIds: [file.id] });
|
||||
|
||||
@@ -1000,7 +999,7 @@ describe('Timelines', () => {
|
||||
|
||||
const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
|
||||
await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png');
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png');
|
||||
const bobNote1 = await post(bob, { text: 'hi' });
|
||||
const bobNote2 = await post(bob, { fileIds: [file.id] });
|
||||
|
||||
@@ -1159,7 +1158,7 @@ describe('Timelines', () => {
|
||||
test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => {
|
||||
const [alice, bob] = await Promise.all([signup(), signup()]);
|
||||
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png');
|
||||
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png');
|
||||
const bobNote1 = await post(bob, { text: 'hi' });
|
||||
const bobNote2 = await post(bob, { fileIds: [file.id] });
|
||||
|
||||
|
@@ -73,13 +73,21 @@ describe('RoleService', () => {
|
||||
CacheService,
|
||||
IdService,
|
||||
GlobalEventService,
|
||||
{
|
||||
provide: NotificationService,
|
||||
useFactory: () => ({
|
||||
createNotification: jest.fn(),
|
||||
}),
|
||||
},
|
||||
{
|
||||
provide: NotificationService.name,
|
||||
useExisting: NotificationService,
|
||||
},
|
||||
],
|
||||
})
|
||||
.useMocker((token) => {
|
||||
if (token === MetaService) {
|
||||
return { fetch: jest.fn() };
|
||||
} else if (token === NotificationService) {
|
||||
return { createNotification: jest.fn() };
|
||||
}
|
||||
if (typeof token === 'function') {
|
||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
||||
@@ -98,6 +106,8 @@ describe('RoleService', () => {
|
||||
|
||||
metaService = app.get<MetaService>(MetaService) as jest.Mocked<MetaService>;
|
||||
notificationService = app.get<NotificationService>(NotificationService) as jest.Mocked<NotificationService>;
|
||||
|
||||
await roleService.onModuleInit();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -284,10 +294,12 @@ describe('RoleService', () => {
|
||||
const user = await createUser();
|
||||
const role = await createRole({
|
||||
isPublic: true,
|
||||
name: 'a',
|
||||
});
|
||||
|
||||
await roleService.assign(user.id, role.id);
|
||||
|
||||
clock.uninstall();
|
||||
await sleep(100);
|
||||
|
||||
const assignments = await roleAssignmentsRepository.find({
|
||||
@@ -301,7 +313,7 @@ describe('RoleService', () => {
|
||||
expect(notificationService.createNotification).toHaveBeenCalled();
|
||||
expect(notificationService.createNotification.mock.lastCall![0]).toBe(user.id);
|
||||
expect(notificationService.createNotification.mock.lastCall![1]).toBe('roleAssigned');
|
||||
expect(notificationService.createNotification.mock.lastCall![2]).toBe({
|
||||
expect(notificationService.createNotification.mock.lastCall![2]).toEqual({
|
||||
roleId: role.id,
|
||||
});
|
||||
});
|
||||
@@ -310,10 +322,12 @@ describe('RoleService', () => {
|
||||
const user = await createUser();
|
||||
const role = await createRole({
|
||||
isPublic: false,
|
||||
name: 'a',
|
||||
});
|
||||
|
||||
await roleService.assign(user.id, role.id);
|
||||
|
||||
clock.uninstall();
|
||||
await sleep(100);
|
||||
|
||||
const assignments = await roleAssignmentsRepository.find({
|
||||
|
Reference in New Issue
Block a user