diff --git a/backend/src/controllers/mo_controller.rs b/backend/src/controllers/mo_controller.rs index c02d6254..ce5a1489 100644 --- a/backend/src/controllers/mo_controller.rs +++ b/backend/src/controllers/mo_controller.rs @@ -1,8 +1,17 @@ +use axum::extract::Query; +use serde::Deserialize; +#[derive(Deserialize, Default)] +#[serde(default)] +pub struct MoQuery { + pub org_id: Option, + pub service_id: Option, +} use crate::dto::top_polluting_site_dto::TopPollutingSite; use crate::green_score::calculate_green_score; use crate::service::advice_service::AdviceService; use crate::service::equivalent_service::EquivalentService; use crate::service::organisation_service::OrganisationService; +use crate::service::service_service::ServiceService; use crate::models::equivalent::Equivalent; use axum::extract::State; use axum::Json; @@ -25,17 +34,33 @@ pub struct MyOrganizationResponse { pub weekly_consumption: Vec, pub monthly_consumption: Vec, pub top_polluting_sites: Vec, + pub is_admin: bool, + pub services: Option>, } -pub async fn mo(State(pool): State, AuthenticatedUser(user_full): AuthenticatedUser) -> Result, AppError> { +pub async fn mo( + State(pool): State, + Query(query): Query, + AuthenticatedUser(user_full): AuthenticatedUser +) -> Result, AppError> { - let organization = user_full.organisation.first().ok_or(AppError::NotFound("User is not in an organization".to_string()))?; + let organization = if let Some(oid) = query.org_id { + user_full.organisation.iter().find(|o| o.id == oid).cloned().ok_or(AppError::NotFound("User is not in the specified organization".to_string()))? + } else { + user_full.organisation.first().cloned().ok_or(AppError::NotFound("User is not in an organization".to_string()))? + }; let organization_id = organization.id; let user_id = user_full.user.id; - let organization_informations = OrganisationService::organization_informations(&pool, organization_id, user_id).await + let service_id = if organization.est_admin { + query.service_id + } else { + user_full.service.map(|s| s.id) + }; + + let organization_informations = OrganisationService::organization_informations(&pool, organization_id, user_id, service_id).await .map_err(AppError::from)?; let advices: Vec = vec![ @@ -48,15 +73,23 @@ pub async fn mo(State(pool): State, AuthenticatedUser(user_full): Aut let equivalents = EquivalentService::equivalent(&pool, Some(user_id), 2, organization_informations.total_consumption).await .ok(); - let daily_consumption = OrganisationService::get_daily_organization_consumption(&pool, organization_id).await + let daily_consumption = OrganisationService::get_daily_organization_consumption(&pool, organization_id, service_id).await .map_err(AppError::from)?; - let weekly_consumption = OrganisationService::get_weekly_organization_consumption(&pool, organization_id).await + let weekly_consumption = OrganisationService::get_weekly_organization_consumption(&pool, organization_id, service_id).await .map_err(AppError::from)?; - let monthly_consumption = OrganisationService::get_monthly_organization_consumption(&pool, organization_id).await + let monthly_consumption = OrganisationService::get_monthly_organization_consumption(&pool, organization_id, service_id).await .map_err(AppError::from)?; - let top_polluting_sites = OrganisationService::get_top5_polluting_sites_by_organization(&pool, organization_id).await + let top_polluting_sites = OrganisationService::get_top5_polluting_sites_by_organization(&pool, organization_id, service_id).await .map_err(AppError::from)?; + let is_admin = organization.est_admin; + + let services = if is_admin { + ServiceService::get_organisation_services(&pool, organization_id).await.ok() + } else { + None + }; + Ok(Json(MyOrganizationResponse { success: true, mo_infos: Some(organization_informations), @@ -67,6 +100,8 @@ pub async fn mo(State(pool): State, AuthenticatedUser(user_full): Aut daily_consumption, weekly_consumption, monthly_consumption, - top_polluting_sites + top_polluting_sites, + is_admin, + services, })) } \ No newline at end of file diff --git a/backend/src/repository/monitored_website_repository.rs b/backend/src/repository/monitored_website_repository.rs index 3144a32d..74dff5f2 100644 --- a/backend/src/repository/monitored_website_repository.rs +++ b/backend/src/repository/monitored_website_repository.rs @@ -52,22 +52,32 @@ impl MonitoredWebsiteRepository { pub async fn get_top5_polluting_sites_by_organization( pool: &MySqlPool, - org_id: i64 + org_id: i64, service_id: Option ) -> Result, Error> { - let results = sqlx::query_as::<_, TopPollutingSite>( + let mut query = sqlx::QueryBuilder::new( "SELECT mw.url_domain, SUM(mw.carbon_footprint) as total_footprint FROM monitored_website mw JOIN user u ON u.id = mw.user_id - WHERE u.organisation_id = ? - AND mw.url_domain IS NOT NULL + JOIN organisation_user ou + ON ou.user_id = u.id + WHERE ou.organisation_id = " + ); + query.push_bind(org_id); + + if let Some(sid) = service_id { + query.push(" AND u.service_id = "); + query.push_bind(sid); + } + + query.push(" AND mw.url_domain IS NOT NULL GROUP BY mw.url_domain ORDER BY total_footprint - DESC LIMIT 5" - ) - .bind(org_id) + DESC LIMIT 5"); + + let results = query.build_query_as::() .fetch_all(pool) .await?; Ok(results) @@ -96,9 +106,9 @@ impl MonitoredWebsiteRepository { pub async fn average_daily_carbon_footprint_for_organization( pool: &MySqlPool, - org_id: i64 + org_id: i64, service_id: Option ) -> f64 { - sqlx::query_as::<_, (f64,)>( + let mut query = sqlx::QueryBuilder::new( "SELECT ROUND( COALESCE( SUM(mw.carbon_footprint) / NULLIF(DATEDIFF(CURDATE(), MIN(DATE(mw.creation_date))) + 1, 0) @@ -106,9 +116,17 @@ impl MonitoredWebsiteRepository { , 2) AS average_daily_carbon_footprint FROM monitored_website mw JOIN user u ON u.id = mw.user_id - WHERE u.organisation_id = ?" - ) - .bind(org_id) + JOIN organisation_user ou ON ou.user_id = u.id + WHERE ou.organisation_id = " + ); + query.push_bind(org_id); + + if let Some(sid) = service_id { + query.push(" AND u.service_id = "); + query.push_bind(sid); + } + + query.build_query_as::<(f64,)>() .fetch_one(pool) .await .map(|(val,)| val) @@ -117,16 +135,25 @@ impl MonitoredWebsiteRepository { pub async fn total_organization_consumption( pool: &MySqlPool, - org_id: i64 + org_id: i64, service_id: Option ) -> Result, Error> { - sqlx::query_as::<_, (Option,)>( - "SELECT SUM(mw.carbon_footprint) as total_consumption - FROM monitored_website mw - JOIN user u - ON mw.user_id = u.id - WHERE u.organisation_id = ?", - ) - .bind(org_id) + let mut query = sqlx::QueryBuilder::new( + "SELECT SUM(mw.carbon_footprint) as total_consumption + FROM monitored_website mw + JOIN user u + ON mw.user_id = u.id + JOIN organisation_user ou + ON ou.user_id = u.id + WHERE ou.organisation_id = " + ); + query.push_bind(org_id); + + if let Some(sid) = service_id { + query.push(" AND u.service_id = "); + query.push_bind(sid); + } + + query.build_query_as::<(Option,)>() .fetch_one(pool) .await .map(|(val,)| val) @@ -237,57 +264,84 @@ impl MonitoredWebsiteRepository { Ok(result) } - pub async fn get_daily_organization_consumption(pool: &MySqlPool, orga_id: i64) -> Result, Error> + pub async fn get_daily_organization_consumption(pool: &MySqlPool, orga_id: i64, service_id: Option) -> Result, Error> { - let result = sqlx::query_as::<_, ConsumptionDataPoint>( + let mut query = sqlx::QueryBuilder::new( "SELECT DATE_FORMAT(mw.creation_date, '%d/%m') as label, SUM(mw.carbon_footprint) as value FROM monitored_website mw JOIN user u ON u.id = mw.user_id - WHERE u.organisation_id = ? - AND mw.creation_date >= DATE_SUB(NOW(), INTERVAL 7 DAY) + JOIN organisation_user ou ON ou.user_id = u.id + WHERE ou.organisation_id = " + ); + query.push_bind(orga_id); + + if let Some(sid) = service_id { + query.push(" AND u.service_id = "); + query.push_bind(sid); + } + + query.push(" AND mw.creation_date >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(mw.creation_date), label - ORDER BY DATE(mw.creation_date) ASC" - ) - .bind(orga_id) + ORDER BY DATE(mw.creation_date) ASC"); + + let result = query.build_query_as::() .fetch_all(pool) .await?; Ok(result) } - pub async fn get_weekly_organization_consumption(pool: &MySqlPool, orga_id: i64) -> Result, Error> + pub async fn get_weekly_organization_consumption(pool: &MySqlPool, orga_id: i64, service_id: Option) -> Result, Error> { - let result = sqlx::query_as::<_, ConsumptionDataPoint>( + let mut query = sqlx::QueryBuilder::new( "SELECT CONCAT('Semaine ', WEEK(mw.creation_date, 1)) as label, SUM(mw.carbon_footprint) as value FROM monitored_website mw JOIN user u ON u.id = mw.user_id - WHERE u.organisation_id = ? - AND mw.creation_date >= DATE_SUB(NOW(), INTERVAL 4 WEEK) + JOIN organisation_user ou ON ou.user_id = u.id + WHERE ou.organisation_id = " + ); + query.push_bind(orga_id); + + if let Some(sid) = service_id { + query.push(" AND u.service_id = "); + query.push_bind(sid); + } + + query.push(" AND mw.creation_date >= DATE_SUB(NOW(), INTERVAL 4 WEEK) GROUP BY WEEK(mw.creation_date, 1), label - ORDER BY WEEK(mw.creation_date, 1) ASC" - ) - .bind(orga_id) + ORDER BY WEEK(mw.creation_date, 1) ASC"); + + let result = query.build_query_as::() .fetch_all(pool) .await?; Ok(result) } - pub async fn get_monthly_organization_consumption(pool: &MySqlPool, org_id: i64) -> Result, Error> + pub async fn get_monthly_organization_consumption(pool: &MySqlPool, org_id: i64, service_id: Option) -> Result, Error> { - let result = sqlx::query_as::<_, ConsumptionDataPoint>( + let mut query = sqlx::QueryBuilder::new( "SELECT DATE_FORMAT(mw.creation_date, '%m/%Y') as label, SUM(mw.carbon_footprint) as value FROM monitored_website mw JOIN user u ON u.id = mw.user_id - WHERE u.organisation_id = ? - AND mw.creation_date >= DATE_SUB(NOW(), INTERVAL 12 MONTH) + JOIN organisation_user ou ON ou.user_id = u.id + WHERE ou.organisation_id = " + ); + query.push_bind(org_id); + + if let Some(sid) = service_id { + query.push(" AND u.service_id = "); + query.push_bind(sid); + } + + query.push(" AND mw.creation_date >= DATE_SUB(NOW(), INTERVAL 12 MONTH) GROUP BY MONTH(mw.creation_date), YEAR(mw.creation_date), label - ORDER BY YEAR(mw.creation_date), MONTH(mw.creation_date) ASC" - ) - .bind(org_id) + ORDER BY YEAR(mw.creation_date), MONTH(mw.creation_date) ASC"); + + let result = query.build_query_as::() .fetch_all(pool) .await?; Ok(result) diff --git a/backend/src/service/monitored_website_service.rs b/backend/src/service/monitored_website_service.rs index 91d9147a..a7d8ddc7 100644 --- a/backend/src/service/monitored_website_service.rs +++ b/backend/src/service/monitored_website_service.rs @@ -117,18 +117,17 @@ impl MonitoredWebsiteService { .collect()) } - pub async fn average_daily_carbon_footprint_for_organization(pool: &MySqlPool, org_id: i64) -> f64 { - let avg = MonitoredWebsiteRepository::average_daily_carbon_footprint_for_organization(pool, org_id).await; - (avg * 100.0).round() / 100.0 + pub async fn average_daily_carbon_footprint_for_organization(pool: &MySqlPool, org_id: i64, service_id: Option) -> f64 { + MonitoredWebsiteRepository::average_daily_carbon_footprint_for_organization(pool, org_id, service_id).await } pub async fn get_daily_consumption_by_user( pool: &MySqlPool, user_id: i64 ) -> Result, Error> { - let daily_consumption: Vec = MonitoredWebsiteRepository::get_daily_consumption_by_user(pool, user_id).await?; + let daily_consumtion: Vec = MonitoredWebsiteRepository::get_daily_consumption_by_user(pool, user_id).await?; - Ok(daily_consumption.into_iter() + Ok(daily_consumtion.into_iter() .map(|consumption_data_point: ConsumptionDataPoint| ConsumptionDataPoint { label: consumption_data_point.label, value: (consumption_data_point.value * 100.0).round() / 100.0 @@ -136,9 +135,8 @@ impl MonitoredWebsiteService { .collect()) } - pub async fn total_organization_consumption(pool: &MySqlPool, org_id: i64) -> Result, Error> { - let total = MonitoredWebsiteRepository::total_organization_consumption(pool, org_id).await?; - Ok(total.map(|t| (t * 100.0).round() / 100.0)) + pub async fn total_organization_consumption(pool: &MySqlPool, org_id: i64, service_id: Option) -> Result, Error> { + MonitoredWebsiteRepository::total_organization_consumption(pool, org_id, service_id).await } pub async fn get_weekly_consumption_by_user( diff --git a/backend/src/service/organisation_service.rs b/backend/src/service/organisation_service.rs index ed518ea9..ed887129 100644 --- a/backend/src/service/organisation_service.rs +++ b/backend/src/service/organisation_service.rs @@ -19,11 +19,11 @@ impl OrganisationService { pub async fn find_id_by_siret(pool: &MySqlPool, siret: String) -> Result, Error> { OrganisationRepository::find_id_by_siret(pool, &siret).await } - pub async fn organization_informations(pool: &MySqlPool, orga_id: i64, user_id: i64) -> Result + pub async fn organization_informations(pool: &MySqlPool, orga_id: i64, user_id: i64, service_id: Option) -> Result { let name: String = OrganisationRepository::organization_name(pool, orga_id).await.unwrap_or(None).unwrap_or_else(|| "Organisation inconnue".to_string()); - let average_daily_carbon_footprint: f64 = MonitoredWebsiteService::average_daily_carbon_footprint_for_organization(pool, orga_id).await; - let total_consumption: f64 = MonitoredWebsiteService::total_organization_consumption(pool, orga_id).await.unwrap_or(None).unwrap_or(0.0); + let average_daily_carbon_footprint: f64 = MonitoredWebsiteService::average_daily_carbon_footprint_for_organization(pool, orga_id, service_id).await; + let total_consumption: f64 = MonitoredWebsiteService::total_organization_consumption(pool, orga_id, service_id).await.unwrap_or(None).unwrap_or(0.0); let equivalent = EquivalentService::equivalent(pool, Some(user_id), 1, total_consumption).await.ok().and_then(|mut v| v.pop()); @@ -35,20 +35,20 @@ impl OrganisationService { }) } - pub async fn get_daily_organization_consumption(pool: &MySqlPool, orga_id: i64) -> Result, Error> { - MonitoredWebsiteRepository::get_daily_organization_consumption(pool, orga_id).await + pub async fn get_daily_organization_consumption(pool: &MySqlPool, orga_id: i64, service_id: Option) -> Result, Error> { + MonitoredWebsiteRepository::get_daily_organization_consumption(pool, orga_id, service_id).await } - pub async fn get_weekly_organization_consumption(pool: &MySqlPool, orga_id: i64) -> Result, Error> { - MonitoredWebsiteRepository::get_weekly_organization_consumption(pool, orga_id).await + pub async fn get_weekly_organization_consumption(pool: &MySqlPool, orga_id: i64, service_id: Option) -> Result, Error> { + MonitoredWebsiteRepository::get_weekly_organization_consumption(pool, orga_id, service_id).await } - pub async fn get_monthly_organization_consumption(pool: &MySqlPool, orga_id: i64) -> Result, Error> { - MonitoredWebsiteRepository::get_monthly_organization_consumption(pool, orga_id).await + pub async fn get_monthly_organization_consumption(pool: &MySqlPool, orga_id: i64, service_id: Option) -> Result, Error> { + MonitoredWebsiteRepository::get_monthly_organization_consumption(pool, orga_id, service_id).await } - pub async fn get_top5_polluting_sites_by_organization(pool: &MySqlPool, org_id: i64) -> Result, Error> { - let top_polluting_sites: Vec = MonitoredWebsiteRepository::get_top5_polluting_sites_by_organization(pool, org_id).await?; + pub async fn get_top5_polluting_sites_by_organization(pool: &MySqlPool, org_id: i64, service_id: Option) -> Result, Error> { + let top_polluting_sites: Vec = MonitoredWebsiteRepository::get_top5_polluting_sites_by_organization(pool, org_id, service_id).await?; Ok(top_polluting_sites.into_iter() .map(|top_polluting_site: TopPollutingSite| TopPollutingSite { diff --git a/backend/tests/monitored_website_repository_tests.rs b/backend/tests/monitored_website_repository_tests.rs index eed7ccad..8859610d 100644 --- a/backend/tests/monitored_website_repository_tests.rs +++ b/backend/tests/monitored_website_repository_tests.rs @@ -125,10 +125,9 @@ async fn devrait_retourner_top5_polluting_sites_by_organization(pool: MySqlPool) .unwrap(); let org_id = result.last_insert_id() as i64; - // Update user avec organisation - sqlx::query("UPDATE user SET organisation_id = ? WHERE id = ?") - .bind(org_id) + sqlx::query("INSERT INTO organisation_user (user_id, organisation_id, est_admin) VALUES (?, ?, false)") .bind(user_id) + .bind(org_id) .execute(&pool) .await .unwrap(); @@ -151,7 +150,7 @@ async fn devrait_retourner_top5_polluting_sites_by_organization(pool: MySqlPool) } // WHEN - let top5 = MonitoredWebsiteRepository::get_top5_polluting_sites_by_organization(&pool, org_id).await.unwrap(); + let top5 = MonitoredWebsiteRepository::get_top5_polluting_sites_by_organization(&pool, org_id, None).await.unwrap(); // THEN assert_eq!(top5.len(), 5, "Devrait retourner 5 sites pour l'organisation"); @@ -170,9 +169,9 @@ async fn devrait_retourner_total_organization_consumption(pool: MySqlPool) { .unwrap(); let org_id = result.last_insert_id() as i64; - sqlx::query("UPDATE user SET organisation_id = ? WHERE id = ?") - .bind(org_id) + sqlx::query("INSERT INTO organisation_user (user_id, organisation_id, est_admin) VALUES (?, ?, false)") .bind(user_id) + .bind(org_id) .execute(&pool) .await .unwrap(); @@ -198,7 +197,7 @@ async fn devrait_retourner_total_organization_consumption(pool: MySqlPool) { MonitoredWebsiteRepository::save_monitored_website_data(&pool, &website2).await.unwrap(); // WHEN - let total = MonitoredWebsiteRepository::total_organization_consumption(&pool, org_id).await.unwrap(); + let total = MonitoredWebsiteRepository::total_organization_consumption(&pool, org_id, None).await.unwrap(); // THEN assert_eq!(total, Some(30.0), "Total conso orga incorrect"); @@ -238,8 +237,8 @@ async fn devrait_retourner_average_daily_carbon_footprint_for_organization(pool: .unwrap(); let org_id = result.last_insert_id() as i64; - sqlx::query("UPDATE user SET organisation_id = ? WHERE id = ?") - .bind(org_id).bind(user_id).execute(&pool).await.unwrap(); + sqlx::query("INSERT INTO organisation_user (user_id, organisation_id, est_admin) VALUES (?, ?, false)") + .bind(user_id).bind(org_id).execute(&pool).await.unwrap(); let website = MonitoredWebsite { id: 1, url_domain: "site1.com".to_string(), user_id, queries_quantity: 10, data_transferred: 100, resources: 5, loading_time: 1.5, @@ -248,7 +247,7 @@ async fn devrait_retourner_average_daily_carbon_footprint_for_organization(pool: MonitoredWebsiteRepository::save_monitored_website_data(&pool, &website).await.unwrap(); // WHEN - let average = MonitoredWebsiteRepository::average_daily_carbon_footprint_for_organization(&pool, org_id).await; + let average = MonitoredWebsiteRepository::average_daily_carbon_footprint_for_organization(&pool, org_id, None).await; // THEN // 1 jour, total 100 -> moyenne 100 @@ -351,15 +350,15 @@ async fn devrait_retourner_get_daily_organization_consumption(pool: MySqlPool) { // Assigner à l'organisation for uid in [u1, u2] { - sqlx::query("UPDATE user SET organisation_id = ? WHERE id = ?") - .bind(org_id).bind(uid).execute(&pool).await.unwrap(); + sqlx::query("INSERT INTO organisation_user (user_id, organisation_id, est_admin) VALUES (?, ?, false)") + .bind(uid).bind(org_id).execute(&pool).await.unwrap(); } insert_measure(&pool, u1, 10.0, "NOW()").await; insert_measure(&pool, u2, 20.0, "NOW()").await; // WHEN - let result = MonitoredWebsiteRepository::get_daily_organization_consumption(&pool, org_id).await.unwrap(); + let result = MonitoredWebsiteRepository::get_daily_organization_consumption(&pool, org_id, None).await.unwrap(); // THEN assert_eq!(result.len(), 1, "Devrait avoir 1 jour de données"); @@ -374,14 +373,14 @@ async fn devrait_retourner_get_weekly_organization_consumption(pool: MySqlPool) let org_id = result.last_insert_id() as i64; let u3 = create_test_user(&pool).await; - sqlx::query("UPDATE user SET organisation_id = ? WHERE id = ?") - .bind(org_id).bind(u3).execute(&pool).await.unwrap(); + sqlx::query("INSERT INTO organisation_user (user_id, organisation_id, est_admin) VALUES (?, ?, false)") + .bind(u3).bind(org_id).execute(&pool).await.unwrap(); insert_measure(&pool, u3, 100.0, "NOW()").await; insert_measure(&pool, u3, 50.0, "DATE_SUB(NOW(), INTERVAL 2 WEEK)").await; // WHEN - let result = MonitoredWebsiteRepository::get_weekly_organization_consumption(&pool, org_id).await.unwrap(); + let result = MonitoredWebsiteRepository::get_weekly_organization_consumption(&pool, org_id, None).await.unwrap(); // THEN assert_eq!(result.len(), 2, "2 semaines de données attendues"); @@ -398,14 +397,14 @@ async fn devrait_retourner_get_monthly_organization_consumption(pool: MySqlPool) let org_id = result.last_insert_id() as i64; let u4 = create_test_user(&pool).await; - sqlx::query("UPDATE user SET organisation_id = ? WHERE id = ?") - .bind(org_id).bind(u4).execute(&pool).await.unwrap(); + sqlx::query("INSERT INTO organisation_user (user_id, organisation_id, est_admin) VALUES (?, ?, false)") + .bind(u4).bind(org_id).execute(&pool).await.unwrap(); insert_measure(&pool, u4, 200.0, "NOW()").await; insert_measure(&pool, u4, 100.0, "DATE_SUB(NOW(), INTERVAL 3 MONTH)").await; // WHEN - let result = MonitoredWebsiteRepository::get_monthly_organization_consumption(&pool, org_id).await.unwrap(); + let result = MonitoredWebsiteRepository::get_monthly_organization_consumption(&pool, org_id, None).await.unwrap(); // THEN assert_eq!(result.len(), 2, "2 mois de données attendues"); diff --git a/backend/tests/organisation_service_tests.rs b/backend/tests/organisation_service_tests.rs index 514ba01d..51bad86d 100644 --- a/backend/tests/organisation_service_tests.rs +++ b/backend/tests/organisation_service_tests.rs @@ -24,7 +24,7 @@ mod tests { let user_id = 1; // WHEN - let infos = OrganisationService::organization_informations(&pool, org_id, user_id).await.unwrap(); + let infos = OrganisationService::organization_informations(&pool, org_id, user_id, None).await.unwrap(); // THEN assert_eq!(infos.name, "Test Organisation"); @@ -97,7 +97,7 @@ mod tests { let org_id = 1; // WHEN - let res = OrganisationService::get_daily_organization_consumption(&pool, org_id).await; + let res = OrganisationService::get_daily_organization_consumption(&pool, org_id, None).await; // THEN assert!(res.is_ok(), "Devrait récupérer les données journalières"); @@ -109,7 +109,7 @@ mod tests { let org_id = 1; // WHEN - let res = OrganisationService::get_weekly_organization_consumption(&pool, org_id).await; + let res = OrganisationService::get_weekly_organization_consumption(&pool, org_id, None).await; // THEN assert!(res.is_ok(), "Devrait récupérer les données hebdomadaires"); @@ -121,7 +121,7 @@ mod tests { let org_id = 1; // WHEN - let res = OrganisationService::get_monthly_organization_consumption(&pool, org_id).await; + let res = OrganisationService::get_monthly_organization_consumption(&pool, org_id, None).await; // THEN assert!(res.is_ok(), "Devrait récupérer les données mensuelles"); @@ -144,7 +144,7 @@ mod tests { .unwrap(); // WHEN - let res = OrganisationService::get_top5_polluting_sites_by_organization(&pool, org_id).await; + let res = OrganisationService::get_top5_polluting_sites_by_organization(&pool, org_id, None).await; // THEN assert!(res.is_ok(), "Devrait récupérer le top 5 des sites polluants"); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8c8164c6..347c8780 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1042,6 +1042,7 @@ "integrity": "sha512-dCYqelr2RVnWUuxc+Dk/dB/SjV/8JBndp1UovCyCZdIQezd8TRwFLNZctYkzgHxRJtaNvseCSRsuuHPeUgIN/A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", @@ -1085,6 +1086,7 @@ "integrity": "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "debug": "^4.4.1", @@ -1448,6 +1450,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2403,6 +2406,7 @@ "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -2501,6 +2505,7 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.43.8.tgz", "integrity": "sha512-d53/xClCjHsuFXuHsn7+F/0NKkkwgRv8kLg2his5YBYqVtfIrBqkvWd+5ZjYN6ryk/jv/rJF00vexXHkK8ofXA==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -2999,7 +3004,8 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tapable": { "version": "2.3.0", @@ -3083,6 +3089,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3113,6 +3120,7 @@ "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", diff --git a/frontend/src/lib/components/widgets/OrganizationAverageDailyCarbonFootprint.svelte b/frontend/src/lib/components/widgets/OrganizationAverageDailyCarbonFootprint.svelte index 33f3e3d6..8359ada1 100644 --- a/frontend/src/lib/components/widgets/OrganizationAverageDailyCarbonFootprint.svelte +++ b/frontend/src/lib/components/widgets/OrganizationAverageDailyCarbonFootprint.svelte @@ -36,7 +36,7 @@ {#if equivalentAverage.icon}
- {equivalentAverage.name} e.currentTarget.src = '/images/equivalent.png'}> + {equivalentAverage.name} { const target = e.currentTarget; if(target instanceof HTMLImageElement) target.src = '/images/equivalent.png'; }}>
{/if} diff --git a/frontend/src/routes/(app)/mon-compte/+page.server.ts b/frontend/src/routes/(app)/mon-compte/+page.server.ts index 786adff6..95213a94 100644 --- a/frontend/src/routes/(app)/mon-compte/+page.server.ts +++ b/frontend/src/routes/(app)/mon-compte/+page.server.ts @@ -11,6 +11,7 @@ export const load: PageServerLoad = async ({ fetch, request, locals, url }) => { let members = []; let services = []; + let accountEquivalents = []; const orgIdParam = url.searchParams.get('orgId'); let targetOrgId = orgIdParam ? parseInt(orgIdParam) : null; @@ -51,12 +52,26 @@ export const load: PageServerLoad = async ({ fetch, request, locals, url }) => { } } + const equivRes = await fetch(`${BACKEND_URL}/account/equivalents`, { + method: 'GET', + headers, + credentials: 'include' + }); + if (equivRes.ok) { + try { + const result = await equivRes.json(); + if (result.success && result.equivalents) { + accountEquivalents = result.equivalents; + } + } catch {} + } + return { userFull: locals.user, members, services, organisation: targetOrg, - accountEquivalents: (locals.user as any)?.equivalents || [], + accountEquivalents, currentOrgId: targetOrgId }; }; diff --git a/frontend/src/routes/(app)/mon-organisation/+page.server.ts b/frontend/src/routes/(app)/mon-organisation/+page.server.ts index c6b7c626..0a91a2d4 100644 --- a/frontend/src/routes/(app)/mon-organisation/+page.server.ts +++ b/frontend/src/routes/(app)/mon-organisation/+page.server.ts @@ -25,7 +25,7 @@ function formatMonthlyData(data: Array<{ label: string; value: number }>, locale return result; } -export const load: PageServerLoad = async ({ fetch, request }) => { +export const load: PageServerLoad = async ({ fetch, request, url }) => { try { const cookieHeader = request.headers.get('cookie') || ''; let locale = 'fr'; @@ -33,7 +33,8 @@ export const load: PageServerLoad = async ({ fetch, request }) => { locale = 'en'; } - const response = await fetch(`${BACKEND_URL}/mon-organisation`, { + let query = url.searchParams.toString(); + const response = await fetch(`${BACKEND_URL}/mon-organisation${query ? '?' + query : ''}`, { method: 'GET', headers: { 'Content-Type': 'application/json', @@ -42,7 +43,6 @@ export const load: PageServerLoad = async ({ fetch, request }) => { credentials: 'include' }); const result = await response.json(); - if (!result.success) { return { organisationData: null, @@ -74,6 +74,10 @@ export const load: PageServerLoad = async ({ fetch, request }) => { weeklyConsumption: result.weekly_consumption || [], monthlyConsumption: formatMonthlyData(result.monthly_consumption || [], locale), topPollutingSites: result.top_polluting_sites || [], + isAdmin: result.is_admin || false, + services: result.services || [], + currentOrgId: url.searchParams.get('org_id') || null, + currentServiceId: url.searchParams.get('service_id') || null, }; } catch (error) { @@ -89,6 +93,10 @@ export const load: PageServerLoad = async ({ fetch, request }) => { weeklyConsumption: [], monthlyConsumption: formatMonthlyData([], 'fr'), topPollutingSites: [], + isAdmin: false, + services: [], + currentOrgId: null, + currentServiceId: null, }; } } \ No newline at end of file diff --git a/frontend/src/routes/(app)/mon-organisation/+page.svelte b/frontend/src/routes/(app)/mon-organisation/+page.svelte index 9bd64222..c2eb9cf4 100644 --- a/frontend/src/routes/(app)/mon-organisation/+page.svelte +++ b/frontend/src/routes/(app)/mon-organisation/+page.svelte @@ -8,6 +8,7 @@ import Advice from "$lib/components/widgets/Advice.svelte"; import type { PageData } from './$types'; import { t } from 'svelte-i18n'; + import { goto } from '$app/navigation'; export let data: PageData; @@ -40,6 +41,35 @@ $: consumptionData = selectedPeriod === 'daily' ? dailyConsumption : selectedPeriod === 'weekly' ? weeklyConsumption : monthlyConsumption; + + $: isAdmin = data.isAdmin; + $: services = data.services || []; + $: userOrgs = data.userFull?.organisation || []; + $: memberService = data.userFull?.service; + + let selectedOrgId = data.currentOrgId || ''; + let selectedServiceId = data.currentServiceId || ''; + $: selectedOrgIdNumber = selectedOrgId ? Number(selectedOrgId) : null; + $: memberServiceName = + !isAdmin && + memberService && + selectedOrgIdNumber !== null && + memberService.id_organisation === selectedOrgIdNumber + ? memberService.nom + : ''; + + $: { + if (!selectedOrgId && userOrgs.length > 0) { + selectedOrgId = userOrgs[0].id.toString(); + } + } + + function handleFilterChange() { + let qs = new URLSearchParams(); + if (selectedOrgId) qs.set('org_id', selectedOrgId); + if (selectedServiceId) qs.set('service_id', selectedServiceId); + goto(`?${qs.toString()}`); + } @@ -54,6 +84,34 @@ { description }

{/if} +
+ {#if userOrgs.length > 1} +
+ + +
+ {/if} + {#if isAdmin} +
+ + +
+ {:else if memberServiceName} +
+ {$t('account.service.name_label')}: + {memberServiceName} +
+ {/if} +
{#if !noDatas}