Skip to content

Commit

Permalink
MongoDB Migration
Browse files Browse the repository at this point in the history
  • Loading branch information
Loudbooks committed Dec 11, 2024
1 parent b43ca5b commit ee764ae
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 13 deletions.
4 changes: 2 additions & 2 deletions backend/src/controllers/get_controller.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::aws_service::AWSService;
use crate::database::aws_service::AWSService;
use actix_web::{
web, HttpRequest, HttpResponse, Responder,
};
use serde::Deserialize;
use std::sync::Arc;
use crate::mongodb_service::MongoService;
use crate::database::mongodb_service::MongoService;

#[derive(Deserialize)]
pub struct ContentQuery {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/controllers/upload_controller.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::aws_service::AWSService;
use crate::database::aws_service::AWSService;
use crate::models::paste::Paste;
use crate::mongodb_service::MongoService;
use crate::database::mongodb_service::MongoService;
use crate::utils::iputils::IPUtils;
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
Expand Down
File renamed without changes.
136 changes: 136 additions & 0 deletions backend/src/database/migration_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use crate::models::paste::Paste;
use crate::models::user::User;
use futures_util::StreamExt;
use mongodb::bson::{doc, Document};
use mongodb::{Collection, Database};

pub struct MigrationService {
database: Database,
admin_database: Database,
users_collection: Collection<User>,
pastes_collection: Collection<Paste>,
}

impl MigrationService {
pub fn new(database: &Database, admin_database: &Database, users_collection: &Collection<User>, pastes_collection: &Collection<Paste>) -> Self {
Self {
database: database.clone(),
admin_database: admin_database.clone(),
users_collection: users_collection.clone(),
pastes_collection: pastes_collection.clone(),
}
}

pub async fn run_migrations(&self) {
self.user_migration_12_11_24().await.map_err(|e| println!("Error migrating users: {}", e)).ok();
self.paste_migration_12_11_24().await.map_err(|e| println!("Error migrating pastes: {}", e)).ok();
}

pub async fn user_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> {
if !self.database.list_collection_names().await?.contains(&"user".to_string()) {
println!("No users to migrate.");
return Ok(());
}

println!("Migrating users...");
let old_user_collection = self.database.collection::<Document>("user");

let mut amount = 0;
let target_amount = old_user_collection.count_documents(doc! {}).await?;
let mut cursor = old_user_collection.find(doc! {}).await?;

while let Some(old_user) = cursor.next().await {
let old_user = old_user?;
let user_ip = old_user.get_str("_id").unwrap_or_default();
let user_id = old_user.get_str("id").unwrap_or_default();
let user_requests = old_user.get_i32("requests").unwrap_or_default();
let user_banned = old_user.get_bool("banned").unwrap_or_default();
let last_visit = old_user.get_i64("lastVisit").unwrap_or_default();

if user_ip.is_empty() || user_id.is_empty() {
println!("Skipping user with empty IP or ID.");
continue;
}

let user = User {
ip: user_ip.to_string(),
id: user_id.to_string(),
requests: user_requests as u64,
created_at: last_visit,
banned: user_banned,
};

self.users_collection.insert_one(user).await?;

amount += 1;
}

println!("Migrated {} out of {} users", amount, target_amount);

let qualified_old_database_name = self.database.name().to_owned() + ".user";
let qualified_new_database_name = self.database.name().to_owned() + ".user_migrated_12_11_24";

self.admin_database.run_command(doc! {
"renameCollection": qualified_old_database_name,
"to": qualified_new_database_name,
"dropTarget": true
}).await?;

Ok(())
}

pub async fn paste_migration_12_11_24(&self) -> Result<(), mongodb::error::Error> {
if !self.database.list_collection_names().await?.contains(&"pastePrivateDTO".to_string()) {
println!("No pastes to migrate.");
}

println!("Migrating pastes...");
let old_paste_collection = self.database.collection::<Document>("pastePrivateDTO");

let mut amount = 0;
let target_amount = old_paste_collection.count_documents(doc! {}).await?;
let mut cursor = old_paste_collection.find(doc! {}).await?;

while let Some(old_paste) = cursor.next().await {
let old_paste = old_paste?;
let paste_id = old_paste.get_str("_id").unwrap_or_default();
let paste_expires_at = old_paste.get_i64("expires").unwrap_or_default();
let paste_created_at = old_paste.get_i64("created").unwrap_or_default();
let paste_creator_ip = old_paste.get_str("creatorIP").unwrap_or_default();
let paste_report_book = old_paste.get_bool("reportBook").unwrap_or_default();
let paste_wrap = old_paste.get_bool("wrap").unwrap_or_default();

if paste_id.is_empty() {
println!("Skipping paste with empty ID.");
continue;
}

let paste = Paste {
id: paste_id.to_string(),
title: "".to_string(),
created: paste_created_at as u64,
report_book: paste_report_book,
wrap: paste_wrap,
creator_ip: paste_creator_ip.to_string(),
expires_at: paste_expires_at as u64,
};

self.pastes_collection.insert_one(paste).await?;

amount += 1;
}

println!("Migrated {} out of {} pastes", amount, target_amount);

let qualified_old_database_name = self.database.name().to_owned() + ".pastePrivateDTO";
let qualified_new_database_name = self.database.name().to_owned() + ".pastePrivateDTO_migrated_12_11_24";

self.admin_database.run_command(doc! {
"renameCollection": qualified_old_database_name,
"to": qualified_new_database_name,
"dropTarget": true
}).await?;

Ok(())
}
}
5 changes: 5 additions & 0 deletions backend/src/database/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod aws_service;
pub mod mongodb_service;
pub mod mongoresult;

mod migration_service;
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use mongodb::bson::{doc, uuid};
use mongodb::{Client, Collection, Cursor};
use mongodb::options::ClientOptions;
use crate::database::migration_service::MigrationService;
use crate::models::paste::Paste;
use crate::models::user::User;
use crate::mongoresult::MongoResult;
use crate::database::mongoresult::MongoResult;

pub struct MongoService {
user_collection: Collection<User>,
Expand All @@ -17,10 +18,14 @@ impl MongoService {
let client = Client::with_options(client_options)?;

let database = client.database(db_name);
let admin_database = client.database("admin");
let user_collection = database.collection::<User>("users");
let paste_collection = database.collection::<Paste>("pastes");

println!("Connected to MongoDB");

let migration_service = MigrationService::new(&database, &admin_database, &user_collection, &paste_collection);
migration_service.run_migrations().await;

Ok(Self {
user_collection,
Expand All @@ -33,7 +38,7 @@ impl MongoService {
let update = doc! {
"$inc": { "requests": 1 },
"$setOnInsert": {
"id": uuid::Uuid::new().to_string(),
"_id": uuid::Uuid::new().to_string(),
"created_at": chrono::Utc::now().timestamp_millis(),
"banned": false
}
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions backend/src/delete_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use futures_util::StreamExt;
use tokio::spawn;
use tokio::time::interval;
use log::{error, warn};
use crate::aws_service::AWSService;
use crate::mongodb_service::MongoService;
use crate::database::aws_service::AWSService;
use crate::database::mongodb_service::MongoService;

pub struct DeleteHandler {
aws_service: Arc<AWSService>,
Expand Down
8 changes: 3 additions & 5 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
mod aws_service;
mod mongodb_service;
mod models;
mod controllers;
mod mongoresult;
mod utils;
mod delete_service;
mod database;

use crate::aws_service::AWSService;
use database::aws_service::AWSService;
use crate::controllers::get_controller::{get_content_handler, get_metadata_handler};
use crate::controllers::upload_controller::upload_handler;
use crate::delete_service::DeleteHandler;
use crate::mongodb_service::MongoService;
use database::mongodb_service::MongoService;
use actix_cors::Cors;
use actix_web::{web, App, HttpServer};
use std::env;
Expand Down

0 comments on commit ee764ae

Please sign in to comment.