mirror of
https://github.com/LemmyNet/lemmy
synced 2024-11-14 16:57:24 +00:00
Merge branch 'main' into feature/language-tags
This commit is contained in:
commit
d74b7c04ff
70 changed files with 723 additions and 362 deletions
16
.drone.yml
16
.drone.yml
|
@ -8,11 +8,12 @@ platform:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: chown repo
|
- name: prepare repo
|
||||||
image: ekidd/rust-musl-builder:1.50.0
|
image: ekidd/rust-musl-builder:1.50.0
|
||||||
user: root
|
user: root
|
||||||
commands:
|
commands:
|
||||||
- chown 1000:1000 . -R
|
- chown 1000:1000 . -R
|
||||||
|
- git fetch --tags
|
||||||
|
|
||||||
- name: check formatting
|
- name: check formatting
|
||||||
image: rustdocker/rust:nightly
|
image: rustdocker/rust:nightly
|
||||||
|
@ -34,7 +35,7 @@ steps:
|
||||||
RUST_TEST_THREADS: 1
|
RUST_TEST_THREADS: 1
|
||||||
commands:
|
commands:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get -y install --no-install-recommends espeak postgresql-client
|
- sudo apt-get -y install --no-install-recommends postgresql-client
|
||||||
- cargo test --workspace --no-fail-fast
|
- cargo test --workspace --no-fail-fast
|
||||||
|
|
||||||
- name: cargo build
|
- name: cargo build
|
||||||
|
@ -136,6 +137,15 @@ platform:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
- name: prepare repo
|
||||||
|
image: rust:1.50-slim-buster
|
||||||
|
user: root
|
||||||
|
commands:
|
||||||
|
- chown 1000:1000 . -R
|
||||||
|
- apt update
|
||||||
|
- apt install --no-install-recommends --yes git
|
||||||
|
- git fetch --tags
|
||||||
|
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
image: rust:1.50-slim-buster
|
image: rust:1.50-slim-buster
|
||||||
environment:
|
environment:
|
||||||
|
@ -145,7 +155,7 @@ steps:
|
||||||
RUST_TEST_THREADS: 1
|
RUST_TEST_THREADS: 1
|
||||||
commands:
|
commands:
|
||||||
- apt-get update
|
- apt-get update
|
||||||
- apt-get -y install --no-install-recommends espeak postgresql-client libssl-dev pkg-config libpq-dev
|
- apt-get -y install --no-install-recommends postgresql-client libssl-dev pkg-config libpq-dev
|
||||||
- cargo test --workspace --no-fail-fast
|
- cargo test --workspace --no-fail-fast
|
||||||
- cargo build
|
- cargo build
|
||||||
|
|
||||||
|
|
67
RELEASES.md
67
RELEASES.md
|
@ -1,3 +1,70 @@
|
||||||
|
# Lemmy v0.11.0 Release (2021-04-27)
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
Since our last release this month, we've had [~60](https://github.com/LemmyNet/lemmy/compare/0.10.0...main) commits to Lemmy.
|
||||||
|
|
||||||
|
### Lemmy Server
|
||||||
|
|
||||||
|
#### Major Changes
|
||||||
|
|
||||||
|
- Add option to disable strict allowlist ( [#1486](https://github.com/LemmyNet/lemmy/issues/1486)) [documentation](https://join.lemmy.ml/docs/en/federation/administration.html) # TODO: need to merge https://github.com/LemmyNet/lemmy-docs/pull/66/files
|
||||||
|
- Add option to limit community creation to admins only ([#1587](https://github.com/LemmyNet/lemmy/issues/1587))
|
||||||
|
- Many search improvements:
|
||||||
|
- Don't search for communities or users when the id is included.
|
||||||
|
- Add creator id to search.
|
||||||
|
|
||||||
|
#### General
|
||||||
|
|
||||||
|
- Adding a user setting to show / hide scores. Fixes [#1503](https://github.com/LemmyNet/lemmy/issues/1503)
|
||||||
|
- Add option to hide read posts. Fixes [#1561](https://github.com/LemmyNet/lemmy/issues/1561)
|
||||||
|
- Mark accounts as bot, and hide bot posts/comments
|
||||||
|
- Adding a short site description, to be used for joinlemmy instance list
|
||||||
|
- Adding matrix id validation. Fixes [#1520](https://github.com/LemmyNet/lemmy/issues/1520)
|
||||||
|
- Adding users active monthly for community sort. Fixes [#1527](https://github.com/LemmyNet/lemmy/issues/1527)
|
||||||
|
- Don't allow zero-space char in display name. Fixes [#1317](https://github.com/LemmyNet/lemmy/issues/1317)
|
||||||
|
- Adding more rust captcha features. Fixes [#1248](https://github.com/LemmyNet/lemmy/issues/1248)
|
||||||
|
- Fixing slur filter regex. Fixes [#1593](https://github.com/LemmyNet/lemmy/issues/1593)
|
||||||
|
|
||||||
|
#### API
|
||||||
|
|
||||||
|
- Added `ChangePassword` as a separate endpoint from `SaveUserSettings`
|
||||||
|
- No other breaking changes, but many fields that were previously required are now optional.
|
||||||
|
- A full list of the API changes can be seen on this diff of [lemmy-js-client: 0.10.0 -> 0.11.0](https://github.com/LemmyNet/lemmy-js-client/compare/0.10.0...0.11.0-rc.13) .
|
||||||
|
|
||||||
|
#### Federation
|
||||||
|
|
||||||
|
- Implement federated bans fixes [#1298](https://github.com/LemmyNet/lemmy/issues/1298)
|
||||||
|
- Remote mods can update/delete/undelete communities.
|
||||||
|
|
||||||
|
### Lemmy UI
|
||||||
|
|
||||||
|
- Updating translations.
|
||||||
|
- Add UI version to UI via docker. Fixes [#263](https://github.com/LemmyNet/lemmy-ui/issues/263)
|
||||||
|
- Add Korean language
|
||||||
|
- Add check for unused languages in update_translations.sh
|
||||||
|
- Validate matrix id on the front end. Fixes [#245](https://github.com/LemmyNet/lemmy-ui/issues/245)
|
||||||
|
- Communities page sorts by monthly active users. Fixes [#244](https://github.com/LemmyNet/lemmy-ui/issues/244)
|
||||||
|
- Correctly render HTML in popup notifications
|
||||||
|
- Fix html notif bug. Fixes [#254](https://github.com/LemmyNet/lemmy-ui/issues/254)
|
||||||
|
- Fixing issue with debounce. Fixes [#236](https://github.com/LemmyNet/lemmy-ui/issues/236)
|
||||||
|
|
||||||
|
|
||||||
|
## Upgrade notes
|
||||||
|
|
||||||
|
### Servers
|
||||||
|
|
||||||
|
If you'd like to make a DB backup before upgrading, follow [this guide](https://join.lemmy.ml/docs/en/administration/backup_and_restore.html).
|
||||||
|
|
||||||
|
To upgrade your instance to `v0.10.0`, simply follow the instructions in the documentation:
|
||||||
|
|
||||||
|
- [Upgrade with manual Docker installation](https://join.lemmy.ml/docs/en/administration/install_docker.html#updating)
|
||||||
|
- [Upgrade with Ansible installation](https://join.lemmy.ml/docs/en/administration/install_ansible.html)
|
||||||
|
|
||||||
|
### Clients / Apps
|
||||||
|
|
||||||
|
- A full list of the API changes can be seen on this diff of [lemmy-js-client: 0.10.0 -> 0.11.0](https://github.com/LemmyNet/lemmy-js-client/compare/0.10.0...0.11.0-rc.13) .
|
||||||
|
|
||||||
# Lemmy v0.10.3 Release (2021-04-07)
|
# Lemmy v0.10.3 Release (2021-04-07)
|
||||||
|
|
||||||
- Fixing instances page.
|
- Fixing instances page.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.10.3
|
0.11.0
|
||||||
|
|
|
@ -7,7 +7,7 @@ services:
|
||||||
- "127.0.0.1:8536:8536"
|
- "127.0.0.1:8536:8536"
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- RUST_LOG=error
|
- RUST_LOG="warn,lemmy_server=info,lemmy_api=info,lemmy_api_common=info,lemmy_api_crud=info,lemmy_apub=info,lemmy_apub_receive=info,lemmy_db_queries=info,lemmy_db_schema=info,lemmy_db_views=info,lemmy_db_views_actor=info,lemmy_db_views_moderator=info,lemmy_routes=info,lemmy_utils=info,lemmy_websocket=info"
|
||||||
volumes:
|
volumes:
|
||||||
- ./lemmy.hjson:/config/config.hjson:ro
|
- ./lemmy.hjson:/config/config.hjson:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
@ -65,11 +65,13 @@
|
||||||
# Allows and blocks are described here:
|
# Allows and blocks are described here:
|
||||||
# https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist
|
# https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist
|
||||||
#
|
#
|
||||||
# comma separated list of instances with which federation is allowed
|
# list of instances with which federation is allowed
|
||||||
# Only one of these blocks should be uncommented
|
|
||||||
# allowed_instances: ["instance1.tld","instance2.tld"]
|
# allowed_instances: ["instance1.tld","instance2.tld"]
|
||||||
# comma separated list of instances which are blocked from federating
|
# instances which we never federate anything with (but previously federated objects are unaffected)
|
||||||
# blocked_instances: []
|
# blocked_instances: []
|
||||||
|
# If true, only federate with instances on the allowlist and block everything else. If false,
|
||||||
|
# use allowlist only for remote communities, and posts/comments in local communities.
|
||||||
|
# strict_allowlist: true
|
||||||
}
|
}
|
||||||
captcha: {
|
captcha: {
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
@ -171,7 +171,7 @@ impl Perform for BanFromCommunity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove/Restore their data if that's desired
|
// Remove/Restore their data if that's desired
|
||||||
if data.remove_data {
|
if data.remove_data.unwrap_or(false) {
|
||||||
// Posts
|
// Posts
|
||||||
blocking(context.pool(), move |conn: &'_ _| {
|
blocking(context.pool(), move |conn: &'_ _| {
|
||||||
Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)
|
Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)
|
||||||
|
|
|
@ -16,6 +16,7 @@ use lemmy_api_common::{
|
||||||
use lemmy_db_queries::{
|
use lemmy_db_queries::{
|
||||||
diesel_option_overwrite,
|
diesel_option_overwrite,
|
||||||
diesel_option_overwrite_to_url,
|
diesel_option_overwrite_to_url,
|
||||||
|
from_opt_str_to_opt_enum,
|
||||||
source::{
|
source::{
|
||||||
comment::Comment_,
|
comment::Comment_,
|
||||||
local_user::LocalUser_,
|
local_user::LocalUser_,
|
||||||
|
@ -68,7 +69,6 @@ use lemmy_websocket::{
|
||||||
LemmyContext,
|
LemmyContext,
|
||||||
UserOperation,
|
UserOperation,
|
||||||
};
|
};
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for Login {
|
impl Perform for Login {
|
||||||
|
@ -169,6 +169,7 @@ impl Perform for SaveUserSettings {
|
||||||
let bio = diesel_option_overwrite(&data.bio);
|
let bio = diesel_option_overwrite(&data.bio);
|
||||||
let display_name = diesel_option_overwrite(&data.display_name);
|
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);
|
||||||
|
let bot_account = data.bot_account;
|
||||||
|
|
||||||
if let Some(Some(bio)) = &bio {
|
if let Some(Some(bio)) = &bio {
|
||||||
if bio.chars().count() > 300 {
|
if bio.chars().count() > 300 {
|
||||||
|
@ -213,6 +214,7 @@ impl Perform for SaveUserSettings {
|
||||||
last_refreshed_at: None,
|
last_refreshed_at: None,
|
||||||
shared_inbox_url: None,
|
shared_inbox_url: None,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
|
bot_account,
|
||||||
};
|
};
|
||||||
|
|
||||||
let person_res = blocking(context.pool(), move |conn| {
|
let person_res = blocking(context.pool(), move |conn| {
|
||||||
|
@ -231,12 +233,14 @@ impl Perform for SaveUserSettings {
|
||||||
email,
|
email,
|
||||||
password_encrypted,
|
password_encrypted,
|
||||||
show_nsfw: data.show_nsfw,
|
show_nsfw: data.show_nsfw,
|
||||||
|
show_bot_accounts: data.show_bot_accounts,
|
||||||
show_scores: data.show_scores,
|
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,
|
||||||
interface_language: data.interface_language.to_owned(),
|
interface_language: data.interface_language.to_owned(),
|
||||||
show_avatars: data.show_avatars,
|
show_avatars: data.show_avatars,
|
||||||
|
show_read_posts: data.show_read_posts,
|
||||||
send_notifications_to_email: data.send_notifications_to_email,
|
send_notifications_to_email: data.send_notifications_to_email,
|
||||||
discussion_languages: data.discussion_languages.to_owned(),
|
discussion_languages: data.discussion_languages.to_owned(),
|
||||||
};
|
};
|
||||||
|
@ -395,7 +399,7 @@ impl Perform for BanPerson {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove their data if that's desired
|
// Remove their data if that's desired
|
||||||
if data.remove_data {
|
if data.remove_data.unwrap_or(false) {
|
||||||
// Posts
|
// Posts
|
||||||
blocking(context.pool(), move |conn: &'_ _| {
|
blocking(context.pool(), move |conn: &'_ _| {
|
||||||
Post::update_removed_for_creator(conn, banned_person_id, None, true)
|
Post::update_removed_for_creator(conn, banned_person_id, None, true)
|
||||||
|
@ -460,17 +464,20 @@ impl Perform for GetReplies {
|
||||||
let data: &GetReplies = &self;
|
let data: &GetReplies = &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 sort = SortType::from_str(&data.sort)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
|
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
let unread_only = data.unread_only;
|
let unread_only = data.unread_only;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
let show_bot_accounts = local_user_view.local_user.show_bot_accounts;
|
||||||
|
|
||||||
let replies = blocking(context.pool(), move |conn| {
|
let replies = blocking(context.pool(), move |conn| {
|
||||||
CommentQueryBuilder::create(conn)
|
CommentQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.unread_only(unread_only)
|
.unread_only(unread_only)
|
||||||
.recipient_id(person_id)
|
.recipient_id(person_id)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
@ -494,7 +501,7 @@ impl Perform for GetPersonMentions {
|
||||||
let data: &GetPersonMentions = &self;
|
let data: &GetPersonMentions = &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 sort = SortType::from_str(&data.sort)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
|
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
|
@ -504,7 +511,7 @@ impl Perform for GetPersonMentions {
|
||||||
PersonMentionQueryBuilder::create(conn)
|
PersonMentionQueryBuilder::create(conn)
|
||||||
.recipient_id(person_id)
|
.recipient_id(person_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.unread_only(unread_only)
|
.unread_only(unread_only)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
|
|
@ -6,6 +6,7 @@ use lemmy_api_common::{
|
||||||
check_downvotes_enabled,
|
check_downvotes_enabled,
|
||||||
get_local_user_view_from_jwt,
|
get_local_user_view_from_jwt,
|
||||||
is_mod_or_admin,
|
is_mod_or_admin,
|
||||||
|
mark_post_as_read,
|
||||||
post::*,
|
post::*,
|
||||||
};
|
};
|
||||||
use lemmy_apub::{ApubLikeableType, ApubObjectType};
|
use lemmy_apub::{ApubLikeableType, ApubObjectType};
|
||||||
|
@ -69,6 +70,9 @@ impl Perform for CreatePostLike {
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the post as read
|
||||||
|
mark_post_as_read(person_id, post_id, context.pool()).await?;
|
||||||
|
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
let post_view = blocking(context.pool(), move |conn| {
|
let post_view = blocking(context.pool(), move |conn| {
|
||||||
|
@ -269,6 +273,9 @@ impl Perform for SavePost {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
// Mark the post as read
|
||||||
|
mark_post_as_read(person_id, post_id, context.pool()).await?;
|
||||||
|
|
||||||
Ok(PostResponse { post_view })
|
Ok(PostResponse { post_view })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,14 @@ use lemmy_api_common::{
|
||||||
site::*,
|
site::*,
|
||||||
};
|
};
|
||||||
use lemmy_apub::fetcher::search::search_by_apub_id;
|
use lemmy_apub::fetcher::search::search_by_apub_id;
|
||||||
use lemmy_db_queries::{source::site::Site_, Crud, SearchType, SortType};
|
use lemmy_db_queries::{
|
||||||
|
from_opt_str_to_opt_enum,
|
||||||
|
source::site::Site_,
|
||||||
|
Crud,
|
||||||
|
ListingType,
|
||||||
|
SearchType,
|
||||||
|
SortType,
|
||||||
|
};
|
||||||
use lemmy_db_schema::source::{moderator::*, site::Site};
|
use lemmy_db_schema::source::{moderator::*, site::Site};
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
comment_view::CommentQueryBuilder,
|
comment_view::CommentQueryBuilder,
|
||||||
|
@ -43,7 +50,6 @@ use lemmy_utils::{
|
||||||
};
|
};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for GetModlog {
|
impl Perform for GetModlog {
|
||||||
|
@ -136,9 +142,16 @@ impl Perform for Search {
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
||||||
let person_id = local_user_view.map(|u| u.person.id);
|
|
||||||
|
|
||||||
let type_ = SearchType::from_str(&data.type_)?;
|
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
|
||||||
|
let show_bot_accounts = local_user_view
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.local_user.show_bot_accounts);
|
||||||
|
let show_read_posts = local_user_view
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.local_user.show_read_posts);
|
||||||
|
|
||||||
|
let person_id = local_user_view.map(|u| u.person.id);
|
||||||
|
|
||||||
let mut posts = Vec::new();
|
let mut posts = Vec::new();
|
||||||
let mut comments = Vec::new();
|
let mut comments = Vec::new();
|
||||||
|
@ -150,17 +163,24 @@ impl Perform for Search {
|
||||||
let q = data.q.to_owned();
|
let q = data.q.to_owned();
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
|
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.listing_type);
|
||||||
|
let search_type: SearchType = from_opt_str_to_opt_enum(&data.type_).unwrap_or(SearchType::All);
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let community_name = data.community_name.to_owned();
|
let community_name = data.community_name.to_owned();
|
||||||
match type_ {
|
let creator_id = data.creator_id;
|
||||||
|
match search_type {
|
||||||
SearchType::Posts => {
|
SearchType::Posts => {
|
||||||
posts = blocking(context.pool(), move |conn| {
|
posts = blocking(context.pool(), move |conn| {
|
||||||
PostQueryBuilder::create(conn)
|
PostQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.show_nsfw(true)
|
.show_nsfw(show_nsfw)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.show_read_posts(show_read_posts)
|
||||||
|
.listing_type(listing_type)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.community_name(community_name)
|
.community_name(community_name)
|
||||||
|
.creator_id(creator_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.search_term(q)
|
.search_term(q)
|
||||||
.page(page)
|
.page(page)
|
||||||
|
@ -172,8 +192,13 @@ impl Perform for Search {
|
||||||
SearchType::Comments => {
|
SearchType::Comments => {
|
||||||
comments = blocking(context.pool(), move |conn| {
|
comments = blocking(context.pool(), move |conn| {
|
||||||
CommentQueryBuilder::create(&conn)
|
CommentQueryBuilder::create(&conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
|
.listing_type(listing_type)
|
||||||
.search_term(q)
|
.search_term(q)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.community_id(community_id)
|
||||||
|
.community_name(community_name)
|
||||||
|
.creator_id(creator_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
@ -184,7 +209,8 @@ impl Perform for Search {
|
||||||
SearchType::Communities => {
|
SearchType::Communities => {
|
||||||
communities = blocking(context.pool(), move |conn| {
|
communities = blocking(context.pool(), move |conn| {
|
||||||
CommunityQueryBuilder::create(conn)
|
CommunityQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
|
.listing_type(listing_type)
|
||||||
.search_term(q)
|
.search_term(q)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.page(page)
|
.page(page)
|
||||||
|
@ -196,7 +222,7 @@ impl Perform for Search {
|
||||||
SearchType::Users => {
|
SearchType::Users => {
|
||||||
users = blocking(context.pool(), move |conn| {
|
users = blocking(context.pool(), move |conn| {
|
||||||
PersonQueryBuilder::create(conn)
|
PersonQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.search_term(q)
|
.search_term(q)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
@ -205,12 +231,20 @@ impl Perform for Search {
|
||||||
.await??;
|
.await??;
|
||||||
}
|
}
|
||||||
SearchType::All => {
|
SearchType::All => {
|
||||||
|
// If the community or creator is included, dont search communities or users
|
||||||
|
let community_or_creator_included =
|
||||||
|
data.community_id.is_some() || data.community_name.is_some() || data.creator_id.is_some();
|
||||||
|
|
||||||
posts = blocking(context.pool(), move |conn| {
|
posts = blocking(context.pool(), move |conn| {
|
||||||
PostQueryBuilder::create(conn)
|
PostQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.show_nsfw(true)
|
.show_nsfw(show_nsfw)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.show_read_posts(show_read_posts)
|
||||||
|
.listing_type(listing_type)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.community_name(community_name)
|
.community_name(community_name)
|
||||||
|
.creator_id(creator_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.search_term(q)
|
.search_term(q)
|
||||||
.page(page)
|
.page(page)
|
||||||
|
@ -220,12 +254,17 @@ impl Perform for Search {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let q = data.q.to_owned();
|
let q = data.q.to_owned();
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let community_name = data.community_name.to_owned();
|
||||||
|
|
||||||
comments = blocking(context.pool(), move |conn| {
|
comments = blocking(context.pool(), move |conn| {
|
||||||
CommentQueryBuilder::create(conn)
|
CommentQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
|
.listing_type(listing_type)
|
||||||
.search_term(q)
|
.search_term(q)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.community_id(community_id)
|
||||||
|
.community_name(community_name)
|
||||||
|
.creator_id(creator_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
@ -234,40 +273,51 @@ impl Perform for Search {
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let q = data.q.to_owned();
|
let q = data.q.to_owned();
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
|
||||||
|
|
||||||
communities = blocking(context.pool(), move |conn| {
|
communities = if community_or_creator_included {
|
||||||
CommunityQueryBuilder::create(conn)
|
vec![]
|
||||||
.sort(&sort)
|
} else {
|
||||||
.search_term(q)
|
blocking(context.pool(), move |conn| {
|
||||||
.my_person_id(person_id)
|
CommunityQueryBuilder::create(conn)
|
||||||
.page(page)
|
.sort(sort)
|
||||||
.limit(limit)
|
.listing_type(listing_type)
|
||||||
.list()
|
.search_term(q)
|
||||||
})
|
.my_person_id(person_id)
|
||||||
.await??;
|
.page(page)
|
||||||
|
.limit(limit)
|
||||||
|
.list()
|
||||||
|
})
|
||||||
|
.await??
|
||||||
|
};
|
||||||
|
|
||||||
let q = data.q.to_owned();
|
let q = data.q.to_owned();
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
|
||||||
|
|
||||||
users = blocking(context.pool(), move |conn| {
|
users = if community_or_creator_included {
|
||||||
PersonQueryBuilder::create(conn)
|
vec![]
|
||||||
.sort(&sort)
|
} else {
|
||||||
.search_term(q)
|
blocking(context.pool(), move |conn| {
|
||||||
.page(page)
|
PersonQueryBuilder::create(conn)
|
||||||
.limit(limit)
|
.sort(sort)
|
||||||
.list()
|
.search_term(q)
|
||||||
})
|
.page(page)
|
||||||
.await??;
|
.limit(limit)
|
||||||
|
.list()
|
||||||
|
})
|
||||||
|
.await??
|
||||||
|
};
|
||||||
}
|
}
|
||||||
SearchType::Url => {
|
SearchType::Url => {
|
||||||
posts = blocking(context.pool(), move |conn| {
|
posts = blocking(context.pool(), move |conn| {
|
||||||
PostQueryBuilder::create(conn)
|
PostQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.show_nsfw(true)
|
.show_nsfw(show_nsfw)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.show_read_posts(show_read_posts)
|
||||||
|
.listing_type(listing_type)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.community_name(community_name)
|
.community_name(community_name)
|
||||||
|
.creator_id(creator_id)
|
||||||
.url_search(q)
|
.url_search(q)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
@ -279,7 +329,7 @@ impl Perform for Search {
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
Ok(SearchResponse {
|
Ok(SearchResponse {
|
||||||
type_: data.type_.to_owned(),
|
type_: search_type.to_string(),
|
||||||
comments,
|
comments,
|
||||||
posts,
|
posts,
|
||||||
communities,
|
communities,
|
||||||
|
|
|
@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct CreateComment {
|
pub struct CreateComment {
|
||||||
pub content: String,
|
pub content: String,
|
||||||
pub parent_id: Option<CommentId>,
|
|
||||||
pub post_id: PostId,
|
pub post_id: PostId,
|
||||||
|
pub parent_id: Option<CommentId>,
|
||||||
pub form_id: Option<String>,
|
pub form_id: Option<String>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
pub language: String,
|
pub language: String,
|
||||||
|
@ -66,13 +66,13 @@ pub struct CreateCommentLike {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct GetComments {
|
pub struct GetComments {
|
||||||
pub type_: String,
|
pub type_: Option<String>,
|
||||||
pub sort: String,
|
pub sort: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub community_id: Option<CommunityId>,
|
pub community_id: Option<CommunityId>,
|
||||||
pub community_name: Option<String>,
|
pub community_name: Option<String>,
|
||||||
pub saved_only: bool,
|
pub saved_only: Option<bool>,
|
||||||
pub auth: Option<String>,
|
pub auth: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ pub struct CommunityResponse {
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct ListCommunities {
|
pub struct ListCommunities {
|
||||||
pub type_: String,
|
pub type_: Option<String>,
|
||||||
pub sort: String,
|
pub sort: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub auth: Option<String>,
|
pub auth: Option<String>,
|
||||||
|
@ -56,7 +56,7 @@ pub struct BanFromCommunity {
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub ban: bool,
|
pub ban: bool,
|
||||||
pub remove_data: bool,
|
pub remove_data: Option<bool>,
|
||||||
pub reason: Option<String>,
|
pub reason: Option<String>,
|
||||||
pub expires: Option<i64>,
|
pub expires: Option<i64>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
@ -84,7 +84,7 @@ pub struct AddModToCommunityResponse {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EditCommunity {
|
pub struct EditCommunity {
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub title: String,
|
pub title: 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>,
|
||||||
|
|
|
@ -14,6 +14,7 @@ use lemmy_db_queries::{
|
||||||
},
|
},
|
||||||
Crud,
|
Crud,
|
||||||
DbPool,
|
DbPool,
|
||||||
|
Readable,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
@ -21,7 +22,7 @@ use lemmy_db_schema::{
|
||||||
community::{Community, CommunityModerator},
|
community::{Community, CommunityModerator},
|
||||||
person::Person,
|
person::Person,
|
||||||
person_mention::{PersonMention, PersonMentionForm},
|
person_mention::{PersonMention, PersonMentionForm},
|
||||||
post::Post,
|
post::{Post, PostRead, PostReadForm},
|
||||||
site::Site,
|
site::Site,
|
||||||
},
|
},
|
||||||
CommunityId,
|
CommunityId,
|
||||||
|
@ -242,6 +243,20 @@ pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError
|
||||||
.map_err(|_| ApiError::err("couldnt_find_post").into())
|
.map_err(|_| ApiError::err("couldnt_find_post").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn mark_post_as_read(
|
||||||
|
person_id: PersonId,
|
||||||
|
post_id: PostId,
|
||||||
|
pool: &DbPool,
|
||||||
|
) -> Result<PostRead, LemmyError> {
|
||||||
|
let post_read_form = PostReadForm { post_id, person_id };
|
||||||
|
|
||||||
|
blocking(pool, move |conn| {
|
||||||
|
PostRead::mark_as_read(conn, &post_read_form)
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
.map_err(|_| ApiError::err("couldnt_mark_post_as_read").into())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_local_user_view_from_jwt(
|
pub async fn get_local_user_view_from_jwt(
|
||||||
jwt: &str,
|
jwt: &str,
|
||||||
pool: &DbPool,
|
pool: &DbPool,
|
||||||
|
|
|
@ -27,10 +27,10 @@ pub struct Login {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Register {
|
pub struct Register {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub email: Option<String>,
|
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub password_verify: String,
|
pub password_verify: String,
|
||||||
pub show_nsfw: bool,
|
pub show_nsfw: bool,
|
||||||
|
pub email: Option<String>,
|
||||||
pub captcha_uuid: Option<String>,
|
pub captcha_uuid: Option<String>,
|
||||||
pub captcha_answer: Option<String>,
|
pub captcha_answer: Option<String>,
|
||||||
pub discussion_languages: Vec<PrimaryLanguageTag>,
|
pub discussion_languages: Vec<PrimaryLanguageTag>,
|
||||||
|
@ -67,6 +67,9 @@ pub struct SaveUserSettings {
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: 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 bot_account: Option<bool>,
|
||||||
|
pub show_bot_accounts: Option<bool>,
|
||||||
|
pub show_read_posts: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
pub discussion_languages: Option<Vec<PrimaryLanguageTag>>,
|
pub discussion_languages: Option<Vec<PrimaryLanguageTag>>,
|
||||||
}
|
}
|
||||||
|
@ -86,13 +89,13 @@ pub struct LoginResponse {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct GetPersonDetails {
|
pub struct GetPersonDetails {
|
||||||
pub person_id: Option<PersonId>,
|
pub person_id: Option<PersonId>, // One of these two are required
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
pub sort: String,
|
pub sort: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub community_id: Option<CommunityId>,
|
pub community_id: Option<CommunityId>,
|
||||||
pub saved_only: bool,
|
pub saved_only: Option<bool>,
|
||||||
pub auth: Option<String>,
|
pub auth: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +139,7 @@ pub struct AddAdminResponse {
|
||||||
pub struct BanPerson {
|
pub struct BanPerson {
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub ban: bool,
|
pub ban: bool,
|
||||||
pub remove_data: bool,
|
pub remove_data: Option<bool>,
|
||||||
pub reason: Option<String>,
|
pub reason: Option<String>,
|
||||||
pub expires: Option<i64>,
|
pub expires: Option<i64>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
@ -150,19 +153,19 @@ pub struct BanPersonResponse {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct GetReplies {
|
pub struct GetReplies {
|
||||||
pub sort: String,
|
pub sort: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub unread_only: bool,
|
pub unread_only: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct GetPersonMentions {
|
pub struct GetPersonMentions {
|
||||||
pub sort: String,
|
pub sort: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub unread_only: bool,
|
pub unread_only: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +232,7 @@ pub struct MarkPrivateMessageAsRead {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct GetPrivateMessages {
|
pub struct GetPrivateMessages {
|
||||||
pub unread_only: bool,
|
pub unread_only: Option<bool>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
|
|
|
@ -14,10 +14,10 @@ use url::Url;
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct CreatePost {
|
pub struct CreatePost {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub community_id: CommunityId,
|
||||||
pub url: Option<Url>,
|
pub url: Option<Url>,
|
||||||
pub body: Option<String>,
|
pub body: Option<String>,
|
||||||
pub nsfw: bool,
|
pub nsfw: Option<bool>,
|
||||||
pub community_id: CommunityId,
|
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
pub language: String,
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
@ -44,13 +44,13 @@ pub struct GetPostResponse {
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct GetPosts {
|
pub struct GetPosts {
|
||||||
pub type_: String,
|
pub type_: Option<String>,
|
||||||
pub sort: String,
|
pub sort: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub community_id: Option<CommunityId>,
|
pub community_id: Option<CommunityId>,
|
||||||
pub community_name: Option<String>,
|
pub community_name: Option<String>,
|
||||||
pub saved_only: bool,
|
pub saved_only: Option<bool>,
|
||||||
pub auth: Option<String>,
|
pub auth: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +69,10 @@ pub struct CreatePostLike {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EditPost {
|
pub struct EditPost {
|
||||||
pub post_id: PostId,
|
pub post_id: PostId,
|
||||||
pub name: String,
|
pub name: Option<String>,
|
||||||
pub url: Option<Url>,
|
pub url: Option<Url>,
|
||||||
pub body: Option<String>,
|
pub body: Option<String>,
|
||||||
pub nsfw: bool,
|
pub nsfw: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
pub language: String,
|
pub language: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,12 @@ use serde::{Deserialize, Serialize};
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Search {
|
pub struct Search {
|
||||||
pub q: String,
|
pub q: String,
|
||||||
pub type_: String,
|
|
||||||
pub community_id: Option<CommunityId>,
|
pub community_id: Option<CommunityId>,
|
||||||
pub community_name: Option<String>,
|
pub community_name: Option<String>,
|
||||||
pub sort: String,
|
pub creator_id: Option<PersonId>,
|
||||||
|
pub type_: Option<String>,
|
||||||
|
pub sort: Option<String>,
|
||||||
|
pub listing_type: Option<String>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub auth: Option<String>,
|
pub auth: Option<String>,
|
||||||
|
@ -68,22 +70,24 @@ pub struct CreateSite {
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
pub banner: Option<String>,
|
pub banner: Option<String>,
|
||||||
pub enable_downvotes: bool,
|
pub enable_downvotes: Option<bool>,
|
||||||
pub open_registration: bool,
|
pub open_registration: Option<bool>,
|
||||||
pub enable_nsfw: bool,
|
pub enable_nsfw: Option<bool>,
|
||||||
|
pub community_creation_admin_only: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EditSite {
|
pub struct EditSite {
|
||||||
pub name: String,
|
pub name: Option<String>,
|
||||||
pub sidebar: Option<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>,
|
||||||
pub enable_downvotes: bool,
|
pub enable_downvotes: Option<bool>,
|
||||||
pub open_registration: bool,
|
pub open_registration: Option<bool>,
|
||||||
pub enable_nsfw: bool,
|
pub enable_nsfw: Option<bool>,
|
||||||
|
pub community_creation_admin_only: Option<bool>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::PerformCrud;
|
use crate::PerformCrud;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt};
|
use lemmy_api_common::{blocking, comment::*, get_local_user_view_from_jwt_opt};
|
||||||
use lemmy_db_queries::{ListingType, SortType};
|
use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType};
|
||||||
use lemmy_db_views::comment_view::CommentQueryBuilder;
|
use lemmy_db_views::comment_view::CommentQueryBuilder;
|
||||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for GetComments {
|
impl PerformCrud for GetComments {
|
||||||
|
@ -18,10 +17,14 @@ impl PerformCrud for GetComments {
|
||||||
) -> Result<GetCommentsResponse, LemmyError> {
|
) -> Result<GetCommentsResponse, LemmyError> {
|
||||||
let data: &GetComments = &self;
|
let data: &GetComments = &self;
|
||||||
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let show_bot_accounts = local_user_view
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.local_user.show_bot_accounts);
|
||||||
let person_id = local_user_view.map(|u| u.person.id);
|
let person_id = local_user_view.map(|u| u.person.id);
|
||||||
|
|
||||||
let type_ = ListingType::from_str(&data.type_)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let community_name = data.community_name.to_owned();
|
let community_name = data.community_name.to_owned();
|
||||||
|
@ -30,12 +33,13 @@ impl PerformCrud for GetComments {
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
let comments = blocking(context.pool(), move |conn| {
|
let comments = blocking(context.pool(), move |conn| {
|
||||||
CommentQueryBuilder::create(conn)
|
CommentQueryBuilder::create(conn)
|
||||||
.listing_type(type_)
|
.listing_type(listing_type)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.saved_only(saved_only)
|
.saved_only(saved_only)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.community_name(community_name)
|
.community_name(community_name)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
.page(page)
|
.page(page)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.list()
|
.list()
|
||||||
|
|
|
@ -4,6 +4,7 @@ use lemmy_api_common::{
|
||||||
blocking,
|
blocking,
|
||||||
community::{CommunityResponse, CreateCommunity},
|
community::{CommunityResponse, CreateCommunity},
|
||||||
get_local_user_view_from_jwt,
|
get_local_user_view_from_jwt,
|
||||||
|
is_admin,
|
||||||
};
|
};
|
||||||
use lemmy_apub::{
|
use lemmy_apub::{
|
||||||
generate_apub_endpoint,
|
generate_apub_endpoint,
|
||||||
|
@ -13,13 +14,16 @@ use lemmy_apub::{
|
||||||
EndpointType,
|
EndpointType,
|
||||||
};
|
};
|
||||||
use lemmy_db_queries::{diesel_option_overwrite_to_url, ApubObject, Crud, Followable, Joinable};
|
use lemmy_db_queries::{diesel_option_overwrite_to_url, ApubObject, Crud, Followable, Joinable};
|
||||||
use lemmy_db_schema::source::community::{
|
use lemmy_db_schema::source::{
|
||||||
Community,
|
community::{
|
||||||
CommunityFollower,
|
Community,
|
||||||
CommunityFollowerForm,
|
CommunityFollower,
|
||||||
CommunityForm,
|
CommunityFollowerForm,
|
||||||
CommunityModerator,
|
CommunityForm,
|
||||||
CommunityModeratorForm,
|
CommunityModerator,
|
||||||
|
CommunityModeratorForm,
|
||||||
|
},
|
||||||
|
site::Site,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::community_view::CommunityView;
|
use lemmy_db_views_actor::community_view::CommunityView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -43,6 +47,11 @@ impl PerformCrud for CreateCommunity {
|
||||||
let data: &CreateCommunity = &self;
|
let data: &CreateCommunity = &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 site = blocking(context.pool(), move |conn| Site::read(conn, 0)).await??;
|
||||||
|
if site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
|
||||||
|
return Err(ApiError::err("only_admins_can_create_communities").into());
|
||||||
|
}
|
||||||
|
|
||||||
check_slurs(&data.name)?;
|
check_slurs(&data.name)?;
|
||||||
check_slurs(&data.title)?;
|
check_slurs(&data.title)?;
|
||||||
check_slurs_opt(&data.description)?;
|
check_slurs_opt(&data.description)?;
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
use crate::PerformCrud;
|
use crate::PerformCrud;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt_opt};
|
use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt_opt};
|
||||||
use lemmy_db_queries::{source::community::Community_, ListingType, SortType};
|
use lemmy_db_queries::{
|
||||||
|
from_opt_str_to_opt_enum,
|
||||||
|
source::community::Community_,
|
||||||
|
ListingType,
|
||||||
|
SortType,
|
||||||
|
};
|
||||||
use lemmy_db_schema::source::community::*;
|
use lemmy_db_schema::source::community::*;
|
||||||
use lemmy_db_views_actor::{
|
use lemmy_db_views_actor::{
|
||||||
community_moderator_view::CommunityModeratorView,
|
community_moderator_view::CommunityModeratorView,
|
||||||
|
@ -9,7 +14,6 @@ use lemmy_db_views_actor::{
|
||||||
};
|
};
|
||||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext};
|
use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext};
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for GetCommunity {
|
impl PerformCrud for GetCommunity {
|
||||||
|
@ -86,15 +90,15 @@ impl PerformCrud for ListCommunities {
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_ = ListingType::from_str(&data.type_)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
|
||||||
|
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
let communities = blocking(context.pool(), move |conn| {
|
let communities = blocking(context.pool(), move |conn| {
|
||||||
CommunityQueryBuilder::create(conn)
|
CommunityQueryBuilder::create(conn)
|
||||||
.listing_type(&type_)
|
.listing_type(listing_type)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.show_nsfw(show_nsfw)
|
.show_nsfw(show_nsfw)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.page(page)
|
.page(page)
|
||||||
|
|
|
@ -16,12 +16,7 @@ use lemmy_db_views_actor::{
|
||||||
community_moderator_view::CommunityModeratorView,
|
community_moderator_view::CommunityModeratorView,
|
||||||
community_view::CommunityView,
|
community_view::CommunityView,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError};
|
||||||
utils::{check_slurs, check_slurs_opt},
|
|
||||||
ApiError,
|
|
||||||
ConnectionId,
|
|
||||||
LemmyError,
|
|
||||||
};
|
|
||||||
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{LemmyContext, UserOperationCrud};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -36,7 +31,7 @@ impl PerformCrud for EditCommunity {
|
||||||
let data: &EditCommunity = &self;
|
let data: &EditCommunity = &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?;
|
||||||
|
|
||||||
check_slurs(&data.title)?;
|
check_slurs_opt(&data.title)?;
|
||||||
check_slurs_opt(&data.description)?;
|
check_slurs_opt(&data.description)?;
|
||||||
|
|
||||||
// Verify its a mod (only mods can edit it)
|
// Verify its a mod (only mods can edit it)
|
||||||
|
@ -61,7 +56,7 @@ 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().unwrap_or(read_community.title),
|
||||||
description: data.description.to_owned(),
|
description: data.description.to_owned(),
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
use crate::PerformCrud;
|
use crate::PerformCrud;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lemmy_api_common::{blocking, check_community_ban, get_local_user_view_from_jwt, post::*};
|
use lemmy_api_common::{
|
||||||
|
blocking,
|
||||||
|
check_community_ban,
|
||||||
|
get_local_user_view_from_jwt,
|
||||||
|
mark_post_as_read,
|
||||||
|
post::*,
|
||||||
|
};
|
||||||
use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType};
|
use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType};
|
||||||
use lemmy_db_queries::{source::post::Post_, Crud, Likeable};
|
use lemmy_db_queries::{source::post::Post_, Crud, Likeable};
|
||||||
use lemmy_db_schema::source::post::*;
|
use lemmy_db_schema::source::post::*;
|
||||||
|
@ -81,9 +87,11 @@ impl PerformCrud for CreatePost {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// They like their own post by default
|
// They like their own post by default
|
||||||
|
let person_id = local_user_view.person.id;
|
||||||
|
let post_id = inserted_post.id;
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm {
|
||||||
post_id: inserted_post.id,
|
post_id,
|
||||||
person_id: local_user_view.person.id,
|
person_id,
|
||||||
score: 1,
|
score: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +100,9 @@ impl PerformCrud for CreatePost {
|
||||||
return Err(ApiError::err("couldnt_like_post").into());
|
return Err(ApiError::err("couldnt_like_post").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the post as read
|
||||||
|
mark_post_as_read(person_id, post_id, context.pool()).await?;
|
||||||
|
|
||||||
updated_post
|
updated_post
|
||||||
.send_like(&local_user_view.person, context)
|
.send_like(&local_user_view.person, context)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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_opt, post::*};
|
use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, mark_post_as_read, post::*};
|
||||||
use lemmy_db_queries::{ListingType, SortType};
|
use lemmy_db_queries::{from_opt_str_to_opt_enum, ListingType, SortType};
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
comment_view::CommentQueryBuilder,
|
comment_view::CommentQueryBuilder,
|
||||||
post_view::{PostQueryBuilder, PostView},
|
post_view::{PostQueryBuilder, PostView},
|
||||||
|
@ -12,7 +12,6 @@ use lemmy_db_views_actor::{
|
||||||
};
|
};
|
||||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
|
use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for GetPost {
|
impl PerformCrud for GetPost {
|
||||||
|
@ -25,6 +24,10 @@ impl PerformCrud for GetPost {
|
||||||
) -> Result<GetPostResponse, LemmyError> {
|
) -> Result<GetPostResponse, LemmyError> {
|
||||||
let data: &GetPost = &self;
|
let data: &GetPost = &self;
|
||||||
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let show_bot_accounts = local_user_view
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.local_user.show_bot_accounts);
|
||||||
let person_id = local_user_view.map(|u| u.person.id);
|
let person_id = local_user_view.map(|u| u.person.id);
|
||||||
|
|
||||||
let id = data.id;
|
let id = data.id;
|
||||||
|
@ -34,10 +37,16 @@ impl PerformCrud for GetPost {
|
||||||
.await?
|
.await?
|
||||||
.map_err(|_| ApiError::err("couldnt_find_post"))?;
|
.map_err(|_| ApiError::err("couldnt_find_post"))?;
|
||||||
|
|
||||||
|
// Mark the post as read
|
||||||
|
if let Some(person_id) = person_id {
|
||||||
|
mark_post_as_read(person_id, id, context.pool()).await?;
|
||||||
|
}
|
||||||
|
|
||||||
let id = data.id;
|
let id = data.id;
|
||||||
let comments = blocking(context.pool(), move |conn| {
|
let comments = blocking(context.pool(), move |conn| {
|
||||||
CommentQueryBuilder::create(conn)
|
CommentQueryBuilder::create(conn)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
.post_id(id)
|
.post_id(id)
|
||||||
.limit(9999)
|
.limit(9999)
|
||||||
.list()
|
.list()
|
||||||
|
@ -88,13 +97,16 @@ impl PerformCrud for GetPosts {
|
||||||
|
|
||||||
let person_id = local_user_view.to_owned().map(|l| l.person.id);
|
let person_id = local_user_view.to_owned().map(|l| l.person.id);
|
||||||
|
|
||||||
let show_nsfw = match &local_user_view {
|
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
|
||||||
Some(uv) => uv.local_user.show_nsfw,
|
let show_bot_accounts = local_user_view
|
||||||
None => false,
|
.as_ref()
|
||||||
};
|
.map(|t| t.local_user.show_bot_accounts);
|
||||||
|
let show_read_posts = local_user_view
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.local_user.show_read_posts);
|
||||||
|
|
||||||
let type_ = ListingType::from_str(&data.type_)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let listing_type: Option<ListingType> = from_opt_str_to_opt_enum(&data.type_);
|
||||||
|
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
|
@ -107,9 +119,11 @@ impl PerformCrud for GetPosts {
|
||||||
|
|
||||||
let posts = blocking(context.pool(), move |conn| {
|
let posts = blocking(context.pool(), move |conn| {
|
||||||
PostQueryBuilder::create(conn)
|
PostQueryBuilder::create(conn)
|
||||||
.listing_type(&type_)
|
.listing_type(listing_type)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.show_nsfw(show_nsfw)
|
.show_nsfw(show_nsfw)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.show_read_posts(show_read_posts)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.community_name(community_name)
|
.community_name(community_name)
|
||||||
.saved_only(saved_only)
|
.saved_only(saved_only)
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_db_schema::{naive_now, source::post::*};
|
||||||
use lemmy_db_views::post_view::PostView;
|
use lemmy_db_views::post_view::PostView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
request::fetch_iframely_and_pictrs_data,
|
request::fetch_iframely_and_pictrs_data,
|
||||||
utils::{check_slurs, check_slurs_opt, is_valid_post_title},
|
utils::{check_slurs_opt, is_valid_post_title},
|
||||||
ApiError,
|
ApiError,
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
|
@ -26,11 +26,13 @@ impl PerformCrud for EditPost {
|
||||||
let data: &EditPost = &self;
|
let data: &EditPost = &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?;
|
||||||
|
|
||||||
check_slurs(&data.name)?;
|
check_slurs_opt(&data.name)?;
|
||||||
check_slurs_opt(&data.body)?;
|
check_slurs_opt(&data.body)?;
|
||||||
|
|
||||||
if !is_valid_post_title(&data.name) {
|
if let Some(name) = &data.name {
|
||||||
return Err(ApiError::err("invalid_post_title").into());
|
if !is_valid_post_title(name) {
|
||||||
|
return Err(ApiError::err("invalid_post_title").into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
|
@ -56,7 +58,7 @@ impl PerformCrud for EditPost {
|
||||||
let post_form = PostForm {
|
let post_form = PostForm {
|
||||||
creator_id: orig_post.creator_id.to_owned(),
|
creator_id: orig_post.creator_id.to_owned(),
|
||||||
community_id: orig_post.community_id,
|
community_id: orig_post.community_id,
|
||||||
name: data.name.trim().to_owned(),
|
name: data.name.to_owned().unwrap_or(orig_post.name),
|
||||||
url: data_url.map(|u| u.to_owned().into()),
|
url: data_url.map(|u| u.to_owned().into()),
|
||||||
body: data.body.to_owned(),
|
body: data.body.to_owned(),
|
||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
|
|
|
@ -67,6 +67,7 @@ impl PerformCrud for CreateSite {
|
||||||
open_registration: data.open_registration,
|
open_registration: data.open_registration,
|
||||||
enable_nsfw: data.enable_nsfw,
|
enable_nsfw: data.enable_nsfw,
|
||||||
updated: None,
|
updated: None,
|
||||||
|
community_creation_admin_only: data.community_creation_admin_only,
|
||||||
};
|
};
|
||||||
|
|
||||||
let create_site = move |conn: &'_ _| Site::create(conn, &site_form);
|
let create_site = move |conn: &'_ _| Site::create(conn, &site_form);
|
||||||
|
|
|
@ -48,10 +48,11 @@ impl PerformCrud for GetSite {
|
||||||
description: None,
|
description: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
enable_downvotes: true,
|
enable_downvotes: None,
|
||||||
open_registration: true,
|
open_registration: None,
|
||||||
enable_nsfw: true,
|
enable_nsfw: None,
|
||||||
auth: login_response.jwt,
|
auth: login_response.jwt,
|
||||||
|
community_creation_admin_only: None,
|
||||||
};
|
};
|
||||||
create_site.perform(context, websocket_id).await?;
|
create_site.perform(context, websocket_id).await?;
|
||||||
info!("Site {} created", setup.site_name);
|
info!("Site {} created", setup.site_name);
|
||||||
|
|
|
@ -18,12 +18,7 @@ use lemmy_db_schema::{
|
||||||
source::site::{Site, SiteForm},
|
source::site::{Site, SiteForm},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::site_view::SiteView;
|
use lemmy_db_views::site_view::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError};
|
||||||
utils::{check_slurs, check_slurs_opt},
|
|
||||||
ApiError,
|
|
||||||
ConnectionId,
|
|
||||||
LemmyError,
|
|
||||||
};
|
|
||||||
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud};
|
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -37,7 +32,7 @@ impl PerformCrud for EditSite {
|
||||||
let data: &EditSite = &self;
|
let data: &EditSite = &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?;
|
||||||
|
|
||||||
check_slurs(&data.name)?;
|
check_slurs_opt(&data.name)?;
|
||||||
check_slurs_opt(&data.description)?;
|
check_slurs_opt(&data.description)?;
|
||||||
|
|
||||||
// Make sure user is an admin
|
// Make sure user is an admin
|
||||||
|
@ -55,16 +50,17 @@ impl PerformCrud for EditSite {
|
||||||
}
|
}
|
||||||
|
|
||||||
let site_form = SiteForm {
|
let site_form = SiteForm {
|
||||||
name: data.name.to_owned(),
|
creator_id: found_site.creator_id,
|
||||||
|
name: data.name.to_owned().unwrap_or(found_site.name),
|
||||||
sidebar,
|
sidebar,
|
||||||
description,
|
description,
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
creator_id: found_site.creator_id,
|
|
||||||
updated: Some(naive_now()),
|
updated: Some(naive_now()),
|
||||||
enable_downvotes: data.enable_downvotes,
|
enable_downvotes: data.enable_downvotes,
|
||||||
open_registration: data.open_registration,
|
open_registration: data.open_registration,
|
||||||
enable_nsfw: data.enable_nsfw,
|
enable_nsfw: data.enable_nsfw,
|
||||||
|
community_creation_admin_only: data.community_creation_admin_only,
|
||||||
};
|
};
|
||||||
|
|
||||||
let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form);
|
let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form);
|
||||||
|
|
|
@ -123,12 +123,14 @@ impl PerformCrud for Register {
|
||||||
email: Some(data.email.to_owned()),
|
email: Some(data.email.to_owned()),
|
||||||
password_encrypted: data.password.to_owned(),
|
password_encrypted: data.password.to_owned(),
|
||||||
show_nsfw: Some(data.show_nsfw),
|
show_nsfw: Some(data.show_nsfw),
|
||||||
|
show_bot_accounts: Some(true),
|
||||||
theme: Some("browser".into()),
|
theme: Some("browser".into()),
|
||||||
default_sort_type: Some(SortType::Active as i16),
|
default_sort_type: Some(SortType::Active as i16),
|
||||||
default_listing_type: Some(ListingType::Subscribed as i16),
|
default_listing_type: Some(ListingType::Subscribed as i16),
|
||||||
interface_language: Some("browser".into()),
|
interface_language: Some("browser".into()),
|
||||||
show_avatars: Some(true),
|
show_avatars: Some(true),
|
||||||
show_scores: Some(true),
|
show_scores: Some(true),
|
||||||
|
show_read_posts: Some(true),
|
||||||
send_notifications_to_email: Some(false),
|
send_notifications_to_email: Some(false),
|
||||||
discussion_languages: Some(data.discussion_languages.to_owned()),
|
discussion_languages: Some(data.discussion_languages.to_owned()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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_opt, person::*};
|
use lemmy_api_common::{blocking, get_local_user_view_from_jwt_opt, person::*};
|
||||||
use lemmy_db_queries::{source::person::Person_, SortType};
|
use lemmy_db_queries::{from_opt_str_to_opt_enum, source::person::Person_, SortType};
|
||||||
use lemmy_db_schema::source::person::*;
|
use lemmy_db_schema::source::person::*;
|
||||||
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
|
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
|
||||||
use lemmy_db_views_actor::{
|
use lemmy_db_views_actor::{
|
||||||
|
@ -11,7 +11,6 @@ use lemmy_db_views_actor::{
|
||||||
};
|
};
|
||||||
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for GetPersonDetails {
|
impl PerformCrud for GetPersonDetails {
|
||||||
|
@ -25,12 +24,15 @@ impl PerformCrud for GetPersonDetails {
|
||||||
let data: &GetPersonDetails = &self;
|
let data: &GetPersonDetails = &self;
|
||||||
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
let show_nsfw = match &local_user_view {
|
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
|
||||||
Some(uv) => uv.local_user.show_nsfw,
|
let show_bot_accounts = local_user_view
|
||||||
None => false,
|
.as_ref()
|
||||||
};
|
.map(|t| t.local_user.show_bot_accounts);
|
||||||
|
let show_read_posts = local_user_view
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t.local_user.show_read_posts);
|
||||||
|
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
|
||||||
|
|
||||||
let username = data
|
let username = data
|
||||||
.username
|
.username
|
||||||
|
@ -65,8 +67,10 @@ impl PerformCrud for GetPersonDetails {
|
||||||
|
|
||||||
let (posts, comments) = blocking(context.pool(), move |conn| {
|
let (posts, comments) = blocking(context.pool(), move |conn| {
|
||||||
let mut posts_query = PostQueryBuilder::create(conn)
|
let mut posts_query = PostQueryBuilder::create(conn)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.show_nsfw(show_nsfw)
|
.show_nsfw(show_nsfw)
|
||||||
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.show_read_posts(show_read_posts)
|
||||||
.saved_only(saved_only)
|
.saved_only(saved_only)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
|
@ -75,7 +79,8 @@ impl PerformCrud for GetPersonDetails {
|
||||||
|
|
||||||
let mut comments_query = CommentQueryBuilder::create(conn)
|
let mut comments_query = CommentQueryBuilder::create(conn)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.sort(&sort)
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.sort(sort)
|
||||||
.saved_only(saved_only)
|
.saved_only(saved_only)
|
||||||
.community_id(community_id)
|
.community_id(community_id)
|
||||||
.page(page)
|
.page(page)
|
||||||
|
@ -83,7 +88,7 @@ impl PerformCrud for GetPersonDetails {
|
||||||
|
|
||||||
// If its saved only, you don't care what creator it was
|
// If its saved only, you don't care what creator it was
|
||||||
// Or, if its not saved, then you only want it for that specific creator
|
// Or, if its not saved, then you only want it for that specific creator
|
||||||
if !saved_only {
|
if !saved_only.unwrap_or(false) {
|
||||||
posts_query = posts_query.creator_id(person_details_id);
|
posts_query = posts_query.creator_id(person_details_id);
|
||||||
comments_query = comments_query.creator_id(person_details_id);
|
comments_query = comments_query.creator_id(person_details_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,7 +290,7 @@ impl CommunityType for Community {
|
||||||
.map(|i| i.into_inner())
|
.map(|i| i.into_inner())
|
||||||
.unique()
|
.unique()
|
||||||
// Don't send to blocked instances
|
// Don't send to blocked instances
|
||||||
.filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
|
.filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(inboxes)
|
Ok(inboxes)
|
||||||
|
|
|
@ -46,7 +46,7 @@ where
|
||||||
Kind: Serialize,
|
Kind: Serialize,
|
||||||
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
|
<T as Extends<Kind>>::Error: From<serde_json::Error> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
if check_is_apub_id_valid(&inbox).is_ok() {
|
if check_is_apub_id_valid(&inbox, false).is_ok() {
|
||||||
debug!(
|
debug!(
|
||||||
"Sending activity {:?} to {}",
|
"Sending activity {:?} to {}",
|
||||||
&activity.id_unchecked(),
|
&activity.id_unchecked(),
|
||||||
|
@ -83,7 +83,7 @@ where
|
||||||
.flatten()
|
.flatten()
|
||||||
.unique()
|
.unique()
|
||||||
.filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname()))
|
.filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname()))
|
||||||
.filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
|
.filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
|
||||||
.map(|inbox| inbox.to_owned())
|
.map(|inbox| inbox.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -124,7 +124,7 @@ where
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
let inbox = community.get_shared_inbox_or_inbox_url();
|
let inbox = community.get_shared_inbox_or_inbox_url();
|
||||||
check_is_apub_id_valid(&inbox)?;
|
check_is_apub_id_valid(&inbox, false)?;
|
||||||
debug!(
|
debug!(
|
||||||
"Sending activity {:?} to community {}",
|
"Sending activity {:?} to community {}",
|
||||||
&activity.id_unchecked(),
|
&activity.id_unchecked(),
|
||||||
|
@ -160,7 +160,7 @@ where
|
||||||
);
|
);
|
||||||
let mentions = mentions
|
let mentions = mentions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
|
.filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
|
||||||
.map(|i| i.to_owned())
|
.map(|i| i.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
send_activity_internal(
|
send_activity_internal(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{check_is_apub_id_valid, APUB_JSON_CONTENT_TYPE};
|
use crate::{check_is_apub_id_valid, APUB_JSON_CONTENT_TYPE};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use lemmy_utils::{request::retry, LemmyError};
|
use lemmy_utils::{request::retry, LemmyError};
|
||||||
|
use log::info;
|
||||||
use reqwest::{Client, StatusCode};
|
use reqwest::{Client, StatusCode};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -59,7 +60,7 @@ where
|
||||||
if *recursion_counter > MAX_REQUEST_NUMBER {
|
if *recursion_counter > MAX_REQUEST_NUMBER {
|
||||||
return Err(LemmyError::from(anyhow!("Maximum recursion depth reached")).into());
|
return Err(LemmyError::from(anyhow!("Maximum recursion depth reached")).into());
|
||||||
}
|
}
|
||||||
check_is_apub_id_valid(&url)?;
|
check_is_apub_id_valid(&url, false)?;
|
||||||
|
|
||||||
let timeout = Duration::from_secs(60);
|
let timeout = Duration::from_secs(60);
|
||||||
|
|
||||||
|
@ -73,11 +74,14 @@ where
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if res.status() == StatusCode::GONE {
|
if res.status() == StatusCode::GONE {
|
||||||
|
info!("Fetched remote object {} which was deleted", url);
|
||||||
return Err(FetchError {
|
return Err(FetchError {
|
||||||
inner: anyhow!("Remote object {} was deleted", url),
|
inner: anyhow!("Fetched remote object {} which was deleted", url),
|
||||||
status_code: Some(res.status()),
|
status_code: Some(res.status()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res.json().await?)
|
let object = res.json().await?;
|
||||||
|
info!("Fetched remote object {}", url);
|
||||||
|
Ok(object)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,18 @@ use url::{ParseError, Url};
|
||||||
pub type GroupExt =
|
pub type GroupExt =
|
||||||
Ext2<actor::ApActor<ApObject<actor::Group>>, GroupExtension, PublicKeyExtension>;
|
Ext2<actor::ApActor<ApObject<actor::Group>>, GroupExtension, PublicKeyExtension>;
|
||||||
/// Activitystreams type for person
|
/// Activitystreams type for person
|
||||||
type PersonExt = Ext2<actor::ApActor<ApObject<actor::Person>>, PersonExtension, PublicKeyExtension>;
|
type PersonExt =
|
||||||
|
Ext2<actor::ApActor<ApObject<actor::Actor<UserTypes>>>, PersonExtension, PublicKeyExtension>;
|
||||||
/// Activitystreams type for post
|
/// Activitystreams type for post
|
||||||
pub type PageExt = Ext1<ApObject<Page>, PageExtension>;
|
pub type PageExt = Ext1<ApObject<Page>, PageExtension>;
|
||||||
pub type NoteExt = Ext1<ApObject<Note>, NoteExtension>;
|
pub type NoteExt = Ext1<ApObject<Note>, NoteExtension>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, PartialEq)]
|
||||||
|
pub enum UserTypes {
|
||||||
|
Person,
|
||||||
|
Service,
|
||||||
|
}
|
||||||
|
|
||||||
pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
|
pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
|
||||||
|
|
||||||
/// Checks if the ID is allowed for sending or receiving.
|
/// Checks if the ID is allowed for sending or receiving.
|
||||||
|
@ -66,8 +73,7 @@ pub static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
|
||||||
/// - URL being in the allowlist (if it is active)
|
/// - URL being in the allowlist (if it is active)
|
||||||
/// - URL not being in the blocklist (if it is active)
|
/// - URL not being in the blocklist (if it is active)
|
||||||
///
|
///
|
||||||
/// Note that only one of allowlist and blacklist can be enabled, not both.
|
pub fn check_is_apub_id_valid(apub_id: &Url, use_strict_allowlist: bool) -> Result<(), LemmyError> {
|
||||||
pub fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
|
|
||||||
let settings = Settings::get();
|
let settings = Settings::get();
|
||||||
let domain = apub_id.domain().context(location_info!())?.to_string();
|
let domain = apub_id.domain().context(location_info!())?.to_string();
|
||||||
let local_instance = settings.get_hostname_without_port()?;
|
let local_instance = settings.get_hostname_without_port()?;
|
||||||
|
@ -96,30 +102,33 @@ pub fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> {
|
||||||
return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into());
|
return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let allowed_instances = Settings::get().get_allowed_instances();
|
// TODO: might be good to put the part above in one method, and below in another
|
||||||
let blocked_instances = Settings::get().get_blocked_instances();
|
// (which only gets called in apub::objects)
|
||||||
|
// -> no that doesnt make sense, we still need the code below for blocklist and strict allowlist
|
||||||
if allowed_instances.is_none() && blocked_instances.is_none() {
|
if let Some(blocked) = Settings::get().get_blocked_instances() {
|
||||||
Ok(())
|
|
||||||
} else if let Some(mut allowed) = allowed_instances {
|
|
||||||
// need to allow this explicitly because apub receive might contain objects from our local
|
|
||||||
// instance. split is needed to remove the port in our federation test setup.
|
|
||||||
allowed.push(local_instance);
|
|
||||||
|
|
||||||
if allowed.contains(&domain) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("{} not in federation allowlist", domain).into())
|
|
||||||
}
|
|
||||||
} else if let Some(blocked) = blocked_instances {
|
|
||||||
if blocked.contains(&domain) {
|
if blocked.contains(&domain) {
|
||||||
Err(anyhow!("{} is in federation blocklist", domain).into())
|
return Err(anyhow!("{} is in federation blocklist", domain).into());
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic!("Invalid config, both allowed_instances and blocked_instances are specified");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(mut allowed) = Settings::get().get_allowed_instances() {
|
||||||
|
// Only check allowlist if this is a community, or strict allowlist is enabled.
|
||||||
|
let strict_allowlist = Settings::get()
|
||||||
|
.federation()
|
||||||
|
.strict_allowlist
|
||||||
|
.unwrap_or(true);
|
||||||
|
if use_strict_allowlist || strict_allowlist {
|
||||||
|
// need to allow this explicitly because apub receive might contain objects from our local
|
||||||
|
// instance.
|
||||||
|
allowed.push(local_instance);
|
||||||
|
|
||||||
|
if !allowed.contains(&domain) {
|
||||||
|
return Err(anyhow!("{} not in federation allowlist", domain).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
|
/// Common functions for ActivityPub objects, which are implemented by most (but not all) objects
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::{context::lemmy_context, note_extension::NoteExtension},
|
extensions::{context::lemmy_context, note_extension::NoteExtension},
|
||||||
fetcher::objects::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
fetcher::objects::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
|
||||||
|
get_community_from_to_or_cc,
|
||||||
objects::{
|
objects::{
|
||||||
check_object_domain,
|
check_object_domain,
|
||||||
check_object_for_community_or_site_ban,
|
check_object_for_community_or_site_ban,
|
||||||
|
@ -147,6 +148,8 @@ impl FromApubToForm<NoteExt> for CommentForm {
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
_mod_action_allowed: bool,
|
_mod_action_allowed: bool,
|
||||||
) -> Result<CommentForm, LemmyError> {
|
) -> Result<CommentForm, LemmyError> {
|
||||||
|
let community = get_community_from_to_or_cc(note, context, request_counter).await?;
|
||||||
|
let ap_id = Some(check_object_domain(note, expected_domain, community.local)?);
|
||||||
let creator_actor_id = ¬e
|
let creator_actor_id = ¬e
|
||||||
.attributed_to()
|
.attributed_to()
|
||||||
.context(location_info!())?
|
.context(location_info!())?
|
||||||
|
@ -204,7 +207,7 @@ impl FromApubToForm<NoteExt> for CommentForm {
|
||||||
published: note.published().map(|u| u.to_owned().naive_local()),
|
published: note.published().map(|u| u.to_owned().naive_local()),
|
||||||
updated: note.updated().map(|u| u.to_owned().naive_local()),
|
updated: note.updated().map(|u| u.to_owned().naive_local()),
|
||||||
deleted: None,
|
deleted: None,
|
||||||
ap_id: Some(check_object_domain(note, expected_domain)?),
|
ap_id,
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
language: note.ext_one.language.to_owned(),
|
language: note.ext_one.language.to_owned(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -203,7 +203,7 @@ impl FromApubToForm<GroupExt> for CommunityForm {
|
||||||
updated: group.inner.updated().map(|u| u.to_owned().naive_local()),
|
updated: group.inner.updated().map(|u| u.to_owned().naive_local()),
|
||||||
deleted: None,
|
deleted: None,
|
||||||
nsfw: Some(group.ext_one.sensitive.unwrap_or(false)),
|
nsfw: Some(group.ext_one.sensitive.unwrap_or(false)),
|
||||||
actor_id: Some(check_object_domain(group, expected_domain)?),
|
actor_id: Some(check_object_domain(group, expected_domain, true)?),
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
private_key: None,
|
private_key: None,
|
||||||
public_key: Some(group.ext_two.to_owned().public_key.public_key_pem),
|
public_key: Some(group.ext_two.to_owned().public_key.public_key_pem),
|
||||||
|
|
|
@ -98,13 +98,14 @@ where
|
||||||
pub(in crate::objects) fn check_object_domain<T, Kind>(
|
pub(in crate::objects) fn check_object_domain<T, Kind>(
|
||||||
apub: &T,
|
apub: &T,
|
||||||
expected_domain: Url,
|
expected_domain: Url,
|
||||||
|
use_strict_allowlist: bool,
|
||||||
) -> Result<DbUrl, LemmyError>
|
) -> Result<DbUrl, LemmyError>
|
||||||
where
|
where
|
||||||
T: Base + AsBase<Kind>,
|
T: Base + AsBase<Kind>,
|
||||||
{
|
{
|
||||||
let domain = expected_domain.domain().context(location_info!())?;
|
let domain = expected_domain.domain().context(location_info!())?;
|
||||||
let object_id = apub.id(domain)?.context(location_info!())?;
|
let object_id = apub.id(domain)?.context(location_info!())?;
|
||||||
check_is_apub_id_valid(object_id)?;
|
check_is_apub_id_valid(object_id, use_strict_allowlist)?;
|
||||||
Ok(object_id.to_owned().into())
|
Ok(object_id.to_owned().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@ use crate::{
|
||||||
},
|
},
|
||||||
ActorType,
|
ActorType,
|
||||||
PersonExt,
|
PersonExt,
|
||||||
|
UserTypes,
|
||||||
};
|
};
|
||||||
use activitystreams::{
|
use activitystreams::{
|
||||||
actor::{ApActor, Endpoints, Person},
|
actor::{Actor, ApActor, ApActorExt, Endpoints},
|
||||||
object::{ApObject, Image, Tombstone},
|
base::{BaseExt, ExtendsExt},
|
||||||
prelude::*,
|
object::{ApObject, Image, Object, ObjectExt, Tombstone},
|
||||||
};
|
};
|
||||||
use activitystreams_ext::Ext2;
|
use activitystreams_ext::Ext2;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
@ -38,7 +39,16 @@ impl ToApub for DbPerson {
|
||||||
type ApubType = PersonExt;
|
type ApubType = PersonExt;
|
||||||
|
|
||||||
async fn to_apub(&self, _pool: &DbPool) -> Result<PersonExt, LemmyError> {
|
async fn to_apub(&self, _pool: &DbPool) -> Result<PersonExt, LemmyError> {
|
||||||
let mut person = ApObject::new(Person::new());
|
let object = Object::<UserTypes>::new_none_type();
|
||||||
|
let mut actor = Actor(object);
|
||||||
|
let kind = if self.bot_account {
|
||||||
|
UserTypes::Service
|
||||||
|
} else {
|
||||||
|
UserTypes::Person
|
||||||
|
};
|
||||||
|
actor.set_kind(kind);
|
||||||
|
let mut person = ApObject::new(actor);
|
||||||
|
|
||||||
person
|
person
|
||||||
.set_many_contexts(lemmy_context()?)
|
.set_many_contexts(lemmy_context()?)
|
||||||
.set_id(self.actor_id.to_owned().into_inner())
|
.set_id(self.actor_id.to_owned().into_inner())
|
||||||
|
@ -189,10 +199,11 @@ impl FromApubToForm<PersonExt> for PersonForm {
|
||||||
banner: banner.map(|o| o.map(|i| i.into())),
|
banner: banner.map(|o| o.map(|i| i.into())),
|
||||||
published: person.inner.published().map(|u| u.to_owned().naive_local()),
|
published: person.inner.published().map(|u| u.to_owned().naive_local()),
|
||||||
updated: person.updated().map(|u| u.to_owned().naive_local()),
|
updated: person.updated().map(|u| u.to_owned().naive_local()),
|
||||||
actor_id: Some(check_object_domain(person, expected_domain)?),
|
actor_id: Some(check_object_domain(person, expected_domain, false)?),
|
||||||
bio: Some(bio),
|
bio: Some(bio),
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
admin: Some(false),
|
admin: Some(false),
|
||||||
|
bot_account: Some(person.inner.is_kind(&UserTypes::Service)),
|
||||||
private_key: None,
|
private_key: None,
|
||||||
public_key: Some(Some(person.ext_two.public_key.to_owned().public_key_pem)),
|
public_key: Some(Some(person.ext_two.public_key.to_owned().public_key_pem)),
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(naive_now()),
|
||||||
|
|
|
@ -144,12 +144,13 @@ impl FromApubToForm<PageExt> for PostForm {
|
||||||
request_counter: &mut i32,
|
request_counter: &mut i32,
|
||||||
mod_action_allowed: bool,
|
mod_action_allowed: bool,
|
||||||
) -> Result<PostForm, LemmyError> {
|
) -> Result<PostForm, LemmyError> {
|
||||||
|
let community = get_community_from_to_or_cc(page, context, request_counter).await?;
|
||||||
let ap_id = if mod_action_allowed {
|
let ap_id = if mod_action_allowed {
|
||||||
let id = page.id_unchecked().context(location_info!())?;
|
let id = page.id_unchecked().context(location_info!())?;
|
||||||
check_is_apub_id_valid(id)?;
|
check_is_apub_id_valid(id, community.local)?;
|
||||||
id.to_owned().into()
|
id.to_owned().into()
|
||||||
} else {
|
} else {
|
||||||
check_object_domain(page, expected_domain)?
|
check_object_domain(page, expected_domain, community.local)?
|
||||||
};
|
};
|
||||||
let ext = &page.ext_one;
|
let ext = &page.ext_one;
|
||||||
let creator_actor_id = page
|
let creator_actor_id = page
|
||||||
|
@ -163,8 +164,6 @@ impl FromApubToForm<PageExt> for PostForm {
|
||||||
let creator =
|
let creator =
|
||||||
get_or_fetch_and_upsert_person(creator_actor_id, context, request_counter).await?;
|
get_or_fetch_and_upsert_person(creator_actor_id, context, request_counter).await?;
|
||||||
|
|
||||||
let community = get_community_from_to_or_cc(page, context, request_counter).await?;
|
|
||||||
|
|
||||||
let thumbnail_url: Option<Url> = match &page.inner.image() {
|
let thumbnail_url: Option<Url> = match &page.inner.image() {
|
||||||
Some(any_image) => Image::from_any_base(
|
Some(any_image) => Image::from_any_base(
|
||||||
any_image
|
any_image
|
||||||
|
@ -232,8 +231,8 @@ impl FromApubToForm<PageExt> for PostForm {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|u| u.to_owned().naive_local()),
|
.map(|u| u.to_owned().naive_local()),
|
||||||
deleted: None,
|
deleted: None,
|
||||||
nsfw: ext.sensitive.unwrap_or(false),
|
nsfw: ext.sensitive,
|
||||||
stickied: ext.stickied.or(Some(false)),
|
stickied: ext.stickied,
|
||||||
embed_title: iframely_title,
|
embed_title: iframely_title,
|
||||||
embed_description: iframely_description,
|
embed_description: iframely_description,
|
||||||
embed_html: iframely_html,
|
embed_html: iframely_html,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
check_is_apub_id_valid,
|
|
||||||
extensions::{context::lemmy_context, note_extension::NoteExtension},
|
extensions::{context::lemmy_context, note_extension::NoteExtension},
|
||||||
fetcher::person::get_or_fetch_and_upsert_person,
|
fetcher::person::get_or_fetch_and_upsert_person,
|
||||||
objects::{
|
objects::{
|
||||||
|
@ -118,8 +117,7 @@ impl FromApubToForm<NoteExt> for PrivateMessageForm {
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
let recipient =
|
let recipient =
|
||||||
get_or_fetch_and_upsert_person(&recipient_actor_id, context, request_counter).await?;
|
get_or_fetch_and_upsert_person(&recipient_actor_id, context, request_counter).await?;
|
||||||
let ap_id = note.id_unchecked().context(location_info!())?.to_string();
|
let ap_id = Some(check_object_domain(note, expected_domain, false)?);
|
||||||
check_is_apub_id_valid(&Url::parse(&ap_id)?)?;
|
|
||||||
|
|
||||||
let content = get_source_markdown_value(note)?.context(location_info!())?;
|
let content = get_source_markdown_value(note)?.context(location_info!())?;
|
||||||
|
|
||||||
|
@ -131,7 +129,7 @@ impl FromApubToForm<NoteExt> for PrivateMessageForm {
|
||||||
updated: note.updated().map(|u| u.to_owned().naive_local()),
|
updated: note.updated().map(|u| u.to_owned().naive_local()),
|
||||||
deleted: None,
|
deleted: None,
|
||||||
read: None,
|
read: None,
|
||||||
ap_id: Some(check_object_domain(note, expected_domain)?),
|
ap_id,
|
||||||
local: Some(false),
|
local: Some(false),
|
||||||
language: note.ext_one.language.to_owned(),
|
language: note.ext_one.language.to_owned(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -220,7 +220,7 @@ where
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.single_xsd_any_uri()
|
.single_xsd_any_uri()
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
check_is_apub_id_valid(&person_id)?;
|
check_is_apub_id_valid(&person_id, false)?;
|
||||||
// check that the sender is a person, not a community
|
// check that the sender is a person, not a community
|
||||||
get_or_fetch_and_upsert_person(&person_id, &context, request_counter).await?;
|
get_or_fetch_and_upsert_person(&person_id, &context, request_counter).await?;
|
||||||
|
|
||||||
|
|
|
@ -96,13 +96,6 @@ pub async fn community_inbox(
|
||||||
assert_activity_not_local(&activity)?;
|
assert_activity_not_local(&activity)?;
|
||||||
insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?;
|
insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?;
|
||||||
|
|
||||||
info!(
|
|
||||||
"Community {} received activity {:?} from {}",
|
|
||||||
community.name,
|
|
||||||
&activity.id_unchecked(),
|
|
||||||
&actor.actor_id()
|
|
||||||
);
|
|
||||||
|
|
||||||
community_receive_message(
|
community_receive_message(
|
||||||
activity.clone(),
|
activity.clone(),
|
||||||
community.clone(),
|
community.clone(),
|
||||||
|
@ -130,6 +123,16 @@ pub(crate) async fn community_receive_message(
|
||||||
.await??;
|
.await??;
|
||||||
check_community_or_site_ban(&person, to_community.id, context.pool()).await?;
|
check_community_or_site_ban(&person, to_community.id, context.pool()).await?;
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Community {} received activity {} from {}",
|
||||||
|
to_community.name,
|
||||||
|
&activity
|
||||||
|
.id_unchecked()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_string(),
|
||||||
|
&person.actor_id().to_string()
|
||||||
|
);
|
||||||
|
|
||||||
let any_base = activity.clone().into_any_base()?;
|
let any_base = activity.clone().into_any_base()?;
|
||||||
let actor_url = actor.actor_id();
|
let actor_url = actor.actor_id();
|
||||||
let activity_kind = activity.kind().context(location_info!())?;
|
let activity_kind = activity.kind().context(location_info!())?;
|
||||||
|
|
|
@ -85,7 +85,7 @@ where
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.single_xsd_any_uri()
|
.single_xsd_any_uri()
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
check_is_apub_id_valid(&actor_id)?;
|
check_is_apub_id_valid(&actor_id, false)?;
|
||||||
let actor = get_or_fetch_and_upsert_actor(&actor_id, &context, request_counter).await?;
|
let actor = get_or_fetch_and_upsert_actor(&actor_id, &context, request_counter).await?;
|
||||||
verify_signature(&request, actor.as_ref())?;
|
verify_signature(&request, actor.as_ref())?;
|
||||||
Ok(actor)
|
Ok(actor)
|
||||||
|
|
|
@ -61,7 +61,7 @@ use lemmy_db_schema::source::{
|
||||||
};
|
};
|
||||||
use lemmy_utils::{location_info, LemmyError};
|
use lemmy_utils::{location_info, LemmyError};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use log::debug;
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use strum_macros::EnumString;
|
use strum_macros::EnumString;
|
||||||
|
@ -115,13 +115,6 @@ pub async fn person_inbox(
|
||||||
assert_activity_not_local(&activity)?;
|
assert_activity_not_local(&activity)?;
|
||||||
insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?;
|
insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?;
|
||||||
|
|
||||||
debug!(
|
|
||||||
"Person {} received activity {:?} from {}",
|
|
||||||
person.name,
|
|
||||||
&activity.id_unchecked(),
|
|
||||||
&actor.actor_id()
|
|
||||||
);
|
|
||||||
|
|
||||||
person_receive_message(
|
person_receive_message(
|
||||||
activity.clone(),
|
activity.clone(),
|
||||||
Some(person.clone()),
|
Some(person.clone()),
|
||||||
|
@ -142,6 +135,15 @@ pub(crate) async fn person_receive_message(
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
is_for_person_inbox(context, &activity).await?;
|
is_for_person_inbox(context, &activity).await?;
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"User received activity {:?} from {}",
|
||||||
|
&activity
|
||||||
|
.id_unchecked()
|
||||||
|
.context(location_info!())?
|
||||||
|
.to_string(),
|
||||||
|
&actor.actor_id().to_string()
|
||||||
|
);
|
||||||
|
|
||||||
let any_base = activity.clone().into_any_base()?;
|
let any_base = activity.clone().into_any_base()?;
|
||||||
let kind = activity.kind().context(location_info!())?;
|
let kind = activity.kind().context(location_info!())?;
|
||||||
let actor_url = actor.actor_id();
|
let actor_url = actor.actor_id();
|
||||||
|
@ -302,7 +304,7 @@ pub async fn receive_announce(
|
||||||
.context(location_info!())?;
|
.context(location_info!())?;
|
||||||
|
|
||||||
let inner_id = inner_activity.id().context(location_info!())?.to_owned();
|
let inner_id = inner_activity.id().context(location_info!())?.to_owned();
|
||||||
check_is_apub_id_valid(&inner_id)?;
|
check_is_apub_id_valid(&inner_id, false)?;
|
||||||
if is_activity_already_known(context.pool(), &inner_id).await? {
|
if is_activity_already_known(context.pool(), &inner_id).await? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,15 +52,16 @@ mod tests {
|
||||||
|
|
||||||
let site_form = SiteForm {
|
let site_form = SiteForm {
|
||||||
name: "test_site".into(),
|
name: "test_site".into(),
|
||||||
|
creator_id: inserted_person.id,
|
||||||
sidebar: None,
|
sidebar: None,
|
||||||
description: None,
|
description: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
creator_id: inserted_person.id,
|
enable_downvotes: None,
|
||||||
enable_downvotes: true,
|
open_registration: None,
|
||||||
open_registration: true,
|
enable_nsfw: None,
|
||||||
enable_nsfw: true,
|
|
||||||
updated: None,
|
updated: None,
|
||||||
|
community_creation_admin_only: Some(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
Site::create(&conn, &site_form).unwrap();
|
Site::create(&conn, &site_form).unwrap();
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub fn get_database_url_from_env() -> Result<String, VarError> {
|
||||||
env::var("LEMMY_DATABASE_URL")
|
env::var("LEMMY_DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
#[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
pub enum SortType {
|
pub enum SortType {
|
||||||
Active,
|
Active,
|
||||||
Hot,
|
Hot,
|
||||||
|
@ -177,7 +177,7 @@ pub enum SortType {
|
||||||
NewComments,
|
NewComments,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone)]
|
#[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
pub enum ListingType {
|
pub enum ListingType {
|
||||||
All,
|
All,
|
||||||
Local,
|
Local,
|
||||||
|
@ -185,7 +185,7 @@ pub enum ListingType {
|
||||||
Community,
|
Community,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
#[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
pub enum SearchType {
|
pub enum SearchType {
|
||||||
All,
|
All,
|
||||||
Comments,
|
Comments,
|
||||||
|
@ -195,6 +195,10 @@ pub enum SearchType {
|
||||||
Url,
|
Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_opt_str_to_opt_enum<T: std::str::FromStr>(opt: &Option<String>) -> Option<T> {
|
||||||
|
opt.as_ref().map(|t| T::from_str(t).ok()).flatten()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fuzzy_search(q: &str) -> String {
|
pub fn fuzzy_search(q: &str) -> String {
|
||||||
let replaced = q.replace(" ", "%");
|
let replaced = q.replace(" ", "%");
|
||||||
format!("%{}%", replaced)
|
format!("%{}%", replaced)
|
||||||
|
|
|
@ -24,7 +24,9 @@ mod safe_settings_type {
|
||||||
show_avatars,
|
show_avatars,
|
||||||
send_notifications_to_email,
|
send_notifications_to_email,
|
||||||
validator_time,
|
validator_time,
|
||||||
|
show_bot_accounts,
|
||||||
show_scores,
|
show_scores,
|
||||||
|
show_read_posts,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ToSafeSettings for LocalUser {
|
impl ToSafeSettings for LocalUser {
|
||||||
|
@ -44,7 +46,9 @@ mod safe_settings_type {
|
||||||
show_avatars,
|
show_avatars,
|
||||||
send_notifications_to_email,
|
send_notifications_to_email,
|
||||||
validator_time,
|
validator_time,
|
||||||
|
show_bot_accounts,
|
||||||
show_scores,
|
show_scores,
|
||||||
|
show_read_posts,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ mod safe_type {
|
||||||
shared_inbox_url,
|
shared_inbox_url,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
admin,
|
admin,
|
||||||
|
bot_account,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ToSafe for Person {
|
impl ToSafe for Person {
|
||||||
|
@ -51,6 +52,7 @@ mod safe_type {
|
||||||
shared_inbox_url,
|
shared_inbox_url,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
admin,
|
admin,
|
||||||
|
bot_account,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,6 +79,7 @@ mod safe_type_alias_1 {
|
||||||
shared_inbox_url,
|
shared_inbox_url,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
admin,
|
admin,
|
||||||
|
bot_account,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ToSafe for PersonAlias1 {
|
impl ToSafe for PersonAlias1 {
|
||||||
|
@ -99,6 +102,7 @@ mod safe_type_alias_1 {
|
||||||
shared_inbox_url,
|
shared_inbox_url,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
admin,
|
admin,
|
||||||
|
bot_account,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +129,7 @@ mod safe_type_alias_2 {
|
||||||
shared_inbox_url,
|
shared_inbox_url,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
admin,
|
admin,
|
||||||
|
bot_account,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ToSafe for PersonAlias2 {
|
impl ToSafe for PersonAlias2 {
|
||||||
|
@ -147,6 +152,7 @@ mod safe_type_alias_2 {
|
||||||
shared_inbox_url,
|
shared_inbox_url,
|
||||||
matrix_user_id,
|
matrix_user_id,
|
||||||
admin,
|
admin,
|
||||||
|
bot_account,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,6 +280,7 @@ mod tests {
|
||||||
actor_id: inserted_person.actor_id.to_owned(),
|
actor_id: inserted_person.actor_id.to_owned(),
|
||||||
bio: None,
|
bio: None,
|
||||||
local: true,
|
local: true,
|
||||||
|
bot_account: false,
|
||||||
admin: false,
|
admin: false,
|
||||||
private_key: None,
|
private_key: None,
|
||||||
public_key: None,
|
public_key: None,
|
||||||
|
|
|
@ -243,6 +243,9 @@ impl Readable<PostReadForm> for PostRead {
|
||||||
use lemmy_db_schema::schema::post_read::dsl::*;
|
use lemmy_db_schema::schema::post_read::dsl::*;
|
||||||
insert_into(post_read)
|
insert_into(post_read)
|
||||||
.values(post_read_form)
|
.values(post_read_form)
|
||||||
|
.on_conflict((post_id, person_id))
|
||||||
|
.do_update()
|
||||||
|
.set(post_read_form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,8 +154,10 @@ table! {
|
||||||
show_avatars -> Bool,
|
show_avatars -> Bool,
|
||||||
send_notifications_to_email -> Bool,
|
send_notifications_to_email -> Bool,
|
||||||
validator_time -> Timestamp,
|
validator_time -> Timestamp,
|
||||||
|
show_bot_accounts -> Bool,
|
||||||
show_scores -> Bool,
|
show_scores -> Bool,
|
||||||
discussion_languages -> Array<Text>,
|
discussion_languages -> Array<Text>,
|
||||||
|
show_read_posts -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +291,7 @@ table! {
|
||||||
shared_inbox_url -> Nullable<Varchar>,
|
shared_inbox_url -> Nullable<Varchar>,
|
||||||
matrix_user_id -> Nullable<Text>,
|
matrix_user_id -> Nullable<Text>,
|
||||||
admin -> Bool,
|
admin -> Bool,
|
||||||
|
bot_account -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +438,7 @@ table! {
|
||||||
icon -> Nullable<Varchar>,
|
icon -> Nullable<Varchar>,
|
||||||
banner -> Nullable<Varchar>,
|
banner -> Nullable<Varchar>,
|
||||||
description -> Nullable<Text>,
|
description -> Nullable<Text>,
|
||||||
|
community_creation_admin_only -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +496,7 @@ table! {
|
||||||
shared_inbox_url -> Nullable<Varchar>,
|
shared_inbox_url -> Nullable<Varchar>,
|
||||||
matrix_user_id -> Nullable<Text>,
|
matrix_user_id -> Nullable<Text>,
|
||||||
admin -> Bool,
|
admin -> Bool,
|
||||||
|
bot_account -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +521,7 @@ table! {
|
||||||
shared_inbox_url -> Nullable<Varchar>,
|
shared_inbox_url -> Nullable<Varchar>,
|
||||||
matrix_user_id -> Nullable<Text>,
|
matrix_user_id -> Nullable<Text>,
|
||||||
admin -> Bool,
|
admin -> Bool,
|
||||||
|
bot_account -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,10 @@ 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_bot_accounts: bool,
|
||||||
pub show_scores: bool,
|
pub show_scores: bool,
|
||||||
pub discussion_languages: Vec<PrimaryLanguageTag>,
|
pub discussion_languages: Vec<PrimaryLanguageTag>,
|
||||||
|
pub show_read_posts: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO redo these, check table defaults
|
// TODO redo these, check table defaults
|
||||||
|
@ -34,8 +36,10 @@ pub struct LocalUserForm {
|
||||||
pub interface_language: Option<String>,
|
pub interface_language: 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_bot_accounts: Option<bool>,
|
||||||
pub show_scores: Option<bool>,
|
pub show_scores: Option<bool>,
|
||||||
pub discussion_languages: Option<Vec<PrimaryLanguageTag>>,
|
pub discussion_languages: Option<Vec<PrimaryLanguageTag>>,
|
||||||
|
pub show_read_posts: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A local user view that removes password encrypted
|
/// A local user view that removes password encrypted
|
||||||
|
@ -53,5 +57,7 @@ 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_bot_accounts: bool,
|
||||||
pub show_scores: bool,
|
pub show_scores: bool,
|
||||||
|
pub show_read_posts: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ pub struct Person {
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
pub shared_inbox_url: Option<DbUrl>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
pub bot_account: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A safe representation of person, without the sensitive info
|
/// A safe representation of person, without the sensitive info
|
||||||
|
@ -49,6 +50,7 @@ pub struct PersonSafe {
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
pub shared_inbox_url: Option<DbUrl>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
pub bot_account: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -73,6 +75,7 @@ pub struct PersonAlias1 {
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
pub shared_inbox_url: Option<DbUrl>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
pub bot_account: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -94,6 +97,7 @@ pub struct PersonSafeAlias1 {
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
pub shared_inbox_url: Option<DbUrl>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
pub bot_account: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -118,6 +122,7 @@ pub struct PersonAlias2 {
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
pub shared_inbox_url: Option<DbUrl>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
pub bot_account: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
|
||||||
|
@ -139,6 +144,7 @@ pub struct PersonSafeAlias2 {
|
||||||
pub shared_inbox_url: Option<DbUrl>,
|
pub shared_inbox_url: Option<DbUrl>,
|
||||||
pub matrix_user_id: Option<String>,
|
pub matrix_user_id: Option<String>,
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
pub bot_account: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, AsChangeset, Clone, Default)]
|
#[derive(Insertable, AsChangeset, Clone, Default)]
|
||||||
|
@ -162,4 +168,5 @@ pub struct PersonForm {
|
||||||
pub shared_inbox_url: Option<Option<DbUrl>>,
|
pub shared_inbox_url: Option<Option<DbUrl>>,
|
||||||
pub matrix_user_id: Option<Option<String>>,
|
pub matrix_user_id: Option<Option<String>>,
|
||||||
pub admin: Option<bool>,
|
pub admin: Option<bool>,
|
||||||
|
pub bot_account: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub struct PostForm {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub creator_id: PersonId,
|
pub creator_id: PersonId,
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub nsfw: bool,
|
pub nsfw: Option<bool>,
|
||||||
pub url: Option<DbUrl>,
|
pub url: Option<DbUrl>,
|
||||||
pub body: Option<String>,
|
pub body: Option<String>,
|
||||||
pub removed: Option<bool>,
|
pub removed: Option<bool>,
|
||||||
|
|
|
@ -16,20 +16,22 @@ pub struct Site {
|
||||||
pub icon: Option<DbUrl>,
|
pub icon: Option<DbUrl>,
|
||||||
pub banner: Option<DbUrl>,
|
pub banner: Option<DbUrl>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
pub community_creation_admin_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 sidebar: Option<Option<String>>,
|
|
||||||
pub creator_id: PersonId,
|
pub creator_id: PersonId,
|
||||||
|
pub sidebar: Option<Option<String>>,
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub enable_downvotes: bool,
|
pub enable_downvotes: Option<bool>,
|
||||||
pub open_registration: bool,
|
pub open_registration: Option<bool>,
|
||||||
pub enable_nsfw: bool,
|
pub enable_nsfw: Option<bool>,
|
||||||
// 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>>,
|
pub description: Option<Option<String>>,
|
||||||
|
pub community_creation_admin_only: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,8 +172,8 @@ impl CommentView {
|
||||||
|
|
||||||
pub struct CommentQueryBuilder<'a> {
|
pub struct CommentQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
listing_type: ListingType,
|
listing_type: Option<ListingType>,
|
||||||
sort: &'a SortType,
|
sort: Option<SortType>,
|
||||||
community_id: Option<CommunityId>,
|
community_id: Option<CommunityId>,
|
||||||
community_name: Option<String>,
|
community_name: Option<String>,
|
||||||
post_id: Option<PostId>,
|
post_id: Option<PostId>,
|
||||||
|
@ -181,8 +181,9 @@ pub struct CommentQueryBuilder<'a> {
|
||||||
recipient_id: Option<PersonId>,
|
recipient_id: Option<PersonId>,
|
||||||
my_person_id: Option<PersonId>,
|
my_person_id: Option<PersonId>,
|
||||||
search_term: Option<String>,
|
search_term: Option<String>,
|
||||||
saved_only: bool,
|
saved_only: Option<bool>,
|
||||||
unread_only: bool,
|
unread_only: Option<bool>,
|
||||||
|
show_bot_accounts: Option<bool>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
}
|
}
|
||||||
|
@ -191,8 +192,8 @@ impl<'a> CommentQueryBuilder<'a> {
|
||||||
pub fn create(conn: &'a PgConnection) -> Self {
|
pub fn create(conn: &'a PgConnection) -> Self {
|
||||||
CommentQueryBuilder {
|
CommentQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
listing_type: ListingType::All,
|
listing_type: None,
|
||||||
sort: &SortType::New,
|
sort: None,
|
||||||
community_id: None,
|
community_id: None,
|
||||||
community_name: None,
|
community_name: None,
|
||||||
post_id: None,
|
post_id: None,
|
||||||
|
@ -200,20 +201,21 @@ impl<'a> CommentQueryBuilder<'a> {
|
||||||
recipient_id: None,
|
recipient_id: None,
|
||||||
my_person_id: None,
|
my_person_id: None,
|
||||||
search_term: None,
|
search_term: None,
|
||||||
saved_only: false,
|
saved_only: None,
|
||||||
unread_only: false,
|
unread_only: None,
|
||||||
|
show_bot_accounts: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listing_type(mut self, listing_type: ListingType) -> Self {
|
pub fn listing_type<T: MaybeOptional<ListingType>>(mut self, listing_type: T) -> Self {
|
||||||
self.listing_type = listing_type;
|
self.listing_type = listing_type.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(mut self, sort: &'a SortType) -> Self {
|
pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
|
||||||
self.sort = sort;
|
self.sort = sort.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,13 +254,18 @@ impl<'a> CommentQueryBuilder<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn saved_only(mut self, saved_only: bool) -> Self {
|
pub fn saved_only<T: MaybeOptional<bool>>(mut self, saved_only: T) -> Self {
|
||||||
self.saved_only = saved_only;
|
self.saved_only = saved_only.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unread_only(mut self, unread_only: bool) -> Self {
|
pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
|
||||||
self.unread_only = unread_only;
|
self.unread_only = unread_only.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_bot_accounts<T: MaybeOptional<bool>>(mut self, show_bot_accounts: T) -> Self {
|
||||||
|
self.show_bot_accounts = show_bot_accounts.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +350,7 @@ impl<'a> CommentQueryBuilder<'a> {
|
||||||
.filter(comment::removed.eq(false));
|
.filter(comment::removed.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.unread_only {
|
if self.unread_only.unwrap_or(false) {
|
||||||
query = query.filter(comment::read.eq(false));
|
query = query.filter(comment::read.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,18 +376,23 @@ impl<'a> CommentQueryBuilder<'a> {
|
||||||
query = query.filter(comment::content.ilike(fuzzy_search(&search_term)));
|
query = query.filter(comment::content.ilike(fuzzy_search(&search_term)));
|
||||||
};
|
};
|
||||||
|
|
||||||
query = match self.listing_type {
|
if let Some(listing_type) = self.listing_type {
|
||||||
// ListingType::Subscribed => query.filter(community_follower::subscribed.eq(true)),
|
query = match listing_type {
|
||||||
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
|
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
|
||||||
ListingType::Local => query.filter(community::local.eq(true)),
|
ListingType::Local => query.filter(community::local.eq(true)),
|
||||||
_ => query,
|
_ => query,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if self.saved_only {
|
if self.saved_only.unwrap_or(false) {
|
||||||
query = query.filter(comment_saved::id.is_not_null());
|
query = query.filter(comment_saved::id.is_not_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
query = match self.sort {
|
if !self.show_bot_accounts.unwrap_or(true) {
|
||||||
|
query = query.filter(person::bot_account.eq(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
query = match self.sort.unwrap_or(SortType::New) {
|
||||||
SortType::Hot | SortType::Active => query
|
SortType::Hot | SortType::Active => query
|
||||||
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
|
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
|
||||||
.then_order_by(comment_aggregates::published.desc()),
|
.then_order_by(comment_aggregates::published.desc()),
|
||||||
|
@ -532,6 +544,7 @@ mod tests {
|
||||||
banned: false,
|
banned: false,
|
||||||
deleted: false,
|
deleted: false,
|
||||||
admin: false,
|
admin: false,
|
||||||
|
bot_account: false,
|
||||||
bio: None,
|
bio: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
updated: None,
|
updated: None,
|
||||||
|
|
|
@ -156,17 +156,18 @@ impl PostView {
|
||||||
|
|
||||||
pub struct PostQueryBuilder<'a> {
|
pub struct PostQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
listing_type: &'a ListingType,
|
listing_type: Option<ListingType>,
|
||||||
sort: &'a SortType,
|
sort: Option<SortType>,
|
||||||
creator_id: Option<PersonId>,
|
creator_id: Option<PersonId>,
|
||||||
community_id: Option<CommunityId>,
|
community_id: Option<CommunityId>,
|
||||||
community_name: Option<String>,
|
community_name: Option<String>,
|
||||||
my_person_id: Option<PersonId>,
|
my_person_id: Option<PersonId>,
|
||||||
search_term: Option<String>,
|
search_term: Option<String>,
|
||||||
url_search: Option<String>,
|
url_search: Option<String>,
|
||||||
show_nsfw: bool,
|
show_nsfw: Option<bool>,
|
||||||
saved_only: bool,
|
show_bot_accounts: Option<bool>,
|
||||||
unread_only: bool,
|
show_read_posts: Option<bool>,
|
||||||
|
saved_only: Option<bool>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
languages: Option<Vec<PrimaryLanguageTag>>,
|
languages: Option<Vec<PrimaryLanguageTag>>,
|
||||||
|
@ -176,30 +177,31 @@ impl<'a> PostQueryBuilder<'a> {
|
||||||
pub fn create(conn: &'a PgConnection) -> Self {
|
pub fn create(conn: &'a PgConnection) -> Self {
|
||||||
PostQueryBuilder {
|
PostQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
listing_type: &ListingType::All,
|
listing_type: None,
|
||||||
sort: &SortType::Hot,
|
sort: None,
|
||||||
creator_id: None,
|
creator_id: None,
|
||||||
community_id: None,
|
community_id: None,
|
||||||
community_name: None,
|
community_name: None,
|
||||||
my_person_id: None,
|
my_person_id: None,
|
||||||
search_term: None,
|
search_term: None,
|
||||||
url_search: None,
|
url_search: None,
|
||||||
show_nsfw: true,
|
show_nsfw: None,
|
||||||
saved_only: false,
|
show_bot_accounts: None,
|
||||||
unread_only: false,
|
show_read_posts: None,
|
||||||
|
saved_only: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
languages: None,
|
languages: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listing_type(mut self, listing_type: &'a ListingType) -> Self {
|
pub fn listing_type<T: MaybeOptional<ListingType>>(mut self, listing_type: T) -> Self {
|
||||||
self.listing_type = listing_type;
|
self.listing_type = listing_type.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(mut self, sort: &'a SortType) -> Self {
|
pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
|
||||||
self.sort = sort;
|
self.sort = sort.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,13 +235,23 @@ impl<'a> PostQueryBuilder<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_nsfw(mut self, show_nsfw: bool) -> Self {
|
pub fn show_nsfw<T: MaybeOptional<bool>>(mut self, show_nsfw: T) -> Self {
|
||||||
self.show_nsfw = show_nsfw;
|
self.show_nsfw = show_nsfw.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn saved_only(mut self, saved_only: bool) -> Self {
|
pub fn show_bot_accounts<T: MaybeOptional<bool>>(mut self, show_bot_accounts: T) -> Self {
|
||||||
self.saved_only = saved_only;
|
self.show_bot_accounts = show_bot_accounts.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_read_posts<T: MaybeOptional<bool>>(mut self, show_read_posts: T) -> Self {
|
||||||
|
self.show_read_posts = show_read_posts.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn saved_only<T: MaybeOptional<bool>>(mut self, saved_only: T) -> Self {
|
||||||
|
self.saved_only = saved_only.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,11 +328,13 @@ impl<'a> PostQueryBuilder<'a> {
|
||||||
))
|
))
|
||||||
.into_boxed();
|
.into_boxed();
|
||||||
|
|
||||||
query = match self.listing_type {
|
if let Some(listing_type) = self.listing_type {
|
||||||
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
|
query = match listing_type {
|
||||||
ListingType::Local => query.filter(community::local.eq(true)),
|
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()),
|
||||||
_ => query,
|
ListingType::Local => query.filter(community::local.eq(true)),
|
||||||
};
|
_ => query,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(community_id) = self.community_id {
|
if let Some(community_id) = self.community_id {
|
||||||
query = query
|
query = query
|
||||||
|
@ -353,26 +367,29 @@ impl<'a> PostQueryBuilder<'a> {
|
||||||
query = query.filter(post::creator_id.eq(creator_id));
|
query = query.filter(post::creator_id.eq(creator_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.show_nsfw {
|
if !self.show_nsfw.unwrap_or(true) {
|
||||||
query = query
|
query = query
|
||||||
.filter(post::nsfw.eq(false))
|
.filter(post::nsfw.eq(false))
|
||||||
.filter(community::nsfw.eq(false));
|
.filter(community::nsfw.eq(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO These two might be wrong
|
if !self.show_bot_accounts.unwrap_or(true) {
|
||||||
if self.saved_only {
|
query = query.filter(person::bot_account.eq(false));
|
||||||
query = query.filter(post_saved::id.is_not_null());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.unread_only {
|
if !self.show_read_posts.unwrap_or(true) {
|
||||||
query = query.filter(post_read::id.is_not_null());
|
query = query.filter(post_read::id.is_null());
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.saved_only.unwrap_or(false) {
|
||||||
|
query = query.filter(post_saved::id.is_not_null());
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(languages) = self.languages {
|
if let Some(languages) = self.languages {
|
||||||
query = query.filter(post::language.eq_any(languages.into_iter()));
|
query = query.filter(post::language.eq_any(languages.into_iter()));
|
||||||
};
|
};
|
||||||
|
|
||||||
query = match self.sort {
|
query = match self.sort.unwrap_or(SortType::Hot) {
|
||||||
SortType::Active => query
|
SortType::Active => query
|
||||||
.then_order_by(
|
.then_order_by(
|
||||||
hot_rank(
|
hot_rank(
|
||||||
|
@ -466,6 +483,7 @@ mod tests {
|
||||||
let person_name = "tegan".to_string();
|
let person_name = "tegan".to_string();
|
||||||
let community_name = "test_community_3".to_string();
|
let community_name = "test_community_3".to_string();
|
||||||
let post_name = "test post 3".to_string();
|
let post_name = "test post 3".to_string();
|
||||||
|
let bot_post_name = "test bot post".to_string();
|
||||||
|
|
||||||
let new_person = PersonForm {
|
let new_person = PersonForm {
|
||||||
name: person_name.to_owned(),
|
name: person_name.to_owned(),
|
||||||
|
@ -474,6 +492,14 @@ mod tests {
|
||||||
|
|
||||||
let inserted_person = Person::create(&conn, &new_person).unwrap();
|
let inserted_person = Person::create(&conn, &new_person).unwrap();
|
||||||
|
|
||||||
|
let new_bot = PersonForm {
|
||||||
|
name: person_name.to_owned(),
|
||||||
|
bot_account: Some(true),
|
||||||
|
..PersonForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_bot = Person::create(&conn, &new_bot).unwrap();
|
||||||
|
|
||||||
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(),
|
||||||
|
@ -492,6 +518,15 @@ mod tests {
|
||||||
|
|
||||||
let inserted_post = Post::create(&conn, &new_post).unwrap();
|
let inserted_post = Post::create(&conn, &new_post).unwrap();
|
||||||
|
|
||||||
|
let new_bot_post = PostForm {
|
||||||
|
name: bot_post_name,
|
||||||
|
creator_id: inserted_bot.id,
|
||||||
|
community_id: inserted_community.id,
|
||||||
|
..PostForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let _inserted_bot_post = Post::create(&conn, &new_bot_post).unwrap();
|
||||||
|
|
||||||
let post_like_form = PostLikeForm {
|
let post_like_form = PostLikeForm {
|
||||||
post_id: inserted_post.id,
|
post_id: inserted_post.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
|
@ -509,16 +544,17 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_post_listings_with_person = PostQueryBuilder::create(&conn)
|
let read_post_listings_with_person = PostQueryBuilder::create(&conn)
|
||||||
.listing_type(&ListingType::Community)
|
.listing_type(ListingType::Community)
|
||||||
.sort(&SortType::New)
|
.sort(SortType::New)
|
||||||
|
.show_bot_accounts(false)
|
||||||
.community_id(inserted_community.id)
|
.community_id(inserted_community.id)
|
||||||
.my_person_id(inserted_person.id)
|
.my_person_id(inserted_person.id)
|
||||||
.list()
|
.list()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let read_post_listings_no_person = PostQueryBuilder::create(&conn)
|
let read_post_listings_no_person = PostQueryBuilder::create(&conn)
|
||||||
.listing_type(&ListingType::Community)
|
.listing_type(ListingType::Community)
|
||||||
.sort(&SortType::New)
|
.sort(SortType::New)
|
||||||
.community_id(inserted_community.id)
|
.community_id(inserted_community.id)
|
||||||
.list()
|
.list()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -563,6 +599,7 @@ mod tests {
|
||||||
actor_id: inserted_person.actor_id.to_owned(),
|
actor_id: inserted_person.actor_id.to_owned(),
|
||||||
local: true,
|
local: true,
|
||||||
admin: false,
|
admin: false,
|
||||||
|
bot_account: false,
|
||||||
banned: false,
|
banned: false,
|
||||||
deleted: false,
|
deleted: false,
|
||||||
bio: None,
|
bio: None,
|
||||||
|
@ -613,6 +650,7 @@ mod tests {
|
||||||
let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
|
let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
|
||||||
Community::delete(&conn, inserted_community.id).unwrap();
|
Community::delete(&conn, inserted_community.id).unwrap();
|
||||||
Person::delete(&conn, inserted_person.id).unwrap();
|
Person::delete(&conn, inserted_person.id).unwrap();
|
||||||
|
Person::delete(&conn, inserted_bot.id).unwrap();
|
||||||
|
|
||||||
// The with user
|
// The with user
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -623,18 +661,20 @@ mod tests {
|
||||||
expected_post_listing_with_user,
|
expected_post_listing_with_user,
|
||||||
read_post_listing_with_person
|
read_post_listing_with_person
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Should be only one person, IE the bot post should be missing
|
||||||
assert_eq!(1, read_post_listings_with_person.len());
|
assert_eq!(1, read_post_listings_with_person.len());
|
||||||
|
|
||||||
// Without the user
|
// Without the user
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_post_listing_no_person,
|
expected_post_listing_no_person,
|
||||||
read_post_listings_no_person[0]
|
read_post_listings_no_person[1]
|
||||||
);
|
);
|
||||||
assert_eq!(expected_post_listing_no_person, read_post_listing_no_person);
|
assert_eq!(expected_post_listing_no_person, read_post_listing_no_person);
|
||||||
assert_eq!(1, read_post_listings_no_person.len());
|
|
||||||
|
|
||||||
// assert_eq!(expected_post, inserted_post);
|
// Should be 2 posts, with the bot post
|
||||||
// assert_eq!(expected_post, updated_post);
|
assert_eq!(2, read_post_listings_no_person.len());
|
||||||
|
|
||||||
assert_eq!(expected_post_like, inserted_post_like);
|
assert_eq!(expected_post_like, inserted_post_like);
|
||||||
assert_eq!(1, like_removed);
|
assert_eq!(1, like_removed);
|
||||||
assert_eq!(1, num_deleted);
|
assert_eq!(1, num_deleted);
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl PrivateMessageView {
|
||||||
pub struct PrivateMessageQueryBuilder<'a> {
|
pub struct PrivateMessageQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
recipient_id: PersonId,
|
recipient_id: PersonId,
|
||||||
unread_only: bool,
|
unread_only: Option<bool>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
}
|
}
|
||||||
|
@ -56,14 +56,14 @@ impl<'a> PrivateMessageQueryBuilder<'a> {
|
||||||
PrivateMessageQueryBuilder {
|
PrivateMessageQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
recipient_id,
|
recipient_id,
|
||||||
unread_only: false,
|
unread_only: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unread_only(mut self, unread_only: bool) -> Self {
|
pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
|
||||||
self.unread_only = unread_only;
|
self.unread_only = unread_only.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ impl<'a> PrivateMessageQueryBuilder<'a> {
|
||||||
.into_boxed();
|
.into_boxed();
|
||||||
|
|
||||||
// If its unread, I only want the ones to me
|
// If its unread, I only want the ones to me
|
||||||
if self.unread_only {
|
if self.unread_only.unwrap_or(false) {
|
||||||
query = query
|
query = query
|
||||||
.filter(private_message::read.eq(false))
|
.filter(private_message::read.eq(false))
|
||||||
.filter(private_message::recipient_id.eq(self.recipient_id));
|
.filter(private_message::recipient_id.eq(self.recipient_id));
|
||||||
|
|
|
@ -94,10 +94,10 @@ impl CommunityView {
|
||||||
|
|
||||||
pub struct CommunityQueryBuilder<'a> {
|
pub struct CommunityQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
listing_type: &'a ListingType,
|
listing_type: Option<ListingType>,
|
||||||
sort: &'a SortType,
|
sort: Option<SortType>,
|
||||||
my_person_id: Option<PersonId>,
|
my_person_id: Option<PersonId>,
|
||||||
show_nsfw: bool,
|
show_nsfw: Option<bool>,
|
||||||
search_term: Option<String>,
|
search_term: Option<String>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
|
@ -108,27 +108,27 @@ impl<'a> CommunityQueryBuilder<'a> {
|
||||||
CommunityQueryBuilder {
|
CommunityQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
my_person_id: None,
|
my_person_id: None,
|
||||||
listing_type: &ListingType::All,
|
listing_type: None,
|
||||||
sort: &SortType::Hot,
|
sort: None,
|
||||||
show_nsfw: true,
|
show_nsfw: None,
|
||||||
search_term: None,
|
search_term: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listing_type(mut self, listing_type: &'a ListingType) -> Self {
|
pub fn listing_type<T: MaybeOptional<ListingType>>(mut self, listing_type: T) -> Self {
|
||||||
self.listing_type = listing_type;
|
self.listing_type = listing_type.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(mut self, sort: &'a SortType) -> Self {
|
pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
|
||||||
self.sort = sort;
|
self.sort = sort.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_nsfw(mut self, show_nsfw: bool) -> Self {
|
pub fn show_nsfw<T: MaybeOptional<bool>>(mut self, show_nsfw: T) -> Self {
|
||||||
self.show_nsfw = show_nsfw;
|
self.show_nsfw = show_nsfw.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ impl<'a> CommunityQueryBuilder<'a> {
|
||||||
.or_filter(community::description.ilike(searcher));
|
.or_filter(community::description.ilike(searcher));
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.sort {
|
match self.sort.unwrap_or(SortType::Hot) {
|
||||||
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()),
|
SortType::TopMonth => query = query.order_by(community_aggregates::users_active_month.desc()),
|
||||||
|
@ -198,15 +198,17 @@ impl<'a> CommunityQueryBuilder<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.show_nsfw {
|
if !self.show_nsfw.unwrap_or(true) {
|
||||||
query = query.filter(community::nsfw.eq(false));
|
query = query.filter(community::nsfw.eq(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
query = match self.listing_type {
|
if let Some(listing_type) = self.listing_type {
|
||||||
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
|
query = match listing_type {
|
||||||
ListingType::Local => query.filter(community::local.eq(true)),
|
ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)),
|
||||||
_ => query,
|
ListingType::Local => query.filter(community::local.eq(true)),
|
||||||
};
|
_ => query,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let (limit, offset) = limit_and_offset(self.page, self.limit);
|
let (limit, offset) = limit_and_offset(self.page, self.limit);
|
||||||
let res = query
|
let res = query
|
||||||
|
|
|
@ -155,8 +155,8 @@ pub struct PersonMentionQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
my_person_id: Option<PersonId>,
|
my_person_id: Option<PersonId>,
|
||||||
recipient_id: Option<PersonId>,
|
recipient_id: Option<PersonId>,
|
||||||
sort: &'a SortType,
|
sort: Option<SortType>,
|
||||||
unread_only: bool,
|
unread_only: Option<bool>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
}
|
}
|
||||||
|
@ -167,20 +167,20 @@ impl<'a> PersonMentionQueryBuilder<'a> {
|
||||||
conn,
|
conn,
|
||||||
my_person_id: None,
|
my_person_id: None,
|
||||||
recipient_id: None,
|
recipient_id: None,
|
||||||
sort: &SortType::New,
|
sort: None,
|
||||||
unread_only: false,
|
unread_only: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(mut self, sort: &'a SortType) -> Self {
|
pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
|
||||||
self.sort = sort;
|
self.sort = sort.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unread_only(mut self, unread_only: bool) -> Self {
|
pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
|
||||||
self.unread_only = unread_only;
|
self.unread_only = unread_only.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,11 +264,11 @@ impl<'a> PersonMentionQueryBuilder<'a> {
|
||||||
query = query.filter(person_mention::recipient_id.eq(recipient_id));
|
query = query.filter(person_mention::recipient_id.eq(recipient_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.unread_only {
|
if self.unread_only.unwrap_or(false) {
|
||||||
query = query.filter(person_mention::read.eq(false));
|
query = query.filter(person_mention::read.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
query = match self.sort {
|
query = match self.sort.unwrap_or(SortType::Hot) {
|
||||||
SortType::Hot | SortType::Active => query
|
SortType::Hot | SortType::Active => query
|
||||||
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
|
.order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
|
||||||
.then_order_by(comment_aggregates::published.desc()),
|
.then_order_by(comment_aggregates::published.desc()),
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl PersonViewSafe {
|
||||||
|
|
||||||
pub struct PersonQueryBuilder<'a> {
|
pub struct PersonQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
sort: &'a SortType,
|
sort: Option<SortType>,
|
||||||
search_term: Option<String>,
|
search_term: Option<String>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
|
@ -68,14 +68,14 @@ impl<'a> PersonQueryBuilder<'a> {
|
||||||
PersonQueryBuilder {
|
PersonQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
search_term: None,
|
search_term: None,
|
||||||
sort: &SortType::Hot,
|
sort: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(mut self, sort: &'a SortType) -> Self {
|
pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
|
||||||
self.sort = sort;
|
self.sort = sort.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ impl<'a> PersonQueryBuilder<'a> {
|
||||||
query = query.filter(person::name.ilike(fuzzy_search(&search_term)));
|
query = query.filter(person::name.ilike(fuzzy_search(&search_term)));
|
||||||
}
|
}
|
||||||
|
|
||||||
query = match self.sort {
|
query = match self.sort.unwrap_or(SortType::Hot) {
|
||||||
SortType::Hot => query
|
SortType::Hot => query
|
||||||
.order_by(person_aggregates::comment_score.desc())
|
.order_by(person_aggregates::comment_score.desc())
|
||||||
.then_order_by(person::published.desc()),
|
.then_order_by(person::published.desc()),
|
||||||
|
|
|
@ -90,11 +90,10 @@ async fn get_feed_data(
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let site_view = blocking(context.pool(), move |conn| SiteView::read(&conn)).await??;
|
let site_view = blocking(context.pool(), move |conn| SiteView::read(&conn)).await??;
|
||||||
|
|
||||||
let listing_type_ = listing_type.clone();
|
|
||||||
let posts = blocking(context.pool(), move |conn| {
|
let posts = blocking(context.pool(), move |conn| {
|
||||||
PostQueryBuilder::create(&conn)
|
PostQueryBuilder::create(&conn)
|
||||||
.listing_type(&listing_type_)
|
.listing_type(listing_type)
|
||||||
.sort(&sort_type)
|
.sort(sort_type)
|
||||||
.list()
|
.list()
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
@ -174,8 +173,8 @@ fn get_feed_user(
|
||||||
let person = Person::find_by_name(&conn, &user_name)?;
|
let person = Person::find_by_name(&conn, &user_name)?;
|
||||||
|
|
||||||
let posts = PostQueryBuilder::create(&conn)
|
let posts = PostQueryBuilder::create(&conn)
|
||||||
.listing_type(&ListingType::All)
|
.listing_type(ListingType::All)
|
||||||
.sort(sort_type)
|
.sort(*sort_type)
|
||||||
.creator_id(person.id)
|
.creator_id(person.id)
|
||||||
.list()?;
|
.list()?;
|
||||||
|
|
||||||
|
@ -200,8 +199,8 @@ fn get_feed_community(
|
||||||
let community = Community::read_from_name(&conn, &community_name)?;
|
let community = Community::read_from_name(&conn, &community_name)?;
|
||||||
|
|
||||||
let posts = PostQueryBuilder::create(&conn)
|
let posts = PostQueryBuilder::create(&conn)
|
||||||
.listing_type(&ListingType::All)
|
.listing_type(ListingType::All)
|
||||||
.sort(sort_type)
|
.sort(*sort_type)
|
||||||
.community_id(community.id)
|
.community_id(community.id)
|
||||||
.list()?;
|
.list()?;
|
||||||
|
|
||||||
|
@ -228,12 +227,17 @@ fn get_feed_front(
|
||||||
) -> Result<ChannelBuilder, LemmyError> {
|
) -> Result<ChannelBuilder, LemmyError> {
|
||||||
let site_view = SiteView::read(&conn)?;
|
let site_view = SiteView::read(&conn)?;
|
||||||
let local_user_id = LocalUserId(Claims::decode(&jwt)?.claims.sub);
|
let local_user_id = LocalUserId(Claims::decode(&jwt)?.claims.sub);
|
||||||
let person_id = LocalUser::read(&conn, local_user_id)?.person_id;
|
let local_user = LocalUser::read(&conn, local_user_id)?;
|
||||||
|
let person_id = local_user.person_id;
|
||||||
|
let show_bot_accounts = local_user.show_bot_accounts;
|
||||||
|
let show_read_posts = local_user.show_read_posts;
|
||||||
|
|
||||||
let posts = PostQueryBuilder::create(&conn)
|
let posts = PostQueryBuilder::create(&conn)
|
||||||
.listing_type(&ListingType::Subscribed)
|
.listing_type(ListingType::Subscribed)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.sort(sort_type)
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.show_read_posts(show_read_posts)
|
||||||
|
.sort(*sort_type)
|
||||||
.list()?;
|
.list()?;
|
||||||
|
|
||||||
let items = create_post_items(posts)?;
|
let items = create_post_items(posts)?;
|
||||||
|
@ -255,20 +259,23 @@ fn get_feed_front(
|
||||||
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
|
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
|
||||||
let site_view = SiteView::read(&conn)?;
|
let site_view = SiteView::read(&conn)?;
|
||||||
let local_user_id = LocalUserId(Claims::decode(&jwt)?.claims.sub);
|
let local_user_id = LocalUserId(Claims::decode(&jwt)?.claims.sub);
|
||||||
let person_id = LocalUser::read(&conn, local_user_id)?.person_id;
|
let local_user = LocalUser::read(&conn, local_user_id)?;
|
||||||
|
let person_id = local_user.person_id;
|
||||||
|
let show_bot_accounts = local_user.show_bot_accounts;
|
||||||
|
|
||||||
let sort = SortType::New;
|
let sort = SortType::New;
|
||||||
|
|
||||||
let replies = CommentQueryBuilder::create(&conn)
|
let replies = CommentQueryBuilder::create(&conn)
|
||||||
.recipient_id(person_id)
|
.recipient_id(person_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.sort(&sort)
|
.show_bot_accounts(show_bot_accounts)
|
||||||
|
.sort(sort)
|
||||||
.list()?;
|
.list()?;
|
||||||
|
|
||||||
let mentions = PersonMentionQueryBuilder::create(&conn)
|
let mentions = PersonMentionQueryBuilder::create(&conn)
|
||||||
.recipient_id(person_id)
|
.recipient_id(person_id)
|
||||||
.my_person_id(person_id)
|
.my_person_id(person_id)
|
||||||
.sort(&sort)
|
.sort(sort)
|
||||||
.list()?;
|
.list()?;
|
||||||
|
|
||||||
let items = create_reply_and_mention_items(replies, mentions)?;
|
let items = create_reply_and_mention_items(replies, mentions)?;
|
||||||
|
|
|
@ -49,6 +49,7 @@ impl Default for FederationConfig {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
allowed_instances: None,
|
allowed_instances: None,
|
||||||
blocked_instances: None,
|
blocked_instances: None,
|
||||||
|
strict_allowlist: Some(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ pub struct FederationConfig {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub allowed_instances: Option<Vec<String>>,
|
pub allowed_instances: Option<Vec<String>>,
|
||||||
pub blocked_instances: Option<Vec<String>>,
|
pub blocked_instances: Option<Vec<String>>,
|
||||||
|
pub strict_allowlist: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
|
|
@ -7,7 +7,7 @@ use regex::{Regex, RegexBuilder};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").expect("compile regex");
|
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").expect("compile regex");
|
||||||
static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().expect("compile regex");
|
static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|ni((g{2,}|q)+|[gq]{2,})[e3r]+(s|z)?|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().expect("compile regex");
|
||||||
static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").expect("compile regex");
|
static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").expect("compile regex");
|
||||||
// TODO keep this old one, it didn't work with port well tho
|
// TODO keep this old one, it didn't work with port well tho
|
||||||
// static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").expect("compile regex");
|
// static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").expect("compile regex");
|
||||||
|
|
|
@ -8,7 +8,7 @@ services:
|
||||||
- "8536:8536"
|
- "8536:8536"
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- RUST_LOG=debug
|
- RUST_LOG="warn,lemmy_server=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_apub_receive=debug,lemmy_db_queries=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug"
|
||||||
volumes:
|
volumes:
|
||||||
- ../lemmy.hjson:/config/config.hjson
|
- ../lemmy.hjson:/config/config.hjson
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
@ -43,7 +43,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- LEMMY_TEST_SEND_SYNC=1
|
- LEMMY_TEST_SEND_SYNC=1
|
||||||
- RUST_BACKTRACE=1
|
- RUST_BACKTRACE=1
|
||||||
- RUST_LOG=debug
|
- RUST_LOG="warn,lemmy_server=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_apub_receive=debug,lemmy_db_queries=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug"
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres_alpha
|
- postgres_alpha
|
||||||
ports:
|
ports:
|
||||||
|
@ -72,7 +72,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- LEMMY_TEST_SEND_SYNC=1
|
- LEMMY_TEST_SEND_SYNC=1
|
||||||
- RUST_BACKTRACE=1
|
- RUST_BACKTRACE=1
|
||||||
- RUST_LOG=debug
|
- RUST_LOG="warn,lemmy_server=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_apub_receive=debug,lemmy_db_queries=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug"
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres_beta
|
- postgres_beta
|
||||||
ports:
|
ports:
|
||||||
|
@ -101,7 +101,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- LEMMY_TEST_SEND_SYNC=1
|
- LEMMY_TEST_SEND_SYNC=1
|
||||||
- RUST_BACKTRACE=1
|
- RUST_BACKTRACE=1
|
||||||
- RUST_LOG=debug
|
- RUST_LOG="warn,lemmy_server=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_apub_receive=debug,lemmy_db_queries=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug"
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres_gamma
|
- postgres_gamma
|
||||||
ports:
|
ports:
|
||||||
|
@ -131,7 +131,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- LEMMY_TEST_SEND_SYNC=1
|
- LEMMY_TEST_SEND_SYNC=1
|
||||||
- RUST_BACKTRACE=1
|
- RUST_BACKTRACE=1
|
||||||
- RUST_LOG=debug
|
- RUST_LOG="warn,lemmy_server=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_apub_receive=debug,lemmy_db_queries=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug"
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres_delta
|
- postgres_delta
|
||||||
ports:
|
ports:
|
||||||
|
@ -161,7 +161,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- LEMMY_TEST_SEND_SYNC=1
|
- LEMMY_TEST_SEND_SYNC=1
|
||||||
- RUST_BACKTRACE=1
|
- RUST_BACKTRACE=1
|
||||||
- RUST_LOG=debug
|
- RUST_LOG="warn,lemmy_server=debug,lemmy_api=debug,lemmy_api_common=debug,lemmy_api_crud=debug,lemmy_apub=debug,lemmy_apub_receive=debug,lemmy_db_queries=debug,lemmy_db_schema=debug,lemmy_db_views=debug,lemmy_db_views_actor=debug,lemmy_db_views_moderator=debug,lemmy_routes=debug,lemmy_utils=debug,lemmy_websocket=debug"
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres_epsilon
|
- postgres_epsilon
|
||||||
ports:
|
ports:
|
||||||
|
|
|
@ -12,12 +12,12 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
lemmy:
|
lemmy:
|
||||||
image: dessalines/lemmy:0.10.3
|
image: dessalines/lemmy:0.11.0
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8536:8536"
|
- "127.0.0.1:8536:8536"
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- RUST_LOG=error
|
- RUST_LOG="warn,lemmy_server=info,lemmy_api=info,lemmy_api_common=info,lemmy_api_crud=info,lemmy_apub=info,lemmy_apub_receive=info,lemmy_db_queries=info,lemmy_db_schema=info,lemmy_db_views=info,lemmy_db_views_actor=info,lemmy_db_views_moderator=info,lemmy_routes=info,lemmy_utils=info,lemmy_websocket=info"
|
||||||
volumes:
|
volumes:
|
||||||
- ./lemmy.hjson:/config/config.hjson
|
- ./lemmy.hjson:/config/config.hjson
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -26,7 +26,7 @@ services:
|
||||||
- iframely
|
- iframely
|
||||||
|
|
||||||
lemmy-ui:
|
lemmy-ui:
|
||||||
image: dessalines/lemmy-ui:0.10.3
|
image: dessalines/lemmy-ui:0.11.0
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:1235:1234"
|
- "127.0.0.1:1235:1234"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
6
migrations/2021-03-31-105915_add_bot_account/down.sql
Normal file
6
migrations/2021-03-31-105915_add_bot_account/down.sql
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
drop view person_alias_1, person_alias_2;
|
||||||
|
alter table person drop column bot_account;
|
||||||
|
create view person_alias_1 as select * from person;
|
||||||
|
create view person_alias_2 as select * from person;
|
||||||
|
|
||||||
|
alter table local_user drop column show_bot_accounts;
|
8
migrations/2021-03-31-105915_add_bot_account/up.sql
Normal file
8
migrations/2021-03-31-105915_add_bot_account/up.sql
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
-- Add the bot_account column to the person table
|
||||||
|
drop view person_alias_1, person_alias_2;
|
||||||
|
alter table person add column bot_account boolean not null default false;
|
||||||
|
create view person_alias_1 as select * from person;
|
||||||
|
create view person_alias_2 as select * from person;
|
||||||
|
|
||||||
|
-- Add the show_bot_accounts to the local user table as a setting
|
||||||
|
alter table local_user add column show_bot_accounts boolean not null default true;
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE site DROP COLUMN community_creation_admin_only;
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE site ADD COLUMN community_creation_admin_only bool NOT NULL DEFAULT false;
|
|
@ -0,0 +1 @@
|
||||||
|
alter table local_user drop column show_read_posts;
|
|
@ -0,0 +1 @@
|
||||||
|
alter table local_user add column show_read_posts boolean default true not null;
|
Loading…
Reference in a new issue