mirror of
https://github.com/spacebarchat/server.git
synced 2026-10-22 15:22:43 +00:00
Merge branch 'master' into feat/refactorIdentify
This commit is contained in:
76 files changed
+3261
-60
No files matched your search
@@ -19,5 +19,5 @@
|
||||
export class ApiConfiguration {
|
||||
defaultVersion: string = "9";
|
||||
activeVersions: string[] = ["6", "7", "8", "9"];
|
||||
endpointPublic: string = "/api";
|
||||
endpointPublic: string | null = null;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import crypto from "crypto";
|
||||
import { ConnectedAccount } from "../entities";
|
||||
import { ConnectedAccountSchema, ConnectionCallbackSchema } from "../schemas";
|
||||
import { Config, DiscordApiErrors } from "../util";
|
||||
|
||||
/**
|
||||
* A connection that can be used to connect to an external service.
|
||||
*/
|
||||
export default abstract class Connection {
|
||||
id: string;
|
||||
settings: { enabled: boolean };
|
||||
states: Map<string, string> = new Map();
|
||||
|
||||
abstract init(): void;
|
||||
|
||||
/**
|
||||
* Generates an authorization url for the connection.
|
||||
* @param args
|
||||
*/
|
||||
abstract getAuthorizationUrl(userId: string): string;
|
||||
|
||||
/**
|
||||
* Returns the redirect_uri for a connection type
|
||||
* @returns redirect_uri for this connection
|
||||
*/
|
||||
getRedirectUri() {
|
||||
const endpointPublic =
|
||||
Config.get().api.endpointPublic ?? "http://localhost:3001";
|
||||
return `${endpointPublic}/connections/${this.id}/callback`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the callback
|
||||
* @param args Callback arguments
|
||||
*/
|
||||
abstract handleCallback(
|
||||
params: ConnectionCallbackSchema,
|
||||
): Promise<ConnectedAccount | null>;
|
||||
|
||||
/**
|
||||
* Gets a user id from state
|
||||
* @param state the state to get the user id from
|
||||
* @returns the user id associated with the state
|
||||
*/
|
||||
getUserId(state: string): string {
|
||||
if (!this.states.has(state)) throw DiscordApiErrors.INVALID_OAUTH_STATE;
|
||||
return this.states.get(state) as string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a state
|
||||
* @param user_id The user id to generate a state for.
|
||||
* @returns a new state
|
||||
*/
|
||||
createState(userId: string): string {
|
||||
const state = crypto.randomBytes(16).toString("hex");
|
||||
this.states.set(state, userId);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a state and checks if it is valid, and deletes it.
|
||||
* @param state The state to check.
|
||||
*/
|
||||
validateState(state: string): void {
|
||||
if (!this.states.has(state)) throw DiscordApiErrors.INVALID_OAUTH_STATE;
|
||||
this.states.delete(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Connected Account in the database.
|
||||
* @param data connected account data
|
||||
* @returns the new connected account
|
||||
*/
|
||||
async createConnection(
|
||||
data: ConnectedAccountSchema,
|
||||
): Promise<ConnectedAccount> {
|
||||
const ca = ConnectedAccount.create({ ...data });
|
||||
await ca.save();
|
||||
return ca;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has an exist connected account for the given extenal id.
|
||||
* @param userId the user id
|
||||
* @param externalId the connection id to find
|
||||
* @returns
|
||||
*/
|
||||
async hasConnection(userId: string, externalId: string): Promise<boolean> {
|
||||
const existing = await ConnectedAccount.findOne({
|
||||
where: {
|
||||
user_id: userId,
|
||||
external_id: externalId,
|
||||
},
|
||||
});
|
||||
|
||||
return !!existing;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ConnectionConfigEntity } from "../entities/ConnectionConfigEntity";
|
||||
|
||||
let config: any;
|
||||
let pairs: ConnectionConfigEntity[];
|
||||
|
||||
export const ConnectionConfig = {
|
||||
init: async function init() {
|
||||
if (config) return config;
|
||||
console.log("[Connections] Loading configuration...");
|
||||
pairs = await ConnectionConfigEntity.find();
|
||||
config = pairsToConfig(pairs);
|
||||
|
||||
return this.set(config);
|
||||
},
|
||||
get: function get() {
|
||||
if (!config) {
|
||||
return {};
|
||||
}
|
||||
return config;
|
||||
},
|
||||
set: function set(val: Partial<any>) {
|
||||
if (!config || !val) return;
|
||||
config = val.merge(config);
|
||||
|
||||
// return applyConfig(config);
|
||||
return applyConfig(val);
|
||||
},
|
||||
};
|
||||
|
||||
function applyConfig(val: any) {
|
||||
async function apply(obj: any, key = ""): Promise<any> {
|
||||
if (typeof obj === "object" && obj !== null && !(obj instanceof Date))
|
||||
return Promise.all(
|
||||
Object.keys(obj).map((k) =>
|
||||
apply(obj[k], key ? `${key}_${k}` : k),
|
||||
),
|
||||
);
|
||||
|
||||
let pair = pairs.find((x) => x.key === key);
|
||||
if (!pair) pair = new ConnectionConfigEntity();
|
||||
|
||||
pair.key = key;
|
||||
|
||||
if (pair.value !== obj) {
|
||||
pair.value = obj;
|
||||
if (!pair.key || pair.key == null) {
|
||||
console.log(`[Connections] WARN: Empty config key`);
|
||||
console.log(pair);
|
||||
} else return pair.save();
|
||||
}
|
||||
}
|
||||
|
||||
return apply(val);
|
||||
}
|
||||
|
||||
function pairsToConfig(pairs: ConnectionConfigEntity[]) {
|
||||
const value: any = {};
|
||||
|
||||
pairs.forEach((p) => {
|
||||
const keys = p.key.split("_");
|
||||
let obj = value;
|
||||
let prev = "";
|
||||
let prevObj = obj;
|
||||
let i = 0;
|
||||
|
||||
for (const key of keys) {
|
||||
if (!isNaN(Number(key)) && !prevObj[prev]?.length)
|
||||
prevObj[prev] = obj = [];
|
||||
if (i++ === keys.length - 1) obj[key] = p.value;
|
||||
else if (!obj[key]) obj[key] = {};
|
||||
|
||||
prev = key;
|
||||
prevObj = obj;
|
||||
obj = obj[key];
|
||||
}
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import Connection from "./Connection";
|
||||
import { ConnectionConfig } from "./ConnectionConfig";
|
||||
import { ConnectionStore } from "./ConnectionStore";
|
||||
|
||||
const root = "dist/connections";
|
||||
const connectionsLoaded = false;
|
||||
|
||||
export class ConnectionLoader {
|
||||
public static async loadConnections() {
|
||||
if (connectionsLoaded) return;
|
||||
ConnectionConfig.init();
|
||||
const dirs = fs.readdirSync(root).filter((x) => {
|
||||
try {
|
||||
fs.readdirSync(path.join(root, x));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
dirs.forEach(async (x) => {
|
||||
const modPath = path.resolve(path.join(root, x));
|
||||
const mod = new (require(modPath).default)() as Connection;
|
||||
ConnectionStore.connections.set(mod.id, mod);
|
||||
|
||||
mod.init();
|
||||
// console.log(`[Connections] Loaded connection '${mod.id}'`);
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public static getConnectionConfig(id: string, defaults?: any): any {
|
||||
let cfg = ConnectionConfig.get()[id];
|
||||
if (defaults) {
|
||||
if (cfg) cfg = Object.assign({}, defaults, cfg);
|
||||
else {
|
||||
cfg = defaults;
|
||||
this.setConnectionConfig(id, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg?.enabled) console.log(`[Connections] ${id} enabled`);
|
||||
|
||||
// if (!cfg)
|
||||
// console.log(
|
||||
// `[ConnectionConfig/WARN] Getting connection settings for '${id}' returned null! (Did you forget to add settings?)`,
|
||||
// );
|
||||
return cfg;
|
||||
}
|
||||
|
||||
public static async setConnectionConfig(
|
||||
id: string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
config: Partial<any>,
|
||||
): Promise<void> {
|
||||
if (!config)
|
||||
console.warn(`[Connections/WARN] ${id} tried to set config=null!`);
|
||||
|
||||
await ConnectionConfig.set({
|
||||
[id]: Object.assign(
|
||||
config,
|
||||
ConnectionLoader.getConnectionConfig(id) || {},
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Connection from "./Connection";
|
||||
import RefreshableConnection from "./RefreshableConnection";
|
||||
|
||||
export class ConnectionStore {
|
||||
public static connections: Map<string, Connection | RefreshableConnection> =
|
||||
new Map();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ConnectedAccount } from "../entities";
|
||||
import { ConnectedAccountCommonOAuthTokenResponse } from "../interfaces";
|
||||
import Connection from "./Connection";
|
||||
|
||||
/**
|
||||
* A connection that can refresh its token.
|
||||
*/
|
||||
export default abstract class RefreshableConnection extends Connection {
|
||||
refreshEnabled = true;
|
||||
/**
|
||||
* Refreshes the token for a connected account.
|
||||
* @param connectedAccount The connected account to refresh
|
||||
*/
|
||||
abstract refreshToken(
|
||||
connectedAccount: ConnectedAccount,
|
||||
): Promise<ConnectedAccountCommonOAuthTokenResponse>;
|
||||
|
||||
/**
|
||||
* Refreshes the token for a connected account and saves it to the database.
|
||||
* @param connectedAccount The connected account to refresh
|
||||
*/
|
||||
async refresh(
|
||||
connectedAccount: ConnectedAccount,
|
||||
): Promise<ConnectedAccountCommonOAuthTokenResponse> {
|
||||
const tokenData = await this.refreshToken(connectedAccount);
|
||||
connectedAccount.token_data = { ...tokenData, fetched_at: Date.now() };
|
||||
await connectedAccount.save();
|
||||
return tokenData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./Connection";
|
||||
export * from "./ConnectionConfig";
|
||||
export * from "./ConnectionLoader";
|
||||
export * from "./ConnectionStore";
|
||||
export * from "./RefreshableConnection";
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ConnectedAccount } from "../entities";
|
||||
|
||||
export class ConnectedAccountDTO {
|
||||
id: string;
|
||||
user_id: string;
|
||||
access_token?: string;
|
||||
friend_sync?: boolean;
|
||||
name: string;
|
||||
revoked?: boolean;
|
||||
show_activity?: number;
|
||||
type: string;
|
||||
verified?: boolean;
|
||||
visibility?: number;
|
||||
integrations?: string[];
|
||||
metadata_?: any;
|
||||
metadata_visibility?: number;
|
||||
two_way_link?: boolean;
|
||||
|
||||
constructor(
|
||||
connectedAccount: ConnectedAccount,
|
||||
with_token: boolean = false,
|
||||
) {
|
||||
this.id = connectedAccount.external_id;
|
||||
this.user_id = connectedAccount.user_id;
|
||||
this.access_token =
|
||||
connectedAccount.token_data && with_token
|
||||
? connectedAccount.token_data.access_token
|
||||
: undefined;
|
||||
this.friend_sync = connectedAccount.friend_sync;
|
||||
this.name = connectedAccount.name;
|
||||
this.revoked = connectedAccount.revoked;
|
||||
this.show_activity = connectedAccount.show_activity;
|
||||
this.type = connectedAccount.type;
|
||||
this.verified = connectedAccount.verified;
|
||||
this.visibility = +(connectedAccount.visibility || false);
|
||||
this.integrations = connectedAccount.integrations;
|
||||
this.metadata_ = connectedAccount.metadata_;
|
||||
this.metadata_visibility = +(
|
||||
connectedAccount.metadata_visibility || false
|
||||
);
|
||||
this.two_way_link = connectedAccount.two_way_link;
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,11 @@ import {
|
||||
ChannelType,
|
||||
Emoji,
|
||||
Guild,
|
||||
Member,
|
||||
PublicUser,
|
||||
Role,
|
||||
Sticker,
|
||||
UserGuildSettings,
|
||||
PublicMember,
|
||||
} from "../entities";
|
||||
|
||||
// TODO: this is not the best place for this type
|
||||
@@ -67,7 +67,7 @@ export interface IReadyGuildDTO {
|
||||
large: boolean | undefined;
|
||||
lazy: boolean;
|
||||
member_count: number | undefined;
|
||||
members: Member[];
|
||||
members: PublicMember[];
|
||||
premium_subscription_count: number | undefined;
|
||||
properties: {
|
||||
name: string;
|
||||
@@ -124,7 +124,7 @@ export class ReadyGuildDTO implements IReadyGuildDTO {
|
||||
large: boolean | undefined;
|
||||
lazy: boolean;
|
||||
member_count: number | undefined;
|
||||
members: Member[];
|
||||
members: PublicMember[];
|
||||
premium_subscription_count: number | undefined;
|
||||
properties: {
|
||||
name: string;
|
||||
@@ -191,7 +191,7 @@ export class ReadyGuildDTO implements IReadyGuildDTO {
|
||||
this.large = guild.large;
|
||||
this.lazy = true; // ??????????
|
||||
this.member_count = guild.member_count;
|
||||
this.members = guild.members;
|
||||
this.members = guild.members?.map((x) => x.toPublicMember());
|
||||
this.premium_subscription_count = guild.premium_subscription_count;
|
||||
this.properties = {
|
||||
name: guild.name,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./ConnectedAccountDTO";
|
||||
export * from "./DmChannelDTO";
|
||||
export * from "./ReadyGuildDTO";
|
||||
export * from "./UserDTO";
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
|
||||
import { ConnectedAccountTokenData } from "../interfaces";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { User } from "./User";
|
||||
|
||||
@@ -27,6 +28,9 @@ export type PublicConnectedAccount = Pick<
|
||||
|
||||
@Entity("connected_accounts")
|
||||
export class ConnectedAccount extends BaseClass {
|
||||
@Column()
|
||||
external_id: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
@RelationId((account: ConnectedAccount) => account.user)
|
||||
user_id: string;
|
||||
@@ -38,26 +42,44 @@ export class ConnectedAccount extends BaseClass {
|
||||
user: User;
|
||||
|
||||
@Column({ select: false })
|
||||
access_token: string;
|
||||
|
||||
@Column({ select: false })
|
||||
friend_sync: boolean;
|
||||
friend_sync?: boolean = false;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column({ select: false })
|
||||
revoked: boolean;
|
||||
revoked?: boolean = false;
|
||||
|
||||
@Column({ select: false })
|
||||
show_activity: boolean;
|
||||
show_activity?: number = 0;
|
||||
|
||||
@Column()
|
||||
type: string;
|
||||
|
||||
@Column()
|
||||
verified: boolean;
|
||||
verified?: boolean = true;
|
||||
|
||||
@Column({ select: false })
|
||||
visibility: number;
|
||||
visibility?: number = 0;
|
||||
|
||||
@Column({ type: "simple-array" })
|
||||
integrations?: string[] = [];
|
||||
|
||||
@Column({ type: "simple-json", name: "metadata", nullable: true })
|
||||
metadata_?: any;
|
||||
|
||||
@Column()
|
||||
metadata_visibility?: number = 0;
|
||||
|
||||
@Column()
|
||||
two_way_link?: boolean = false;
|
||||
|
||||
@Column({ select: false, nullable: true, type: "simple-json" })
|
||||
token_data?: ConnectedAccountTokenData | null;
|
||||
|
||||
async revoke() {
|
||||
this.revoked = true;
|
||||
this.token_data = null;
|
||||
await this.save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Column, Entity } from "typeorm";
|
||||
import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass";
|
||||
|
||||
@Entity("connection_config")
|
||||
export class ConnectionConfigEntity extends BaseClassWithoutId {
|
||||
@PrimaryIdColumn()
|
||||
key: string;
|
||||
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
value: number | boolean | null | string | Date | undefined;
|
||||
}
|
||||
+28
-11
@@ -260,9 +260,9 @@ export class Member extends BaseClassWithoutId {
|
||||
},
|
||||
},
|
||||
}),
|
||||
await Role.findOneOrFail({ where: { id: role_id, guild_id } }),
|
||||
Role.findOneOrFail({ where: { id: role_id, guild_id } }),
|
||||
]);
|
||||
member.roles = member.roles.filter((x) => x.id == role_id);
|
||||
member.roles = member.roles.filter((x) => x.id !== role_id);
|
||||
|
||||
await Promise.all([
|
||||
member.save(),
|
||||
@@ -330,17 +330,25 @@ export class Member extends BaseClassWithoutId {
|
||||
});
|
||||
|
||||
const memberCount = await Member.count({ where: { guild_id } });
|
||||
const memberPreview = await Member.find({
|
||||
where: {
|
||||
guild_id,
|
||||
user: {
|
||||
sessions: {
|
||||
status: Not("invisible" as const), // lol typescript?
|
||||
|
||||
const memberPreview = (
|
||||
await Member.find({
|
||||
where: {
|
||||
guild_id,
|
||||
user: {
|
||||
sessions: {
|
||||
status: Not("invisible" as const), // lol typescript?
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
take: 10,
|
||||
});
|
||||
relations: ["user", "roles"],
|
||||
take: 10,
|
||||
})
|
||||
).map((member) => ({
|
||||
...member.toPublicMember(),
|
||||
user: member.user.toPublicUser(),
|
||||
roles: member.roles.map((x) => x.id),
|
||||
}));
|
||||
|
||||
if (
|
||||
await Member.count({
|
||||
@@ -440,6 +448,15 @@ export class Member extends BaseClassWithoutId {
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
toPublicMember() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const member: any = {};
|
||||
PublicMemberProjection.forEach((x) => {
|
||||
member[x] = this[x];
|
||||
});
|
||||
return member as PublicMember;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChannelOverride {
|
||||
|
||||
@@ -27,6 +27,7 @@ export * from "./Channel";
|
||||
export * from "./ClientRelease";
|
||||
export * from "./Config";
|
||||
export * from "./ConnectedAccount";
|
||||
export * from "./ConnectionConfigEntity";
|
||||
export * from "./EmbedCache";
|
||||
export * from "./Emoji";
|
||||
export * from "./Encryption";
|
||||
|
||||
@@ -25,3 +25,4 @@ export * from "./dtos/index";
|
||||
export * from "./schemas";
|
||||
export * from "./imports";
|
||||
export * from "./config";
|
||||
export * from "./connections";
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface ConnectedAccountCommonOAuthTokenResponse {
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
scope: string;
|
||||
refresh_token?: string;
|
||||
expires_in?: number;
|
||||
}
|
||||
|
||||
export interface ConnectedAccountTokenData {
|
||||
access_token: string;
|
||||
token_type?: string;
|
||||
scope?: string;
|
||||
refresh_token?: string;
|
||||
expires_in?: number;
|
||||
expires_at?: number;
|
||||
fetched_at: number;
|
||||
}
|
||||
@@ -422,6 +422,10 @@ export interface UserDeleteEvent extends Event {
|
||||
};
|
||||
}
|
||||
|
||||
export interface UserConnectionsUpdateEvent extends Event {
|
||||
event: "USER_CONNECTIONS_UPDATE";
|
||||
}
|
||||
|
||||
export interface VoiceStateUpdateEvent extends Event {
|
||||
event: "VOICE_STATE_UPDATE";
|
||||
data: VoiceState & {
|
||||
@@ -563,6 +567,7 @@ export type EventData =
|
||||
| TypingStartEvent
|
||||
| UserUpdateEvent
|
||||
| UserDeleteEvent
|
||||
| UserConnectionsUpdateEvent
|
||||
| VoiceStateUpdateEvent
|
||||
| VoiceServerUpdateEvent
|
||||
| WebhooksUpdateEvent
|
||||
@@ -614,6 +619,7 @@ export enum EVENTEnum {
|
||||
TypingStart = "TYPING_START",
|
||||
UserUpdate = "USER_UPDATE",
|
||||
UserDelete = "USER_DELETE",
|
||||
UserConnectionsUpdate = "USER_CONNECTIONS_UPDATE",
|
||||
WebhooksUpdate = "WEBHOOKS_UPDATE",
|
||||
InteractionCreate = "INTERACTION_CREATE",
|
||||
VoiceStateUpdate = "VOICE_STATE_UPDATE",
|
||||
@@ -665,6 +671,7 @@ export type EVENT =
|
||||
| "TYPING_START"
|
||||
| "USER_UPDATE"
|
||||
| "USER_DELETE"
|
||||
| "USER_CONNECTIONS_UPDATE"
|
||||
| "USER_NOTE_UPDATE"
|
||||
| "WEBHOOKS_UPDATE"
|
||||
| "INTERACTION_CREATE"
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
*/
|
||||
|
||||
export * from "./Activity";
|
||||
export * from "./Presence";
|
||||
export * from "./Interaction";
|
||||
export * from "./ConnectedAccount";
|
||||
export * from "./Event";
|
||||
export * from "./Interaction";
|
||||
export * from "./Presence";
|
||||
export * from "./Status";
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ConnectedAccountTokenData } from "../interfaces";
|
||||
|
||||
export interface ConnectedAccountSchema {
|
||||
external_id: string;
|
||||
user_id: string;
|
||||
token_data?: ConnectedAccountTokenData;
|
||||
friend_sync?: boolean;
|
||||
name: string;
|
||||
revoked?: boolean;
|
||||
show_activity?: number;
|
||||
type: string;
|
||||
verified?: boolean;
|
||||
visibility?: number;
|
||||
integrations?: string[];
|
||||
metadata_?: any;
|
||||
metadata_visibility?: number;
|
||||
two_way_link?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface ConnectionCallbackSchema {
|
||||
code?: string;
|
||||
state: string;
|
||||
insecure: boolean;
|
||||
friend_sync: boolean;
|
||||
openid_params?: any; // TODO: types
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2023 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface ConnectionUpdateSchema {
|
||||
visibility?: boolean;
|
||||
show_activity?: boolean;
|
||||
metadata_visibility?: boolean;
|
||||
}
|
||||
@@ -30,6 +30,9 @@ export * from "./ChannelModifySchema";
|
||||
export * from "./ChannelPermissionOverwriteSchema";
|
||||
export * from "./ChannelReorderSchema";
|
||||
export * from "./CodesVerificationSchema";
|
||||
export * from "./ConnectedAccountSchema";
|
||||
export * from "./ConnectionCallbackSchema";
|
||||
export * from "./ConnectionUpdateSchema";
|
||||
export * from "./DmChannelCreateSchema";
|
||||
export * from "./EmojiCreateSchema";
|
||||
export * from "./EmojiModifySchema";
|
||||
|
||||
@@ -21,3 +21,11 @@
|
||||
export function containsAll(arr: unknown[], target: unknown[]) {
|
||||
return target.every((v) => arr.includes(v));
|
||||
}
|
||||
|
||||
/* https://stackoverflow.com/a/50636286 */
|
||||
export function partition<T>(array: T[], filter: (elem: T) => boolean) {
|
||||
const pass: T[] = [],
|
||||
fail: T[] = [];
|
||||
array.forEach((e) => (filter(e) ? pass : fail).push(e));
|
||||
return [pass, fail];
|
||||
}
|
||||
@@ -578,6 +578,7 @@ export const DiscordApiErrors = {
|
||||
UNKNOWN_EMOJI: new ApiError("Unknown emoji", 10014),
|
||||
UNKNOWN_WEBHOOK: new ApiError("Unknown webhook", 10015),
|
||||
UNKNOWN_WEBHOOK_SERVICE: new ApiError("Unknown webhook service", 10016),
|
||||
UNKNOWN_CONNECTION: new ApiError("Unknown connection", 10017, 400),
|
||||
UNKNOWN_SESSION: new ApiError("Unknown session", 10020),
|
||||
UNKNOWN_BAN: new ApiError("Unknown ban", 10026),
|
||||
UNKNOWN_SKU: new ApiError("Unknown SKU", 10027),
|
||||
@@ -786,6 +787,11 @@ export const DiscordApiErrors = {
|
||||
40006,
|
||||
),
|
||||
USER_BANNED: new ApiError("The user is banned from this guild", 40007),
|
||||
CONNECTION_REVOKED: new ApiError(
|
||||
"The connection has been revoked",
|
||||
40012,
|
||||
400,
|
||||
),
|
||||
TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError(
|
||||
"Target user is not connected to voice",
|
||||
40032,
|
||||
|
||||
Reference in new issue
Block a user