Adding a get_random_community endpoint. (#5042)

* Adding a get_random_community endpoint.

- Fixes #4698

* Fixing issue from main.

* Adding ListingType to the query.

* More concise query filter.
This commit is contained in:
Dessalines 2024-10-02 09:10:41 -04:00 committed by GitHub
parent 483bdd592e
commit 432d46c1aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 98 additions and 11 deletions

View file

@ -3,4 +3,5 @@ pub mod ban;
pub mod block; pub mod block;
pub mod follow; pub mod follow;
pub mod hide; pub mod hide;
pub mod random;
pub mod transfer; pub mod transfer;

View file

@ -0,0 +1,55 @@
use activitypub_federation::config::Data;
use actix_web::web::{Json, Query};
use lemmy_api_common::{
community::{CommunityResponse, GetRandomCommunity},
context::LemmyContext,
utils::{check_private_instance, is_mod_or_admin_opt},
};
use lemmy_db_schema::source::{
actor_language::CommunityLanguage,
community::Community,
local_site::LocalSite,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))]
pub async fn get_random_community(
data: Query<GetRandomCommunity>,
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<CommunityResponse>> {
let local_site = LocalSite::read(&mut context.pool()).await?;
check_private_instance(&local_user_view, &local_site)?;
let local_user = local_user_view.as_ref().map(|u| &u.local_user);
let random_community_id =
Community::get_random_community_id(&mut context.pool(), &data.type_).await?;
let is_mod_or_admin = is_mod_or_admin_opt(
&mut context.pool(),
local_user_view.as_ref(),
Some(random_community_id),
)
.await
.is_ok();
let community_view = CommunityView::read(
&mut context.pool(),
random_community_id,
local_user,
is_mod_or_admin,
)
.await?;
let discussion_languages =
CommunityLanguage::read(&mut context.pool(), random_community_id).await?;
Ok(Json(CommunityResponse {
community_view,
discussion_languages,
}))
}

View file

@ -63,7 +63,7 @@ pub async fn leave_admin(
let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?;
let oauth_providers = OAuthProvider::get_all_public(&mut context.pool()).await?; let oauth_providers = OAuthProvider::get_all_public(&mut context.pool()).await?;
let blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?; let blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?;
let tagline = Tagline::get_random(&mut context.pool()).await?; let tagline = Tagline::get_random(&mut context.pool()).await.ok();
Ok(Json(GetSiteResponse { Ok(Json(GetSiteResponse {
site_view, site_view,

View file

@ -225,3 +225,12 @@ pub struct TransferCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub person_id: PersonId, pub person_id: PersonId,
} }
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Fetches a random community
pub struct GetRandomCommunity {
pub type_: Option<ListingType>,
}

View file

@ -43,7 +43,7 @@ pub async fn get_site(
let all_languages = Language::read_all(&mut context.pool()).await?; let all_languages = Language::read_all(&mut context.pool()).await?;
let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?;
let blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?; let blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?;
let tagline = Tagline::get_random(&mut context.pool()).await?; let tagline = Tagline::get_random(&mut context.pool()).await.ok();
let admin_oauth_providers = OAuthProvider::get_all(&mut context.pool()).await?; let admin_oauth_providers = OAuthProvider::get_all(&mut context.pool()).await?;
let oauth_providers = let oauth_providers =
OAuthProvider::convert_providers_to_public(admin_oauth_providers.clone()); OAuthProvider::convert_providers_to_public(admin_oauth_providers.clone());

View file

@ -30,12 +30,13 @@ use crate::{
get_conn, get_conn,
DbPool, DbPool,
}, },
ListingType,
SubscribedType, SubscribedType,
}; };
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use diesel::{ use diesel::{
deserialize, deserialize,
dsl::{self, exists, insert_into}, dsl::{self, exists, insert_into, not},
pg::Pg, pg::Pg,
result::Error, result::Error,
select, select,
@ -193,6 +194,30 @@ impl Community {
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn get_random_community_id(
pool: &mut DbPool<'_>,
type_: &Option<ListingType>,
) -> Result<CommunityId, Error> {
let conn = &mut get_conn(pool).await?;
sql_function!(fn random() -> Text);
let mut query = community::table
.filter(not(community::deleted))
.filter(not(community::removed))
.into_boxed();
if let Some(ListingType::Local) = type_ {
query = query.filter(community::local);
}
query
.select(community::id)
.order(random())
.limit(1)
.first::<CommunityId>(conn)
.await
}
} }
impl CommunityModerator { impl CommunityModerator {

View file

@ -5,7 +5,7 @@ use crate::{
traits::Crud, traits::Crud,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
use diesel::{insert_into, result::Error, ExpressionMethods, OptionalExtension, QueryDsl}; use diesel::{insert_into, result::Error, ExpressionMethods, QueryDsl};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
#[async_trait] #[async_trait]
@ -51,14 +51,9 @@ impl Tagline {
.await .await
} }
pub async fn get_random(pool: &mut DbPool<'_>) -> Result<Option<Self>, Error> { pub async fn get_random(pool: &mut DbPool<'_>) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
sql_function!(fn random() -> Text); sql_function!(fn random() -> Text);
tagline tagline.order(random()).limit(1).first::<Self>(conn).await
.order(random())
.limit(1)
.first::<Self>(conn)
.await
.optional()
} }
} }

View file

@ -17,6 +17,7 @@ use lemmy_api::{
block::block_community, block::block_community,
follow::follow_community, follow::follow_community,
hide::hide_community, hide::hide_community,
random::get_random_community,
transfer::transfer_community, transfer::transfer_community,
}, },
local_user::{ local_user::{
@ -193,6 +194,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
.wrap(rate_limit.message()) .wrap(rate_limit.message())
.route("", web::get().to(get_community)) .route("", web::get().to(get_community))
.route("", web::put().to(update_community)) .route("", web::put().to(update_community))
.route("/random", web::get().to(get_random_community))
.route("/hide", web::put().to(hide_community)) .route("/hide", web::put().to(hide_community))
.route("/list", web::get().to(list_communities)) .route("/list", web::get().to(list_communities))
.route("/follow", web::post().to(follow_community)) .route("/follow", web::post().to(follow_community))