diff --git a/RELEASES.md b/RELEASES.md index 95b458240..bc8843866 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,10 @@ +# Lemmy v0.10.3 Release (2021-04-07) + +- Fixing instances page. +- Fixed unban not working. +- Fixed post title fetching and cross-post search. +- Fixed navigating to a user page. + # Lemmy v0.10.2 Release (2021-04-05) - Forcing a crash if config.hjson fails to load. Should show errors easier. diff --git a/ansible/VERSION b/ansible/VERSION index 5eef0f10e..a3f5a8ed4 100644 --- a/ansible/VERSION +++ b/ansible/VERSION @@ -1 +1 @@ -0.10.2 +0.10.3 diff --git a/api_tests/package.json b/api_tests/package.json index 7cb949594..ca21c4130 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -16,7 +16,7 @@ "eslint": "^7.18.0", "eslint-plugin-jane": "^9.0.3", "jest": "^26.6.3", - "lemmy-js-client": "0.10.0-rc.13", + "lemmy-js-client": "0.11.0-rc.3", "node-fetch": "^2.6.1", "prettier": "^2.1.2", "ts-jest": "^26.4.4", diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index 7be6f4c59..a86c1259a 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -31,7 +31,6 @@ function assertCommunityFederation( expect(communityOne.community.published).toBe( communityTwo.community.published ); - expect(communityOne.creator.actor_id).toBe(communityTwo.creator.actor_id); expect(communityOne.community.nsfw).toBe(communityTwo.community.nsfw); expect(communityOne.community.removed).toBe(communityTwo.community.removed); expect(communityOne.community.deleted).toBe(communityTwo.community.deleted); diff --git a/api_tests/src/private_message.spec.ts b/api_tests/src/private_message.spec.ts index 5539b19c7..11b41cb17 100644 --- a/api_tests/src/private_message.spec.ts +++ b/api_tests/src/private_message.spec.ts @@ -15,8 +15,8 @@ let recipient_id: number; beforeAll(async () => { await setupLogins(); - let follow = await followBeta(alpha); - recipient_id = follow.community_view.creator.id; + await followBeta(alpha); + recipient_id = 3; }); afterAll(async () => { diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock index 8f8abf873..1e459523b 100644 --- a/api_tests/yarn.lock +++ b/api_tests/yarn.lock @@ -3233,10 +3233,10 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "~0.3.2" -lemmy-js-client@0.10.0-rc.13: - version "0.10.0-rc.13" - resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.10.0-rc.13.tgz#ea2e88857243374d7fbd49ee6b4bb94c34359d85" - integrity sha512-zodvYkwBYR7iP27ah6L/QPUphUUdq38kCH7QF2CUYBrsSAEkGmq2kdz+iusnQ1Ht7Ad80GtYycFprsZBveV5eQ== +lemmy-js-client@0.11.0-rc.3: + version "0.11.0-rc.3" + resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.11.0-rc.3.tgz#dd4727ca4d16fe9593368725aacfd9e7a8d52548" + integrity sha512-16mgl+TS1+0UHiY+ZKPuqHfbrn93h8K8tJ+kKJ1pjT2WhG23o0B8dLahG1jDQPG+dkXpR6PZxYudMYjuO8WvjQ== leven@^3.1.0: version "3.1.0" diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index f1cf570c0..3e6ae3e47 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -10,11 +10,7 @@ use lemmy_api_common::{ }; use lemmy_apub::{ActorType, CommunityType, UserType}; use lemmy_db_queries::{ - source::{ - comment::Comment_, - community::{CommunityModerator_, Community_}, - post::Post_, - }, + source::{comment::Comment_, community::CommunityModerator_, post::Post_}, Bannable, Crud, Followable, @@ -324,12 +320,6 @@ impl Perform for TransferCommunity { let data: &TransferCommunity = &self; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - let community_id = data.community_id; - let read_community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) - }) - .await??; - let site_creator_id = blocking(context.pool(), move |conn| { Site::read(conn, 1).map(|s| s.creator_id) }) @@ -337,7 +327,7 @@ impl Perform for TransferCommunity { let mut admins = blocking(context.pool(), move |conn| PersonViewSafe::admins(conn)).await??; - // Making sure the creator, if an admin, is at the top + // Making sure the site creator, if an admin, is at the top let creator_index = admins .iter() .position(|r| r.person.id == site_creator_id) @@ -345,8 +335,15 @@ impl Perform for TransferCommunity { let creator_person = admins.remove(creator_index); admins.insert(0, creator_person); - // Make sure user is the creator, or an admin - if local_user_view.person.id != read_community.creator_id + // Fetch the community mods + let community_id = data.community_id; + let mut community_mods = blocking(context.pool(), move |conn| { + CommunityModeratorView::for_community(conn, community_id) + }) + .await??; + + // Make sure transferrer is either the top community mod, or an admin + if local_user_view.person.id != community_mods[0].moderator.id && !admins .iter() .map(|a| a.person.id) @@ -355,19 +352,8 @@ impl Perform for TransferCommunity { return Err(ApiError::err("not_an_admin").into()); } - let community_id = data.community_id; - let new_creator = data.person_id; - let update = move |conn: &'_ _| Community::update_creator(conn, community_id, new_creator); - if blocking(context.pool(), update).await?.is_err() { - return Err(ApiError::err("couldnt_update_community").into()); - }; - - // You also have to re-do the community_moderator table, reordering it. - let community_id = data.community_id; - let mut community_mods = blocking(context.pool(), move |conn| { - CommunityModeratorView::for_community(conn, community_id) - }) - .await??; + // You have to re-do the community_moderator table, reordering it. + // Add the transferee to the top let creator_index = community_mods .iter() .position(|r| r.moderator.id == data.person_id) @@ -375,6 +361,7 @@ impl Perform for TransferCommunity { let creator_person = community_mods.remove(creator_index); community_mods.insert(0, creator_person); + // Delete all the mods let community_id = data.community_id; blocking(context.pool(), move |conn| { CommunityModerator::delete_for_community(conn, community_id) @@ -382,6 +369,7 @@ impl Perform for TransferCommunity { .await??; // TODO: this should probably be a bulk operation + // Re-add the mods, in the new order for cmod in &community_mods { let community_moderator_form = CommunityModeratorForm { community_id: cmod.community.id, @@ -395,6 +383,8 @@ impl Perform for TransferCommunity { } // Mod tables + // TODO there should probably be another table for transfer community + // Right now, it will just look like it modded them twice let form = ModAddCommunityForm { mod_person_id: local_user_view.person.id, other_person_id: data.person_id, diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 5dc678be6..0ba3fbea2 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -1,9 +1,9 @@ use actix_web::{web, web::Data}; +use captcha::Captcha; use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*}; use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation}; use serde::Deserialize; -use std::{env, process::Command}; mod comment; mod comment_report; @@ -63,6 +63,9 @@ pub async fn match_websocket_operation( UserOperation::SaveUserSettings => { do_websocket_operation::(context, id, op, data).await } + UserOperation::ChangePassword => { + do_websocket_operation::(context, id, op, data).await + } UserOperation::GetReportCount => { do_websocket_operation::(context, id, op, data).await } @@ -158,60 +161,23 @@ where serialize_websocket_message(&op, &res) } -pub(crate) fn captcha_espeak_wav_base64(captcha: &str) -> Result { - let mut built_text = String::new(); +/// Converts the captcha to a base64 encoded wav audio file +pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String { + let letters = captcha.as_wav(); - // Building proper speech text for espeak - for mut c in captcha.chars() { - let new_str = if c.is_alphabetic() { - if c.is_lowercase() { - c.make_ascii_uppercase(); - format!("lower case {} ... ", c) - } else { - c.make_ascii_uppercase(); - format!("capital {} ... ", c) - } - } else { - format!("{} ...", c) - }; + let mut concat_letters: Vec = Vec::new(); - built_text.push_str(&new_str); + for letter in letters { + let bytes = letter.unwrap_or_default(); + concat_letters.extend(bytes); } - espeak_wav_base64(&built_text) -} - -pub(crate) fn espeak_wav_base64(text: &str) -> Result { - // Make a temp file path - let uuid = uuid::Uuid::new_v4().to_string(); - let file_path = format!( - "{}/lemmy_espeak_{}.wav", - env::temp_dir().to_string_lossy(), - &uuid - ); - - // Write the wav file - Command::new("espeak") - .arg("-w") - .arg(&file_path) - .arg(text) - .status()?; - - // Read the wav file bytes - let bytes = std::fs::read(&file_path)?; - - // Delete the file - std::fs::remove_file(file_path)?; - // Convert to base64 - let base64 = base64::encode(bytes); - - Ok(base64) + base64::encode(concat_letters) } #[cfg(test)] mod tests { - use crate::captcha_espeak_wav_base64; use lemmy_api_common::check_validator_time; use lemmy_db_queries::{establish_unpooled_connection, source::local_user::LocalUser_, Crud}; use lemmy_db_schema::source::{ @@ -253,9 +219,4 @@ mod tests { let num_deleted = Person::delete(&conn, inserted_person.id).unwrap(); assert_eq!(1, num_deleted); } - - #[test] - fn test_espeak() { - assert!(captcha_espeak_wav_base64("WxRt2l").is_ok()) - } } diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs index 656ddf971..0acb29f15 100644 --- a/crates/api/src/local_user.rs +++ b/crates/api/src/local_user.rs @@ -1,4 +1,4 @@ -use crate::{captcha_espeak_wav_base64, Perform}; +use crate::{captcha_as_wav_base64, Perform}; use actix_web::web::Data; use anyhow::Context; use bcrypt::verify; @@ -18,7 +18,6 @@ use lemmy_db_queries::{ diesel_option_overwrite_to_url, source::{ comment::Comment_, - community::Community_, local_user::LocalUser_, password_reset_request::PasswordResetRequest_, person::Person_, @@ -33,7 +32,6 @@ use lemmy_db_schema::{ naive_now, source::{ comment::Comment, - community::*, local_user::{LocalUser, LocalUserForm}, moderator::*, password_reset_request::*, @@ -60,7 +58,7 @@ use lemmy_utils::{ email::send_email, location_info, settings::structs::Settings, - utils::{generate_random_string, is_valid_preferred_username, naive_from_unix}, + utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix}, ApiError, ConnectionId, LemmyError, @@ -135,13 +133,11 @@ impl Perform for GetCaptcha { let answer = captcha.chars_as_string(); - let png_byte_array = captcha.as_png().expect("failed to generate captcha"); - - let png = base64::encode(png_byte_array); + let png = captcha.as_base64().expect("failed to generate captcha"); let uuid = uuid::Uuid::new_v4().to_string(); - let wav = captcha_espeak_wav_base64(&answer).ok(); + let wav = captcha_as_wav_base64(&captcha); let captcha_item = CaptchaItem { answer, @@ -174,7 +170,7 @@ impl Perform for SaveUserSettings { let banner = diesel_option_overwrite_to_url(&data.banner)?; let email = diesel_option_overwrite(&data.email); let bio = diesel_option_overwrite(&data.bio); - let preferred_username = diesel_option_overwrite(&data.preferred_username); + let display_name = diesel_option_overwrite(&data.display_name); let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id); if let Some(Some(bio)) = &bio { @@ -183,59 +179,30 @@ impl Perform for SaveUserSettings { } } - if let Some(Some(preferred_username)) = &preferred_username { - if !is_valid_preferred_username(preferred_username.trim()) { + if let Some(Some(display_name)) = &display_name { + if !is_valid_display_name(display_name.trim()) { return Err(ApiError::err("invalid_username").into()); } } + if let Some(Some(matrix_user_id)) = &matrix_user_id { + if !is_valid_matrix_id(matrix_user_id) { + return Err(ApiError::err("invalid_matrix_id").into()); + } + } + let local_user_id = local_user_view.local_user.id; let person_id = local_user_view.person.id; - let password_encrypted = match &data.new_password { - Some(new_password) => { - match &data.new_password_verify { - Some(new_password_verify) => { - password_length_check(&new_password)?; - - // Make sure passwords match - if new_password != new_password_verify { - return Err(ApiError::err("passwords_dont_match").into()); - } - - // Check the old password - match &data.old_password { - Some(old_password) => { - let valid: bool = - verify(old_password, &local_user_view.local_user.password_encrypted) - .unwrap_or(false); - if !valid { - return Err(ApiError::err("password_incorrect").into()); - } - let new_password = new_password.to_owned(); - let user = blocking(context.pool(), move |conn| { - LocalUser::update_password(conn, local_user_id, &new_password) - }) - .await??; - user.password_encrypted - } - None => return Err(ApiError::err("password_incorrect").into()), - } - } - None => return Err(ApiError::err("passwords_dont_match").into()), - } - } - None => local_user_view.local_user.password_encrypted, - }; - let default_listing_type = data.default_listing_type; let default_sort_type = data.default_sort_type; + let password_encrypted = local_user_view.local_user.password_encrypted; let person_form = PersonForm { name: local_user_view.person.name, avatar, banner, inbox_url: None, - preferred_username, + display_name, published: None, updated: Some(naive_now()), banned: None, @@ -267,6 +234,7 @@ impl Perform for SaveUserSettings { email, password_encrypted, show_nsfw: data.show_nsfw, + show_scores: data.show_scores, theme: data.theme.to_owned(), default_sort_type, default_listing_type, @@ -301,6 +269,49 @@ impl Perform for SaveUserSettings { } } +#[async_trait::async_trait(?Send)] +impl Perform for ChangePassword { + type Response = LoginResponse; + + async fn perform( + &self, + context: &Data, + _websocket_id: Option, + ) -> Result { + let data: &ChangePassword = &self; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; + + password_length_check(&data.new_password)?; + + // Make sure passwords match + if data.new_password != data.new_password_verify { + return Err(ApiError::err("passwords_dont_match").into()); + } + + // Check the old password + let valid: bool = verify( + &data.old_password, + &local_user_view.local_user.password_encrypted, + ) + .unwrap_or(false); + if !valid { + return Err(ApiError::err("password_incorrect").into()); + } + + let local_user_id = local_user_view.local_user.id; + let new_password = data.new_password.to_owned(); + let updated_local_user = blocking(context.pool(), move |conn| { + LocalUser::update_password(conn, local_user_id, &new_password) + }) + .await??; + + // Return the jwt + Ok(LoginResponse { + jwt: Claims::jwt(updated_local_user.id.0)?, + }) + } +} + #[async_trait::async_trait(?Send)] impl Perform for AddAdmin { type Response = AddAdminResponse; @@ -394,10 +405,9 @@ impl Perform for BanPerson { .await??; // Communities - blocking(context.pool(), move |conn: &'_ _| { - Community::update_removed_for_creator(conn, banned_person_id, true) - }) - .await??; + // Remove all communities where they're the top mod + // TODO couldn't get group by's working in diesel, + // for now, remove the communities manually // Comments blocking(context.pool(), move |conn: &'_ _| { diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index dccc3bce5..2f820f1a2 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -418,3 +418,12 @@ pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { Ok(()) } } + +/// Checks the site description length +pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> { + if description.len() > 150 { + Err(ApiError::err("site_description_length_overflow").into()) + } else { + Ok(()) + } +} diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 7767da460..6402096c9 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -39,32 +39,41 @@ pub struct GetCaptchaResponse { #[derive(Serialize)] pub struct CaptchaResponse { - pub png: String, // A Base64 encoded png - pub wav: Option, // A Base64 encoded wav audio + pub png: String, // A Base64 encoded png + pub wav: String, // A Base64 encoded wav audio pub uuid: String, } #[derive(Deserialize)] pub struct SaveUserSettings { pub show_nsfw: Option, + pub show_scores: Option, pub theme: Option, pub default_sort_type: Option, pub default_listing_type: Option, pub lang: Option, pub avatar: Option, pub banner: Option, - pub preferred_username: Option, + pub display_name: Option, pub email: Option, pub bio: Option, pub matrix_user_id: Option, + pub show_avatars: Option, pub new_password: Option, pub new_password_verify: Option, pub old_password: Option, - pub show_avatars: Option, pub send_notifications_to_email: Option, pub auth: String, } +#[derive(Deserialize)] +pub struct ChangePassword { + pub new_password: String, + pub new_password_verify: String, + pub old_password: String, + pub auth: String, +} + #[derive(Serialize)] pub struct LoginResponse { pub jwt: String, diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index 090fa8f5b..397b5a72b 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -18,7 +18,6 @@ use lemmy_db_views_moderator::{ mod_sticky_post_view::ModStickyPostView, }; use serde::{Deserialize, Serialize}; -use url::Url; #[derive(Deserialize, Debug)] pub struct Search { @@ -65,9 +64,10 @@ pub struct GetModlogResponse { #[derive(Deserialize)] pub struct CreateSite { pub name: String, + pub sidebar: Option, pub description: Option, - pub icon: Option, - pub banner: Option, + pub icon: Option, + pub banner: Option, pub enable_downvotes: bool, pub open_registration: bool, pub enable_nsfw: bool, @@ -77,6 +77,7 @@ pub struct CreateSite { #[derive(Deserialize)] pub struct EditSite { pub name: String, + pub sidebar: Option, pub description: Option, pub icon: Option, pub banner: Option, diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index bef376f0b..393b3746a 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -75,7 +75,6 @@ impl PerformCrud for CreateCommunity { description: data.description.to_owned(), icon, banner, - creator_id: local_user_view.person.id, nsfw: data.nsfw, actor_id: Some(community_actor_id.to_owned()), private_key: Some(keypair.private_key), diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index 9b52660f6..b94c153b2 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -7,7 +7,10 @@ use lemmy_db_schema::source::{ community::*, moderator::{ModRemoveCommunity, ModRemoveCommunityForm}, }; -use lemmy_db_views_actor::community_view::CommunityView; +use lemmy_db_views_actor::{ + community_moderator_view::CommunityModeratorView, + community_view::CommunityView, +}; use lemmy_utils::{utils::naive_from_unix, ApiError, ConnectionId, LemmyError}; use lemmy_websocket::{LemmyContext, UserOperationCrud}; @@ -23,13 +26,15 @@ impl PerformCrud for DeleteCommunity { let data: &DeleteCommunity = &self; let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - // Verify its the creator (only a creator can delete the community) + // Fetch the community mods let community_id = data.community_id; - let read_community = blocking(context.pool(), move |conn| { - Community::read(conn, community_id) + let community_mods = blocking(context.pool(), move |conn| { + CommunityModeratorView::for_community(conn, community_id) }) .await??; - if read_community.creator_id != local_user_view.person.id { + + // Make sure deleter is the top mod + if local_user_view.person.id != community_mods[0].moderator.id { return Err(ApiError::err("no_community_edit_allowed").into()); } diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index 0a0540fa7..9e8339fbe 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -61,7 +61,6 @@ impl PerformCrud for EditCommunity { let community_form = CommunityForm { name: read_community.name, title: data.title.to_owned(), - creator_id: read_community.creator_id, description: data.description.to_owned(), icon, banner, diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 855e41c1f..b9889bf1e 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -1,7 +1,18 @@ use crate::PerformCrud; use actix_web::web::Data; -use lemmy_api_common::{blocking, get_local_user_view_from_jwt, is_admin, site::*}; -use lemmy_db_queries::{source::site::Site_, Crud}; +use lemmy_api_common::{ + blocking, + get_local_user_view_from_jwt, + is_admin, + site::*, + site_description_length_check, +}; +use lemmy_db_queries::{ + diesel_option_overwrite, + diesel_option_overwrite_to_url, + source::site::Site_, + Crud, +}; use lemmy_db_schema::source::site::{Site, *}; use lemmy_db_views::site_view::SiteView; use lemmy_utils::{ @@ -36,11 +47,21 @@ impl PerformCrud for CreateSite { // Make sure user is an admin is_admin(&local_user_view)?; + let sidebar = diesel_option_overwrite(&data.sidebar); + let description = diesel_option_overwrite(&data.description); + let icon = diesel_option_overwrite_to_url(&data.icon)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; + + if let Some(Some(desc)) = &description { + site_description_length_check(desc)?; + } + let site_form = SiteForm { name: data.name.to_owned(), - description: data.description.to_owned(), - icon: Some(data.icon.to_owned().map(|url| url.into())), - banner: Some(data.banner.to_owned().map(|url| url.into())), + sidebar, + description, + icon, + banner, creator_id: local_user_view.person.id, enable_downvotes: data.enable_downvotes, open_registration: data.open_registration, diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index 270665195..d3bf0d2d1 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -43,6 +43,7 @@ impl PerformCrud for GetSite { let create_site = CreateSite { name: setup.site_name.to_owned(), + sidebar: None, description: None, icon: None, banner: None, diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index 06940a75c..e9c5828df 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -5,8 +5,14 @@ use lemmy_api_common::{ get_local_user_view_from_jwt, is_admin, site::{EditSite, SiteResponse}, + site_description_length_check, +}; +use lemmy_db_queries::{ + diesel_option_overwrite, + diesel_option_overwrite_to_url, + source::site::Site_, + Crud, }; -use lemmy_db_queries::{diesel_option_overwrite_to_url, source::site::Site_, Crud}; use lemmy_db_schema::{ naive_now, source::site::{Site, SiteForm}, @@ -39,12 +45,19 @@ impl PerformCrud for EditSite { let found_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??; + let sidebar = diesel_option_overwrite(&data.sidebar); + let description = diesel_option_overwrite(&data.description); let icon = diesel_option_overwrite_to_url(&data.icon)?; let banner = diesel_option_overwrite_to_url(&data.banner)?; + if let Some(Some(desc)) = &description { + site_description_length_check(desc)?; + } + let site_form = SiteForm { name: data.name.to_owned(), - description: data.description.to_owned(), + sidebar, + description, icon, banner, creator_id: found_site.creator_id, diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 63a6474d6..96bc3be9a 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -133,6 +133,7 @@ impl PerformCrud for Register { default_listing_type: Some(ListingType::Subscribed as i16), lang: Some("browser".into()), show_avatars: Some(true), + show_scores: Some(true), send_notifications_to_email: Some(false), }; @@ -177,7 +178,6 @@ impl PerformCrud for Register { name: default_community_name.to_string(), title: "The Default Community".to_string(), description: Some("The Default Community".to_string()), - creator_id: inserted_person.id, actor_id: Some(actor_id.to_owned()), private_key: Some(main_community_keypair.private_key), public_key: Some(main_community_keypair.public_key), diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index acf1f045c..f886fd1b0 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -1,6 +1,6 @@ use crate::{ extensions::{context::lemmy_context, group_extension::GroupExtension}, - fetcher::{community::fetch_community_mods, person::get_or_fetch_and_upsert_person}, + fetcher::community::fetch_community_mods, generate_moderators_url, objects::{ check_object_domain, @@ -140,24 +140,7 @@ impl FromApubToForm for CommunityForm { request_counter: &mut i32, _mod_action_allowed: bool, ) -> Result { - let moderator_uris = fetch_community_mods(context, group, request_counter).await?; - let creator = if let Some(creator_uri) = moderator_uris.first() { - get_or_fetch_and_upsert_person(creator_uri, context, request_counter) - } else { - // NOTE: code for compatibility with lemmy v0.9.9 - let creator_uri = group - .inner - .attributed_to() - .map(|a| a.as_many()) - .flatten() - .map(|a| a.first()) - .flatten() - .map(|a| a.as_xsd_any_uri()) - .flatten() - .context(location_info!())?; - get_or_fetch_and_upsert_person(creator_uri, context, request_counter) - } - .await?; + fetch_community_mods(context, group, request_counter).await?; let name = group .inner @@ -215,7 +198,6 @@ impl FromApubToForm for CommunityForm { name, title, description, - creator_id: creator.id, removed: None, published: group.inner.published().map(|u| u.to_owned().naive_local()), updated: group.inner.updated().map(|u| u.to_owned().naive_local()), diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs index 25c785d84..3e468d5c8 100644 --- a/crates/apub/src/objects/person.rs +++ b/crates/apub/src/objects/person.rs @@ -64,7 +64,8 @@ impl ToApub for DbPerson { set_content_and_source(&mut person, bio)?; } - if let Some(i) = self.preferred_username.to_owned() { + // In apub, the "name" is a display name + if let Some(i) = self.display_name.to_owned() { person.set_name(i); } @@ -161,7 +162,7 @@ impl FromApubToForm for PersonForm { .preferred_username() .context(location_info!())? .to_string(); - let preferred_username: Option = person + let display_name: Option = person .name() .map(|n| n.one()) .flatten() @@ -176,12 +177,12 @@ impl FromApubToForm for PersonForm { .map(|s| s.to_owned().into()); check_slurs(&name)?; - check_slurs_opt(&preferred_username)?; + check_slurs_opt(&display_name)?; check_slurs_opt(&bio)?; Ok(PersonForm { name, - preferred_username: Some(preferred_username), + display_name: Some(display_name), banned: None, deleted: None, avatar: avatar.map(|o| o.map(|i| i.into())), diff --git a/crates/db_queries/src/aggregates/comment_aggregates.rs b/crates/db_queries/src/aggregates/comment_aggregates.rs index a2bea11ef..898c57da3 100644 --- a/crates/db_queries/src/aggregates/comment_aggregates.rs +++ b/crates/db_queries/src/aggregates/comment_aggregates.rs @@ -58,7 +58,6 @@ mod tests { let new_community = CommunityForm { name: "TIL_comment_agg".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -142,5 +141,9 @@ mod tests { Person::delete(&conn, another_inserted_person.id).unwrap(); let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap(); assert_eq!(1, person_num_deleted); + + // Delete the community + let community_num_deleted = Community::delete(&conn, inserted_community.id).unwrap(); + assert_eq!(1, community_num_deleted); } } diff --git a/crates/db_queries/src/aggregates/community_aggregates.rs b/crates/db_queries/src/aggregates/community_aggregates.rs index 25c0b394e..c668c15ac 100644 --- a/crates/db_queries/src/aggregates/community_aggregates.rs +++ b/crates/db_queries/src/aggregates/community_aggregates.rs @@ -62,7 +62,6 @@ mod tests { let new_community = CommunityForm { name: "TIL_community_agg".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -71,7 +70,6 @@ mod tests { let another_community = CommunityForm { name: "TIL_community_agg_2".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -169,6 +167,14 @@ mod tests { let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap(); assert_eq!(1, person_num_deleted); + // Delete the community + let community_num_deleted = Community::delete(&conn, inserted_community.id).unwrap(); + assert_eq!(1, community_num_deleted); + + let another_community_num_deleted = + Community::delete(&conn, another_inserted_community.id).unwrap(); + assert_eq!(1, another_community_num_deleted); + // Should be none found, since the creator was deleted let after_delete = CommunityAggregates::read(&conn, inserted_community.id); assert!(after_delete.is_err()); diff --git a/crates/db_queries/src/aggregates/person_aggregates.rs b/crates/db_queries/src/aggregates/person_aggregates.rs index 953f74ee7..56d72d38b 100644 --- a/crates/db_queries/src/aggregates/person_aggregates.rs +++ b/crates/db_queries/src/aggregates/person_aggregates.rs @@ -58,7 +58,6 @@ mod tests { let new_community = CommunityForm { name: "TIL_site_agg".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -160,6 +159,10 @@ mod tests { assert_eq!(1, person_num_deleted); Person::delete(&conn, another_inserted_person.id).unwrap(); + // Delete the community + let community_num_deleted = Community::delete(&conn, inserted_community.id).unwrap(); + assert_eq!(1, community_num_deleted); + // Should be none found let after_delete = PersonAggregates::read(&conn, inserted_person.id); assert!(after_delete.is_err()); diff --git a/crates/db_queries/src/aggregates/post_aggregates.rs b/crates/db_queries/src/aggregates/post_aggregates.rs index fe7381316..2fcb6f5d2 100644 --- a/crates/db_queries/src/aggregates/post_aggregates.rs +++ b/crates/db_queries/src/aggregates/post_aggregates.rs @@ -62,7 +62,6 @@ mod tests { let new_community = CommunityForm { name: "TIL_community_agg".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -149,6 +148,10 @@ mod tests { let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap(); assert_eq!(1, person_num_deleted); + // Delete the community + let community_num_deleted = Community::delete(&conn, inserted_community.id).unwrap(); + assert_eq!(1, community_num_deleted); + // Should be none found, since the creator was deleted let after_delete = PostAggregates::read(&conn, inserted_post.id); assert!(after_delete.is_err()); diff --git a/crates/db_queries/src/aggregates/site_aggregates.rs b/crates/db_queries/src/aggregates/site_aggregates.rs index 64fbdf7df..995462e1a 100644 --- a/crates/db_queries/src/aggregates/site_aggregates.rs +++ b/crates/db_queries/src/aggregates/site_aggregates.rs @@ -49,6 +49,7 @@ mod tests { let site_form = SiteForm { name: "test_site".into(), + sidebar: None, description: None, icon: None, banner: None, @@ -63,7 +64,6 @@ mod tests { let new_community = CommunityForm { name: "TIL_site_agg".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -118,6 +118,10 @@ mod tests { let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap(); assert_eq!(1, person_num_deleted); + // Delete the community + let community_num_deleted = Community::delete(&conn, inserted_community.id).unwrap(); + assert_eq!(1, community_num_deleted); + let after_delete = SiteAggregates::read(&conn); assert!(after_delete.is_err()); } diff --git a/crates/db_queries/src/source/comment.rs b/crates/db_queries/src/source/comment.rs index 8d77626aa..1eec0c987 100644 --- a/crates/db_queries/src/source/comment.rs +++ b/crates/db_queries/src/source/comment.rs @@ -254,7 +254,6 @@ mod tests { let new_community = CommunityForm { name: "test community".to_string(), title: "nada".to_owned(), - creator_id: inserted_person.id, ..CommunityForm::default() }; diff --git a/crates/db_queries/src/source/community.rs b/crates/db_queries/src/source/community.rs index 1970eef88..3f1f04767 100644 --- a/crates/db_queries/src/source/community.rs +++ b/crates/db_queries/src/source/community.rs @@ -26,7 +26,6 @@ mod safe_type { name, title, description, - creator_id, removed, published, updated, @@ -46,7 +45,6 @@ mod safe_type { name, title, description, - creator_id, removed, published, updated, @@ -122,16 +120,6 @@ pub trait Community_ { community_id: CommunityId, new_removed: bool, ) -> Result; - fn update_removed_for_creator( - conn: &PgConnection, - for_creator_id: PersonId, - new_removed: bool, - ) -> Result, Error>; - fn update_creator( - conn: &PgConnection, - community_id: CommunityId, - new_creator_id: PersonId, - ) -> Result; fn distinct_federated_communities(conn: &PgConnection) -> Result, Error>; fn read_from_followers_url( conn: &PgConnection, @@ -170,28 +158,6 @@ impl Community_ for Community { .get_result::(conn) } - fn update_removed_for_creator( - conn: &PgConnection, - for_creator_id: PersonId, - new_removed: bool, - ) -> Result, Error> { - use lemmy_db_schema::schema::community::dsl::*; - diesel::update(community.filter(creator_id.eq(for_creator_id))) - .set((removed.eq(new_removed), updated.eq(naive_now()))) - .get_results::(conn) - } - - fn update_creator( - conn: &PgConnection, - community_id: CommunityId, - new_creator_id: PersonId, - ) -> Result { - use lemmy_db_schema::schema::community::dsl::*; - diesel::update(community.find(community_id)) - .set((creator_id.eq(new_creator_id), updated.eq(naive_now()))) - .get_result::(conn) - } - fn distinct_federated_communities(conn: &PgConnection) -> Result, Error> { use lemmy_db_schema::schema::community::dsl::*; community.select(actor_id).distinct().load::(conn) @@ -363,7 +329,6 @@ mod tests { let new_community = CommunityForm { name: "TIL".into(), - creator_id: inserted_person.id, title: "nada".to_owned(), ..CommunityForm::default() }; @@ -372,7 +337,6 @@ mod tests { let expected_community = Community { id: inserted_community.id, - creator_id: inserted_person.id, name: "TIL".into(), title: "nada".to_owned(), description: None, diff --git a/crates/db_queries/src/source/local_user.rs b/crates/db_queries/src/source/local_user.rs index 18720ceba..d1fad2e85 100644 --- a/crates/db_queries/src/source/local_user.rs +++ b/crates/db_queries/src/source/local_user.rs @@ -24,6 +24,7 @@ mod safe_settings_type { show_avatars, send_notifications_to_email, validator_time, + show_scores, ); impl ToSafeSettings for LocalUser { @@ -43,6 +44,7 @@ mod safe_settings_type { show_avatars, send_notifications_to_email, validator_time, + show_scores, ) } } diff --git a/crates/db_queries/src/source/moderator.rs b/crates/db_queries/src/source/moderator.rs index c641fffc7..14bb07f1c 100644 --- a/crates/db_queries/src/source/moderator.rs +++ b/crates/db_queries/src/source/moderator.rs @@ -224,7 +224,6 @@ mod tests { let new_community = CommunityForm { name: "mod_community".to_string(), title: "nada".to_owned(), - creator_id: inserted_person.id, ..CommunityForm::default() }; diff --git a/crates/db_queries/src/source/person.rs b/crates/db_queries/src/source/person.rs index 35ed540c0..2d332bd01 100644 --- a/crates/db_queries/src/source/person.rs +++ b/crates/db_queries/src/source/person.rs @@ -15,7 +15,7 @@ mod safe_type { type Columns = ( id, name, - preferred_username, + display_name, avatar, banned, published, @@ -37,7 +37,7 @@ mod safe_type { ( id, name, - preferred_username, + display_name, avatar, banned, published, @@ -63,7 +63,7 @@ mod safe_type_alias_1 { type Columns = ( id, name, - preferred_username, + display_name, avatar, banned, published, @@ -85,7 +85,7 @@ mod safe_type_alias_1 { ( id, name, - preferred_username, + display_name, avatar, banned, published, @@ -111,7 +111,7 @@ mod safe_type_alias_2 { type Columns = ( id, name, - preferred_username, + display_name, avatar, banned, published, @@ -133,7 +133,7 @@ mod safe_type_alias_2 { ( id, name, - preferred_username, + display_name, avatar, banned, published, @@ -236,7 +236,7 @@ impl Person_ for Person { diesel::update(person.find(person_id)) .set(( - preferred_username.eq::>(None), + display_name.eq::>(None), bio.eq::>(None), matrix_user_id.eq::>(None), deleted.eq(true), @@ -264,7 +264,7 @@ mod tests { let expected_person = Person { id: inserted_person.id, name: "holly".into(), - preferred_username: None, + display_name: None, avatar: None, banner: None, banned: false, diff --git a/crates/db_queries/src/source/person_mention.rs b/crates/db_queries/src/source/person_mention.rs index 5a3a7ea61..456894200 100644 --- a/crates/db_queries/src/source/person_mention.rs +++ b/crates/db_queries/src/source/person_mention.rs @@ -105,7 +105,6 @@ mod tests { let new_community = CommunityForm { name: "test community lake".to_string(), title: "nada".to_owned(), - creator_id: inserted_person.id, ..CommunityForm::default() }; diff --git a/crates/db_queries/src/source/post.rs b/crates/db_queries/src/source/post.rs index 169ca18ef..0205dc954 100644 --- a/crates/db_queries/src/source/post.rs +++ b/crates/db_queries/src/source/post.rs @@ -281,7 +281,6 @@ mod tests { let new_community = CommunityForm { name: "test community_3".to_string(), title: "nada".to_owned(), - creator_id: inserted_person.id, ..CommunityForm::default() }; diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 5bc55f529..9b05d29ab 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -78,7 +78,6 @@ table! { name -> Varchar, title -> Varchar, description -> Nullable, - creator_id -> Int4, removed -> Bool, published -> Timestamp, updated -> Nullable, @@ -154,6 +153,7 @@ table! { show_avatars -> Bool, send_notifications_to_email -> Bool, validator_time -> Timestamp, + show_scores -> Bool, } } @@ -270,7 +270,7 @@ table! { person (id) { id -> Int4, name -> Varchar, - preferred_username -> Nullable, + display_name -> Nullable, avatar -> Nullable, banned -> Bool, published -> Timestamp, @@ -421,7 +421,7 @@ table! { site (id) { id -> Int4, name -> Varchar, - description -> Nullable, + sidebar -> Nullable, creator_id -> Int4, published -> Timestamp, updated -> Nullable, @@ -430,6 +430,7 @@ table! { enable_nsfw -> Bool, icon -> Nullable, banner -> Nullable, + description -> Nullable, } } @@ -470,7 +471,7 @@ table! { person_alias_1 (id) { id -> Int4, name -> Varchar, - preferred_username -> Nullable, + display_name -> Nullable, avatar -> Nullable, banned -> Bool, published -> Timestamp, @@ -494,7 +495,7 @@ table! { person_alias_2 (id) { id -> Int4, name -> Varchar, - preferred_username -> Nullable, + display_name -> Nullable, avatar -> Nullable, banned -> Bool, published -> Timestamp, @@ -532,7 +533,6 @@ joinable!(comment_like -> post (post_id)); joinable!(comment_report -> comment (comment_id)); joinable!(comment_saved -> comment (comment_id)); joinable!(comment_saved -> person (person_id)); -joinable!(community -> person (creator_id)); joinable!(community_aggregates -> community (community_id)); joinable!(community_follower -> community (community_id)); joinable!(community_follower -> person (person_id)); diff --git a/crates/db_schema/src/source/comment.rs b/crates/db_schema/src/source/comment.rs index fba61f463..bd36a48e8 100644 --- a/crates/db_schema/src/source/comment.rs +++ b/crates/db_schema/src/source/comment.rs @@ -56,8 +56,8 @@ pub struct CommentAlias1 { pub struct CommentForm { pub creator_id: PersonId, pub post_id: PostId, - pub parent_id: Option, pub content: String, + pub parent_id: Option, pub removed: Option, pub read: Option, pub published: Option, diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs index 427510270..1581933f0 100644 --- a/crates/db_schema/src/source/community.rs +++ b/crates/db_schema/src/source/community.rs @@ -13,7 +13,6 @@ pub struct Community { pub name: String, pub title: String, pub description: Option, - pub creator_id: PersonId, pub removed: bool, pub published: chrono::NaiveDateTime, pub updated: Option, @@ -39,7 +38,6 @@ pub struct CommunitySafe { pub name: String, pub title: String, pub description: Option, - pub creator_id: PersonId, pub removed: bool, pub published: chrono::NaiveDateTime, pub updated: Option, @@ -57,7 +55,6 @@ pub struct CommunityForm { pub name: String, pub title: String, pub description: Option, - pub creator_id: PersonId, pub removed: Option, pub published: Option, pub updated: Option, diff --git a/crates/db_schema/src/source/local_user.rs b/crates/db_schema/src/source/local_user.rs index 6f28a8fbc..0a7181fdb 100644 --- a/crates/db_schema/src/source/local_user.rs +++ b/crates/db_schema/src/source/local_user.rs @@ -16,6 +16,7 @@ pub struct LocalUser { pub show_avatars: bool, pub send_notifications_to_email: bool, pub validator_time: chrono::NaiveDateTime, + pub show_scores: bool, } // TODO redo these, check table defaults @@ -32,6 +33,7 @@ pub struct LocalUserForm { pub lang: Option, pub show_avatars: Option, pub send_notifications_to_email: Option, + pub show_scores: Option, } /// A local user view that removes password encrypted @@ -49,4 +51,5 @@ pub struct LocalUserSettings { pub show_avatars: bool, pub send_notifications_to_email: bool, pub validator_time: chrono::NaiveDateTime, + pub show_scores: bool, } diff --git a/crates/db_schema/src/source/person.rs b/crates/db_schema/src/source/person.rs index 2c0e7e8b7..be1ce268f 100644 --- a/crates/db_schema/src/source/person.rs +++ b/crates/db_schema/src/source/person.rs @@ -10,7 +10,7 @@ use serde::Serialize; pub struct Person { pub id: PersonId, pub name: String, - pub preferred_username: Option, + pub display_name: Option, pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, @@ -35,7 +35,7 @@ pub struct Person { pub struct PersonSafe { pub id: PersonId, pub name: String, - pub preferred_username: Option, + pub display_name: Option, pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, @@ -56,7 +56,7 @@ pub struct PersonSafe { pub struct PersonAlias1 { pub id: PersonId, pub name: String, - pub preferred_username: Option, + pub display_name: Option, pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, @@ -80,7 +80,7 @@ pub struct PersonAlias1 { pub struct PersonSafeAlias1 { pub id: PersonId, pub name: String, - pub preferred_username: Option, + pub display_name: Option, pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, @@ -101,7 +101,7 @@ pub struct PersonSafeAlias1 { pub struct PersonAlias2 { pub id: PersonId, pub name: String, - pub preferred_username: Option, + pub display_name: Option, pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, @@ -125,7 +125,7 @@ pub struct PersonAlias2 { pub struct PersonSafeAlias2 { pub id: PersonId, pub name: String, - pub preferred_username: Option, + pub display_name: Option, pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, @@ -145,7 +145,7 @@ pub struct PersonSafeAlias2 { #[table_name = "person"] pub struct PersonForm { pub name: String, - pub preferred_username: Option>, + pub display_name: Option>, pub avatar: Option>, pub banned: Option, pub published: Option, diff --git a/crates/db_schema/src/source/post.rs b/crates/db_schema/src/source/post.rs index 87681e010..2581db95c 100644 --- a/crates/db_schema/src/source/post.rs +++ b/crates/db_schema/src/source/post.rs @@ -35,16 +35,16 @@ pub struct Post { #[table_name = "post"] pub struct PostForm { pub name: String, - pub url: Option, - pub body: Option, pub creator_id: PersonId, pub community_id: CommunityId, + pub nsfw: bool, + pub url: Option, + pub body: Option, pub removed: Option, pub locked: Option, pub published: Option, pub updated: Option, pub deleted: Option, - pub nsfw: bool, pub stickied: Option, pub embed_title: Option, pub embed_description: Option, diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs index 0723772eb..41042bc5c 100644 --- a/crates/db_schema/src/source/site.rs +++ b/crates/db_schema/src/source/site.rs @@ -6,7 +6,7 @@ use serde::Serialize; pub struct Site { pub id: i32, pub name: String, - pub description: Option, + pub sidebar: Option, pub creator_id: PersonId, pub published: chrono::NaiveDateTime, pub updated: Option, @@ -15,13 +15,14 @@ pub struct Site { pub enable_nsfw: bool, pub icon: Option, pub banner: Option, + pub description: Option, } #[derive(Insertable, AsChangeset)] #[table_name = "site"] pub struct SiteForm { pub name: String, - pub description: Option, + pub sidebar: Option>, pub creator_id: PersonId, pub updated: Option, pub enable_downvotes: bool, @@ -30,4 +31,5 @@ pub struct SiteForm { // when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column. pub icon: Option>, pub banner: Option>, + pub description: Option>, } diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index 6b13103c0..fd2debf2c 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -462,7 +462,6 @@ mod tests { let new_community = CommunityForm { name: "test community 5".to_string(), title: "nada".to_owned(), - creator_id: inserted_person.id, ..CommunityForm::default() }; @@ -519,7 +518,7 @@ mod tests { creator: PersonSafe { id: inserted_person.id, name: "timmy".into(), - preferred_username: None, + display_name: None, published: inserted_person.published, avatar: None, actor_id: inserted_person.actor_id.to_owned(), @@ -567,7 +566,6 @@ mod tests { local: true, title: "nada".to_owned(), description: None, - creator_id: inserted_person.id, updated: None, banner: None, published: inserted_community.published, diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index df67d3693..a6843416e 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -263,7 +263,7 @@ impl<'a> PostQueryBuilder<'a> { community_person_ban::table.on( post::community_id .eq(community_person_ban::community_id) - .and(community_person_ban::person_id.eq(community::creator_id)), + .and(community_person_ban::person_id.eq(post::creator_id)), ), ) .inner_join(post_aggregates::table) @@ -462,7 +462,6 @@ mod tests { let new_community = CommunityForm { name: community_name.to_owned(), title: "nada".to_owned(), - creator_id: inserted_person.id, ..CommunityForm::default() }; @@ -541,7 +540,7 @@ mod tests { creator: PersonSafe { id: inserted_person.id, name: person_name, - preferred_username: None, + display_name: None, published: inserted_person.published, avatar: None, actor_id: inserted_person.actor_id.to_owned(), @@ -568,7 +567,6 @@ mod tests { local: true, title: "nada".to_owned(), description: None, - creator_id: inserted_person.id, updated: None, banner: None, published: inserted_community.published, diff --git a/crates/db_views_actor/src/community_view.rs b/crates/db_views_actor/src/community_view.rs index fe3a80bb7..0ee503a71 100644 --- a/crates/db_views_actor/src/community_view.rs +++ b/crates/db_views_actor/src/community_view.rs @@ -12,11 +12,8 @@ use lemmy_db_queries::{ ViewToVec, }; use lemmy_db_schema::{ - schema::{community, community_aggregates, community_follower, person}, - source::{ - community::{Community, CommunityFollower, CommunitySafe}, - person::{Person, PersonSafe}, - }, + schema::{community, community_aggregates, community_follower}, + source::community::{Community, CommunityFollower, CommunitySafe}, CommunityId, PersonId, }; @@ -25,14 +22,12 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct CommunityView { pub community: CommunitySafe, - pub creator: PersonSafe, pub subscribed: bool, pub counts: CommunityAggregates, } type CommunityViewTuple = ( CommunitySafe, - PersonSafe, CommunityAggregates, Option, ); @@ -46,9 +41,8 @@ impl CommunityView { // The left join below will return None in this case let person_id_join = my_person_id.unwrap_or(PersonId(-1)); - let (community, creator, counts, follower) = community::table + let (community, counts, follower) = community::table .find(community_id) - .inner_join(person::table) .inner_join(community_aggregates::table) .left_join( community_follower::table.on( @@ -59,7 +53,6 @@ impl CommunityView { ) .select(( Community::safe_columns_tuple(), - Person::safe_columns_tuple(), community_aggregates::all_columns, community_follower::all_columns.nullable(), )) @@ -67,7 +60,6 @@ impl CommunityView { Ok(CommunityView { community, - creator, subscribed: follower.is_some(), counts, }) @@ -165,7 +157,6 @@ impl<'a> CommunityQueryBuilder<'a> { let person_id_join = self.my_person_id.unwrap_or(PersonId(-1)); let mut query = community::table - .inner_join(person::table) .inner_join(community_aggregates::table) .left_join( community_follower::table.on( @@ -176,7 +167,6 @@ impl<'a> CommunityQueryBuilder<'a> { ) .select(( Community::safe_columns_tuple(), - Person::safe_columns_tuple(), community_aggregates::all_columns, community_follower::all_columns.nullable(), )) @@ -193,6 +183,7 @@ impl<'a> CommunityQueryBuilder<'a> { match self.sort { SortType::New => query = query.order_by(community::published.desc()), SortType::TopAll => query = query.order_by(community_aggregates::subscribers.desc()), + SortType::TopMonth => query = query.order_by(community_aggregates::users_active_month.desc()), // Covers all other sorts, including hot _ => { query = query @@ -236,9 +227,8 @@ impl ViewToVec for CommunityView { .iter() .map(|a| Self { community: a.0.to_owned(), - creator: a.1.to_owned(), - counts: a.2.to_owned(), - subscribed: a.3.is_some(), + counts: a.1.to_owned(), + subscribed: a.2.is_some(), }) .collect::>() } diff --git a/crates/utils/src/settings/defaults.rs b/crates/utils/src/settings/defaults.rs index 56d24c7fb..3e7b344f2 100644 --- a/crates/utils/src/settings/defaults.rs +++ b/crates/utils/src/settings/defaults.rs @@ -24,12 +24,12 @@ impl Default for Settings { impl Default for DatabaseConfig { fn default() -> Self { Self { - user: "lemmy".into(), + user: Some("lemmy".to_string()), password: "password".into(), host: "localhost".into(), - port: 5432, - database: "lemmy".into(), - pool_size: 5, + port: Some(5432), + database: Some("lemmy".to_string()), + pool_size: Some(5), } } } diff --git a/crates/utils/src/settings/mod.rs b/crates/utils/src/settings/mod.rs index d052fec6c..406bf7de0 100644 --- a/crates/utils/src/settings/mod.rs +++ b/crates/utils/src/settings/mod.rs @@ -16,7 +16,7 @@ use deser_hjson::from_str; use merge::Merge; use std::{env, fs, io::Error, net::IpAddr, sync::RwLock}; -pub(crate) mod defaults; +pub mod defaults; pub mod structs; static CONFIG_FILE: &str = "config/config.hjson"; @@ -60,7 +60,11 @@ impl Settings { let conf = self.database(); format!( "postgres://{}:{}@{}:{}/{}", - conf.user, conf.password, conf.host, conf.port, conf.database, + conf.user(), + conf.password, + conf.host, + conf.port(), + conf.database(), ) } diff --git a/crates/utils/src/settings/structs.rs b/crates/utils/src/settings/structs.rs index 21d89b98a..3863f6e3c 100644 --- a/crates/utils/src/settings/structs.rs +++ b/crates/utils/src/settings/structs.rs @@ -27,12 +27,40 @@ pub struct CaptchaConfig { #[derive(Debug, Deserialize, Clone)] pub struct DatabaseConfig { - pub user: String, + pub(super) user: Option, pub password: String, pub host: String, - pub port: i32, - pub database: String, - pub pool_size: u32, + pub(super) port: Option, + pub(super) database: Option, + pub(super) pool_size: Option, +} + +impl DatabaseConfig { + pub fn user(&self) -> String { + self + .user + .to_owned() + .unwrap_or_else(|| DatabaseConfig::default().user.expect("missing user")) + } + pub fn port(&self) -> i32 { + self + .port + .unwrap_or_else(|| DatabaseConfig::default().port.expect("missing port")) + } + pub fn database(&self) -> String { + self.database.to_owned().unwrap_or_else(|| { + DatabaseConfig::default() + .database + .expect("missing database") + }) + } + pub fn pool_size(&self) -> u32 { + self.pool_size.unwrap_or_else(|| { + DatabaseConfig::default() + .pool_size + .expect("missing pool_size") + }) + } } #[derive(Debug, Deserialize, Clone)] diff --git a/crates/utils/src/test.rs b/crates/utils/src/test.rs index aaa59bfa7..da38299a8 100644 --- a/crates/utils/src/test.rs +++ b/crates/utils/src/test.rs @@ -1,7 +1,8 @@ use crate::utils::{ is_valid_community_name, + is_valid_display_name, + is_valid_matrix_id, is_valid_post_title, - is_valid_preferred_username, is_valid_username, remove_slurs, scrape_text_for_mentions, @@ -29,9 +30,15 @@ fn test_valid_register_username() { } #[test] -fn test_valid_preferred_username() { - assert!(is_valid_preferred_username("hello @there")); - assert!(!is_valid_preferred_username("@hello there")); +fn test_valid_display_name() { + assert!(is_valid_display_name("hello @there")); + assert!(!is_valid_display_name("@hello there")); + + // Make sure zero-space with an @ doesn't work + assert!(!is_valid_display_name(&format!( + "{}@my name is", + '\u{200b}' + ))); } #[test] @@ -50,6 +57,14 @@ fn test_valid_post_title() { assert!(!is_valid_post_title("\n \n \n \n ")); // tabs/spaces/newlines } +#[test] +fn test_valid_matrix_id() { + assert!(is_valid_matrix_id("@dess:matrix.org")); + assert!(!is_valid_matrix_id("dess:matrix.org")); + assert!(!is_valid_matrix_id(" @dess:matrix.org")); + assert!(!is_valid_matrix_id("@dess:matrix.org t")); +} + #[test] fn test_slur_filter() { let test = diff --git a/crates/utils/src/utils.rs b/crates/utils/src/utils.rs index c53d6c7c2..a34d9e303 100644 --- a/crates/utils/src/utils.rs +++ b/crates/utils/src/utils.rs @@ -15,6 +15,7 @@ lazy_static! { static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").expect("compile regex"); static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").expect("compile regex"); static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").expect("compile regex"); + static ref VALID_MATRIX_ID_REGEX: Regex = Regex::new(r"^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$").expect("compile regex"); } pub fn naive_from_unix(time: i64) -> NaiveDateTime { @@ -108,10 +109,15 @@ pub fn is_valid_username(name: &str) -> bool { } // Can't do a regex here, reverse lookarounds not supported -pub fn is_valid_preferred_username(preferred_username: &str) -> bool { - !preferred_username.starts_with('@') - && preferred_username.chars().count() >= 3 - && preferred_username.chars().count() <= 20 +pub fn is_valid_display_name(name: &str) -> bool { + !name.starts_with('@') + && !name.starts_with('\u{200b}') + && name.chars().count() >= 3 + && name.chars().count() <= 20 +} + +pub fn is_valid_matrix_id(matrix_id: &str) -> bool { + VALID_MATRIX_ID_REGEX.is_match(matrix_id) } pub fn is_valid_community_name(name: &str) -> bool { diff --git a/crates/utils/src/version.rs b/crates/utils/src/version.rs index 476a14bd4..397d2a429 100644 --- a/crates/utils/src/version.rs +++ b/crates/utils/src/version.rs @@ -1 +1 @@ -pub const VERSION: &str = "0.10.2"; +pub const VERSION: &str = "0.10.3"; diff --git a/crates/websocket/src/lib.rs b/crates/websocket/src/lib.rs index 0b2a9fb4f..f5f5f0804 100644 --- a/crates/websocket/src/lib.rs +++ b/crates/websocket/src/lib.rs @@ -123,6 +123,7 @@ pub enum UserOperation { PostJoin, CommunityJoin, ModJoin, + ChangePassword, } #[derive(EnumString, ToString, Debug, Clone)] diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 954c85c84..5d2acec7f 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -49,9 +49,6 @@ FROM alpine:3.12 as lemmy # Install libpq for postgres RUN apk add libpq -# Install Espeak for captchas -RUN apk add espeak - RUN addgroup -g 1000 lemmy RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy diff --git a/docker/dev/docker_update_volume_mount.sh b/docker/dev/docker_update_volume_mount.sh index e99ac31a8..7fbd212a5 100755 --- a/docker/dev/docker_update_volume_mount.sh +++ b/docker/dev/docker_update_volume_mount.sh @@ -9,4 +9,4 @@ mkdir -p volumes/pictrs sudo chown -R 991:991 volumes/pictrs sudo docker build ../../ --file ../dev/volume_mount.dockerfile -t lemmy-dev:latest sudo docker-compose pull --ignore-pull-failures || true -sudo docker-compose up -d +sudo docker-compose up diff --git a/docker/dev/volume_mount.dockerfile b/docker/dev/volume_mount.dockerfile index 38e019f7f..00d9c4735 100644 --- a/docker/dev/volume_mount.dockerfile +++ b/docker/dev/volume_mount.dockerfile @@ -19,9 +19,9 @@ RUN --mount=type=cache,target=/app/target \ FROM ubuntu:20.10 -# Install libpq for postgres and espeak +# Install libpq for postgres RUN apt-get update -y -RUN apt-get install -y libpq-dev espeak +RUN apt-get install -y libpq-dev # Copy resources COPY --from=rust /app/lemmy_server /app/lemmy diff --git a/docker/prod/Dockerfile.arm b/docker/prod/Dockerfile.arm index 61d1f86c9..b3eacb4f9 100644 --- a/docker/prod/Dockerfile.arm +++ b/docker/prod/Dockerfile.arm @@ -22,9 +22,9 @@ RUN cp ./target/release/lemmy_server /app/lemmy_server # The Debian runner FROM debian:buster-slim as lemmy -# Install libpq for postgres and espeak for captchas +# Install libpq for postgres RUN apt-get update \ - && apt-get -y install --no-install-recommends espeak postgresql-client libc6 libssl1.1 \ + && apt-get -y install --no-install-recommends postgresql-client libc6 libssl1.1 \ && rm -rf /var/lib/apt/lists/* RUN addgroup --gid 1000 lemmy diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index 5e617c6cc..1024ecbc9 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -12,7 +12,7 @@ services: restart: always lemmy: - image: dessalines/lemmy:0.10.2 + image: dessalines/lemmy:0.10.3 ports: - "127.0.0.1:8536:8536" restart: always @@ -26,7 +26,7 @@ services: - iframely lemmy-ui: - image: dessalines/lemmy-ui:0.10.2 + image: dessalines/lemmy-ui:0.10.3 ports: - "127.0.0.1:1235:1234" restart: always diff --git a/migrations/2021-03-31-103917_add_show_score_setting/down.sql b/migrations/2021-03-31-103917_add_show_score_setting/down.sql new file mode 100644 index 000000000..9d35b5638 --- /dev/null +++ b/migrations/2021-03-31-103917_add_show_score_setting/down.sql @@ -0,0 +1 @@ +alter table local_user drop column show_scores; diff --git a/migrations/2021-03-31-103917_add_show_score_setting/up.sql b/migrations/2021-03-31-103917_add_show_score_setting/up.sql new file mode 100644 index 000000000..7960886a3 --- /dev/null +++ b/migrations/2021-03-31-103917_add_show_score_setting/up.sql @@ -0,0 +1 @@ +alter table local_user add column show_scores boolean default true not null; diff --git a/migrations/2021-03-31-144349_add_site_short_description/down.sql b/migrations/2021-03-31-144349_add_site_short_description/down.sql new file mode 100644 index 000000000..0035ee770 --- /dev/null +++ b/migrations/2021-03-31-144349_add_site_short_description/down.sql @@ -0,0 +1,2 @@ +alter table site drop column description; +alter table site rename column sidebar to description; diff --git a/migrations/2021-03-31-144349_add_site_short_description/up.sql b/migrations/2021-03-31-144349_add_site_short_description/up.sql new file mode 100644 index 000000000..09dc36a7d --- /dev/null +++ b/migrations/2021-03-31-144349_add_site_short_description/up.sql @@ -0,0 +1,5 @@ +-- Renaming description to sidebar +alter table site rename column description to sidebar; + +-- Adding a short description column +alter table site add column description varchar(150); diff --git a/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql new file mode 100644 index 000000000..844c02d38 --- /dev/null +++ b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql @@ -0,0 +1,6 @@ +alter table person rename display_name to preferred_username; + +-- Regenerate the person_alias views +drop view person_alias_1, person_alias_2; +create view person_alias_1 as select * from person; +create view person_alias_2 as select * from person; diff --git a/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql new file mode 100644 index 000000000..f4b9729c1 --- /dev/null +++ b/migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql @@ -0,0 +1,6 @@ +alter table person rename preferred_username to display_name; + +-- Regenerate the person_alias views +drop view person_alias_1, person_alias_2; +create view person_alias_1 as select * from person; +create view person_alias_2 as select * from person; diff --git a/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql new file mode 100644 index 000000000..9748bc17f --- /dev/null +++ b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/down.sql @@ -0,0 +1 @@ +drop index idx_community_aggregates_users_active_month; diff --git a/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql new file mode 100644 index 000000000..4ae90e0ab --- /dev/null +++ b/migrations/2021-04-01-181826_add_community_agg_active_monthly_index/up.sql @@ -0,0 +1,2 @@ +create index idx_community_aggregates_users_active_month on community_aggregates (users_active_month desc); + diff --git a/migrations/2021-04-02-021422_remove_community_creator/down.sql b/migrations/2021-04-02-021422_remove_community_creator/down.sql new file mode 100644 index 000000000..d015f252b --- /dev/null +++ b/migrations/2021-04-02-021422_remove_community_creator/down.sql @@ -0,0 +1,24 @@ + +-- Add the column back +alter table community add column creator_id int references person on update cascade on delete cascade; + +-- Recreate the index +create index idx_community_creator on community (creator_id); + +-- Add the data, selecting the highest mod +update community +set creator_id = sub.person_id +from ( + select + cm.community_id, + cm.person_id + from + community_moderator cm + limit 1 +) as sub +where id = sub.community_id; + +-- Set to not null +alter table community alter column creator_id set not null; + + diff --git a/migrations/2021-04-02-021422_remove_community_creator/up.sql b/migrations/2021-04-02-021422_remove_community_creator/up.sql new file mode 100644 index 000000000..c3415c6ab --- /dev/null +++ b/migrations/2021-04-02-021422_remove_community_creator/up.sql @@ -0,0 +1,2 @@ +-- Drop the column +alter table community drop column creator_id; diff --git a/src/api_routes.rs b/src/api_routes.rs index e0158c338..f8e8f7e18 100644 --- a/src/api_routes.rs +++ b/src/api_routes.rs @@ -182,6 +182,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { "/save_user_settings", web::put().to(route_post::), ) + .route( + "/change_password", + web::put().to(route_post::), + ) .route("/report_count", web::get().to(route_get::)), ) // Admin Actions diff --git a/src/code_migrations.rs b/src/code_migrations.rs index 144c39f87..d8563b51b 100644 --- a/src/code_migrations.rs +++ b/src/code_migrations.rs @@ -89,7 +89,6 @@ fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> { name: ccommunity.name.to_owned(), title: ccommunity.title.to_owned(), description: ccommunity.description.to_owned(), - creator_id: ccommunity.creator_id, removed: None, deleted: None, nsfw: None, diff --git a/src/main.rs b/src/main.rs index 5b8a7ec1d..8cda9ff4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,7 +38,7 @@ async fn main() -> Result<(), LemmyError> { }; let manager = ConnectionManager::::new(&db_url); let pool = Pool::builder() - .max_size(settings.database().pool_size) + .max_size(settings.database().pool_size()) .build(manager) .unwrap_or_else(|_| panic!("Error connecting to {}", db_url));