feat(core/database): migrate to discriminators
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -2867,7 +2867,9 @@ dependencies = [
|
|||||||
"mongodb",
|
"mongodb",
|
||||||
"nanoid",
|
"nanoid",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"rand 0.8.5",
|
||||||
"redis-kiss",
|
"redis-kiss",
|
||||||
|
"regex",
|
||||||
"revolt-models",
|
"revolt-models",
|
||||||
"revolt-permissions",
|
"revolt-permissions",
|
||||||
"revolt-presence",
|
"revolt-presence",
|
||||||
@@ -2878,6 +2880,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"ulid 1.0.0",
|
"ulid 1.0.0",
|
||||||
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4327,6 +4330,12 @@ dependencies = [
|
|||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ revolt-permissions = { version = "0.6.0-rc.2", path = "../permissions", features
|
|||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
rand = "0.8.5"
|
||||||
ulid = "1.0.0"
|
ulid = "1.0.0"
|
||||||
nanoid = "0.4.0"
|
nanoid = "0.4.0"
|
||||||
once_cell = "1.17"
|
once_cell = "1.17"
|
||||||
@@ -46,6 +47,10 @@ redis-kiss = { version = "0.1.4" }
|
|||||||
bson = { optional = true, version = "2.1.0" }
|
bson = { optional = true, version = "2.1.0" }
|
||||||
mongodb = { optional = true, version = "2.1.0", default-features = false }
|
mongodb = { optional = true, version = "2.1.0", default-features = false }
|
||||||
|
|
||||||
|
# Database Migration
|
||||||
|
unicode-segmentation = "1.10.1"
|
||||||
|
regex = "1"
|
||||||
|
|
||||||
# Async Language Features
|
# Async Language Features
|
||||||
futures = "0.3.19"
|
futures = "0.3.19"
|
||||||
async-trait = "0.1.51"
|
async-trait = "0.1.51"
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ use crate::{
|
|||||||
MongoDb,
|
MongoDb,
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct MigrationInfo {
|
struct MigrationInfo {
|
||||||
@@ -16,7 +18,7 @@ struct MigrationInfo {
|
|||||||
revision: i32,
|
revision: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LATEST_REVISION: i32 = 24;
|
pub const LATEST_REVISION: i32 = 25;
|
||||||
|
|
||||||
pub async fn migrate_database(db: &MongoDb) {
|
pub async fn migrate_database(db: &MongoDb) {
|
||||||
let migrations = db.col::<Document>("migrations");
|
let migrations = db.col::<Document>("migrations");
|
||||||
@@ -769,24 +771,114 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if revision <= 23 {
|
if revision <= 23 {
|
||||||
info!("Running migration [revision 23 / 09-06-2023]: Add collection `channel_webhooks` if not exists, update users index.");
|
info!("Running migration [revision 23 / 10-06-2023]: Generate discriminators for users.");
|
||||||
|
|
||||||
db.db()
|
|
||||||
.create_collection("channel_webhooks", None)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
db.db()
|
db.db()
|
||||||
.run_command(
|
.run_command(
|
||||||
doc! {
|
doc! {
|
||||||
"dropIndexes": "users",
|
"dropIndexes": "users",
|
||||||
"indexes": "username"
|
"index": "username"
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to drop existing username index.");
|
.expect("Failed to drop existing username index.");
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct UserInformation {
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
id: String,
|
||||||
|
username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let re_username = regex::Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap();
|
||||||
|
|
||||||
|
let users: Vec<UserInformation> = db
|
||||||
|
.col::<UserInformation>("users")
|
||||||
|
.find(doc! {}, None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|doc| doc.expect("id and username"))
|
||||||
|
.collect()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let search_space: Vec<String> = (0..9999).map(|v| format!("{:0>4}", v)).collect();
|
||||||
|
|
||||||
|
for i in 0..users.len() {
|
||||||
|
let info = &users[i];
|
||||||
|
let discriminator = {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
search_space.choose(&mut rng).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
if re_username.is_match(&info.username) {
|
||||||
|
info!(
|
||||||
|
"Migrating user \"{}\" to #{} ({i}/{}) - compliant",
|
||||||
|
info.username,
|
||||||
|
discriminator,
|
||||||
|
users.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
db.col::<UserInformation>("users")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": &info.id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$set": {
|
||||||
|
"discriminator": discriminator
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
let mut sanitised = info
|
||||||
|
.username
|
||||||
|
.graphemes(true)
|
||||||
|
.filter(|s| re_username.is_match(s))
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
while sanitised.len() < 2 {
|
||||||
|
sanitised += "_";
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Migrating user \"{}\" to #{} ({i}/{}) - sanitised: \"{}\"",
|
||||||
|
info.username,
|
||||||
|
discriminator,
|
||||||
|
users.len(),
|
||||||
|
sanitised
|
||||||
|
);
|
||||||
|
|
||||||
|
db.col::<UserInformation>("users")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": &info.id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$set": {
|
||||||
|
"username": &info.username,
|
||||||
|
"discriminator": discriminator
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if revision <= 24 {
|
||||||
|
info!("Running migration [revision 24 / 09-06-2023]: Add collection `channel_webhooks` if not exists, update users index.");
|
||||||
|
|
||||||
|
db.db()
|
||||||
|
.create_collection("channel_webhooks", None)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
db.db()
|
db.db()
|
||||||
.run_command(
|
.run_command(
|
||||||
doc! {
|
doc! {
|
||||||
|
|||||||
Reference in New Issue
Block a user