diff --git a/server/src/double_labeled_graph.rs b/server/src/double_labeled_graph.rs index d529c48..a53007f 100644 --- a/server/src/double_labeled_graph.rs +++ b/server/src/double_labeled_graph.rs @@ -115,4 +115,27 @@ impl DoubleLabeledGraph { hi_edges, } } + + pub fn only_roots(&self) -> DoubleLabeledGraph { + todo!() + } + + pub fn only_node_with_successors_roots(&self, node: String) -> DoubleLabeledGraph { + todo!() + } + + pub fn nodes_iter(&self) -> impl Iterator + '_ { + self.node_labels.iter().map(|(k, v)| (k.clone(), v.clone())) + } + + pub fn edges_iter(&self) -> impl Iterator + '_ { + self.lo_edges + .iter() + .map(|(k, v)| (k.clone(), v.clone(), "lo".to_string())) + .chain( + self.hi_edges + .iter() + .map(|(k, v)| (k.clone(), v.clone(), "hi".to_string())), + ) + } } diff --git a/server/src/main.rs b/server/src/main.rs index 44342c3..b68417e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -18,20 +18,18 @@ use actix_cors::Cors; mod adf; mod config; mod double_labeled_graph; -mod user; mod pmc_vis; +mod user; use adf::{ add_adf_problem, delete_adf_problem, get_adf_problem, get_adf_problems_for_user, solve_adf_problem, }; use config::{AppState, ASSET_DIRECTORY, COOKIE_DURATION}; +use pmc_vis::{pmc_vis_get_initial, pmc_vis_get_outgoing}; use user::{ create_username_index, delete_account, login, logout, register, update_user, user_info, }; -use pmc_vis::{ - pmc_vis_get_initial, pmc_vis_get_outgoing, -}; #[actix_web::main] async fn main() -> std::io::Result<()> { diff --git a/server/src/pmc_vis.rs b/server/src/pmc_vis.rs index eaeae45..af12936 100644 --- a/server/src/pmc_vis.rs +++ b/server/src/pmc_vis.rs @@ -1,8 +1,12 @@ +use crate::{ + adf::{AcAndGraph, AdfProblem, OptionWithError}, + config::{AppState, RunningInfo, Task, ADF_COLL, COMPUTE_TIME, DB_NAME, USER_COLL}, + double_labeled_graph::DoubleLabeledGraph, +}; use actix_identity::Identity; -use actix_web::{get, web, HttpResponse, Responder, http::header}; -use serde::Deserialize; -use crate::config::AppState; - +use actix_web::{get, http::header, web, HttpResponse, Responder}; +use mongodb::bson::doc; +use serde::{Deserialize, Serialize}; const DUMMY_INITIAL: &str = r#"{ "nodes": [ @@ -126,7 +130,7 @@ const DUMMY_INITIAL: &str = r#"{ ] }"#; -const DUMMY_OUTGOING : &str = r#"{ +const DUMMY_OUTGOING: &str = r#"{ "nodes": [ { "id": "0", @@ -802,18 +806,131 @@ const DUMMY_OUTGOING : &str = r#"{ ] }"#; -#[get("/{problem_id}/initial")] +#[derive(Serialize)] +struct PmcVisNode { + id: String, + name: String, + #[serde(rename = "type")] + node_type: String, +} + +#[derive(Serialize)] +struct PmcVisEdge { + source: String, + target: String, + label: String, +} + +struct PmcVisGraph { + nodes: Vec, + edges: Vec, +} + +impl From for PmcVisGraph { + fn from(graph: DoubleLabeledGraph) -> Self { + PmcVisGraph { + nodes: graph + .nodes_iter() + .map(|(k, v)| PmcVisNode { + id: k, + name: v, + node_type: "s".to_string(), + }) + .collect(), + edges: graph + .edges_iter() + .map(|(s, t, l)| PmcVisEdge { + source: s, + target: t, + label: l, + }) + .collect(), + } + } +} + +#[derive(Serialize)] +struct PmcVisInfo { + #[serde(rename = "ID")] + id: String, +} + +#[derive(Serialize)] +struct PmcVisDto { + nodes: Vec, + edges: Vec, + info: PmcVisInfo, +} + +impl PmcVisDto { + fn from_pmc_vis_graph_and_id(graph: PmcVisGraph, id: String) -> Self { + Self { + nodes: graph.nodes, + edges: graph.edges, + info: PmcVisInfo { id }, + } + } +} + +#[get("/{problem_name}/initial")] async fn pmc_vis_get_initial( - _app_state: web::Data, - _identity: Option, + app_state: web::Data, + identity: Option, path: web::Path, ) -> impl Responder { - let _problem_id = path.into_inner(); + let problem_name = path.into_inner(); - HttpResponse::Ok() - .append_header(header::ContentType::json()) - .body(DUMMY_INITIAL) - // HttpResponse::Ok().json(...) + let adf_coll: mongodb::Collection = app_state + .mongodb_client + .database(DB_NAME) + .collection(ADF_COLL); + + let username = match identity.map(|id| id.id()) { + None => { + return HttpResponse::Unauthorized().body("You need to login to get an ADF problem.") + } + Some(Err(err)) => return HttpResponse::InternalServerError().body(err.to_string()), + Some(Ok(username)) => username, + }; + + let adf_problem = match adf_coll + .find_one(doc! { "name": &problem_name, "username": &username }, None) + .await + { + Err(err) => return HttpResponse::InternalServerError().body(err.to_string()), + Ok(None) => { + return HttpResponse::NotFound() + .body(format!("ADF problem with name {problem_name} not found.")) + } + Ok(Some(prob)) => prob, + }; + + let parse_only_graph: DoubleLabeledGraph = match adf_problem.acs_per_strategy.parse_only { + OptionWithError::None => { + return HttpResponse::BadRequest().body("The ADF problem has not been parsed yet.") + } + OptionWithError::Error(err) => { + return HttpResponse::BadRequest().body(format!( + "The ADF problem could not be parsed. Update it and try again. Error: {err}" + )) + } + OptionWithError::Some(acs_and_graphs) => { + acs_and_graphs + .first() + .expect("There should be exacly one graph in the parsing result.") + .clone() + .graph + } + }; + + HttpResponse::Ok().json(PmcVisDto::from_pmc_vis_graph_and_id( + PmcVisGraph::from(parse_only_graph.only_roots()), + problem_name, + )) + + // HttpResponse::Ok() + // .append_header(header::ContentType::json()) + // .body(DUMMY_INITIAL) } #[derive(Deserialize)] @@ -823,16 +940,63 @@ struct OutgoingQuery { #[get("/{problem_id}/outgoing")] async fn pmc_vis_get_outgoing( - _app_state: web::Data, - _identity: Option, + app_state: web::Data, + identity: Option, path: web::Path, query: web::Query, ) -> impl Responder { - let _problem_id = path.into_inner(); - let _node_id = &query.id; + let problem_name = path.into_inner(); + let node_id = &query.id; - HttpResponse::Ok() - .append_header(header::ContentType::json()) - .body(DUMMY_OUTGOING) - // HttpResponse::Ok().json(...) + let adf_coll: mongodb::Collection = app_state + .mongodb_client + .database(DB_NAME) + .collection(ADF_COLL); + + let username = match identity.map(|id| id.id()) { + None => { + return HttpResponse::Unauthorized().body("You need to login to get an ADF problem.") + } + Some(Err(err)) => return HttpResponse::InternalServerError().body(err.to_string()), + Some(Ok(username)) => username, + }; + + let adf_problem = match adf_coll + .find_one(doc! { "name": &problem_name, "username": &username }, None) + .await + { + Err(err) => return HttpResponse::InternalServerError().body(err.to_string()), + Ok(None) => { + return HttpResponse::NotFound() + .body(format!("ADF problem with name {problem_name} not found.")) + } + Ok(Some(prob)) => prob, + }; + + let parse_only_graph: DoubleLabeledGraph = match adf_problem.acs_per_strategy.parse_only { + OptionWithError::None => { + return HttpResponse::BadRequest().body("The ADF problem has not been parsed yet.") + } + OptionWithError::Error(err) => { + return HttpResponse::BadRequest().body(format!( + "The ADF problem could not be parsed. Update it and try again. Error: {err}" + )) + } + OptionWithError::Some(acs_and_graphs) => { + acs_and_graphs + .first() + .expect("There should be exacly one graph in the parsing result.") + .clone() + .graph + } + }; + + HttpResponse::Ok().json(PmcVisDto::from_pmc_vis_graph_and_id( + PmcVisGraph::from(parse_only_graph.only_node_with_successors_roots(node_id.to_string())), + problem_name, + )) + + // HttpResponse::Ok() + // .append_header(header::ContentType::json()) + // .body(DUMMY_OUTGOING) }