Adding shortname fetching for users and communities. Fixes #1662 (#1663)

This commit is contained in:
Dessalines 2021-07-20 00:29:50 -04:00 committed by GitHub
parent f18139d06c
commit 5fe7de2bff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 92 additions and 50 deletions

View file

@ -10,7 +10,7 @@ use lemmy_api_common::{
is_admin, is_admin,
site::*, site::*,
}; };
use lemmy_apub::fetcher::search::search_by_apub_id; use lemmy_apub::{build_actor_id_from_shortname, fetcher::search::search_by_apub_id, EndpointType};
use lemmy_db_queries::{ use lemmy_db_queries::{
from_opt_str_to_opt_enum, from_opt_str_to_opt_enum,
source::site::Site_, source::site::Site_,
@ -167,7 +167,11 @@ impl Perform for Search {
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.listing_type); let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.listing_type);
let search_type: SearchType = from_opt_str_to_opt_enum(&data.type_).unwrap_or(SearchType::All); let search_type: SearchType = from_opt_str_to_opt_enum(&data.type_).unwrap_or(SearchType::All);
let community_id = data.community_id; let community_id = data.community_id;
let community_name = data.community_name.to_owned(); let community_actor_id = data
.community_name
.as_ref()
.map(|t| build_actor_id_from_shortname(EndpointType::Community, t).ok())
.unwrap_or(None);
let creator_id = data.creator_id; let creator_id = data.creator_id;
match search_type { match search_type {
SearchType::Posts => { SearchType::Posts => {
@ -179,7 +183,7 @@ impl Perform for Search {
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.listing_type(listing_type) .listing_type(listing_type)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id)
.creator_id(creator_id) .creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.search_term(q) .search_term(q)
@ -197,7 +201,7 @@ impl Perform for Search {
.search_term(q) .search_term(q)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id)
.creator_id(creator_id) .creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)
@ -234,6 +238,7 @@ impl Perform for Search {
// If the community or creator is included, dont search communities or users // If the community or creator is included, dont search communities or users
let community_or_creator_included = let community_or_creator_included =
data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some(); data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
let community_actor_id_2 = community_actor_id.to_owned();
posts = blocking(context.pool(), move |conn| { posts = blocking(context.pool(), move |conn| {
PostQueryBuilder::create(conn) PostQueryBuilder::create(conn)
@ -243,7 +248,7 @@ impl Perform for Search {
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.listing_type(listing_type) .listing_type(listing_type)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id_2)
.creator_id(creator_id) .creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.search_term(q) .search_term(q)
@ -254,7 +259,7 @@ impl Perform for Search {
.await??; .await??;
let q = data.q.to_owned(); let q = data.q.to_owned();
let community_name = data.community_name.to_owned(); let community_actor_id = community_actor_id.to_owned();
comments = blocking(context.pool(), move |conn| { comments = blocking(context.pool(), move |conn| {
CommentQueryBuilder::create(conn) CommentQueryBuilder::create(conn)
@ -263,7 +268,7 @@ impl Perform for Search {
.search_term(q) .search_term(q)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id)
.creator_id(creator_id) .creator_id(creator_id)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)
@ -316,7 +321,7 @@ impl Perform for Search {
.listing_type(listing_type) .listing_type(listing_type)
.my_person_id(person_id) .my_person_id(person_id)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id)
.creator_id(creator_id) .creator_id(creator_id)
.url_search(q) .url_search(q)
.page(page) .page(page)

View file

@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetCommunity { pub struct GetCommunity {
pub id: Option<CommunityId>, pub id: Option<CommunityId>,
/// Example: star_trek , or star_trek@xyz.tld
pub name: Option<String>, pub name: Option<String>,
pub auth: Option<String>, pub auth: Option<String>,
} }

View file

@ -82,6 +82,7 @@ pub struct LoginResponse {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetPersonDetails { pub struct GetPersonDetails {
pub person_id: Option<PersonId>, // One of these two are required pub person_id: Option<PersonId>, // One of these two are required
/// Example: dessalines , or dessalines@xyz.tld
pub username: Option<String>, pub username: Option<String>,
pub sort: Option<String>, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,

View file

@ -1,6 +1,7 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt}; use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt};
use lemmy_apub::{build_actor_id_from_shortname, EndpointType};
use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType}; use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType};
use lemmy_db_views::comment_view::CommentQueryBuilder; use lemmy_db_views::comment_view::CommentQueryBuilder;
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ApiError, ConnectionId, LemmyError};
@ -27,7 +28,11 @@ impl PerformCrud for GetComments {
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_); let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
let community_id = data.community_id; let community_id = data.community_id;
let community_name = data.community_name.to_owned(); let community_actor_id = data
.community_name
.as_ref()
.map(|t| build_actor_id_from_shortname(EndpointType::Community, t).ok())
.unwrap_or(None);
let saved_only = data.saved_only; let saved_only = data.saved_only;
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
@ -37,7 +42,7 @@ impl PerformCrud for GetComments {
.sort(sort) .sort(sort)
.saved_only(saved_only) .saved_only(saved_only)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id)
.my_person_id(person_id) .my_person_id(person_id)
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.page(page) .page(page)

View file

@ -1,12 +1,8 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt_opt}; use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt_opt};
use lemmy_db_queries::{ use lemmy_apub::{build_actor_id_from_shortname, EndpointType};
from_opt_str_to_opt_enum, use lemmy_db_queries::{from_opt_str_to_opt_enum, ApubObject, ListingType, SortType};
source::community::Community_,
ListingType,
SortType,
};
use lemmy_db_schema::source::community::*; use lemmy_db_schema::source::community::*;
use lemmy_db_views_actor::{ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
@ -32,8 +28,10 @@ impl PerformCrud for GetCommunity {
Some(id) => id, Some(id) => id,
None => { None => {
let name = data.name.to_owned().unwrap_or_else(|| "main".to_string()); let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
let community_actor_id = build_actor_id_from_shortname(EndpointType::Community, &name)?;
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &name) Community::read_from_apub_id(conn, &community_actor_id)
}) })
.await? .await?
.map_err(|_| ApiError::err("couldnt_find_community"))? .map_err(|_| ApiError::err("couldnt_find_community"))?

View file

@ -1,6 +1,7 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, mark_post_as_read, post::*}; use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, mark_post_as_read, post::*};
use lemmy_apub::{build_actor_id_from_shortname, EndpointType};
use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType}; use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType};
use lemmy_db_views::{ use lemmy_db_views::{
comment_view::CommentQueryBuilder, comment_view::CommentQueryBuilder,
@ -111,7 +112,11 @@ impl PerformCrud for GetPosts {
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let community_id = data.community_id; let community_id = data.community_id;
let community_name = data.community_name.to_owned(); let community_actor_id = data
.community_name
.as_ref()
.map(|t| build_actor_id_from_shortname(EndpointType::Community, t).ok())
.unwrap_or(None);
let saved_only = data.saved_only; let saved_only = data.saved_only;
let posts = blocking(context.pool(), move |conn| { let posts = blocking(context.pool(), move |conn| {
@ -122,7 +127,7 @@ impl PerformCrud for GetPosts {
.show_bot_accounts(show_bot_accounts) .show_bot_accounts(show_bot_accounts)
.show_read_posts(show_read_posts) .show_read_posts(show_read_posts)
.community_id(community_id) .community_id(community_id)
.community_name(community_name) .community_actor_id(community_actor_id)
.saved_only(saved_only) .saved_only(saved_only)
.my_person_id(person_id) .my_person_id(person_id)
.page(page) .page(page)

View file

@ -1,7 +1,8 @@
use crate::PerformCrud; use crate::PerformCrud;
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, person::*}; use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, person::*};
use lemmy_db_queries::{from_opt_str_to_opt_enum, source::person::Person_, SortType}; use lemmy_apub::{build_actor_id_from_shortname, EndpointType};
use lemmy_db_queries::{from_opt_str_to_opt_enum, ApubObject, SortType};
use lemmy_db_schema::source::person::*; use lemmy_db_schema::source::person::*;
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder}; use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
use lemmy_db_views_actor::{ use lemmy_db_views_actor::{
@ -34,15 +35,17 @@ impl PerformCrud for GetPersonDetails {
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort); let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
let username = data
.username
.to_owned()
.unwrap_or_else(|| "admin".to_string());
let person_details_id = match data.person_id { let person_details_id = match data.person_id {
Some(id) => id, Some(id) => id,
None => { None => {
let name = data
.username
.to_owned()
.unwrap_or_else(|| "admin".to_string());
let actor_id = build_actor_id_from_shortname(EndpointType::Person, &name)?;
let person = blocking(context.pool(), move |conn| { let person = blocking(context.pool(), move |conn| {
Person::find_by_name(conn, &username) Person::read_from_apub_id(conn, &actor_id)
}) })
.await?; .await?;
person person

View file

@ -279,10 +279,11 @@ pub enum EndpointType {
PrivateMessage, PrivateMessage,
} }
/// Generates the ActivityPub ID for a given object type and ID. /// Generates an apub endpoint for a given domain, IE xyz.tld
pub fn generate_apub_endpoint( pub fn generate_apub_endpoint_for_domain(
endpoint_type: EndpointType, endpoint_type: EndpointType,
name: &str, name: &str,
domain: &str,
) -> Result<DbUrl, ParseError> { ) -> Result<DbUrl, ParseError> {
let point = match endpoint_type { let point = match endpoint_type {
EndpointType::Community => "c", EndpointType::Community => "c",
@ -292,14 +293,18 @@ pub fn generate_apub_endpoint(
EndpointType::PrivateMessage => "private_message", EndpointType::PrivateMessage => "private_message",
}; };
Ok( Ok(Url::parse(&format!("{}/{}/{}", domain, point, name))?.into())
Url::parse(&format!( }
"{}/{}/{}",
Settings::get().get_protocol_and_hostname(), /// Generates the ActivityPub ID for a given object type and ID.
point, pub fn generate_apub_endpoint(
name endpoint_type: EndpointType,
))? name: &str,
.into(), ) -> Result<DbUrl, ParseError> {
generate_apub_endpoint_for_domain(
endpoint_type,
name,
&Settings::get().get_protocol_and_hostname(),
) )
} }
@ -330,6 +335,26 @@ pub fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError
Ok(Url::parse(&format!("{}/moderators", community_id))?.into()) Ok(Url::parse(&format!("{}/moderators", community_id))?.into())
} }
/// Takes in a shortname of the type dessalines@xyz.tld or dessalines (assumed to be local), and outputs the actor id.
/// Used in the API for communities and users.
pub fn build_actor_id_from_shortname(
endpoint_type: EndpointType,
short_name: &str,
) -> Result<DbUrl, ParseError> {
let split = short_name.split('@').collect::<Vec<&str>>();
let name = split[0];
// If there's no @, its local
let domain = if split.len() == 1 {
Settings::get().get_protocol_and_hostname()
} else {
format!("https://{}", split[1])
};
generate_apub_endpoint_for_domain(endpoint_type, name, &domain)
}
/// Store a sent or received activity in the database, for logging purposes. These records are not /// Store a sent or received activity in the database, for logging purposes. These records are not
/// persistent. /// persistent.
pub async fn insert_activity<T>( pub async fn insert_activity<T>(

View file

@ -32,6 +32,7 @@ use lemmy_db_schema::{
}, },
CommentId, CommentId,
CommunityId, CommunityId,
DbUrl,
PersonId, PersonId,
PostId, PostId,
}; };
@ -175,7 +176,7 @@ pub struct CommentQueryBuilder<'a> {
listing_type: Option<ListingType>, listing_type: Option<ListingType>,
sort: Option<SortType>, sort: Option<SortType>,
community_id: Option<CommunityId>, community_id: Option<CommunityId>,
community_name: Option<String>, community_actor_id: Option<DbUrl>,
post_id: Option<PostId>, post_id: Option<PostId>,
creator_id: Option<PersonId>, creator_id: Option<PersonId>,
recipient_id: Option<PersonId>, recipient_id: Option<PersonId>,
@ -195,7 +196,7 @@ impl<'a> CommentQueryBuilder<'a> {
listing_type: None, listing_type: None,
sort: None, sort: None,
community_id: None, community_id: None,
community_name: None, community_actor_id: None,
post_id: None, post_id: None,
creator_id: None, creator_id: None,
recipient_id: None, recipient_id: None,
@ -244,8 +245,8 @@ impl<'a> CommentQueryBuilder<'a> {
self self
} }
pub fn community_name<T: MaybeOptional<String>>(mut self, community_name: T) -> Self { pub fn community_actor_id<T: MaybeOptional<DbUrl>>(mut self, community_actor_id: T) -> Self {
self.community_name = community_name.get_optional(); self.community_actor_id = community_actor_id.get_optional();
self self
} }
@ -362,10 +363,8 @@ impl<'a> CommentQueryBuilder<'a> {
query = query.filter(post::community_id.eq(community_id)); query = query.filter(post::community_id.eq(community_id));
} }
if let Some(community_name) = self.community_name { if let Some(community_actor_id) = self.community_actor_id {
query = query query = query.filter(community::actor_id.eq(community_actor_id))
.filter(community::name.eq(community_name))
.filter(comment::local.eq(true));
} }
if let Some(post_id) = self.post_id { if let Some(post_id) = self.post_id {

View file

@ -28,6 +28,7 @@ use lemmy_db_schema::{
post::{Post, PostRead, PostSaved}, post::{Post, PostRead, PostSaved},
}, },
CommunityId, CommunityId,
DbUrl,
PersonId, PersonId,
PostId, PostId,
}; };
@ -159,7 +160,7 @@ pub struct PostQueryBuilder<'a> {
sort: Option<SortType>, sort: Option<SortType>,
creator_id: Option<PersonId>, creator_id: Option<PersonId>,
community_id: Option<CommunityId>, community_id: Option<CommunityId>,
community_name: Option<String>, community_actor_id: Option<DbUrl>,
my_person_id: Option<PersonId>, my_person_id: Option<PersonId>,
search_term: Option<String>, search_term: Option<String>,
url_search: Option<String>, url_search: Option<String>,
@ -179,7 +180,7 @@ impl<'a> PostQueryBuilder<'a> {
sort: None, sort: None,
creator_id: None, creator_id: None,
community_id: None, community_id: None,
community_name: None, community_actor_id: None,
my_person_id: None, my_person_id: None,
search_term: None, search_term: None,
url_search: None, url_search: None,
@ -212,8 +213,8 @@ impl<'a> PostQueryBuilder<'a> {
self self
} }
pub fn community_name<T: MaybeOptional<String>>(mut self, community_name: T) -> Self { pub fn community_actor_id<T: MaybeOptional<DbUrl>>(mut self, community_actor_id: T) -> Self {
self.community_name = community_name.get_optional(); self.community_actor_id = community_actor_id.get_optional();
self self
} }
@ -334,10 +335,9 @@ impl<'a> PostQueryBuilder<'a> {
.then_order_by(post_aggregates::stickied.desc()); .then_order_by(post_aggregates::stickied.desc());
} }
if let Some(community_name) = self.community_name { if let Some(community_actor_id) = self.community_actor_id {
query = query query = query
.filter(community::name.eq(community_name)) .filter(community::actor_id.eq(community_actor_id))
.filter(community::local.eq(true))
.then_order_by(post_aggregates::stickied.desc()); .then_order_by(post_aggregates::stickied.desc());
} }