Freakazoid182 3 weeks ago committed by GitHub
commit ff21690fd8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -11,7 +11,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},
@ -62,10 +62,8 @@ 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 blocked_urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?;
let tagline = Tagline::get_random(&mut context.pool()).await?;
Ok(Json(GetSiteResponse {
site_view,
@ -74,8 +72,7 @@ pub async fn leave_admin(
my_user: None,
all_languages,
discussion_languages,
taglines,
custom_emojis,
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;
pub mod send_activity;
pub mod sensitive;
pub mod site;
pub mod tagline;
#[cfg(feature = "full")]
pub mod utils;

@ -18,7 +18,6 @@ use lemmy_db_schema::{
};
use lemmy_db_views::structs::{
CommentView,
CustomEmojiView,
LocalUserView,
PostView,
RegistrationApplicationView,
@ -190,7 +189,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 content_warning: Option<String>,
pub default_post_listing_mode: Option<PostListingMode>,
@ -271,8 +269,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 to email admins for new reports.
pub reports_email_admins: Option<bool>,
@ -289,7 +285,6 @@ pub struct EditSite {
/// The response for a site.
pub struct SiteResponse {
pub site_view: SiteView,
pub taglines: Vec<Tagline>,
}
#[skip_serializing_none]
@ -304,10 +299,7 @@ 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>,
pub tagline: Option<Tagline>,
pub blocked_urls: Vec<LocalSiteUrlBlocklist>,
}

@ -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::{
custom_emoji::{CustomEmoji, CustomEmojiInsertForm},
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
local_site::LocalSite,
use lemmy_db_schema::{
source::{
custom_emoji::{CustomEmoji, CustomEmojiInsertForm},
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
},
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;

@ -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::{
custom_emoji::{CustomEmoji, CustomEmojiUpdateForm},
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
local_site::LocalSite,
use lemmy_db_schema::{
source::{
custom_emoji::{CustomEmoji, CustomEmojiUpdateForm},
custom_emoji_keyword::{CustomEmojiKeyword, CustomEmojiKeywordInsertForm},
},
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())

@ -4,4 +4,5 @@ pub mod custom_emoji;
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_option_overwrite, naive_now},
@ -133,17 +132,11 @@ pub async fn create_site(
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
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<()> {
@ -586,7 +579,6 @@ mod tests {
captcha_difficulty: None,
allowed_instances: None,
blocked_instances: None,
taglines: None,
registration_mode: site_registration_mode,
content_warning: None,
default_post_listing_mode: None,

@ -9,7 +9,7 @@ use lemmy_db_schema::source::{
local_site_url_blocklist::LocalSiteUrlBlocklist,
tagline::Tagline,
};
use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_db_views_actor::structs::{
CommunityBlockView,
CommunityFollowerView,
@ -47,10 +47,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?;
Ok(GetSiteResponse {
site_view,
admins,
@ -58,9 +56,8 @@ pub async fn get_site(
my_user: None,
all_languages,
discussion_languages,
taglines,
custom_emojis,
blocked_urls,
tagline,
})
})
.await

@ -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_option_overwrite, naive_now},
@ -180,9 +179,6 @@ 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?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
@ -191,10 +187,7 @@ pub async fn update_site(
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<()> {
@ -597,7 +590,6 @@ mod tests {
allowed_instances: None,
blocked_instances: None,
blocked_urls: None,
taglines: None,
registration_mode: site_registration_mode,
reports_email_admins: None,
content_warning: None,

@ -0,0 +1,41 @@
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, utils::validation::is_valid_tagline_content};
#[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?;
is_valid_tagline_content(&content)?;
let tagline_form = TaglineInsertForm {
content: Some(content),
};
let tagline = Tagline::create(&mut context.pool(), &tagline_form).await?;
Ok(Json(TaglineResponse { tagline }))
}

@ -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()))
}

@ -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 }))
}

@ -0,0 +1,4 @@
pub mod create;
pub mod delete;
pub mod list;
pub mod update;

@ -0,0 +1,43 @@
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, utils::validation::is_valid_tagline_content};
#[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?;
is_valid_tagline_content(&content)?;
let tagline_form = TaglineUpdateForm {
content: Some(content),
updated: Some(Some(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> {
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?;
#[async_trait]
impl Crud for Tagline {
type InsertForm = TaglineInsertForm;
type UpdateForm = TaglineUpdateForm;
type IdType = TaglineId;
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 create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
insert_into(tagline)
.values(form)
.get_result::<Self>(conn)
.await
}
async fn clear(conn: &mut AsyncPgConnection) -> Result<usize, Error> {
diesel::delete(tagline).execute(conn).await
async fn update(
pool: &mut DbPool<'_>,
tagline_id: TaglineId,
new_tagline: &Self::UpdateForm,
) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
diesel::update(tagline.find(tagline_id))
.set(new_tagline)
.get_result::<Self>(conn)
.await
}
}
pub async fn get_all(
impl Tagline {
pub async fn list(
pool: &mut DbPool<'_>,
for_local_site_id: LocalSiteId,
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
.filter(local_site_id.eq(for_local_site_id))
.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()
}
}

@ -152,6 +152,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);
#[cfg(feature = "full")]
#[derive(Serialize, Deserialize)]
#[serde(remote = "Ltree")]

@ -254,7 +254,6 @@ diesel::table! {
diesel::table! {
custom_emoji (id) {
id -> Int4,
local_site_id -> Int4,
#[max_length = 128]
shortcode -> Varchar,
image_url -> Text,
@ -929,7 +928,6 @@ diesel::table! {
diesel::table! {
tagline (id) {
id -> Int4,
local_site_id -> Int4,
content -> Text,
published -> Timestamptz,
updated -> Nullable<Timestamptz>,
@ -966,7 +964,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));
@ -1028,7 +1025,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 content: String,
pub updated: Option<DateTime<Utc>>,
pub struct TaglineInsertForm {
pub content: Option<String>,
}
#[derive(Clone, Default)]
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = tagline))]
pub struct TaglineUpdateForm {
pub content: Option<String>,
pub updated: Option<Option<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,39 @@ impl CustomEmojiView {
}
}
pub async fn get_all(
pub async fn get_all(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
Self::list(pool, &None, None, None, true).await
}
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))
.order(custom_emoji::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)

@ -176,6 +176,7 @@ pub enum LemmyErrorType {
InvalidUnixTime,
InvalidBotAction,
CantBlockLocalInstance,
TaglineInvalid,
Unknown(String),
}

@ -22,6 +22,8 @@ const BIO_MAX_LENGTH: usize = 300;
const ALT_TEXT_MAX_LENGTH: usize = 300;
const SITE_NAME_MAX_LENGTH: usize = 20;
const SITE_NAME_MIN_LENGTH: usize = 1;
const TAGLINE_CONTENT_MIN_LENGTH: usize = 1;
const TAGLINE_CONTENT_MAX_LENGTH: usize = 50000;
const SITE_DESCRIPTION_MAX_LENGTH: usize = 150;
//Invisible unicode characters, taken from https://invisible-characters.com/
const FORBIDDEN_DISPLAY_CHARS: [char; 53] = [
@ -169,6 +171,20 @@ pub fn is_valid_body_field(body: &Option<String>, post: bool) -> LemmyResult<()>
Ok(())
}
pub fn is_valid_tagline_content(content: &str) -> LemmyResult<()> {
min_length_check(
content,
TAGLINE_CONTENT_MIN_LENGTH,
LemmyErrorType::TaglineInvalid,
)?;
max_length_check(
content,
TAGLINE_CONTENT_MAX_LENGTH,
LemmyErrorType::TaglineInvalid,
)?;
Ok(())
}
pub fn is_valid_bio_field(bio: &str) -> LemmyResult<()> {
max_length_check(bio, BIO_MAX_LENGTH, LemmyErrorType::BioLengthOverflow)
}

@ -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;

@ -106,6 +106,7 @@ use lemmy_api_crud::{
custom_emoji::{
create::create_custom_emoji,
delete::delete_custom_emoji,
list::list_custom_emojis,
update::update_custom_emoji,
},
post::{
@ -122,6 +123,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::register, delete::delete_account},
};
use lemmy_apub::api::{
@ -354,6 +361,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(
@ -361,7 +376,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)),
),
);
cfg.service(

Loading…
Cancel
Save