Skip to content

Commit

Permalink
backend, frontend: add geographic restrictions to access tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
Synar authored and ElysaSrc committed Jun 29, 2024
1 parent 9afb528 commit cdd19e8
Show file tree
Hide file tree
Showing 15 changed files with 323 additions and 12 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions backend/migrations/20240322224255_requests_for_entities_cache.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CREATE OR REPLACE FUNCTION fetch_entities_within_view(
input_ymin DOUBLE PRECISION,
input_xmax DOUBLE PRECISION,
input_ymax DOUBLE PRECISION,
geographic_restriction TEXT,
input_family_id UUID,

allow_all_categories BOOL,
Expand Down Expand Up @@ -55,6 +56,10 @@ BEGIN
ec.web_mercator_location,
ST_MakeEnvelope(input_xmin, input_ymin, input_xmax, input_ymax, 3857)
)
AND (
geographic_restriction IS NULL OR
ST_Intersects(ec.web_mercator_location, st_geomfromtext(geographic_restriction))
)
AND NOT ec.hidden
AND ec.family_id = input_family_id
-- Categories filter
Expand Down Expand Up @@ -139,6 +144,7 @@ $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION search_entities(
search_query TEXT,
geographic_restriction TEXT,
input_family_id UUID,

allow_all_categories BOOL,
Expand Down Expand Up @@ -191,6 +197,10 @@ BEGIN
OR (full_text_search_ts @@ plainto_tsquery(search_query))
)
)
AND (
geographic_restriction IS NULL OR
ST_Intersects(ec.web_mercator_location, st_geomfromtext(geographic_restriction))
)
AND ec.family_id = input_family_id
AND NOT ec.hidden
-- Categories
Expand Down
2 changes: 2 additions & 0 deletions backend/src/api/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ pub async fn viewer_view_request(
ymin: request.ymin,
xmax: request.xmax,
ymax: request.ymax,
geographic_restriction: token.perms.geographic_restrictions.clone(),
family_id: request.family_id,
allow_all_categories: token.perms.categories_policy.allow_all,
allow_all_tags: token.perms.tags_policy.allow_all,
Expand Down Expand Up @@ -185,6 +186,7 @@ async fn viewer_search_request(

let request = SearchEntitiesRequest {
search_query: request.search_query,
geographic_restriction: token.perms.geographic_restrictions.clone(),
family_id: request.family_id,
allow_all_categories: token.perms.categories_policy.allow_all,
allow_all_tags: token.perms.tags_policy.allow_all,
Expand Down
3 changes: 3 additions & 0 deletions backend/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
root::{self, BootstrapResponse, SafeMode, StatusResponse},
ErrorResponse,
},
helpers::postgis_polygons::MultiPolygon,
models::{
access_token::{
AccessToken, AccessTokenStats, NewOrUpdateAccessToken, PermissionPolicy, Permissions,
Expand Down Expand Up @@ -193,6 +194,8 @@ use utoipa::OpenApi;
NewCommentRequest,
PublicNewEntityRequest,
FetchedEntity,
// helper postgis polygons
MultiPolygon,
))
)]
pub struct ApiDoc {}
1 change: 1 addition & 0 deletions backend/src/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod deserializers;
pub mod hcaptcha;
pub mod postgis_polygons;
72 changes: 72 additions & 0 deletions backend/src/helpers/postgis_polygons.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

pub type Coordinates = (f64, f64);
pub type Polygon = Vec<Coordinates>;

#[derive(Serialize, Deserialize, Debug, Clone, ToSchema)]
pub struct MultiPolygon(Vec<Polygon>);

impl MultiPolygon {
pub fn to_polygon_string(&self, srid: Option<u32>) -> String {
let polygons_str = self
.0
.iter()
.map(|polygon| {
let coords_str = polygon
.iter()
.map(|&(x, y)| format!("{} {}", x, y))
.collect::<Vec<_>>()
.join(", ");
format!("({})", coords_str)
})
.collect::<Vec<_>>()
.join("),(");

match srid {
Some(srid) => format!("SRID={};MULTIPOLYGON(({}))", srid, polygons_str),
None => format!("MULTIPOLYGON(({}))", polygons_str),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_to_polygon_string() {
let multi_polygon = MultiPolygon(vec![
vec![(30.0, 20.0), (45.0, 40.0), (10.0, 40.0), (30.0, 20.0)],
vec![
(15.0, 5.0),
(40.0, 10.0),
(10.0, 20.0),
(5.0, 10.0),
(15.0, 5.0),
],
]);

let expected_string =
"MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))";
assert_eq!(multi_polygon.to_polygon_string(None), expected_string);
}

#[test]
fn test_to_polygon_string_with_srid() {
let multi_polygon = MultiPolygon(vec![
vec![(30.0, 20.0), (45.0, 40.0), (10.0, 40.0), (30.0, 20.0)],
vec![
(15.0, 5.0),
(40.0, 10.0),
(10.0, 20.0),
(5.0, 10.0),
(15.0, 5.0),
],
]);

let expected_string =
"SRID=3857;MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))";
assert_eq!(multi_polygon.to_polygon_string(Some(3857)), expected_string);
}
}
3 changes: 2 additions & 1 deletion backend/src/models/access_token.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::api::AppError;
use crate::{api::AppError, helpers::postgis_polygons::MultiPolygon};
use serde::{Deserialize, Serialize};
use serde_json::{to_value, Value};
use sqlx::{types::Json, PgConnection};
Expand All @@ -10,6 +10,7 @@ pub struct Permissions {
pub families_policy: PermissionPolicy,
pub categories_policy: PermissionPolicy,
pub tags_policy: PermissionPolicy,
pub geographic_restrictions: Option<MultiPolygon>,
pub can_access_comments: bool,
}

Expand Down
16 changes: 13 additions & 3 deletions backend/src/models/entity_cache.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use crate::api::AppError;
use crate::{api::AppError, helpers::postgis_polygons::MultiPolygon};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::{query_as, types::Json, PgConnection};
Expand Down Expand Up @@ -206,6 +206,7 @@ pub struct FindEntitiesRequest {
pub ymin: f64,
pub xmax: f64,
pub ymax: f64,
pub geographic_restriction: Option<MultiPolygon>,
pub family_id: Uuid,

pub allow_all_categories: bool,
Expand All @@ -228,6 +229,7 @@ pub struct FindEntitiesRequest {

pub struct SearchEntitiesRequest {
pub search_query: String,
pub geographic_restriction: Option<MultiPolygon>,
pub family_id: Uuid,

pub allow_all_categories: bool,
Expand Down Expand Up @@ -294,13 +296,17 @@ impl ViewerCachedEntity {
$14,
$15,
$16,
$17
$17,
$18
)
"#,
request.xmin,
request.ymin,
request.xmax,
request.ymax,
request
.geographic_restriction
.map(|g| g.to_polygon_string(Some(3857))),
request.family_id,
request.allow_all_categories,
request.allow_all_tags,
Expand Down Expand Up @@ -408,10 +414,14 @@ impl ViewerCachedEntity {
$12,
$13,
$14,
$15
$15,
$16
)
"#,
request.search_query,
request
.geographic_restriction
.map(|g| g.to_polygon_string(Some(3857))),
request.family_id,
request.allow_all_categories,
request.allow_all_tags,
Expand Down
4 changes: 4 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
cargo sqlx prepare --check
echo "::endgroup::"
echo "::group::Backend tests"
cargo test
echo "::endgroup::"
echo "::group::Backend lint"
cargo fmt -- --check
cargo clippy -- -D warnings
Expand Down
Loading

0 comments on commit cdd19e8

Please sign in to comment.