Skip to content

Commit

Permalink
Refactor element model
Browse files Browse the repository at this point in the history
  • Loading branch information
bubelov committed Aug 21, 2024
1 parent a074c42 commit d347210
Show file tree
Hide file tree
Showing 19 changed files with 146 additions and 444 deletions.
21 changes: 12 additions & 9 deletions src/area/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ impl Into<Json<AreaView>> for Area {
mod test {
use crate::area::admin::{AreaView, PatchArgs, PostArgs};
use crate::area::Area;
use crate::element::Element;
use crate::osm::overpass::OverpassElement;
use crate::test::{mock_state, mock_tags, phuket_geo_json};
use crate::{auth, Result};
Expand Down Expand Up @@ -289,18 +290,20 @@ mod test {
tags.insert("geo_json".into(), phuket_geo_json());
Area::insert(tags, &state.conn)?;

let area_element = state
.element_repo
.insert(&OverpassElement {
let area_element = Element::insert(
&OverpassElement {
lat: Some(7.979623499157051),
lon: Some(98.33448362485439),
..OverpassElement::mock(1)
})
.await?;
let area_element = state
.element_repo
.set_tag(area_element.id, "areas", &json!([{"name":"test"}]))
.await?;
},
&state.conn,
)?;
let area_element = Element::set_tag(
area_element.id,
"areas",
&json!([{"name":"test"}]),
&state.conn,
)?;

assert!(
area_element
Expand Down
4 changes: 2 additions & 2 deletions src/area/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ mod test {
};
let area_element = Element::insert(&area_element, &conn)?;
let area_element =
Element::_set_tag(area_element.id, "areas", &json!("[{id:1},{id:2}]"), &conn)?;
Element::set_tag(area_element.id, "areas", &json!("[{id:1},{id:2}]"), &conn)?;
let mut tags = Map::new();
let url_alias = json!("test");
tags.insert("url_alias".into(), url_alias.clone());
Expand Down Expand Up @@ -172,7 +172,7 @@ mod test {
..OverpassElement::mock(1)
};
let area_element = Element::insert(&area_element, &conn)?;
Element::_set_tag(area_element.id, "areas", &json!("[{id:1},{id:2}]"), &conn)?;
Element::set_tag(area_element.id, "areas", &json!("[{id:1},{id:2}]"), &conn)?;
let mut tags = Map::new();
let url_alias = json!("test");
tags.insert("url_alias".into(), url_alias.clone());
Expand Down
3 changes: 0 additions & 3 deletions src/area/v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ pub async fn get_by_id(id: Path<String>, pool: Data<Arc<Pool>>) -> Result<Json<G
#[cfg(test)]
mod test {
use crate::area::Area;
use crate::element::ElementRepo;
use crate::error::{self, ApiError};
use crate::test::mock_state;
use crate::Result;
Expand All @@ -99,7 +98,6 @@ mod test {
let app = test::init_service(
App::new()
.app_data(QueryConfig::default().error_handler(error::query_error_handler))
.app_data(Data::new(ElementRepo::mock()))
.service(scope("/").service(super::get)),
)
.await;
Expand All @@ -115,7 +113,6 @@ mod test {
let app = test::init_service(
App::new()
.app_data(QueryConfig::default().error_handler(error::query_error_handler))
.app_data(Data::new(ElementRepo::mock()))
.service(scope("/").service(super::get)),
)
.await;
Expand Down
3 changes: 2 additions & 1 deletion src/boost/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ pub fn run(osm_type: &str, osm_id: i64, days: i64, conn: &Connection) -> Result<
boost_expires.format(&Iso8601::DEFAULT)?
);

element.set_tag(
Element::set_tag(
element.id,
"boost:expires",
&Value::String(boost_expires.format(&Iso8601::DEFAULT)?),
&conn,
Expand Down
2 changes: 1 addition & 1 deletion src/command/generate_android_icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub async fn run(conn: &Connection) -> Result<()> {

if old_icon != new_icon {
info!(element.id, old_icon, new_icon, "Updating icon");
element.set_tag("icon:android", &new_icon.clone().into(), &conn)?;
Element::set_tag(element.id, "icon:android", &new_icon.clone().into(), &conn)?;
}

if new_icon == "question_mark" {
Expand Down
2 changes: 1 addition & 1 deletion src/command/generate_element_categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub async fn run(conn: &Connection) -> Result<()> {

if new_category != old_category {
info!(element.id, old_category, new_category, "Updating category",);
element.set_tag("category", &new_category.clone().into(), &conn)?;
Element::set_tag(element.id, "category", &new_category.clone().into(), &conn)?;
}

if new_category == "other" {
Expand Down
13 changes: 10 additions & 3 deletions src/command/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ async fn process_elements(fresh_elements: Vec<OverpassElement>, mut db: Connecti

if new_android_icon != old_android_icon {
info!(old_android_icon, new_android_icon, "Updating Android icon");
updated_element = updated_element.set_tag(
updated_element = Element::set_tag(
updated_element.id,
"icon:android",
&new_android_icon.clone().into(),
&tx,
Expand Down Expand Up @@ -223,8 +224,14 @@ async fn process_elements(fresh_elements: Vec<OverpassElement>, mut db: Connecti
let category = element.overpass_data.generate_category();
let android_icon = element.overpass_data.generate_android_icon();

let element = element.set_tag("category", &category.clone().into(), &tx)?;
let element = element.set_tag("icon:android", &android_icon.clone().into(), &tx)?;
let element =
Element::set_tag(element.id, "category", &category.clone().into(), &tx)?;
let element = Element::set_tag(
element.id,
"icon:android",
&android_icon.clone().into(),
&tx,
)?;

info!(category, android_icon);

Expand Down
180 changes: 22 additions & 158 deletions src/element/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ use super::Element;
use crate::{
auth::{self},
discord,
element::ElementRepo,
osm::overpass::OverpassElement,
Error,
};
use actix_web::{
patch, post,
web::{Data, Form, Json, Path},
patch,
web::{Data, Json, Path},
HttpRequest,
};
use deadpool_sqlite::Pool;
Expand Down Expand Up @@ -76,114 +75,28 @@ pub async fn patch(
id: Path<String>,
args: Json<PatchArgs>,
pool: Data<Arc<Pool>>,
repo: Data<ElementRepo>,
) -> Result<Json<ElementView>, Error> {
let token = auth::service::check(&req, &pool).await?;
let int_id = id.parse::<i64>();
let element = match int_id {
Ok(id) => repo.select_by_id(id).await,
Err(_) => {
let id_parts: Vec<&str> = id.split(":").collect();
if id_parts.len() != 2 {
Err(Error::HttpBadRequest("Invalid identifier".into()))?
}
let r#type = id_parts[0];
let id = id_parts[1]
.parse::<i64>()
.map_err(|_| Error::HttpBadRequest("Invalid identifier".into()))?;
repo.select_by_osm_type_and_id(r#type, id).await
}
}?
.ok_or(Error::HttpNotFound(format!(
"There is no element with id = {id}"
)))?;
let element = repo.patch_tags(element.id, &args.tags).await?;
let log_message = format!(
"{} updated element {} https://api.btcmap.org/v3/elements/{}",
token.owner,
element.name(),
element.id,
);
warn!(log_message);
discord::send_message_to_channel(&log_message, discord::CHANNEL_API).await;
Ok(element.into())
}

#[derive(Serialize, Deserialize)]
struct PostTagsArgs {
name: String,
value: String,
}

#[post("{id}/tags")]
pub async fn post_tags(
req: HttpRequest,
id: Path<String>,
args: Form<PostTagsArgs>,
pool: Data<Arc<Pool>>,
repo: Data<ElementRepo>,
) -> Result<Json<ElementView>, Error> {
let token = auth::service::check(&req, &pool).await?;
let id_parts: Vec<&str> = id.split(":").collect();
if id_parts.len() != 2 {
Err(Error::HttpBadRequest("Invalid identifier".into()))?
}
let r#type = id_parts[0];
let id = id_parts[1]
.parse::<i64>()
.map_err(|_| Error::HttpBadRequest("Invalid identifier".into()))?;
let element = repo
.select_by_osm_type_and_id(r#type, id)
let cloned_id = id.clone();
let element = pool
.get()
.await?
.interact(move |conn| Element::select_by_id_or_osm_id(&cloned_id, &conn))
.await??
.ok_or(Error::HttpNotFound(format!(
"There is no element with id = {}",
"There is no area with id or alias = {}",
id,
)))?;
let element = if args.value.len() > 0 {
repo.set_tag(element.id, &args.name, &args.value.clone().into())
.await?
} else {
repo.remove_tag(element.id, &args.name).await?
};
let log_message = format!(
"WARNING: {} used DEPRECATED API to set {} = {}",
token.owner, args.name, args.value,
);
warn!(log_message);
discord::send_message_to_channel(&log_message, discord::CHANNEL_API).await;
Ok(element.into())
}

#[patch("{id}/tags")]
pub async fn patch_tags(
req: HttpRequest,
id: Path<String>,
args: Json<Map<String, Value>>,
pool: Data<Arc<Pool>>,
repo: Data<ElementRepo>,
) -> Result<Json<ElementView>, Error> {
let token = auth::service::check(&req, &pool).await?;
let id_parts: Vec<&str> = id.split(":").collect();
if id_parts.len() != 2 {
Err(Error::HttpBadRequest("Invalid identifier".into()))?
}
let r#type = id_parts[0];
let id = id_parts[1]
.parse::<i64>()
.map_err(|_| Error::HttpBadRequest("Invalid identifier".into()))?;
let element = repo
.select_by_osm_type_and_id(r#type, id)
let element = pool
.get()
.await?
.ok_or(Error::HttpNotFound(format!(
"There is no element with id = {}",
id,
)))?;
let element = repo.patch_tags(element.id, &args).await?;
.interact(move |conn| Element::patch_tags(element.id, &args.tags.clone(), conn))
.await??;
let log_message = format!(
"{} patched tags for element https://api.btcmap.org/v2/elements/{} {}",
"{} updated element {} https://api.btcmap.org/v3/elements/{}",
token.owner,
id,
serde_json::to_string_pretty(&args).unwrap(),
element.name(),
element.id,
);
warn!(log_message);
discord::send_message_to_channel(&log_message, discord::CHANNEL_API).await;
Expand All @@ -192,25 +105,24 @@ pub async fn patch_tags(

#[cfg(test)]
mod test {
use crate::element::admin::{PatchArgs, PostTagsArgs};
use crate::element::ElementRepo;
use crate::element::admin::PatchArgs;
use crate::element::Element;
use crate::osm::overpass::OverpassElement;
use crate::test::mock_state;
use crate::{auth, Result};
use actix_web::http::StatusCode;
use actix_web::test::TestRequest;
use actix_web::web::Data;
use actix_web::{test, App};
use serde_json::{json, Map, Value};
use serde_json::{Map, Value};

#[test]
async fn patch_unauthorized() -> Result<()> {
let state = mock_state().await;
state.element_repo.insert(&OverpassElement::mock(1)).await?;
Element::insert(&OverpassElement::mock(1), &state.conn)?;
let app = test::init_service(
App::new()
.app_data(Data::new(state.pool))
.app_data(Data::new(state.element_repo))
.service(super::patch),
)
.await;
Expand All @@ -227,11 +139,10 @@ mod test {
async fn patch() -> Result<()> {
let state = mock_state().await;
let token = auth::service::mock_token("test", &state.pool).await.secret;
let element = state.element_repo.insert(&OverpassElement::mock(1)).await?;
let element = Element::insert(&OverpassElement::mock(1), &state.conn)?;
let app = test::init_service(
App::new()
.app_data(Data::new(state.pool.clone()))
.app_data(Data::new(ElementRepo::new(&state.pool)))
.app_data(Data::new(state.pool))
.service(super::patch),
)
.await;
Expand All @@ -253,58 +164,11 @@ mod test {
.to_request();
let res = test::call_service(&app, req).await;
assert_eq!(res.status(), StatusCode::OK);
let element = state.element_repo.select_by_id(element.id).await?.unwrap();
let element = Element::select_by_id(element.id, &state.conn)?.unwrap();
assert!(element.tags["string"].is_string());
assert!(element.tags["unsigned"].is_u64());
assert!(element.tags["float"].is_f64());
assert!(element.tags["bool"].is_boolean());
Ok(())
}

#[test]
async fn post_tags() -> Result<()> {
let state = mock_state().await;
let token = auth::service::mock_token("test", &state.pool).await.secret;
let element = state.element_repo.insert(&OverpassElement::mock(1)).await?;
let app = test::init_service(
App::new()
.app_data(Data::new(state.pool))
.app_data(Data::new(state.element_repo))
.service(super::post_tags),
)
.await;
let req = TestRequest::post()
.uri(&format!("/{}/tags", element.overpass_data.btcmap_id()))
.append_header(("Authorization", format!("Bearer {token}")))
.set_form(PostTagsArgs {
name: "foo".into(),
value: "bar".into(),
})
.to_request();
let res = test::call_service(&app, req).await;
assert!(res.status().is_success());
Ok(())
}

#[test]
async fn patch_tags() -> Result<()> {
let state = mock_state().await;
let token = auth::service::mock_token("test", &state.pool).await.secret;
let element = state.element_repo.insert(&OverpassElement::mock(1)).await?;
let app = test::init_service(
App::new()
.app_data(Data::new(state.pool))
.app_data(Data::new(state.element_repo))
.service(super::patch_tags),
)
.await;
let req = TestRequest::patch()
.uri(&format!("/{}/tags", element.overpass_data.btcmap_id()))
.append_header(("Authorization", format!("Bearer {token}")))
.set_json(json!({ "foo": "bar" }))
.to_request();
let res = test::call_service(&app, req).await;
assert_eq!(res.status(), StatusCode::OK);
Ok(())
}
}
1 change: 0 additions & 1 deletion src/element/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
pub mod model;
pub use model::Element;
pub use model::ElementRepo;
pub mod admin;
pub mod service;
pub mod v2;
Expand Down
Loading

0 comments on commit d347210

Please sign in to comment.