mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 06:00:21 +01:00
Merge branch 'stream-types' into swn
This commit is contained in:
commit
1e7a4eebfe
44 changed files with 695 additions and 186 deletions
|
@ -209,6 +209,7 @@
|
||||||
"seedrandom": "3.0.5",
|
"seedrandom": "3.0.5",
|
||||||
"sharp": "0.29.1",
|
"sharp": "0.29.1",
|
||||||
"speakeasy": "2.0.0",
|
"speakeasy": "2.0.0",
|
||||||
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"style-loader": "3.2.1",
|
"style-loader": "3.2.1",
|
||||||
"summaly": "2.4.1",
|
"summaly": "2.4.1",
|
||||||
|
|
|
@ -3,13 +3,13 @@ import { Note } from '@/models/entities/note';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { UserListJoinings, UserGroupJoinings } from '@/models/index';
|
import { UserListJoinings, UserGroupJoinings } from '@/models/index';
|
||||||
import { getFullApAccount } from './convert-host';
|
import { getFullApAccount } from './convert-host';
|
||||||
import { PackedNote } from '../models/repositories/note';
|
|
||||||
import { parseAcct } from '@/misc/acct';
|
import { parseAcct } from '@/misc/acct';
|
||||||
|
import { Packed } from './schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい
|
* noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい
|
||||||
*/
|
*/
|
||||||
export async function checkHitAntenna(antenna: Antenna, note: (Note | PackedNote), noteUser: { username: string; host: string | null; }, noteUserFollowers?: User['id'][], antennaUserFollowing?: User['id'][]): Promise<boolean> {
|
export async function checkHitAntenna(antenna: Antenna, note: (Note | Packed<'Note'>), noteUser: { username: string; host: string | null; }, noteUserFollowers?: User['id'][], antennaUserFollowing?: User['id'][]): Promise<boolean> {
|
||||||
if (note.visibility === 'specified') return false;
|
if (note.visibility === 'specified') return false;
|
||||||
|
|
||||||
if (note.visibility === 'followers') {
|
if (note.visibility === 'followers') {
|
||||||
|
|
|
@ -21,6 +21,9 @@ import { packedClipSchema } from '@/models/repositories/clip';
|
||||||
import { packedFederationInstanceSchema } from '@/models/repositories/federation-instance';
|
import { packedFederationInstanceSchema } from '@/models/repositories/federation-instance';
|
||||||
import { packedQueueCountSchema } from '@/models/repositories/queue';
|
import { packedQueueCountSchema } from '@/models/repositories/queue';
|
||||||
import { packedGalleryPostSchema } from '@/models/repositories/gallery-post';
|
import { packedGalleryPostSchema } from '@/models/repositories/gallery-post';
|
||||||
|
import { packedEmojiSchema } from '@/models/repositories/emoji';
|
||||||
|
import { packedReversiGameSchema } from '@/models/repositories/games/reversi/game';
|
||||||
|
import { packedReversiMatchingSchema } from '@/models/repositories/games/reversi/matching';
|
||||||
|
|
||||||
export const refs = {
|
export const refs = {
|
||||||
User: packedUserSchema,
|
User: packedUserSchema,
|
||||||
|
@ -45,8 +48,13 @@ export const refs = {
|
||||||
Clip: packedClipSchema,
|
Clip: packedClipSchema,
|
||||||
FederationInstance: packedFederationInstanceSchema,
|
FederationInstance: packedFederationInstanceSchema,
|
||||||
GalleryPost: packedGalleryPostSchema,
|
GalleryPost: packedGalleryPostSchema,
|
||||||
|
Emoji: packedEmojiSchema,
|
||||||
|
ReversiGame: packedReversiGameSchema,
|
||||||
|
ReversiMatching: packedReversiMatchingSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Packed<x extends keyof typeof refs> = ObjType<(typeof refs[x])['properties']>;
|
||||||
|
|
||||||
export interface Schema extends SimpleSchema {
|
export interface Schema extends SimpleSchema {
|
||||||
items?: Schema;
|
items?: Schema;
|
||||||
properties?: Obj;
|
properties?: Obj;
|
||||||
|
@ -92,7 +100,7 @@ export type SchemaType<p extends Schema> =
|
||||||
p['type'] extends 'array' ? NullOrUndefined<p, MyType<NonNullable<p['items']>>[]> :
|
p['type'] extends 'array' ? NullOrUndefined<p, MyType<NonNullable<p['items']>>[]> :
|
||||||
p['type'] extends 'object' ? (
|
p['type'] extends 'object' ? (
|
||||||
p['ref'] extends keyof typeof refs
|
p['ref'] extends keyof typeof refs
|
||||||
? NullOrUndefined<p, SchemaType<typeof refs[p['ref']]>>
|
? NullOrUndefined<p, Packed<p['ref']>>
|
||||||
: NullOrUndefined<p, ObjType<NonNullable<p['properties']>>>
|
: NullOrUndefined<p, ObjType<NonNullable<p['properties']>>>
|
||||||
) :
|
) :
|
||||||
p['type'] extends 'any' ? NullOrUndefined<p, any> :
|
p['type'] extends 'any' ? NullOrUndefined<p, any> :
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Antenna } from '@/models/entities/antenna';
|
import { Antenna } from '@/models/entities/antenna';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { AntennaNotes, UserGroupJoinings } from '../index';
|
import { AntennaNotes, UserGroupJoinings } from '../index';
|
||||||
|
|
||||||
export type PackedAntenna = SchemaType<typeof packedAntennaSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Antenna)
|
@EntityRepository(Antenna)
|
||||||
export class AntennaRepository extends Repository<Antenna> {
|
export class AntennaRepository extends Repository<Antenna> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Antenna['id'] | Antenna,
|
src: Antenna['id'] | Antenna,
|
||||||
): Promise<PackedAntenna> {
|
): Promise<Packed<'Antenna'>> {
|
||||||
const antenna = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const antenna = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null;
|
const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { App } from '@/models/entities/app';
|
import { App } from '@/models/entities/app';
|
||||||
import { AccessTokens } from '../index';
|
import { AccessTokens } from '../index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
|
import { User } from '../entities/user';
|
||||||
export type PackedApp = SchemaType<typeof packedAppSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(App)
|
@EntityRepository(App)
|
||||||
export class AppRepository extends Repository<App> {
|
export class AppRepository extends Repository<App> {
|
||||||
|
@ -15,7 +14,7 @@ export class AppRepository extends Repository<App> {
|
||||||
includeSecret?: boolean,
|
includeSecret?: boolean,
|
||||||
includeProfileImageIds?: boolean
|
includeProfileImageIds?: boolean
|
||||||
}
|
}
|
||||||
): Promise<PackedApp> {
|
): Promise<Packed<'App'>> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: false,
|
detail: false,
|
||||||
includeSecret: false,
|
includeSecret: false,
|
||||||
|
@ -52,13 +51,9 @@ export const packedAppSchema = {
|
||||||
type: 'string' as const,
|
type: 'string' as const,
|
||||||
optional: false as const, nullable: false as const
|
optional: false as const, nullable: false as const
|
||||||
},
|
},
|
||||||
createdAt: {
|
callbackUrl: {
|
||||||
type: 'string' as const,
|
type: 'string' as const,
|
||||||
optional: false as const, nullable: false as const
|
optional: false as const, nullable: true as const
|
||||||
},
|
|
||||||
lastUsedAt: {
|
|
||||||
type: 'string' as const,
|
|
||||||
optional: false as const, nullable: false as const
|
|
||||||
},
|
},
|
||||||
permission: {
|
permission: {
|
||||||
type: 'array' as const,
|
type: 'array' as const,
|
||||||
|
|
|
@ -2,17 +2,15 @@ import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Users } from '../index';
|
import { Users } from '../index';
|
||||||
import { Blocking } from '@/models/entities/blocking';
|
import { Blocking } from '@/models/entities/blocking';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedBlocking = SchemaType<typeof packedBlockingSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Blocking)
|
@EntityRepository(Blocking)
|
||||||
export class BlockingRepository extends Repository<Blocking> {
|
export class BlockingRepository extends Repository<Blocking> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Blocking['id'] | Blocking,
|
src: Blocking['id'] | Blocking,
|
||||||
me?: { id: User['id'] } | null | undefined
|
me?: { id: User['id'] } | null | undefined
|
||||||
): Promise<PackedBlocking> {
|
): Promise<Packed<'Blocking'>> {
|
||||||
const blocking = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const blocking = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
return await awaitAll({
|
return await awaitAll({
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Channel } from '@/models/entities/channel';
|
import { Channel } from '@/models/entities/channel';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index';
|
import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedChannel = SchemaType<typeof packedChannelSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Channel)
|
@EntityRepository(Channel)
|
||||||
export class ChannelRepository extends Repository<Channel> {
|
export class ChannelRepository extends Repository<Channel> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Channel['id'] | Channel,
|
src: Channel['id'] | Channel,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
): Promise<PackedChannel> {
|
): Promise<Packed<'Channel'>> {
|
||||||
const channel = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const channel = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
const meId = me ? me.id : null;
|
const meId = me ? me.id : null;
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Clip } from '@/models/entities/clip';
|
import { Clip } from '@/models/entities/clip';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { Users } from '../index';
|
import { Users } from '../index';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
|
|
||||||
export type PackedClip = SchemaType<typeof packedClipSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Clip)
|
@EntityRepository(Clip)
|
||||||
export class ClipRepository extends Repository<Clip> {
|
export class ClipRepository extends Repository<Clip> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Clip['id'] | Clip,
|
src: Clip['id'] | Clip,
|
||||||
): Promise<PackedClip> {
|
): Promise<Packed<'Clip'>> {
|
||||||
const clip = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const clip = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
return await awaitAll({
|
return await awaitAll({
|
||||||
|
|
|
@ -4,14 +4,12 @@ import { Users, DriveFolders } from '../index';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { toPuny } from '@/misc/convert-host';
|
import { toPuny } from '@/misc/convert-host';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import config from '@/config/index';
|
import config from '@/config/index';
|
||||||
import { query, appendQuery } from '@/prelude/url';
|
import { query, appendQuery } from '@/prelude/url';
|
||||||
import { Meta } from '@/models/entities/meta';
|
import { Meta } from '@/models/entities/meta';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
|
|
||||||
export type PackedDriveFile = SchemaType<typeof packedDriveFileSchema>;
|
|
||||||
|
|
||||||
type PackOptions = {
|
type PackOptions = {
|
||||||
detail?: boolean,
|
detail?: boolean,
|
||||||
self?: boolean,
|
self?: boolean,
|
||||||
|
@ -99,12 +97,12 @@ export class DriveFileRepository extends Repository<DriveFile> {
|
||||||
return parseInt(sum, 10) || 0;
|
return parseInt(sum, 10) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async pack(src: DriveFile['id'], options?: PackOptions): Promise<PackedDriveFile | null>;
|
public async pack(src: DriveFile['id'], options?: PackOptions): Promise<Packed<'DriveFile'> | null>;
|
||||||
public async pack(src: DriveFile, options?: PackOptions): Promise<PackedDriveFile>;
|
public async pack(src: DriveFile, options?: PackOptions): Promise<Packed<'DriveFile'>>;
|
||||||
public async pack(
|
public async pack(
|
||||||
src: DriveFile['id'] | DriveFile,
|
src: DriveFile['id'] | DriveFile,
|
||||||
options?: PackOptions
|
options?: PackOptions
|
||||||
): Promise<PackedDriveFile | null> {
|
): Promise<Packed<'DriveFile'> | null> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: false,
|
detail: false,
|
||||||
self: false
|
self: false
|
||||||
|
|
|
@ -2,9 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { DriveFolders, DriveFiles } from '../index';
|
import { DriveFolders, DriveFiles } from '../index';
|
||||||
import { DriveFolder } from '@/models/entities/drive-folder';
|
import { DriveFolder } from '@/models/entities/drive-folder';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export type PackedDriveFolder = SchemaType<typeof packedDriveFolderSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(DriveFolder)
|
@EntityRepository(DriveFolder)
|
||||||
export class DriveFolderRepository extends Repository<DriveFolder> {
|
export class DriveFolderRepository extends Repository<DriveFolder> {
|
||||||
|
@ -20,7 +18,7 @@ export class DriveFolderRepository extends Repository<DriveFolder> {
|
||||||
options?: {
|
options?: {
|
||||||
detail: boolean
|
detail: boolean
|
||||||
}
|
}
|
||||||
): Promise<PackedDriveFolder> {
|
): Promise<Packed<'DriveFolder'>> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: false
|
detail: false
|
||||||
}, options);
|
}, options);
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Emoji } from '@/models/entities/emoji';
|
import { Emoji } from '@/models/entities/emoji';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
@EntityRepository(Emoji)
|
@EntityRepository(Emoji)
|
||||||
export class EmojiRepository extends Repository<Emoji> {
|
export class EmojiRepository extends Repository<Emoji> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Emoji['id'] | Emoji,
|
src: Emoji['id'] | Emoji,
|
||||||
) {
|
): Promise<Packed<'Emoji'>> {
|
||||||
const emoji = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const emoji = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -24,3 +25,41 @@ export class EmojiRepository extends Repository<Emoji> {
|
||||||
return Promise.all(emojis.map(x => this.pack(x)));
|
return Promise.all(emojis.map(x => this.pack(x)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const packedEmojiSchema = {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
aliases: {
|
||||||
|
type: 'array' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
items: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Users } from '../index';
|
import { Users } from '../index';
|
||||||
import { Following } from '@/models/entities/following';
|
import { Following } from '@/models/entities/following';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
type LocalFollowerFollowing = Following & {
|
type LocalFollowerFollowing = Following & {
|
||||||
|
@ -29,8 +29,6 @@ type RemoteFolloweeFollowing = Following & {
|
||||||
followeeSharedInbox: string;
|
followeeSharedInbox: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PackedFollowing = SchemaType<typeof packedFollowingSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Following)
|
@EntityRepository(Following)
|
||||||
export class FollowingRepository extends Repository<Following> {
|
export class FollowingRepository extends Repository<Following> {
|
||||||
public isLocalFollower(following: Following): following is LocalFollowerFollowing {
|
public isLocalFollower(following: Following): following is LocalFollowerFollowing {
|
||||||
|
@ -56,7 +54,7 @@ export class FollowingRepository extends Repository<Following> {
|
||||||
populateFollowee?: boolean;
|
populateFollowee?: boolean;
|
||||||
populateFollower?: boolean;
|
populateFollower?: boolean;
|
||||||
}
|
}
|
||||||
): Promise<PackedFollowing> {
|
): Promise<Packed<'Following'>> {
|
||||||
const following = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const following = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
if (opts == null) opts = {};
|
if (opts == null) opts = {};
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { GalleryPost } from '@/models/entities/gallery-post';
|
import { GalleryPost } from '@/models/entities/gallery-post';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { Users, DriveFiles, GalleryLikes } from '../index';
|
import { Users, DriveFiles, GalleryLikes } from '../index';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedGalleryPost = SchemaType<typeof packedGalleryPostSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(GalleryPost)
|
@EntityRepository(GalleryPost)
|
||||||
export class GalleryPostRepository extends Repository<GalleryPost> {
|
export class GalleryPostRepository extends Repository<GalleryPost> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: GalleryPost['id'] | GalleryPost,
|
src: GalleryPost['id'] | GalleryPost,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
): Promise<PackedGalleryPost> {
|
): Promise<Packed<'GalleryPost'>> {
|
||||||
const meId = me ? me.id : null;
|
const meId = me ? me.id : null;
|
||||||
const post = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const post = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { User } from '@/models/entities/user';
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Users } from '../../../index';
|
import { Users } from '../../../index';
|
||||||
import { ReversiGame } from '@/models/entities/games/reversi/game';
|
import { ReversiGame } from '@/models/entities/games/reversi/game';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
@EntityRepository(ReversiGame)
|
@EntityRepository(ReversiGame)
|
||||||
export class ReversiGameRepository extends Repository<ReversiGame> {
|
export class ReversiGameRepository extends Repository<ReversiGame> {
|
||||||
|
@ -11,7 +12,7 @@ export class ReversiGameRepository extends Repository<ReversiGame> {
|
||||||
options?: {
|
options?: {
|
||||||
detail?: boolean
|
detail?: boolean
|
||||||
}
|
}
|
||||||
) {
|
): Promise<Packed<'ReversiGame'>> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: true
|
detail: true
|
||||||
}, options);
|
}, options);
|
||||||
|
@ -20,8 +21,8 @@ export class ReversiGameRepository extends Repository<ReversiGame> {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: game.id,
|
id: game.id,
|
||||||
createdAt: game.createdAt,
|
createdAt: game.createdAt.toISOString(),
|
||||||
startedAt: game.startedAt,
|
startedAt: game.startedAt && game.startedAt.toISOString(),
|
||||||
isStarted: game.isStarted,
|
isStarted: game.isStarted,
|
||||||
isEnded: game.isEnded,
|
isEnded: game.isEnded,
|
||||||
form1: game.form1,
|
form1: game.form1,
|
||||||
|
@ -41,9 +42,150 @@ export class ReversiGameRepository extends Repository<ReversiGame> {
|
||||||
canPutEverywhere: game.canPutEverywhere,
|
canPutEverywhere: game.canPutEverywhere,
|
||||||
loopedBoard: game.loopedBoard,
|
loopedBoard: game.loopedBoard,
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
logs: game.logs,
|
logs: game.logs.map(log => ({
|
||||||
|
at: log.at.toISOString(),
|
||||||
|
color: log.color,
|
||||||
|
pos: log.pos
|
||||||
|
})),
|
||||||
map: game.map,
|
map: game.map,
|
||||||
} : {})
|
} : {})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const packedReversiGameSchema = {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'date-time',
|
||||||
|
},
|
||||||
|
startedAt: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
format: 'date-time',
|
||||||
|
},
|
||||||
|
isStarted: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
isEnded: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
form1: {
|
||||||
|
type: 'any' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
form2: {
|
||||||
|
type: 'any' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
user1Accepted: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
user2Accepted: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
user1Id: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
user2Id: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
user1: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
ref: 'User' as const,
|
||||||
|
},
|
||||||
|
user2: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
ref: 'User' as const,
|
||||||
|
},
|
||||||
|
winnerId: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
winner: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
ref: 'User' as const,
|
||||||
|
},
|
||||||
|
surrendered: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
black: {
|
||||||
|
type: 'number' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
},
|
||||||
|
bw: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
isLlotheo: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
canPutEverywhere: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
loopedBoard: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
logs: {
|
||||||
|
type: 'array' as const,
|
||||||
|
optional: true as const, nullable: false as const,
|
||||||
|
items: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: true as const, nullable: false as const,
|
||||||
|
properties: {
|
||||||
|
at: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'date-time',
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: 'boolean' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
pos: {
|
||||||
|
type: 'number' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
type: 'array' as const,
|
||||||
|
optional: true as const, nullable: false as const,
|
||||||
|
items: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -3,18 +3,19 @@ import { ReversiMatching } from '@/models/entities/games/reversi/matching';
|
||||||
import { Users } from '../../../index';
|
import { Users } from '../../../index';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
@EntityRepository(ReversiMatching)
|
@EntityRepository(ReversiMatching)
|
||||||
export class ReversiMatchingRepository extends Repository<ReversiMatching> {
|
export class ReversiMatchingRepository extends Repository<ReversiMatching> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: ReversiMatching['id'] | ReversiMatching,
|
src: ReversiMatching['id'] | ReversiMatching,
|
||||||
me: { id: User['id'] }
|
me: { id: User['id'] }
|
||||||
) {
|
): Promise<Packed<'ReversiMatching'>> {
|
||||||
const matching = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const matching = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
return await awaitAll({
|
return await awaitAll({
|
||||||
id: matching.id,
|
id: matching.id,
|
||||||
createdAt: matching.createdAt,
|
createdAt: matching.createdAt.toISOString(),
|
||||||
parentId: matching.parentId,
|
parentId: matching.parentId,
|
||||||
parent: Users.pack(matching.parentId, me, {
|
parent: Users.pack(matching.parentId, me, {
|
||||||
detail: true
|
detail: true
|
||||||
|
@ -26,3 +27,43 @@ export class ReversiMatchingRepository extends Repository<ReversiMatching> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const packedReversiMatchingSchema = {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'date-time',
|
||||||
|
},
|
||||||
|
parentId: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
parent: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: true as const,
|
||||||
|
ref: 'User' as const,
|
||||||
|
},
|
||||||
|
childId: {
|
||||||
|
type: 'string' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
child: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
ref: 'User' as const,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Hashtag } from '@/models/entities/hashtag';
|
import { Hashtag } from '@/models/entities/hashtag';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export type PackedHashtag = SchemaType<typeof packedHashtagSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Hashtag)
|
@EntityRepository(Hashtag)
|
||||||
export class HashtagRepository extends Repository<Hashtag> {
|
export class HashtagRepository extends Repository<Hashtag> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Hashtag,
|
src: Hashtag,
|
||||||
): Promise<PackedHashtag> {
|
): Promise<Packed<'Hashtag'>> {
|
||||||
return {
|
return {
|
||||||
tag: src.name,
|
tag: src.name,
|
||||||
mentionedUsersCount: src.mentionedUsersCount,
|
mentionedUsersCount: src.mentionedUsersCount,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { MessagingMessage } from '@/models/entities/messaging-message';
|
import { MessagingMessage } from '@/models/entities/messaging-message';
|
||||||
import { Users, DriveFiles, UserGroups } from '../index';
|
import { Users, DriveFiles, UserGroups } from '../index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedMessagingMessage = SchemaType<typeof packedMessagingMessageSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(MessagingMessage)
|
@EntityRepository(MessagingMessage)
|
||||||
export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
||||||
public validateText(text: string): boolean {
|
public validateText(text: string): boolean {
|
||||||
|
@ -19,7 +17,7 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> {
|
||||||
populateRecipient?: boolean,
|
populateRecipient?: boolean,
|
||||||
populateGroup?: boolean,
|
populateGroup?: boolean,
|
||||||
}
|
}
|
||||||
): Promise<PackedMessagingMessage> {
|
): Promise<Packed<'MessagingMessage'>> {
|
||||||
const opts = options || {
|
const opts = options || {
|
||||||
populateRecipient: true,
|
populateRecipient: true,
|
||||||
populateGroup: true,
|
populateGroup: true,
|
||||||
|
|
|
@ -2,17 +2,15 @@ import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Users } from '../index';
|
import { Users } from '../index';
|
||||||
import { Muting } from '@/models/entities/muting';
|
import { Muting } from '@/models/entities/muting';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedMuting = SchemaType<typeof packedMutingSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Muting)
|
@EntityRepository(Muting)
|
||||||
export class MutingRepository extends Repository<Muting> {
|
export class MutingRepository extends Repository<Muting> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Muting['id'] | Muting,
|
src: Muting['id'] | Muting,
|
||||||
me?: { id: User['id'] } | null | undefined
|
me?: { id: User['id'] } | null | undefined
|
||||||
): Promise<PackedMuting> {
|
): Promise<Packed<'Muting'>> {
|
||||||
const muting = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const muting = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
return await awaitAll({
|
return await awaitAll({
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { NoteReaction } from '@/models/entities/note-reaction';
|
import { NoteReaction } from '@/models/entities/note-reaction';
|
||||||
import { Users } from '../index';
|
import { Users } from '../index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { convertLegacyReaction } from '@/misc/reaction-lib';
|
import { convertLegacyReaction } from '@/misc/reaction-lib';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedNoteReaction = SchemaType<typeof packedNoteReactionSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(NoteReaction)
|
@EntityRepository(NoteReaction)
|
||||||
export class NoteReactionRepository extends Repository<NoteReaction> {
|
export class NoteReactionRepository extends Repository<NoteReaction> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: NoteReaction['id'] | NoteReaction,
|
src: NoteReaction['id'] | NoteReaction,
|
||||||
me?: { id: User['id'] } | null | undefined
|
me?: { id: User['id'] } | null | undefined
|
||||||
): Promise<PackedNoteReaction> {
|
): Promise<Packed<'NoteReaction'>> {
|
||||||
const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -3,15 +3,13 @@ import * as mfm from 'mfm-js';
|
||||||
import { Note } from '@/models/entities/note';
|
import { Note } from '@/models/entities/note';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '../index';
|
import { Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls, Channels } from '../index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { nyaize } from '@/misc/nyaize';
|
import { nyaize } from '@/misc/nyaize';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib';
|
import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib';
|
||||||
import { NoteReaction } from '@/models/entities/note-reaction';
|
import { NoteReaction } from '@/models/entities/note-reaction';
|
||||||
import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis';
|
import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis';
|
||||||
|
|
||||||
export type PackedNote = SchemaType<typeof packedNoteSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Note)
|
@EntityRepository(Note)
|
||||||
export class NoteRepository extends Repository<Note> {
|
export class NoteRepository extends Repository<Note> {
|
||||||
public validateCw(x: string) {
|
public validateCw(x: string) {
|
||||||
|
@ -67,7 +65,7 @@ export class NoteRepository extends Repository<Note> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async hideNote(packedNote: PackedNote, meId: User['id'] | null) {
|
private async hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) {
|
||||||
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
||||||
let hide = false;
|
let hide = false;
|
||||||
|
|
||||||
|
@ -137,7 +135,7 @@ export class NoteRepository extends Repository<Note> {
|
||||||
myReactions: Map<Note['id'], NoteReaction | null>;
|
myReactions: Map<Note['id'], NoteReaction | null>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
): Promise<PackedNote> {
|
): Promise<Packed<'Note'>> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: true,
|
detail: true,
|
||||||
skipHide: false
|
skipHide: false
|
||||||
|
|
|
@ -2,15 +2,13 @@ import { EntityRepository, In, Repository } from 'typeorm';
|
||||||
import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index';
|
import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index';
|
||||||
import { Notification } from '@/models/entities/notification';
|
import { Notification } from '@/models/entities/notification';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { Note } from '@/models/entities/note';
|
import { Note } from '@/models/entities/note';
|
||||||
import { NoteReaction } from '@/models/entities/note-reaction';
|
import { NoteReaction } from '@/models/entities/note-reaction';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis';
|
import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis';
|
||||||
import { notificationTypes } from '@/types';
|
import { notificationTypes } from '@/types';
|
||||||
|
|
||||||
export type PackedNotification = SchemaType<typeof packedNotificationSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Notification)
|
@EntityRepository(Notification)
|
||||||
export class NotificationRepository extends Repository<Notification> {
|
export class NotificationRepository extends Repository<Notification> {
|
||||||
public async pack(
|
public async pack(
|
||||||
|
@ -20,7 +18,7 @@ export class NotificationRepository extends Repository<Notification> {
|
||||||
myReactions: Map<Note['id'], NoteReaction | null>;
|
myReactions: Map<Note['id'], NoteReaction | null>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
): Promise<PackedNotification> {
|
): Promise<Packed<'Notification'>> {
|
||||||
const notification = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const notification = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null;
|
const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { Page } from '@/models/entities/page';
|
import { Page } from '@/models/entities/page';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { Users, DriveFiles, PageLikes } from '../index';
|
import { Users, DriveFiles, PageLikes } from '../index';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { DriveFile } from '@/models/entities/drive-file';
|
import { DriveFile } from '@/models/entities/drive-file';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
|
||||||
export type PackedPage = SchemaType<typeof packedPageSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(Page)
|
@EntityRepository(Page)
|
||||||
export class PageRepository extends Repository<Page> {
|
export class PageRepository extends Repository<Page> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Page['id'] | Page,
|
src: Page['id'] | Page,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
): Promise<PackedPage> {
|
): Promise<Packed<'Page'>> {
|
||||||
const meId = me ? me.id : null;
|
const meId = me ? me.id : null;
|
||||||
const page = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const page = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Signin } from '@/models/entities/signin';
|
||||||
@EntityRepository(Signin)
|
@EntityRepository(Signin)
|
||||||
export class SigninRepository extends Repository<Signin> {
|
export class SigninRepository extends Repository<Signin> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: any,
|
src: Signin,
|
||||||
) {
|
) {
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { UserGroup } from '@/models/entities/user-group';
|
import { UserGroup } from '@/models/entities/user-group';
|
||||||
import { UserGroupJoinings } from '../index';
|
import { UserGroupJoinings } from '../index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export type PackedUserGroup = SchemaType<typeof packedUserGroupSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(UserGroup)
|
@EntityRepository(UserGroup)
|
||||||
export class UserGroupRepository extends Repository<UserGroup> {
|
export class UserGroupRepository extends Repository<UserGroup> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: UserGroup['id'] | UserGroup,
|
src: UserGroup['id'] | UserGroup,
|
||||||
): Promise<PackedUserGroup> {
|
): Promise<Packed<'UserGroup'>> {
|
||||||
const userGroup = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const userGroup = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
const users = await UserGroupJoinings.find({
|
const users = await UserGroupJoinings.find({
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { UserList } from '@/models/entities/user-list';
|
import { UserList } from '@/models/entities/user-list';
|
||||||
import { UserListJoinings } from '../index';
|
import { UserListJoinings } from '../index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export type PackedUserList = SchemaType<typeof packedUserListSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(UserList)
|
@EntityRepository(UserList)
|
||||||
export class UserListRepository extends Repository<UserList> {
|
export class UserListRepository extends Repository<UserList> {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: UserList['id'] | UserList,
|
src: UserList['id'] | UserList,
|
||||||
): Promise<PackedUserList> {
|
): Promise<Packed<'UserList'>> {
|
||||||
const userList = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
const userList = typeof src === 'object' ? src : await this.findOneOrFail(src);
|
||||||
|
|
||||||
const users = await UserListJoinings.find({
|
const users = await UserListJoinings.find({
|
||||||
|
|
|
@ -3,14 +3,12 @@ import { EntityRepository, Repository, In, Not } from 'typeorm';
|
||||||
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
|
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 { 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';
|
import config from '@/config/index';
|
||||||
import { SchemaType } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
import { awaitAll } from '@/prelude/await-all';
|
import { awaitAll } from '@/prelude/await-all';
|
||||||
import { populateEmojis } from '@/misc/populate-emojis';
|
import { populateEmojis } from '@/misc/populate-emojis';
|
||||||
import { getAntennas } from '@/misc/antenna-cache';
|
import { getAntennas } from '@/misc/antenna-cache';
|
||||||
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const';
|
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const';
|
||||||
|
|
||||||
export type PackedUser = SchemaType<typeof packedUserSchema>;
|
|
||||||
|
|
||||||
@EntityRepository(User)
|
@EntityRepository(User)
|
||||||
export class UserRepository extends Repository<User> {
|
export class UserRepository extends Repository<User> {
|
||||||
public async getRelation(me: User['id'], target: User['id']) {
|
public async getRelation(me: User['id'], target: User['id']) {
|
||||||
|
@ -164,7 +162,7 @@ export class UserRepository extends Repository<User> {
|
||||||
detail?: boolean,
|
detail?: boolean,
|
||||||
includeSecrets?: boolean,
|
includeSecrets?: boolean,
|
||||||
}
|
}
|
||||||
): Promise<PackedUser> {
|
): Promise<Packed<'User'>> {
|
||||||
const opts = Object.assign({
|
const opts = Object.assign({
|
||||||
detail: false,
|
detail: false,
|
||||||
includeSecrets: false
|
includeSecrets: false
|
||||||
|
|
|
@ -93,7 +93,7 @@ export async function readGroupMessagingMessage(
|
||||||
id: In(messageIds)
|
id: In(messageIds)
|
||||||
});
|
});
|
||||||
|
|
||||||
const reads = [];
|
const reads: MessagingMessage['id'][] = [];
|
||||||
|
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
if (message.userId === userId) continue;
|
if (message.userId === userId) continue;
|
||||||
|
|
|
@ -137,7 +137,7 @@ export default define(meta, async (ps, user) => {
|
||||||
notify: ps.notify,
|
notify: ps.notify,
|
||||||
});
|
});
|
||||||
|
|
||||||
publishInternalEvent('antennaUpdated', Antennas.findOneOrFail(antenna.id));
|
publishInternalEvent('antennaUpdated', await Antennas.findOneOrFail(antenna.id));
|
||||||
|
|
||||||
return await Antennas.pack(antenna.id);
|
return await Antennas.pack(antenna.id);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Channel from '../channel';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { StreamMessages } from '../types';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'antenna';
|
public readonly chName = 'antenna';
|
||||||
|
@ -19,11 +20,9 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onEvent(data: any) {
|
private async onEvent(data: StreamMessages['antenna']['spec']) {
|
||||||
const { type, body } = data;
|
if (data.type === 'note') {
|
||||||
|
const note = await Notes.pack(data.body.id, this.user, { detail: true });
|
||||||
if (type === 'note') {
|
|
||||||
const note = await Notes.pack(body.id, this.user, { detail: true });
|
|
||||||
|
|
||||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||||
if (isMutedUserRelated(note, this.muting)) return;
|
if (isMutedUserRelated(note, this.muting)) return;
|
||||||
|
@ -33,8 +32,6 @@ export default class extends Channel {
|
||||||
this.connection.cacheNote(note);
|
this.connection.cacheNote(note);
|
||||||
|
|
||||||
this.send('note', note);
|
this.send('note', note);
|
||||||
} else {
|
|
||||||
this.send(type, body);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@ import Channel from '../channel';
|
||||||
import { Notes, Users } from '@/models/index';
|
import { Notes, Users } from '@/models/index';
|
||||||
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
|
import { StreamMessages } from '../types';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'channel';
|
public readonly chName = 'channel';
|
||||||
|
@ -25,7 +26,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
if (note.channelId !== this.channelId) return;
|
if (note.channelId !== this.channelId) return;
|
||||||
|
|
||||||
// リプライなら再pack
|
// リプライなら再pack
|
||||||
|
@ -52,7 +53,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private onEvent(data: any) {
|
private onEvent(data: StreamMessages['channel']['spec']) {
|
||||||
if (data.type === 'typing') {
|
if (data.type === 'typing') {
|
||||||
const id = data.body;
|
const id = data.body;
|
||||||
const begin = this.typers[id] == null;
|
const begin = this.typers[id] == null;
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import Channel from '../channel';
|
import Channel from '../channel';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'globalTimeline';
|
public readonly chName = 'globalTimeline';
|
||||||
|
@ -24,7 +24,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
if (note.visibility !== 'public') return;
|
if (note.visibility !== 'public') return;
|
||||||
if (note.channelId != null) return;
|
if (note.channelId != null) return;
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ import autobind from 'autobind-decorator';
|
||||||
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import Channel from '../channel';
|
import Channel from '../channel';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { normalizeForSearch } from '@/misc/normalize-for-search';
|
import { normalizeForSearch } from '@/misc/normalize-for-search';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'hashtag';
|
public readonly chName = 'hashtag';
|
||||||
|
@ -23,7 +23,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
const noteTags = note.tags ? note.tags.map((t: string) => t.toLowerCase()) : [];
|
const noteTags = note.tags ? note.tags.map((t: string) => t.toLowerCase()) : [];
|
||||||
const matched = this.q.some(tags => tags.every(tag => noteTags.includes(normalizeForSearch(tag))));
|
const matched = this.q.some(tags => tags.every(tag => noteTags.includes(normalizeForSearch(tag))));
|
||||||
if (!matched) return;
|
if (!matched) return;
|
||||||
|
|
|
@ -2,9 +2,9 @@ import autobind from 'autobind-decorator';
|
||||||
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import Channel from '../channel';
|
import Channel from '../channel';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'homeTimeline';
|
public readonly chName = 'homeTimeline';
|
||||||
|
@ -18,7 +18,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
if (note.channelId) {
|
if (note.channelId) {
|
||||||
if (!this.followingChannels.has(note.channelId)) return;
|
if (!this.followingChannels.has(note.channelId)) return;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import Channel from '../channel';
|
import Channel from '../channel';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'hybridTimeline';
|
public readonly chName = 'hybridTimeline';
|
||||||
|
@ -22,7 +22,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
// チャンネルの投稿ではなく、自分自身の投稿 または
|
// チャンネルの投稿ではなく、自分自身の投稿 または
|
||||||
// チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または
|
// チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または
|
||||||
// チャンネルの投稿ではなく、全体公開のローカルの投稿 または
|
// チャンネルの投稿ではなく、全体公開のローカルの投稿 または
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import Channel from '../channel';
|
import Channel from '../channel';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
import { Notes } from '@/models/index';
|
import { Notes } from '@/models/index';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { checkWordMute } from '@/misc/check-word-mute';
|
import { checkWordMute } from '@/misc/check-word-mute';
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'localTimeline';
|
public readonly chName = 'localTimeline';
|
||||||
|
@ -24,7 +24,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
if (note.user.host !== null) return;
|
if (note.user.host !== null) return;
|
||||||
if (note.visibility !== 'public') return;
|
if (note.visibility !== 'public') return;
|
||||||
if (note.channelId != null && !this.followingChannels.has(note.channelId)) return;
|
if (note.channelId != null && !this.followingChannels.has(note.channelId)) return;
|
||||||
|
|
|
@ -11,35 +11,33 @@ export default class extends Channel {
|
||||||
public async init(params: any) {
|
public async init(params: any) {
|
||||||
// Subscribe main stream channel
|
// Subscribe main stream channel
|
||||||
this.subscriber.on(`mainStream:${this.user!.id}`, async data => {
|
this.subscriber.on(`mainStream:${this.user!.id}`, async data => {
|
||||||
const { type } = data;
|
switch (data.type) {
|
||||||
let { body } = data;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'notification': {
|
case 'notification': {
|
||||||
if (this.muting.has(body.userId)) return;
|
if (data.body.userId && this.muting.has(data.body.userId)) return;
|
||||||
if (body.note && body.note.isHidden) {
|
|
||||||
const note = await Notes.pack(body.note.id, this.user, {
|
if (data.body.note && data.body.note.isHidden) {
|
||||||
|
const note = await Notes.pack(data.body.note.id, this.user, {
|
||||||
detail: true
|
detail: true
|
||||||
});
|
});
|
||||||
this.connection.cacheNote(note);
|
this.connection.cacheNote(note);
|
||||||
body.note = note;
|
data.body.note = note;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'mention': {
|
case 'mention': {
|
||||||
if (this.muting.has(body.userId)) return;
|
if (this.muting.has(data.body.userId)) return;
|
||||||
if (body.isHidden) {
|
if (data.body.isHidden) {
|
||||||
const note = await Notes.pack(body.id, this.user, {
|
const note = await Notes.pack(data.body.id, this.user, {
|
||||||
detail: true
|
detail: true
|
||||||
});
|
});
|
||||||
this.connection.cacheNote(note);
|
this.connection.cacheNote(note);
|
||||||
body = note;
|
data.body = note;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.send(type, body);
|
this.send(data.type, data.body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivit
|
||||||
import Channel from '../channel';
|
import Channel from '../channel';
|
||||||
import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index';
|
import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index';
|
||||||
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
|
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
|
||||||
|
import { UserGroup } from '@/models/entities/user-group';
|
||||||
|
import { StreamMessages } from '../types';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'messaging';
|
public readonly chName = 'messaging';
|
||||||
|
@ -12,7 +14,7 @@ export default class extends Channel {
|
||||||
private otherpartyId: string | null;
|
private otherpartyId: string | null;
|
||||||
private otherparty: User | null;
|
private otherparty: User | null;
|
||||||
private groupId: string | null;
|
private groupId: string | null;
|
||||||
private subCh: string;
|
private subCh: `messagingStream:${User['id']}-${User['id']}` | `messagingStream:${UserGroup['id']}`;
|
||||||
private typers: Record<User['id'], Date> = {};
|
private typers: Record<User['id'], Date> = {};
|
||||||
private emitTypersIntervalId: ReturnType<typeof setInterval>;
|
private emitTypersIntervalId: ReturnType<typeof setInterval>;
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private onEvent(data: any) {
|
private onEvent(data: StreamMessages['messaging']['spec'] | StreamMessages['groupMessaging']['spec']) {
|
||||||
if (data.type === 'typing') {
|
if (data.type === 'typing') {
|
||||||
const id = data.body;
|
const id = data.body;
|
||||||
const begin = this.typers[id] == null;
|
const begin = this.typers[id] == null;
|
||||||
|
|
|
@ -3,8 +3,8 @@ import Channel from '../channel';
|
||||||
import { Notes, UserListJoinings, UserLists } from '@/models/index';
|
import { Notes, UserListJoinings, UserLists } from '@/models/index';
|
||||||
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
import { isMutedUserRelated } from '@/misc/is-muted-user-related';
|
||||||
import { User } from '@/models/entities/user';
|
import { User } from '@/models/entities/user';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
import { isBlockerUserRelated } from '@/misc/is-blocker-user-related';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
export default class extends Channel {
|
export default class extends Channel {
|
||||||
public readonly chName = 'userList';
|
public readonly chName = 'userList';
|
||||||
|
@ -47,7 +47,7 @@ export default class extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNote(note: PackedNote) {
|
private async onNote(note: Packed<'Note'>) {
|
||||||
if (!this.listUsers.includes(note.userId)) return;
|
if (!this.listUsers.includes(note.userId)) return;
|
||||||
|
|
||||||
if (['followers', 'specified'].includes(note.visibility)) {
|
if (['followers', 'specified'].includes(note.visibility)) {
|
||||||
|
|
|
@ -14,7 +14,8 @@ import { AccessToken } from '@/models/entities/access-token';
|
||||||
import { UserProfile } from '@/models/entities/user-profile';
|
import { UserProfile } from '@/models/entities/user-profile';
|
||||||
import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream';
|
import { publishChannelStream, publishGroupMessagingStream, publishMessagingStream } from '@/services/stream';
|
||||||
import { UserGroup } from '@/models/entities/user-group';
|
import { UserGroup } from '@/models/entities/user-group';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
import { StreamEventEmitter, StreamMessages } from './types';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main stream connection
|
* Main stream connection
|
||||||
|
@ -28,10 +29,10 @@ export default class Connection {
|
||||||
public followingChannels: Set<ChannelModel['id']> = new Set();
|
public followingChannels: Set<ChannelModel['id']> = new Set();
|
||||||
public token?: AccessToken;
|
public token?: AccessToken;
|
||||||
private wsConnection: websocket.connection;
|
private wsConnection: websocket.connection;
|
||||||
public subscriber: EventEmitter;
|
public subscriber: StreamEventEmitter;
|
||||||
private channels: Channel[] = [];
|
private channels: Channel[] = [];
|
||||||
private subscribingNotes: any = {};
|
private subscribingNotes: any = {};
|
||||||
private cachedNotes: PackedNote[] = [];
|
private cachedNotes: Packed<'Note'>[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
wsConnection: websocket.connection,
|
wsConnection: websocket.connection,
|
||||||
|
@ -46,8 +47,8 @@ export default class Connection {
|
||||||
|
|
||||||
this.wsConnection.on('message', this.onWsConnectionMessage);
|
this.wsConnection.on('message', this.onWsConnectionMessage);
|
||||||
|
|
||||||
this.subscriber.on('broadcast', async ({ type, body }) => {
|
this.subscriber.on('broadcast', data => {
|
||||||
this.onBroadcastMessage(type, body);
|
this.onBroadcastMessage(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.user) {
|
if (this.user) {
|
||||||
|
@ -57,43 +58,41 @@ export default class Connection {
|
||||||
this.updateFollowingChannels();
|
this.updateFollowingChannels();
|
||||||
this.updateUserProfile();
|
this.updateUserProfile();
|
||||||
|
|
||||||
this.subscriber.on(`user:${this.user.id}`, ({ type, body }) => {
|
this.subscriber.on(`user:${this.user.id}`, this.onUserEvent);
|
||||||
this.onUserEvent(type, body);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private onUserEvent(type: string, body: any) {
|
private onUserEvent(data: StreamMessages['user']['spec']) { // { type, body }と展開すると型も展開されてしまう
|
||||||
switch (type) {
|
switch (data.type) {
|
||||||
case 'follow':
|
case 'follow':
|
||||||
this.following.add(body.id);
|
this.following.add(data.body.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'unfollow':
|
case 'unfollow':
|
||||||
this.following.delete(body.id);
|
this.following.delete(data.body.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'mute':
|
case 'mute':
|
||||||
this.muting.add(body.id);
|
this.muting.add(data.body.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'unmute':
|
case 'unmute':
|
||||||
this.muting.delete(body.id);
|
this.muting.delete(data.body.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: block events
|
// TODO: block events
|
||||||
|
|
||||||
case 'followChannel':
|
case 'followChannel':
|
||||||
this.followingChannels.add(body.id);
|
this.followingChannels.add(data.body.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'unfollowChannel':
|
case 'unfollowChannel':
|
||||||
this.followingChannels.delete(body.id);
|
this.followingChannels.delete(data.body.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'updateUserProfile':
|
case 'updateUserProfile':
|
||||||
this.userProfile = body;
|
this.userProfile = data.body;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'terminate':
|
case 'terminate':
|
||||||
|
@ -145,13 +144,13 @@ export default class Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private onBroadcastMessage(type: string, body: any) {
|
private onBroadcastMessage(data: StreamMessages['broadcast']['spec']) {
|
||||||
this.sendMessageToWs(type, body);
|
this.sendMessageToWs(data.type, data.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
public cacheNote(note: PackedNote) {
|
public cacheNote(note: Packed<'Note'>) {
|
||||||
const add = (note: PackedNote) => {
|
const add = (note: Packed<'Note'>) => {
|
||||||
const existIndex = this.cachedNotes.findIndex(n => n.id === note.id);
|
const existIndex = this.cachedNotes.findIndex(n => n.id === note.id);
|
||||||
if (existIndex > -1) {
|
if (existIndex > -1) {
|
||||||
this.cachedNotes[existIndex] = note;
|
this.cachedNotes[existIndex] = note;
|
||||||
|
@ -249,7 +248,7 @@ export default class Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async onNoteStreamMessage(data: any) {
|
private async onNoteStreamMessage(data: StreamMessages['note']['spec']) {
|
||||||
this.sendMessageToWs('noteUpdated', {
|
this.sendMessageToWs('noteUpdated', {
|
||||||
id: data.body.id,
|
id: data.body.id,
|
||||||
type: data.type,
|
type: data.type,
|
||||||
|
|
299
src/server/api/stream/types.ts
Normal file
299
src/server/api/stream/types.ts
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
import Emitter from 'strict-event-emitter-types';
|
||||||
|
import { Channel } from '@/models/entities/channel';
|
||||||
|
import { User } from '@/models/entities/user';
|
||||||
|
import { UserProfile } from '@/models/entities/user-profile';
|
||||||
|
import { Note } from '@/models/entities/note';
|
||||||
|
import { Antenna } from '@/models/entities/antenna';
|
||||||
|
import { DriveFile } from '@/models/entities/drive-file';
|
||||||
|
import { DriveFolder } from '@/models/entities/drive-folder';
|
||||||
|
import { Emoji } from '@/models/entities/emoji';
|
||||||
|
import { UserList } from '@/models/entities/user-list';
|
||||||
|
import { MessagingMessage } from '@/models/entities/messaging-message';
|
||||||
|
import { UserGroup } from '@/models/entities/user-group';
|
||||||
|
import { ReversiGame } from '@/models/entities/games/reversi/game';
|
||||||
|
import { AbuseUserReport } from '@/models/entities/abuse-user-report';
|
||||||
|
import { Signin } from '@/models/entities/signin';
|
||||||
|
import { Page } from '@/models/entities/page';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
|
//#region Stream type-body definitions
|
||||||
|
export interface InternalStreamTypes {
|
||||||
|
antennaCreated: Antenna;
|
||||||
|
antennaDeleted: Antenna;
|
||||||
|
antennaUpdated: Antenna;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BroadcastTypes {
|
||||||
|
emojiAdded: {
|
||||||
|
emoji: Packed<'Emoji'>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserStreamTypes {
|
||||||
|
terminate: {};
|
||||||
|
followChannel: Channel;
|
||||||
|
unfollowChannel: Channel;
|
||||||
|
updateUserProfile: UserProfile;
|
||||||
|
mute: User;
|
||||||
|
unmute: User;
|
||||||
|
follow: Packed<'User'>;
|
||||||
|
unfollow: Packed<'User'>;
|
||||||
|
userAdded: Packed<'User'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MainStreamTypes {
|
||||||
|
notification: Packed<'Notification'>;
|
||||||
|
mention: Packed<'Note'>;
|
||||||
|
reply: Packed<'Note'>;
|
||||||
|
renote: Packed<'Note'>;
|
||||||
|
follow: Packed<'User'>;
|
||||||
|
followed: Packed<'User'>;
|
||||||
|
unfollow: Packed<'User'>;
|
||||||
|
meUpdated: Packed<'User'>;
|
||||||
|
pageEvent: {
|
||||||
|
pageId: Page['id'];
|
||||||
|
event: string;
|
||||||
|
var: any;
|
||||||
|
userId: User['id'];
|
||||||
|
user: Packed<'User'>;
|
||||||
|
};
|
||||||
|
urlUploadFinished: {
|
||||||
|
marker?: string | null;
|
||||||
|
file: Packed<'DriveFile'>;
|
||||||
|
};
|
||||||
|
readAllNotifications: undefined;
|
||||||
|
unreadNotification: Packed<'Notification'>;
|
||||||
|
unreadMention: Note['id'];
|
||||||
|
readAllUnreadMentions: undefined;
|
||||||
|
unreadSpecifiedNote: Note['id'];
|
||||||
|
readAllUnreadSpecifiedNotes: undefined;
|
||||||
|
readAllMessagingMessages: undefined;
|
||||||
|
messagingMessage: Packed<'MessagingMessage'>;
|
||||||
|
unreadMessagingMessage: Packed<'MessagingMessage'>;
|
||||||
|
readAllAntennas: undefined;
|
||||||
|
unreadAntenna: Antenna;
|
||||||
|
readAllAnnouncements: undefined;
|
||||||
|
readAllChannels: undefined;
|
||||||
|
unreadChannel: Note['id'];
|
||||||
|
myTokenRegenerated: undefined;
|
||||||
|
reversiNoInvites: undefined;
|
||||||
|
reversiInvited: Packed<'ReversiMatching'>;
|
||||||
|
signin: Signin;
|
||||||
|
registryUpdated: {
|
||||||
|
scope?: string[];
|
||||||
|
key: string;
|
||||||
|
value: any | null;
|
||||||
|
};
|
||||||
|
driveFileCreated: Packed<'DriveFile'>;
|
||||||
|
readAntenna: Antenna;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DriveStreamTypes {
|
||||||
|
fileCreated: Packed<'DriveFile'>;
|
||||||
|
fileDeleted: DriveFile['id'];
|
||||||
|
fileUpdated: Packed<'DriveFile'>;
|
||||||
|
folderCreated: Packed<'DriveFolder'>;
|
||||||
|
folderDeleted: DriveFolder['id'];
|
||||||
|
folderUpdated: Packed<'DriveFolder'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoteStreamTypes {
|
||||||
|
pollVoted: {
|
||||||
|
choice: number;
|
||||||
|
userId: User['id'];
|
||||||
|
};
|
||||||
|
deleted: {
|
||||||
|
deletedAt: Date;
|
||||||
|
};
|
||||||
|
reacted: {
|
||||||
|
reaction: string;
|
||||||
|
emoji?: Emoji;
|
||||||
|
userId: User['id'];
|
||||||
|
};
|
||||||
|
unreacted: {
|
||||||
|
reaction: string;
|
||||||
|
userId: User['id'];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
type NoteStreamEventTypes = {
|
||||||
|
[key in keyof NoteStreamTypes]: {
|
||||||
|
id: Note['id'];
|
||||||
|
body: NoteStreamTypes[key];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ChannelStreamTypes {
|
||||||
|
typing: User['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserListStreamTypes {
|
||||||
|
userAdded: Packed<'User'>;
|
||||||
|
userRemoved: Packed<'User'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AntennaStreamTypes {
|
||||||
|
note: Note;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessagingStreamTypes {
|
||||||
|
read: MessagingMessage['id'][];
|
||||||
|
typing: User['id'];
|
||||||
|
message: Packed<'MessagingMessage'>;
|
||||||
|
deleted: MessagingMessage['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupMessagingStreamTypes {
|
||||||
|
read: {
|
||||||
|
ids: MessagingMessage['id'][];
|
||||||
|
userId: User['id'];
|
||||||
|
};
|
||||||
|
typing: User['id'];
|
||||||
|
message: Packed<'MessagingMessage'>;
|
||||||
|
deleted: MessagingMessage['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MessagingIndexStreamTypes {
|
||||||
|
read: MessagingMessage['id'][];
|
||||||
|
message: Packed<'MessagingMessage'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReversiStreamTypes {
|
||||||
|
matched: Packed<'ReversiGame'>;
|
||||||
|
invited: Packed<'ReversiMatching'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReversiGameStreamTypes {
|
||||||
|
started: Packed<'ReversiGame'>;
|
||||||
|
ended: {
|
||||||
|
winnerId?: User['id'] | null,
|
||||||
|
game: Packed<'ReversiGame'>;
|
||||||
|
};
|
||||||
|
updateSettings: {
|
||||||
|
key: string;
|
||||||
|
value: FIXME;
|
||||||
|
};
|
||||||
|
initForm: {
|
||||||
|
userId: User['id'];
|
||||||
|
form: FIXME;
|
||||||
|
};
|
||||||
|
updateForm: {
|
||||||
|
userId: User['id'];
|
||||||
|
id: string;
|
||||||
|
value: FIXME;
|
||||||
|
};
|
||||||
|
message: {
|
||||||
|
userId: User['id'];
|
||||||
|
message: FIXME;
|
||||||
|
};
|
||||||
|
changeAccepts: {
|
||||||
|
user1: boolean;
|
||||||
|
user2: boolean;
|
||||||
|
};
|
||||||
|
set: {
|
||||||
|
at: Date;
|
||||||
|
color: boolean;
|
||||||
|
pos: number;
|
||||||
|
next: boolean;
|
||||||
|
};
|
||||||
|
watching: User['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AdminStreamTypes {
|
||||||
|
newAbuseUserReport: {
|
||||||
|
id: AbuseUserReport['id'];
|
||||||
|
targetUserId: User['id'],
|
||||||
|
reporterId: User['id'],
|
||||||
|
comment: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
// 辞書(interface or type)から{ type, body }ユニオンを定義
|
||||||
|
// https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type
|
||||||
|
// VS Codeの展開を防止するためにEvents型を定義
|
||||||
|
type Events<T extends object> = { [K in keyof T]: { type: K; body: T[K]; } };
|
||||||
|
type EventUnionFromDictionary<
|
||||||
|
T extends object,
|
||||||
|
U = Events<T>
|
||||||
|
> = U[keyof U];
|
||||||
|
|
||||||
|
// name/messages(spec) pairs dictionary
|
||||||
|
export type StreamMessages = {
|
||||||
|
internal: {
|
||||||
|
name: 'internal';
|
||||||
|
spec: EventUnionFromDictionary<InternalStreamTypes>;
|
||||||
|
};
|
||||||
|
broadcast: {
|
||||||
|
name: 'broadcast';
|
||||||
|
spec: EventUnionFromDictionary<BroadcastTypes>;
|
||||||
|
};
|
||||||
|
user: {
|
||||||
|
name: `user:${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<UserStreamTypes>;
|
||||||
|
};
|
||||||
|
main: {
|
||||||
|
name: `mainStream:${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<MainStreamTypes>;
|
||||||
|
};
|
||||||
|
drive: {
|
||||||
|
name: `driveStream:${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<DriveStreamTypes>;
|
||||||
|
};
|
||||||
|
note: {
|
||||||
|
name: `noteStream:${Note['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<NoteStreamEventTypes>;
|
||||||
|
};
|
||||||
|
channel: {
|
||||||
|
name: `channelStream:${Channel['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<ChannelStreamTypes>;
|
||||||
|
};
|
||||||
|
userList: {
|
||||||
|
name: `userListStream:${UserList['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<UserListStreamTypes>;
|
||||||
|
};
|
||||||
|
antenna: {
|
||||||
|
name: `antennaStream:${Antenna['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<AntennaStreamTypes>;
|
||||||
|
};
|
||||||
|
messaging: {
|
||||||
|
name: `messagingStream:${User['id']}-${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<MessagingStreamTypes>;
|
||||||
|
};
|
||||||
|
groupMessaging: {
|
||||||
|
name: `messagingStream:${UserGroup['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<GroupMessagingStreamTypes>;
|
||||||
|
};
|
||||||
|
messagingIndex: {
|
||||||
|
name: `messagingIndexStream:${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<MessagingIndexStreamTypes>;
|
||||||
|
};
|
||||||
|
reversi: {
|
||||||
|
name: `reversiStream:${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<ReversiStreamTypes>;
|
||||||
|
};
|
||||||
|
reversiGame: {
|
||||||
|
name: `reversiGameStream:${ReversiGame['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<ReversiGameStreamTypes>;
|
||||||
|
};
|
||||||
|
admin: {
|
||||||
|
name: `adminStream:${User['id']}`;
|
||||||
|
spec: EventUnionFromDictionary<AdminStreamTypes>;
|
||||||
|
};
|
||||||
|
notes: {
|
||||||
|
name: 'notesStream';
|
||||||
|
spec: Packed<'Note'>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// API event definitions
|
||||||
|
// ストリームごとのEmitterの辞書を用意
|
||||||
|
type EventEmitterDictionary = { [x in keyof StreamMessages]: Emitter<EventEmitter, { [y in StreamMessages[x]['name']]: (e: StreamMessages[x]['spec']) => void }> };
|
||||||
|
// 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
|
||||||
|
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
||||||
|
// Emitter辞書から共用体型を作り、UnionToIntersectionで交差型にする
|
||||||
|
export type StreamEventEmitter = UnionToIntersection<EventEmitterDictionary[keyof StreamMessages]>;
|
||||||
|
// { [y in name]: (e: spec) => void }をまとめてその交差型をEmitterにかけるとts(2590)にひっかかる
|
||||||
|
|
||||||
|
// provide stream channels union
|
||||||
|
export type StreamChannels = StreamMessages[keyof StreamMessages]['name'];
|
|
@ -6,15 +6,15 @@ import { Not, IsNull, In } from 'typeorm';
|
||||||
import { Channel } from '@/models/entities/channel';
|
import { Channel } from '@/models/entities/channel';
|
||||||
import { checkHitAntenna } from '@/misc/check-hit-antenna';
|
import { checkHitAntenna } from '@/misc/check-hit-antenna';
|
||||||
import { getAntennas } from '@/misc/antenna-cache';
|
import { getAntennas } from '@/misc/antenna-cache';
|
||||||
import { PackedNote } from '@/models/repositories/note';
|
|
||||||
import { readNotificationByQuery } from '@/server/api/common/read-notification';
|
import { readNotificationByQuery } from '@/server/api/common/read-notification';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark notes as read
|
* Mark notes as read
|
||||||
*/
|
*/
|
||||||
export default async function(
|
export default async function(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
notes: (Note | PackedNote)[],
|
notes: (Note | Packed<'Note'>)[],
|
||||||
info?: {
|
info?: {
|
||||||
following: Set<User['id']>;
|
following: Set<User['id']>;
|
||||||
followingChannels: Set<Channel['id']>;
|
followingChannels: Set<Channel['id']>;
|
||||||
|
@ -34,10 +34,10 @@ export default async function(
|
||||||
})).map(x => x.followeeId));
|
})).map(x => x.followeeId));
|
||||||
|
|
||||||
const myAntennas = (await getAntennas()).filter(a => a.userId === userId);
|
const myAntennas = (await getAntennas()).filter(a => a.userId === userId);
|
||||||
const readMentions: (Note | PackedNote)[] = [];
|
const readMentions: (Note | Packed<'Note'>)[] = [];
|
||||||
const readSpecifiedNotes: (Note | PackedNote)[] = [];
|
const readSpecifiedNotes: (Note | Packed<'Note'>)[] = [];
|
||||||
const readChannelNotes: (Note | PackedNote)[] = [];
|
const readChannelNotes: (Note | Packed<'Note'>)[] = [];
|
||||||
const readAntennaNotes: (Note | PackedNote)[] = [];
|
const readAntennaNotes: (Note | Packed<'Note'>)[] = [];
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
if (note.mentions && note.mentions.includes(userId)) {
|
if (note.mentions && note.mentions.includes(userId)) {
|
||||||
|
@ -52,7 +52,7 @@ export default async function(
|
||||||
|
|
||||||
if (note.user != null) { // たぶんnullになることは無いはずだけど一応
|
if (note.user != null) { // たぶんnullになることは無いはずだけど一応
|
||||||
for (const antenna of myAntennas) {
|
for (const antenna of myAntennas) {
|
||||||
if (checkHitAntenna(antenna, note, note.user as any, undefined, Array.from(following))) {
|
if (await checkHitAntenna(antenna, note, note.user as any, undefined, Array.from(following))) {
|
||||||
readAntennaNotes.push(note);
|
readAntennaNotes.push(note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@ import * as push from 'web-push';
|
||||||
import config from '@/config/index';
|
import config from '@/config/index';
|
||||||
import { SwSubscriptions } from '@/models/index';
|
import { SwSubscriptions } from '@/models/index';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
import { PackedNotification } from '../models/repositories/notification';
|
import { Packed } from '@/misc/schema';
|
||||||
import { PackedMessagingMessage } from '../models/repositories/messaging-message';
|
import { pushNotificationData } from '@/types';
|
||||||
import { pushNotificationData } from '../types';
|
|
||||||
|
|
||||||
type pushNotificationsTypes = {
|
type pushNotificationsTypes = {
|
||||||
'notification': PackedNotification;
|
'notification': Packed<'Notification'>;
|
||||||
'unreadMessagingMessage': PackedMessagingMessage;
|
'unreadMessagingMessage': Packed<'MessagingMessage'>;
|
||||||
'readNotifications': { notificationIds: string[] };
|
'readNotifications': { notificationIds: string[] };
|
||||||
'readAllNotifications': undefined;
|
'readAllNotifications': undefined;
|
||||||
'readAllMessagingMessages': undefined;
|
'readAllMessagingMessages': undefined;
|
||||||
|
|
|
@ -7,9 +7,28 @@ import { UserGroup } from '@/models/entities/user-group';
|
||||||
import config from '@/config/index';
|
import config from '@/config/index';
|
||||||
import { Antenna } from '@/models/entities/antenna';
|
import { Antenna } from '@/models/entities/antenna';
|
||||||
import { Channel } from '@/models/entities/channel';
|
import { Channel } from '@/models/entities/channel';
|
||||||
|
import {
|
||||||
|
StreamChannels,
|
||||||
|
AdminStreamTypes,
|
||||||
|
AntennaStreamTypes,
|
||||||
|
BroadcastTypes,
|
||||||
|
ChannelStreamTypes,
|
||||||
|
DriveStreamTypes,
|
||||||
|
GroupMessagingStreamTypes,
|
||||||
|
InternalStreamTypes,
|
||||||
|
MainStreamTypes,
|
||||||
|
MessagingIndexStreamTypes,
|
||||||
|
MessagingStreamTypes,
|
||||||
|
NoteStreamTypes,
|
||||||
|
ReversiGameStreamTypes,
|
||||||
|
ReversiStreamTypes,
|
||||||
|
UserListStreamTypes,
|
||||||
|
UserStreamTypes
|
||||||
|
} from '@/server/api/stream/types';
|
||||||
|
import { Packed } from '@/misc/schema';
|
||||||
|
|
||||||
class Publisher {
|
class Publisher {
|
||||||
private publish = (channel: string, type: string | null, value?: any): void => {
|
private publish = (channel: StreamChannels, type: string | null, value?: any): void => {
|
||||||
const message = type == null ? value : value == null ?
|
const message = type == null ? value : value == null ?
|
||||||
{ type: type, body: null } :
|
{ type: type, body: null } :
|
||||||
{ type: type, body: value };
|
{ type: type, body: value };
|
||||||
|
@ -20,70 +39,70 @@ class Publisher {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishInternalEvent = (type: string, value?: any): void => {
|
public publishInternalEvent = <K extends keyof InternalStreamTypes>(type: K, value?: InternalStreamTypes[K]): void => {
|
||||||
this.publish('internal', type, typeof value === 'undefined' ? null : value);
|
this.publish('internal', type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishUserEvent = (userId: User['id'], type: string, value?: any): void => {
|
public publishUserEvent = <K extends keyof UserStreamTypes>(userId: User['id'], type: K, value?: UserStreamTypes[K]): void => {
|
||||||
this.publish(`user:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`user:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishBroadcastStream = (type: string, value?: any): void => {
|
public publishBroadcastStream = <K extends keyof BroadcastTypes>(type: K, value?: BroadcastTypes[K]): void => {
|
||||||
this.publish('broadcast', type, typeof value === 'undefined' ? null : value);
|
this.publish('broadcast', type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishMainStream = (userId: User['id'], type: string, value?: any): void => {
|
public publishMainStream = <K extends keyof MainStreamTypes>(userId: User['id'], type: K, value?: MainStreamTypes[K]): void => {
|
||||||
this.publish(`mainStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`mainStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishDriveStream = (userId: User['id'], type: string, value?: any): void => {
|
public publishDriveStream = <K extends keyof DriveStreamTypes>(userId: User['id'], type: K, value?: DriveStreamTypes[K]): void => {
|
||||||
this.publish(`driveStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`driveStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishNoteStream = (noteId: Note['id'], type: string, value: any): void => {
|
public publishNoteStream = <K extends keyof NoteStreamTypes>(noteId: Note['id'], type: K, value?: NoteStreamTypes[K]): void => {
|
||||||
this.publish(`noteStream:${noteId}`, type, {
|
this.publish(`noteStream:${noteId}`, type, {
|
||||||
id: noteId,
|
id: noteId,
|
||||||
body: value
|
body: value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishChannelStream = (channelId: Channel['id'], type: string, value?: any): void => {
|
public publishChannelStream = <K extends keyof ChannelStreamTypes>(channelId: Channel['id'], type: K, value?: ChannelStreamTypes[K]): void => {
|
||||||
this.publish(`channelStream:${channelId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`channelStream:${channelId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishUserListStream = (listId: UserList['id'], type: string, value?: any): void => {
|
public publishUserListStream = <K extends keyof UserListStreamTypes>(listId: UserList['id'], type: K, value?: UserListStreamTypes[K]): void => {
|
||||||
this.publish(`userListStream:${listId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`userListStream:${listId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishAntennaStream = (antennaId: Antenna['id'], type: string, value?: any): void => {
|
public publishAntennaStream = <K extends keyof AntennaStreamTypes>(antennaId: Antenna['id'], type: K, value?: AntennaStreamTypes[K]): void => {
|
||||||
this.publish(`antennaStream:${antennaId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`antennaStream:${antennaId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishMessagingStream = (userId: User['id'], otherpartyId: User['id'], type: string, value?: any): void => {
|
public publishMessagingStream = <K extends keyof MessagingStreamTypes>(userId: User['id'], otherpartyId: User['id'], type: K, value?: MessagingStreamTypes[K]): void => {
|
||||||
this.publish(`messagingStream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`messagingStream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishGroupMessagingStream = (groupId: UserGroup['id'], type: string, value?: any): void => {
|
public publishGroupMessagingStream = <K extends keyof GroupMessagingStreamTypes>(groupId: UserGroup['id'], type: K, value?: GroupMessagingStreamTypes[K]): void => {
|
||||||
this.publish(`messagingStream:${groupId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`messagingStream:${groupId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishMessagingIndexStream = (userId: User['id'], type: string, value?: any): void => {
|
public publishMessagingIndexStream = <K extends keyof MessagingIndexStreamTypes>(userId: User['id'], type: K, value?: MessagingIndexStreamTypes[K]): void => {
|
||||||
this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishReversiStream = (userId: User['id'], type: string, value?: any): void => {
|
public publishReversiStream = <K extends keyof ReversiStreamTypes>(userId: User['id'], type: K, value?: ReversiStreamTypes[K]): void => {
|
||||||
this.publish(`reversiStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`reversiStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishReversiGameStream = (gameId: ReversiGame['id'], type: string, value?: any): void => {
|
public publishReversiGameStream = <K extends keyof ReversiGameStreamTypes>(gameId: ReversiGame['id'], type: K, value?: ReversiGameStreamTypes[K]): void => {
|
||||||
this.publish(`reversiGameStream:${gameId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`reversiGameStream:${gameId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishNotesStream = (note: any): void => {
|
public publishNotesStream = (note: Packed<'Note'>): void => {
|
||||||
this.publish('notesStream', null, note);
|
this.publish('notesStream', null, note);
|
||||||
}
|
}
|
||||||
|
|
||||||
public publishAdminStream = (userId: User['id'], type: string, value?: any): void => {
|
public publishAdminStream = <K extends keyof AdminStreamTypes>(userId: User['id'], type: K, value?: AdminStreamTypes[K]): void => {
|
||||||
this.publish(`adminStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`adminStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10279,6 +10279,11 @@ streamsearch@0.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
||||||
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
||||||
|
|
||||||
|
strict-event-emitter-types@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz#05e15549cb4da1694478a53543e4e2f4abcf277f"
|
||||||
|
integrity sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==
|
||||||
|
|
||||||
strict-uri-encode@^1.0.0:
|
strict-uri-encode@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||||
|
|
Loading…
Reference in a new issue