v12 (#5712)
Co-authored-by: MeiMei <30769358+mei23@users.noreply.github.com> Co-authored-by: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com>
This commit is contained in:
parent
a5955c1123
commit
f6154dc0af
871 changed files with 26140 additions and 71950 deletions
36
src/models/entities/announcement-read.ts
Normal file
36
src/models/entities/announcement-read.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { User } from './user';
|
||||
import { Announcement } from './announcement';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
@Index(['userId', 'announcementId'], { unique: true })
|
||||
export class AnnouncementRead {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the AnnouncementRead.'
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Index()
|
||||
@Column(id())
|
||||
public announcementId: Announcement['id'];
|
||||
|
||||
@ManyToOne(type => Announcement, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public announcement: Announcement | null;
|
||||
}
|
43
src/models/entities/announcement.ts
Normal file
43
src/models/entities/announcement.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { Entity, Index, Column, PrimaryColumn } from 'typeorm';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
export class Announcement {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the Announcement.'
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The updated date of the Announcement.',
|
||||
nullable: true
|
||||
})
|
||||
public updatedAt: Date | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 8192, nullable: false
|
||||
})
|
||||
public text: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 256, nullable: false
|
||||
})
|
||||
public title: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, nullable: true
|
||||
})
|
||||
public imageUrl: string | null;
|
||||
|
||||
constructor(data: Partial<Announcement>) {
|
||||
if (data == null) return;
|
||||
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
(this as any)[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
43
src/models/entities/antenna-note.ts
Normal file
43
src/models/entities/antenna-note.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||
import { Note } from './note';
|
||||
import { Antenna } from './antenna';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
@Index(['noteId', 'antennaId'], { unique: true })
|
||||
export class AntennaNote {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The note ID.'
|
||||
})
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public note: Note | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The antenna ID.'
|
||||
})
|
||||
public antennaId: Antenna['id'];
|
||||
|
||||
@ManyToOne(type => Antenna, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public antenna: Antenna | null;
|
||||
|
||||
@Index()
|
||||
@Column('boolean', {
|
||||
default: false
|
||||
})
|
||||
public read: boolean;
|
||||
}
|
81
src/models/entities/antenna.ts
Normal file
81
src/models/entities/antenna.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { User } from './user';
|
||||
import { id } from '../id';
|
||||
import { UserList } from './user-list';
|
||||
|
||||
@Entity()
|
||||
export class Antenna {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the Antenna.'
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The owner ID.'
|
||||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128,
|
||||
comment: 'The name of the Antenna.'
|
||||
})
|
||||
public name: string;
|
||||
|
||||
@Column('enum', { enum: ['home', 'all', 'users', 'list'] })
|
||||
public src: 'home' | 'all' | 'users' | 'list';
|
||||
|
||||
@Column({
|
||||
...id(),
|
||||
nullable: true
|
||||
})
|
||||
public userListId: UserList['id'] | null;
|
||||
|
||||
@ManyToOne(type => UserList, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public userList: UserList | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, array: true,
|
||||
default: '{}'
|
||||
})
|
||||
public users: string[];
|
||||
|
||||
@Column('jsonb', {
|
||||
default: []
|
||||
})
|
||||
public keywords: string[][];
|
||||
|
||||
@Column('boolean', {
|
||||
default: false
|
||||
})
|
||||
public caseSensitive: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false
|
||||
})
|
||||
public withReplies: boolean;
|
||||
|
||||
@Column('boolean')
|
||||
public withFile: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 2048, nullable: true,
|
||||
})
|
||||
public expression: string | null;
|
||||
|
||||
@Column('boolean')
|
||||
public notify: boolean;
|
||||
}
|
37
src/models/entities/clip-note.ts
Normal file
37
src/models/entities/clip-note.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { Entity, Index, JoinColumn, Column, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||
import { Note } from './note';
|
||||
import { Clip } from './clip';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
@Index(['noteId', 'clipId'], { unique: true })
|
||||
export class ClipNote {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The note ID.'
|
||||
})
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public note: Note | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The clip ID.'
|
||||
})
|
||||
public clipId: Clip['id'];
|
||||
|
||||
@ManyToOne(type => Clip, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public clip: Clip | null;
|
||||
}
|
38
src/models/entities/clip.ts
Normal file
38
src/models/entities/clip.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { User } from './user';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
export class Clip {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the Clip.'
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: 'The owner ID.'
|
||||
})
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128,
|
||||
comment: 'The name of the Clip.'
|
||||
})
|
||||
public name: string;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false
|
||||
})
|
||||
public isPublic: boolean;
|
||||
}
|
|
@ -34,11 +34,6 @@ export class Meta {
|
|||
})
|
||||
public maintainerEmail: string | null;
|
||||
|
||||
@Column('jsonb', {
|
||||
default: [],
|
||||
})
|
||||
public announcements: Record<string, any>[];
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
|
@ -54,11 +49,6 @@ export class Meta {
|
|||
})
|
||||
public disableGlobalTimeline: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: true,
|
||||
})
|
||||
public enableEmojiReaction: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
|
|
|
@ -58,18 +58,6 @@ export class Note {
|
|||
})
|
||||
public cw: string | null;
|
||||
|
||||
@Column({
|
||||
...id(),
|
||||
nullable: true
|
||||
})
|
||||
public appId: App['id'] | null;
|
||||
|
||||
@ManyToOne(type => App, {
|
||||
onDelete: 'SET NULL'
|
||||
})
|
||||
@JoinColumn()
|
||||
public app: App | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
|
@ -177,11 +165,6 @@ export class Note {
|
|||
})
|
||||
public hasPoll: boolean;
|
||||
|
||||
@Column('jsonb', {
|
||||
nullable: true, default: null
|
||||
})
|
||||
public geo: any | null;
|
||||
|
||||
//#region Denormalized fields
|
||||
@Index()
|
||||
@Column('varchar', {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Entity, Index, JoinColumn, ManyToOne, Column, PrimaryColumn } from 'typ
|
|||
import { User } from './user';
|
||||
import { id } from '../id';
|
||||
import { Note } from './note';
|
||||
import { FollowRequest } from './follow-request';
|
||||
|
||||
@Entity()
|
||||
export class Notification {
|
||||
|
@ -54,12 +55,14 @@ export class Notification {
|
|||
* quote - (自分または自分がWatchしている)投稿が引用Renoteされた
|
||||
* reaction - (自分または自分がWatchしている)投稿にリアクションされた
|
||||
* pollVote - (自分または自分がWatchしている)投稿の投票に投票された
|
||||
* receiveFollowRequest - フォローリクエストされた
|
||||
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
||||
*/
|
||||
@Column('varchar', {
|
||||
length: 32,
|
||||
@Column('enum', {
|
||||
enum: ['follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest', 'followRequestAccepted'],
|
||||
comment: 'The type of the Notification.'
|
||||
})
|
||||
public type: string;
|
||||
public type: 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollVote' | 'receiveFollowRequest' | 'followRequestAccepted';
|
||||
|
||||
/**
|
||||
* 通知が読まれたかどうか
|
||||
|
@ -82,6 +85,18 @@ export class Notification {
|
|||
@JoinColumn()
|
||||
public note: Note | null;
|
||||
|
||||
@Column({
|
||||
...id(),
|
||||
nullable: true
|
||||
})
|
||||
public followRequestId: FollowRequest['id'] | null;
|
||||
|
||||
@ManyToOne(type => FollowRequest, {
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
@JoinColumn()
|
||||
public followRequest: FollowRequest | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 128, nullable: true
|
||||
})
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { getRepository, getCustomRepository } from 'typeorm';
|
||||
import { Announcement } from './entities/announcement';
|
||||
import { AnnouncementRead } from './entities/announcement-read';
|
||||
import { Instance } from './entities/instance';
|
||||
import { Emoji } from './entities/emoji';
|
||||
import { Poll } from './entities/poll';
|
||||
|
@ -44,7 +46,13 @@ import { PageRepository } from './repositories/page';
|
|||
import { PageLikeRepository } from './repositories/page-like';
|
||||
import { ModerationLogRepository } from './repositories/moderation-logs';
|
||||
import { UsedUsername } from './entities/used-username';
|
||||
import { ClipRepository } from './repositories/clip';
|
||||
import { ClipNote } from './entities/clip-note';
|
||||
import { AntennaRepository } from './repositories/antenna';
|
||||
import { AntennaNote } from './entities/antenna-note';
|
||||
|
||||
export const Announcements = getRepository(Announcement);
|
||||
export const AnnouncementReads = getRepository(AnnouncementRead);
|
||||
export const Apps = getCustomRepository(AppRepository);
|
||||
export const Notes = getCustomRepository(NoteRepository);
|
||||
export const NoteFavorites = getCustomRepository(NoteFavoriteRepository);
|
||||
|
@ -90,3 +98,7 @@ export const Logs = getRepository(Log);
|
|||
export const Pages = getCustomRepository(PageRepository);
|
||||
export const PageLikes = getCustomRepository(PageLikeRepository);
|
||||
export const ModerationLogs = getCustomRepository(ModerationLogRepository);
|
||||
export const Clips = getCustomRepository(ClipRepository);
|
||||
export const ClipNotes = getRepository(ClipNote);
|
||||
export const Antennas = getCustomRepository(AntennaRepository);
|
||||
export const AntennaNotes = getRepository(AntennaNote);
|
||||
|
|
58
src/models/repositories/antenna.ts
Normal file
58
src/models/repositories/antenna.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { EntityRepository, Repository } from 'typeorm';
|
||||
import { Antenna } from '../entities/antenna';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { AntennaNotes } from '..';
|
||||
|
||||
export type PackedAntenna = SchemaType<typeof packedAntennaSchema>;
|
||||
|
||||
@EntityRepository(Antenna)
|
||||
export class AntennaRepository extends Repository<Antenna> {
|
||||
public async pack(
|
||||
src: Antenna['id'] | Antenna,
|
||||
): Promise<PackedAntenna> {
|
||||
const antenna = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||
|
||||
const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null;
|
||||
|
||||
return {
|
||||
id: antenna.id,
|
||||
createdAt: antenna.createdAt.toISOString(),
|
||||
name: antenna.name,
|
||||
keywords: antenna.keywords,
|
||||
src: antenna.src,
|
||||
userListId: antenna.userListId,
|
||||
users: antenna.users,
|
||||
caseSensitive: antenna.caseSensitive,
|
||||
notify: antenna.notify,
|
||||
withReplies: antenna.withReplies,
|
||||
withFile: antenna.withFile,
|
||||
hasUnreadNote
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const packedAntennaSchema = {
|
||||
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',
|
||||
description: 'The unique identifier for this Antenna.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the Antenna was created.'
|
||||
},
|
||||
name: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The name of the Antenna.'
|
||||
},
|
||||
},
|
||||
};
|
46
src/models/repositories/clip.ts
Normal file
46
src/models/repositories/clip.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { EntityRepository, Repository } from 'typeorm';
|
||||
import { Clip } from '../entities/clip';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
||||
export type PackedClip = SchemaType<typeof packedClipSchema>;
|
||||
|
||||
@EntityRepository(Clip)
|
||||
export class ClipRepository extends Repository<Clip> {
|
||||
public async pack(
|
||||
src: Clip['id'] | Clip,
|
||||
): Promise<PackedClip> {
|
||||
const clip = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||
|
||||
return {
|
||||
id: clip.id,
|
||||
createdAt: clip.createdAt.toISOString(),
|
||||
name: clip.name,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const packedClipSchema = {
|
||||
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',
|
||||
description: 'The unique identifier for this Clip.',
|
||||
example: 'xxxxxxxxxx',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'date-time',
|
||||
description: 'The date that the Clip was created.'
|
||||
},
|
||||
name: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The name of the Clip.'
|
||||
},
|
||||
},
|
||||
};
|
|
@ -3,6 +3,7 @@ import { NoteReaction } from '../entities/note-reaction';
|
|||
import { Users } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { convertLegacyReaction } from '../../misc/reaction-lib';
|
||||
|
||||
export type PackedNoteReaction = SchemaType<typeof packedNoteReactionSchema>;
|
||||
|
||||
|
@ -18,7 +19,7 @@ export class NoteReactionRepository extends Repository<NoteReaction> {
|
|||
id: reaction.id,
|
||||
createdAt: reaction.createdAt.toISOString(),
|
||||
user: await Users.pack(reaction.userId, me),
|
||||
type: reaction.reaction,
|
||||
type: convertLegacyReaction(reaction.reaction),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Emojis, Users, Apps, PollVotes, DriveFiles, NoteReactions, Followings,
|
|||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
import { convertLegacyReaction } from '../../misc/reaction-lib';
|
||||
|
||||
export type PackedNote = SchemaType<typeof packedNoteSchema>;
|
||||
|
||||
|
@ -71,7 +72,6 @@ export class NoteRepository extends Repository<Note> {
|
|||
packedNote.text = null;
|
||||
packedNote.poll = undefined;
|
||||
packedNote.cw = null;
|
||||
packedNote.geo = undefined;
|
||||
packedNote.isHidden = true;
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ export class NoteRepository extends Repository<Note> {
|
|||
});
|
||||
|
||||
if (reaction) {
|
||||
return reaction.reaction;
|
||||
return convertLegacyReaction(reaction.reaction);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -178,7 +178,6 @@ export class NoteRepository extends Repository<Note> {
|
|||
const packed = await awaitAll({
|
||||
id: note.id,
|
||||
createdAt: note.createdAt.toISOString(),
|
||||
app: note.appId ? Apps.pack(note.appId) : undefined,
|
||||
userId: note.userId,
|
||||
user: Users.pack(note.user || note.userId, meId),
|
||||
text: text,
|
||||
|
@ -189,7 +188,7 @@ export class NoteRepository extends Repository<Note> {
|
|||
viaMobile: note.viaMobile || undefined,
|
||||
renoteCount: note.renoteCount,
|
||||
repliesCount: note.repliesCount,
|
||||
reactions: note.reactions,
|
||||
reactions: note.reactions, // v12 TODO: convert legacy reaction
|
||||
tags: note.tags.length > 0 ? note.tags : undefined,
|
||||
emojis: populateEmojis(note.emojis, host, Object.keys(note.reactions)),
|
||||
fileIds: note.fileIds,
|
||||
|
@ -356,9 +355,6 @@ export const packedNoteSchema = {
|
|||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
},
|
||||
geo: {
|
||||
type: 'object' as const,
|
||||
optional: true as const, nullable: true as const,
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
|
|
|
@ -70,7 +70,7 @@ export const packedNotificationSchema = {
|
|||
type: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
enum: ['follow', 'receiveFollowRequest', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote'],
|
||||
enum: ['follow', 'followRequestAccepted', 'receiveFollowRequest', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote'],
|
||||
description: 'The type of the notification.'
|
||||
},
|
||||
userId: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import $ from 'cafy';
|
||||
import { EntityRepository, Repository, In, Not } from 'typeorm';
|
||||
import { User, ILocalUser, IRemoteUser } from '../entities/user';
|
||||
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages } from '..';
|
||||
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes } from '..';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import config from '../../config';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
|
@ -84,6 +84,47 @@ export class UserRepository extends Repository<User> {
|
|||
return withUser || withGroups.some(x => x);
|
||||
}
|
||||
|
||||
public async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> {
|
||||
const reads = await AnnouncementReads.find({
|
||||
userId: userId
|
||||
});
|
||||
|
||||
const count = await Announcements.count(reads.length > 0 ? {
|
||||
id: Not(In(reads.map(read => read.announcementId)))
|
||||
} : {});
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
public async getHasUnreadAntenna(userId: User['id']): Promise<boolean> {
|
||||
const antennas = await Antennas.find({ userId });
|
||||
|
||||
const unread = antennas.length > 0 ? await AntennaNotes.findOne({
|
||||
antennaId: In(antennas.map(x => x.id)),
|
||||
read: false
|
||||
}) : null;
|
||||
|
||||
return unread != null;
|
||||
}
|
||||
|
||||
public async getHasUnreadNotification(userId: User['id']): Promise<boolean> {
|
||||
const mute = await Mutings.find({
|
||||
muterId: userId
|
||||
});
|
||||
const mutedUserIds = mute.map(m => m.muteeId);
|
||||
|
||||
const count = await Notifications.count({
|
||||
where: {
|
||||
notifieeId: userId,
|
||||
...(mutedUserIds.length > 0 ? { notifierId: Not(In(mutedUserIds)) } : {}),
|
||||
isRead: false
|
||||
},
|
||||
take: 1
|
||||
});
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
public async pack(
|
||||
src: User['id'] | User,
|
||||
me?: User['id'] | User | null | undefined,
|
||||
|
@ -193,14 +234,10 @@ export class UserRepository extends Repository<User> {
|
|||
alwaysMarkNsfw: profile!.alwaysMarkNsfw,
|
||||
carefulBot: profile!.carefulBot,
|
||||
autoAcceptFollowed: profile!.autoAcceptFollowed,
|
||||
hasUnreadAnnouncement: this.getHasUnreadAnnouncement(user.id),
|
||||
hasUnreadAntenna: this.getHasUnreadAntenna(user.id),
|
||||
hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage(user.id),
|
||||
hasUnreadNotification: Notifications.count({
|
||||
where: {
|
||||
notifieeId: user.id,
|
||||
isRead: false
|
||||
},
|
||||
take: 1
|
||||
}).then(count => count > 0),
|
||||
hasUnreadNotification: this.getHasUnreadNotification(user.id),
|
||||
pendingReceivedFollowRequestsCount: FollowRequests.count({
|
||||
followeeId: user.id
|
||||
}),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue