Skip to content

Commit de96a2a

Browse files
committed
Implement v3 users endpoints
1 parent 3ab14cf commit de96a2a

6 files changed

Lines changed: 292 additions & 19 deletions

File tree

src/osm/osm.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct OsmUserResponse {
6565
user: OsmUser,
6666
}
6767

68-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
68+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
6969
pub struct OsmUser {
7070
pub id: i64,
7171
pub display_name: String,
@@ -80,32 +80,32 @@ pub struct OsmUser {
8080
pub blocks: Blocks,
8181
}
8282

83-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
83+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
8484
pub struct ContributorTerms {
8585
pub agreed: bool,
8686
}
8787

88-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
88+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
8989
pub struct Img {
9090
pub href: String,
9191
}
9292

93-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
93+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
9494
pub struct Changesets {
9595
pub count: i32,
9696
}
9797

98-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
98+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
9999
pub struct Traces {
100100
pub count: i32,
101101
}
102102

103-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
103+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
104104
pub struct Blocks {
105105
received: BlocksReceived,
106106
}
107107

108-
#[derive(Serialize, Deserialize, Clone, PartialEq)]
108+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
109109
pub struct BlocksReceived {
110110
count: i32,
111111
active: i32,

src/server/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ pub async fn run() -> Result<()> {
155155
scope("reports")
156156
.service(report::v3::get)
157157
.service(report::v3::get_by_id),
158+
)
159+
.service(
160+
scope("users")
161+
.service(user::admin::patch_tags)
162+
.service(user::v3::get)
163+
.service(user::v3::get_by_id),
158164
),
159165
)
160166
.service(

src/user/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ pub use model::User;
33
pub use model::UserRepo;
44
pub mod admin;
55
pub mod v2;
6+
pub mod v3;

src/user/model.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use crate::{osm::osm::OsmUser, Error, Result};
22
use deadpool_sqlite::Pool;
33
use rusqlite::{named_params, Connection, OptionalExtension, Row};
4-
use serde_json::Value;
4+
use serde_json::{Map, Value};
55
use std::{collections::HashMap, sync::Arc};
6-
use time::OffsetDateTime;
6+
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
7+
#[cfg(test)]
8+
use tracing::debug;
79

810
pub struct UserRepo {
911
pool: Arc<Pool>,
@@ -12,7 +14,7 @@ pub struct UserRepo {
1214
pub struct User {
1315
pub id: i64,
1416
pub osm_data: OsmUser,
15-
pub tags: HashMap<String, Value>,
17+
pub tags: Map<String, Value>,
1618
pub created_at: OffsetDateTime,
1719
pub updated_at: OffsetDateTime,
1820
pub deleted_at: Option<OffsetDateTime>,
@@ -23,6 +25,13 @@ impl UserRepo {
2325
Self { pool: pool.clone() }
2426
}
2527

28+
#[cfg(test)]
29+
pub fn mock() -> Self {
30+
Self {
31+
pool: Arc::new(crate::test::mock_pool()),
32+
}
33+
}
34+
2635
#[cfg(test)]
2736
pub async fn insert(&self, id: i64, osm_data: &OsmUser) -> Result<User> {
2837
let osm_data = osm_data.clone();
@@ -43,10 +52,10 @@ impl UserRepo {
4352

4453
pub async fn select_updated_since(
4554
&self,
46-
updated_since: &str,
55+
updated_since: &OffsetDateTime,
4756
limit: Option<i64>,
4857
) -> Result<Vec<User>> {
49-
let updated_since = updated_since.to_string();
58+
let updated_since = updated_since.clone();
5059
self.pool
5160
.get()
5261
.await?
@@ -70,6 +79,16 @@ impl UserRepo {
7079
.interact(move |conn| User::patch_tags(id, &tags, conn))
7180
.await?
7281
}
82+
83+
#[cfg(test)]
84+
pub async fn set_updated_at(&self, id: i64, updated_at: &OffsetDateTime) -> Result<User> {
85+
let updated_at = updated_at.clone();
86+
self.pool
87+
.get()
88+
.await?
89+
.interact(move |conn| User::_set_updated_at(id, &updated_at, conn))
90+
.await?
91+
}
7392
}
7493

7594
impl User {
@@ -120,7 +139,7 @@ impl User {
120139
}
121140

122141
pub fn select_updated_since(
123-
updated_since: &str,
142+
updated_since: &OffsetDateTime,
124143
limit: Option<i64>,
125144
conn: &Connection,
126145
) -> Result<Vec<User>> {
@@ -141,7 +160,10 @@ impl User {
141160
Ok(conn
142161
.prepare(query)?
143162
.query_map(
144-
named_params! { ":updated_since": updated_since, ":limit": limit.unwrap_or(i64::MAX) },
163+
named_params! {
164+
":updated_since": updated_since.format(&Rfc3339)?,
165+
":limit": limit.unwrap_or(i64::MAX)
166+
},
145167
mapper(),
146168
)?
147169
.collect::<Result<Vec<_>, _>>()?)
@@ -210,6 +232,31 @@ impl User {
210232

211233
Ok(())
212234
}
235+
236+
#[cfg(test)]
237+
pub fn _set_updated_at(
238+
id: i64,
239+
updated_at: &OffsetDateTime,
240+
conn: &Connection,
241+
) -> Result<User> {
242+
let query = format!(
243+
r#"
244+
UPDATE user
245+
SET updated_at = :updated_at
246+
WHERE rowid = :id
247+
"#
248+
);
249+
debug!(query);
250+
conn.execute(
251+
&query,
252+
named_params! {
253+
":id": id,
254+
":updated_at": updated_at.format(&Rfc3339)?,
255+
},
256+
)?;
257+
Ok(User::select_by_id(id, &conn)?
258+
.ok_or(Error::Rusqlite(rusqlite::Error::QueryReturnedNoRows))?)
259+
}
213260
}
214261

215262
const fn mapper() -> fn(&Row) -> rusqlite::Result<User> {
@@ -232,6 +279,7 @@ const fn mapper() -> fn(&Row) -> rusqlite::Result<User> {
232279
mod test {
233280
use crate::{osm::osm::OsmUser, test::mock_conn, user::User, Result};
234281
use std::collections::HashMap;
282+
use time::macros::datetime;
235283

236284
#[test]
237285
fn insert() -> Result<()> {
@@ -270,7 +318,7 @@ mod test {
270318
)?;
271319
assert_eq!(
272320
2,
273-
User::select_updated_since("2020-01-01T00:00:00Z", None, &conn)?.len()
321+
User::select_updated_since(&datetime!(2020-01-01 00:00:00 UTC), None, &conn)?.len()
274322
);
275323
Ok(())
276324
}

src/user/v2.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,24 @@ use actix_web::web::Redirect;
1111
use actix_web::Either;
1212
use serde::Deserialize;
1313
use serde::Serialize;
14+
use serde_json::Map;
1415
use serde_json::Value;
15-
use std::collections::HashMap;
1616
use time::format_description::well_known::Rfc3339;
1717
use time::OffsetDateTime;
1818

1919
#[derive(Deserialize)]
2020
pub struct GetArgs {
21-
updated_since: Option<String>,
21+
#[serde(default)]
22+
#[serde(with = "time::serde::rfc3339::option")]
23+
updated_since: Option<OffsetDateTime>,
2224
limit: Option<i64>,
2325
}
2426

2527
#[derive(Serialize, Deserialize)]
2628
pub struct GetItem {
2729
pub id: i64,
2830
pub osm_json: OsmUser,
29-
pub tags: HashMap<String, Value>,
31+
pub tags: Map<String, Value>,
3032
#[serde(with = "time::serde::rfc3339")]
3133
pub created_at: OffsetDateTime,
3234
#[serde(with = "time::serde::rfc3339")]
@@ -157,7 +159,7 @@ mod test {
157159
)
158160
.await;
159161
let req = TestRequest::get()
160-
.uri("/?updated_since=2022-01-10")
162+
.uri("/?updated_since=2022-01-10T00:00:00Z")
161163
.to_request();
162164
let res: Vec<GetItem> = test::call_and_read_body_json(&app, req).await;
163165
assert_eq!(res.len(), 1);

0 commit comments

Comments
 (0)