mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-22 20:31:19 +00:00
Merge branch 'main' into drone-release-main
This commit is contained in:
commit
3a6e0d9393
68 changed files with 395 additions and 315 deletions
|
@ -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)
|
# Lemmy v0.10.2 Release (2021-04-05)
|
||||||
|
|
||||||
- Forcing a crash if config.hjson fails to load. Should show errors easier.
|
- Forcing a crash if config.hjson fails to load. Should show errors easier.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.10.2
|
0.10.3
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"eslint": "^7.18.0",
|
"eslint": "^7.18.0",
|
||||||
"eslint-plugin-jane": "^9.0.3",
|
"eslint-plugin-jane": "^9.0.3",
|
||||||
"jest": "^26.6.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",
|
"node-fetch": "^2.6.1",
|
||||||
"prettier": "^2.1.2",
|
"prettier": "^2.1.2",
|
||||||
"ts-jest": "^26.4.4",
|
"ts-jest": "^26.4.4",
|
||||||
|
|
|
@ -31,7 +31,6 @@ function assertCommunityFederation(
|
||||||
expect(communityOne.community.published).toBe(
|
expect(communityOne.community.published).toBe(
|
||||||
communityTwo.community.published
|
communityTwo.community.published
|
||||||
);
|
);
|
||||||
expect(communityOne.creator.actor_id).toBe(communityTwo.creator.actor_id);
|
|
||||||
expect(communityOne.community.nsfw).toBe(communityTwo.community.nsfw);
|
expect(communityOne.community.nsfw).toBe(communityTwo.community.nsfw);
|
||||||
expect(communityOne.community.removed).toBe(communityTwo.community.removed);
|
expect(communityOne.community.removed).toBe(communityTwo.community.removed);
|
||||||
expect(communityOne.community.deleted).toBe(communityTwo.community.deleted);
|
expect(communityOne.community.deleted).toBe(communityTwo.community.deleted);
|
||||||
|
|
|
@ -15,8 +15,8 @@ let recipient_id: number;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await setupLogins();
|
await setupLogins();
|
||||||
let follow = await followBeta(alpha);
|
await followBeta(alpha);
|
||||||
recipient_id = follow.community_view.creator.id;
|
recipient_id = 3;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
|
|
@ -3233,10 +3233,10 @@ language-tags@^1.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
language-subtag-registry "~0.3.2"
|
language-subtag-registry "~0.3.2"
|
||||||
|
|
||||||
lemmy-js-client@0.10.0-rc.13:
|
lemmy-js-client@0.11.0-rc.3:
|
||||||
version "0.10.0-rc.13"
|
version "0.11.0-rc.3"
|
||||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.10.0-rc.13.tgz#ea2e88857243374d7fbd49ee6b4bb94c34359d85"
|
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.11.0-rc.3.tgz#dd4727ca4d16fe9593368725aacfd9e7a8d52548"
|
||||||
integrity sha512-zodvYkwBYR7iP27ah6L/QPUphUUdq38kCH7QF2CUYBrsSAEkGmq2kdz+iusnQ1Ht7Ad80GtYycFprsZBveV5eQ==
|
integrity sha512-16mgl+TS1+0UHiY+ZKPuqHfbrn93h8K8tJ+kKJ1pjT2WhG23o0B8dLahG1jDQPG+dkXpR6PZxYudMYjuO8WvjQ==
|
||||||
|
|
||||||
leven@^3.1.0:
|
leven@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
|
|
|
@ -10,11 +10,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_apub::{ActorType, CommunityType, UserType};
|
use lemmy_apub::{ActorType, CommunityType, UserType};
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
source::{
|
source::{comment::Comment_, community::CommunityModerator_, post::Post_},
|
||||||
comment::Comment_,
|
|
||||||
community::{CommunityModerator_, Community_},
|
|
||||||
post::Post_,
|
|
||||||
},
|
|
||||||
Bannable,
|
Bannable,
|
||||||
Crud,
|
Crud,
|
||||||
Followable,
|
Followable,
|
||||||
|
@ -324,12 +320,6 @@ impl Perform for TransferCommunity {
|
||||||
let data: &TransferCommunity = &self;
|
let data: &TransferCommunity = &self;
|
||||||
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
|
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| {
|
let site_creator_id = blocking(context.pool(), move |conn| {
|
||||||
Site::read(conn, 1).map(|s| s.creator_id)
|
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??;
|
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
|
let creator_index = admins
|
||||||
.iter()
|
.iter()
|
||||||
.position(|r| r.person.id == site_creator_id)
|
.position(|r| r.person.id == site_creator_id)
|
||||||
|
@ -345,8 +335,15 @@ impl Perform for TransferCommunity {
|
||||||
let creator_person = admins.remove(creator_index);
|
let creator_person = admins.remove(creator_index);
|
||||||
admins.insert(0, creator_person);
|
admins.insert(0, creator_person);
|
||||||
|
|
||||||
// Make sure user is the creator, or an admin
|
// Fetch the community mods
|
||||||
if local_user_view.person.id != read_community.creator_id
|
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
|
&& !admins
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| a.person.id)
|
.map(|a| a.person.id)
|
||||||
|
@ -355,19 +352,8 @@ impl Perform for TransferCommunity {
|
||||||
return Err(ApiError::err("not_an_admin").into());
|
return Err(ApiError::err("not_an_admin").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let community_id = data.community_id;
|
// You have to re-do the community_moderator table, reordering it.
|
||||||
let new_creator = data.person_id;
|
// Add the transferee to the top
|
||||||
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??;
|
|
||||||
let creator_index = community_mods
|
let creator_index = community_mods
|
||||||
.iter()
|
.iter()
|
||||||
.position(|r| r.moderator.id == data.person_id)
|
.position(|r| r.moderator.id == data.person_id)
|
||||||
|
@ -375,6 +361,7 @@ impl Perform for TransferCommunity {
|
||||||
let creator_person = community_mods.remove(creator_index);
|
let creator_person = community_mods.remove(creator_index);
|
||||||
community_mods.insert(0, creator_person);
|
community_mods.insert(0, creator_person);
|
||||||
|
|
||||||
|
// Delete all the mods
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
blocking(context.pool(), move |conn| {
|
blocking(context.pool(), move |conn| {
|
||||||
CommunityModerator::delete_for_community(conn, community_id)
|
CommunityModerator::delete_for_community(conn, community_id)
|
||||||
|
@ -382,6 +369,7 @@ impl Perform for TransferCommunity {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// TODO: this should probably be a bulk operation
|
// TODO: this should probably be a bulk operation
|
||||||
|
// Re-add the mods, in the new order
|
||||||
for cmod in &community_mods {
|
for cmod in &community_mods {
|
||||||
let community_moderator_form = CommunityModeratorForm {
|
let community_moderator_form = CommunityModeratorForm {
|
||||||
community_id: cmod.community.id,
|
community_id: cmod.community.id,
|
||||||
|
@ -395,6 +383,8 @@ impl Perform for TransferCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod tables
|
// 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 {
|
let form = ModAddCommunityForm {
|
||||||
mod_person_id: local_user_view.person.id,
|
mod_person_id: local_user_view.person.id,
|
||||||
other_person_id: data.person_id,
|
other_person_id: data.person_id,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use actix_web::{web, web::Data};
|
use actix_web::{web, web::Data};
|
||||||
|
use captcha::Captcha;
|
||||||
use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*};
|
use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*};
|
||||||
use lemmy_utils::{ConnectionId, LemmyError};
|
use lemmy_utils::{ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{env, process::Command};
|
|
||||||
|
|
||||||
mod comment;
|
mod comment;
|
||||||
mod comment_report;
|
mod comment_report;
|
||||||
|
@ -63,6 +63,9 @@ pub async fn match_websocket_operation(
|
||||||
UserOperation::SaveUserSettings => {
|
UserOperation::SaveUserSettings => {
|
||||||
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
|
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
|
||||||
}
|
}
|
||||||
|
UserOperation::ChangePassword => {
|
||||||
|
do_websocket_operation::<ChangePassword>(context, id, op, data).await
|
||||||
|
}
|
||||||
UserOperation::GetReportCount => {
|
UserOperation::GetReportCount => {
|
||||||
do_websocket_operation::<GetReportCount>(context, id, op, data).await
|
do_websocket_operation::<GetReportCount>(context, id, op, data).await
|
||||||
}
|
}
|
||||||
|
@ -158,60 +161,23 @@ where
|
||||||
serialize_websocket_message(&op, &res)
|
serialize_websocket_message(&op, &res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn captcha_espeak_wav_base64(captcha: &str) -> Result<String, LemmyError> {
|
/// Converts the captcha to a base64 encoded wav audio file
|
||||||
let mut built_text = String::new();
|
pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
|
||||||
|
let letters = captcha.as_wav();
|
||||||
|
|
||||||
// Building proper speech text for espeak
|
let mut concat_letters: Vec<u8> = Vec::new();
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
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<String, LemmyError> {
|
|
||||||
// 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
|
// Convert to base64
|
||||||
let base64 = base64::encode(bytes);
|
base64::encode(concat_letters)
|
||||||
|
|
||||||
Ok(base64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::captcha_espeak_wav_base64;
|
|
||||||
use lemmy_api_common::check_validator_time;
|
use lemmy_api_common::check_validator_time;
|
||||||
use lemmy_db_queries::{establish_unpooled_connection, source::local_user::LocalUser_, Crud};
|
use lemmy_db_queries::{establish_unpooled_connection, source::local_user::LocalUser_, Crud};
|
||||||
use lemmy_db_schema::source::{
|
use lemmy_db_schema::source::{
|
||||||
|
@ -253,9 +219,4 @@ mod tests {
|
||||||
let num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
let num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
||||||
assert_eq!(1, num_deleted);
|
assert_eq!(1, num_deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_espeak() {
|
|
||||||
assert!(captcha_espeak_wav_base64("WxRt2l").is_ok())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{captcha_espeak_wav_base64, Perform};
|
use crate::{captcha_as_wav_base64, Perform};
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use bcrypt::verify;
|
use bcrypt::verify;
|
||||||
|
@ -18,7 +18,6 @@ use lemmy_db_queries::{
|
||||||
diesel_option_overwrite_to_url,
|
diesel_option_overwrite_to_url,
|
||||||
source::{
|
source::{
|
||||||
comment::Comment_,
|
comment::Comment_,
|
||||||
community::Community_,
|
|
||||||
local_user::LocalUser_,
|
local_user::LocalUser_,
|
||||||
password_reset_request::PasswordResetRequest_,
|
password_reset_request::PasswordResetRequest_,
|
||||||
person::Person_,
|
person::Person_,
|
||||||
|
@ -33,7 +32,6 @@ use lemmy_db_schema::{
|
||||||
naive_now,
|
naive_now,
|
||||||
source::{
|
source::{
|
||||||
comment::Comment,
|
comment::Comment,
|
||||||
community::*,
|
|
||||||
local_user::{LocalUser, LocalUserForm},
|
local_user::{LocalUser, LocalUserForm},
|
||||||
moderator::*,
|
moderator::*,
|
||||||
password_reset_request::*,
|
password_reset_request::*,
|
||||||
|
@ -60,7 +58,7 @@ use lemmy_utils::{
|
||||||
email::send_email,
|
email::send_email,
|
||||||
location_info,
|
location_info,
|
||||||
settings::structs::Settings,
|
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,
|
ApiError,
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
|
@ -135,13 +133,11 @@ impl Perform for GetCaptcha {
|
||||||
|
|
||||||
let answer = captcha.chars_as_string();
|
let answer = captcha.chars_as_string();
|
||||||
|
|
||||||
let png_byte_array = captcha.as_png().expect("failed to generate captcha");
|
let png = captcha.as_base64().expect("failed to generate captcha");
|
||||||
|
|
||||||
let png = base64::encode(png_byte_array);
|
|
||||||
|
|
||||||
let uuid = uuid::Uuid::new_v4().to_string();
|
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 {
|
let captcha_item = CaptchaItem {
|
||||||
answer,
|
answer,
|
||||||
|
@ -174,7 +170,7 @@ impl Perform for SaveUserSettings {
|
||||||
let banner = diesel_option_overwrite_to_url(&data.banner)?;
|
let banner = diesel_option_overwrite_to_url(&data.banner)?;
|
||||||
let email = diesel_option_overwrite(&data.email);
|
let email = diesel_option_overwrite(&data.email);
|
||||||
let bio = diesel_option_overwrite(&data.bio);
|
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);
|
let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id);
|
||||||
|
|
||||||
if let Some(Some(bio)) = &bio {
|
if let Some(Some(bio)) = &bio {
|
||||||
|
@ -183,59 +179,30 @@ impl Perform for SaveUserSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Some(preferred_username)) = &preferred_username {
|
if let Some(Some(display_name)) = &display_name {
|
||||||
if !is_valid_preferred_username(preferred_username.trim()) {
|
if !is_valid_display_name(display_name.trim()) {
|
||||||
return Err(ApiError::err("invalid_username").into());
|
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 local_user_id = local_user_view.local_user.id;
|
||||||
let person_id = local_user_view.person.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_listing_type = data.default_listing_type;
|
||||||
let default_sort_type = data.default_sort_type;
|
let default_sort_type = data.default_sort_type;
|
||||||
|
let password_encrypted = local_user_view.local_user.password_encrypted;
|
||||||
|
|
||||||
let person_form = PersonForm {
|
let person_form = PersonForm {
|
||||||
name: local_user_view.person.name,
|
name: local_user_view.person.name,
|
||||||
avatar,
|
avatar,
|
||||||
banner,
|
banner,
|
||||||
inbox_url: None,
|
inbox_url: None,
|
||||||
preferred_username,
|
display_name,
|
||||||
published: None,
|
published: None,
|
||||||
updated: Some(naive_now()),
|
updated: Some(naive_now()),
|
||||||
banned: None,
|
banned: None,
|
||||||
|
@ -267,6 +234,7 @@ impl Perform for SaveUserSettings {
|
||||||
email,
|
email,
|
||||||
password_encrypted,
|
password_encrypted,
|
||||||
show_nsfw: data.show_nsfw,
|
show_nsfw: data.show_nsfw,
|
||||||
|
show_scores: data.show_scores,
|
||||||
theme: data.theme.to_owned(),
|
theme: data.theme.to_owned(),
|
||||||
default_sort_type,
|
default_sort_type,
|
||||||
default_listing_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<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<LoginResponse, LemmyError> {
|
||||||
|
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)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for AddAdmin {
|
impl Perform for AddAdmin {
|
||||||
type Response = AddAdminResponse;
|
type Response = AddAdminResponse;
|
||||||
|
@ -394,10 +405,9 @@ impl Perform for BanPerson {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// Communities
|
// Communities
|
||||||
blocking(context.pool(), move |conn: &'_ _| {
|
// Remove all communities where they're the top mod
|
||||||
Community::update_removed_for_creator(conn, banned_person_id, true)
|
// TODO couldn't get group by's working in diesel,
|
||||||
})
|
// for now, remove the communities manually
|
||||||
.await??;
|
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
blocking(context.pool(), move |conn: &'_ _| {
|
blocking(context.pool(), move |conn: &'_ _| {
|
||||||
|
|
|
@ -418,3 +418,12 @@ pub fn password_length_check(pass: &str) -> Result<(), LemmyError> {
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,32 +39,41 @@ pub struct GetCaptchaResponse {
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct CaptchaResponse {
|
pub struct CaptchaResponse {
|
||||||
pub png: String, // A Base64 encoded png
|
pub png: String, // A Base64 encoded png
|
||||||
pub wav: Option<String>, // A Base64 encoded wav audio
|
pub wav: String, // A Base64 encoded wav audio
|
||||||
pub uuid: String,
|
pub uuid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct SaveUserSettings {
|
pub struct SaveUserSettings {
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
|
pub show_scores: Option<bool>,
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
pub default_sort_type: Option<i16>,
|
pub default_sort_type: Option<i16>,
|
||||||
pub default_listing_type: Option<i16>,
|
pub default_listing_type: Option<i16>,
|
||||||
pub lang: Option<String>,
|
pub lang: Option<String>,
|
||||||
pub avatar: Option<String>,
|
pub avatar: Option<String>,
|
||||||
pub banner: Option<String>,
|
pub banner: Option<String>,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
pub bio: Option<String>,
|
pub bio: Option<String>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
|
pub show_avatars: Option<bool>,
|
||||||
pub new_password: Option<String>,
|
pub new_password: Option<String>,
|
||||||
pub new_password_verify: Option<String>,
|
pub new_password_verify: Option<String>,
|
||||||
pub old_password: Option<String>,
|
pub old_password: Option<String>,
|
||||||
pub show_avatars: Option<bool>,
|
|
||||||
pub send_notifications_to_email: Option<bool>,
|
pub send_notifications_to_email: Option<bool>,
|
||||||
pub auth: String,
|
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)]
|
#[derive(Serialize)]
|
||||||
pub struct LoginResponse {
|
pub struct LoginResponse {
|
||||||
pub jwt: String,
|
pub jwt: String,
|
||||||
|
|
|
@ -18,7 +18,6 @@ use lemmy_db_views_moderator::{
|
||||||
mod_sticky_post_view::ModStickyPostView,
|
mod_sticky_post_view::ModStickyPostView,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Search {
|
pub struct Search {
|
||||||
|
@ -65,9 +64,10 @@ pub struct GetModlogResponse {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct CreateSite {
|
pub struct CreateSite {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub sidebar: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub icon: Option<Url>,
|
pub icon: Option<String>,
|
||||||
pub banner: Option<Url>,
|
pub banner: Option<String>,
|
||||||
pub enable_downvotes: bool,
|
pub enable_downvotes: bool,
|
||||||
pub open_registration: bool,
|
pub open_registration: bool,
|
||||||
pub enable_nsfw: bool,
|
pub enable_nsfw: bool,
|
||||||
|
@ -77,6 +77,7 @@ pub struct CreateSite {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EditSite {
|
pub struct EditSite {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub sidebar: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
pub banner: Option<String>,
|
pub banner: Option<String>,
|
||||||
|
|
|
@ -75,7 +75,6 @@ impl PerformCrud for CreateCommunity {
|
||||||
description: data.description.to_owned(),
|
description: data.description.to_owned(),
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
creator_id: local_user_view.person.id,
|
|
||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
actor_id: Some(community_actor_id.to_owned()),
|
actor_id: Some(community_actor_id.to_owned()),
|
||||||
private_key: Some(keypair.private_key),
|
private_key: Some(keypair.private_key),
|
||||||
|
|
|
@ -7,7 +7,10 @@ use lemmy_db_schema::source::{
|
||||||
community::*,
|
community::*,
|
||||||
moderator::{ModRemoveCommunity, ModRemoveCommunityForm},
|
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_utils::{utils::naive_from_unix, ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||||
|
|
||||||
|
@ -23,13 +26,15 @@ impl PerformCrud for DeleteCommunity {
|
||||||
let data: &DeleteCommunity = &self;
|
let data: &DeleteCommunity = &self;
|
||||||
let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
|
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 community_id = data.community_id;
|
||||||
let read_community = blocking(context.pool(), move |conn| {
|
let community_mods = blocking(context.pool(), move |conn| {
|
||||||
Community::read(conn, community_id)
|
CommunityModeratorView::for_community(conn, community_id)
|
||||||
})
|
})
|
||||||
.await??;
|
.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());
|
return Err(ApiError::err("no_community_edit_allowed").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ impl PerformCrud for EditCommunity {
|
||||||
let community_form = CommunityForm {
|
let community_form = CommunityForm {
|
||||||
name: read_community.name,
|
name: read_community.name,
|
||||||
title: data.title.to_owned(),
|
title: data.title.to_owned(),
|
||||||
creator_id: read_community.creator_id,
|
|
||||||
description: data.description.to_owned(),
|
description: data.description.to_owned(),
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
use crate::PerformCrud;
|
use crate::PerformCrud;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lemmy_api_common::{blocking, get_local_user_view_from_jwt, is_admin, site::*};
|
use lemmy_api_common::{
|
||||||
use lemmy_db_queries::{source::site::Site_, Crud};
|
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_schema::source::site::{Site, *};
|
||||||
use lemmy_db_views::site_view::SiteView;
|
use lemmy_db_views::site_view::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -36,11 +47,21 @@ impl PerformCrud for CreateSite {
|
||||||
// Make sure user is an admin
|
// Make sure user is an admin
|
||||||
is_admin(&local_user_view)?;
|
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 {
|
let site_form = SiteForm {
|
||||||
name: data.name.to_owned(),
|
name: data.name.to_owned(),
|
||||||
description: data.description.to_owned(),
|
sidebar,
|
||||||
icon: Some(data.icon.to_owned().map(|url| url.into())),
|
description,
|
||||||
banner: Some(data.banner.to_owned().map(|url| url.into())),
|
icon,
|
||||||
|
banner,
|
||||||
creator_id: local_user_view.person.id,
|
creator_id: local_user_view.person.id,
|
||||||
enable_downvotes: data.enable_downvotes,
|
enable_downvotes: data.enable_downvotes,
|
||||||
open_registration: data.open_registration,
|
open_registration: data.open_registration,
|
||||||
|
|
|
@ -43,6 +43,7 @@ impl PerformCrud for GetSite {
|
||||||
|
|
||||||
let create_site = CreateSite {
|
let create_site = CreateSite {
|
||||||
name: setup.site_name.to_owned(),
|
name: setup.site_name.to_owned(),
|
||||||
|
sidebar: None,
|
||||||
description: None,
|
description: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
|
|
|
@ -5,8 +5,14 @@ use lemmy_api_common::{
|
||||||
get_local_user_view_from_jwt,
|
get_local_user_view_from_jwt,
|
||||||
is_admin,
|
is_admin,
|
||||||
site::{EditSite, SiteResponse},
|
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::{
|
use lemmy_db_schema::{
|
||||||
naive_now,
|
naive_now,
|
||||||
source::site::{Site, SiteForm},
|
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 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 icon = diesel_option_overwrite_to_url(&data.icon)?;
|
||||||
let banner = diesel_option_overwrite_to_url(&data.banner)?;
|
let banner = diesel_option_overwrite_to_url(&data.banner)?;
|
||||||
|
|
||||||
|
if let Some(Some(desc)) = &description {
|
||||||
|
site_description_length_check(desc)?;
|
||||||
|
}
|
||||||
|
|
||||||
let site_form = SiteForm {
|
let site_form = SiteForm {
|
||||||
name: data.name.to_owned(),
|
name: data.name.to_owned(),
|
||||||
description: data.description.to_owned(),
|
sidebar,
|
||||||
|
description,
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
creator_id: found_site.creator_id,
|
creator_id: found_site.creator_id,
|
||||||
|
|
|
@ -133,6 +133,7 @@ impl PerformCrud for Register {
|
||||||
default_listing_type: Some(ListingType::Subscribed as i16),
|
default_listing_type: Some(ListingType::Subscribed as i16),
|
||||||
lang: Some("browser".into()),
|
lang: Some("browser".into()),
|
||||||
show_avatars: Some(true),
|
show_avatars: Some(true),
|
||||||
|
show_scores: Some(true),
|
||||||
send_notifications_to_email: Some(false),
|
send_notifications_to_email: Some(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -177,7 +178,6 @@ impl PerformCrud for Register {
|
||||||
name: default_community_name.to_string(),
|
name: default_community_name.to_string(),
|
||||||
title: "The Default Community".to_string(),
|
title: "The Default Community".to_string(),
|
||||||
description: Some("The Default Community".to_string()),
|
description: Some("The Default Community".to_string()),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
actor_id: Some(actor_id.to_owned()),
|
actor_id: Some(actor_id.to_owned()),
|
||||||
private_key: Some(main_community_keypair.private_key),
|
private_key: Some(main_community_keypair.private_key),
|
||||||
public_key: Some(main_community_keypair.public_key),
|
public_key: Some(main_community_keypair.public_key),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::{context::lemmy_context, group_extension::GroupExtension},
|
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,
|
generate_moderators_url,
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
|
@ -140,24 +140,7 @@ impl FromApubToForm<GroupExt> for CommunityForm {
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
_mod_action_allowed: bool,
|
_mod_action_allowed: bool,
|
||||||
) -> Result<Self, LemmyError> {
|
) -> Result<Self, LemmyError> {
|
||||||
let moderator_uris = fetch_community_mods(context, group, request_counter).await?;
|
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?;
|
|
||||||
|
|
||||||
let name = group
|
let name = group
|
||||||
.inner
|
.inner
|
||||||
|
@ -215,7 +198,6 @@ impl FromApubToForm<GroupExt> for CommunityForm {
|
||||||
name,
|
name,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
creator_id: creator.id,
|
|
||||||
removed: None,
|
removed: None,
|
||||||
published: group.inner.published().map(|u| u.to_owned().naive_local()),
|
published: group.inner.published().map(|u| u.to_owned().naive_local()),
|
||||||
updated: group.inner.updated().map(|u| u.to_owned().naive_local()),
|
updated: group.inner.updated().map(|u| u.to_owned().naive_local()),
|
||||||
|
|
|
@ -64,7 +64,8 @@ impl ToApub for DbPerson {
|
||||||
set_content_and_source(&mut person, bio)?;
|
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);
|
person.set_name(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +162,7 @@ impl FromApubToForm<PersonExt> for PersonForm {
|
||||||
.preferred_username()
|
.preferred_username()
|
||||||
.context(location_info!())?
|
.context(location_info!())?
|
||||||
.to_string();
|
.to_string();
|
||||||
let preferred_username: Option<String> = person
|
let display_name: Option<String> = person
|
||||||
.name()
|
.name()
|
||||||
.map(|n| n.one())
|
.map(|n| n.one())
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -176,12 +177,12 @@ impl FromApubToForm<PersonExt> for PersonForm {
|
||||||
.map(|s| s.to_owned().into());
|
.map(|s| s.to_owned().into());
|
||||||
|
|
||||||
check_slurs(&name)?;
|
check_slurs(&name)?;
|
||||||
check_slurs_opt(&preferred_username)?;
|
check_slurs_opt(&display_name)?;
|
||||||
check_slurs_opt(&bio)?;
|
check_slurs_opt(&bio)?;
|
||||||
|
|
||||||
Ok(PersonForm {
|
Ok(PersonForm {
|
||||||
name,
|
name,
|
||||||
preferred_username: Some(preferred_username),
|
display_name: Some(display_name),
|
||||||
banned: None,
|
banned: None,
|
||||||
deleted: None,
|
deleted: None,
|
||||||
avatar: avatar.map(|o| o.map(|i| i.into())),
|
avatar: avatar.map(|o| o.map(|i| i.into())),
|
||||||
|
|
|
@ -58,7 +58,6 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL_comment_agg".into(),
|
name: "TIL_comment_agg".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -142,5 +141,9 @@ mod tests {
|
||||||
Person::delete(&conn, another_inserted_person.id).unwrap();
|
Person::delete(&conn, another_inserted_person.id).unwrap();
|
||||||
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
||||||
assert_eq!(1, person_num_deleted);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,6 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL_community_agg".into(),
|
name: "TIL_community_agg".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -71,7 +70,6 @@ mod tests {
|
||||||
|
|
||||||
let another_community = CommunityForm {
|
let another_community = CommunityForm {
|
||||||
name: "TIL_community_agg_2".into(),
|
name: "TIL_community_agg_2".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -169,6 +167,14 @@ mod tests {
|
||||||
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
||||||
assert_eq!(1, person_num_deleted);
|
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
|
// Should be none found, since the creator was deleted
|
||||||
let after_delete = CommunityAggregates::read(&conn, inserted_community.id);
|
let after_delete = CommunityAggregates::read(&conn, inserted_community.id);
|
||||||
assert!(after_delete.is_err());
|
assert!(after_delete.is_err());
|
||||||
|
|
|
@ -58,7 +58,6 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL_site_agg".into(),
|
name: "TIL_site_agg".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -160,6 +159,10 @@ mod tests {
|
||||||
assert_eq!(1, person_num_deleted);
|
assert_eq!(1, person_num_deleted);
|
||||||
Person::delete(&conn, another_inserted_person.id).unwrap();
|
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
|
// Should be none found
|
||||||
let after_delete = PersonAggregates::read(&conn, inserted_person.id);
|
let after_delete = PersonAggregates::read(&conn, inserted_person.id);
|
||||||
assert!(after_delete.is_err());
|
assert!(after_delete.is_err());
|
||||||
|
|
|
@ -62,7 +62,6 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL_community_agg".into(),
|
name: "TIL_community_agg".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -149,6 +148,10 @@ mod tests {
|
||||||
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
||||||
assert_eq!(1, person_num_deleted);
|
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
|
// Should be none found, since the creator was deleted
|
||||||
let after_delete = PostAggregates::read(&conn, inserted_post.id);
|
let after_delete = PostAggregates::read(&conn, inserted_post.id);
|
||||||
assert!(after_delete.is_err());
|
assert!(after_delete.is_err());
|
||||||
|
|
|
@ -49,6 +49,7 @@ mod tests {
|
||||||
|
|
||||||
let site_form = SiteForm {
|
let site_form = SiteForm {
|
||||||
name: "test_site".into(),
|
name: "test_site".into(),
|
||||||
|
sidebar: None,
|
||||||
description: None,
|
description: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
|
@ -63,7 +64,6 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL_site_agg".into(),
|
name: "TIL_site_agg".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -118,6 +118,10 @@ mod tests {
|
||||||
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
let person_num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
|
||||||
assert_eq!(1, person_num_deleted);
|
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);
|
let after_delete = SiteAggregates::read(&conn);
|
||||||
assert!(after_delete.is_err());
|
assert!(after_delete.is_err());
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,7 +254,6 @@ mod tests {
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "test community".to_string(),
|
name: "test community".to_string(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ mod safe_type {
|
||||||
name,
|
name,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
creator_id,
|
|
||||||
removed,
|
removed,
|
||||||
published,
|
published,
|
||||||
updated,
|
updated,
|
||||||
|
@ -46,7 +45,6 @@ mod safe_type {
|
||||||
name,
|
name,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
creator_id,
|
|
||||||
removed,
|
removed,
|
||||||
published,
|
published,
|
||||||
updated,
|
updated,
|
||||||
|
@ -122,16 +120,6 @@ pub trait Community_ {
|
||||||
community_id: CommunityId,
|
community_id: CommunityId,
|
||||||
new_removed: bool,
|
new_removed: bool,
|
||||||
) -> Result<Community, Error>;
|
) -> Result<Community, Error>;
|
||||||
fn update_removed_for_creator(
|
|
||||||
conn: &PgConnection,
|
|
||||||
for_creator_id: PersonId,
|
|
||||||
new_removed: bool,
|
|
||||||
) -> Result<Vec<Community>, Error>;
|
|
||||||
fn update_creator(
|
|
||||||
conn: &PgConnection,
|
|
||||||
community_id: CommunityId,
|
|
||||||
new_creator_id: PersonId,
|
|
||||||
) -> Result<Community, Error>;
|
|
||||||
fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error>;
|
fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error>;
|
||||||
fn read_from_followers_url(
|
fn read_from_followers_url(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
|
@ -170,28 +158,6 @@ impl Community_ for Community {
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_removed_for_creator(
|
|
||||||
conn: &PgConnection,
|
|
||||||
for_creator_id: PersonId,
|
|
||||||
new_removed: bool,
|
|
||||||
) -> Result<Vec<Community>, 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::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_creator(
|
|
||||||
conn: &PgConnection,
|
|
||||||
community_id: CommunityId,
|
|
||||||
new_creator_id: PersonId,
|
|
||||||
) -> Result<Community, Error> {
|
|
||||||
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::<Self>(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error> {
|
fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error> {
|
||||||
use lemmy_db_schema::schema::community::dsl::*;
|
use lemmy_db_schema::schema::community::dsl::*;
|
||||||
community.select(actor_id).distinct().load::<String>(conn)
|
community.select(actor_id).distinct().load::<String>(conn)
|
||||||
|
@ -363,7 +329,6 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL".into(),
|
name: "TIL".into(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
@ -372,7 +337,6 @@ mod tests {
|
||||||
|
|
||||||
let expected_community = Community {
|
let expected_community = Community {
|
||||||
id: inserted_community.id,
|
id: inserted_community.id,
|
||||||
creator_id: inserted_person.id,
|
|
||||||
name: "TIL".into(),
|
name: "TIL".into(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
description: None,
|
description: None,
|
||||||
|
|
|
@ -24,6 +24,7 @@ mod safe_settings_type {
|
||||||
show_avatars,
|
show_avatars,
|
||||||
send_notifications_to_email,
|
send_notifications_to_email,
|
||||||
validator_time,
|
validator_time,
|
||||||
|
show_scores,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ToSafeSettings for LocalUser {
|
impl ToSafeSettings for LocalUser {
|
||||||
|
@ -43,6 +44,7 @@ mod safe_settings_type {
|
||||||
show_avatars,
|
show_avatars,
|
||||||
send_notifications_to_email,
|
send_notifications_to_email,
|
||||||
validator_time,
|
validator_time,
|
||||||
|
show_scores,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,6 @@ mod tests {
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "mod_community".to_string(),
|
name: "mod_community".to_string(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ mod safe_type {
|
||||||
type Columns = (
|
type Columns = (
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
preferred_username,
|
display_name,
|
||||||
avatar,
|
avatar,
|
||||||
banned,
|
banned,
|
||||||
published,
|
published,
|
||||||
|
@ -37,7 +37,7 @@ mod safe_type {
|
||||||
(
|
(
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
preferred_username,
|
display_name,
|
||||||
avatar,
|
avatar,
|
||||||
banned,
|
banned,
|
||||||
published,
|
published,
|
||||||
|
@ -63,7 +63,7 @@ mod safe_type_alias_1 {
|
||||||
type Columns = (
|
type Columns = (
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
preferred_username,
|
display_name,
|
||||||
avatar,
|
avatar,
|
||||||
banned,
|
banned,
|
||||||
published,
|
published,
|
||||||
|
@ -85,7 +85,7 @@ mod safe_type_alias_1 {
|
||||||
(
|
(
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
preferred_username,
|
display_name,
|
||||||
avatar,
|
avatar,
|
||||||
banned,
|
banned,
|
||||||
published,
|
published,
|
||||||
|
@ -111,7 +111,7 @@ mod safe_type_alias_2 {
|
||||||
type Columns = (
|
type Columns = (
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
preferred_username,
|
display_name,
|
||||||
avatar,
|
avatar,
|
||||||
banned,
|
banned,
|
||||||
published,
|
published,
|
||||||
|
@ -133,7 +133,7 @@ mod safe_type_alias_2 {
|
||||||
(
|
(
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
preferred_username,
|
display_name,
|
||||||
avatar,
|
avatar,
|
||||||
banned,
|
banned,
|
||||||
published,
|
published,
|
||||||
|
@ -236,7 +236,7 @@ impl Person_ for Person {
|
||||||
|
|
||||||
diesel::update(person.find(person_id))
|
diesel::update(person.find(person_id))
|
||||||
.set((
|
.set((
|
||||||
preferred_username.eq::<Option<String>>(None),
|
display_name.eq::<Option<String>>(None),
|
||||||
bio.eq::<Option<String>>(None),
|
bio.eq::<Option<String>>(None),
|
||||||
matrix_user_id.eq::<Option<String>>(None),
|
matrix_user_id.eq::<Option<String>>(None),
|
||||||
deleted.eq(true),
|
deleted.eq(true),
|
||||||
|
@ -264,7 +264,7 @@ mod tests {
|
||||||
let expected_person = Person {
|
let expected_person = Person {
|
||||||
id: inserted_person.id,
|
id: inserted_person.id,
|
||||||
name: "holly".into(),
|
name: "holly".into(),
|
||||||
preferred_username: None,
|
display_name: None,
|
||||||
avatar: None,
|
avatar: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
banned: false,
|
banned: false,
|
||||||
|
|
|
@ -105,7 +105,6 @@ mod tests {
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "test community lake".to_string(),
|
name: "test community lake".to_string(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -281,7 +281,6 @@ mod tests {
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "test community_3".to_string(),
|
name: "test community_3".to_string(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ table! {
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
title -> Varchar,
|
title -> Varchar,
|
||||||
description -> Nullable<Text>,
|
description -> Nullable<Text>,
|
||||||
creator_id -> Int4,
|
|
||||||
removed -> Bool,
|
removed -> Bool,
|
||||||
published -> Timestamp,
|
published -> Timestamp,
|
||||||
updated -> Nullable<Timestamp>,
|
updated -> Nullable<Timestamp>,
|
||||||
|
@ -154,6 +153,7 @@ table! {
|
||||||
show_avatars -> Bool,
|
show_avatars -> Bool,
|
||||||
send_notifications_to_email -> Bool,
|
send_notifications_to_email -> Bool,
|
||||||
validator_time -> Timestamp,
|
validator_time -> Timestamp,
|
||||||
|
show_scores -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ table! {
|
||||||
person (id) {
|
person (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
preferred_username -> Nullable<Varchar>,
|
display_name -> Nullable<Varchar>,
|
||||||
avatar -> Nullable<Varchar>,
|
avatar -> Nullable<Varchar>,
|
||||||
banned -> Bool,
|
banned -> Bool,
|
||||||
published -> Timestamp,
|
published -> Timestamp,
|
||||||
|
@ -421,7 +421,7 @@ table! {
|
||||||
site (id) {
|
site (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
description -> Nullable<Text>,
|
sidebar -> Nullable<Text>,
|
||||||
creator_id -> Int4,
|
creator_id -> Int4,
|
||||||
published -> Timestamp,
|
published -> Timestamp,
|
||||||
updated -> Nullable<Timestamp>,
|
updated -> Nullable<Timestamp>,
|
||||||
|
@ -430,6 +430,7 @@ table! {
|
||||||
enable_nsfw -> Bool,
|
enable_nsfw -> Bool,
|
||||||
icon -> Nullable<Varchar>,
|
icon -> Nullable<Varchar>,
|
||||||
banner -> Nullable<Varchar>,
|
banner -> Nullable<Varchar>,
|
||||||
|
description -> Nullable<Text>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +471,7 @@ table! {
|
||||||
person_alias_1 (id) {
|
person_alias_1 (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
preferred_username -> Nullable<Varchar>,
|
display_name -> Nullable<Varchar>,
|
||||||
avatar -> Nullable<Varchar>,
|
avatar -> Nullable<Varchar>,
|
||||||
banned -> Bool,
|
banned -> Bool,
|
||||||
published -> Timestamp,
|
published -> Timestamp,
|
||||||
|
@ -494,7 +495,7 @@ table! {
|
||||||
person_alias_2 (id) {
|
person_alias_2 (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
preferred_username -> Nullable<Varchar>,
|
display_name -> Nullable<Varchar>,
|
||||||
avatar -> Nullable<Varchar>,
|
avatar -> Nullable<Varchar>,
|
||||||
banned -> Bool,
|
banned -> Bool,
|
||||||
published -> Timestamp,
|
published -> Timestamp,
|
||||||
|
@ -532,7 +533,6 @@ joinable!(comment_like -> post (post_id));
|
||||||
joinable!(comment_report -> comment (comment_id));
|
joinable!(comment_report -> comment (comment_id));
|
||||||
joinable!(comment_saved -> comment (comment_id));
|
joinable!(comment_saved -> comment (comment_id));
|
||||||
joinable!(comment_saved -> person (person_id));
|
joinable!(comment_saved -> person (person_id));
|
||||||
joinable!(community -> person (creator_id));
|
|
||||||
joinable!(community_aggregates -> community (community_id));
|
joinable!(community_aggregates -> community (community_id));
|
||||||
joinable!(community_follower -> community (community_id));
|
joinable!(community_follower -> community (community_id));
|
||||||
joinable!(community_follower -> person (person_id));
|
joinable!(community_follower -> person (person_id));
|
||||||
|
|
|
@ -56,8 +56,8 @@ pub struct CommentAlias1 {
|
||||||
pub struct CommentForm {
|
pub struct CommentForm {
|
||||||
pub creator_id: PersonId,
|
pub creator_id: PersonId,
|
||||||
pub post_id: PostId,
|
pub post_id: PostId,
|
||||||
pub parent_id: Option<CommentId>,
|
|
||||||
pub content: String,
|
pub content: String,
|
||||||
|
pub parent_id: Option<CommentId>,
|
||||||
pub removed: Option<bool>,
|
pub removed: Option<bool>,
|
||||||
pub read: Option<bool>,
|
pub read: Option<bool>,
|
||||||
pub published: Option<chrono::NaiveDateTime>,
|
pub published: Option<chrono::NaiveDateTime>,
|
||||||
|
|
|
@ -13,7 +13,6 @@ pub struct Community {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub creator_id: PersonId,
|
|
||||||
pub removed: bool,
|
pub removed: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
|
@ -39,7 +38,6 @@ pub struct CommunitySafe {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub creator_id: PersonId,
|
|
||||||
pub removed: bool,
|
pub removed: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
|
@ -57,7 +55,6 @@ pub struct CommunityForm {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub creator_id: PersonId,
|
|
||||||
pub removed: Option<bool>,
|
pub removed: Option<bool>,
|
||||||
pub published: Option<chrono::NaiveDateTime>,
|
pub published: Option<chrono::NaiveDateTime>,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub struct LocalUser {
|
||||||
pub show_avatars: bool,
|
pub show_avatars: bool,
|
||||||
pub send_notifications_to_email: bool,
|
pub send_notifications_to_email: bool,
|
||||||
pub validator_time: chrono::NaiveDateTime,
|
pub validator_time: chrono::NaiveDateTime,
|
||||||
|
pub show_scores: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO redo these, check table defaults
|
// TODO redo these, check table defaults
|
||||||
|
@ -32,6 +33,7 @@ pub struct LocalUserForm {
|
||||||
pub lang: Option<String>,
|
pub lang: Option<String>,
|
||||||
pub show_avatars: Option<bool>,
|
pub show_avatars: Option<bool>,
|
||||||
pub send_notifications_to_email: Option<bool>,
|
pub send_notifications_to_email: Option<bool>,
|
||||||
|
pub show_scores: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A local user view that removes password encrypted
|
/// A local user view that removes password encrypted
|
||||||
|
@ -49,4 +51,5 @@ pub struct LocalUserSettings {
|
||||||
pub show_avatars: bool,
|
pub show_avatars: bool,
|
||||||
pub send_notifications_to_email: bool,
|
pub send_notifications_to_email: bool,
|
||||||
pub validator_time: chrono::NaiveDateTime,
|
pub validator_time: chrono::NaiveDateTime,
|
||||||
|
pub show_scores: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use serde::Serialize;
|
||||||
pub struct Person {
|
pub struct Person {
|
||||||
pub id: PersonId,
|
pub id: PersonId,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub avatar: Option<DbUrl>,
|
pub avatar: Option<DbUrl>,
|
||||||
pub banned: bool,
|
pub banned: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
|
@ -35,7 +35,7 @@ pub struct Person {
|
||||||
pub struct PersonSafe {
|
pub struct PersonSafe {
|
||||||
pub id: PersonId,
|
pub id: PersonId,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub avatar: Option<DbUrl>,
|
pub avatar: Option<DbUrl>,
|
||||||
pub banned: bool,
|
pub banned: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
|
@ -56,7 +56,7 @@ pub struct PersonSafe {
|
||||||
pub struct PersonAlias1 {
|
pub struct PersonAlias1 {
|
||||||
pub id: PersonId,
|
pub id: PersonId,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub avatar: Option<DbUrl>,
|
pub avatar: Option<DbUrl>,
|
||||||
pub banned: bool,
|
pub banned: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
|
@ -80,7 +80,7 @@ pub struct PersonAlias1 {
|
||||||
pub struct PersonSafeAlias1 {
|
pub struct PersonSafeAlias1 {
|
||||||
pub id: PersonId,
|
pub id: PersonId,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub avatar: Option<DbUrl>,
|
pub avatar: Option<DbUrl>,
|
||||||
pub banned: bool,
|
pub banned: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
|
@ -101,7 +101,7 @@ pub struct PersonSafeAlias1 {
|
||||||
pub struct PersonAlias2 {
|
pub struct PersonAlias2 {
|
||||||
pub id: PersonId,
|
pub id: PersonId,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub avatar: Option<DbUrl>,
|
pub avatar: Option<DbUrl>,
|
||||||
pub banned: bool,
|
pub banned: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
|
@ -125,7 +125,7 @@ pub struct PersonAlias2 {
|
||||||
pub struct PersonSafeAlias2 {
|
pub struct PersonSafeAlias2 {
|
||||||
pub id: PersonId,
|
pub id: PersonId,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<String>,
|
pub display_name: Option<String>,
|
||||||
pub avatar: Option<DbUrl>,
|
pub avatar: Option<DbUrl>,
|
||||||
pub banned: bool,
|
pub banned: bool,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
|
@ -145,7 +145,7 @@ pub struct PersonSafeAlias2 {
|
||||||
#[table_name = "person"]
|
#[table_name = "person"]
|
||||||
pub struct PersonForm {
|
pub struct PersonForm {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub preferred_username: Option<Option<String>>,
|
pub display_name: Option<Option<String>>,
|
||||||
pub avatar: Option<Option<DbUrl>>,
|
pub avatar: Option<Option<DbUrl>>,
|
||||||
pub banned: Option<bool>,
|
pub banned: Option<bool>,
|
||||||
pub published: Option<chrono::NaiveDateTime>,
|
pub published: Option<chrono::NaiveDateTime>,
|
||||||
|
|
|
@ -35,16 +35,16 @@ pub struct Post {
|
||||||
#[table_name = "post"]
|
#[table_name = "post"]
|
||||||
pub struct PostForm {
|
pub struct PostForm {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub url: Option<DbUrl>,
|
|
||||||
pub body: Option<String>,
|
|
||||||
pub creator_id: PersonId,
|
pub creator_id: PersonId,
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
|
pub nsfw: bool,
|
||||||
|
pub url: Option<DbUrl>,
|
||||||
|
pub body: Option<String>,
|
||||||
pub removed: Option<bool>,
|
pub removed: Option<bool>,
|
||||||
pub locked: Option<bool>,
|
pub locked: Option<bool>,
|
||||||
pub published: Option<chrono::NaiveDateTime>,
|
pub published: Option<chrono::NaiveDateTime>,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub deleted: Option<bool>,
|
pub deleted: Option<bool>,
|
||||||
pub nsfw: bool,
|
|
||||||
pub stickied: Option<bool>,
|
pub stickied: Option<bool>,
|
||||||
pub embed_title: Option<String>,
|
pub embed_title: Option<String>,
|
||||||
pub embed_description: Option<String>,
|
pub embed_description: Option<String>,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use serde::Serialize;
|
||||||
pub struct Site {
|
pub struct Site {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: Option<String>,
|
pub sidebar: Option<String>,
|
||||||
pub creator_id: PersonId,
|
pub creator_id: PersonId,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
|
@ -15,13 +15,14 @@ pub struct Site {
|
||||||
pub enable_nsfw: bool,
|
pub enable_nsfw: bool,
|
||||||
pub icon: Option<DbUrl>,
|
pub icon: Option<DbUrl>,
|
||||||
pub banner: Option<DbUrl>,
|
pub banner: Option<DbUrl>,
|
||||||
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, AsChangeset)]
|
#[derive(Insertable, AsChangeset)]
|
||||||
#[table_name = "site"]
|
#[table_name = "site"]
|
||||||
pub struct SiteForm {
|
pub struct SiteForm {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: Option<String>,
|
pub sidebar: Option<Option<String>>,
|
||||||
pub creator_id: PersonId,
|
pub creator_id: PersonId,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub enable_downvotes: bool,
|
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.
|
// 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<Option<DbUrl>>,
|
pub icon: Option<Option<DbUrl>>,
|
||||||
pub banner: Option<Option<DbUrl>>,
|
pub banner: Option<Option<DbUrl>>,
|
||||||
|
pub description: Option<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -462,7 +462,6 @@ mod tests {
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "test community 5".to_string(),
|
name: "test community 5".to_string(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -519,7 +518,7 @@ mod tests {
|
||||||
creator: PersonSafe {
|
creator: PersonSafe {
|
||||||
id: inserted_person.id,
|
id: inserted_person.id,
|
||||||
name: "timmy".into(),
|
name: "timmy".into(),
|
||||||
preferred_username: None,
|
display_name: None,
|
||||||
published: inserted_person.published,
|
published: inserted_person.published,
|
||||||
avatar: None,
|
avatar: None,
|
||||||
actor_id: inserted_person.actor_id.to_owned(),
|
actor_id: inserted_person.actor_id.to_owned(),
|
||||||
|
@ -567,7 +566,6 @@ mod tests {
|
||||||
local: true,
|
local: true,
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
description: None,
|
description: None,
|
||||||
creator_id: inserted_person.id,
|
|
||||||
updated: None,
|
updated: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
published: inserted_community.published,
|
published: inserted_community.published,
|
||||||
|
|
|
@ -263,7 +263,7 @@ impl<'a> PostQueryBuilder<'a> {
|
||||||
community_person_ban::table.on(
|
community_person_ban::table.on(
|
||||||
post::community_id
|
post::community_id
|
||||||
.eq(community_person_ban::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)
|
.inner_join(post_aggregates::table)
|
||||||
|
@ -462,7 +462,6 @@ mod tests {
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: community_name.to_owned(),
|
name: community_name.to_owned(),
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
creator_id: inserted_person.id,
|
|
||||||
..CommunityForm::default()
|
..CommunityForm::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -541,7 +540,7 @@ mod tests {
|
||||||
creator: PersonSafe {
|
creator: PersonSafe {
|
||||||
id: inserted_person.id,
|
id: inserted_person.id,
|
||||||
name: person_name,
|
name: person_name,
|
||||||
preferred_username: None,
|
display_name: None,
|
||||||
published: inserted_person.published,
|
published: inserted_person.published,
|
||||||
avatar: None,
|
avatar: None,
|
||||||
actor_id: inserted_person.actor_id.to_owned(),
|
actor_id: inserted_person.actor_id.to_owned(),
|
||||||
|
@ -568,7 +567,6 @@ mod tests {
|
||||||
local: true,
|
local: true,
|
||||||
title: "nada".to_owned(),
|
title: "nada".to_owned(),
|
||||||
description: None,
|
description: None,
|
||||||
creator_id: inserted_person.id,
|
|
||||||
updated: None,
|
updated: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
published: inserted_community.published,
|
published: inserted_community.published,
|
||||||
|
|
|
@ -12,11 +12,8 @@ use lemmy_db_queries::{
|
||||||
ViewToVec,
|
ViewToVec,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
schema::{community, community_aggregates, community_follower, person},
|
schema::{community, community_aggregates, community_follower},
|
||||||
source::{
|
source::community::{Community, CommunityFollower, CommunitySafe},
|
||||||
community::{Community, CommunityFollower, CommunitySafe},
|
|
||||||
person::{Person, PersonSafe},
|
|
||||||
},
|
|
||||||
CommunityId,
|
CommunityId,
|
||||||
PersonId,
|
PersonId,
|
||||||
};
|
};
|
||||||
|
@ -25,14 +22,12 @@ use serde::Serialize;
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
pub struct CommunityView {
|
pub struct CommunityView {
|
||||||
pub community: CommunitySafe,
|
pub community: CommunitySafe,
|
||||||
pub creator: PersonSafe,
|
|
||||||
pub subscribed: bool,
|
pub subscribed: bool,
|
||||||
pub counts: CommunityAggregates,
|
pub counts: CommunityAggregates,
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommunityViewTuple = (
|
type CommunityViewTuple = (
|
||||||
CommunitySafe,
|
CommunitySafe,
|
||||||
PersonSafe,
|
|
||||||
CommunityAggregates,
|
CommunityAggregates,
|
||||||
Option<CommunityFollower>,
|
Option<CommunityFollower>,
|
||||||
);
|
);
|
||||||
|
@ -46,9 +41,8 @@ impl CommunityView {
|
||||||
// The left join below will return None in this case
|
// The left join below will return None in this case
|
||||||
let person_id_join = my_person_id.unwrap_or(PersonId(-1));
|
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)
|
.find(community_id)
|
||||||
.inner_join(person::table)
|
|
||||||
.inner_join(community_aggregates::table)
|
.inner_join(community_aggregates::table)
|
||||||
.left_join(
|
.left_join(
|
||||||
community_follower::table.on(
|
community_follower::table.on(
|
||||||
|
@ -59,7 +53,6 @@ impl CommunityView {
|
||||||
)
|
)
|
||||||
.select((
|
.select((
|
||||||
Community::safe_columns_tuple(),
|
Community::safe_columns_tuple(),
|
||||||
Person::safe_columns_tuple(),
|
|
||||||
community_aggregates::all_columns,
|
community_aggregates::all_columns,
|
||||||
community_follower::all_columns.nullable(),
|
community_follower::all_columns.nullable(),
|
||||||
))
|
))
|
||||||
|
@ -67,7 +60,6 @@ impl CommunityView {
|
||||||
|
|
||||||
Ok(CommunityView {
|
Ok(CommunityView {
|
||||||
community,
|
community,
|
||||||
creator,
|
|
||||||
subscribed: follower.is_some(),
|
subscribed: follower.is_some(),
|
||||||
counts,
|
counts,
|
||||||
})
|
})
|
||||||
|
@ -165,7 +157,6 @@ impl<'a> CommunityQueryBuilder<'a> {
|
||||||
let person_id_join = self.my_person_id.unwrap_or(PersonId(-1));
|
let person_id_join = self.my_person_id.unwrap_or(PersonId(-1));
|
||||||
|
|
||||||
let mut query = community::table
|
let mut query = community::table
|
||||||
.inner_join(person::table)
|
|
||||||
.inner_join(community_aggregates::table)
|
.inner_join(community_aggregates::table)
|
||||||
.left_join(
|
.left_join(
|
||||||
community_follower::table.on(
|
community_follower::table.on(
|
||||||
|
@ -176,7 +167,6 @@ impl<'a> CommunityQueryBuilder<'a> {
|
||||||
)
|
)
|
||||||
.select((
|
.select((
|
||||||
Community::safe_columns_tuple(),
|
Community::safe_columns_tuple(),
|
||||||
Person::safe_columns_tuple(),
|
|
||||||
community_aggregates::all_columns,
|
community_aggregates::all_columns,
|
||||||
community_follower::all_columns.nullable(),
|
community_follower::all_columns.nullable(),
|
||||||
))
|
))
|
||||||
|
@ -193,6 +183,7 @@ impl<'a> CommunityQueryBuilder<'a> {
|
||||||
match self.sort {
|
match self.sort {
|
||||||
SortType::New => query = query.order_by(community::published.desc()),
|
SortType::New => query = query.order_by(community::published.desc()),
|
||||||
SortType::TopAll => query = query.order_by(community_aggregates::subscribers.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
|
// Covers all other sorts, including hot
|
||||||
_ => {
|
_ => {
|
||||||
query = query
|
query = query
|
||||||
|
@ -236,9 +227,8 @@ impl ViewToVec for CommunityView {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| Self {
|
.map(|a| Self {
|
||||||
community: a.0.to_owned(),
|
community: a.0.to_owned(),
|
||||||
creator: a.1.to_owned(),
|
counts: a.1.to_owned(),
|
||||||
counts: a.2.to_owned(),
|
subscribed: a.2.is_some(),
|
||||||
subscribed: a.3.is_some(),
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<Self>>()
|
.collect::<Vec<Self>>()
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ impl Default for Settings {
|
||||||
impl Default for DatabaseConfig {
|
impl Default for DatabaseConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
user: "lemmy".into(),
|
user: Some("lemmy".to_string()),
|
||||||
password: "password".into(),
|
password: "password".into(),
|
||||||
host: "localhost".into(),
|
host: "localhost".into(),
|
||||||
port: 5432,
|
port: Some(5432),
|
||||||
database: "lemmy".into(),
|
database: Some("lemmy".to_string()),
|
||||||
pool_size: 5,
|
pool_size: Some(5),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use deser_hjson::from_str;
|
||||||
use merge::Merge;
|
use merge::Merge;
|
||||||
use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
|
use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
|
||||||
|
|
||||||
pub(crate) mod defaults;
|
pub mod defaults;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
|
|
||||||
static CONFIG_FILE: &str = "config/config.hjson";
|
static CONFIG_FILE: &str = "config/config.hjson";
|
||||||
|
@ -60,7 +60,11 @@ impl Settings {
|
||||||
let conf = self.database();
|
let conf = self.database();
|
||||||
format!(
|
format!(
|
||||||
"postgres://{}:{}@{}:{}/{}",
|
"postgres://{}:{}@{}:{}/{}",
|
||||||
conf.user, conf.password, conf.host, conf.port, conf.database,
|
conf.user(),
|
||||||
|
conf.password,
|
||||||
|
conf.host,
|
||||||
|
conf.port(),
|
||||||
|
conf.database(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,40 @@ pub struct CaptchaConfig {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
pub struct DatabaseConfig {
|
pub struct DatabaseConfig {
|
||||||
pub user: String,
|
pub(super) user: Option<String>,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub port: i32,
|
pub(super) port: Option<i32>,
|
||||||
pub database: String,
|
pub(super) database: Option<String>,
|
||||||
pub pool_size: u32,
|
pub(super) pool_size: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
is_valid_community_name,
|
is_valid_community_name,
|
||||||
|
is_valid_display_name,
|
||||||
|
is_valid_matrix_id,
|
||||||
is_valid_post_title,
|
is_valid_post_title,
|
||||||
is_valid_preferred_username,
|
|
||||||
is_valid_username,
|
is_valid_username,
|
||||||
remove_slurs,
|
remove_slurs,
|
||||||
scrape_text_for_mentions,
|
scrape_text_for_mentions,
|
||||||
|
@ -29,9 +30,15 @@ fn test_valid_register_username() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_valid_preferred_username() {
|
fn test_valid_display_name() {
|
||||||
assert!(is_valid_preferred_username("hello @there"));
|
assert!(is_valid_display_name("hello @there"));
|
||||||
assert!(!is_valid_preferred_username("@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]
|
#[test]
|
||||||
|
@ -50,6 +57,14 @@ fn test_valid_post_title() {
|
||||||
assert!(!is_valid_post_title("\n \n \n \n ")); // tabs/spaces/newlines
|
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]
|
#[test]
|
||||||
fn test_slur_filter() {
|
fn test_slur_filter() {
|
||||||
let test =
|
let test =
|
||||||
|
|
|
@ -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_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_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_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 {
|
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
|
// Can't do a regex here, reverse lookarounds not supported
|
||||||
pub fn is_valid_preferred_username(preferred_username: &str) -> bool {
|
pub fn is_valid_display_name(name: &str) -> bool {
|
||||||
!preferred_username.starts_with('@')
|
!name.starts_with('@')
|
||||||
&& preferred_username.chars().count() >= 3
|
&& !name.starts_with('\u{200b}')
|
||||||
&& preferred_username.chars().count() <= 20
|
&& 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 {
|
pub fn is_valid_community_name(name: &str) -> bool {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
pub const VERSION: &str = "0.10.2";
|
pub const VERSION: &str = "0.10.3";
|
||||||
|
|
|
@ -123,6 +123,7 @@ pub enum UserOperation {
|
||||||
PostJoin,
|
PostJoin,
|
||||||
CommunityJoin,
|
CommunityJoin,
|
||||||
ModJoin,
|
ModJoin,
|
||||||
|
ChangePassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Clone)]
|
#[derive(EnumString, ToString, Debug, Clone)]
|
||||||
|
|
|
@ -49,9 +49,6 @@ FROM alpine:3.12 as lemmy
|
||||||
# Install libpq for postgres
|
# Install libpq for postgres
|
||||||
RUN apk add libpq
|
RUN apk add libpq
|
||||||
|
|
||||||
# Install Espeak for captchas
|
|
||||||
RUN apk add espeak
|
|
||||||
|
|
||||||
RUN addgroup -g 1000 lemmy
|
RUN addgroup -g 1000 lemmy
|
||||||
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
|
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,4 @@ mkdir -p volumes/pictrs
|
||||||
sudo chown -R 991:991 volumes/pictrs
|
sudo chown -R 991:991 volumes/pictrs
|
||||||
sudo docker build ../../ --file ../dev/volume_mount.dockerfile -t lemmy-dev:latest
|
sudo docker build ../../ --file ../dev/volume_mount.dockerfile -t lemmy-dev:latest
|
||||||
sudo docker-compose pull --ignore-pull-failures || true
|
sudo docker-compose pull --ignore-pull-failures || true
|
||||||
sudo docker-compose up -d
|
sudo docker-compose up
|
||||||
|
|
|
@ -19,9 +19,9 @@ RUN --mount=type=cache,target=/app/target \
|
||||||
|
|
||||||
FROM ubuntu:20.10
|
FROM ubuntu:20.10
|
||||||
|
|
||||||
# Install libpq for postgres and espeak
|
# Install libpq for postgres
|
||||||
RUN apt-get update -y
|
RUN apt-get update -y
|
||||||
RUN apt-get install -y libpq-dev espeak
|
RUN apt-get install -y libpq-dev
|
||||||
|
|
||||||
# Copy resources
|
# Copy resources
|
||||||
COPY --from=rust /app/lemmy_server /app/lemmy
|
COPY --from=rust /app/lemmy_server /app/lemmy
|
||||||
|
|
|
@ -22,9 +22,9 @@ RUN cp ./target/release/lemmy_server /app/lemmy_server
|
||||||
# The Debian runner
|
# The Debian runner
|
||||||
FROM debian:buster-slim as lemmy
|
FROM debian:buster-slim as lemmy
|
||||||
|
|
||||||
# Install libpq for postgres and espeak for captchas
|
# Install libpq for postgres
|
||||||
RUN apt-get update \
|
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/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN addgroup --gid 1000 lemmy
|
RUN addgroup --gid 1000 lemmy
|
||||||
|
|
|
@ -12,7 +12,7 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
lemmy:
|
lemmy:
|
||||||
image: dessalines/lemmy:0.10.2
|
image: dessalines/lemmy:0.10.3
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8536:8536"
|
- "127.0.0.1:8536:8536"
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -26,7 +26,7 @@ services:
|
||||||
- iframely
|
- iframely
|
||||||
|
|
||||||
lemmy-ui:
|
lemmy-ui:
|
||||||
image: dessalines/lemmy-ui:0.10.2
|
image: dessalines/lemmy-ui:0.10.3
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:1235:1234"
|
- "127.0.0.1:1235:1234"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
alter table local_user drop column show_scores;
|
|
@ -0,0 +1 @@
|
||||||
|
alter table local_user add column show_scores boolean default true not null;
|
|
@ -0,0 +1,2 @@
|
||||||
|
alter table site drop column description;
|
||||||
|
alter table site rename column sidebar to description;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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;
|
|
@ -0,0 +1 @@
|
||||||
|
drop index idx_community_aggregates_users_active_month;
|
|
@ -0,0 +1,2 @@
|
||||||
|
create index idx_community_aggregates_users_active_month on community_aggregates (users_active_month desc);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- Drop the column
|
||||||
|
alter table community drop column creator_id;
|
|
@ -182,6 +182,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
"/save_user_settings",
|
"/save_user_settings",
|
||||||
web::put().to(route_post::<SaveUserSettings>),
|
web::put().to(route_post::<SaveUserSettings>),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/change_password",
|
||||||
|
web::put().to(route_post::<ChangePassword>),
|
||||||
|
)
|
||||||
.route("/report_count", web::get().to(route_get::<GetReportCount>)),
|
.route("/report_count", web::get().to(route_get::<GetReportCount>)),
|
||||||
)
|
)
|
||||||
// Admin Actions
|
// Admin Actions
|
||||||
|
|
|
@ -89,7 +89,6 @@ fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> {
|
||||||
name: ccommunity.name.to_owned(),
|
name: ccommunity.name.to_owned(),
|
||||||
title: ccommunity.title.to_owned(),
|
title: ccommunity.title.to_owned(),
|
||||||
description: ccommunity.description.to_owned(),
|
description: ccommunity.description.to_owned(),
|
||||||
creator_id: ccommunity.creator_id,
|
|
||||||
removed: None,
|
removed: None,
|
||||||
deleted: None,
|
deleted: None,
|
||||||
nsfw: None,
|
nsfw: None,
|
||||||
|
|
|
@ -38,7 +38,7 @@ async fn main() -> Result<(), LemmyError> {
|
||||||
};
|
};
|
||||||
let manager = ConnectionManager::<PgConnection>::new(&db_url);
|
let manager = ConnectionManager::<PgConnection>::new(&db_url);
|
||||||
let pool = Pool::builder()
|
let pool = Pool::builder()
|
||||||
.max_size(settings.database().pool_size)
|
.max_size(settings.database().pool_size())
|
||||||
.build(manager)
|
.build(manager)
|
||||||
.unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
|
.unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue