user database improvements
This commit is contained in:
parent
5b95593d9c
commit
a9be4068b1
@ -1,5 +1,6 @@
|
|||||||
const { Collection } = require("@discordjs/collection");
|
const { Collection } = require("@discordjs/collection");
|
||||||
const { ObjectId } = require("mongodb");
|
const { ObjectId } = require("mongodb");
|
||||||
|
const { inspect } = require('node:util');
|
||||||
|
|
||||||
const { AbstractUserDatabase } = require("../interfaces/");
|
const { AbstractUserDatabase } = require("../interfaces/");
|
||||||
const { User } = require("../structures");
|
const { User } = require("../structures");
|
||||||
@ -23,8 +24,9 @@ class UserDatabase extends AbstractUserDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchUser (id, force = false) {
|
async fetchUser (id, force = false) {
|
||||||
|
|
||||||
if (!force && this.cache.has(id)) return this.cache.get(id);
|
if (!force && this.cache.has(id)) return this.cache.get(id);
|
||||||
|
if (id.includes('temp')) return null;
|
||||||
|
|
||||||
const data = await this.collection.findOne({ _id: ObjectId(id) });
|
const data = await this.collection.findOne({ _id: ObjectId(id) });
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
@ -33,15 +35,15 @@ class UserDatabase extends AbstractUserDatabase {
|
|||||||
this.cache.set(id, user);
|
this.cache.set(id, user);
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findUser (name) {
|
async findUser (username) {
|
||||||
|
|
||||||
let user = this.cache.find(u => u.name.toLowerCase() === name.toLowerCase());
|
let user = this.cache.find(u => u.username.toLowerCase() === username.toLowerCase());
|
||||||
if (user) return Promise.resolve(user);
|
if (user) return Promise.resolve(user);
|
||||||
|
|
||||||
const data = await this.collection.findOne({ name }, { collation: { locale: 'en', strength: 2 } });
|
const data = await this.collection.findOne({ username }, { collation: { locale: 'en', strength: 2 } });
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
|
|
||||||
user = this._createUser(data);
|
user = this._createUser(data);
|
||||||
@ -72,29 +74,61 @@ class UserDatabase extends AbstractUserDatabase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves or creates a user based on a discord profile
|
* Retrieves or creates a user based on a discord profile
|
||||||
*
|
* TODO: Somehow generalise this for any external OAuth profiles, passport normalises most profiles to the same fields
|
||||||
* @param {*} profile
|
* @param {*} profile
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof UserDatabase
|
* @memberof UserDatabase
|
||||||
*/
|
*/
|
||||||
async userFromDiscord (profile) {
|
async userFromDiscord (profile) {
|
||||||
|
|
||||||
|
// TODO: Figure out what to do when a user already exists with the same username as the discord profile
|
||||||
|
// Will break when logging in with discord to an existing account that doesn't have a linked account
|
||||||
let user = this.cache.find((u) => u.externalProfiles.discord?.id === profile.id);
|
let user = this.cache.find((u) => u.externalProfiles.discord?.id === profile.id);
|
||||||
if (user) return Promise.resolve(user);
|
if (user) return Promise.resolve(user);
|
||||||
|
|
||||||
const data = await this.collection.findOne({ 'externalProfiles.discord.id': profile.id });
|
const data = await this.collection.findOne({ 'externalProfiles.discord.id': profile.id });
|
||||||
if (data) user = this._createUser(data);
|
if (data) return Promise.resolve(this._createUser(data));
|
||||||
else {
|
|
||||||
this.logger.info(`Creating new user from Discord profile: ${profile.username} (${profile.id})`);
|
// If a user with the same username already exists, force the holder of the discord account to create a new account or log in to the other account and link them
|
||||||
user = this._createUser({ type: 'user', name: profile.username });
|
const existing = await this.collection.findOne({ username: profile.username }, { collation: { locale: 'en', strength: 2 } });
|
||||||
user.addExternalProfile('discord', profile);
|
if (existing) {
|
||||||
await user.save();
|
const temp = this._createUser({ type: 'user', temporary: true, displayName: profile.username });
|
||||||
this.cache.set(user.id, user);
|
temp.addExternalProfile('discord', profile);
|
||||||
|
// TODO: need to store the user somewhere shared across the shards
|
||||||
|
this.cache.set(temp.id, temp);
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.info(`Creating new user from Discord profile: ${profile.username} (${profile.id})`);
|
||||||
|
user = this._createUser({ type: 'user', name: profile.username });
|
||||||
|
user.addExternalProfile('discord', profile);
|
||||||
|
await user.save();
|
||||||
|
this.cache.set(user.id, user);
|
||||||
|
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user from username and password
|
||||||
|
*
|
||||||
|
* @param {*} username
|
||||||
|
* @param {*} password
|
||||||
|
* @memberof UserDatabase
|
||||||
|
*/
|
||||||
|
async createUser (username, password) {
|
||||||
|
|
||||||
|
const user = this._createUser({
|
||||||
|
username,
|
||||||
|
type: 'user'
|
||||||
|
});
|
||||||
|
await user.setPassword(password);
|
||||||
|
await this.updateUser(user);
|
||||||
|
this.cache.set(user.id, user);
|
||||||
|
return user;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates user entry
|
* Updates user entry
|
||||||
*
|
*
|
||||||
@ -102,14 +136,25 @@ class UserDatabase extends AbstractUserDatabase {
|
|||||||
* @memberof UserDatabase
|
* @memberof UserDatabase
|
||||||
*/
|
*/
|
||||||
async updateUser (user) {
|
async updateUser (user) {
|
||||||
if (user.id) await this.collection.updateOne({ _id: ObjectId(user.id) }, user.json);
|
const { json } = user;
|
||||||
|
this.logger.debug(`Storing user ${inspect(user.json)}`);
|
||||||
|
if (user._id) await this.collection.updateOne({ _id: ObjectId(user._id) }, json);
|
||||||
else {
|
else {
|
||||||
const result = await this.collection.insertOne(user.json);
|
const result = await this.collection.insertOne(json);
|
||||||
user.id = result.insertedId;
|
user._id = result.insertedId;
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for creating user object
|
||||||
|
* Not strictly necessary but it's here in case the constructor changes in a way that can easily be wrapped
|
||||||
|
*
|
||||||
|
* @param {object} data Raw user data
|
||||||
|
* @return {user}
|
||||||
|
* @memberof UserDatabase
|
||||||
|
*/
|
||||||
_createUser (data) {
|
_createUser (data) {
|
||||||
if (!data) throw new Error(`Missing data to create user`);
|
if (!data) throw new Error(`Missing data to create user`);
|
||||||
return new User(this, data);
|
return new User(this, data);
|
||||||
|
Loading…
Reference in New Issue
Block a user