mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-22 04:11:17 +00:00
Feature/custom emoji and tagline views (#4580)
* Add custom_emoji list route * Add tagline list route * Apply linting * Remove unecessary TaglineView * Add category filter for custom emoji * Add create tagline endpoint * Add update tagline endpoint * Add delete tagline endpoint * Format through lint.sh * Remove custom_emojis and taglines from site resource * Get random tagline on site requets * Impl Crud for Tagline Remove superfluous properties * Move tagline endpoints under /admin * Impl Crud for CustomEmoji * Remove delete from tagline and custom emoji impls * Check markdown for tagline * Validate markdown on tagline * Make content fields non optional Add error types for tagline validation * Use process_markdown instead of process_markdown_opt * Consolidate Tagline error types * Remove unecessary clone * Updat misleading comments * Remove local_site_id from tagline and custom_emoji * Update TaglineInserForm and TaglineUpdateForm * Add ignore_page_limits for custom emojis EmojiPicker needs to be able to retrieve all emojis in 1 call * Update custom_emoji_view Only keep get_all als helper function calling list with paging ignored Only order on category when filtering on category * Removing pointless get_all fn. * remove tagline length checks * make fields of TaglineInsertForm and TaglineUpdateForm mandatory * move emoji order statement * add comment for GetSiteResponse.tagline --------- Co-authored-by: Freakazoid182 <> Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> Co-authored-by: Dessalines <tyhou13@gmx.com> Co-authored-by: Felix Ableitner <me@nutomic.com>
This commit is contained in:
parent
026e23cf32
commit
43f20881cb
29 changed files with 417 additions and 146 deletions
|
@ -12,7 +12,7 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView};
|
||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||
use lemmy_db_views_actor::structs::PersonView;
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorType, LemmyResult},
|
||||
|
@ -61,11 +61,9 @@ pub async fn leave_admin(
|
|||
|
||||
let all_languages = Language::read_all(&mut context.pool()).await?;
|
||||
let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?;
|
||||
let taglines = Tagline::get_all(&mut context.pool(), site_view.local_site.id).await?;
|
||||
let custom_emojis =
|
||||
CustomEmojiView::get_all(&mut context.pool(), site_view.local_site.id).await?;
|
||||
let oauth_providers = OAuthProvider::get_all_public(&mut context.pool()).await?;
|
||||
let blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?;
|
||||
let tagline = Tagline::get_random(&mut context.pool()).await?;
|
||||
|
||||
Ok(Json(GetSiteResponse {
|
||||
site_view,
|
||||
|
@ -74,10 +72,9 @@ pub async fn leave_admin(
|
|||
my_user: None,
|
||||
all_languages,
|
||||
discussion_languages,
|
||||
taglines,
|
||||
custom_emojis,
|
||||
oauth_providers: Some(oauth_providers),
|
||||
admin_oauth_providers: None,
|
||||
blocked_urls,
|
||||
tagline,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use lemmy_db_schema::newtypes::CustomEmojiId;
|
||||
use lemmy_db_views::structs::CustomEmojiView;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
#[cfg(feature = "full")]
|
||||
use ts_rs::TS;
|
||||
use url::Url;
|
||||
|
@ -46,3 +47,23 @@ pub struct DeleteCustomEmoji {
|
|||
pub struct CustomEmojiResponse {
|
||||
pub custom_emoji: CustomEmojiView,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A response for custom emojis.
|
||||
pub struct ListCustomEmojisResponse {
|
||||
pub custom_emojis: Vec<CustomEmojiView>,
|
||||
}
|
||||
|
||||
#[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 list of custom emojis.
|
||||
pub struct ListCustomEmojis {
|
||||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
pub category: Option<String>,
|
||||
pub ignore_page_limits: Option<bool>,
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ pub mod request;
|
|||
#[cfg(feature = "full")]
|
||||
pub mod send_activity;
|
||||
pub mod site;
|
||||
pub mod tagline;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod utils;
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ use lemmy_db_schema::{
|
|||
};
|
||||
use lemmy_db_views::structs::{
|
||||
CommentView,
|
||||
CustomEmojiView,
|
||||
LocalUserView,
|
||||
PostView,
|
||||
RegistrationApplicationView,
|
||||
|
@ -202,7 +201,6 @@ pub struct CreateSite {
|
|||
pub captcha_difficulty: Option<String>,
|
||||
pub allowed_instances: Option<Vec<String>>,
|
||||
pub blocked_instances: Option<Vec<String>>,
|
||||
pub taglines: Option<Vec<String>>,
|
||||
pub registration_mode: Option<RegistrationMode>,
|
||||
pub oauth_registration: Option<bool>,
|
||||
pub content_warning: Option<String>,
|
||||
|
@ -288,8 +286,6 @@ pub struct EditSite {
|
|||
pub blocked_instances: Option<Vec<String>>,
|
||||
/// A list of blocked URLs
|
||||
pub blocked_urls: Option<Vec<String>>,
|
||||
/// A list of taglines shown at the top of the front page.
|
||||
pub taglines: Option<Vec<String>>,
|
||||
pub registration_mode: Option<RegistrationMode>,
|
||||
/// Whether or not external auth methods can auto-register users.
|
||||
pub oauth_registration: Option<bool>,
|
||||
|
@ -306,7 +302,6 @@ pub struct EditSite {
|
|||
/// The response for a site.
|
||||
pub struct SiteResponse {
|
||||
pub site_view: SiteView,
|
||||
pub taglines: Vec<Tagline>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
@ -321,10 +316,8 @@ pub struct GetSiteResponse {
|
|||
pub my_user: Option<MyUserInfo>,
|
||||
pub all_languages: Vec<Language>,
|
||||
pub discussion_languages: Vec<LanguageId>,
|
||||
/// A list of taglines shown at the top of the front page.
|
||||
pub taglines: Vec<Tagline>,
|
||||
/// A list of custom emojis your site supports.
|
||||
pub custom_emojis: Vec<CustomEmojiView>,
|
||||
/// If the site has any taglines, a random one is included here for displaying
|
||||
pub tagline: Option<Tagline>,
|
||||
/// A list of external auth methods your site supports.
|
||||
pub oauth_providers: Option<Vec<PublicOAuthProvider>>,
|
||||
pub admin_oauth_providers: Option<Vec<OAuthProvider>>,
|
||||
|
|
55
crates/api_common/src/tagline.rs
Normal file
55
crates/api_common/src/tagline.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use lemmy_db_schema::{newtypes::TaglineId, source::tagline::Tagline};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
#[cfg(feature = "full")]
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Create a tagline
|
||||
pub struct CreateTagline {
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Update a tagline
|
||||
pub struct UpdateTagline {
|
||||
pub id: TaglineId,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Delete a tagline
|
||||
pub struct DeleteTagline {
|
||||
pub id: TaglineId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
pub struct TaglineResponse {
|
||||
pub tagline: Tagline,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A response for taglines.
|
||||
pub struct ListTaglinesResponse {
|
||||
pub taglines: Vec<Tagline>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Fetches a list of taglines.
|
||||
pub struct ListTaglines {
|
||||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
}
|
|
@ -5,10 +5,12 @@ use lemmy_api_common::{
|
|||
custom_emoji::{CreateCustomEmoji, CustomEmojiResponse},
|
||||
utils::is_admin,
|
||||
};
|
||||
use lemmy_db_schema::source::{
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
custom_emoji::{CustomEmoji, CustomEmojiInsertForm},
|
||||
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
|
||||
local_site::LocalSite,
|
||||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{CustomEmojiView, LocalUserView};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
@ -19,12 +21,10 @@ pub async fn create_custom_emoji(
|
|||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<CustomEmojiResponse>> {
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
// Make sure user is an admin
|
||||
is_admin(&local_user_view)?;
|
||||
|
||||
let emoji_form = CustomEmojiInsertForm::builder()
|
||||
.local_site_id(local_site.id)
|
||||
.shortcode(data.shortcode.to_lowercase().trim().to_string())
|
||||
.alt_text(data.alt_text.to_string())
|
||||
.category(data.category.to_string())
|
||||
|
|
|
@ -6,7 +6,7 @@ use lemmy_api_common::{
|
|||
utils::is_admin,
|
||||
SuccessResponse,
|
||||
};
|
||||
use lemmy_db_schema::source::custom_emoji::CustomEmoji;
|
||||
use lemmy_db_schema::{source::custom_emoji::CustomEmoji, traits::Crud};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
||||
|
|
25
crates/api_crud/src/custom_emoji/list.rs
Normal file
25
crates/api_crud/src/custom_emoji/list.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
custom_emoji::{ListCustomEmojis, ListCustomEmojisResponse},
|
||||
};
|
||||
use lemmy_db_views::structs::{CustomEmojiView, LocalUserView};
|
||||
use lemmy_utils::error::LemmyError;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_custom_emojis(
|
||||
data: Query<ListCustomEmojis>,
|
||||
local_user_view: Option<LocalUserView>,
|
||||
context: Data<LemmyContext>,
|
||||
) -> Result<Json<ListCustomEmojisResponse>, LemmyError> {
|
||||
let custom_emojis = CustomEmojiView::list(
|
||||
&mut context.pool(),
|
||||
&data.category,
|
||||
data.page,
|
||||
data.limit,
|
||||
data.ignore_page_limits.unwrap_or(false),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ListCustomEmojisResponse { custom_emojis }))
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod create;
|
||||
pub mod delete;
|
||||
pub mod list;
|
||||
pub mod update;
|
||||
|
|
|
@ -5,10 +5,12 @@ use lemmy_api_common::{
|
|||
custom_emoji::{CustomEmojiResponse, EditCustomEmoji},
|
||||
utils::is_admin,
|
||||
};
|
||||
use lemmy_db_schema::source::{
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
custom_emoji::{CustomEmoji, CustomEmojiUpdateForm},
|
||||
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
|
||||
local_site::LocalSite,
|
||||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::{CustomEmojiView, LocalUserView};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
|
@ -19,12 +21,10 @@ pub async fn update_custom_emoji(
|
|||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<CustomEmojiResponse>> {
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
// Make sure user is an admin
|
||||
is_admin(&local_user_view)?;
|
||||
|
||||
let emoji_form = CustomEmojiUpdateForm::builder()
|
||||
.local_site_id(local_site.id)
|
||||
.alt_text(data.alt_text.to_string())
|
||||
.category(data.category.to_string())
|
||||
.image_url(data.clone().image_url.into())
|
||||
|
|
|
@ -5,4 +5,5 @@ pub mod oauth_provider;
|
|||
pub mod post;
|
||||
pub mod private_message;
|
||||
pub mod site;
|
||||
pub mod tagline;
|
||||
pub mod user;
|
||||
|
|
|
@ -20,7 +20,6 @@ use lemmy_db_schema::{
|
|||
local_site::{LocalSite, LocalSiteUpdateForm},
|
||||
local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitUpdateForm},
|
||||
site::{Site, SiteUpdateForm},
|
||||
tagline::Tagline,
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{diesel_string_update, diesel_url_create, naive_now},
|
||||
|
@ -135,17 +134,11 @@ pub async fn create_site(
|
|||
|
||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||
|
||||
let new_taglines = data.taglines.clone();
|
||||
let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?;
|
||||
|
||||
let rate_limit_config =
|
||||
local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);
|
||||
context.rate_limit_cell().set_config(rate_limit_config);
|
||||
|
||||
Ok(Json(SiteResponse {
|
||||
site_view,
|
||||
taglines,
|
||||
}))
|
||||
Ok(Json(SiteResponse { site_view }))
|
||||
}
|
||||
|
||||
fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> {
|
||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::source::{
|
|||
person_block::PersonBlock,
|
||||
tagline::Tagline,
|
||||
};
|
||||
use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView};
|
||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||
use lemmy_db_views_actor::structs::{CommunityFollowerView, CommunityModeratorView, PersonView};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
|
@ -42,10 +42,8 @@ pub async fn get_site(
|
|||
let admins = PersonView::admins(&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 taglines = Tagline::get_all(&mut context.pool(), site_view.local_site.id).await?;
|
||||
let custom_emojis =
|
||||
CustomEmojiView::get_all(&mut context.pool(), site_view.local_site.id).await?;
|
||||
let blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?;
|
||||
let tagline = Tagline::get_random(&mut context.pool()).await?;
|
||||
let admin_oauth_providers = OAuthProvider::get_all(&mut context.pool()).await?;
|
||||
let oauth_providers =
|
||||
OAuthProvider::convert_providers_to_public(admin_oauth_providers.clone());
|
||||
|
@ -57,9 +55,8 @@ pub async fn get_site(
|
|||
my_user: None,
|
||||
all_languages,
|
||||
discussion_languages,
|
||||
taglines,
|
||||
custom_emojis,
|
||||
blocked_urls,
|
||||
tagline,
|
||||
oauth_providers: Some(oauth_providers),
|
||||
admin_oauth_providers: Some(admin_oauth_providers),
|
||||
})
|
||||
|
|
|
@ -24,7 +24,6 @@ use lemmy_db_schema::{
|
|||
local_site_url_blocklist::LocalSiteUrlBlocklist,
|
||||
local_user::LocalUser,
|
||||
site::{Site, SiteUpdateForm},
|
||||
tagline::Tagline,
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{diesel_string_update, diesel_url_update, naive_now},
|
||||
|
@ -187,19 +186,13 @@ pub async fn update_site(
|
|||
.with_lemmy_type(LemmyErrorType::CouldntSetAllEmailVerified)?;
|
||||
}
|
||||
|
||||
let new_taglines = data.taglines.clone();
|
||||
let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?;
|
||||
|
||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||
|
||||
let rate_limit_config =
|
||||
local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);
|
||||
context.rate_limit_cell().set_config(rate_limit_config);
|
||||
|
||||
Ok(Json(SiteResponse {
|
||||
site_view,
|
||||
taglines,
|
||||
}))
|
||||
Ok(Json(SiteResponse { site_view }))
|
||||
}
|
||||
|
||||
fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> LemmyResult<()> {
|
||||
|
|
38
crates/api_crud/src/tagline/create.rs
Normal file
38
crates/api_crud/src/tagline/create.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
tagline::{CreateTagline, TaglineResponse},
|
||||
utils::{get_url_blocklist, is_admin, local_site_to_slur_regex, process_markdown},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
local_site::LocalSite,
|
||||
tagline::{Tagline, TaglineInsertForm},
|
||||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::LemmyError;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn create_tagline(
|
||||
data: Json<CreateTagline>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> Result<Json<TaglineResponse>, LemmyError> {
|
||||
// Make sure user is an admin
|
||||
is_admin(&local_user_view)?;
|
||||
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
|
||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||
let url_blocklist = get_url_blocklist(&context).await?;
|
||||
let content = process_markdown(&data.content, &slur_regex, &url_blocklist, &context).await?;
|
||||
|
||||
let tagline_form = TaglineInsertForm { content };
|
||||
|
||||
let tagline = Tagline::create(&mut context.pool(), &tagline_form).await?;
|
||||
|
||||
Ok(Json(TaglineResponse { tagline }))
|
||||
}
|
25
crates/api_crud/src/tagline/delete.rs
Normal file
25
crates/api_crud/src/tagline/delete.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
tagline::DeleteTagline,
|
||||
utils::is_admin,
|
||||
SuccessResponse,
|
||||
};
|
||||
use lemmy_db_schema::{source::tagline::Tagline, traits::Crud};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::LemmyError;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn delete_tagline(
|
||||
data: Json<DeleteTagline>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> Result<Json<SuccessResponse>, LemmyError> {
|
||||
// Make sure user is an admin
|
||||
is_admin(&local_user_view)?;
|
||||
|
||||
Tagline::delete(&mut context.pool(), data.id).await?;
|
||||
|
||||
Ok(Json(SuccessResponse::default()))
|
||||
}
|
19
crates/api_crud/src/tagline/list.rs
Normal file
19
crates/api_crud/src/tagline/list.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use actix_web::web::{Data, Json, Query};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
tagline::{ListTaglines, ListTaglinesResponse},
|
||||
};
|
||||
use lemmy_db_schema::source::tagline::Tagline;
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::LemmyError;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn list_taglines(
|
||||
data: Query<ListTaglines>,
|
||||
local_user_view: Option<LocalUserView>,
|
||||
context: Data<LemmyContext>,
|
||||
) -> Result<Json<ListTaglinesResponse>, LemmyError> {
|
||||
let taglines = Tagline::list(&mut context.pool(), data.page, data.limit).await?;
|
||||
|
||||
Ok(Json(ListTaglinesResponse { taglines }))
|
||||
}
|
4
crates/api_crud/src/tagline/mod.rs
Normal file
4
crates/api_crud/src/tagline/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub mod create;
|
||||
pub mod delete;
|
||||
pub mod list;
|
||||
pub mod update;
|
42
crates/api_crud/src/tagline/update.rs
Normal file
42
crates/api_crud/src/tagline/update.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
tagline::{TaglineResponse, UpdateTagline},
|
||||
utils::{get_url_blocklist, is_admin, local_site_to_slur_regex, process_markdown},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
local_site::LocalSite,
|
||||
tagline::{Tagline, TaglineUpdateForm},
|
||||
},
|
||||
traits::Crud,
|
||||
utils::naive_now,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::LemmyError;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn update_tagline(
|
||||
data: Json<UpdateTagline>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> Result<Json<TaglineResponse>, LemmyError> {
|
||||
// Make sure user is an admin
|
||||
is_admin(&local_user_view)?;
|
||||
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
|
||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||
let url_blocklist = get_url_blocklist(&context).await?;
|
||||
let content = process_markdown(&data.content, &slur_regex, &url_blocklist, &context).await?;
|
||||
|
||||
let tagline_form = TaglineUpdateForm {
|
||||
content,
|
||||
updated: naive_now(),
|
||||
};
|
||||
|
||||
let tagline = Tagline::update(&mut context.pool(), data.id, &tagline_form).await?;
|
||||
|
||||
Ok(Json(TaglineResponse { tagline }))
|
||||
}
|
|
@ -8,36 +8,37 @@ use crate::{
|
|||
custom_emoji::{CustomEmoji, CustomEmojiInsertForm, CustomEmojiUpdateForm},
|
||||
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
|
||||
},
|
||||
traits::Crud,
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
impl CustomEmoji {
|
||||
pub async fn create(pool: &mut DbPool<'_>, form: &CustomEmojiInsertForm) -> Result<Self, Error> {
|
||||
#[async_trait]
|
||||
impl Crud for CustomEmoji {
|
||||
type InsertForm = CustomEmojiInsertForm;
|
||||
type UpdateForm = CustomEmojiUpdateForm;
|
||||
type IdType = CustomEmojiId;
|
||||
|
||||
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
insert_into(custom_emoji)
|
||||
.values(form)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
pub async fn update(
|
||||
|
||||
async fn update(
|
||||
pool: &mut DbPool<'_>,
|
||||
emoji_id: CustomEmojiId,
|
||||
form: &CustomEmojiUpdateForm,
|
||||
emoji_id: Self::IdType,
|
||||
new_custom_emoji: &Self::UpdateForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::update(custom_emoji.find(emoji_id))
|
||||
.set(form)
|
||||
.set(new_custom_emoji)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
pub async fn delete(pool: &mut DbPool<'_>, emoji_id: CustomEmojiId) -> Result<usize, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
diesel::delete(custom_emoji.find(emoji_id))
|
||||
.execute(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomEmojiKeyword {
|
||||
|
|
|
@ -1,58 +1,64 @@
|
|||
use crate::{
|
||||
newtypes::LocalSiteId,
|
||||
schema::tagline::dsl::{local_site_id, tagline},
|
||||
source::tagline::{Tagline, TaglineForm},
|
||||
utils::{get_conn, DbPool},
|
||||
newtypes::TaglineId,
|
||||
schema::tagline::dsl::{published, tagline},
|
||||
source::tagline::{Tagline, TaglineInsertForm, TaglineUpdateForm},
|
||||
traits::Crud,
|
||||
utils::{get_conn, limit_and_offset, DbPool},
|
||||
};
|
||||
use diesel::{insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::{AsyncPgConnection, RunQueryDsl};
|
||||
use diesel::{insert_into, result::Error, ExpressionMethods, OptionalExtension, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
impl Tagline {
|
||||
pub async fn replace(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_local_site_id: LocalSiteId,
|
||||
list_content: Option<Vec<String>>,
|
||||
) -> Result<Vec<Self>, Error> {
|
||||
#[async_trait]
|
||||
impl Crud for Tagline {
|
||||
type InsertForm = TaglineInsertForm;
|
||||
type UpdateForm = TaglineUpdateForm;
|
||||
type IdType = TaglineId;
|
||||
|
||||
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
if let Some(list) = list_content {
|
||||
conn
|
||||
.build_transaction()
|
||||
.run(|conn| {
|
||||
Box::pin(async move {
|
||||
Self::clear(conn).await?;
|
||||
|
||||
for item in list {
|
||||
let form = TaglineForm {
|
||||
local_site_id: for_local_site_id,
|
||||
content: item,
|
||||
updated: None,
|
||||
};
|
||||
insert_into(tagline)
|
||||
.values(form)
|
||||
.get_result::<Self>(conn)
|
||||
.await?;
|
||||
}
|
||||
Self::get_all(&mut conn.into(), for_local_site_id).await
|
||||
}) as _
|
||||
})
|
||||
.await
|
||||
} else {
|
||||
Self::get_all(&mut conn.into(), for_local_site_id).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn clear(conn: &mut AsyncPgConnection) -> Result<usize, Error> {
|
||||
diesel::delete(tagline).execute(conn).await
|
||||
}
|
||||
|
||||
pub async fn get_all(
|
||||
async fn update(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_local_site_id: LocalSiteId,
|
||||
) -> Result<Vec<Self>, Error> {
|
||||
tagline_id: TaglineId,
|
||||
new_tagline: &Self::UpdateForm,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
tagline
|
||||
.filter(local_site_id.eq(for_local_site_id))
|
||||
.get_results::<Self>(conn)
|
||||
diesel::update(tagline.find(tagline_id))
|
||||
.set(new_tagline)
|
||||
.get_result::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl Tagline {
|
||||
pub async fn list(
|
||||
pool: &mut DbPool<'_>,
|
||||
page: Option<i64>,
|
||||
limit: Option<i64>,
|
||||
) -> Result<Vec<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
let (limit, offset) = limit_and_offset(page, limit)?;
|
||||
tagline
|
||||
.order(published.desc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.get_results::<Self>(conn)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_random(pool: &mut DbPool<'_>) -> Result<Option<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
sql_function!(fn random() -> Text);
|
||||
tagline
|
||||
.order(random())
|
||||
.limit(1)
|
||||
.first::<Self>(conn)
|
||||
.await
|
||||
.optional()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,6 +148,12 @@ pub struct LocalSiteId(i32);
|
|||
/// The custom emoji id.
|
||||
pub struct CustomEmojiId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// The tagline id.
|
||||
pub struct TaglineId(i32);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
|
|
@ -258,7 +258,6 @@ diesel::table! {
|
|||
diesel::table! {
|
||||
custom_emoji (id) {
|
||||
id -> Int4,
|
||||
local_site_id -> Int4,
|
||||
#[max_length = 128]
|
||||
shortcode -> Varchar,
|
||||
image_url -> Text,
|
||||
|
@ -974,7 +973,6 @@ diesel::table! {
|
|||
diesel::table! {
|
||||
tagline (id) {
|
||||
id -> Int4,
|
||||
local_site_id -> Int4,
|
||||
content -> Text,
|
||||
published -> Timestamptz,
|
||||
updated -> Nullable<Timestamptz>,
|
||||
|
@ -1011,7 +1009,6 @@ diesel::joinable!(community_moderator -> community (community_id));
|
|||
diesel::joinable!(community_moderator -> person (person_id));
|
||||
diesel::joinable!(community_person_ban -> community (community_id));
|
||||
diesel::joinable!(community_person_ban -> person (person_id));
|
||||
diesel::joinable!(custom_emoji -> local_site (local_site_id));
|
||||
diesel::joinable!(custom_emoji_keyword -> custom_emoji (custom_emoji_id));
|
||||
diesel::joinable!(email_verification -> local_user (local_user_id));
|
||||
diesel::joinable!(federation_allowlist -> instance (instance_id));
|
||||
|
@ -1075,7 +1072,6 @@ diesel::joinable!(site -> instance (instance_id));
|
|||
diesel::joinable!(site_aggregates -> site (site_id));
|
||||
diesel::joinable!(site_language -> language (language_id));
|
||||
diesel::joinable!(site_language -> site (site_id));
|
||||
diesel::joinable!(tagline -> local_site (local_site_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
admin_purge_comment,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::newtypes::{CustomEmojiId, DbUrl, LocalSiteId};
|
||||
use crate::newtypes::{CustomEmojiId, DbUrl};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::custom_emoji;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -10,21 +10,13 @@ use typed_builder::TypedBuilder;
|
|||
|
||||
#[skip_serializing_none]
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||
)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = custom_emoji))]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
diesel(belongs_to(crate::source::local_site::LocalSite))
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A custom emoji.
|
||||
pub struct CustomEmoji {
|
||||
pub id: CustomEmojiId,
|
||||
pub local_site_id: LocalSiteId,
|
||||
pub shortcode: String,
|
||||
pub image_url: DbUrl,
|
||||
pub alt_text: String,
|
||||
|
@ -37,7 +29,6 @@ pub struct CustomEmoji {
|
|||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = custom_emoji))]
|
||||
pub struct CustomEmojiInsertForm {
|
||||
pub local_site_id: LocalSiteId,
|
||||
pub shortcode: String,
|
||||
pub image_url: DbUrl,
|
||||
pub alt_text: String,
|
||||
|
@ -48,7 +39,6 @@ pub struct CustomEmojiInsertForm {
|
|||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = custom_emoji))]
|
||||
pub struct CustomEmojiUpdateForm {
|
||||
pub local_site_id: LocalSiteId,
|
||||
pub image_url: DbUrl,
|
||||
pub alt_text: String,
|
||||
pub category: String,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::newtypes::LocalSiteId;
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::tagline;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -9,21 +8,13 @@ use ts_rs::TS;
|
|||
|
||||
#[skip_serializing_none]
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||
)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = tagline))]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
diesel(belongs_to(crate::source::local_site::LocalSite))
|
||||
)]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A tagline, shown at the top of your site.
|
||||
pub struct Tagline {
|
||||
pub id: i32,
|
||||
pub local_site_id: LocalSiteId,
|
||||
pub content: String,
|
||||
pub published: DateTime<Utc>,
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
|
@ -32,8 +23,14 @@ pub struct Tagline {
|
|||
#[derive(Clone, Default)]
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = tagline))]
|
||||
pub struct TaglineForm {
|
||||
pub local_site_id: LocalSiteId,
|
||||
pub struct TaglineInsertForm {
|
||||
pub content: String,
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = tagline))]
|
||||
pub struct TaglineUpdateForm {
|
||||
pub content: String,
|
||||
pub updated: DateTime<Utc>,
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ use crate::structs::CustomEmojiView;
|
|||
use diesel::{result::Error, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
newtypes::{CustomEmojiId, LocalSiteId},
|
||||
newtypes::CustomEmojiId,
|
||||
schema::{custom_emoji, custom_emoji_keyword},
|
||||
source::{custom_emoji::CustomEmoji, custom_emoji_keyword::CustomEmojiKeyword},
|
||||
utils::{get_conn, DbPool},
|
||||
utils::{get_conn, limit_and_offset, DbPool},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -35,18 +35,34 @@ impl CustomEmojiView {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_all(
|
||||
pub async fn list(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_local_site_id: LocalSiteId,
|
||||
category: &Option<String>,
|
||||
page: Option<i64>,
|
||||
limit: Option<i64>,
|
||||
ignore_page_limits: bool,
|
||||
) -> Result<Vec<Self>, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
let emojis = custom_emoji::table
|
||||
.filter(custom_emoji::local_site_id.eq(for_local_site_id))
|
||||
|
||||
let mut query = custom_emoji::table
|
||||
.left_join(
|
||||
custom_emoji_keyword::table.on(custom_emoji_keyword::custom_emoji_id.eq(custom_emoji::id)),
|
||||
)
|
||||
.order(custom_emoji::category)
|
||||
.then_order_by(custom_emoji::id)
|
||||
.into_boxed();
|
||||
|
||||
if !ignore_page_limits {
|
||||
let (limit, offset) = limit_and_offset(page, limit)?;
|
||||
query = query.limit(limit).offset(offset);
|
||||
}
|
||||
|
||||
if let Some(category) = category {
|
||||
query = query.filter(custom_emoji::category.eq(category))
|
||||
}
|
||||
|
||||
query = query.then_order_by(custom_emoji::id);
|
||||
|
||||
let emojis = query
|
||||
.select((
|
||||
custom_emoji::all_columns,
|
||||
custom_emoji_keyword::all_columns.nullable(), // (or all the columns if you want)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
ALTER TABLE custom_emoji
|
||||
ADD COLUMN local_site_id int REFERENCES local_site (site_id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
UPDATE
|
||||
custom_emoji
|
||||
SET
|
||||
local_site_id = (
|
||||
SELECT
|
||||
site_id
|
||||
FROM
|
||||
local_site
|
||||
LIMIT 1);
|
||||
|
||||
ALTER TABLE custom_emoji
|
||||
ALTER COLUMN local_site_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE tagline
|
||||
ADD COLUMN local_site_id int REFERENCES local_site (site_id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
UPDATE
|
||||
tagline
|
||||
SET
|
||||
local_site_id = (
|
||||
SELECT
|
||||
site_id
|
||||
FROM
|
||||
local_site
|
||||
LIMIT 1);
|
||||
|
||||
ALTER TABLE tagline
|
||||
ALTER COLUMN local_site_id SET NOT NULL;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE custom_emoji
|
||||
DROP COLUMN local_site_id;
|
||||
|
||||
ALTER TABLE tagline
|
||||
DROP COLUMN local_site_id;
|
||||
|
|
@ -107,6 +107,7 @@ use lemmy_api_crud::{
|
|||
custom_emoji::{
|
||||
create::create_custom_emoji,
|
||||
delete::delete_custom_emoji,
|
||||
list::list_custom_emojis,
|
||||
update::update_custom_emoji,
|
||||
},
|
||||
oauth_provider::{
|
||||
|
@ -128,6 +129,12 @@ use lemmy_api_crud::{
|
|||
update::update_private_message,
|
||||
},
|
||||
site::{create::create_site, read::get_site, update::update_site},
|
||||
tagline::{
|
||||
create::create_tagline,
|
||||
delete::delete_tagline,
|
||||
list::list_taglines,
|
||||
update::update_tagline,
|
||||
},
|
||||
user::{
|
||||
create::{authenticate_with_oauth, register},
|
||||
delete::delete_account,
|
||||
|
@ -381,6 +388,14 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
.route("/community", web::post().to(purge_community))
|
||||
.route("/post", web::post().to(purge_post))
|
||||
.route("/comment", web::post().to(purge_comment)),
|
||||
)
|
||||
.service(
|
||||
web::scope("/tagline")
|
||||
.wrap(rate_limit.message())
|
||||
.route("", web::post().to(create_tagline))
|
||||
.route("", web::put().to(update_tagline))
|
||||
.route("/delete", web::post().to(delete_tagline))
|
||||
.route("/list", web::get().to(list_taglines)),
|
||||
),
|
||||
)
|
||||
.service(
|
||||
|
@ -388,7 +403,8 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
.wrap(rate_limit.message())
|
||||
.route("", web::post().to(create_custom_emoji))
|
||||
.route("", web::put().to(update_custom_emoji))
|
||||
.route("/delete", web::post().to(delete_custom_emoji)),
|
||||
.route("/delete", web::post().to(delete_custom_emoji))
|
||||
.route("/list", web::get().to(list_custom_emojis)),
|
||||
)
|
||||
.service(
|
||||
web::scope("/oauth_provider")
|
||||
|
|
Loading…
Reference in a new issue