Support search by DID
This commit is contained in:
parent
46526fd4be
commit
21df4fa35c
2 changed files with 73 additions and 25 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use tokio_postgres::GenericClient;
|
use tokio_postgres::GenericClient;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -9,12 +11,14 @@ use crate::activitypub::fetcher::helpers::{
|
||||||
};
|
};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::errors::{ValidationError, HttpError};
|
use crate::errors::{ValidationError, HttpError};
|
||||||
|
use crate::ethereum::identity::DidPkh;
|
||||||
use crate::mastodon_api::accounts::types::Account;
|
use crate::mastodon_api::accounts::types::Account;
|
||||||
use crate::mastodon_api::statuses::helpers::build_status_list;
|
use crate::mastodon_api::statuses::helpers::build_status_list;
|
||||||
use crate::models::posts::helpers::can_view_post;
|
use crate::models::posts::helpers::can_view_post;
|
||||||
use crate::models::posts::types::Post;
|
use crate::models::posts::types::Post;
|
||||||
use crate::models::profiles::queries::{
|
use crate::models::profiles::queries::{
|
||||||
search_profile,
|
search_profile,
|
||||||
|
search_profile_by_did,
|
||||||
search_profile_by_wallet_address,
|
search_profile_by_wallet_address,
|
||||||
};
|
};
|
||||||
use crate::models::profiles::types::DbActorProfile;
|
use crate::models::profiles::types::DbActorProfile;
|
||||||
|
@ -28,6 +32,7 @@ enum SearchQuery {
|
||||||
ProfileQuery(String, Option<String>),
|
ProfileQuery(String, Option<String>),
|
||||||
Url(String),
|
Url(String),
|
||||||
WalletAddress(String),
|
WalletAddress(String),
|
||||||
|
Did(DidPkh),
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +53,10 @@ fn parse_profile_query(query: &str) ->
|
||||||
|
|
||||||
fn parse_search_query(search_query: &str) -> SearchQuery {
|
fn parse_search_query(search_query: &str) -> SearchQuery {
|
||||||
let search_query = search_query.trim();
|
let search_query = search_query.trim();
|
||||||
|
// DID is a valid URI so it should be tried before Url::parse
|
||||||
|
if let Ok(did) = DidPkh::from_str(search_query) {
|
||||||
|
return SearchQuery::Did(did);
|
||||||
|
};
|
||||||
if Url::parse(search_query).is_ok() {
|
if Url::parse(search_query).is_ok() {
|
||||||
return SearchQuery::Url(search_query.to_string());
|
return SearchQuery::Url(search_query.to_string());
|
||||||
};
|
};
|
||||||
|
@ -163,6 +172,13 @@ pub async fn search(
|
||||||
false,
|
false,
|
||||||
).await?;
|
).await?;
|
||||||
},
|
},
|
||||||
|
SearchQuery::Did(did) => {
|
||||||
|
profiles = search_profile_by_did(
|
||||||
|
db_client,
|
||||||
|
&did,
|
||||||
|
false,
|
||||||
|
).await?;
|
||||||
|
},
|
||||||
SearchQuery::Unknown => (), // ignore
|
SearchQuery::Unknown => (), // ignore
|
||||||
};
|
};
|
||||||
let accounts: Vec<Account> = profiles.into_iter()
|
let accounts: Vec<Account> = profiles.into_iter()
|
||||||
|
|
|
@ -2,6 +2,7 @@ use tokio_postgres::GenericClient;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::database::catch_unique_violation;
|
use crate::database::catch_unique_violation;
|
||||||
|
use crate::database::query_macro::query;
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::ethereum::identity::DidPkh;
|
use crate::ethereum::identity::DidPkh;
|
||||||
use crate::models::cleanup::{
|
use crate::models::cleanup::{
|
||||||
|
@ -377,19 +378,13 @@ pub async fn search_profile(
|
||||||
Ok(profiles)
|
Ok(profiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn search_profile_by_wallet_address(
|
pub async fn search_profile_by_did(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
currency: &Currency,
|
did: &DidPkh,
|
||||||
wallet_address: &str,
|
|
||||||
prefer_verified: bool,
|
prefer_verified: bool,
|
||||||
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
||||||
let field_name = currency.field_name();
|
let did_str = did.to_string();
|
||||||
let did_str = DidPkh::from_address(currency, wallet_address).to_string();
|
let identity_proof_query =
|
||||||
// If currency is Ethereum,
|
|
||||||
// search over extra fields must be case insensitive.
|
|
||||||
// This query does not scan user_account.wallet_address because
|
|
||||||
// login addresses are private by default.
|
|
||||||
let rows = db_client.query(
|
|
||||||
"
|
"
|
||||||
SELECT actor_profile, TRUE AS is_verified
|
SELECT actor_profile, TRUE AS is_verified
|
||||||
FROM actor_profile
|
FROM actor_profile
|
||||||
|
@ -397,22 +392,49 @@ pub async fn search_profile_by_wallet_address(
|
||||||
EXISTS (
|
EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM jsonb_array_elements(actor_profile.identity_proofs) AS proof
|
FROM jsonb_array_elements(actor_profile.identity_proofs) AS proof
|
||||||
WHERE proof ->> 'issuer' = $3
|
WHERE proof ->> 'issuer' = $did
|
||||||
)
|
)
|
||||||
UNION ALL
|
";
|
||||||
SELECT actor_profile, FALSE
|
let rows = if let Some(currency) = did.currency() {
|
||||||
FROM actor_profile
|
// If currency is Ethereum,
|
||||||
WHERE
|
// search over extra fields must be case insensitive.
|
||||||
EXISTS (
|
#[allow(unreachable_patterns)]
|
||||||
SELECT 1
|
let value_op = match currency {
|
||||||
FROM jsonb_array_elements(actor_profile.extra_fields) AS field
|
Currency::Ethereum => "ILIKE",
|
||||||
WHERE
|
_ => "LIKE",
|
||||||
field ->> 'name' ILIKE $1
|
};
|
||||||
AND field ->> 'value' ILIKE $2
|
// This query does not scan user_account.wallet_address because
|
||||||
)
|
// login addresses are private by default.
|
||||||
",
|
let statement = format!(
|
||||||
&[&field_name, &wallet_address, &did_str],
|
"
|
||||||
).await?;
|
{identity_proof_query}
|
||||||
|
UNION ALL
|
||||||
|
SELECT actor_profile, FALSE
|
||||||
|
FROM actor_profile
|
||||||
|
WHERE
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM jsonb_array_elements(actor_profile.extra_fields) AS field
|
||||||
|
WHERE
|
||||||
|
field ->> 'name' ILIKE $field_name
|
||||||
|
AND field ->> 'value' {value_op} $field_value
|
||||||
|
)
|
||||||
|
",
|
||||||
|
identity_proof_query=identity_proof_query,
|
||||||
|
value_op=value_op,
|
||||||
|
);
|
||||||
|
let field_name = currency.field_name();
|
||||||
|
let query = query!(
|
||||||
|
&statement,
|
||||||
|
did=did_str,
|
||||||
|
field_name=field_name,
|
||||||
|
field_value=did.address,
|
||||||
|
)?;
|
||||||
|
db_client.query(query.sql(), query.parameters()).await?
|
||||||
|
} else {
|
||||||
|
let query = query!(identity_proof_query, did=did_str)?;
|
||||||
|
db_client.query(query.sql(), query.parameters()).await?
|
||||||
|
};
|
||||||
let mut verified = vec![];
|
let mut verified = vec![];
|
||||||
let mut unverified = vec![];
|
let mut unverified = vec![];
|
||||||
for row in rows {
|
for row in rows {
|
||||||
|
@ -432,6 +454,16 @@ pub async fn search_profile_by_wallet_address(
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn search_profile_by_wallet_address(
|
||||||
|
db_client: &impl GenericClient,
|
||||||
|
currency: &Currency,
|
||||||
|
wallet_address: &str,
|
||||||
|
prefer_verified: bool,
|
||||||
|
) -> Result<Vec<DbActorProfile>, DatabaseError> {
|
||||||
|
let did = DidPkh::from_address(currency, wallet_address);
|
||||||
|
search_profile_by_did(db_client, &did, prefer_verified).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn update_follower_count(
|
pub async fn update_follower_count(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
profile_id: &Uuid,
|
profile_id: &Uuid,
|
||||||
|
|
Loading…
Reference in a new issue