Add support for search by Note url

This commit is contained in:
silverpill 2021-11-07 21:07:38 +00:00
parent 284840463c
commit 81d6cf3daf
5 changed files with 65 additions and 13 deletions

View file

@ -3,6 +3,6 @@ pub mod actor;
pub mod constants;
pub mod deliverer;
pub mod fetcher;
mod receiver;
pub mod receiver;
pub mod views;
mod vocabulary;

View file

@ -9,7 +9,7 @@ use crate::config::Config;
use crate::database::{Pool, get_database_client};
use crate::errors::{DatabaseError, HttpError, ValidationError};
use crate::models::attachments::queries::create_attachment;
use crate::models::posts::types::PostCreateData;
use crate::models::posts::types::{Post, PostCreateData};
use crate::models::posts::queries::{
create_post,
get_post_by_id,
@ -101,9 +101,18 @@ pub async fn process_note(
config: &Config,
db_client: &mut impl GenericClient,
object: Object,
) -> Result<(), HttpError> {
) -> Result<Post, HttpError> {
match get_post_by_object_id(db_client, &object.id).await {
Ok(post) => return Ok(post), // post already exists
Err(DatabaseError::NotFound(_)) => (), // continue processing
Err(other_error) => return Err(other_error.into()),
};
let initial_object_id = object.id.clone();
let mut maybe_parent_object_id = object.in_reply_to.clone();
let mut objects = vec![object];
let mut posts = vec![];
// Fetch ancestors by going through inReplyTo references
// TODO: fetch replies too
loop {
@ -133,6 +142,7 @@ pub async fn process_note(
maybe_parent_object_id = object.in_reply_to.clone();
objects.push(object);
}
// Objects are ordered according to their place in reply tree,
// starting with the root
objects.reverse();
@ -189,9 +199,14 @@ pub async fn process_note(
object_id: Some(object.id),
created_at: object.published,
};
create_post(db_client, &author.id, post_data).await?;
let post = create_post(db_client, &author.id, post_data).await?;
posts.push(post);
}
Ok(())
let initial_post = posts.into_iter()
.find(|post| post.object_id.as_ref() == Some(&initial_object_id))
.unwrap();
Ok(initial_post)
}
pub async fn receive_activity(

View file

@ -1,18 +1,21 @@
use regex::Regex;
use tokio_postgres::GenericClient;
use crate::activitypub::fetcher::fetch_profile;
use crate::activitypub::fetcher::{fetch_object, fetch_profile};
use crate::activitypub::receiver::process_note;
use crate::config::Config;
use crate::errors::{ValidationError, HttpError};
use crate::mastodon_api::accounts::types::Account;
use crate::mastodon_api::statuses::types::Status;
use crate::models::posts::types::Post;
use crate::models::profiles::queries::{create_profile, search_profile};
use crate::models::profiles::types::DbActorProfile;
use super::types::SearchResults;
fn parse_search_query(query: &str) ->
fn parse_profile_query(query: &str) ->
Result<(String, Option<String>), ValidationError>
{
let acct_regexp = Regex::new(r"^@?(?P<user>\w+)(@(?P<instance>[\w\.-]+))?").unwrap();
let acct_regexp = Regex::new(r"^@?(?P<user>\w+)(@(?P<instance>[\w\.-]+))?$").unwrap();
let acct_caps = acct_regexp.captures(query)
.ok_or(ValidationError("invalid search query"))?;
let username = acct_caps.name("user")
@ -28,7 +31,13 @@ async fn search_profiles(
db_client: &impl GenericClient,
search_query: &str,
) -> Result<Vec<DbActorProfile>, HttpError> {
let (username, instance) = parse_search_query(search_query)?;
let (username, instance) = match parse_profile_query(search_query) {
Ok(parsed) => parsed,
Err(_) => {
// Not an 'acct' query
return Ok(vec![]);
},
};
let mut profiles = search_profile(db_client, &username, instance.as_ref()).await?;
if profiles.len() == 0 && instance.is_some() {
let instance_uri = instance.unwrap();
@ -50,14 +59,40 @@ async fn search_profiles(
Ok(profiles)
}
async fn search_note(
config: &Config,
db_client: &mut impl GenericClient,
search_query: &str,
) -> Result<Option<Post>, HttpError> {
if url::Url::parse(search_query).is_err() {
// Not a valid URL
return Ok(None);
}
let maybe_post = if let Ok(object) = fetch_object(search_query).await {
let post = process_note(config, db_client, object).await?;
Some(post)
} else {
None
};
Ok(maybe_post)
}
pub async fn search(
config: &Config,
db_client: &impl GenericClient,
db_client: &mut impl GenericClient,
search_query: &str,
) -> Result<SearchResults, HttpError> {
let profiles = search_profiles(config, db_client, search_query).await?;
let accounts: Vec<Account> = profiles.into_iter()
.map(|profile| Account::from_profile(profile, &config.instance_url()))
.collect();
Ok(SearchResults { accounts })
let maybe_post = search_note(config, db_client, search_query).await?;
let statuses = match maybe_post {
Some(post) => {
let status = Status::from_post(post, &config.instance_url());
vec![status]
},
None => vec![],
};
Ok(SearchResults { accounts, statuses })
}

View file

@ -1,6 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::mastodon_api::accounts::types::Account;
use crate::mastodon_api::statuses::types::Status;
/// https://docs.joinmastodon.org/methods/search/
#[derive(Deserialize)]
@ -11,4 +12,5 @@ pub struct SearchQueryParams {
#[derive(Serialize)]
pub struct SearchResults {
pub accounts: Vec<Account>,
pub statuses: Vec<Status>,
}

View file

@ -16,9 +16,9 @@ async fn search_view(
db_pool: web::Data<Pool>,
query_params: web::Query<SearchQueryParams>,
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
let db_client = &mut **get_database_client(&db_pool).await?;
get_current_user(db_client, auth.token()).await?;
let results = search(&config, db_client, &query_params.q).await?;
let results = search(&config, db_client, &query_params.q.trim()).await?;
Ok(HttpResponse::Ok().json(results))
}