Compare commits

...

33 commits

Author SHA1 Message Date
Freakazoid182 ff21690fd8
Merge 920adccdb4 into b459949f57 2024-04-26 19:04:59 +05:30
Dessalines b459949f57 Version 0.19.4-beta.5 2024-04-25 19:59:24 -04:00
Dessalines 93f5df2d2a
Adding post_id desc to all post_aggregates indexes. Fixes #4618 (#4662)
* Adding post_id desc to all post_aggregates indexes. Fixes #4618

* Running pg_format

* Not rebuilding indexes which had no changes.
2024-04-25 18:19:02 -04:00
Nutomic cf426493e1
Fix community add mod check (fixes #4624) (#4667) 2024-04-25 11:47:38 -04:00
Freek van Zee 920adccdb4 Merge branch 'main' into feature/custom-emoji-and-tagline-views 2024-04-16 22:15:23 +02:00
Freek van Zee 4771085253 Update custom_emoji_view
Only keep get_all als helper function calling list with paging ignored

Only order on category when filtering on category
2024-04-16 22:03:06 +02:00
Freek van Zee 1f629cc02d Add ignore_page_limits for custom emojis
EmojiPicker needs to be able to retrieve all emojis in 1 call
2024-04-14 12:44:46 +02:00
Freek van Zee 999e9845e7 Update TaglineInserForm and TaglineUpdateForm 2024-04-11 21:40:50 +02:00
Freek van Zee 6935acba2f Remove local_site_id from tagline and custom_emoji 2024-04-08 23:14:03 +02:00
Freek van Zee 562c909f4b Updat misleading comments 2024-04-08 21:40:11 +02:00
Freek van Zee 8c7b3001ae Remove unecessary clone 2024-04-08 21:39:17 +02:00
Freek van Zee 7ce89fb5e6 Consolidate Tagline error types 2024-04-08 21:28:55 +02:00
SleeplessOne1917 5cf15a4c8c
Merge branch 'main' into feature/custom-emoji-and-tagline-views 2024-04-08 17:07:02 +00:00
Freakazoid182 6ffcc1f98a Use process_markdown instead of process_markdown_opt 2024-04-07 11:06:55 +02:00
Freakazoid182 7759602c9d Make content fields non optional
Add error types for tagline validation
2024-04-06 12:17:47 +02:00
SleeplessOne1917 55be9a14ac
Merge branch 'main' into feature/custom-emoji-and-tagline-views 2024-04-05 21:05:51 -04:00
Freakazoid182 b2b8c43757 Validate markdown on tagline 2024-04-05 23:34:43 +02:00
Freakazoid182 abdfc90dbe Check markdown for tagline 2024-04-05 23:20:59 +02:00
Freakazoid182 ead51517e4 Remove delete from tagline and custom emoji impls 2024-04-05 22:57:36 +02:00
Freakazoid182 bab417a73e Impl Crud for CustomEmoji 2024-04-05 22:55:36 +02:00
Freakazoid182 5342a22765 Move tagline endpoints under /admin 2024-04-05 22:36:37 +02:00
Freakazoid182 144c112247 Impl Crud for Tagline
Remove superfluous properties
2024-04-05 22:36:08 +02:00
Freakazoid182 f1b993f90e Get random tagline on site requets 2024-04-04 23:07:51 +02:00
Freakazoid182 2b1fdf106b Remove custom_emojis and taglines from site resource 2024-04-04 22:26:19 +02:00
Freakazoid182 5358908c17 Format through lint.sh 2024-04-03 22:49:02 +02:00
Freakazoid182 e536d39c2b Add delete tagline endpoint 2024-04-03 22:42:25 +02:00
Freakazoid182 ab938062e4 Add update tagline endpoint 2024-04-03 22:33:43 +02:00
Freakazoid182 a1a7e2ca33 Add create tagline endpoint 2024-04-03 22:14:25 +02:00
Freakazoid182 486c746eb9 Add category filter for custom emoji 2024-04-02 23:23:01 +02:00
Freakazoid182 17e2834e1b Remove unecessary TaglineView 2024-04-02 22:27:53 +02:00
Freakazoid182 10a8f01fad Apply linting 2024-03-31 17:42:48 +02:00
Freakazoid182 b4a86157a5 Add tagline list route 2024-03-31 17:25:54 +02:00
Freakazoid182 fd275231bc Add custom_emoji list route 2024-03-31 16:49:32 +02:00
37 changed files with 725 additions and 178 deletions

28
Cargo.lock generated
View file

@ -2582,13 +2582,13 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lemmy_api"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"actix-web",
"actix-web-httpauth",
"anyhow",
"base64 0.21.7",
"base64 0.22.0",
"bcrypt",
"captcha",
"chrono",
@ -2611,7 +2611,7 @@ dependencies = [
[[package]]
name = "lemmy_api_common"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"actix-web",
@ -2649,7 +2649,7 @@ dependencies = [
[[package]]
name = "lemmy_api_crud"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"accept-language",
"activitypub_federation",
@ -2672,7 +2672,7 @@ dependencies = [
[[package]]
name = "lemmy_apub"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"actix-web",
@ -2710,7 +2710,7 @@ dependencies = [
[[package]]
name = "lemmy_db_perf"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"anyhow",
"clap",
@ -2725,7 +2725,7 @@ dependencies = [
[[package]]
name = "lemmy_db_schema"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"anyhow",
@ -2765,7 +2765,7 @@ dependencies = [
[[package]]
name = "lemmy_db_views"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"actix-web",
"chrono",
@ -2787,7 +2787,7 @@ dependencies = [
[[package]]
name = "lemmy_db_views_actor"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"chrono",
"diesel",
@ -2807,7 +2807,7 @@ dependencies = [
[[package]]
name = "lemmy_db_views_moderator"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"diesel",
"diesel-async",
@ -2819,7 +2819,7 @@ dependencies = [
[[package]]
name = "lemmy_federate"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"anyhow",
@ -2842,7 +2842,7 @@ dependencies = [
[[package]]
name = "lemmy_routes"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"actix-web",
@ -2867,7 +2867,7 @@ dependencies = [
[[package]]
name = "lemmy_server"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"activitypub_federation",
"actix-cors",
@ -2910,7 +2910,7 @@ dependencies = [
[[package]]
name = "lemmy_utils"
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
dependencies = [
"actix-web",
"anyhow",

View file

@ -1,5 +1,5 @@
[workspace.package]
version = "0.19.4-beta.4"
version = "0.19.4-beta.5"
edition = "2021"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
@ -88,17 +88,17 @@ unused_self = "deny"
unwrap_used = "deny"
[workspace.dependencies]
lemmy_api = { version = "=0.19.4-beta.4", path = "./crates/api" }
lemmy_api_crud = { version = "=0.19.4-beta.4", path = "./crates/api_crud" }
lemmy_apub = { version = "=0.19.4-beta.4", path = "./crates/apub" }
lemmy_utils = { version = "=0.19.4-beta.4", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=0.19.4-beta.4", path = "./crates/db_schema" }
lemmy_api_common = { version = "=0.19.4-beta.4", path = "./crates/api_common" }
lemmy_routes = { version = "=0.19.4-beta.4", path = "./crates/routes" }
lemmy_db_views = { version = "=0.19.4-beta.4", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.4-beta.4", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.4-beta.4", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.4-beta.4", path = "./crates/federate" }
lemmy_api = { version = "=0.19.4-beta.5", path = "./crates/api" }
lemmy_api_crud = { version = "=0.19.4-beta.5", path = "./crates/api_crud" }
lemmy_apub = { version = "=0.19.4-beta.5", path = "./crates/apub" }
lemmy_utils = { version = "=0.19.4-beta.5", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=0.19.4-beta.5", path = "./crates/db_schema" }
lemmy_api_common = { version = "=0.19.4-beta.5", path = "./crates/api_common" }
lemmy_routes = { version = "=0.19.4-beta.5", path = "./crates/routes" }
lemmy_db_views = { version = "=0.19.4-beta.5", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.4-beta.5", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.4-beta.5", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.4-beta.5", path = "./crates/federate" }
activitypub_federation = { version = "0.5.4", default-features = false, features = [
"actix-web",
] }

View file

@ -36,8 +36,20 @@ pub async fn add_mod_to_community(
let community = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
// If user is admin and community is remote, explicitly check that he is a
// moderator. This is necessary because otherwise the action would be rejected
// by the community's home instance.
if local_user_view.local_user.admin && !community.local {
Err(LemmyErrorType::NotAModerator)?
let is_mod = CommunityModeratorView::is_community_moderator(
&mut context.pool(),
community.id,
local_user_view.person.id,
)
.await?;
if !is_mod {
Err(LemmyErrorType::NotAModerator)?
}
}
// Update in local database

View file

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

View file

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

View file

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

View file

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

View 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>,
}

View file

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

View file

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

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

View file

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

View file

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

View file

@ -4,4 +4,5 @@ pub mod custom_emoji;
pub mod post;
pub mod private_message;
pub mod site;
pub mod tagline;
pub mod user;

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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")]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

@ -1 +1 @@
Subproject commit c88dd1e3b36ee1617f1b86acf94c1b7946e97cd4
Subproject commit 866e4056656755f7b31e20094b46391e6931e3e7

View file

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

View file

@ -0,0 +1,6 @@
ALTER TABLE custom_emoji
DROP COLUMN local_site_id;
ALTER TABLE tagline
DROP COLUMN local_site_id;

View file

@ -0,0 +1,120 @@
DROP INDEX idx_post_aggregates_community_active;
DROP INDEX idx_post_aggregates_community_controversy;
DROP INDEX idx_post_aggregates_community_hot;
DROP INDEX idx_post_aggregates_community_most_comments;
DROP INDEX idx_post_aggregates_community_newest_comment_time;
DROP INDEX idx_post_aggregates_community_newest_comment_time_necro;
DROP INDEX idx_post_aggregates_community_published;
DROP INDEX idx_post_aggregates_community_published_asc;
DROP INDEX idx_post_aggregates_community_scaled;
DROP INDEX idx_post_aggregates_community_score;
DROP INDEX idx_post_aggregates_featured_community_active;
DROP INDEX idx_post_aggregates_featured_community_controversy;
DROP INDEX idx_post_aggregates_featured_community_hot;
DROP INDEX idx_post_aggregates_featured_community_most_comments;
DROP INDEX idx_post_aggregates_featured_community_newest_comment_time;
DROP INDEX idx_post_aggregates_featured_community_newest_comment_time_necr;
DROP INDEX idx_post_aggregates_featured_community_published;
DROP INDEX idx_post_aggregates_featured_community_published_asc;
DROP INDEX idx_post_aggregates_featured_community_scaled;
DROP INDEX idx_post_aggregates_featured_community_score;
DROP INDEX idx_post_aggregates_featured_local_active;
DROP INDEX idx_post_aggregates_featured_local_controversy;
DROP INDEX idx_post_aggregates_featured_local_hot;
DROP INDEX idx_post_aggregates_featured_local_most_comments;
DROP INDEX idx_post_aggregates_featured_local_newest_comment_time;
DROP INDEX idx_post_aggregates_featured_local_newest_comment_time_necro;
DROP INDEX idx_post_aggregates_featured_local_published;
DROP INDEX idx_post_aggregates_featured_local_published_asc;
DROP INDEX idx_post_aggregates_featured_local_scaled;
DROP INDEX idx_post_aggregates_featured_local_score;
CREATE INDEX idx_post_aggregates_community_active ON public.post_aggregates USING btree (community_id, featured_local DESC, hot_rank_active DESC, published DESC);
CREATE INDEX idx_post_aggregates_community_controversy ON public.post_aggregates USING btree (community_id, featured_local DESC, controversy_rank DESC);
CREATE INDEX idx_post_aggregates_community_hot ON public.post_aggregates USING btree (community_id, featured_local DESC, hot_rank DESC, published DESC);
CREATE INDEX idx_post_aggregates_community_most_comments ON public.post_aggregates USING btree (community_id, featured_local DESC, comments DESC, published DESC);
CREATE INDEX idx_post_aggregates_community_newest_comment_time ON public.post_aggregates USING btree (community_id, featured_local DESC, newest_comment_time DESC);
CREATE INDEX idx_post_aggregates_community_newest_comment_time_necro ON public.post_aggregates USING btree (community_id, featured_local DESC, newest_comment_time_necro DESC);
CREATE INDEX idx_post_aggregates_community_published ON public.post_aggregates USING btree (community_id, featured_local DESC, published DESC);
CREATE INDEX idx_post_aggregates_community_published_asc ON public.post_aggregates USING btree (community_id, featured_local DESC, public.reverse_timestamp_sort (published) DESC);
CREATE INDEX idx_post_aggregates_community_scaled ON public.post_aggregates USING btree (community_id, featured_local DESC, scaled_rank DESC, published DESC);
CREATE INDEX idx_post_aggregates_community_score ON public.post_aggregates USING btree (community_id, featured_local DESC, score DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_community_active ON public.post_aggregates USING btree (community_id, featured_community DESC, hot_rank_active DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_community_controversy ON public.post_aggregates USING btree (community_id, featured_community DESC, controversy_rank DESC);
CREATE INDEX idx_post_aggregates_featured_community_hot ON public.post_aggregates USING btree (community_id, featured_community DESC, hot_rank DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_community_most_comments ON public.post_aggregates USING btree (community_id, featured_community DESC, comments DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time ON public.post_aggregates USING btree (community_id, featured_community DESC, newest_comment_time DESC);
CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time_necr ON public.post_aggregates USING btree (community_id, featured_community DESC, newest_comment_time_necro DESC);
CREATE INDEX idx_post_aggregates_featured_community_published ON public.post_aggregates USING btree (community_id, featured_community DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_community_published_asc ON public.post_aggregates USING btree (community_id, featured_community DESC, public.reverse_timestamp_sort (published) DESC);
CREATE INDEX idx_post_aggregates_featured_community_scaled ON public.post_aggregates USING btree (community_id, featured_community DESC, scaled_rank DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_community_score ON public.post_aggregates USING btree (community_id, featured_community DESC, score DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_local_active ON public.post_aggregates USING btree (featured_local DESC, hot_rank_active DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_local_controversy ON public.post_aggregates USING btree (featured_local DESC, controversy_rank DESC);
CREATE INDEX idx_post_aggregates_featured_local_hot ON public.post_aggregates USING btree (featured_local DESC, hot_rank DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_local_most_comments ON public.post_aggregates USING btree (featured_local DESC, comments DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time ON public.post_aggregates USING btree (featured_local DESC, newest_comment_time DESC);
CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time_necro ON public.post_aggregates USING btree (featured_local DESC, newest_comment_time_necro DESC);
CREATE INDEX idx_post_aggregates_featured_local_published ON public.post_aggregates USING btree (featured_local DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_local_published_asc ON public.post_aggregates USING btree (featured_local DESC, public.reverse_timestamp_sort (published) DESC);
CREATE INDEX idx_post_aggregates_featured_local_scaled ON public.post_aggregates USING btree (featured_local DESC, scaled_rank DESC, published DESC);
CREATE INDEX idx_post_aggregates_featured_local_score ON public.post_aggregates USING btree (featured_local DESC, score DESC, published DESC);

View file

@ -0,0 +1,121 @@
-- Add , post_id DESC to all these
DROP INDEX idx_post_aggregates_community_active;
DROP INDEX idx_post_aggregates_community_controversy;
DROP INDEX idx_post_aggregates_community_hot;
DROP INDEX idx_post_aggregates_community_most_comments;
DROP INDEX idx_post_aggregates_community_newest_comment_time;
DROP INDEX idx_post_aggregates_community_newest_comment_time_necro;
DROP INDEX idx_post_aggregates_community_published;
DROP INDEX idx_post_aggregates_community_published_asc;
DROP INDEX idx_post_aggregates_community_scaled;
DROP INDEX idx_post_aggregates_community_score;
DROP INDEX idx_post_aggregates_featured_community_active;
DROP INDEX idx_post_aggregates_featured_community_controversy;
DROP INDEX idx_post_aggregates_featured_community_hot;
DROP INDEX idx_post_aggregates_featured_community_most_comments;
DROP INDEX idx_post_aggregates_featured_community_newest_comment_time;
DROP INDEX idx_post_aggregates_featured_community_newest_comment_time_necr;
DROP INDEX idx_post_aggregates_featured_community_published;
DROP INDEX idx_post_aggregates_featured_community_published_asc;
DROP INDEX idx_post_aggregates_featured_community_scaled;
DROP INDEX idx_post_aggregates_featured_community_score;
DROP INDEX idx_post_aggregates_featured_local_active;
DROP INDEX idx_post_aggregates_featured_local_controversy;
DROP INDEX idx_post_aggregates_featured_local_hot;
DROP INDEX idx_post_aggregates_featured_local_most_comments;
DROP INDEX idx_post_aggregates_featured_local_newest_comment_time;
DROP INDEX idx_post_aggregates_featured_local_newest_comment_time_necro;
DROP INDEX idx_post_aggregates_featured_local_published;
DROP INDEX idx_post_aggregates_featured_local_published_asc;
DROP INDEX idx_post_aggregates_featured_local_scaled;
DROP INDEX idx_post_aggregates_featured_local_score;
CREATE INDEX idx_post_aggregates_community_active ON public.post_aggregates USING btree (community_id, featured_local DESC, hot_rank_active DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_controversy ON public.post_aggregates USING btree (community_id, featured_local DESC, controversy_rank DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_hot ON public.post_aggregates USING btree (community_id, featured_local DESC, hot_rank DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_most_comments ON public.post_aggregates USING btree (community_id, featured_local DESC, comments DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_newest_comment_time ON public.post_aggregates USING btree (community_id, featured_local DESC, newest_comment_time DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_newest_comment_time_necro ON public.post_aggregates USING btree (community_id, featured_local DESC, newest_comment_time_necro DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_published ON public.post_aggregates USING btree (community_id, featured_local DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_published_asc ON public.post_aggregates USING btree (community_id, featured_local DESC, public.reverse_timestamp_sort (published) DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_scaled ON public.post_aggregates USING btree (community_id, featured_local DESC, scaled_rank DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_community_score ON public.post_aggregates USING btree (community_id, featured_local DESC, score DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_active ON public.post_aggregates USING btree (community_id, featured_community DESC, hot_rank_active DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_controversy ON public.post_aggregates USING btree (community_id, featured_community DESC, controversy_rank DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_hot ON public.post_aggregates USING btree (community_id, featured_community DESC, hot_rank DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_most_comments ON public.post_aggregates USING btree (community_id, featured_community DESC, comments DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time ON public.post_aggregates USING btree (community_id, featured_community DESC, newest_comment_time DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_newest_comment_time_necr ON public.post_aggregates USING btree (community_id, featured_community DESC, newest_comment_time_necro DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_published ON public.post_aggregates USING btree (community_id, featured_community DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_published_asc ON public.post_aggregates USING btree (community_id, featured_community DESC, public.reverse_timestamp_sort (published) DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_scaled ON public.post_aggregates USING btree (community_id, featured_community DESC, scaled_rank DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_community_score ON public.post_aggregates USING btree (community_id, featured_community DESC, score DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_active ON public.post_aggregates USING btree (featured_local DESC, hot_rank_active DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_controversy ON public.post_aggregates USING btree (featured_local DESC, controversy_rank DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_hot ON public.post_aggregates USING btree (featured_local DESC, hot_rank DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_most_comments ON public.post_aggregates USING btree (featured_local DESC, comments DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time ON public.post_aggregates USING btree (featured_local DESC, newest_comment_time DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_newest_comment_time_necro ON public.post_aggregates USING btree (featured_local DESC, newest_comment_time_necro DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_published ON public.post_aggregates USING btree (featured_local DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_published_asc ON public.post_aggregates USING btree (featured_local DESC, public.reverse_timestamp_sort (published) DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_scaled ON public.post_aggregates USING btree (featured_local DESC, scaled_rank DESC, published DESC, post_id DESC);
CREATE INDEX idx_post_aggregates_featured_local_score ON public.post_aggregates USING btree (featured_local DESC, score DESC, published DESC, post_id DESC);

View file

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