feat: rename farmer to resource provider across codebase and update terminology
This commit is contained in:
@@ -392,11 +392,11 @@ impl DashboardController {
|
||||
render_template(&tmpl, "dashboard/user.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the farmer section of the dashboard
|
||||
pub async fn farmer_section(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
/// Renders the resource provider section of the dashboard
|
||||
pub async fn resource_provider_section(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||
.active_page("dashboard")
|
||||
.active_section("farmer")
|
||||
.active_section("resource_provider")
|
||||
.gitea_enabled(get_app_config().is_gitea_enabled())
|
||||
.build();
|
||||
|
||||
@@ -406,17 +406,17 @@ impl DashboardController {
|
||||
return render_template(&tmpl, "dashboard/welcome.html", &ctx);
|
||||
}
|
||||
|
||||
// FARMER FIX: Use persistent data only, no mock data for farmer dashboard
|
||||
// RESOURCE PROVIDER FIX: Use persistent data only, no mock data for resource provider dashboard
|
||||
if let Ok(Some(user_email)) = session.get::<String>("user_email") {
|
||||
ctx.insert("user_email", &user_email);
|
||||
// Initialize farmer service with slice calculator
|
||||
if let Ok(farmer_service) = crate::services::farmer::FarmerService::builder().build() {
|
||||
// Repair node-group data consistency when farmer dashboard loads
|
||||
if let Err(_e) = farmer_service.repair_node_group_consistency(&user_email) {
|
||||
// Initialize resource provider service with slice calculator
|
||||
if let Ok(resource_provider_service) = crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
// Repair node-group data consistency when resource provider dashboard loads
|
||||
if let Err(_e) = resource_provider_service.repair_node_group_consistency(&user_email) {
|
||||
}
|
||||
|
||||
// Repair missing marketplace SLA data for existing nodes
|
||||
if let Err(_e) = farmer_service.repair_missing_marketplace_sla(
|
||||
if let Err(_e) = resource_provider_service.repair_missing_marketplace_sla(
|
||||
&user_email,
|
||||
99.8, // default uptime
|
||||
100, // default bandwidth
|
||||
@@ -424,18 +424,18 @@ impl DashboardController {
|
||||
) {
|
||||
}
|
||||
|
||||
// Get farmer nodes with updated slice calculations
|
||||
let farmer_nodes = farmer_service.get_farmer_nodes(&user_email);
|
||||
// Get resource provider nodes with updated slice calculations
|
||||
let resource_provider_nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||
|
||||
// Calculate farmer statistics from nodes
|
||||
let total_nodes = farmer_nodes.len() as u32;
|
||||
// Calculate resource_provider statistics from nodes
|
||||
let total_nodes = resource_provider_nodes.len() as u32;
|
||||
let mut online_nodes = 0u32;
|
||||
let mut total_base_slices = 0u32;
|
||||
let mut allocated_base_slices = 0u32;
|
||||
let mut total_monthly_earnings = rust_decimal::Decimal::ZERO;
|
||||
let mut average_uptime = 0.0f32;
|
||||
|
||||
for node in &farmer_nodes {
|
||||
for node in &resource_provider_nodes {
|
||||
if matches!(node.status, crate::models::user::NodeStatus::Online) {
|
||||
online_nodes += 1;
|
||||
}
|
||||
@@ -449,8 +449,8 @@ impl DashboardController {
|
||||
average_uptime /= total_nodes as f32;
|
||||
}
|
||||
|
||||
// Create farmer statistics for the dashboard
|
||||
let farmer_stats = serde_json::json!({
|
||||
// Create resource_provider statistics for the dashboard
|
||||
let resource_provider_stats = serde_json::json!({
|
||||
"total_nodes": total_nodes,
|
||||
"online_nodes": online_nodes,
|
||||
"total_base_slices": total_base_slices,
|
||||
@@ -465,8 +465,8 @@ impl DashboardController {
|
||||
}
|
||||
});
|
||||
|
||||
ctx.insert("farmer_stats", &farmer_stats);
|
||||
ctx.insert("farmer_nodes", &farmer_nodes);
|
||||
ctx.insert("resource_provider_stats", &resource_provider_stats);
|
||||
ctx.insert("resource_provider_nodes", &resource_provider_nodes);
|
||||
}
|
||||
|
||||
// Load user data from session (without mock data override)
|
||||
@@ -490,7 +490,7 @@ impl DashboardController {
|
||||
}
|
||||
|
||||
ctx.insert("wallet_balance", &persistent_data.wallet_balance_usd);
|
||||
ctx.insert("farmer_earnings", &persistent_data.farmer_earnings);
|
||||
ctx.insert("resource_provider_earnings", &persistent_data.resource_provider_earnings);
|
||||
}
|
||||
|
||||
ctx.insert("user_json", &user_json);
|
||||
@@ -498,10 +498,10 @@ impl DashboardController {
|
||||
}
|
||||
}
|
||||
|
||||
// Load slice rental service to get farmer slice rental statistics
|
||||
// Load slice rental service to get resource_provider slice rental statistics
|
||||
if let Ok(slice_rental_service) = crate::services::slice_rental::SliceRentalService::builder().build() {
|
||||
let farmer_slice_stats = slice_rental_service.get_farmer_slice_statistics(&user_email);
|
||||
ctx.insert("slice_rental_statistics", &farmer_slice_stats);
|
||||
let resource_provider_slice_stats = slice_rental_service.get_resource_provider_slice_statistics(&user_email);
|
||||
ctx.insert("slice_rental_statistics", &resource_provider_slice_stats);
|
||||
|
||||
// Release any expired rentals
|
||||
if let Err(_e) = slice_rental_service.release_expired_rentals(&user_email) {
|
||||
@@ -509,7 +509,7 @@ impl DashboardController {
|
||||
}
|
||||
}
|
||||
|
||||
render_template(&tmpl, "dashboard/farmer.html", &ctx)
|
||||
render_template(&tmpl, "dashboard/resource_provider.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the app provider section of the dashboard
|
||||
@@ -837,13 +837,13 @@ impl DashboardController {
|
||||
render_template(&tmpl, "dashboard/pools.html", &ctx)
|
||||
}
|
||||
|
||||
/// API endpoint to return farmer dashboard data as JSON
|
||||
pub async fn farmer_data_api(session: Session) -> Result<impl Responder> {
|
||||
/// API endpoint to return resource_provider dashboard data as JSON
|
||||
pub async fn resource_provider_data_api(session: Session) -> Result<impl Responder> {
|
||||
|
||||
let user_email = session.get::<String>("user_email").unwrap_or_default().unwrap_or_default();
|
||||
|
||||
// FARMER FIX: Use farmer service to ensure data consistency
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// RESOURCE_PROVIDER FIX: Use resource_provider service to ensure data consistency
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(_e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -853,16 +853,16 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Repair data consistency before loading
|
||||
if let Err(_e) = farmer_service.repair_node_group_consistency(&user_email) {
|
||||
if let Err(_e) = resource_provider_service.repair_node_group_consistency(&user_email) {
|
||||
}
|
||||
|
||||
// Load real farmer data from persistence using farmer service
|
||||
let nodes = farmer_service.get_farmer_nodes(&user_email);
|
||||
let earnings = farmer_service.get_farmer_earnings(&user_email);
|
||||
let stats = farmer_service.get_farmer_statistics(&user_email);
|
||||
// Load real resource_provider data from persistence using resource_provider service
|
||||
let nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||
let earnings = resource_provider_service.get_resource_provider_earnings(&user_email);
|
||||
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
|
||||
|
||||
// Always use persistent data - no fallback to mock data for farmer dashboard
|
||||
// If no data exists, return empty but valid farmer data structure
|
||||
// Always use persistent data - no fallback to mock data for resource_provider dashboard
|
||||
// If no data exists, return empty but valid resource_provider data structure
|
||||
if nodes.is_empty() {
|
||||
return Ok(ResponseBuilder::ok()
|
||||
.json(serde_json::json!({
|
||||
@@ -885,12 +885,12 @@ impl DashboardController {
|
||||
.build());
|
||||
}
|
||||
|
||||
// Load slice products for this farmer
|
||||
// Load slice products for this resource_provider
|
||||
let slice_products = crate::services::user_persistence::UserPersistence::get_slice_products(&user_email);
|
||||
let active_slices = slice_products.len() as i32;
|
||||
|
||||
// Build comprehensive farmer data using statistics from farmer service
|
||||
let farmer_data = serde_json::json!({
|
||||
// Build comprehensive resource_provider data using statistics from resource_provider service
|
||||
let resource_provider_data = serde_json::json!({
|
||||
"total_nodes": stats.total_nodes,
|
||||
"online_nodes": stats.online_nodes,
|
||||
"total_capacity": stats.total_capacity,
|
||||
@@ -904,13 +904,13 @@ impl DashboardController {
|
||||
"slice_products": slice_products
|
||||
});
|
||||
Ok(ResponseBuilder::ok()
|
||||
.json(farmer_data)
|
||||
.json(resource_provider_data)
|
||||
.build())
|
||||
}
|
||||
|
||||
/// Enhanced farmer dashboard with node management
|
||||
pub async fn farmer_dashboard_enhanced(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
let farmer_service = crate::services::farmer::FarmerService::builder()
|
||||
/// Enhanced resource_provider dashboard with node management
|
||||
pub async fn resource_provider_dashboard_enhanced(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
let resource_provider_service = crate::services::resource_provider::ResourceProviderService::builder()
|
||||
.auto_sync_enabled(true)
|
||||
.metrics_collection(true)
|
||||
.build()
|
||||
@@ -922,14 +922,14 @@ impl DashboardController {
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default();
|
||||
|
||||
// Load farmer data using the service
|
||||
let nodes = farmer_service.get_farmer_nodes(&user_email);
|
||||
let earnings = farmer_service.get_farmer_earnings(&user_email);
|
||||
let stats = farmer_service.get_farmer_statistics(&user_email);
|
||||
// Load resource_provider data using the service
|
||||
let nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||
let earnings = resource_provider_service.get_resource_provider_earnings(&user_email);
|
||||
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
|
||||
|
||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||
.active_page("dashboard")
|
||||
.active_section("farmer")
|
||||
.active_section("resource_provider")
|
||||
.build();
|
||||
|
||||
ctx.insert("nodes", &nodes);
|
||||
@@ -944,10 +944,10 @@ impl DashboardController {
|
||||
ctx.insert("user", &user);
|
||||
}
|
||||
|
||||
render_template(&tmpl, "dashboard/farmer.html", &ctx)
|
||||
render_template(&tmpl, "dashboard/resource_provider.html", &ctx)
|
||||
}
|
||||
|
||||
/// API endpoint to add a new farm node using FarmerService
|
||||
/// API endpoint to add a new farm node using ResourceProviderService
|
||||
pub async fn add_farm_node_enhanced(session: Session, form: web::Json<serde_json::Value>) -> Result<impl Responder> {
|
||||
|
||||
let user_email = session.get::<String>("user_email")
|
||||
@@ -960,8 +960,8 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
// Initialize farmer service
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(_e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1064,7 +1064,7 @@ impl DashboardController {
|
||||
.bandwidth_mbps(node_data_json.get("bandwidth_mbps")
|
||||
.and_then(|v| v.as_i64())
|
||||
.unwrap_or(100) as i32)
|
||||
.node_type("MyceliumNode"); // Always MyceliumNode - farmers register MyceliumNodes to Mycelium Grid
|
||||
.node_type("MyceliumNode"); // Always MyceliumNode - resource providers register MyceliumNodes to Mycelium Grid
|
||||
|
||||
// Add optional fields
|
||||
if let Some(region) = node_data_json.get("region").and_then(|v| v.as_str()) {
|
||||
@@ -1087,8 +1087,8 @@ impl DashboardController {
|
||||
actix_web::error::ErrorBadRequest(format!("Invalid node data: {}", e))
|
||||
})?;
|
||||
|
||||
// Add node using farmer service
|
||||
match farmer_service.add_node(&user_email, node_data) {
|
||||
// Add node using resource_provider service
|
||||
match resource_provider_service.add_node(&user_email, node_data) {
|
||||
Ok(node) => {
|
||||
|
||||
// Add activity record
|
||||
@@ -1143,7 +1143,7 @@ impl DashboardController {
|
||||
_ => crate::models::user::NodeStatus::Offline,
|
||||
};
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1152,7 +1152,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
match farmer_service.update_node_status(&user_email, &node_id, status) {
|
||||
match resource_provider_service.update_node_status(&user_email, &node_id, status) {
|
||||
Ok(()) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1182,7 +1182,7 @@ impl DashboardController {
|
||||
|
||||
let node_id = path.into_inner();
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1191,7 +1191,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
match farmer_service.get_node_by_id(&user_email, &node_id) {
|
||||
match resource_provider_service.get_node_by_id(&user_email, &node_id) {
|
||||
Some(mut node) => {
|
||||
|
||||
// MARKETPLACE SLA FIX: Override grid data with marketplace SLA values when available
|
||||
@@ -1235,7 +1235,7 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1244,7 +1244,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let stats = farmer_service.get_farmer_statistics(&user_email);
|
||||
let stats = resource_provider_service.get_resource_provider_statistics(&user_email);
|
||||
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1262,7 +1262,7 @@ impl DashboardController {
|
||||
}
|
||||
|
||||
/// API endpoint to update node configuration
|
||||
pub async fn update_node_comprehensive(session: Session, path: web::Path<String>, form: web::Json<crate::services::farmer::NodeUpdateData>) -> Result<impl Responder> {
|
||||
pub async fn update_node_comprehensive(session: Session, path: web::Path<String>, form: web::Json<crate::services::resource_provider::NodeUpdateData>) -> Result<impl Responder> {
|
||||
let user_email = session.get::<String>("user_email")
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default();
|
||||
@@ -1275,7 +1275,7 @@ impl DashboardController {
|
||||
|
||||
let node_id = path.into_inner();
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1284,7 +1284,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
match farmer_service.update_node(&user_email, &node_id, form.into_inner()) {
|
||||
match resource_provider_service.update_node(&user_email, &node_id, form.into_inner()) {
|
||||
Ok(()) => {
|
||||
|
||||
// Add activity record
|
||||
@@ -1324,7 +1324,7 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1338,7 +1338,7 @@ impl DashboardController {
|
||||
let mut customized_formats = Vec::new();
|
||||
|
||||
for format_id in default_format_ids {
|
||||
if let Some(format) = farmer_service.get_default_slice_format_with_customizations(&user_email, format_id) {
|
||||
if let Some(format) = resource_provider_service.get_default_slice_format_with_customizations(&user_email, format_id) {
|
||||
customized_formats.push(format);
|
||||
}
|
||||
}
|
||||
@@ -1358,7 +1358,7 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1367,7 +1367,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let groups = farmer_service.get_node_groups(&user_email);
|
||||
let groups = resource_provider_service.get_node_groups(&user_email);
|
||||
Ok(ResponseBuilder::ok().json(groups).build())
|
||||
}
|
||||
|
||||
@@ -1383,7 +1383,7 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1402,7 +1402,7 @@ impl DashboardController {
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
match farmer_service.create_custom_node_group(&user_email, name, description, None) {
|
||||
match resource_provider_service.create_custom_node_group(&user_email, name, description, None) {
|
||||
Ok(group) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1431,7 +1431,7 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1449,10 +1449,10 @@ impl DashboardController {
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
match farmer_service.update_node_group_assignment(&user_email, node_id, group_id) {
|
||||
match resource_provider_service.update_node_group_assignment(&user_email, node_id, group_id) {
|
||||
Ok(group_name) => {
|
||||
// FARMER FIX: Repair consistency after group assignment change
|
||||
if let Err(e) = farmer_service.repair_node_group_consistency(&user_email) {
|
||||
// RESOURCE_PROVIDER FIX: Repair consistency after group assignment change
|
||||
if let Err(e) = resource_provider_service.repair_node_group_consistency(&user_email) {
|
||||
}
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1482,7 +1482,7 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1493,7 +1493,7 @@ impl DashboardController {
|
||||
|
||||
let group_id = path.into_inner();
|
||||
|
||||
match farmer_service.delete_custom_node_group(&user_email, &group_id) {
|
||||
match resource_provider_service.delete_custom_node_group(&user_email, &group_id) {
|
||||
Ok(()) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1523,7 +1523,7 @@ impl DashboardController {
|
||||
|
||||
let format_id = path.into_inner();
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1532,7 +1532,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
match farmer_service.get_default_slice_format_with_customizations(&user_email, &format_id) {
|
||||
match resource_provider_service.get_default_slice_format_with_customizations(&user_email, &format_id) {
|
||||
Some(format) => {
|
||||
Ok(ResponseBuilder::ok().json(format).build())
|
||||
}
|
||||
@@ -1558,7 +1558,7 @@ impl DashboardController {
|
||||
|
||||
let format_id = path.into_inner();
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -1576,7 +1576,7 @@ impl DashboardController {
|
||||
let bandwidth_mbps = form.get("bandwidth_mbps").and_then(|v| v.as_i64()).unwrap_or(100) as i32;
|
||||
let price_per_hour = form.get("price_per_hour").and_then(|v| v.as_f64()).map(rust_decimal::Decimal::from_f64_retain).flatten().unwrap_or(rust_decimal::Decimal::from(10));
|
||||
|
||||
let customization = crate::services::farmer::DefaultSliceFormat {
|
||||
let customization = crate::services::resource_provider::DefaultSliceFormat {
|
||||
id: format_id.clone(),
|
||||
name,
|
||||
cpu_cores,
|
||||
@@ -1587,7 +1587,7 @@ impl DashboardController {
|
||||
price_per_hour,
|
||||
};
|
||||
|
||||
match farmer_service.save_default_slice_customization(&user_email, &format_id, customization) {
|
||||
match resource_provider_service.save_default_slice_customization(&user_email, &format_id, customization) {
|
||||
Ok(_) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1630,9 +1630,9 @@ impl DashboardController {
|
||||
.map(|p| rust_decimal::Decimal::from_f64_retain(p).unwrap_or(rust_decimal::Decimal::new(50, 2)))
|
||||
.unwrap_or(rust_decimal::Decimal::new(50, 2)); // Fallback to 0.50 TFC/hour only if no price provided
|
||||
|
||||
// Load user data to get farmer name
|
||||
// Load user data to get resource_provider name
|
||||
let user = Self::load_user_with_persistent_data(&session);
|
||||
let farmer_name = user.as_ref().map(|u| u.name.clone()).unwrap_or_else(|| "Unknown Farmer".to_string());
|
||||
let resource_provider_name = user.as_ref().map(|u| u.name.clone()).unwrap_or_else(|| "Unknown ResourceProvider".to_string());
|
||||
|
||||
// Create slice configuration with pricing
|
||||
let slice_pricing = crate::models::product::SlicePricing::from_hourly(
|
||||
@@ -1657,7 +1657,7 @@ impl DashboardController {
|
||||
// Create slice product
|
||||
let slice_product = crate::models::product::Product::create_slice_product(
|
||||
user_email.clone(),
|
||||
farmer_name,
|
||||
resource_provider_name,
|
||||
name,
|
||||
slice_config,
|
||||
price_per_hour,
|
||||
@@ -2225,18 +2225,18 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize farmer service to check for existing nodes
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service to check for existing nodes
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
"error": "Failed to initialize farmer service"
|
||||
"error": "Failed to initialize resource_provider service"
|
||||
})).build());
|
||||
}
|
||||
};
|
||||
|
||||
// Get existing nodes to check for duplicates
|
||||
let existing_nodes = farmer_service.get_farmer_nodes(&user_email);
|
||||
let existing_nodes = resource_provider_service.get_resource_provider_nodes(&user_email);
|
||||
|
||||
// Validate each node and fetch data
|
||||
let mut validated_nodes = Vec::new();
|
||||
@@ -2502,12 +2502,12 @@ impl DashboardController {
|
||||
let slice_format = form.get("slice_format").and_then(|v| v.as_str()).map(|s| s.to_string());
|
||||
let slice_price = form.get("slice_price").and_then(|v| v.as_f64()).map(|p| Decimal::from_f64_retain(p).unwrap_or_default());
|
||||
|
||||
// Initialize farmer service
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
"error": "Failed to initialize farmer service"
|
||||
"error": "Failed to initialize resource_provider service"
|
||||
})).build());
|
||||
}
|
||||
};
|
||||
@@ -2515,7 +2515,7 @@ impl DashboardController {
|
||||
// Add nodes with comprehensive configuration
|
||||
log::info!(
|
||||
target: "api.dashboard",
|
||||
"add_grid_nodes:invoke_farmer_service req_id={} email={} node_count={} slice_enabled={} full_node_enabled={} pricing_mode={}",
|
||||
"add_grid_nodes:invoke_resource_provider_service req_id={} email={} node_count={} slice_enabled={} full_node_enabled={} pricing_mode={}",
|
||||
req_id,
|
||||
user_email,
|
||||
node_ids.len(),
|
||||
@@ -2556,19 +2556,19 @@ impl DashboardController {
|
||||
// For multi-node scenarios, apply pricing configuration based on user choice
|
||||
if node_ids.len() > 1 && pricing_mode == "same_for_all" && rental_options.is_some() {
|
||||
} else if node_ids.len() > 1 && pricing_mode == "individual" && individual_node_pricing.is_some() {
|
||||
// Individual pricing will be handled in the farmer service
|
||||
// Individual pricing will be handled in the resource_provider service
|
||||
}
|
||||
|
||||
// Choose the appropriate method based on pricing mode
|
||||
if pricing_mode == "individual" && individual_node_pricing.is_some() {
|
||||
farmer_service.add_multiple_grid_nodes_with_individual_pricing(
|
||||
resource_provider_service.add_multiple_grid_nodes_with_individual_pricing(
|
||||
&user_email,
|
||||
node_ids.clone(),
|
||||
slice_formats,
|
||||
individual_node_pricing.unwrap()
|
||||
).await
|
||||
} else {
|
||||
farmer_service.add_multiple_grid_nodes_with_comprehensive_config(
|
||||
resource_provider_service.add_multiple_grid_nodes_with_comprehensive_config(
|
||||
&user_email,
|
||||
node_ids.clone(),
|
||||
slice_formats,
|
||||
@@ -2576,7 +2576,7 @@ impl DashboardController {
|
||||
).await
|
||||
}
|
||||
} else {
|
||||
farmer_service.add_multiple_grid_nodes(&user_email, node_ids.clone()).await
|
||||
resource_provider_service.add_multiple_grid_nodes(&user_email, node_ids.clone()).await
|
||||
};
|
||||
|
||||
match add_result {
|
||||
@@ -2594,7 +2594,7 @@ impl DashboardController {
|
||||
// If node_group_id is provided, assign nodes to existing group
|
||||
if let Some(group_id) = node_group_id {
|
||||
for node in &added_nodes {
|
||||
if let Err(e) = farmer_service.assign_node_to_group(&user_email, &node.id, Some(group_id.clone())) {
|
||||
if let Err(e) = resource_provider_service.assign_node_to_group(&user_email, &node.id, Some(group_id.clone())) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
@@ -2606,7 +2606,7 @@ impl DashboardController {
|
||||
group_data.get("description").and_then(|v| v.as_str())
|
||||
) {
|
||||
// Create node group
|
||||
match farmer_service.create_custom_node_group(
|
||||
match resource_provider_service.create_custom_node_group(
|
||||
&user_email,
|
||||
group_name.to_string(),
|
||||
Some(group_description.to_string()),
|
||||
@@ -2626,7 +2626,7 @@ impl DashboardController {
|
||||
|
||||
// Add nodes to group
|
||||
for node in &added_nodes {
|
||||
if let Err(e) = farmer_service.assign_node_to_group(&user_email, &node.id, Some(group.id.clone())) {
|
||||
if let Err(e) = resource_provider_service.assign_node_to_group(&user_email, &node.id, Some(group.id.clone())) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2663,7 +2663,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = farmer_service.stake_on_node(&user_email, &node.id, staking_options) {
|
||||
if let Err(e) = resource_provider_service.stake_on_node(&user_email, &node.id, staking_options) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
@@ -2691,7 +2691,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
for node in &added_nodes {
|
||||
if let Err(e) = farmer_service.stake_on_node(&user_email, &node.id, staking_options.clone()) {
|
||||
if let Err(e) = resource_provider_service.stake_on_node(&user_email, &node.id, staking_options.clone()) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
@@ -2752,11 +2752,11 @@ impl DashboardController {
|
||||
let slice_format = form.get("slice_format").and_then(|v| v.as_str()).map(|s| s.to_string());
|
||||
let slice_price = form.get("slice_price").and_then(|v| v.as_f64()).map(|p| Decimal::from_f64_retain(p).unwrap_or_default());
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(_e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
"error": "Failed to initialize farmer service"
|
||||
"error": "Failed to initialize resource_provider service"
|
||||
})).build());
|
||||
}
|
||||
};
|
||||
@@ -2774,7 +2774,7 @@ impl DashboardController {
|
||||
resource_optimization: crate::models::user::ResourceOptimization::default(),
|
||||
};
|
||||
|
||||
match farmer_service.create_custom_node_group(
|
||||
match resource_provider_service.create_custom_node_group(
|
||||
&user_email,
|
||||
name.to_string(),
|
||||
description,
|
||||
@@ -2810,7 +2810,7 @@ impl DashboardController {
|
||||
})).build()),
|
||||
};
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
"success": false,
|
||||
@@ -2818,15 +2818,15 @@ impl DashboardController {
|
||||
})).build()),
|
||||
};
|
||||
|
||||
// FARMER FIX: Repair node-group data consistency before getting statistics
|
||||
if let Err(e) = farmer_service.repair_node_group_consistency(&user_email) {
|
||||
// RESOURCE_PROVIDER FIX: Repair node-group data consistency before getting statistics
|
||||
if let Err(e) = resource_provider_service.repair_node_group_consistency(&user_email) {
|
||||
}
|
||||
|
||||
let groups = farmer_service.get_node_groups(&user_email);
|
||||
let groups = resource_provider_service.get_node_groups(&user_email);
|
||||
let mut groups_with_stats = Vec::new();
|
||||
|
||||
for group in groups {
|
||||
match farmer_service.get_group_statistics(&user_email, &group.id) {
|
||||
match resource_provider_service.get_group_statistics(&user_email, &group.id) {
|
||||
Ok(stats) => {
|
||||
groups_with_stats.push(serde_json::json!({
|
||||
"group": group,
|
||||
@@ -5387,7 +5387,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Check if node exists and get its details first
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -5398,7 +5398,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Verify node exists and belongs to user
|
||||
let _node = match farmer_service.get_node_by_id(&user_email, &node_id) {
|
||||
let _node = match resource_provider_service.get_node_by_id(&user_email, &node_id) {
|
||||
Some(node) => node,
|
||||
None => {
|
||||
return Ok(ResponseBuilder::not_found().json(serde_json::json!({
|
||||
@@ -5457,7 +5457,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let _farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let _resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -5927,7 +5927,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -5970,7 +5970,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Stake on node
|
||||
match farmer_service.stake_on_node(&user_email, &node_id, staking_options) {
|
||||
match resource_provider_service.stake_on_node(&user_email, &node_id, staking_options) {
|
||||
Ok(()) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -6010,7 +6010,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6030,7 +6030,7 @@ impl DashboardController {
|
||||
match action {
|
||||
"unstake" => {
|
||||
// Unstake from node
|
||||
match farmer_service.unstake_from_node(&user_email, &node_id) {
|
||||
match resource_provider_service.unstake_from_node(&user_email, &node_id) {
|
||||
Ok(returned_amount) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -6078,7 +6078,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Update node staking
|
||||
match farmer_service.update_node_staking(&user_email, &node_id, staking_options) {
|
||||
match resource_provider_service.update_node_staking(&user_email, &node_id, staking_options) {
|
||||
Ok(()) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -6120,7 +6120,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6130,7 +6130,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
let statistics = farmer_service.get_staking_statistics(&user_email);
|
||||
let statistics = resource_provider_service.get_staking_statistics(&user_email);
|
||||
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
@@ -6293,7 +6293,7 @@ impl DashboardController {
|
||||
.build())
|
||||
}
|
||||
|
||||
/// Refresh slice calculations for farmer
|
||||
/// Refresh slice calculations for resource_provider
|
||||
pub async fn refresh_slice_calculations(session: Session) -> Result<impl Responder> {
|
||||
let user_email = match session.get::<String>("user_email") {
|
||||
Ok(Some(email)) => email,
|
||||
@@ -6303,7 +6303,7 @@ impl DashboardController {
|
||||
})).build())
|
||||
};
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6313,7 +6313,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
match farmer_service.refresh_all_slice_calculations(&user_email) {
|
||||
match resource_provider_service.refresh_all_slice_calculations(&user_email) {
|
||||
Ok(_) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
@@ -6329,7 +6329,7 @@ impl DashboardController {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync farmer nodes with ThreeFold Grid
|
||||
/// Sync resource_provider nodes with ThreeFold Grid
|
||||
pub async fn sync_with_grid(session: Session) -> Result<impl Responder> {
|
||||
// Check authentication
|
||||
if let Err(response) = Self::check_authentication(&session) {
|
||||
@@ -6463,7 +6463,7 @@ impl DashboardController {
|
||||
|
||||
let node_id = path.into_inner();
|
||||
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6473,7 +6473,7 @@ impl DashboardController {
|
||||
}
|
||||
};
|
||||
|
||||
match farmer_service.get_node_slices(&user_email, node_id) {
|
||||
match resource_provider_service.get_node_slices(&user_email, node_id) {
|
||||
Ok(slices) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
@@ -6525,7 +6525,7 @@ impl DashboardController {
|
||||
}
|
||||
|
||||
// Initialize services
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6550,7 +6550,7 @@ impl DashboardController {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
for node_id in &node_ids {
|
||||
match farmer_service.fetch_and_validate_grid_node(*node_id).await {
|
||||
match resource_provider_service.fetch_and_validate_grid_node(*node_id).await {
|
||||
Ok(node_data) => {
|
||||
// Calculate automatic slices
|
||||
let total_base_slices = slice_calculator.calculate_max_base_slices(&node_data.capacity);
|
||||
@@ -6709,8 +6709,8 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
// Initialize farmer service
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6722,7 +6722,7 @@ impl DashboardController {
|
||||
|
||||
// Add nodes with automatic slice management
|
||||
|
||||
match farmer_service.add_multiple_grid_nodes_with_automatic_slices(
|
||||
match resource_provider_service.add_multiple_grid_nodes_with_automatic_slices(
|
||||
&user_email,
|
||||
node_ids.clone(),
|
||||
base_slice_price,
|
||||
@@ -6759,7 +6759,7 @@ impl DashboardController {
|
||||
}
|
||||
}
|
||||
|
||||
/// API endpoint to refresh slice calculations for all farmer nodes
|
||||
/// API endpoint to refresh slice calculations for all resource_provider nodes
|
||||
pub async fn refresh_slice_calculations_api(session: Session) -> Result<impl Responder> {
|
||||
|
||||
let user_email = session.get::<String>("user_email")
|
||||
@@ -6773,8 +6773,8 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
// Initialize farmer service
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6785,7 +6785,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Refresh slice calculations for all nodes
|
||||
match farmer_service.refresh_all_slice_calculations_async(&user_email).await {
|
||||
match resource_provider_service.refresh_all_slice_calculations_async(&user_email).await {
|
||||
Ok(updated_nodes) => {
|
||||
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
@@ -6817,8 +6817,8 @@ impl DashboardController {
|
||||
})).build());
|
||||
}
|
||||
|
||||
// Initialize farmer service
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6829,7 +6829,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Sync all nodes with grid
|
||||
match farmer_service.sync_all_nodes_with_grid_async(&user_email).await {
|
||||
match resource_provider_service.sync_all_nodes_with_grid_async(&user_email).await {
|
||||
Ok(synced_nodes) => {
|
||||
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
@@ -6863,8 +6863,8 @@ impl DashboardController {
|
||||
|
||||
let node_id = path.into_inner();
|
||||
|
||||
// Initialize farmer service
|
||||
let farmer_service = match crate::services::farmer::FarmerService::builder().build() {
|
||||
// Initialize resource_provider service
|
||||
let resource_provider_service = match crate::services::resource_provider::ResourceProviderService::builder().build() {
|
||||
Ok(service) => service,
|
||||
Err(e) => {
|
||||
return Ok(ResponseBuilder::internal_error().json(serde_json::json!({
|
||||
@@ -6875,7 +6875,7 @@ impl DashboardController {
|
||||
};
|
||||
|
||||
// Get node slice details
|
||||
match farmer_service.get_node_slice_details(&user_email, &node_id) {
|
||||
match resource_provider_service.get_node_slice_details(&user_email, &node_id) {
|
||||
Ok(slice_details) => {
|
||||
Ok(ResponseBuilder::ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
|
@@ -13,7 +13,7 @@ use chrono::Utc;
|
||||
/// Form data for slice rental requests
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SliceRentalForm {
|
||||
pub farmer_email: String,
|
||||
pub resource_provider_email: String,
|
||||
pub node_id: String,
|
||||
pub combination_id: String,
|
||||
pub quantity: u32,
|
||||
@@ -377,7 +377,7 @@ impl MarketplaceController {
|
||||
render_template(&tmpl, "marketplace/compute_resources.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the Mycelium Nodes marketplace page with REAL farmer nodes from database
|
||||
/// Renders the Mycelium Nodes marketplace page with REAL resource_provider nodes from database
|
||||
pub async fn mycelium_nodes(tmpl: web::Data<Tera>, session: Session, query: web::Query<std::collections::HashMap<String, String>>) -> Result<impl Responder> {
|
||||
// Build services using established builder pattern
|
||||
let currency_service = CurrencyService::builder()
|
||||
@@ -411,7 +411,7 @@ impl MarketplaceController {
|
||||
.unwrap_or(0);
|
||||
let page_size = 12;
|
||||
|
||||
// Get all real farmer nodes as marketplace products
|
||||
// Get all real resource_provider nodes as marketplace products
|
||||
let all_node_products = node_marketplace_service.get_all_marketplace_nodes();
|
||||
|
||||
// Clone query for reuse
|
||||
@@ -933,7 +933,7 @@ impl MarketplaceController {
|
||||
pub async fn show_slice_rental_form(
|
||||
tmpl: web::Data<Tera>,
|
||||
session: Session,
|
||||
path: web::Path<(String, String, String)> // farmer_email, node_id, combination_id
|
||||
path: web::Path<(String, String, String)> // resource_provider_email, node_id, combination_id
|
||||
) -> Result<impl Responder> {
|
||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||
.active_page("marketplace")
|
||||
@@ -951,7 +951,7 @@ impl MarketplaceController {
|
||||
}
|
||||
}
|
||||
|
||||
let (farmer_email, node_id, combination_id) = path.into_inner();
|
||||
let (resource_provider_email, node_id, combination_id) = path.into_inner();
|
||||
|
||||
// Get slice details for the form
|
||||
let node_marketplace_service = NodeMarketplaceService::builder()
|
||||
@@ -963,12 +963,12 @@ impl MarketplaceController {
|
||||
// Find the specific slice combination by checking product attributes
|
||||
if let Some(slice_product) = slice_combinations.iter().find(|p| {
|
||||
// Check if this product matches the requested slice
|
||||
if let (Some(farmer_attr), Some(node_attr), Some(combo_attr)) = (
|
||||
p.attributes.get("farmer_email"),
|
||||
if let (Some(resource_provider_attr), Some(node_attr), Some(combo_attr)) = (
|
||||
p.attributes.get("resource_provider_email"),
|
||||
p.attributes.get("node_id"),
|
||||
p.attributes.get("combination_id")
|
||||
) {
|
||||
farmer_attr.value.as_str() == Some(&farmer_email) &&
|
||||
resource_provider_attr.value.as_str() == Some(&resource_provider_email) &&
|
||||
node_attr.value.as_str() == Some(&node_id) &&
|
||||
combo_attr.value.as_str() == Some(&combination_id)
|
||||
} else {
|
||||
@@ -998,11 +998,11 @@ impl MarketplaceController {
|
||||
|
||||
slice_info.insert("price_per_hour", serde_json::Value::String(slice_product.base_price.to_string()));
|
||||
slice_info.insert("node_id", serde_json::Value::String(node_id.clone()));
|
||||
slice_info.insert("farmer_email", serde_json::Value::String(farmer_email.clone()));
|
||||
slice_info.insert("resource_provider_email", serde_json::Value::String(resource_provider_email.clone()));
|
||||
slice_info.insert("combination_id", serde_json::Value::String(combination_id.clone()));
|
||||
|
||||
ctx.insert("slice", &slice_info);
|
||||
ctx.insert("farmer_email", &farmer_email);
|
||||
ctx.insert("resource_provider_email", &resource_provider_email);
|
||||
ctx.insert("node_id", &node_id);
|
||||
ctx.insert("combination_id", &combination_id);
|
||||
}
|
||||
@@ -1109,7 +1109,7 @@ impl MarketplaceController {
|
||||
// Attempt to rent the slice with deployment options
|
||||
match slice_rental_service.rent_slice_combination_with_deployment(
|
||||
&user_email,
|
||||
&form.farmer_email,
|
||||
&form.resource_provider_email,
|
||||
&form.node_id,
|
||||
&form.combination_id,
|
||||
form.quantity,
|
||||
@@ -1134,7 +1134,7 @@ impl MarketplaceController {
|
||||
meta.insert("deployment_type".to_string(), serde_json::Value::String(form.deployment_type.clone()));
|
||||
meta.insert("deployment_name".to_string(), serde_json::Value::String(deployment_name.clone()));
|
||||
meta.insert("quantity".to_string(), serde_json::Value::Number(serde_json::Number::from(form.quantity)));
|
||||
meta.insert("farmer_email".to_string(), serde_json::Value::String(form.farmer_email.clone()));
|
||||
meta.insert("resource_provider_email".to_string(), serde_json::Value::String(form.resource_provider_email.clone()));
|
||||
if form.deployment_type == "kubernetes" {
|
||||
meta.insert("k8s_masters".to_string(), serde_json::Value::Number(serde_json::Number::from(form.k8s_masters.unwrap_or(1))));
|
||||
meta.insert("k8s_workers".to_string(), serde_json::Value::Number(serde_json::Number::from(form.k8s_workers.unwrap_or(1))));
|
||||
@@ -1206,7 +1206,7 @@ impl MarketplaceController {
|
||||
// Attempt to rent the slice with deployment options
|
||||
match slice_rental_service.rent_slice_combination_with_deployment(
|
||||
&user_email,
|
||||
&form.farmer_email,
|
||||
&form.resource_provider_email,
|
||||
&form.node_id,
|
||||
&form.combination_id,
|
||||
form.quantity,
|
||||
@@ -1231,7 +1231,7 @@ impl MarketplaceController {
|
||||
meta.insert("deployment_type".to_string(), serde_json::Value::String(form.deployment_type.clone()));
|
||||
meta.insert("deployment_name".to_string(), serde_json::Value::String(form.deployment_name.clone()));
|
||||
meta.insert("quantity".to_string(), serde_json::Value::Number(serde_json::Number::from(form.quantity)));
|
||||
meta.insert("farmer_email".to_string(), serde_json::Value::String(form.farmer_email.clone()));
|
||||
meta.insert("resource_provider_email".to_string(), serde_json::Value::String(form.resource_provider_email.clone()));
|
||||
serde_json::Value::Object(meta.into_iter().collect())
|
||||
}),
|
||||
category: "slice_rental".to_string(),
|
||||
@@ -1270,7 +1270,7 @@ impl MarketplaceController {
|
||||
/// Request structure for slice rental with deployment options
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct SliceRentalRequest {
|
||||
pub farmer_email: String,
|
||||
pub resource_provider_email: String,
|
||||
pub node_id: String,
|
||||
pub combination_id: String,
|
||||
pub quantity: u32,
|
||||
@@ -1503,7 +1503,7 @@ fn reconstruct_service_from_json(service_value: &serde_json::Value) -> Result<cr
|
||||
// Attempt to rent the slice combination
|
||||
match slice_rental_service.rent_slice_combination(
|
||||
&user_email,
|
||||
&form.farmer_email,
|
||||
&form.resource_provider_email,
|
||||
&form.node_id,
|
||||
&form.combination_id,
|
||||
form.quantity,
|
||||
@@ -1602,7 +1602,7 @@ fn reconstruct_service_from_json(service_value: &serde_json::Value) -> Result<cr
|
||||
// Create SliceAssignmentRequest from the data
|
||||
let assignment_request_obj = SliceAssignmentRequest {
|
||||
user_email: user_email.clone(),
|
||||
farmer_email: assignment_request.get("farmer_email")
|
||||
resource_provider_email: assignment_request.get("resource_provider_email")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("unknown@example.com")
|
||||
.to_string(),
|
||||
|
@@ -88,8 +88,8 @@ impl PublicController {
|
||||
render_template(&tmpl, "legal/terms.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the farmers terms page
|
||||
pub async fn terms_farmers(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
/// Renders the resource providers terms page
|
||||
pub async fn terms_resource_providers(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
let mut ctx = crate::models::builders::ContextBuilder::new()
|
||||
.build();
|
||||
ctx.insert("active_page", "terms");
|
||||
@@ -105,7 +105,7 @@ impl PublicController {
|
||||
}
|
||||
}
|
||||
|
||||
render_template(&tmpl, "legal/terms-farmers.html", &ctx)
|
||||
render_template(&tmpl, "legal/terms-resource_providers.html", &ctx)
|
||||
}
|
||||
|
||||
/// Renders the service providers terms page
|
||||
|
@@ -173,7 +173,7 @@ impl RentalController {
|
||||
rental_id: rental_id.clone(),
|
||||
slice_combination_id: format!("combo-{}", rental_id),
|
||||
node_id: "node-placeholder".to_string(), // TODO: Get from product
|
||||
farmer_email: "farmer@example.com".to_string(), // TODO: Get from product
|
||||
resource_provider_email: "resource_provider@example.com".to_string(), // TODO: Get from product
|
||||
slice_allocation: crate::services::slice_calculator::SliceAllocation {
|
||||
allocation_id: format!("alloc-{}", rental_id),
|
||||
slice_combination_id: format!("combo-{}", rental_id),
|
||||
|
@@ -33,5 +33,5 @@ pub mod utils;
|
||||
|
||||
// Re-export commonly used types
|
||||
pub use models::user::{User, NodeStakingOptions, FarmNode};
|
||||
pub use services::farmer::FarmerService;
|
||||
pub use services::resource_provider::ResourceProviderService;
|
||||
pub use services::user_persistence::UserPersistence;
|
||||
|
@@ -1234,11 +1234,11 @@ impl SessionDataBuilder {
|
||||
|
||||
// MockDataBuilder removed - using persistent data only
|
||||
// =============================================================================
|
||||
// FARMER DATA BUILDER
|
||||
// RESOURCE_PROVIDER DATA BUILDER
|
||||
// =============================================================================
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FarmerDataBuilder {
|
||||
pub struct ResourceProviderDataBuilder {
|
||||
total_nodes: Option<i32>,
|
||||
online_nodes: Option<i32>,
|
||||
total_capacity: Option<crate::models::user::NodeCapacity>,
|
||||
@@ -1251,7 +1251,7 @@ pub struct FarmerDataBuilder {
|
||||
active_slices: Option<i32>,
|
||||
}
|
||||
|
||||
impl FarmerDataBuilder {
|
||||
impl ResourceProviderDataBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
@@ -1373,8 +1373,8 @@ impl FarmerDataBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<crate::models::user::FarmerData, String> {
|
||||
Ok(crate::models::user::FarmerData {
|
||||
pub fn build(self) -> Result<crate::models::user::ResourceProviderData, String> {
|
||||
Ok(crate::models::user::ResourceProviderData {
|
||||
total_nodes: self.total_nodes.unwrap_or(0),
|
||||
online_nodes: self.online_nodes.unwrap_or(0),
|
||||
total_capacity: self.total_capacity.unwrap_or(crate::models::user::NodeCapacity {
|
||||
@@ -1445,8 +1445,8 @@ impl FarmerDataBuilder {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SliceProductBuilder {
|
||||
farmer_id: Option<String>,
|
||||
farmer_name: Option<String>,
|
||||
resource_provider_id: Option<String>,
|
||||
resource_provider_name: Option<String>,
|
||||
slice_name: Option<String>,
|
||||
cpu_cores: Option<i32>,
|
||||
memory_gb: Option<i32>,
|
||||
@@ -1464,13 +1464,13 @@ impl SliceProductBuilder {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn farmer_id(mut self, farmer_id: impl Into<String>) -> Self {
|
||||
self.farmer_id = Some(farmer_id.into());
|
||||
pub fn resource_provider_id(mut self, resource_provider_id: impl Into<String>) -> Self {
|
||||
self.resource_provider_id = Some(resource_provider_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn farmer_name(mut self, farmer_name: impl Into<String>) -> Self {
|
||||
self.farmer_name = Some(farmer_name.into());
|
||||
pub fn resource_provider_name(mut self, resource_provider_name: impl Into<String>) -> Self {
|
||||
self.resource_provider_name = Some(resource_provider_name.into());
|
||||
self
|
||||
}
|
||||
|
||||
@@ -1525,8 +1525,8 @@ impl SliceProductBuilder {
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<crate::models::product::Product, String> {
|
||||
let farmer_id = self.farmer_id.ok_or("farmer_id is required")?;
|
||||
let farmer_name = self.farmer_name.ok_or("farmer_name is required")?;
|
||||
let resource_provider_id = self.resource_provider_id.ok_or("resource_provider_id is required")?;
|
||||
let resource_provider_name = self.resource_provider_name.ok_or("resource_provider_name is required")?;
|
||||
let slice_name = self.slice_name.ok_or("slice_name is required")?;
|
||||
let cpu_cores = self.cpu_cores.ok_or("cpu_cores is required")?;
|
||||
let memory_gb = self.memory_gb.ok_or("memory_gb is required")?;
|
||||
@@ -1552,8 +1552,8 @@ impl SliceProductBuilder {
|
||||
};
|
||||
|
||||
Ok(crate::models::product::Product::create_slice_product(
|
||||
farmer_id,
|
||||
farmer_name,
|
||||
resource_provider_id,
|
||||
resource_provider_name,
|
||||
slice_name,
|
||||
slice_config,
|
||||
price_per_hour,
|
||||
@@ -2081,7 +2081,7 @@ impl NodeRentalBuilder {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FarmerRentalEarningBuilder {
|
||||
pub struct ResourceProviderRentalEarningBuilder {
|
||||
id: Option<String>,
|
||||
node_id: Option<String>,
|
||||
rental_id: Option<String>,
|
||||
@@ -2093,7 +2093,7 @@ pub struct FarmerRentalEarningBuilder {
|
||||
payment_status: Option<crate::models::user::PaymentStatus>,
|
||||
}
|
||||
|
||||
impl FarmerRentalEarningBuilder {
|
||||
impl ResourceProviderRentalEarningBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
@@ -2143,10 +2143,10 @@ impl FarmerRentalEarningBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<crate::models::user::FarmerRentalEarning, String> {
|
||||
pub fn build(self) -> Result<crate::models::user::ResourceProviderRentalEarning, String> {
|
||||
let id = self.id.unwrap_or_else(|| format!("earning_{}", uuid::Uuid::new_v4()));
|
||||
|
||||
Ok(crate::models::user::FarmerRentalEarning {
|
||||
Ok(crate::models::user::ResourceProviderRentalEarning {
|
||||
id,
|
||||
node_id: self.node_id.ok_or("node_id is required")?,
|
||||
rental_id: self.rental_id.ok_or("rental_id is required")?,
|
||||
@@ -2469,8 +2469,8 @@ impl NodeCreationDataBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<crate::services::farmer::NodeCreationData, String> {
|
||||
Ok(crate::services::farmer::NodeCreationData {
|
||||
pub fn build(self) -> Result<crate::services::resource_provider::NodeCreationData, String> {
|
||||
Ok(crate::services::resource_provider::NodeCreationData {
|
||||
name: self.name.ok_or("name is required")?,
|
||||
location: self.location.ok_or("location is required")?,
|
||||
cpu_cores: self.cpu_cores.unwrap_or(4),
|
||||
|
@@ -305,10 +305,10 @@ pub enum SliceType {
|
||||
}
|
||||
|
||||
impl Product {
|
||||
/// Create a slice product from farmer configuration
|
||||
/// Create a slice product from resource_provider configuration
|
||||
pub fn create_slice_product(
|
||||
farmer_id: String,
|
||||
farmer_name: String,
|
||||
resource_provider_id: String,
|
||||
resource_provider_name: String,
|
||||
slice_name: String,
|
||||
slice_config: SliceConfiguration,
|
||||
price_per_hour: Decimal,
|
||||
@@ -322,8 +322,8 @@ impl Product {
|
||||
slice_config.cpu_cores, slice_config.memory_gb, slice_config.storage_gb),
|
||||
price_per_hour,
|
||||
"USD".to_string(),
|
||||
farmer_id,
|
||||
farmer_name,
|
||||
resource_provider_id,
|
||||
resource_provider_name,
|
||||
);
|
||||
|
||||
// Add slice-specific attributes
|
||||
@@ -448,8 +448,8 @@ impl Product {
|
||||
/// Create a full node product from a FarmNode
|
||||
pub fn create_full_node_product(
|
||||
node: &crate::models::user::FarmNode,
|
||||
farmer_email: &str,
|
||||
farmer_name: &str,
|
||||
resource_provider_email: &str,
|
||||
resource_provider_name: &str,
|
||||
) -> Self {
|
||||
let mut product = Product {
|
||||
id: format!("fullnode_{}", node.id),
|
||||
@@ -469,8 +469,8 @@ impl Product {
|
||||
.unwrap_or_else(|| Decimal::from(200)), // Default price
|
||||
base_currency: "USD".to_string(),
|
||||
attributes: HashMap::new(),
|
||||
provider_id: farmer_email.to_string(),
|
||||
provider_name: farmer_name.to_string(),
|
||||
provider_id: resource_provider_email.to_string(),
|
||||
provider_name: resource_provider_name.to_string(),
|
||||
availability: match node.availability_status {
|
||||
crate::models::user::NodeAvailabilityStatus::Available => ProductAvailability::Available,
|
||||
crate::models::user::NodeAvailabilityStatus::PartiallyRented => ProductAvailability::Limited,
|
||||
|
@@ -146,7 +146,7 @@ pub struct RegionDeployments {
|
||||
pub gateways: i32,
|
||||
}
|
||||
|
||||
/// Node information for farmer dashboard
|
||||
/// Node information for resource_provider dashboard
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NodeInfo {
|
||||
pub id: String,
|
||||
@@ -200,14 +200,14 @@ impl std::fmt::Display for NodeStatus {
|
||||
}
|
||||
}
|
||||
|
||||
/// Default maintenance window for farmer settings
|
||||
/// Default maintenance window for resource_provider settings
|
||||
pub fn default_maintenance_window() -> String {
|
||||
"02:00-04:00 UTC".to_string()
|
||||
}
|
||||
|
||||
/// Farmer configuration settings
|
||||
/// ResourceProvider configuration settings
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FarmerSettings {
|
||||
pub struct ResourceProviderSettings {
|
||||
pub auto_accept_reserved_slices: bool,
|
||||
pub maintenance_window: String, // e.g., "02:00-04:00 UTC"
|
||||
pub notification_email: Option<String>,
|
||||
@@ -229,7 +229,7 @@ pub struct FarmerSettings {
|
||||
pub preferred_regions: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for FarmerSettings {
|
||||
impl Default for ResourceProviderSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
auto_accept_reserved_slices: true,
|
||||
@@ -324,7 +324,7 @@ impl Default for LiquidityPoolConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FarmerData {
|
||||
impl Default for ResourceProviderData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
total_nodes: 0,
|
||||
@@ -761,9 +761,9 @@ pub struct QuickAction {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
/// Farmer-specific data
|
||||
/// ResourceProvider-specific data
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FarmerData {
|
||||
pub struct ResourceProviderData {
|
||||
pub total_nodes: i32,
|
||||
pub active_nodes: i32,
|
||||
pub total_monthly_earnings_usd: i32,
|
||||
@@ -1224,7 +1224,7 @@ where
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
/// Node group for farmer organization
|
||||
/// Node group for resource_provider organization
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NodeGroup {
|
||||
pub id: String,
|
||||
@@ -1358,7 +1358,7 @@ pub struct NodeCapacity {
|
||||
pub ram_gb: i32,
|
||||
}
|
||||
|
||||
/// Farmer node information
|
||||
/// ResourceProvider node information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FarmNode {
|
||||
pub id: String,
|
||||
@@ -1418,7 +1418,7 @@ pub struct FarmNode {
|
||||
pub health_score: f32,
|
||||
}
|
||||
|
||||
/// Earnings record for farmer data
|
||||
/// Earnings record for resource_provider data
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EarningsRecord {
|
||||
pub date: String,
|
||||
@@ -1428,7 +1428,7 @@ pub struct EarningsRecord {
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
/// Group statistics for farmer dashboard
|
||||
/// Group statistics for resource_provider dashboard
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GroupStatistics {
|
||||
pub group_name: String,
|
||||
@@ -1517,7 +1517,7 @@ pub struct GridNodeData {
|
||||
|
||||
/// Additional missing user model types
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FarmerRentalEarning {
|
||||
pub struct ResourceProviderRentalEarning {
|
||||
pub date: String,
|
||||
pub amount: Decimal,
|
||||
pub rental_id: String,
|
||||
|
@@ -52,7 +52,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
.route("/marketplace/services", web::get().to(MarketplaceController::services))
|
||||
.route("/marketplace/statistics", web::get().to(MarketplaceController::statistics))
|
||||
// Slice rental routes
|
||||
.route("/marketplace/slice/rent/{farmer_email}/{node_id}/{combination_id}", web::get().to(MarketplaceController::show_slice_rental_form))
|
||||
.route("/marketplace/slice/rent/{resource_provider_email}/{node_id}/{combination_id}", web::get().to(MarketplaceController::show_slice_rental_form))
|
||||
.route("/marketplace/slice/rent", web::post().to(MarketplaceController::process_slice_rental))
|
||||
// .route("/marketplace/rent-slice", web::post().to(MarketplaceController::rent_slice)) // Legacy route [DISABLED]
|
||||
// Product routes
|
||||
@@ -107,7 +107,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
.route("/dashboard/slice-rentals/{id}/manage", web::post().to(DashboardController::manage_slice_rental_deployment))
|
||||
.route("/dashboard/slice-rentals/{id}", web::delete().to(DashboardController::cancel_slice_rental))
|
||||
.route("/dashboard/user/slice-rentals/{id}", web::post().to(DashboardController::manage_slice_rental))
|
||||
.route("/dashboard/farmer-data", web::get().to(DashboardController::farmer_data_api))
|
||||
.route("/dashboard/resource_provider-data", web::get().to(DashboardController::resource_provider_data_api))
|
||||
.route("/dashboard/app-provider-data", web::get().to(DashboardController::app_provider_data_api))
|
||||
.route("/dashboard/slice-products", web::get().to(DashboardController::get_slice_products))
|
||||
.route("/dashboard/slice-products", web::post().to(DashboardController::create_slice_product))
|
||||
@@ -116,19 +116,19 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
.route("/dashboard/slice-details/{id}", web::get().to(DashboardController::get_slice_details))
|
||||
.route("/dashboard/slice-configuration/{id}", web::put().to(DashboardController::update_slice_configuration))
|
||||
.route("/dashboard/service-provider-data", web::get().to(DashboardController::service_provider_data_api))
|
||||
// Farmer management API routes
|
||||
.route("/dashboard/farm-nodes", web::post().to(DashboardController::add_farm_node))
|
||||
.route("/dashboard/farm-nodes-enhanced", web::post().to(DashboardController::add_farm_node_enhanced))
|
||||
.route("/dashboard/farm-nodes/{id}", web::get().to(DashboardController::get_node_details))
|
||||
.route("/dashboard/farm-nodes/{id}", web::put().to(DashboardController::update_node_comprehensive))
|
||||
.route("/dashboard/farm-nodes/{id}/status", web::put().to(DashboardController::update_node_status))
|
||||
// Farmer slice management API routes
|
||||
.route("/dashboard/farmer/slice-calculations/refresh", web::post().to(DashboardController::refresh_slice_calculations))
|
||||
.route("/dashboard/farmer/grid-sync", web::post().to(DashboardController::sync_with_grid))
|
||||
.route("/dashboard/farmer/nodes/{id}/slices", web::get().to(DashboardController::get_node_slices))
|
||||
.route("/dashboard/farmer/slice-statistics", web::get().to(DashboardController::get_slice_statistics))
|
||||
.route("/dashboard/farm-nodes/{id}", web::delete().to(DashboardController::delete_node))
|
||||
.route("/dashboard/farm-nodes/{id}/configuration", web::put().to(DashboardController::update_node_configuration))
|
||||
// Resource provider management API routes
|
||||
.route("/dashboard/resource_provider-nodes", web::post().to(DashboardController::add_resource_provider_node))
|
||||
.route("/dashboard/resource_provider-nodes-enhanced", web::post().to(DashboardController::add_resource_provider_node_enhanced))
|
||||
.route("/dashboard/resource_provider-nodes/{id}", web::get().to(DashboardController::get_node_details))
|
||||
.route("/dashboard/resource_provider-nodes/{id}", web::put().to(DashboardController::update_node_comprehensive))
|
||||
.route("/dashboard/resource_provider-nodes/{id}/status", web::put().to(DashboardController::update_node_status))
|
||||
// Resource provider slice management API routes
|
||||
.route("/dashboard/resource_provider/slice-calculations/refresh", web::post().to(DashboardController::refresh_slice_calculations))
|
||||
.route("/dashboard/resource_provider/grid-sync", web::post().to(DashboardController::sync_with_grid))
|
||||
.route("/dashboard/resource_provider/nodes/{id}/slices", web::get().to(DashboardController::get_node_slices))
|
||||
.route("/dashboard/resource_provider/slice-statistics", web::get().to(DashboardController::get_slice_statistics))
|
||||
.route("/dashboard/resource_provider-nodes/{id}", web::delete().to(DashboardController::delete_node))
|
||||
.route("/dashboard/resource_provider-nodes/{id}/configuration", web::put().to(DashboardController::update_node_configuration))
|
||||
.route("/dashboard/default-slice-formats", web::get().to(DashboardController::get_default_slice_formats))
|
||||
.route("/dashboard/default-slice-details/{id}", web::get().to(DashboardController::get_default_slice_details))
|
||||
.route("/dashboard/default-slice-customization/{id}", web::put().to(DashboardController::save_default_slice_customization))
|
||||
@@ -148,8 +148,8 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
.route("/dashboard/node-groups/{id}", web::delete().to(DashboardController::delete_custom_node_group))
|
||||
.route("/dashboard/nodes/assign-group", web::post().to(DashboardController::assign_node_to_group))
|
||||
// Node staking API routes
|
||||
.route("/dashboard/farm-nodes/{id}/stake", web::post().to(DashboardController::stake_on_node))
|
||||
.route("/dashboard/farm-nodes/{id}/staking", web::put().to(DashboardController::update_node_staking))
|
||||
.route("/dashboard/resource_provider-nodes/{id}/stake", web::post().to(DashboardController::stake_on_node))
|
||||
.route("/dashboard/resource_provider-nodes/{id}/staking", web::put().to(DashboardController::update_node_staking))
|
||||
.route("/dashboard/staking/statistics", web::get().to(DashboardController::get_staking_statistics))
|
||||
// Service management API routes
|
||||
.route("/dashboard/services", web::get().to(DashboardController::get_user_services))
|
||||
@@ -260,7 +260,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
.wrap(JwtAuth) // Apply authentication middleware to all dashboard routes
|
||||
.route("", web::get().to(DashboardController::index))
|
||||
.route("/user", web::get().to(DashboardController::user_section))
|
||||
.route("/farmer", web::get().to(DashboardController::farmer_section))
|
||||
.route("/resource_provider", web::get().to(DashboardController::resource_provider_section))
|
||||
.route("/app-provider", web::get().to(DashboardController::app_provider_section))
|
||||
.route("/service-provider", web::get().to(DashboardController::service_provider_section))
|
||||
|
||||
@@ -282,7 +282,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
// Public information routes (legal, changelog, roadmap)
|
||||
.route("/privacy", web::get().to(PublicController::privacy))
|
||||
.route("/terms", web::get().to(PublicController::terms))
|
||||
.route("/terms/farmers", web::get().to(PublicController::terms_farmers))
|
||||
.route("/terms/resource_providers", web::get().to(PublicController::terms_resource_providers))
|
||||
.route("/terms/service-providers", web::get().to(PublicController::terms_service_providers))
|
||||
.route("/terms/solution-providers", web::get().to(PublicController::terms_solution_providers))
|
||||
.route("/terms/users", web::get().to(PublicController::terms_users))
|
||||
|
@@ -2,7 +2,7 @@
|
||||
pub mod auto_topup;
|
||||
pub mod currency;
|
||||
pub mod factory;
|
||||
pub mod farmer;
|
||||
pub mod resource_provider;
|
||||
pub mod grid;
|
||||
pub mod instant_purchase;
|
||||
pub mod navbar;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
//! Node marketplace service for aggregating farmer nodes into marketplace products
|
||||
//! Node marketplace service for aggregating resource_provider nodes into marketplace products
|
||||
//! Follows the established builder pattern for consistent API design
|
||||
|
||||
use crate::models::user::FarmNode;
|
||||
@@ -11,7 +11,7 @@ use rust_decimal::prelude::ToPrimitive;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Service for converting farmer nodes to marketplace products
|
||||
/// Service for converting resource_provider nodes to marketplace products
|
||||
#[derive(Clone)]
|
||||
pub struct NodeMarketplaceService {
|
||||
currency_service: CurrencyService,
|
||||
@@ -89,7 +89,7 @@ impl NodeMarketplaceService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all farmer nodes as marketplace products
|
||||
/// Get all resource_provider nodes as marketplace products
|
||||
pub fn get_all_marketplace_nodes(&self) -> Vec<Product> {
|
||||
let mut all_products = Vec::new();
|
||||
|
||||
@@ -125,16 +125,16 @@ impl NodeMarketplaceService {
|
||||
}
|
||||
|
||||
/// Convert FarmNode to Product using builder pattern
|
||||
pub fn convert_node_to_product(&self, node: &FarmNode, farmer_email: &str) -> Result<Product, String> {
|
||||
pub fn convert_node_to_product(&self, node: &FarmNode, resource_provider_email: &str) -> Result<Product, String> {
|
||||
// Calculate price based on node capacity
|
||||
let hourly_price = self.calculate_node_price(node)?;
|
||||
|
||||
// Create product attributes with node specifications
|
||||
let mut attributes = HashMap::new();
|
||||
|
||||
attributes.insert("farmer_email".to_string(), crate::models::product::ProductAttribute {
|
||||
key: "farmer_email".to_string(),
|
||||
value: serde_json::Value::String(farmer_email.to_string()),
|
||||
attributes.insert("resource_provider_email".to_string(), crate::models::product::ProductAttribute {
|
||||
key: "resource_provider_email".to_string(),
|
||||
value: serde_json::Value::String(resource_provider_email.to_string()),
|
||||
attribute_type: crate::models::product::AttributeType::Text,
|
||||
is_searchable: true,
|
||||
is_filterable: true,
|
||||
@@ -200,8 +200,8 @@ impl NodeMarketplaceService {
|
||||
display_order: Some(6),
|
||||
});
|
||||
|
||||
// Get farmer display name
|
||||
let farmer_display_name = self.get_farmer_display_name(farmer_email);
|
||||
// Get resource_provider display name
|
||||
let resource_provider_display_name = self.get_resource_provider_display_name(resource_provider_email);
|
||||
|
||||
// Create metadata with location
|
||||
let metadata = crate::models::product::ProductMetadata {
|
||||
@@ -215,7 +215,7 @@ impl NodeMarketplaceService {
|
||||
// Use Product builder pattern with add_attribute for each attribute
|
||||
let mut builder = crate::models::product::Product::builder()
|
||||
.id(format!("node_{}", node.id))
|
||||
.name(format!("{} - {}", node.name, farmer_display_name))
|
||||
.name(format!("{} - {}", node.name, resource_provider_display_name))
|
||||
.description(format!("Mycelium Node with {} CPU cores, {} GB RAM, {} GB storage in {}. Uptime: {:.1}%, Health Score: {:.1}",
|
||||
node.capacity.cpu_cores,
|
||||
node.capacity.memory_gb,
|
||||
@@ -226,8 +226,8 @@ impl NodeMarketplaceService {
|
||||
.base_price(hourly_price)
|
||||
.base_currency("USD".to_string())
|
||||
.category_id("hardware".to_string())
|
||||
.provider_id(farmer_email.to_string())
|
||||
.provider_name(farmer_display_name)
|
||||
.provider_id(resource_provider_email.to_string())
|
||||
.provider_name(resource_provider_display_name)
|
||||
.metadata(metadata)
|
||||
.availability(if self.is_node_online(node) {
|
||||
crate::models::product::ProductAvailability::Available
|
||||
@@ -276,17 +276,17 @@ impl NodeMarketplaceService {
|
||||
format!("{}", node.status) == "Online"
|
||||
}
|
||||
|
||||
/// Get farmer display name from email
|
||||
fn get_farmer_display_name(&self, farmer_email: &str) -> String {
|
||||
/// Get resource_provider display name from email
|
||||
fn get_resource_provider_display_name(&self, resource_provider_email: &str) -> String {
|
||||
// Try to get actual name from persistent data
|
||||
if let Some(user_data) = UserPersistence::load_user_data(farmer_email) {
|
||||
if let Some(user_data) = UserPersistence::load_user_data(resource_provider_email) {
|
||||
if let Some(name) = user_data.name {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to email username
|
||||
farmer_email.split('@').next().unwrap_or("Farmer").to_string()
|
||||
resource_provider_email.split('@').next().unwrap_or("ResourceProvider").to_string()
|
||||
}
|
||||
|
||||
/// Apply marketplace filters to node products
|
||||
@@ -438,7 +438,7 @@ impl NodeMarketplaceService {
|
||||
let mut total_cpu_cores = 0u32;
|
||||
let mut total_memory_gb = 0u32;
|
||||
let mut total_storage_gb = 0u32;
|
||||
let mut unique_farmers = std::collections::HashSet::new();
|
||||
let mut unique_resource_providers = std::collections::HashSet::new();
|
||||
let mut unique_locations = std::collections::HashSet::new();
|
||||
|
||||
for product in &all_slices {
|
||||
@@ -456,8 +456,8 @@ impl NodeMarketplaceService {
|
||||
total_storage_gb += (storage * quantity) as u32;
|
||||
}
|
||||
|
||||
if let Some(farmer) = product.attributes.get("farmer_email").and_then(|f| f.value.as_str()) {
|
||||
unique_farmers.insert(farmer.to_string());
|
||||
if let Some(resource_provider) = product.attributes.get("resource_provider_email").and_then(|f| f.value.as_str()) {
|
||||
unique_resource_providers.insert(resource_provider.to_string());
|
||||
}
|
||||
|
||||
if let Some(location) = &product.metadata.location {
|
||||
@@ -471,9 +471,9 @@ impl NodeMarketplaceService {
|
||||
"total_cpu_cores": total_cpu_cores,
|
||||
"total_memory_gb": total_memory_gb,
|
||||
"total_storage_gb": total_storage_gb,
|
||||
"unique_farmers": unique_farmers.len(),
|
||||
"unique_resource_providers": unique_resource_providers.len(),
|
||||
"unique_locations": unique_locations.len(),
|
||||
"farmers": unique_farmers.into_iter().collect::<Vec<_>>(),
|
||||
"resource_providers": unique_resource_providers.into_iter().collect::<Vec<_>>(),
|
||||
"locations": unique_locations.into_iter().collect::<Vec<_>>()
|
||||
})
|
||||
}
|
||||
@@ -531,7 +531,7 @@ impl NodeMarketplaceService {
|
||||
pub fn get_all_slice_combinations(&self) -> Vec<Product> {
|
||||
let mut all_slice_products = Vec::new();
|
||||
|
||||
// Read all user data files to find farmers with nodes
|
||||
// Read all user data files to find resource_providers with nodes
|
||||
if let Ok(entries) = std::fs::read_dir("./user_data") {
|
||||
for entry in entries.flatten() {
|
||||
if let Some(filename) = entry.file_name().to_str() {
|
||||
@@ -585,14 +585,14 @@ impl NodeMarketplaceService {
|
||||
&self,
|
||||
combination: &SliceCombination,
|
||||
_node: &FarmNode,
|
||||
farmer_email: &str
|
||||
resource_provider_email: &str
|
||||
) -> Result<Product, String> {
|
||||
let mut attributes = HashMap::new();
|
||||
|
||||
// Farmer information
|
||||
attributes.insert("farmer_email".to_string(), crate::models::product::ProductAttribute {
|
||||
key: "farmer_email".to_string(),
|
||||
value: serde_json::Value::String(farmer_email.to_string()),
|
||||
// ResourceProvider information
|
||||
attributes.insert("resource_provider_email".to_string(), crate::models::product::ProductAttribute {
|
||||
key: "resource_provider_email".to_string(),
|
||||
value: serde_json::Value::String(resource_provider_email.to_string()),
|
||||
attribute_type: crate::models::product::AttributeType::Text,
|
||||
is_searchable: true,
|
||||
is_filterable: true,
|
||||
@@ -701,15 +701,15 @@ impl NodeMarketplaceService {
|
||||
display_order: Some(10),
|
||||
});
|
||||
|
||||
// Get farmer display name
|
||||
let farmer_display_name = self.get_farmer_display_name(farmer_email);
|
||||
// Get resource_provider display name
|
||||
let resource_provider_display_name = self.get_resource_provider_display_name(resource_provider_email);
|
||||
|
||||
// Create metadata
|
||||
let metadata = crate::models::product::ProductMetadata {
|
||||
location: Some(combination.node_location.clone()),
|
||||
custom_fields: {
|
||||
let mut fields = std::collections::HashMap::new();
|
||||
fields.insert("provider".to_string(), serde_json::Value::String(farmer_display_name.clone()));
|
||||
fields.insert("provider".to_string(), serde_json::Value::String(resource_provider_display_name.clone()));
|
||||
fields.insert("certification".to_string(), serde_json::Value::String(combination.node_certification_type.clone()));
|
||||
fields.insert("created_at".to_string(), serde_json::Value::String(chrono::Utc::now().to_rfc3339()));
|
||||
fields.insert("updated_at".to_string(), serde_json::Value::String(chrono::Utc::now().to_rfc3339()));
|
||||
@@ -727,7 +727,7 @@ impl NodeMarketplaceService {
|
||||
// Build product using the builder pattern
|
||||
let mut product = crate::models::product::Product::builder()
|
||||
.id(format!("slice_{}_{}", combination.node_id, combination.id))
|
||||
.name(format!("{} Slice ({}x Base Unit)", farmer_display_name, combination.multiplier))
|
||||
.name(format!("{} Slice ({}x Base Unit)", resource_provider_display_name, combination.multiplier))
|
||||
.description(format!(
|
||||
"Compute slice with {} vCPU, {}GB RAM, {}GB storage from {} ({}% uptime)",
|
||||
combination.cpu_cores,
|
||||
@@ -739,8 +739,8 @@ impl NodeMarketplaceService {
|
||||
.category_id("compute_slices".to_string())
|
||||
.base_price(combination.price_per_hour)
|
||||
.base_currency("USD".to_string())
|
||||
.provider_id(farmer_email.to_string())
|
||||
.provider_name(farmer_display_name)
|
||||
.provider_id(resource_provider_email.to_string())
|
||||
.provider_name(resource_provider_display_name)
|
||||
.metadata(metadata)
|
||||
.build()
|
||||
.map_err(|e| format!("Failed to build slice product: {}", e))?;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
//! Node rental service for managing node rentals and farmer earnings
|
||||
//! Node rental service for managing node rentals and resource_provider earnings
|
||||
//! Follows the established builder pattern for consistent API design
|
||||
|
||||
use crate::models::user::{NodeRental, NodeRentalType, NodeRentalStatus, FarmerRentalEarning, PaymentStatus, NodeAvailabilityStatus};
|
||||
use crate::models::user::{NodeRental, NodeRentalType, NodeRentalStatus, ResourceProviderRentalEarning, PaymentStatus, NodeAvailabilityStatus};
|
||||
use crate::services::user_persistence::{UserPersistence, ProductRental};
|
||||
use rust_decimal::Decimal;
|
||||
use chrono::{Utc, Duration};
|
||||
@@ -65,7 +65,7 @@ impl NodeRentalService {
|
||||
duration_months: u32,
|
||||
rental_type: NodeRentalType,
|
||||
monthly_cost: Decimal,
|
||||
) -> Result<(NodeRental, FarmerRentalEarning), String> {
|
||||
) -> Result<(NodeRental, ResourceProviderRentalEarning), String> {
|
||||
// Extract node ID from product ID
|
||||
let node_id = if product_id.starts_with("fullnode_") {
|
||||
product_id.strip_prefix("fullnode_").unwrap_or(product_id)
|
||||
@@ -99,8 +99,8 @@ impl NodeRentalService {
|
||||
.payment_method("USD".to_string())
|
||||
.build()?;
|
||||
|
||||
// Create farmer earning record
|
||||
let farmer_earning = crate::models::builders::FarmerRentalEarningBuilder::new()
|
||||
// Create resource_provider earning record
|
||||
let resource_provider_earning = crate::models::builders::ResourceProviderRentalEarningBuilder::new()
|
||||
.node_id(node_id.to_string())
|
||||
.rental_id(rental.id.clone())
|
||||
.renter_email(renter_email.to_string())
|
||||
@@ -111,29 +111,29 @@ impl NodeRentalService {
|
||||
.payment_status(PaymentStatus::Completed)
|
||||
.build()?;
|
||||
|
||||
// Find the farmer who owns this node
|
||||
let farmer_email = self.find_node_owner(node_id)?;
|
||||
// Find the resource_provider who owns this node
|
||||
let resource_provider_email = self.find_node_owner(node_id)?;
|
||||
|
||||
// Save rental to renter's data
|
||||
self.save_rental_to_user(&rental, renter_email, product_id)?;
|
||||
|
||||
// Save earning to farmer's data
|
||||
self.save_earning_to_farmer(&farmer_earning, &farmer_email)?;
|
||||
// Save earning to resource_provider's data
|
||||
self.save_earning_to_resource_provider(&resource_provider_earning, &resource_provider_email)?;
|
||||
|
||||
// Update node availability status
|
||||
self.update_node_availability(node_id, &farmer_email)?;
|
||||
self.update_node_availability(node_id, &resource_provider_email)?;
|
||||
|
||||
Ok((rental, farmer_earning))
|
||||
Ok((rental, resource_provider_earning))
|
||||
}
|
||||
|
||||
/// Check for rental conflicts
|
||||
fn check_rental_conflicts(&self, node_id: &str, rental_type: &NodeRentalType) -> Result<(), String> {
|
||||
// Find the farmer who owns this node
|
||||
let farmer_email = self.find_node_owner(node_id)?;
|
||||
// Find the resource_provider who owns this node
|
||||
let resource_provider_email = self.find_node_owner(node_id)?;
|
||||
|
||||
if let Some(farmer_data) = UserPersistence::load_user_data(&farmer_email) {
|
||||
if let Some(resource_provider_data) = UserPersistence::load_user_data(&resource_provider_email) {
|
||||
// Check existing rentals for this node
|
||||
let existing_rentals: Vec<_> = farmer_data.node_rentals.iter()
|
||||
let existing_rentals: Vec<_> = resource_provider_data.node_rentals.iter()
|
||||
.filter(|r| r.node_id == node_id && r.is_active())
|
||||
.collect();
|
||||
|
||||
@@ -166,7 +166,7 @@ impl NodeRentalService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Find the farmer who owns a specific node
|
||||
/// Find the resource_provider who owns a specific node
|
||||
fn find_node_owner(&self, node_id: &str) -> Result<String, String> {
|
||||
// Scan all user files to find the node owner
|
||||
if let Ok(entries) = std::fs::read_dir("./user_data/") {
|
||||
@@ -226,31 +226,31 @@ impl NodeRentalService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Save earning record to farmer's persistent data
|
||||
fn save_earning_to_farmer(&self, earning: &FarmerRentalEarning, farmer_email: &str) -> Result<(), String> {
|
||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
||||
.unwrap_or_else(|| self.create_default_user_data(farmer_email));
|
||||
/// Save earning record to resource_provider's persistent data
|
||||
fn save_earning_to_resource_provider(&self, earning: &ResourceProviderRentalEarning, resource_provider_email: &str) -> Result<(), String> {
|
||||
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||
.unwrap_or_else(|| self.create_default_user_data(resource_provider_email));
|
||||
|
||||
// Add to farmer rental earnings
|
||||
farmer_data.farmer_rental_earnings.push(earning.clone());
|
||||
// Add to resource_provider rental earnings
|
||||
resource_provider_data.resource_provider_rental_earnings.push(earning.clone());
|
||||
|
||||
// Update wallet balance
|
||||
farmer_data.wallet_balance_usd += earning.amount;
|
||||
resource_provider_data.wallet_balance_usd += earning.amount;
|
||||
|
||||
UserPersistence::save_user_data(&farmer_data)
|
||||
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
|
||||
UserPersistence::save_user_data(&resource_provider_data)
|
||||
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update node availability status based on current rentals
|
||||
fn update_node_availability(&self, node_id: &str, farmer_email: &str) -> Result<(), String> {
|
||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
||||
.ok_or("Farmer data not found")?;
|
||||
fn update_node_availability(&self, node_id: &str, resource_provider_email: &str) -> Result<(), String> {
|
||||
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||
.ok_or("ResourceProvider data not found")?;
|
||||
|
||||
if let Some(node) = farmer_data.nodes.iter_mut().find(|n| n.id == node_id) {
|
||||
if let Some(node) = resource_provider_data.nodes.iter_mut().find(|n| n.id == node_id) {
|
||||
// Count active rentals for this node
|
||||
let active_rentals: Vec<_> = farmer_data.node_rentals.iter()
|
||||
let active_rentals: Vec<_> = resource_provider_data.node_rentals.iter()
|
||||
.filter(|r| r.node_id == node_id && r.is_active())
|
||||
.collect();
|
||||
|
||||
@@ -262,7 +262,7 @@ impl NodeRentalService {
|
||||
NodeAvailabilityStatus::PartiallyRented
|
||||
};
|
||||
|
||||
UserPersistence::save_user_data(&farmer_data)
|
||||
UserPersistence::save_user_data(&resource_provider_data)
|
||||
.map_err(|e| format!("Failed to update node availability: {}", e))?;
|
||||
}
|
||||
|
||||
@@ -285,10 +285,10 @@ impl NodeRentalService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get farmer earnings from rentals
|
||||
pub fn get_farmer_rental_earnings(&self, farmer_email: &str) -> Vec<FarmerRentalEarning> {
|
||||
if let Some(farmer_data) = UserPersistence::load_user_data(farmer_email) {
|
||||
farmer_data.farmer_rental_earnings
|
||||
/// Get resource_provider earnings from rentals
|
||||
pub fn get_resource_provider_rental_earnings(&self, resource_provider_email: &str) -> Vec<ResourceProviderRentalEarning> {
|
||||
if let Some(resource_provider_data) = UserPersistence::load_user_data(resource_provider_email) {
|
||||
resource_provider_data.resource_provider_rental_earnings
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
@@ -309,8 +309,8 @@ impl NodeRentalService {
|
||||
}
|
||||
|
||||
// Update node availability
|
||||
let farmer_email = self.find_node_owner(&rental.node_id)?;
|
||||
self.update_node_availability(&rental.node_id, &farmer_email)?;
|
||||
let resource_provider_email = self.find_node_owner(&rental.node_id)?;
|
||||
self.update_node_availability(&rental.node_id, &resource_provider_email)?;
|
||||
|
||||
UserPersistence::save_user_data(&user_data)
|
||||
.map_err(|e| format!("Failed to save user data: {}", e))?;
|
||||
|
@@ -241,8 +241,8 @@ impl ProductService {
|
||||
if let Some(combination_id) = product.attributes.get("combination_id") {
|
||||
details["combination_id"] = combination_id.value.clone();
|
||||
}
|
||||
if let Some(farmer_email) = product.attributes.get("farmer_email") {
|
||||
details["farmer_email"] = farmer_email.value.clone();
|
||||
if let Some(resource_provider_email) = product.attributes.get("resource_provider_email") {
|
||||
details["resource_provider_email"] = resource_provider_email.value.clone();
|
||||
}
|
||||
if let Some(cpu_cores) = product.attributes.get("cpu_cores") {
|
||||
details["cpu_cores"] = cpu_cores.value.clone();
|
||||
|
@@ -1,4 +1,4 @@
|
||||
//! Farmer service for managing nodes, slice allocation, and earnings
|
||||
//! ResourceProvider service for managing nodes, slice allocation, and earnings
|
||||
//! Follows the established builder pattern for consistent API design
|
||||
|
||||
use crate::models::user::{FarmNode, NodeCapacity, NodeStatus, EarningsRecord, NodeGroup, GroupStatistics, MarketplaceSLA};
|
||||
@@ -12,7 +12,7 @@ use std::str::FromStr;
|
||||
use chrono::{Utc, DateTime};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// Staking statistics for a farmer
|
||||
/// Staking statistics for a resource_provider
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StakingStatistics {
|
||||
pub total_staked_amount: Decimal,
|
||||
@@ -30,25 +30,25 @@ impl Default for StakingStatistics {
|
||||
}
|
||||
}
|
||||
|
||||
/// Service for farmer-specific operations
|
||||
/// Service for resource_provider-specific operations
|
||||
#[derive(Clone)]
|
||||
pub struct FarmerService {
|
||||
pub struct ResourceProviderService {
|
||||
auto_sync_enabled: bool,
|
||||
metrics_collection: bool,
|
||||
grid_service: GridService,
|
||||
slice_calculator: SliceCalculatorService,
|
||||
}
|
||||
|
||||
/// Builder for FarmerService
|
||||
/// Builder for ResourceProviderService
|
||||
#[derive(Default)]
|
||||
pub struct FarmerServiceBuilder {
|
||||
pub struct ResourceProviderServiceBuilder {
|
||||
auto_sync_enabled: Option<bool>,
|
||||
metrics_collection: Option<bool>,
|
||||
grid_service: Option<GridService>,
|
||||
slice_calculator: Option<SliceCalculatorService>,
|
||||
}
|
||||
|
||||
impl FarmerServiceBuilder {
|
||||
impl ResourceProviderServiceBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
@@ -73,7 +73,7 @@ impl FarmerServiceBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<FarmerService, String> {
|
||||
pub fn build(self) -> Result<ResourceProviderService, String> {
|
||||
let grid_service = self.grid_service.unwrap_or_else(|| {
|
||||
GridService::builder().build().expect("Failed to create default GridService")
|
||||
});
|
||||
@@ -82,7 +82,7 @@ impl FarmerServiceBuilder {
|
||||
SliceCalculatorService::builder().build().expect("Failed to create default SliceCalculatorService")
|
||||
});
|
||||
|
||||
Ok(FarmerService {
|
||||
Ok(ResourceProviderService {
|
||||
auto_sync_enabled: self.auto_sync_enabled.unwrap_or(true),
|
||||
metrics_collection: self.metrics_collection.unwrap_or(true),
|
||||
grid_service,
|
||||
@@ -91,13 +91,13 @@ impl FarmerServiceBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
impl FarmerService {
|
||||
pub fn builder() -> FarmerServiceBuilder {
|
||||
FarmerServiceBuilder::new()
|
||||
impl ResourceProviderService {
|
||||
pub fn builder() -> ResourceProviderServiceBuilder {
|
||||
ResourceProviderServiceBuilder::new()
|
||||
}
|
||||
|
||||
/// Get all nodes for a farmer
|
||||
pub fn get_farmer_nodes(&self, user_email: &str) -> Vec<FarmNode> {
|
||||
/// Get all nodes for a resource_provider
|
||||
pub fn get_resource_provider_nodes(&self, user_email: &str) -> Vec<FarmNode> {
|
||||
if let Some(data) = UserPersistence::load_user_data(user_email) {
|
||||
// Debug: Log marketplace SLA data for all nodes
|
||||
for node in &data.nodes {
|
||||
@@ -111,10 +111,10 @@ impl FarmerService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a new node for a farmer (manual creation)
|
||||
/// Add a new node for a resource_provider (manual creation)
|
||||
pub fn add_node(&self, user_email: &str, node_data: NodeCreationData) -> Result<FarmNode, String> {
|
||||
// Check for duplicate node names first
|
||||
let existing_nodes = self.get_farmer_nodes(user_email);
|
||||
let existing_nodes = self.get_resource_provider_nodes(user_email);
|
||||
if existing_nodes.iter().any(|n| n.name == node_data.name) {
|
||||
return Err(format!("Node '{}' is already registered", node_data.name));
|
||||
}
|
||||
@@ -234,7 +234,7 @@ impl FarmerService {
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Auto-generate marketplace products if rental options are configured
|
||||
self.auto_generate_marketplace_products(&node, user_email, &persistent_data.name.unwrap_or_else(|| "Unknown Farmer".to_string()), node_data.slice_prices.as_ref())?;
|
||||
self.auto_generate_marketplace_products(&node, user_email, &persistent_data.name.unwrap_or_else(|| "Unknown ResourceProvider".to_string()), node_data.slice_prices.as_ref())?;
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
@@ -434,10 +434,10 @@ impl FarmerService {
|
||||
|
||||
/// Sync node capacity and slices with grid data
|
||||
pub async fn sync_node_with_grid(&self, user_email: &str, node_id: &str) -> Result<(), String> {
|
||||
let mut farmer_data = UserPersistence::load_user_data(user_email)
|
||||
.ok_or("Farmer data not found")?;
|
||||
let mut resource_provider_data = UserPersistence::load_user_data(user_email)
|
||||
.ok_or("ResourceProvider data not found")?;
|
||||
|
||||
if let Some(node) = farmer_data.nodes.iter_mut().find(|n| n.id == node_id) {
|
||||
if let Some(node) = resource_provider_data.nodes.iter_mut().find(|n| n.id == node_id) {
|
||||
if let Some(grid_node_id) = &node.grid_node_id {
|
||||
// Fetch latest capacity from grid
|
||||
let grid_id: u32 = grid_node_id.parse().unwrap_or(0);
|
||||
@@ -472,7 +472,7 @@ impl FarmerService {
|
||||
}
|
||||
|
||||
// Save updated data
|
||||
UserPersistence::save_user_data(&farmer_data)
|
||||
UserPersistence::save_user_data(&resource_provider_data)
|
||||
.map_err(|e| format!("Failed to save user data: {}", e))?;
|
||||
} else {
|
||||
return Err("Node is not linked to grid".to_string());
|
||||
@@ -486,7 +486,7 @@ impl FarmerService {
|
||||
|
||||
/// Auto-generate marketplace products for a node based on rental options
|
||||
/// Products are now managed through persistent user data and aggregated by ProductService
|
||||
fn auto_generate_marketplace_products(&self, _node: &FarmNode, _farmer_email: &str, _farmer_name: &str, _slice_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<(), String> {
|
||||
fn auto_generate_marketplace_products(&self, _node: &FarmNode, _resource_provider_email: &str, _resource_provider_name: &str, _slice_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<(), String> {
|
||||
// Product generation is now handled through persistent user data
|
||||
// ProductService automatically aggregates products from user-owned data
|
||||
Ok(())
|
||||
@@ -754,7 +754,7 @@ impl FarmerService {
|
||||
}
|
||||
|
||||
/// Create a slice product from a node and slice format
|
||||
fn create_slice_product_from_node(&self, node: &FarmNode, slice_format_id: &str, farmer_email: &str, farmer_name: &str, custom_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<crate::models::product::Product, String> {
|
||||
fn create_slice_product_from_node(&self, node: &FarmNode, slice_format_id: &str, resource_provider_email: &str, resource_provider_name: &str, custom_prices: Option<&std::collections::HashMap<String, rust_decimal::Decimal>>) -> Result<crate::models::product::Product, String> {
|
||||
// Get slice format details and default pricing
|
||||
let (cpu_cores, memory_gb, storage_gb, bandwidth_mbps, default_price) = match slice_format_id {
|
||||
"basic" => (2, 4, 100, 100, 25),
|
||||
@@ -789,8 +789,8 @@ impl FarmerService {
|
||||
base_price: price,
|
||||
base_currency: "USD".to_string(),
|
||||
attributes: std::collections::HashMap::new(),
|
||||
provider_id: farmer_email.to_string(),
|
||||
provider_name: farmer_name.to_string(),
|
||||
provider_id: resource_provider_email.to_string(),
|
||||
provider_name: resource_provider_name.to_string(),
|
||||
availability: match node.availability_status {
|
||||
crate::models::user::NodeAvailabilityStatus::Available => crate::models::product::ProductAvailability::Available,
|
||||
crate::models::user::NodeAvailabilityStatus::PartiallyRented => crate::models::product::ProductAvailability::Limited,
|
||||
@@ -880,19 +880,19 @@ impl FarmerService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get farmer earnings
|
||||
pub fn get_farmer_earnings(&self, user_email: &str) -> Vec<EarningsRecord> {
|
||||
/// Get resource_provider earnings
|
||||
pub fn get_resource_provider_earnings(&self, user_email: &str) -> Vec<EarningsRecord> {
|
||||
if let Some(data) = UserPersistence::load_user_data(user_email) {
|
||||
data.farmer_earnings
|
||||
data.resource_provider_earnings
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get farmer statistics
|
||||
pub fn get_farmer_statistics(&self, user_email: &str) -> FarmerStatistics {
|
||||
let nodes = self.get_farmer_nodes(user_email);
|
||||
let earnings = self.get_farmer_earnings(user_email);
|
||||
/// Get resource_provider statistics
|
||||
pub fn get_resource_provider_statistics(&self, user_email: &str) -> FarmerStatistics {
|
||||
let nodes = self.get_resource_provider_nodes(user_email);
|
||||
let earnings = self.get_resource_provider_earnings(user_email);
|
||||
|
||||
let total_nodes = nodes.len() as i32;
|
||||
let online_nodes = nodes.iter()
|
||||
@@ -990,7 +990,7 @@ impl FarmerService {
|
||||
slice_config.bandwidth_mbps <= available_bandwidth)
|
||||
}
|
||||
|
||||
/// Get default slice formats available to all farmers
|
||||
/// Get default slice formats available to all resource providers
|
||||
pub fn get_default_slice_formats(&self) -> Vec<DefaultSliceFormat> {
|
||||
vec![
|
||||
DefaultSliceFormat {
|
||||
@@ -1039,8 +1039,8 @@ impl FarmerService {
|
||||
|
||||
// Load user customizations from persistent data
|
||||
if let Some(persistent_data) = UserPersistence::load_user_data(user_email) {
|
||||
if let Some(farmer_settings) = persistent_data.farmer_settings {
|
||||
if let Some(customizations) = farmer_settings.default_slice_customizations {
|
||||
if let Some(resource_provider_settings) = persistent_data.resource_provider_settings {
|
||||
if let Some(customizations) = resource_provider_settings.default_slice_customizations {
|
||||
if let Some(custom_format) = customizations.get(format_id) {
|
||||
// Apply user customizations
|
||||
if let Some(cpu_cores) = custom_format.get("cpu_cores").and_then(|v| v.as_u64()).map(|v| v as u32) {
|
||||
@@ -1075,9 +1075,9 @@ impl FarmerService {
|
||||
pub fn save_default_slice_customization(&self, user_email: &str, format_id: &str, customization: DefaultSliceFormat) -> Result<(), String> {
|
||||
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||
|
||||
// Initialize farmer settings if needed
|
||||
if persistent_data.farmer_settings.is_none() {
|
||||
persistent_data.farmer_settings = Some(crate::models::user::FarmerSettings {
|
||||
// Initialize resource_provider settings if needed
|
||||
if persistent_data.resource_provider_settings.is_none() {
|
||||
persistent_data.resource_provider_settings = Some(crate::models::user::FarmerSettings {
|
||||
auto_accept_reserved_slices: true,
|
||||
maintenance_window: "02:00-04:00 UTC".to_string(),
|
||||
notification_email: None,
|
||||
@@ -1096,12 +1096,12 @@ impl FarmerService {
|
||||
}
|
||||
|
||||
// Initialize default slice customizations if needed
|
||||
if let Some(ref mut farmer_settings) = persistent_data.farmer_settings {
|
||||
if farmer_settings.default_slice_customizations.is_none() {
|
||||
farmer_settings.default_slice_customizations = Some(serde_json::to_value(std::collections::HashMap::<String, serde_json::Value>::new()).unwrap_or_default());
|
||||
if let Some(ref mut resource_provider_settings) = persistent_data.resource_provider_settings {
|
||||
if resource_provider_settings.default_slice_customizations.is_none() {
|
||||
resource_provider_settings.default_slice_customizations = Some(serde_json::to_value(std::collections::HashMap::<String, serde_json::Value>::new()).unwrap_or_default());
|
||||
}
|
||||
|
||||
if let Some(ref mut customizations) = farmer_settings.default_slice_customizations {
|
||||
if let Some(ref mut customizations) = resource_provider_settings.default_slice_customizations {
|
||||
if let Some(obj) = customizations.as_object_mut() {
|
||||
obj.insert(format_id.to_string(), serde_json::to_value(customization).unwrap_or_default());
|
||||
}
|
||||
@@ -1288,7 +1288,7 @@ impl FarmerService {
|
||||
/// Add a node from ThreeFold Grid by node ID
|
||||
pub async fn add_grid_node(&self, user_email: &str, grid_node_id: u32, _slice_format: Option<String>, _slice_price: Option<Decimal>) -> Result<FarmNode, String> {
|
||||
// Check for duplicate grid node IDs first
|
||||
let existing_nodes = self.get_farmer_nodes(user_email);
|
||||
let existing_nodes = self.get_resource_provider_nodes(user_email);
|
||||
if existing_nodes.iter().any(|n| n.grid_node_id == Some(grid_node_id.to_string())) {
|
||||
return Err(format!("Node {} is already registered", grid_node_id));
|
||||
}
|
||||
@@ -1845,8 +1845,8 @@ impl FarmerService {
|
||||
.unwrap_or(false);
|
||||
|
||||
if slice_rental_enabled || full_node_rental_enabled {
|
||||
let farmer_name = persistent_data.name.unwrap_or_else(|| "Unknown Farmer".to_string());
|
||||
self.auto_generate_marketplace_products(&node, user_email, &farmer_name, None)?;
|
||||
let resource_provider_name = persistent_data.name.unwrap_or_else(|| "Unknown ResourceProvider".to_string());
|
||||
self.auto_generate_marketplace_products(&node, user_email, &resource_provider_name, None)?;
|
||||
}
|
||||
}
|
||||
Ok(node)
|
||||
@@ -1856,7 +1856,7 @@ impl FarmerService {
|
||||
// NODE GROUP MANAGEMENT
|
||||
// =============================================================================
|
||||
|
||||
/// Ensure default node groups exist for a farmer
|
||||
/// Ensure default node groups exist for a resource_provider
|
||||
pub fn ensure_default_node_groups(&self, user_email: &str) -> Result<(), String> {
|
||||
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||
|
||||
@@ -1898,7 +1898,7 @@ impl FarmerService {
|
||||
Ok(group)
|
||||
}
|
||||
|
||||
/// Get all node groups for a farmer (ensures defaults exist)
|
||||
/// Get all node groups for a resource_provider (ensures defaults exist)
|
||||
pub fn get_node_groups(&self, user_email: &str) -> Vec<NodeGroup> {
|
||||
// Ensure default groups exist first
|
||||
if let Err(e) = self.ensure_default_node_groups(user_email) {
|
||||
@@ -2165,7 +2165,7 @@ impl FarmerService {
|
||||
|
||||
/// Get node by name (for duplicate checking)
|
||||
pub fn get_node_by_name(&self, user_email: &str, node_name: &str) -> Option<FarmNode> {
|
||||
let nodes = self.get_farmer_nodes(user_email);
|
||||
let nodes = self.get_resource_provider_nodes(user_email);
|
||||
nodes.into_iter().find(|n| n.name == node_name)
|
||||
}
|
||||
|
||||
@@ -2278,12 +2278,12 @@ impl FarmerService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create default user data for new farmers
|
||||
/// Create default user data for new resource providers
|
||||
fn create_default_user_data(user_email: &str) -> UserPersistentData {
|
||||
crate::models::builders::SessionDataBuilder::new_user(user_email)
|
||||
}
|
||||
|
||||
/// Refresh all slice calculations for a farmer
|
||||
/// Refresh all slice calculations for a resource_provider
|
||||
pub fn refresh_all_slice_calculations(&self, user_email: &str) -> Result<(), String> {
|
||||
let mut persistent_data = UserPersistence::load_user_data(user_email)
|
||||
.ok_or("User data not found")?;
|
||||
@@ -2395,7 +2395,7 @@ impl FarmerService {
|
||||
Ok(slices)
|
||||
}
|
||||
|
||||
/// Get comprehensive slice statistics for a farmer
|
||||
/// Get comprehensive slice statistics for a resource_provider
|
||||
pub fn get_slice_statistics(&self, user_email: &str) -> Result<serde_json::Value, String> {
|
||||
let persistent_data = UserPersistence::load_user_data(user_email)
|
||||
.ok_or("User data not found")?;
|
||||
@@ -2821,7 +2821,7 @@ impl FarmerService {
|
||||
Ok(repaired_count)
|
||||
}
|
||||
|
||||
/// Refresh all slice calculations for a farmer (async version)
|
||||
/// Refresh all slice calculations for a resource_provider (async version)
|
||||
pub async fn refresh_all_slice_calculations_async(&self, user_email: &str) -> Result<u32, String> {
|
||||
let mut persistent_data = UserPersistence::load_user_data(user_email)
|
||||
.ok_or("User data not found")?;
|
||||
@@ -2971,7 +2971,7 @@ pub struct NodeUpdateData {
|
||||
pub marketplace_sla: Option<MarketplaceSLA>,
|
||||
}
|
||||
|
||||
/// Default slice formats available to all farmers
|
||||
/// Default slice formats available to all resource providers
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DefaultSliceFormat {
|
||||
pub id: String,
|
||||
@@ -2984,7 +2984,7 @@ pub struct DefaultSliceFormat {
|
||||
pub price_per_hour: rust_decimal::Decimal,
|
||||
}
|
||||
|
||||
/// Farmer statistics summary
|
||||
/// ResourceProvider statistics summary
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FarmerStatistics {
|
||||
pub total_nodes: i32,
|
@@ -18,7 +18,7 @@ pub struct SliceAssignmentService {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SliceAssignmentRequest {
|
||||
pub user_email: String,
|
||||
pub farmer_email: String,
|
||||
pub resource_provider_email: String,
|
||||
pub node_id: String,
|
||||
pub combination_id: String,
|
||||
pub quantity: u32,
|
||||
@@ -127,7 +127,7 @@ pub struct SecurityConfiguration {
|
||||
pub struct SliceAssignment {
|
||||
pub assignment_id: String,
|
||||
pub user_email: String,
|
||||
pub farmer_email: String,
|
||||
pub resource_provider_email: String,
|
||||
pub node_id: String,
|
||||
pub combination_id: String,
|
||||
pub slice_allocations: Vec<SliceAllocation>,
|
||||
@@ -241,7 +241,7 @@ impl SliceAssignmentService {
|
||||
let assignment = SliceAssignment {
|
||||
assignment_id,
|
||||
user_email: request.user_email,
|
||||
farmer_email: request.farmer_email,
|
||||
resource_provider_email: request.resource_provider_email,
|
||||
node_id: request.node_id,
|
||||
combination_id: request.combination_id,
|
||||
slice_allocations,
|
||||
@@ -377,7 +377,7 @@ impl SliceAssignmentService {
|
||||
"status": "deploying",
|
||||
"deployment_type": "vm",
|
||||
"node_id": assignment.node_id,
|
||||
"farmer_email": assignment.farmer_email,
|
||||
"resource_provider_email": assignment.resource_provider_email,
|
||||
"started_at": Utc::now(),
|
||||
"estimated_completion": Utc::now() + chrono::Duration::minutes(5)
|
||||
});
|
||||
|
@@ -42,7 +42,7 @@ pub struct SliceCombination {
|
||||
pub node_location: String,
|
||||
pub node_certification_type: String,
|
||||
pub node_id: String,
|
||||
pub farmer_email: String,
|
||||
pub resource_provider_email: String,
|
||||
}
|
||||
|
||||
/// Track individual slice rentals
|
||||
@@ -70,7 +70,7 @@ pub enum AllocationStatus {
|
||||
pub struct SlicePricing {
|
||||
pub base_price_per_hour: Decimal, // Price for 1 base slice per hour
|
||||
pub currency: String,
|
||||
pub pricing_multiplier: Decimal, // Farmer can adjust pricing (0.5x - 2.0x)
|
||||
pub pricing_multiplier: Decimal, // ResourceProvider can adjust pricing (0.5x - 2.0x)
|
||||
}
|
||||
|
||||
impl Default for SlicePricing {
|
||||
@@ -157,7 +157,7 @@ impl SliceCalculatorService {
|
||||
max_base_slices: u32,
|
||||
allocated_slices: u32,
|
||||
node: &FarmNode,
|
||||
farmer_email: &str
|
||||
resource_provider_email: &str
|
||||
) -> Vec<SliceCombination> {
|
||||
let available_base_slices = max_base_slices.saturating_sub(allocated_slices);
|
||||
let mut combinations = Vec::new();
|
||||
@@ -208,7 +208,7 @@ impl SliceCalculatorService {
|
||||
.to_string())
|
||||
.unwrap_or_else(|| "DIY".to_string()),
|
||||
node_id: node.id.clone(),
|
||||
farmer_email: farmer_email.to_string(),
|
||||
resource_provider_email: resource_provider_email.to_string(),
|
||||
};
|
||||
|
||||
combinations.push(combination);
|
||||
@@ -225,7 +225,7 @@ impl SliceCalculatorService {
|
||||
max_base_slices: u32,
|
||||
allocated_slices: u32,
|
||||
node: &FarmNode,
|
||||
farmer_email: &str,
|
||||
resource_provider_email: &str,
|
||||
uptime_percentage: f64,
|
||||
bandwidth_mbps: u32,
|
||||
base_price_per_hour: Decimal
|
||||
@@ -283,7 +283,7 @@ impl SliceCalculatorService {
|
||||
.to_string())
|
||||
.unwrap_or_else(|| "DIY".to_string()),
|
||||
node_id: node.id.clone(),
|
||||
farmer_email: farmer_email.to_string(),
|
||||
resource_provider_email: resource_provider_email.to_string(),
|
||||
};
|
||||
|
||||
combinations.push(combination);
|
||||
@@ -304,7 +304,7 @@ impl SliceCalculatorService {
|
||||
&self,
|
||||
node: &mut FarmNode,
|
||||
rented_base_slices: u32,
|
||||
farmer_email: &str
|
||||
resource_provider_email: &str
|
||||
) -> Result<(), String> {
|
||||
// Update allocated count
|
||||
node.allocated_base_slices += rented_base_slices as i32;
|
||||
@@ -314,7 +314,7 @@ impl SliceCalculatorService {
|
||||
node.total_base_slices as u32,
|
||||
node.allocated_base_slices as u32,
|
||||
node,
|
||||
farmer_email
|
||||
resource_provider_email
|
||||
);
|
||||
node.available_combinations = combinations.iter()
|
||||
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||
@@ -328,7 +328,7 @@ impl SliceCalculatorService {
|
||||
&self,
|
||||
node: &mut FarmNode,
|
||||
released_base_slices: u32,
|
||||
farmer_email: &str
|
||||
resource_provider_email: &str
|
||||
) -> Result<(), String> {
|
||||
// Update allocated count
|
||||
node.allocated_base_slices = node.allocated_base_slices.saturating_sub(released_base_slices as i32);
|
||||
@@ -338,7 +338,7 @@ impl SliceCalculatorService {
|
||||
node.total_base_slices as u32,
|
||||
node.allocated_base_slices as u32,
|
||||
node,
|
||||
farmer_email
|
||||
resource_provider_email
|
||||
).iter()
|
||||
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||
.collect();
|
||||
@@ -364,7 +364,7 @@ pub struct SliceRental {
|
||||
pub rental_id: String,
|
||||
pub slice_combination_id: String,
|
||||
pub node_id: String,
|
||||
pub farmer_email: String,
|
||||
pub resource_provider_email: String,
|
||||
pub slice_allocation: SliceAllocation,
|
||||
pub total_cost: Decimal,
|
||||
pub payment_status: PaymentStatus,
|
||||
|
@@ -56,11 +56,11 @@ impl SliceRentalService {
|
||||
SliceRentalServiceBuilder::new()
|
||||
}
|
||||
|
||||
/// Rent a slice combination from a farmer's node
|
||||
/// Rent a slice combination from a resource_provider's node
|
||||
pub fn rent_slice_combination(
|
||||
&self,
|
||||
renter_email: &str,
|
||||
farmer_email: &str,
|
||||
resource_provider_email: &str,
|
||||
node_id: &str,
|
||||
combination_id: &str,
|
||||
quantity: u32,
|
||||
@@ -68,9 +68,9 @@ impl SliceRentalService {
|
||||
) -> Result<SliceRental, String> {
|
||||
// Atomic operation with file locking to prevent conflicts
|
||||
if self.enable_file_locking {
|
||||
self.rent_with_file_lock(renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours)
|
||||
self.rent_with_file_lock(renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours)
|
||||
} else {
|
||||
self.rent_without_lock(renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours)
|
||||
self.rent_without_lock(renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ impl SliceRentalService {
|
||||
pub fn rent_slice_combination_with_deployment(
|
||||
&self,
|
||||
renter_email: &str,
|
||||
farmer_email: &str,
|
||||
resource_provider_email: &str,
|
||||
node_id: &str,
|
||||
combination_id: &str,
|
||||
quantity: u32,
|
||||
@@ -89,7 +89,7 @@ impl SliceRentalService {
|
||||
) -> Result<SliceRental, String> {
|
||||
// First rent the slice combination
|
||||
let mut rental = self.rent_slice_combination(
|
||||
renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours
|
||||
renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours
|
||||
)?;
|
||||
|
||||
// Add deployment metadata to the rental
|
||||
@@ -133,21 +133,21 @@ impl SliceRentalService {
|
||||
fn rent_with_file_lock(
|
||||
&self,
|
||||
renter_email: &str,
|
||||
farmer_email: &str,
|
||||
resource_provider_email: &str,
|
||||
node_id: &str,
|
||||
combination_id: &str,
|
||||
quantity: u32,
|
||||
rental_duration_hours: u32,
|
||||
) -> Result<SliceRental, String> {
|
||||
// Create lock file
|
||||
let lock_file_path = format!("./user_data/.lock_{}_{}", farmer_email.replace("@", "_"), node_id);
|
||||
let lock_file_path = format!("./user_data/.lock_{}_{}", resource_provider_email.replace("@", "_"), node_id);
|
||||
let _lock_file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open(&lock_file_path)
|
||||
.map_err(|e| format!("Failed to create lock file: {}", e))?;
|
||||
|
||||
let result = self.rent_without_lock(renter_email, farmer_email, node_id, combination_id, quantity, rental_duration_hours);
|
||||
let result = self.rent_without_lock(renter_email, resource_provider_email, node_id, combination_id, quantity, rental_duration_hours);
|
||||
|
||||
// Clean up lock file
|
||||
let _ = std::fs::remove_file(&lock_file_path);
|
||||
@@ -159,21 +159,21 @@ impl SliceRentalService {
|
||||
fn rent_without_lock(
|
||||
&self,
|
||||
renter_email: &str,
|
||||
farmer_email: &str,
|
||||
resource_provider_email: &str,
|
||||
node_id: &str,
|
||||
combination_id: &str,
|
||||
quantity: u32,
|
||||
rental_duration_hours: u32,
|
||||
) -> Result<SliceRental, String> {
|
||||
// Load farmer data
|
||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
||||
.ok_or_else(|| "Farmer not found".to_string())?;
|
||||
// Load resource_provider data
|
||||
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||
.ok_or_else(|| "ResourceProvider not found".to_string())?;
|
||||
|
||||
// Find the node
|
||||
let node_index = farmer_data.nodes.iter().position(|n| n.id == node_id)
|
||||
let node_index = resource_provider_data.nodes.iter().position(|n| n.id == node_id)
|
||||
.ok_or_else(|| "Node not found".to_string())?;
|
||||
|
||||
let node = &mut farmer_data.nodes[node_index];
|
||||
let node = &mut resource_provider_data.nodes[node_index];
|
||||
|
||||
// Find the slice combination
|
||||
let combination = node.available_combinations.iter()
|
||||
@@ -226,7 +226,7 @@ impl SliceRentalService {
|
||||
self.slice_calculator.update_availability_after_rental(
|
||||
node,
|
||||
total_base_slices_needed,
|
||||
farmer_email
|
||||
resource_provider_email
|
||||
)?;
|
||||
|
||||
// Add allocation to node
|
||||
@@ -237,7 +237,7 @@ impl SliceRentalService {
|
||||
rental_id: rental_id.clone(),
|
||||
slice_combination_id: combination_id.to_string(),
|
||||
node_id: node_id.to_string(),
|
||||
farmer_email: farmer_email.to_string(),
|
||||
resource_provider_email: resource_provider_email.to_string(),
|
||||
slice_allocation: allocation,
|
||||
total_cost,
|
||||
payment_status: PaymentStatus::Paid,
|
||||
@@ -260,12 +260,12 @@ impl SliceRentalService {
|
||||
renter_data.wallet_balance_usd -= total_cost;
|
||||
renter_data.slice_rentals.push(slice_rental.clone());
|
||||
|
||||
// Add earnings to farmer
|
||||
farmer_data.wallet_balance_usd += total_cost;
|
||||
// Add earnings to resource_provider
|
||||
resource_provider_data.wallet_balance_usd += total_cost;
|
||||
|
||||
// Save both user data
|
||||
UserPersistence::save_user_data(&farmer_data)
|
||||
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
|
||||
UserPersistence::save_user_data(&resource_provider_data)
|
||||
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
|
||||
UserPersistence::save_user_data(&renter_data)
|
||||
.map_err(|e| format!("Failed to save renter data: {}", e))?;
|
||||
|
||||
@@ -273,14 +273,14 @@ impl SliceRentalService {
|
||||
}
|
||||
|
||||
/// Release expired slice rentals
|
||||
pub fn release_expired_rentals(&self, farmer_email: &str) -> Result<u32, String> {
|
||||
let mut farmer_data = UserPersistence::load_user_data(farmer_email)
|
||||
.ok_or_else(|| "Farmer not found".to_string())?;
|
||||
pub fn release_expired_rentals(&self, resource_provider_email: &str) -> Result<u32, String> {
|
||||
let mut resource_provider_data = UserPersistence::load_user_data(resource_provider_email)
|
||||
.ok_or_else(|| "ResourceProvider not found".to_string())?;
|
||||
|
||||
let mut released_count = 0;
|
||||
let now = Utc::now();
|
||||
|
||||
for node in &mut farmer_data.nodes {
|
||||
for node in &mut resource_provider_data.nodes {
|
||||
let mut expired_allocations = Vec::new();
|
||||
|
||||
// Find expired allocations
|
||||
@@ -314,7 +314,7 @@ impl SliceRentalService {
|
||||
self.slice_calculator.update_availability_after_release(
|
||||
node,
|
||||
base_slices_used,
|
||||
farmer_email
|
||||
resource_provider_email
|
||||
)?;
|
||||
|
||||
released_count += 1;
|
||||
@@ -322,20 +322,20 @@ impl SliceRentalService {
|
||||
}
|
||||
|
||||
if released_count > 0 {
|
||||
UserPersistence::save_user_data(&farmer_data)
|
||||
.map_err(|e| format!("Failed to save farmer data: {}", e))?;
|
||||
UserPersistence::save_user_data(&resource_provider_data)
|
||||
.map_err(|e| format!("Failed to save resource_provider data: {}", e))?;
|
||||
}
|
||||
|
||||
Ok(released_count)
|
||||
}
|
||||
|
||||
|
||||
/// Get slice rental statistics for a farmer
|
||||
pub fn get_farmer_slice_statistics(&self, farmer_email: &str) -> SliceRentalStatistics {
|
||||
if let Some(farmer_data) = UserPersistence::load_user_data(farmer_email) {
|
||||
/// Get slice rental statistics for a resource_provider
|
||||
pub fn get_resource_provider_slice_statistics(&self, resource_provider_email: &str) -> SliceRentalStatistics {
|
||||
if let Some(resource_provider_data) = UserPersistence::load_user_data(resource_provider_email) {
|
||||
let mut stats = SliceRentalStatistics::default();
|
||||
|
||||
for node in &farmer_data.nodes {
|
||||
for node in &resource_provider_data.nodes {
|
||||
stats.total_nodes += 1;
|
||||
stats.total_base_slices += node.total_base_slices as u32;
|
||||
stats.allocated_base_slices += node.allocated_base_slices as u32;
|
||||
@@ -379,7 +379,7 @@ impl SliceRentalService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Statistics for farmer slice rentals
|
||||
/// Statistics for resource_provider slice rentals
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct SliceRentalStatistics {
|
||||
pub total_nodes: u32,
|
||||
|
@@ -46,10 +46,10 @@ pub struct UserPersistentData {
|
||||
pub deleted: Option<bool>,
|
||||
pub deleted_at: Option<String>,
|
||||
pub deletion_reason: Option<String>,
|
||||
// Farmer-specific data
|
||||
// ResourceProvider-specific data
|
||||
pub nodes: Vec<crate::models::user::FarmNode>,
|
||||
pub farmer_earnings: Vec<crate::models::user::EarningsRecord>,
|
||||
pub farmer_settings: Option<crate::models::user::FarmerSettings>,
|
||||
pub resource_provider_earnings: Vec<crate::models::user::EarningsRecord>,
|
||||
pub resource_provider_settings: Option<crate::models::user::FarmerSettings>,
|
||||
#[serde(default)]
|
||||
pub slice_products: Vec<crate::models::product::Product>,
|
||||
// User activity tracking
|
||||
@@ -63,10 +63,10 @@ pub struct UserPersistentData {
|
||||
#[serde(default)]
|
||||
pub active_product_rentals: Vec<ProductRental>,
|
||||
#[serde(default)]
|
||||
pub farmer_rental_earnings: Vec<crate::models::user::FarmerRentalEarning>,
|
||||
pub resource_provider_rental_earnings: Vec<crate::models::user::FarmerRentalEarning>,
|
||||
#[serde(default)]
|
||||
pub node_rentals: Vec<crate::models::user::NodeRental>,
|
||||
// Node groups for farmer organization
|
||||
// Node groups for resource_provider organization
|
||||
#[serde(default)]
|
||||
pub node_groups: Vec<crate::models::user::NodeGroup>,
|
||||
// NEW: Slice rental tracking for users
|
||||
@@ -142,15 +142,15 @@ impl Default for UserPersistentData {
|
||||
deleted_at: None,
|
||||
deletion_reason: None,
|
||||
nodes: Vec::new(),
|
||||
farmer_earnings: Vec::new(),
|
||||
farmer_settings: None,
|
||||
resource_provider_earnings: Vec::new(),
|
||||
resource_provider_settings: None,
|
||||
slice_products: Vec::new(),
|
||||
user_activities: Vec::new(),
|
||||
user_preferences: None,
|
||||
usage_statistics: None,
|
||||
orders: Vec::new(),
|
||||
active_product_rentals: Vec::new(),
|
||||
farmer_rental_earnings: Vec::new(),
|
||||
resource_provider_rental_earnings: Vec::new(),
|
||||
node_rentals: Vec::new(),
|
||||
node_groups: Vec::new(),
|
||||
slice_rentals: Vec::new(),
|
||||
@@ -1306,19 +1306,19 @@ impl UserPersistence {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get farmer earnings for a user
|
||||
pub fn get_farmer_earnings(user_email: &str) -> Vec<crate::models::user::EarningsRecord> {
|
||||
/// Get resource_provider earnings for a user
|
||||
pub fn get_resource_provider_earnings(user_email: &str) -> Vec<crate::models::user::EarningsRecord> {
|
||||
if let Some(data) = Self::load_user_data(user_email) {
|
||||
data.farmer_earnings
|
||||
data.resource_provider_earnings
|
||||
} else {
|
||||
Vec::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get farmer settings for a user
|
||||
pub fn get_farmer_settings(user_email: &str) -> Option<crate::models::user::FarmerSettings> {
|
||||
/// Get resource_provider settings for a user
|
||||
pub fn get_resource_provider_settings(user_email: &str) -> Option<crate::models::user::FarmerSettings> {
|
||||
if let Some(data) = Self::load_user_data(user_email) {
|
||||
data.farmer_settings
|
||||
data.resource_provider_settings
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
// Dashboard Farmer JavaScript
|
||||
// Handles farmer dashboard functionality including automatic slice management, grid integration, and node management
|
||||
// Dashboard ResourceProvider JavaScript
|
||||
// Handles resource_provider dashboard functionality including automatic slice management, grid integration, and node management
|
||||
|
||||
if (window.farmerDashboardInitialized) {
|
||||
console.debug('Farmer dashboard already initialized; skipping');
|
||||
if (window.resourceProviderDashboardInitialized) {
|
||||
console.debug('ResourceProvider dashboard already initialized; skipping');
|
||||
} else {
|
||||
window.farmerDashboardInitialized = true;
|
||||
window.resourceProviderDashboardInitialized = true;
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('🚜 Farmer Dashboard JavaScript loaded - Automatic Slice System');
|
||||
console.log('🚜 ResourceProvider Dashboard JavaScript loaded - Automatic Slice System');
|
||||
|
||||
// Initialize dashboard
|
||||
initializeFarmerDashboard();
|
||||
@@ -762,7 +762,7 @@ function showNodeDetailsModal(node) {
|
||||
function loadSliceStatistics() {
|
||||
console.log('📊 Loading slice statistics');
|
||||
|
||||
window.apiJson('/api/dashboard/farmer/slice-statistics')
|
||||
window.apiJson('/api/dashboard/resource_provider/slice-statistics')
|
||||
.then(data => {
|
||||
// apiJson returns unwrapped data; support either {statistics: {...}} or {...}
|
||||
const stats = (data && data.statistics) ? data.statistics : (data || {});
|
||||
@@ -1173,12 +1173,12 @@ function createSimpleIndividualPricingForms() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize farmer dashboard functionality
|
||||
* Initialize resource_provider dashboard functionality
|
||||
*/
|
||||
function initializeFarmerDashboard() {
|
||||
console.log('🚜 Initializing farmer dashboard');
|
||||
console.log('🚜 Initializing resource_provider dashboard');
|
||||
|
||||
// Load farmer data
|
||||
// Load resource_provider data
|
||||
loadFarmerData();
|
||||
|
||||
// Load slice templates
|
||||
@@ -2911,12 +2911,12 @@ function resetSliceConfigurationForm() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load farmer data from API
|
||||
* Load resource_provider data from API
|
||||
*/
|
||||
async function loadFarmerData() {
|
||||
try {
|
||||
const data = await window.apiJson('/api/dashboard/farmer-data');
|
||||
console.log('🚜 Loaded farmer data:', data);
|
||||
const data = await window.apiJson('/api/dashboard/resource_provider-data');
|
||||
console.log('🚜 Loaded resource_provider data:', data);
|
||||
|
||||
// Load node groups as well
|
||||
const groupsResult = await window.apiJson('/api/dashboard/node-groups');
|
||||
@@ -2924,8 +2924,8 @@ async function loadFarmerData() {
|
||||
data.nodeGroups = nodeGroups;
|
||||
console.log('🚜 Node groups loaded:', nodeGroups);
|
||||
|
||||
// Store farmer data globally for slice status checking
|
||||
window.farmerData = data;
|
||||
// Store resource_provider data globally for slice status checking
|
||||
window.resourceProviderData = data;
|
||||
|
||||
// Update dashboard stats
|
||||
updateDashboardStats(data);
|
||||
@@ -2940,8 +2940,8 @@ async function loadFarmerData() {
|
||||
loadSliceTemplates();
|
||||
|
||||
} catch (error) {
|
||||
console.error('🚜 Error loading farmer data:', error);
|
||||
showNotification('Failed to load farmer data', 'error');
|
||||
console.error('🚜 Error loading resource_provider data:', error);
|
||||
showNotification('Failed to load resource_provider data', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3130,13 +3130,13 @@ function showSliceTemplatesError() {
|
||||
* Returns 'Active' if at least one node is using this slice format, 'Available' otherwise
|
||||
*/
|
||||
function getSliceFormatStatus(sliceFormatId) {
|
||||
// Check if we have farmer data loaded
|
||||
if (!window.farmerData || !window.farmerData.nodes) {
|
||||
// Check if we have resource_provider data loaded
|
||||
if (!window.resourceProviderData || !window.resourceProviderData.nodes) {
|
||||
return 'Available'; // Default to Available if no data
|
||||
}
|
||||
|
||||
// Check if any node has this slice format in their slice_formats array
|
||||
const isUsedByAnyNode = window.farmerData.nodes.some(node => {
|
||||
const isUsedByAnyNode = window.resourceProviderData.nodes.some(node => {
|
||||
return node.slice_formats &&
|
||||
Array.isArray(node.slice_formats) &&
|
||||
node.slice_formats.includes(sliceFormatId);
|
||||
@@ -3507,8 +3507,8 @@ function updateNodesTable(nodes) {
|
||||
|
||||
// Group info with enhanced display - get actual group name from loaded groups
|
||||
let groupInfo = '<span class="badge bg-secondary">Single</span>';
|
||||
if (node.node_group_id && window.farmerData && window.farmerData.nodeGroups) {
|
||||
const group = window.farmerData.nodeGroups.find(g => g.id === node.node_group_id);
|
||||
if (node.node_group_id && window.resourceProviderData && window.resourceProviderData.nodeGroups) {
|
||||
const group = window.resourceProviderData.nodeGroups.find(g => g.id === node.node_group_id);
|
||||
if (group) {
|
||||
groupInfo = `<span class="badge bg-info">${group.name}</span>`;
|
||||
}
|
||||
@@ -3966,7 +3966,7 @@ async function addGridNodes() {
|
||||
// Reset form
|
||||
resetAddNodeForm();
|
||||
|
||||
// Reload farmer data and node groups with small delay for backend processing
|
||||
// Reload resource_provider data and node groups with small delay for backend processing
|
||||
setTimeout(async () => {
|
||||
await loadFarmerData();
|
||||
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after adding new nodes
|
||||
@@ -4155,7 +4155,7 @@ async function confirmNodeDeletion() {
|
||||
deleteModal.hide();
|
||||
}
|
||||
|
||||
// Reload farmer data and node groups with small delay for backend processing
|
||||
// Reload resource_provider data and node groups with small delay for backend processing
|
||||
setTimeout(() => {
|
||||
loadFarmerData();
|
||||
loadNodeGroups(); // FARMER FIX: Refresh node groups table after node deletion
|
||||
@@ -4925,7 +4925,7 @@ async function saveNodeConfiguration() {
|
||||
modal.hide();
|
||||
}
|
||||
|
||||
// Reload farmer data and node groups with small delay for backend processing
|
||||
// Reload resource_provider data and node groups with small delay for backend processing
|
||||
setTimeout(async () => {
|
||||
await loadFarmerData();
|
||||
await loadNodeGroups(); // FARMER FIX: Refresh node groups table after node configuration changes
|
||||
@@ -5627,7 +5627,7 @@ function createSliceFormatCard(format, type) {
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
// Use persistent data from farmer settings (price_per_hour) instead of hardcoded fallback
|
||||
// Use persistent data from resource_provider settings (price_per_hour) instead of hardcoded fallback
|
||||
const hourlyPrice = format.price_per_hour || format.price || 10; // Default to 10 if no price found
|
||||
pricingDisplay = `<small class="text-muted">${hourlyPrice} ${currency}/hour</small>`;
|
||||
}
|
||||
@@ -5706,15 +5706,15 @@ function getSliceFormatDisplayName(formatId, formatName) {
|
||||
return formatName;
|
||||
}
|
||||
|
||||
// Look up custom slice products from loaded farmer data
|
||||
if (window.farmerData && window.farmerData.slice_products) {
|
||||
const sliceProduct = window.farmerData.slice_products.find(product => product.id === formatId);
|
||||
// Look up custom slice products from loaded resource_provider data
|
||||
if (window.resourceProviderData && window.resourceProviderData.slice_products) {
|
||||
const sliceProduct = window.resourceProviderData.slice_products.find(product => product.id === formatId);
|
||||
if (sliceProduct && sliceProduct.name) {
|
||||
return sliceProduct.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Look up from globally loaded slice products if farmer data not available
|
||||
// Look up from globally loaded slice products if resource_provider data not available
|
||||
if (window.loadedSliceProducts) {
|
||||
const sliceProduct = window.loadedSliceProducts.find(product => product.id === formatId);
|
||||
if (sliceProduct && sliceProduct.name) {
|
||||
@@ -7189,7 +7189,7 @@ function clearValidationError(input) {
|
||||
*/
|
||||
async function updateStakingDisplay() {
|
||||
try {
|
||||
const data = await window.apiJson('/api/dashboard/farmer-data');
|
||||
const data = await window.apiJson('/api/dashboard/resource_provider-data');
|
||||
const nodes = data.nodes || [];
|
||||
|
||||
// Calculate staking statistics
|
||||
@@ -7523,7 +7523,7 @@ function showStakeNodeModal(nodeId) {
|
||||
console.log('🛡️ Showing stake modal for node:', nodeId);
|
||||
|
||||
// Find the node data
|
||||
const node = window.farmerData?.nodes?.find(n => n.id === nodeId);
|
||||
const node = window.resourceProviderData?.nodes?.find(n => n.id === nodeId);
|
||||
if (!node) {
|
||||
showNotification('Node not found', 'error');
|
||||
return;
|
||||
@@ -7657,7 +7657,7 @@ async function stakeOnNode(nodeId, modal) {
|
||||
showNotification(`Successfully staked ${stakeAmount} TFP on node`, 'success');
|
||||
modal.hide();
|
||||
|
||||
// Refresh farmer data to show updated staking
|
||||
// Refresh resource_provider data to show updated staking
|
||||
await loadFarmerData();
|
||||
|
||||
// Update wallet balance display
|
||||
@@ -7683,7 +7683,7 @@ async function unstakeFromNode(nodeId) {
|
||||
console.log('🛡️ Unstaking TFP from node:', nodeId);
|
||||
|
||||
// Find the node data
|
||||
const node = window.farmerData?.nodes?.find(n => n.id === nodeId);
|
||||
const node = window.resourceProviderData?.nodes?.find(n => n.id === nodeId);
|
||||
if (!node || !node.staking_options || !node.staking_options.staking_enabled) {
|
||||
showNotification('Node is not currently staked', 'error');
|
||||
return;
|
||||
@@ -7712,7 +7712,7 @@ async function unstakeFromNode(nodeId) {
|
||||
const returnedAmount = result?.returned_amount || stakedAmount;
|
||||
showNotification(`Successfully unstaked ${returnedAmount} TFP from node`, 'success');
|
||||
|
||||
// Refresh farmer data to show updated staking
|
||||
// Refresh resource_provider data to show updated staking
|
||||
await loadFarmerData();
|
||||
|
||||
// Update wallet balance display
|
||||
@@ -7731,7 +7731,7 @@ function showUpdateStakeModal(nodeId) {
|
||||
console.log('🛡️ Showing update stake modal for node:', nodeId);
|
||||
|
||||
// Find the node data
|
||||
const node = window.farmerData?.nodes?.find(n => n.id === nodeId);
|
||||
const node = window.resourceProviderData?.nodes?.find(n => n.id === nodeId);
|
||||
if (!node || !node.staking_options || !node.staking_options.staking_enabled) {
|
||||
showNotification('Node is not currently staked', 'error');
|
||||
return;
|
||||
@@ -7847,7 +7847,7 @@ async function updateNodeStaking(nodeId, modal) {
|
||||
showNotification(`Successfully updated staking to ${newStakeAmount} TFP`, 'success');
|
||||
modal.hide();
|
||||
|
||||
// Refresh farmer data to show updated staking
|
||||
// Refresh resource_provider data to show updated staking
|
||||
await loadFarmerData();
|
||||
|
||||
// Update wallet balance display
|
@@ -31,7 +31,7 @@ class DemoWorkflow {
|
||||
action: () => this.demoAppDeployment()
|
||||
},
|
||||
{
|
||||
title: "Farmer: Node Management",
|
||||
title: "ResourceProvider: Node Management",
|
||||
description: "Manage your farming nodes and monitor capacity.",
|
||||
action: () => this.demoNodeManagement()
|
||||
},
|
||||
@@ -265,7 +265,7 @@ class DemoWorkflow {
|
||||
}
|
||||
|
||||
demoNodeManagement() {
|
||||
showNotification('Demo: Simulating farmer node management...', 'info');
|
||||
showNotification('Demo: Simulating resource_provider node management...', 'info');
|
||||
|
||||
setTimeout(() => {
|
||||
// Simulate node status change
|
||||
|
@@ -431,7 +431,7 @@ class MarketplaceIntegration {
|
||||
|
||||
if (!sessionStorage.getItem('marketplaceSlices')) {
|
||||
// Get real users from user database
|
||||
const alexUser = userDB.getUser('user-001'); // Alex Thompson - Farmer
|
||||
const alexUser = userDB.getUser('user-001'); // Alex Thompson - ResourceProvider
|
||||
|
||||
const mockSlices = [
|
||||
{
|
||||
|
@@ -12,11 +12,11 @@ class UserDatabase {
|
||||
const mockUsers = [
|
||||
{
|
||||
id: 'user-001',
|
||||
username: 'sara_farmer',
|
||||
username: 'sara_resource_provider',
|
||||
display_name: 'Sara Nicks',
|
||||
email: 'user1@example.com',
|
||||
password: 'password',
|
||||
role: 'farmer',
|
||||
role: 'resource_provider',
|
||||
location: 'Amsterdam, Netherlands',
|
||||
joined_date: '2024-01-15',
|
||||
reputation: 4.8,
|
||||
@@ -84,7 +84,7 @@ class UserDatabase {
|
||||
display_name: 'Jordan Mitchell',
|
||||
email: 'user5@example.com',
|
||||
password: 'password',
|
||||
role: 'multi', // Can be farmer, app_provider, service_provider, user
|
||||
role: 'multi', // Can be resource_provider, app_provider, service_provider, user
|
||||
location: 'Toronto, Canada',
|
||||
joined_date: new Date().toISOString().split('T')[0],
|
||||
reputation: 5.0,
|
||||
|
@@ -14,7 +14,7 @@ impl DataValidator {
|
||||
|
||||
if let Value::Object(ref mut obj) = value {
|
||||
Self::repair_user_activities(obj)?;
|
||||
Self::repair_farmer_settings(obj)?;
|
||||
Self::repair_resource_provider_settings(obj)?;
|
||||
Self::ensure_required_fields(obj)?;
|
||||
}
|
||||
|
||||
@@ -47,20 +47,20 @@ impl DataValidator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Repairs farmer settings to include all required fields
|
||||
fn repair_farmer_settings(obj: &mut Map<String, Value>) -> Result<(), String> {
|
||||
if let Some(Value::Object(ref mut farmer_settings)) = obj.get_mut("farmer_settings") {
|
||||
/// Repairs resource_provider settings to include all required fields
|
||||
fn repair_resource_provider_settings(obj: &mut Map<String, Value>) -> Result<(), String> {
|
||||
if let Some(Value::Object(ref mut resource_provider_settings)) = obj.get_mut("resource_provider_settings") {
|
||||
// Ensure minimum_deployment_duration exists
|
||||
if !farmer_settings.contains_key("minimum_deployment_duration") {
|
||||
farmer_settings.insert(
|
||||
if !resource_provider_settings.contains_key("minimum_deployment_duration") {
|
||||
resource_provider_settings.insert(
|
||||
"minimum_deployment_duration".to_string(),
|
||||
Value::Number(serde_json::Number::from(24))
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure preferred_regions exists
|
||||
if !farmer_settings.contains_key("preferred_regions") {
|
||||
farmer_settings.insert(
|
||||
if !resource_provider_settings.contains_key("preferred_regions") {
|
||||
resource_provider_settings.insert(
|
||||
"preferred_regions".to_string(),
|
||||
Value::Array(vec![
|
||||
Value::String("NA".to_string()),
|
||||
@@ -83,7 +83,7 @@ impl DataValidator {
|
||||
("apps", Value::Array(vec![])),
|
||||
("app_deployments", Value::Array(vec![])),
|
||||
("nodes", Value::Array(vec![])),
|
||||
("farmer_earnings", Value::Array(vec![])),
|
||||
("resource_provider_earnings", Value::Array(vec![])),
|
||||
("user_activities", Value::Array(vec![])),
|
||||
("pool_positions", Value::Object(Map::new())),
|
||||
];
|
||||
|
@@ -78,7 +78,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/farmer" class="btn btn-outline-info w-100 mb-2">
|
||||
<a href="/dashboard/resource_provider" class="btn btn-outline-info w-100 mb-2">
|
||||
<i class="bi bi-hdd-rack me-2"></i> Add a Mycelium Node
|
||||
</a>
|
||||
</div>
|
||||
@@ -117,11 +117,11 @@
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-success badge-role">FARMER</span>
|
||||
<h4>Farmer Dashboard</h4>
|
||||
<span class="badge bg-success badge-role">RESOURCE PROVIDER</span>
|
||||
<h4>Resource Provider Dashboard</h4>
|
||||
<p>Manage your nodes, create slices, set pricing, and track earnings.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/farmer" class="btn btn-sm btn-outline-success">Access Farmer Dashboard</a>
|
||||
<a href="/dashboard/resource_provider" class="btn btn-sm btn-outline-success">Access Resource Provider Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -28,9 +28,9 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'farmer' %}active{% endif %}" href="/dashboard/farmer">
|
||||
<a class="nav-link {% if active_section == 'resource_provider' %}active{% endif %}" href="/dashboard/resource_provider">
|
||||
<i class="bi bi-hdd-rack me-1"></i>
|
||||
Farmer
|
||||
Resource Provider
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
|
@@ -1,10 +1,10 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Farmer{% endblock %}
|
||||
{% block title %}ThreeFold Dashboard - Resource Provider{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>Farmer Dashboard</h1>
|
||||
<h1>Resource Provider Dashboard</h1>
|
||||
<p class="lead">Manage your nodes, configure slices, and monitor earnings</p>
|
||||
|
||||
<!-- Status Summary -->
|
||||
@@ -13,8 +13,8 @@
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Active Nodes</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0" id="active-nodes-count">{{ farmer_stats.online_nodes }}</h2>
|
||||
<small class="text-muted">of {{ farmer_stats.total_nodes }} total</small>
|
||||
<h2 class="mb-0" id="active-nodes-count">{{ resource provider_stats.online_nodes }}</h2>
|
||||
<small class="text-muted">of {{ resource provider_stats.total_nodes }} total</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,8 +22,8 @@
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Allocated Slices</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0" id="active-slices-count">{{ farmer_stats.allocated_base_slices }}</h2>
|
||||
<small class="text-muted">of {{ farmer_stats.total_base_slices }} total</small>
|
||||
<h2 class="mb-0" id="active-slices-count">{{ resource provider_stats.allocated_base_slices }}</h2>
|
||||
<small class="text-muted">of {{ resource provider_stats.total_base_slices }} total</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Monthly Earnings</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0" id="monthly-earnings">{{ farmer_stats.monthly_earnings }}</h2>
|
||||
<h2 class="mb-0" id="monthly-earnings">{{ resource provider_stats.monthly_earnings }}</h2>
|
||||
<small class="text-muted">$/month</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -187,7 +187,7 @@
|
||||
<div class="stats-card primary">
|
||||
<h6 class="card-title">Total Base Slices</h6>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h3 class="mb-0" id="total-base-slices">{{ farmer_stats.total_base_slices }}</h3>
|
||||
<h3 class="mb-0" id="total-base-slices">{{ resource provider_stats.total_base_slices }}</h3>
|
||||
<small class="text-muted">Available</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,7 +196,7 @@
|
||||
<div class="stats-card success">
|
||||
<h6 class="card-title">Allocated Slices</h6>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h3 class="mb-0" id="allocated-base-slices">{{ farmer_stats.allocated_base_slices }}</h3>
|
||||
<h3 class="mb-0" id="allocated-base-slices">{{ resource provider_stats.allocated_base_slices }}</h3>
|
||||
<small class="text-muted">Rented</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -205,7 +205,7 @@
|
||||
<div class="stats-card info">
|
||||
<h6 class="card-title">Available Slices</h6>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h3 class="mb-0" id="available-base-slices">{{ farmer_stats.available_base_slices }}</h3>
|
||||
<h3 class="mb-0" id="available-base-slices">{{ resource provider_stats.available_base_slices }}</h3>
|
||||
<small class="text-muted">For Rent</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,7 +214,7 @@
|
||||
<div class="stats-card warning">
|
||||
<h6 class="card-title">Utilization</h6>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h3 class="mb-0" id="slice-utilization">{{ farmer_stats.slice_utilization_percentage }}%</h3>
|
||||
<h3 class="mb-0" id="slice-utilization">{{ resource provider_stats.slice_utilization_percentage }}%</h3>
|
||||
<small class="text-muted">Capacity</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -238,8 +238,8 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="node-slices-table">
|
||||
{% if farmer_nodes %}
|
||||
{% for node in farmer_nodes %}
|
||||
{% if resource provider_nodes %}
|
||||
{% for node in resource provider_nodes %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
@@ -396,8 +396,8 @@
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
|
||||
<!-- Load farmer dashboard JavaScript -->
|
||||
<script src="/static/js/dashboard-farmer.js"></script>
|
||||
<!-- Load resource provider dashboard JavaScript -->
|
||||
<script src="/static/js/dashboard-resource_provider.js"></script>
|
||||
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
@@ -55,7 +55,7 @@
|
||||
<div class="display-4 mb-3 text-success">
|
||||
<i class="bi bi-hdd-rack"></i>
|
||||
</div>
|
||||
<h5>As a Farmer</h5>
|
||||
<h5>As a Resource Provider</h5>
|
||||
<p>Manage nodes, configure slices, set pricing</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -341,7 +341,7 @@
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-people me-2 text-success"></i>Community Building</h5>
|
||||
<p class="card-text">Connects hardware providers with potential farmers</p>
|
||||
<p class="card-text">Connects hardware providers with potential resource providers</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -78,7 +78,7 @@
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-hdd-rack me-2"></i>Farmers</h5>
|
||||
<h5 class="card-title"><i class="bi bi-hdd-rack me-2"></i>Resource Providers</h5>
|
||||
<p class="card-text">Contribute compute capacity to the ThreeFold Grid and earn through the platform's ecosystem.</p>
|
||||
<a href="/docs" class="btn btn-outline-primary">Learn More</a>
|
||||
</div>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Farmers Terms and Conditions - Project Mycelium{% endblock %}
|
||||
{% block title %}Resource Providers Terms and Conditions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
@@ -9,25 +9,25 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Farmers</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Resource Providers</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-hdd-rack fs-1 me-3 text-primary"></i>
|
||||
<h1>Farmers Terms and Conditions</h1>
|
||||
<h1>Resource Providers Terms and Conditions</h1>
|
||||
</div>
|
||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-0">These terms specifically apply to Farmers (Resource Providers) on the Project Mycelium who contribute capacity to the Mycelium Grid.</p>
|
||||
<p class="mb-0">These terms specifically apply to Resource Providers (Resource Providers) on the Project Mycelium who contribute capacity to the Mycelium Grid.</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Definition of a Farmer</h2>
|
||||
<p>A "Farmer" refers to any individual or entity that connects hardware resources to the Mycelium Grid, including but not limited to compute nodes (Mycelium Nodes), storage capacity, network infrastructure, or other compatible devices that contribute to the Mycelium Grid's capacity.</p>
|
||||
<h2>1. Definition of a Resource Provider</h2>
|
||||
<p>A "Resource Provider" refers to any individual or entity that connects hardware resources to the Mycelium Grid, including but not limited to compute nodes (Mycelium Nodes), storage capacity, network infrastructure, or other compatible devices that contribute to the Mycelium Grid's capacity.</p>
|
||||
|
||||
<h2>2. Farmer Responsibilities</h2>
|
||||
<p>As a Farmer on the Project Mycelium, you agree to:</p>
|
||||
<h2>2. Resource Provider Responsibilities</h2>
|
||||
<p>As a Resource Provider on the Project Mycelium, you agree to:</p>
|
||||
<ul>
|
||||
<li>Maintain your connected hardware in good working condition with adequate internet connectivity</li>
|
||||
<li>Ensure your hardware meets the minimum technical requirements specified in the Farming documentation</li>
|
||||
@@ -37,7 +37,7 @@
|
||||
</ul>
|
||||
|
||||
<h2>3. Reputation System and Staking</h2>
|
||||
<p>The Project Mycelium employs a reputation system that affects farmer visibility and rewards:</p>
|
||||
<p>The Project Mycelium employs a reputation system that affects resource provider visibility and rewards:</p>
|
||||
<ul>
|
||||
<li>Your reputation score is calculated based on multiple factors including uptime, staked Credits, and performance metrics</li>
|
||||
<li>Staking Credits increases your reputation score and may qualify you for additional benefits</li>
|
||||
@@ -48,10 +48,10 @@
|
||||
<h2>4. Rewards and Credits</h2>
|
||||
<p>Compensation for resource contribution is governed by the following principles:</p>
|
||||
<ul>
|
||||
<li>Farmers receive USD Credits based on the resources utilized from their contributed capacity</li>
|
||||
<li>Resource Providers receive USD Credits based on the resources utilized from their contributed capacity</li>
|
||||
<li>Credits have a fixed value of 1.0 USD per Credit</li>
|
||||
<li>Earned Credits can be exchanged for fiat currencies or other supported tokens through the available liquidity pools</li>
|
||||
<li>Payment schedules and minimum thresholds are detailed in the Farmer dashboard</li>
|
||||
<li>Payment schedules and minimum thresholds are detailed in the Resource Provider dashboard</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Hardware and Capacity</h2>
|
||||
@@ -72,8 +72,8 @@
|
||||
<li>Slashing penalties may include reputation reduction, temporary suspension, or in severe cases, permanent removal from the marketplace</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Termination of Farmer Status</h2>
|
||||
<p>You may cease being a Farmer by:</p>
|
||||
<h2>7. Termination of Resource Provider Status</h2>
|
||||
<p>You may cease being a Resource Provider by:</p>
|
||||
<ul>
|
||||
<li>Disconnecting your hardware from the Mycelium Grid</li>
|
||||
<li>Providing notice through your dashboard at least 30 days prior to complete disconnection</li>
|
||||
@@ -81,7 +81,7 @@
|
||||
</ul>
|
||||
|
||||
<h2>8. Liability Limitation</h2>
|
||||
<p>As a Farmer, you acknowledge that:</p>
|
||||
<p>As a Resource Provider, you acknowledge that:</p>
|
||||
<ul>
|
||||
<li>ThreeFold is not responsible for any damage to your hardware resulting from normal operation</li>
|
||||
<li>ThreeFold does not guarantee minimum income or utilization rates for your contributed capacity</li>
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
<div class="alert alert-warning mt-5">
|
||||
<h5 class="alert-heading">Important Note</h5>
|
||||
<p class="mb-0">These Farmer-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
|
||||
<p class="mb-0">These Resource Provider-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 mb-3">
|
@@ -18,9 +18,9 @@
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-hdd-rack fs-1 mb-3 text-primary"></i>
|
||||
<h5 class="card-title">Farmers</h5>
|
||||
<h5 class="card-title">Resource Providers</h5>
|
||||
<p class="card-text">Resource Providers contributing capacity to the ThreeFold Grid</p>
|
||||
<a href="/terms/farmers" class="btn btn-outline-primary mt-3">View Terms</a>
|
||||
<a href="/terms/resource providers" class="btn btn-outline-primary mt-3">View Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -129,8 +129,8 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="provider-name">
|
||||
{% if product_data.product.attributes.farmer_email %}
|
||||
{{ product_data.product.attributes.farmer_email.value | truncate(length=15) }}
|
||||
{% if product_data.product.attributes.resource provider_email %}
|
||||
{{ product_data.product.attributes.resource provider_email.value | truncate(length=15) }}
|
||||
{% else %}
|
||||
{% if product_data.product.provider %}{{ product_data.product.provider }}{% else %}Unknown{% endif %}
|
||||
{% endif %}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<h5 class="alert-heading">What are Mycelium Nodes?</h5>
|
||||
<p>Mycelium Nodes are the physical hardware units that make up the Mycelium Grid. These certified servers provide compute, storage, and network capacity to the decentralized internet infrastructure.</p>
|
||||
<hr>
|
||||
<p class="mb-0">By purchasing a Mycelium Node, you become a farmer in the Mycelium ecosystem, earning MC rewards while contributing to the decentralized internet.</p>
|
||||
<p class="mb-0">By purchasing a Mycelium Node, you become a resource provider in the Mycelium ecosystem, earning MC rewards while contributing to the decentralized internet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -302,7 +302,7 @@
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Become a Mycelium Farmer</h3>
|
||||
<h3 class="card-title">Become a Mycelium Resource Provider</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h5>1. Purchase Your Mycelium Node</h5>
|
||||
@@ -322,7 +322,7 @@
|
||||
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>ROI Potential:</strong> Mycelium Node farmers typically see return on investment within 2-4 years, depending on grid utilization and MC price.
|
||||
<strong>ROI Potential:</strong> Mycelium Node resource providers typically see return on investment within 2-4 years, depending on grid utilization and MC price.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -24,7 +24,7 @@
|
||||
<strong>Node:</strong> {{ slice.node_id }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Farmer:</strong> {{ slice.farmer_email }}
|
||||
<strong>Resource Provider:</strong> {{ slice.resource provider_email }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Specifications:</strong>
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="card-body">
|
||||
<form id="sliceRentalForm" method="POST" action="/marketplace/slice/rent">
|
||||
<!-- Hidden fields -->
|
||||
<input type="hidden" name="farmer_email" value="{{ farmer_email }}">
|
||||
<input type="hidden" name="resource provider_email" value="{{ resource provider_email }}">
|
||||
<input type="hidden" name="node_id" value="{{ node_id }}">
|
||||
<input type="hidden" name="combination_id" value="{{ combination_id }}">
|
||||
|
||||
|
Reference in New Issue
Block a user