mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 14:21:19 +00:00
Merge branch 'main' into feature/1298-federated-bans
This commit is contained in:
commit
821888e973
75 changed files with 476 additions and 367 deletions
72
.drone.yml
72
.drone.yml
|
@ -55,7 +55,39 @@ steps:
|
|||
- yarn
|
||||
- yarn api-test
|
||||
|
||||
- name: make release build and push to docker hub
|
||||
- name: publish dev docker image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dockerfile: docker/prod/Dockerfile
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: dessalines/lemmy
|
||||
tags:
|
||||
- dev-linux-amd64
|
||||
when:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
|
||||
- name: publish dev docker manifest
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
target: "dessalines/lemmy:dev"
|
||||
template: "dessalines/lemmy:dev-OS-ARCH"
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
ignore_missing: true
|
||||
when:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
|
||||
- name: publish release docker image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dockerfile: docker/prod/Dockerfile
|
||||
|
@ -70,7 +102,7 @@ steps:
|
|||
ref:
|
||||
- refs/tags/*
|
||||
|
||||
- name: push to docker manifest
|
||||
- name: publish release docker manifest
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
username:
|
||||
|
@ -140,7 +172,39 @@ steps:
|
|||
- yarn
|
||||
- yarn api-test
|
||||
|
||||
- name: make release build and push to docker hub
|
||||
- name: publish dev docker image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dockerfile: docker/prod/Dockerfile.arm
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: dessalines/lemmy
|
||||
tags:
|
||||
- dev-linux-arm64
|
||||
when:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
|
||||
- name: publish dev docker manifest
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
target: "dessalines/lemmy:dev"
|
||||
template: "dessalines/lemmy:dev-OS-ARCH"
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
ignore_missing: true
|
||||
when:
|
||||
ref:
|
||||
- refs/heads/main
|
||||
|
||||
- name: publish release docker image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dockerfile: docker/prod/Dockerfile.arm
|
||||
|
@ -155,7 +219,7 @@ steps:
|
|||
ref:
|
||||
- refs/tags/*
|
||||
|
||||
- name: push to docker manifest
|
||||
- name: publish release docker manifest
|
||||
image: plugins/manifest
|
||||
settings:
|
||||
username:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.10.2
|
||||
0.10.3
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
@ -340,12 +336,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)
|
||||
})
|
||||
|
@ -353,7 +343,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)
|
||||
|
@ -361,8 +351,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)
|
||||
|
@ -371,19 +368,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)
|
||||
|
@ -391,6 +377,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)
|
||||
|
@ -398,6 +385,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,
|
||||
|
@ -411,6 +399,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,
|
||||
|
|
|
@ -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::<SaveUserSettings>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::ChangePassword => {
|
||||
do_websocket_operation::<ChangePassword>(context, id, op, data).await
|
||||
}
|
||||
UserOperation::GetReportCount => {
|
||||
do_websocket_operation::<GetReportCount>(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<String, LemmyError> {
|
||||
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)
|
||||
let mut concat_letters: Vec<u8> = Vec::new();
|
||||
|
||||
for letter in letters {
|
||||
let bytes = letter.unwrap_or_default();
|
||||
concat_letters.extend(bytes);
|
||||
}
|
||||
} else {
|
||||
format!("{} ...", c)
|
||||
};
|
||||
|
||||
built_text.push_str(&new_str);
|
||||
}
|
||||
|
||||
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
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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)]
|
||||
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: &'_ _| {
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,31 +40,40 @@ pub struct GetCaptchaResponse {
|
|||
#[derive(Serialize)]
|
||||
pub struct CaptchaResponse {
|
||||
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,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SaveUserSettings {
|
||||
pub show_nsfw: Option<bool>,
|
||||
pub show_scores: Option<bool>,
|
||||
pub theme: Option<String>,
|
||||
pub default_sort_type: Option<i16>,
|
||||
pub default_listing_type: Option<i16>,
|
||||
pub lang: Option<String>,
|
||||
pub avatar: Option<String>,
|
||||
pub banner: Option<String>,
|
||||
pub preferred_username: Option<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
pub matrix_user_id: Option<String>,
|
||||
pub show_avatars: Option<bool>,
|
||||
pub new_password: Option<String>,
|
||||
pub new_password_verify: Option<String>,
|
||||
pub old_password: Option<String>,
|
||||
pub show_avatars: Option<bool>,
|
||||
pub send_notifications_to_email: Option<bool>,
|
||||
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,
|
||||
|
|
|
@ -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<String>,
|
||||
pub description: Option<String>,
|
||||
pub icon: Option<Url>,
|
||||
pub banner: Option<Url>,
|
||||
pub icon: Option<String>,
|
||||
pub banner: Option<String>,
|
||||
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<String>,
|
||||
pub description: Option<String>,
|
||||
pub icon: Option<String>,
|
||||
pub banner: Option<String>,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<GroupExt> for CommunityForm {
|
|||
request_counter: &mut i32,
|
||||
_mod_action_allowed: bool,
|
||||
) -> Result<Self, LemmyError> {
|
||||
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<GroupExt> 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()),
|
||||
|
|
|
@ -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<PersonExt> for PersonForm {
|
|||
.preferred_username()
|
||||
.context(location_info!())?
|
||||
.to_string();
|
||||
let preferred_username: Option<String> = person
|
||||
let display_name: Option<String> = person
|
||||
.name()
|
||||
.map(|n| n.one())
|
||||
.flatten()
|
||||
|
@ -176,12 +177,12 @@ impl FromApubToForm<PersonExt> 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())),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -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<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 read_from_followers_url(
|
||||
conn: &PgConnection,
|
||||
|
@ -170,28 +158,6 @@ impl Community_ for Community {
|
|||
.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> {
|
||||
use lemmy_db_schema::schema::community::dsl::*;
|
||||
community.select(actor_id).distinct().load::<String>(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,
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -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::<Option<String>>(None),
|
||||
display_name.eq::<Option<String>>(None),
|
||||
bio.eq::<Option<String>>(None),
|
||||
matrix_user_id.eq::<Option<String>>(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,
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ table! {
|
|||
name -> Varchar,
|
||||
title -> Varchar,
|
||||
description -> Nullable<Text>,
|
||||
creator_id -> Int4,
|
||||
removed -> Bool,
|
||||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
|
@ -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<Varchar>,
|
||||
display_name -> Nullable<Varchar>,
|
||||
avatar -> Nullable<Varchar>,
|
||||
banned -> Bool,
|
||||
published -> Timestamp,
|
||||
|
@ -421,7 +421,7 @@ table! {
|
|||
site (id) {
|
||||
id -> Int4,
|
||||
name -> Varchar,
|
||||
description -> Nullable<Text>,
|
||||
sidebar -> Nullable<Text>,
|
||||
creator_id -> Int4,
|
||||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
|
@ -430,6 +430,7 @@ table! {
|
|||
enable_nsfw -> Bool,
|
||||
icon -> Nullable<Varchar>,
|
||||
banner -> Nullable<Varchar>,
|
||||
description -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,7 +471,7 @@ table! {
|
|||
person_alias_1 (id) {
|
||||
id -> Int4,
|
||||
name -> Varchar,
|
||||
preferred_username -> Nullable<Varchar>,
|
||||
display_name -> Nullable<Varchar>,
|
||||
avatar -> Nullable<Varchar>,
|
||||
banned -> Bool,
|
||||
published -> Timestamp,
|
||||
|
@ -494,7 +495,7 @@ table! {
|
|||
person_alias_2 (id) {
|
||||
id -> Int4,
|
||||
name -> Varchar,
|
||||
preferred_username -> Nullable<Varchar>,
|
||||
display_name -> Nullable<Varchar>,
|
||||
avatar -> Nullable<Varchar>,
|
||||
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));
|
||||
|
|
|
@ -56,8 +56,8 @@ pub struct CommentAlias1 {
|
|||
pub struct CommentForm {
|
||||
pub creator_id: PersonId,
|
||||
pub post_id: PostId,
|
||||
pub parent_id: Option<CommentId>,
|
||||
pub content: String,
|
||||
pub parent_id: Option<CommentId>,
|
||||
pub removed: Option<bool>,
|
||||
pub read: Option<bool>,
|
||||
pub published: Option<chrono::NaiveDateTime>,
|
||||
|
|
|
@ -13,7 +13,6 @@ pub struct Community {
|
|||
pub name: String,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub creator_id: PersonId,
|
||||
pub removed: bool,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
|
@ -39,7 +38,6 @@ pub struct CommunitySafe {
|
|||
pub name: String,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub creator_id: PersonId,
|
||||
pub removed: bool,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
|
@ -57,7 +55,6 @@ pub struct CommunityForm {
|
|||
pub name: String,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
pub creator_id: PersonId,
|
||||
pub removed: Option<bool>,
|
||||
pub published: Option<chrono::NaiveDateTime>,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
|
|
|
@ -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<String>,
|
||||
pub show_avatars: Option<bool>,
|
||||
pub send_notifications_to_email: Option<bool>,
|
||||
pub show_scores: Option<bool>,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use serde::Serialize;
|
|||
pub struct Person {
|
||||
pub id: PersonId,
|
||||
pub name: String,
|
||||
pub preferred_username: Option<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar: Option<DbUrl>,
|
||||
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<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar: Option<DbUrl>,
|
||||
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<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar: Option<DbUrl>,
|
||||
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<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar: Option<DbUrl>,
|
||||
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<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar: Option<DbUrl>,
|
||||
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<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar: Option<DbUrl>,
|
||||
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<Option<String>>,
|
||||
pub display_name: Option<Option<String>>,
|
||||
pub avatar: Option<Option<DbUrl>>,
|
||||
pub banned: Option<bool>,
|
||||
pub published: Option<chrono::NaiveDateTime>,
|
||||
|
|
|
@ -35,16 +35,16 @@ pub struct Post {
|
|||
#[table_name = "post"]
|
||||
pub struct PostForm {
|
||||
pub name: String,
|
||||
pub url: Option<DbUrl>,
|
||||
pub body: Option<String>,
|
||||
pub creator_id: PersonId,
|
||||
pub community_id: CommunityId,
|
||||
pub nsfw: bool,
|
||||
pub url: Option<DbUrl>,
|
||||
pub body: Option<String>,
|
||||
pub removed: Option<bool>,
|
||||
pub locked: Option<bool>,
|
||||
pub published: Option<chrono::NaiveDateTime>,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: Option<bool>,
|
||||
pub nsfw: bool,
|
||||
pub stickied: Option<bool>,
|
||||
pub embed_title: Option<String>,
|
||||
pub embed_description: Option<String>,
|
||||
|
|
|
@ -6,7 +6,7 @@ use serde::Serialize;
|
|||
pub struct Site {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub sidebar: Option<String>,
|
||||
pub creator_id: PersonId,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
|
@ -15,13 +15,14 @@ pub struct Site {
|
|||
pub enable_nsfw: bool,
|
||||
pub icon: Option<DbUrl>,
|
||||
pub banner: Option<DbUrl>,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset)]
|
||||
#[table_name = "site"]
|
||||
pub struct SiteForm {
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub sidebar: Option<Option<String>>,
|
||||
pub creator_id: PersonId,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
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<Option<DbUrl>>,
|
||||
pub banner: Option<Option<DbUrl>>,
|
||||
pub description: Option<Option<String>>,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<CommunityFollower>,
|
||||
);
|
||||
|
@ -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::<Vec<Self>>()
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,40 @@ pub struct CaptchaConfig {
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct DatabaseConfig {
|
||||
pub user: String,
|
||||
pub(super) user: Option<String>,
|
||||
pub password: String,
|
||||
pub host: String,
|
||||
pub port: i32,
|
||||
pub database: String,
|
||||
pub pool_size: u32,
|
||||
pub(super) port: Option<i32>,
|
||||
pub(super) database: Option<String>,
|
||||
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)]
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1 +1 @@
|
|||
pub const VERSION: &str = "0.10.2";
|
||||
pub const VERSION: &str = "0.10.3";
|
||||
|
|
|
@ -123,6 +123,7 @@ pub enum UserOperation {
|
|||
PostJoin,
|
||||
CommunityJoin,
|
||||
ModJoin,
|
||||
ChangePassword,
|
||||
}
|
||||
|
||||
#[derive(EnumString, ToString, Debug, Clone)]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ services:
|
|||
- iframely
|
||||
|
||||
lemmy-ui:
|
||||
image: dessalines/lemmy-ui:0.10.2
|
||||
image: dessalines/lemmy-ui:dev
|
||||
ports:
|
||||
- "1235:1234"
|
||||
restart: always
|
||||
|
|
|
@ -8,4 +8,5 @@ set -e
|
|||
mkdir -p volumes/pictrs
|
||||
sudo chown -R 991:991 volumes/pictrs
|
||||
sudo docker build ../../ --file ../dev/Dockerfile -t lemmy-dev:latest
|
||||
sudo docker-compose pull --ignore-pull-failures || true
|
||||
sudo docker-compose up -d
|
||||
|
|
|
@ -8,4 +8,5 @@ set -e
|
|||
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 up -d
|
||||
sudo docker-compose pull --ignore-pull-failures || true
|
||||
sudo docker-compose up
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -29,7 +29,7 @@ services:
|
|||
- ./volumes/pictrs_alpha:/mnt
|
||||
|
||||
lemmy-alpha-ui:
|
||||
image: dessalines/lemmy-ui:0.10.3
|
||||
image: dessalines/lemmy-ui:dev
|
||||
environment:
|
||||
- LEMMY_INTERNAL_HOST=lemmy-alpha:8541
|
||||
- LEMMY_EXTERNAL_HOST=localhost:8541
|
||||
|
@ -58,7 +58,7 @@ services:
|
|||
- ./volumes/postgres_alpha:/var/lib/postgresql/data
|
||||
|
||||
lemmy-beta-ui:
|
||||
image: dessalines/lemmy-ui:0.10.3
|
||||
image: dessalines/lemmy-ui:dev
|
||||
environment:
|
||||
- LEMMY_INTERNAL_HOST=lemmy-beta:8551
|
||||
- LEMMY_EXTERNAL_HOST=localhost:8551
|
||||
|
@ -87,7 +87,7 @@ services:
|
|||
- ./volumes/postgres_beta:/var/lib/postgresql/data
|
||||
|
||||
lemmy-gamma-ui:
|
||||
image: dessalines/lemmy-ui:0.10.3
|
||||
image: dessalines/lemmy-ui:dev
|
||||
environment:
|
||||
- LEMMY_INTERNAL_HOST=lemmy-gamma:8561
|
||||
- LEMMY_EXTERNAL_HOST=localhost:8561
|
||||
|
@ -117,7 +117,7 @@ services:
|
|||
|
||||
# An instance with only an allowlist for beta
|
||||
lemmy-delta-ui:
|
||||
image: dessalines/lemmy-ui:0.10.2
|
||||
image: dessalines/lemmy-ui:dev
|
||||
environment:
|
||||
- LEMMY_INTERNAL_HOST=lemmy-delta:8571
|
||||
- LEMMY_EXTERNAL_HOST=localhost:8571
|
||||
|
@ -147,7 +147,7 @@ services:
|
|||
|
||||
# An instance who has a blocklist, with lemmy-alpha blocked
|
||||
lemmy-epsilon-ui:
|
||||
image: dessalines/lemmy-ui:0.10.2
|
||||
image: dessalines/lemmy-ui:dev
|
||||
environment:
|
||||
- LEMMY_INTERNAL_HOST=lemmy-epsilon:8581
|
||||
- LEMMY_EXTERNAL_HOST=localhost:8581
|
||||
|
|
|
@ -8,4 +8,5 @@ for Item in alpha beta gamma delta epsilon ; do
|
|||
sudo chown -R 991:991 volumes/pictrs_$Item
|
||||
done
|
||||
|
||||
sudo docker-compose pull --ignore-pull-failures || true
|
||||
sudo docker-compose up
|
||||
|
|
|
@ -1,38 +1,11 @@
|
|||
ARG RUST_BUILDER_IMAGE=ekidd/rust-musl-builder:1.50.0
|
||||
|
||||
# Cargo chef plan
|
||||
FROM $RUST_BUILDER_IMAGE as planner
|
||||
WORKDIR /app
|
||||
RUN cargo install cargo-chef
|
||||
|
||||
# Copy dirs
|
||||
COPY ./ ./
|
||||
|
||||
RUN sudo chown -R rust:rust .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
# Cargo chef cache dependencies
|
||||
FROM $RUST_BUILDER_IMAGE as cacher
|
||||
ARG CARGO_BUILD_TARGET=x86_64-unknown-linux-musl
|
||||
WORKDIR /app
|
||||
RUN cargo install cargo-chef
|
||||
COPY --from=planner /app/recipe.json ./recipe.json
|
||||
RUN sudo chown -R rust:rust .
|
||||
RUN cargo chef cook --release --target ${CARGO_BUILD_TARGET} --recipe-path recipe.json
|
||||
|
||||
# Build the project
|
||||
FROM $RUST_BUILDER_IMAGE as builder
|
||||
FROM ekidd/rust-musl-builder:1.50.0 as builder
|
||||
|
||||
ARG CARGO_BUILD_TARGET=x86_64-unknown-linux-musl
|
||||
ARG RUSTRELEASEDIR="release"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy over the cached dependencies
|
||||
COPY --from=cacher /app/target target
|
||||
COPY --from=cacher /home/rust/.cargo /home/rust/.cargo
|
||||
|
||||
# Copy the rest of the dirs
|
||||
COPY ./ ./
|
||||
|
||||
RUN sudo chown -R rust:rust .
|
||||
|
@ -49,9 +22,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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,14 +12,6 @@ echo "pub const VERSION: &str = \"$new_tag\";" > "crates/utils/src/version.rs"
|
|||
git add "crates/utils/src/version.rs"
|
||||
popd
|
||||
|
||||
# Changing various references to the Lemmy version
|
||||
sed -i "s/dessalines\/lemmy:.*/dessalines\/lemmy:$new_tag/" ../dev/docker-compose.yml
|
||||
sed -i "s/dessalines\/lemmy-ui:.*/dessalines\/lemmy-ui:$new_tag/" ../dev/docker-compose.yml
|
||||
sed -i "s/dessalines\/lemmy:.*/dessalines\/lemmy:$new_tag/" ../federation/docker-compose.yml
|
||||
sed -i "s/dessalines\/lemmy-ui:.*/dessalines\/lemmy-ui:$new_tag/" ../federation/docker-compose.yml
|
||||
git add ../dev/docker-compose.yml
|
||||
git add ../federation/docker-compose.yml
|
||||
|
||||
# The ansible and docker installs should only update for non release-candidates
|
||||
# IE, when the third semver is a number, not '2-rc'
|
||||
if [ ! -z "${third_semver##*[!0-9]*}" ]; then
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
web::put().to(route_post::<SaveUserSettings>),
|
||||
)
|
||||
.route(
|
||||
"/change_password",
|
||||
web::put().to(route_post::<ChangePassword>),
|
||||
)
|
||||
.route("/report_count", web::get().to(route_get::<GetReportCount>)),
|
||||
)
|
||||
// Admin Actions
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -38,7 +38,7 @@ async fn main() -> Result<(), LemmyError> {
|
|||
};
|
||||
let manager = ConnectionManager::<PgConnection>::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));
|
||||
|
||||
|
|
Loading…
Reference in a new issue