diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts
index 12b0b49a..0f7be2a7 100644
--- a/util/src/entities/Member.ts
+++ b/util/src/entities/Member.ts
@@ -26,6 +26,22 @@ import { BaseClassWithoutId } from "./BaseClass";
import { Ban, PublicGuildRelations } from ".";
import { DiscordApiErrors } from "../util/Constants";
+export const MemberPrivateProjection: (keyof Member)[] = [
+ "id",
+ "guild",
+ "guild_id",
+ "deaf",
+ "joined_at",
+ "last_message_id",
+ "mute",
+ "nick",
+ "pending",
+ "premium_since",
+ "roles",
+ "settings",
+ "user",
+];
+
@Entity("members")
@Index(["id", "guild_id"], { unique: true })
export class Member extends BaseClassWithoutId {
@@ -81,7 +97,7 @@ export class Member extends BaseClassWithoutId {
@Column()
pending: boolean;
- @Column({ type: "simple-json" })
+ @Column({ type: "simple-json", select: false })
settings: UserGuildSettings;
@Column({ nullable: true })
diff --git a/util/src/entities/Session.ts b/util/src/entities/Session.ts
index 7cc325f5..ac5313f1 100644
--- a/util/src/entities/Session.ts
+++ b/util/src/entities/Session.ts
@@ -1,6 +1,8 @@
import { User } from "./User";
import { BaseClass } from "./BaseClass";
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import { Status } from "../interfaces/Status";
+import { Activity } from "../interfaces/Activity";
//TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them
@@ -17,11 +19,13 @@ export class Session extends BaseClass {
user: User;
//TODO check, should be 32 char long hex string
- @Column({ nullable: false })
+ @Column({ nullable: false, select: false })
session_id: string;
- activities: []; //TODO
+ @Column({ type: "simple-json", nullable: true })
+ activities: Activity[] = [];
+ // TODO client_status
@Column({ type: "simple-json", select: false })
client_info: {
client: string;
@@ -29,6 +33,14 @@ export class Session extends BaseClass {
version: number;
};
- @Column({ nullable: false })
- status: string; //TODO enum
+ @Column({ nullable: false, type: "varchar" })
+ status: Status; //TODO enum
}
+
+export const PrivateSessionProjection: (keyof Session)[] = [
+ "user_id",
+ "session_id",
+ "activities",
+ "client_info",
+ "status",
+];
diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index 04f1e9cb..bc852616 100644
--- a/util/src/entities/User.ts
+++ b/util/src/entities/User.ts
@@ -4,7 +4,7 @@ import { BitField } from "../util/BitField";
import { Relationship } from "./Relationship";
import { ConnectedAccount } from "./ConnectedAccount";
import { Config, FieldErrors, Snowflake, trimSpecial } from "..";
-import { Member } from ".";
+import { Member, Session } from ".";
export enum PublicUserEnum {
username,
@@ -131,6 +131,9 @@ export class User extends BaseClass {
@Column()
rights: string; // Rights
+ @OneToMany(() => Session, (session: Session) => session.user)
+ sessions: Session[];
+
@JoinColumn({ name: "relationship_ids" })
@OneToMany(() => Relationship, (relationship: Relationship) => relationship.from, {
cascade: true,
@@ -250,11 +253,13 @@ export class User extends BaseClass {
await user.save();
- if (Config.get().guild.autoJoin.enabled) {
- for (const guild of Config.get().guild.autoJoin.guilds || []) {
- await Member.addToGuild(user.id, guild);
+ setImmediate(async () => {
+ if (Config.get().guild.autoJoin.enabled) {
+ for (const guild of Config.get().guild.autoJoin.guilds || []) {
+ await Member.addToGuild(user.id, guild).catch((e) => {});
+ }
}
- }
+ });
return user;
}
@@ -293,7 +298,7 @@ export const defaultSettings: UserSettings = {
render_reactions: true,
restricted_guilds: [],
show_current_game: true,
- status: "offline",
+ status: "online",
stream_notifications_enabled: true,
theme: "dark",
timezone_offset: 0,
diff --git a/util/src/interfaces/Activity.ts b/util/src/interfaces/Activity.ts
index f5a3c270..43984afd 100644
--- a/util/src/interfaces/Activity.ts
+++ b/util/src/interfaces/Activity.ts
@@ -1,37 +1,38 @@
export interface Activity {
- name: string;
- type: ActivityType;
- url?: string;
- created_at?: Date;
+ name: string; // the activity's name
+ type: ActivityType; // activity type // TODO: check if its between range 0-5
+ url?: string; // stream url, is validated when type is 1
+ created_at?: number; // unix timestamp of when the activity was added to the user's session
timestamps?: {
- start?: number;
- end?: number;
- }[];
- application_id?: string;
+ // unix timestamps for start and/or end of the game
+ start: number;
+ end: number;
+ };
+ application_id?: string; // application id for the game
details?: string;
state?: string;
emoji?: {
name: string;
id?: string;
- amimated?: boolean;
+ animated: boolean;
};
party?: {
id?: string;
- size?: [number, number];
+ size?: [number]; // used to show the party's current and maximum size // TODO: array length 2
};
assets?: {
- large_image?: string;
- large_text?: string;
- small_image?: string;
- small_text?: string;
+ large_image?: string; // the id for a large asset of the activity, usually a snowflake
+ large_text?: string; // text displayed when hovering over the large image of the activity
+ small_image?: string; // the id for a small asset of the activity, usually a snowflake
+ small_text?: string; // text displayed when hovering over the small image of the activity
};
secrets?: {
- join?: string;
- spectate?: string;
- match?: string;
+ join?: string; // the secret for joining a party
+ spectate?: string; // the secret for spectating a game
+ match?: string; // the secret for a specific instanced match
};
instance?: boolean;
- flags?: bigint;
+ flags: string; // activity flags OR d together, describes what the payload includes
}
export enum ActivityType {
diff --git a/util/src/interfaces/Event.ts b/util/src/interfaces/Event.ts
index 13fd4b8b..a5253c09 100644
--- a/util/src/interfaces/Event.ts
+++ b/util/src/interfaces/Event.ts
@@ -13,6 +13,7 @@ import { ConnectedAccount } from "../entities/ConnectedAccount";
import { Relationship, RelationshipType } from "../entities/Relationship";
import { Presence } from "./Presence";
import { Sticker } from "..";
+import { Activity, Status } from ".";
export interface Event {
guild_id?: string;
@@ -454,6 +455,37 @@ export interface RelationshipRemoveEvent extends Event {
data: Omit<PublicRelationship, "nickname">;
}
+export interface SessionsReplace extends Event {
+ event: "SESSIONS_REPLACE";
+ data: {
+ activities: Activity[];
+ client_info: {
+ version: number;
+ os: string;
+ client: string;
+ };
+ status: Status;
+ }[];
+}
+
+export interface GuildMemberListUpdate extends Event {
+ event: "GUILD_MEMBER_LIST_UPDATE";
+ data: {
+ groups: { id: string; count: number }[];
+ guild_id: string;
+ id: string;
+ member_count: number;
+ online_count: number;
+ ops: {
+ index: number;
+ item: {
+ member?: PublicMember & { presence: Presence };
+ group?: { id: string; count: number }[];
+ };
+ }[];
+ };
+}
+
export type EventData =
| InvalidatedEvent
| ReadyEvent
@@ -474,6 +506,7 @@ export type EventData =
| GuildMemberRemoveEvent
| GuildMemberUpdateEvent
| GuildMembersChunkEvent
+ | GuildMemberListUpdate
| GuildRoleCreateEvent
| GuildRoleUpdateEvent
| GuildRoleDeleteEvent
@@ -523,6 +556,7 @@ export enum EVENTEnum {
GuildMemberUpdate = "GUILD_MEMBER_UPDATE",
GuildMemberSpeaking = "GUILD_MEMBER_SPEAKING",
GuildMembersChunk = "GUILD_MEMBERS_CHUNK",
+ GuildMemberListUpdate = "GUILD_MEMBER_LIST_UPDATE",
GuildRoleCreate = "GUILD_ROLE_CREATE",
GuildRoleDelete = "GUILD_ROLE_DELETE",
GuildRoleUpdate = "GUILD_ROLE_UPDATE",
@@ -546,6 +580,7 @@ export enum EVENTEnum {
ApplicationCommandCreate = "APPLICATION_COMMAND_CREATE",
ApplicationCommandUpdate = "APPLICATION_COMMAND_UPDATE",
ApplicationCommandDelete = "APPLICATION_COMMAND_DELETE",
+ SessionsReplace = "SESSIONS_REPLACE",
}
export type EVENT =
@@ -569,6 +604,7 @@ export type EVENT =
| "GUILD_MEMBER_UPDATE"
| "GUILD_MEMBER_SPEAKING"
| "GUILD_MEMBERS_CHUNK"
+ | "GUILD_MEMBER_LIST_UPDATE"
| "GUILD_ROLE_CREATE"
| "GUILD_ROLE_DELETE"
| "GUILD_ROLE_UPDATE"
@@ -597,6 +633,7 @@ export type EVENT =
| "MESSAGE_ACK"
| "RELATIONSHIP_ADD"
| "RELATIONSHIP_REMOVE"
+ | "SESSIONS_REPLACE"
| CUSTOMEVENTS;
export type CUSTOMEVENTS = "INVALIDATED" | "RATELIMIT";
diff --git a/util/src/interfaces/Presence.ts b/util/src/interfaces/Presence.ts
index 4a1ff038..7663891a 100644
--- a/util/src/interfaces/Presence.ts
+++ b/util/src/interfaces/Presence.ts
@@ -1,10 +1,12 @@
import { ClientStatus, Status } from "./Status";
import { Activity } from "./Activity";
+import { PublicUser } from "../entities/User";
export interface Presence {
- user_id: string;
+ user: PublicUser;
guild_id?: string;
status: Status;
activities: Activity[];
client_status: ClientStatus;
+ // TODO: game
}
|