diff --git a/backend/src/controllers/get_controller.rs b/backend/src/controllers/get_controller.rs index bcc6e9e..3264802 100644 --- a/backend/src/controllers/get_controller.rs +++ b/backend/src/controllers/get_controller.rs @@ -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 { diff --git a/backend/src/controllers/upload_controller.rs b/backend/src/controllers/upload_controller.rs index 57002a1..7f178c0 100644 --- a/backend/src/controllers/upload_controller.rs +++ b/backend/src/controllers/upload_controller.rs @@ -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}; diff --git a/backend/src/aws_service.rs b/backend/src/database/aws_service.rs similarity index 100% rename from backend/src/aws_service.rs rename to backend/src/database/aws_service.rs diff --git a/backend/src/database/migration_service.rs b/backend/src/database/migration_service.rs new file mode 100644 index 0000000..412a335 --- /dev/null +++ b/backend/src/database/migration_service.rs @@ -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, + pastes_collection: Collection, +} + +impl MigrationService { + pub fn new(database: &Database, admin_database: &Database, users_collection: &Collection, pastes_collection: &Collection) -> 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::("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::("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(()) + } +} \ No newline at end of file diff --git a/backend/src/database/mod.rs b/backend/src/database/mod.rs new file mode 100644 index 0000000..ffa89f5 --- /dev/null +++ b/backend/src/database/mod.rs @@ -0,0 +1,5 @@ +pub mod aws_service; +pub mod mongodb_service; +pub mod mongoresult; + +mod migration_service; \ No newline at end of file diff --git a/backend/src/mongodb_service.rs b/backend/src/database/mongodb_service.rs similarity index 86% rename from backend/src/mongodb_service.rs rename to backend/src/database/mongodb_service.rs index db2e1cc..a56690d 100644 --- a/backend/src/mongodb_service.rs +++ b/backend/src/database/mongodb_service.rs @@ -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, @@ -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::("users"); let paste_collection = database.collection::("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, @@ -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 } diff --git a/backend/src/mongoresult.rs b/backend/src/database/mongoresult.rs similarity index 100% rename from backend/src/mongoresult.rs rename to backend/src/database/mongoresult.rs diff --git a/backend/src/delete_service.rs b/backend/src/delete_service.rs index 8f59397..aa02abc 100644 --- a/backend/src/delete_service.rs +++ b/backend/src/delete_service.rs @@ -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, diff --git a/backend/src/main.rs b/backend/src/main.rs index d5cf34a..5ebf303 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -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;