Merge pull request 'Search Actor' (#870) from search-actor into main

Reviewed-on: #870
pull/885/head
KitaitiMakoto 3 years ago
commit 46fc030df4

@ -143,6 +143,7 @@ jobs:
cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
- run_with_coverage:
cmd: |
cargo run -p plume-cli --no-default-features --features=${FEATURES} -- migration run
cmd="cargo test --all --exclude plume-front --exclude plume-macro --no-run --no-default-features --features=${FEATURES} -j"
for i in 36 4 2 1 1; do
$cmd $i && break

@ -9,6 +9,7 @@
- Allow `dir` attributes for LtoR text in RtoL document (#860)
- More translation languages (#862)
- Proxy support (#829)
- Riker a actor system library (#870)
### Changed
@ -16,6 +17,7 @@
- Use tracing crate (#868)
- Update Rust version to nightly-2021-01-15 (#878)
- Upgrade Tantivy to 0.13.3 and lindera-tantivy to 0.7.1 (#878)
- Run searcher on actor system (#870)
### Fixed

289
Cargo.lock generated

@ -9,7 +9,7 @@ dependencies = [
"activitystreams-derive",
"activitystreams-traits",
"activitystreams-types",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
]
@ -32,7 +32,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542"
dependencies = [
"failure",
"serde",
"serde 1.0.118",
"serde_json",
]
@ -46,7 +46,7 @@ dependencies = [
"activitystreams-traits",
"chrono",
"mime 0.3.16",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
]
@ -126,6 +126,9 @@ name = "ahash"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
dependencies = [
"const-random",
]
[[package]]
name = "aho-corasick"
@ -168,6 +171,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "arc-swap"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabe5a181f83789739c194cbe5a897dde195078fac08568d09221fd6137a7ba8"
[[package]]
name = "array_tool"
version = "1.0.3"
@ -344,7 +353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
dependencies = [
"byteorder 1.3.4",
"serde",
"serde 1.0.118",
]
[[package]]
@ -516,8 +525,8 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"num-traits 0.2.14",
"serde 1.0.118",
"time",
"winapi 0.3.9",
]
@ -555,6 +564,44 @@ dependencies = [
"memchr",
]
[[package]]
name = "config"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
dependencies = [
"lazy_static",
"nom 5.1.2",
"rust-ini",
"serde 1.0.118",
"serde-hjson",
"serde_json",
"toml 0.5.8",
"yaml-rust",
]
[[package]]
name = "const-random"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4"
dependencies = [
"const-random-macro",
"proc-macro-hack 0.5.19",
]
[[package]]
name = "const-random-macro"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40"
dependencies = [
"getrandom 0.2.1",
"lazy_static",
"proc-macro-hack 0.5.19",
"tiny-keccak",
]
[[package]]
name = "const_fn"
version = "0.4.4"
@ -607,7 +654,7 @@ dependencies = [
"idna 0.1.5",
"log 0.4.11",
"publicsuffix",
"serde",
"serde 1.0.118",
"serde_json",
"time",
"try_from",
@ -789,6 +836,17 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
[[package]]
name = "dashmap"
version = "3.11.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f260e2fc850179ef410018660006951c1b55b79e8087e87111a2c388994b9b5"
dependencies = [
"ahash",
"cfg-if 0.1.10",
"num_cpus",
]
[[package]]
name = "data-encoding"
version = "2.1.2"
@ -1370,6 +1428,17 @@ dependencies = [
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
]
[[package]]
name = "gettext"
version = "0.3.0"
@ -1943,7 +2012,7 @@ dependencies = [
"log 0.4.11",
"native-tls",
"nom 4.2.3",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
]
@ -2010,7 +2079,7 @@ dependencies = [
"lindera-dictionary",
"lindera-ipadic",
"lindera-ipadic-builder",
"serde",
"serde 1.0.118",
"serde_json",
]
@ -2023,7 +2092,7 @@ dependencies = [
"bincode",
"byteorder 1.3.4",
"encoding",
"serde",
"serde 1.0.118",
"yada",
]
@ -2091,9 +2160,13 @@ dependencies = [
[[package]]
name = "linked-hash-map"
version = "0.5.3"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
dependencies = [
"serde 0.8.23",
"serde_test",
]
[[package]]
name = "lock_api"
@ -2152,7 +2225,7 @@ dependencies = [
"log 0.4.11",
"phf",
"phf_codegen",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
"string_cache",
@ -2504,7 +2577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg 1.0.1",
"num-traits",
"num-traits 0.2.14",
]
[[package]]
@ -2515,7 +2588,16 @@ checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
dependencies = [
"autocfg 1.0.1",
"num-integer",
"num-traits",
"num-traits 0.2.14",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
dependencies = [
"num-traits 0.2.14",
]
[[package]]
@ -2826,7 +2908,7 @@ dependencies = [
"chrono",
"indexmap",
"line-wrap",
"serde",
"serde 1.0.118",
"xml-rs",
]
@ -2854,6 +2936,7 @@ dependencies = [
"plume-api",
"plume-common",
"plume-models",
"riker",
"rocket",
"rocket_contrib",
"rocket_csrf",
@ -2862,7 +2945,7 @@ dependencies = [
"rsass",
"ructe",
"scheduled-thread-pool",
"serde",
"serde 1.0.118",
"serde_json",
"shrinkwraprs 0.2.3",
"tracing",
@ -2876,7 +2959,7 @@ dependencies = [
name = "plume-api"
version = "0.6.1-dev"
dependencies = [
"serde",
"serde 1.0.118",
"serde_derive",
]
@ -2909,7 +2992,7 @@ dependencies = [
"regex-syntax 0.6.21",
"reqwest 0.9.24",
"rocket",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
"shrinkwraprs 0.3.0",
@ -2926,7 +3009,7 @@ dependencies = [
"gettext-macros",
"gettext-utils",
"lazy_static",
"serde",
"serde 1.0.118",
"serde_json",
"stdweb",
"stdweb-internal-runtime",
@ -2961,15 +3044,17 @@ dependencies = [
"ldap3",
"lindera-tantivy",
"migrations_internals",
"once_cell",
"openssl",
"plume-api",
"plume-common",
"plume-macro",
"reqwest 0.9.24",
"riker",
"rocket",
"rocket_i18n",
"scheduled-thread-pool",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
"shrinkwraprs 0.2.3",
@ -3220,7 +3305,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"getrandom 0.1.15",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
@ -3268,7 +3353,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
"getrandom 0.1.15",
]
[[package]]
@ -3445,7 +3530,7 @@ dependencies = [
"mime 0.3.16",
"mime_guess 2.0.3",
"native-tls",
"serde",
"serde 1.0.118",
"serde_json",
"serde_urlencoded 0.5.5",
"socks",
@ -3484,7 +3569,7 @@ dependencies = [
"native-tls",
"percent-encoding 2.1.0",
"pin-project-lite 0.2.0",
"serde",
"serde 1.0.118",
"serde_urlencoded 0.7.0",
"tokio 0.2.24",
"tokio-tls",
@ -3495,6 +3580,38 @@ dependencies = [
"winreg 0.7.0",
]
[[package]]
name = "riker"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abff93ece5a5d3d7f2c54dfba7550657a644c9dc0a871c7ddf8c31381971c41b"
dependencies = [
"chrono",
"config",
"dashmap",
"futures 0.3.8",
"num_cpus",
"pin-utils",
"rand 0.7.3",
"regex",
"riker-macros",
"slog",
"slog-scope",
"slog-stdlog",
"uuid 0.8.1",
]
[[package]]
name = "riker-macros"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2a8e8f71c9e7980a596c39c7e3537ea8563054526e15712a610ac97a02dba15"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]]
name = "ring"
version = "0.13.5"
@ -3523,7 +3640,7 @@ dependencies = [
"rocket_http",
"state",
"time",
"toml",
"toml 0.4.10",
"version_check 0.9.2",
"yansi",
]
@ -3552,7 +3669,7 @@ dependencies = [
"log 0.4.11",
"notify",
"rocket",
"serde",
"serde 1.0.118",
"serde_json",
]
@ -3564,7 +3681,7 @@ dependencies = [
"data-encoding",
"ring",
"rocket",
"serde",
"serde 1.0.118",
"time",
]
@ -3623,7 +3740,7 @@ dependencies = [
"lazy_static",
"nom 4.2.3",
"num-rational",
"num-traits",
"num-traits 0.2.14",
"rand 0.6.5",
]
@ -3640,13 +3757,19 @@ dependencies = [
"nom 5.1.2",
]
[[package]]
name = "rust-ini"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
[[package]]
name = "rust-stemmers"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
dependencies = [
"serde",
"serde 1.0.118",
"serde_derive",
]
@ -3749,6 +3872,12 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
[[package]]
name = "serde"
version = "1.0.118"
@ -3758,6 +3887,19 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-hjson"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
dependencies = [
"lazy_static",
"linked-hash-map",
"num-traits 0.1.43",
"regex",
"serde 0.8.23",
]
[[package]]
name = "serde_derive"
version = "1.0.118"
@ -3777,7 +3919,16 @@ checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [
"itoa",
"ryu",
"serde",
"serde 1.0.118",
]
[[package]]
name = "serde_test"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
dependencies = [
"serde 0.8.23",
]
[[package]]
@ -3788,7 +3939,7 @@ checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
dependencies = [
"dtoa",
"itoa",
"serde",
"serde 1.0.118",
"url 1.7.2",
]
@ -3801,7 +3952,7 @@ dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
"serde 1.0.118",
]
[[package]]
@ -3878,6 +4029,34 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "slog"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06"
[[package]]
name = "slog-scope"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c44c89dd8b0ae4537d1ae318353eaf7840b4869c536e31c41e963d1ea523ee6"
dependencies = [
"arc-swap",
"lazy_static",
"slog",
]
[[package]]
name = "slog-stdlog"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8228ab7302adbf4fcb37e66f3cda78003feb521e7fd9e3847ec117a7784d0f5a"
dependencies = [
"log 0.4.11",
"slog",
"slog-scope",
]
[[package]]
name = "smallvec"
version = "0.6.13"
@ -3948,7 +4127,7 @@ checksum = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb"
dependencies = [
"discard",
"rustc_version",
"serde",
"serde 1.0.118",
"serde_json",
"stdweb-derive",
"stdweb-internal-macros",
@ -3964,7 +4143,7 @@ checksum = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"serde",
"serde 1.0.118",
"serde_derive",
"syn 0.15.44",
]
@ -3978,7 +4157,7 @@ dependencies = [
"base-x",
"proc-macro2 0.4.30",
"quote 0.6.13",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
"sha1",
@ -4010,7 +4189,7 @@ dependencies = [
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
"serde",
"serde 1.0.118",
"string_cache_codegen",
"string_cache_shared",
]
@ -4154,7 +4333,7 @@ dependencies = [
"onig",
"plist",
"regex-syntax 0.6.21",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
"walkdir",
@ -4194,7 +4373,7 @@ dependencies = [
"rayon",
"regex",
"rust-stemmers",
"serde",
"serde 1.0.118",
"serde_json",
"smallvec 1.5.1",
"snap",
@ -4322,6 +4501,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinyvec"
version = "1.1.0"
@ -4605,7 +4793,16 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
dependencies = [
"serde",
"serde 1.0.118",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde 1.0.118",
]
[[package]]
@ -4674,7 +4871,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
dependencies = [
"serde",
"serde 1.0.118",
"tracing-core",
]
@ -4689,7 +4886,7 @@ dependencies = [
"lazy_static",
"matchers",
"regex",
"serde",
"serde 1.0.118",
"serde_json",
"sharded-slab",
"smallvec 1.5.1",
@ -4875,7 +5072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
dependencies = [
"rand 0.7.3",
"serde",
"serde 1.0.118",
]
[[package]]
@ -4887,7 +5084,7 @@ dependencies = [
"idna 0.1.5",
"lazy_static",
"regex",
"serde",
"serde 1.0.118",
"serde_derive",
"serde_json",
"url 1.7.2",
@ -4989,7 +5186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
dependencies = [
"cfg-if 1.0.0",
"serde",
"serde 1.0.118",
"serde_json",
"wasm-bindgen-macro",
]
@ -5067,7 +5264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec24b1b0700d4b466d280228ed0f62274eedeaa80206820f071fdc8ed787b664"
dependencies = [
"reqwest 0.9.24",
"serde",
"serde 1.0.118",
"serde_derive",
]

@ -32,6 +32,7 @@ validator_derive = "0.8"
webfinger = "0.4.1"
tracing = "0.1.22"
tracing-subscriber = "0.2.15"
riker = "0.4.2"
[[bin]]
name = "plume"

@ -33,6 +33,8 @@ diesel-derive-newtype = "0.1.2"
glob = "0.3.0"
lindera-tantivy = { version = "0.7.1", optional = true }
tracing = "0.1.22"
riker = "0.4.2"
once_cell = "1.5.2"
[dependencies.chrono]
features = ["serde"]

@ -1,6 +1,6 @@
use crate::{
ap_url, instance::*, medias::Media, posts::Post, safe_string::SafeString, schema::blogs,
search::Searcher, users::User, Connection, Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE,
users::User, Connection, Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE,
};
use activitypub::{
actor::Group,
@ -317,9 +317,9 @@ impl Blog {
.and_then(|c| c.url().ok())
}
pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> {
pub fn delete(&self, conn: &Connection) -> Result<()> {
for post in Post::get_for_blog(conn, &self)? {
post.delete(conn, searcher)?;
post.delete(conn)?;
}
diesel::delete(self)
.execute(conn)
@ -497,10 +497,8 @@ pub(crate) mod tests {
use super::*;
use crate::{
blog_authors::*,
config::CONFIG,
instance::tests as instance_tests,
medias::NewMedia,
search::tests::get_searcher,
tests::{db, rockets},
users::tests as usersTests,
Connection as Conn,
@ -767,9 +765,7 @@ pub(crate) mod tests {
conn.test_transaction::<_, (), _>(|| {
let (_, blogs) = fill_database(conn);
blogs[0]
.delete(conn, &get_searcher(&CONFIG.search_tokenizers))
.unwrap();
blogs[0].delete(conn).unwrap();
assert!(Blog::get(conn, blogs[0].id).is_err());
Ok(())
})
@ -779,7 +775,6 @@ pub(crate) mod tests {
fn delete_via_user() {
let conn = &db();
conn.test_transaction::<_, (), _>(|| {
let searcher = get_searcher(&CONFIG.search_tokenizers);
let (user, _) = fill_database(conn);
let b1 = Blog::insert(
@ -836,10 +831,10 @@ pub(crate) mod tests {
)
.unwrap();
user[0].delete(conn, &searcher).unwrap();
user[0].delete(conn).unwrap();
assert!(Blog::get(conn, blog[0].id).is_ok());
assert!(Blog::get(conn, blog[1].id).is_err());
user[1].delete(conn, &searcher).unwrap();
user[1].delete(conn).unwrap();
assert!(Blog::get(conn, blog[0].id).is_err());
Ok(())
})
@ -886,7 +881,7 @@ pub(crate) mod tests {
let _: Blog = blogs[0].save_changes(conn).unwrap();
let ap_repr = blogs[0].to_activity(conn).unwrap();
blogs[0].delete(conn, &*r.searcher).unwrap();
blogs[0].delete(conn).unwrap();
let blog = Blog::from_activity(&r, ap_repr).unwrap();
assert_eq!(blog.actor_id, blogs[0].actor_id);

@ -97,7 +97,6 @@ pub(crate) mod tests {
source: String::new(),
cover_id: None,
},
&rockets.searcher,
)
.unwrap();

@ -17,7 +17,10 @@ extern crate serde_json;
#[macro_use]
extern crate tantivy;
use once_cell::sync::Lazy;
use plume_common::activity_pub::inbox::InboxError;
use posts::PostEvent;
use riker::actors::{channel, ActorSystem, ChannelRef, SystemBuilder};
#[cfg(not(any(feature = "sqlite", feature = "postgres")))]
compile_error!("Either feature \"sqlite\" or \"postgres\" must be enabled for this crate.");
@ -30,6 +33,16 @@ pub type Connection = diesel::SqliteConnection;
#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
pub type Connection = diesel::PgConnection;
pub(crate) static ACTOR_SYS: Lazy<ActorSystem> = Lazy::new(|| {
SystemBuilder::new()
.name("plume")
.create()
.expect("Failed to create actor system")
});
pub(crate) static POST_CHAN: Lazy<ChannelRef<PostEvent>> =
Lazy::new(|| channel("post_events", &*ACTOR_SYS).expect("Failed to create post channel"));
/// All the possible errors that can be encoutered in this crate
#[derive(Debug)]
pub enum Error {

@ -1,7 +1,7 @@
use crate::{
ap_url, blogs::Blog, instance::Instance, medias::Media, mentions::Mention, post_authors::*,
safe_string::SafeString, schema::posts, search::Searcher, tags::*, timeline::*, users::User,
Connection, Error, PlumeRocket, Result, CONFIG,
safe_string::SafeString, schema::posts, tags::*, timeline::*, users::User, Connection, Error,
PlumeRocket, PostEvent::*, Result, CONFIG, POST_CHAN,
};
use activitypub::{
activity::{Create, Delete, Update},
@ -19,11 +19,13 @@ use plume_common::{
},
utils::md_to_html,
};
use riker::actors::{Publish, Tell};
use std::collections::HashSet;
use std::sync::Arc;
pub type LicensedArticle = CustomObject<Licensed, Article>;
#[derive(Queryable, Identifiable, Clone, AsChangeset)]
#[derive(Queryable, Identifiable, Clone, AsChangeset, Debug)]
#[changeset_options(treat_none_as_null = "true")]
pub struct Post {
pub id: i32,
@ -62,7 +64,7 @@ impl Post {
find_by!(posts, find_by_ap_url, ap_url as &str);
last!(posts);
pub fn insert(conn: &Connection, new: NewPost, searcher: &Searcher) -> Result<Self> {
pub fn insert(conn: &Connection, new: NewPost) -> Result<Self> {
diesel::insert_into(posts::table)
.values(new)
.execute(conn)?;
@ -77,23 +79,29 @@ impl Post {
let _: Post = post.save_changes(conn)?;
}
searcher.add_document(conn, &post)?;
if post.published {
post.publish_published();
}
Ok(post)
}
pub fn update(&self, conn: &Connection, searcher: &Searcher) -> Result<Self> {
pub fn update(&self, conn: &Connection) -> Result<Self> {
diesel::update(self).set(self).execute(conn)?;
let post = Self::get(conn, self.id)?;
searcher.update_document(conn, &post)?;
// TODO: Call publish_published() when newly published
if post.published {
self.publish_updated();
}
Ok(post)
}
pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> {
pub fn delete(&self, conn: &Connection) -> Result<()> {
for m in Mention::list_for_post(&conn, self.id)? {
m.delete(conn)?;
}
diesel::delete(self).execute(conn)?;
searcher.delete_document(self);
self.publish_deleted();
Ok(())
}
@ -545,6 +553,36 @@ impl Post {
.set_to_link_vec(vec![Id::new(PUBLIC_VISIBILITY)])?;
Ok(act)
}
fn publish_published(&self) {
POST_CHAN.tell(
Publish {
msg: PostPublished(Arc::new(self.clone())),
topic: "post.published".into(),
},
None,
)
}
fn publish_updated(&self) {
POST_CHAN.tell(
Publish {
msg: PostUpdated(Arc::new(self.clone())),
topic: "post.updated".into(),
},
None,
)
}
fn publish_deleted(&self) {
POST_CHAN.tell(
Publish {
msg: PostDeleted(Arc::new(self.clone())),
topic: "post.deleted".into(),
},
None,
)
}
}
impl FromId<PlumeRocket> for Post {
@ -557,7 +595,6 @@ impl FromId<PlumeRocket> for Post {
fn from_activity(c: &PlumeRocket, article: LicensedArticle) -> Result<Self> {
let conn = &*c.conn;
let searcher = &c.searcher;
let license = article.custom_props.license_string().unwrap_or_default();
let article = article.object;
@ -605,7 +642,6 @@ impl FromId<PlumeRocket> for Post {
source: article.ap_object_props.source_object::<Source>()?.content,
cover_id: cover,
},
searcher,
)?;
for author in authors {
@ -670,7 +706,7 @@ impl AsObject<User, Delete, &PlumeRocket> for Post {
.into_iter()
.any(|a| actor.id == a.id);
if can_delete {
self.delete(&c.conn, &c.searcher).map(|_| ())
self.delete(&c.conn).map(|_| ())
} else {
Err(Error::Unauthorized)
}
@ -727,7 +763,6 @@ impl AsObject<User, Update, &PlumeRocket> for PostUpdate {
fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> {
let conn = &*c.conn;
let searcher = &c.searcher;
let mut post = Post::from_id(c, &self.ap_url, None, CONFIG.proxy()).map_err(|(_, e)| e)?;
if !post.is_author(conn, actor.id)? {
@ -789,7 +824,7 @@ impl AsObject<User, Update, &PlumeRocket> for PostUpdate {
post.update_hashtags(conn, hashtags)?;
}
post.update(conn, searcher)?;
post.update(conn)?;
Ok(())
}
}
@ -800,6 +835,25 @@ impl IntoId for Post {
}
}
#[derive(Clone, Debug)]
pub enum PostEvent {
PostPublished(Arc<Post>),
PostUpdated(Arc<Post>),
PostDeleted(Arc<Post>),
}
impl From<PostEvent> for Arc<Post> {
fn from(event: PostEvent) -> Self {
use PostEvent::*;
match event {
PostPublished(post) => post,
PostUpdated(post) => post,
PostDeleted(post) => post,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -831,7 +885,6 @@ mod tests {
source: "Hello".into(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
PostAuthor::insert(
@ -843,7 +896,7 @@ mod tests {
)
.unwrap();
let create = post.create_activity(conn).unwrap();
post.delete(conn, &r.searcher).unwrap();
post.delete(conn).unwrap();
match inbox(&r, serde_json::to_value(create).unwrap()).unwrap() {
InboxResult::Post(p) => {

@ -0,0 +1,207 @@
use super::Searcher;
use crate::{db_conn::DbPool, posts::PostEvent, ACTOR_SYS, POST_CHAN};
use riker::actors::{Actor, ActorFactoryArgs, ActorRefFactory, Context, Sender, Subscribe, Tell};
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
use tracing::error;
pub struct SearchActor {
searcher: Arc<Searcher>,
conn: DbPool,
}
impl SearchActor {
pub fn init(searcher: Arc<Searcher>, conn: DbPool) {
ACTOR_SYS
.actor_of_args::<SearchActor, _>("search", (searcher, conn))
.expect("Failed to initialize searcher actor");
}
}
impl Actor for SearchActor {
type Msg = PostEvent;
fn pre_start(&mut self, ctx: &Context<Self::Msg>) {
POST_CHAN.tell(
Subscribe {
actor: Box::new(ctx.myself()),
topic: "*".into(),
},
None,
)
}
fn recv(&mut self, _ctx: &Context<Self::Msg>, msg: Self::Msg, _sender: Sender) {
use PostEvent::*;
// Wait for transaction commited
sleep(Duration::from_millis(500));
match msg {
PostPublished(post) => {
let conn = self.conn.get();
match conn {
Ok(conn) => {
self.searcher
.add_document(&conn, &post)
.unwrap_or_else(|e| error!("{:?}", e));
}
_ => {
error!("Failed to get database connection");
}
}
}
PostUpdated(post) => {
let conn = self.conn.get();
match conn {
Ok(_) => {
self.searcher
.update_document(&conn.unwrap(), &post)
.unwrap_or_else(|e| error!("{:?}", e));
}
_ => {
error!("Failed to get database connection");
}
}
}
PostDeleted(post) => self.searcher.delete_document(&post),
}
}
}
impl ActorFactoryArgs<(Arc<Searcher>, DbPool)> for SearchActor {
fn create_args((searcher, conn): (Arc<Searcher>, DbPool)) -> Self {
Self { searcher, conn }
}
}
#[cfg(test)]
mod tests {
use crate::diesel::Connection;
use crate::diesel::RunQueryDsl;
use crate::{
blog_authors::{BlogAuthor, NewBlogAuthor},
blogs::{Blog, NewBlog},
db_conn::{DbPool, PragmaForeignKey},
instance::{Instance, NewInstance},
post_authors::{NewPostAuthor, PostAuthor},
posts::{NewPost, Post},
safe_string::SafeString,
search::{actor::SearchActor, tests::get_searcher, Query},
users::{NewUser, User},
Connection as Conn, CONFIG,
};
use diesel::r2d2::ConnectionManager;
use plume_common::utils::random_hex;
use std::str::FromStr;
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
#[test]
fn post_updated() {
// Need to commit so that searcher on another thread retrieve records.
// So, build DbPool instead of using DB_POOL for testing.
let manager = ConnectionManager::<Conn>::new(CONFIG.database_url.as_str());
let db_pool = DbPool::builder()
.connection_customizer(Box::new(PragmaForeignKey))
.build(manager)
.unwrap();
let searcher = Arc::new(get_searcher(&CONFIG.search_tokenizers));
SearchActor::init(searcher.clone(), db_pool.clone());
let conn = db_pool.clone().get().unwrap();
let title = random_hex()[..8].to_owned();
let (instance, user, blog) = fill_database(&conn);
let author = &blog.list_authors(&conn).unwrap()[0];
let post = Post::insert(
&conn,
NewPost {
blog_id: blog.id,
slug: title.clone(),
title: title.clone(),
content: SafeString::new(""),
published: true,
license: "CC-BY-SA".to_owned(),
ap_url: "".to_owned(),
creation_date: None,
subtitle: "".to_owned(),
source: "".to_owned(),
cover_id: None,
},
)
.unwrap();
PostAuthor::insert(
&conn,
NewPostAuthor {
post_id: post.id,
author_id: author.id,
},
)
.unwrap();
let post_id = post.id;
// Wait for searcher on another thread add document asynchronously
sleep(Duration::from_millis(700));
searcher.commit();
assert_eq!(
searcher.search_document(&conn, Query::from_str(&title).unwrap(), (0, 1))[0].id,
post_id
);
// TODO: Make sure records are deleted even when assertion failed
post.delete(&conn).unwrap();
blog.delete(&conn).unwrap();
user.delete(&conn).unwrap();
diesel::delete(&instance).execute(&conn).unwrap();
}
fn fill_database(conn: &Conn) -> (Instance, User, Blog) {
conn.transaction::<(Instance, User, Blog), diesel::result::Error, _>(|| {
let instance = Instance::insert(
conn,
NewInstance {
default_license: "CC-0-BY-SA".to_string(),
local: true,
long_description: SafeString::new("Good morning"),
long_description_html: "<p>Good morning</p>".to_string(),
short_description: SafeString::new("Hello"),
short_description_html: "<p>Hello</p>".to_string(),
name: random_hex().to_string(),
open_registrations: true,
public_domain: random_hex().to_string(),
},
)
.unwrap();
let mut user = NewUser::default();
user.instance_id = instance.id;
user.username = random_hex().to_string();
user.ap_url = random_hex().to_string();
user.inbox_url = random_hex().to_string();
user.outbox_url = random_hex().to_string();
user.followers_endpoint = random_hex().to_string();
let user = User::insert(conn, user).unwrap();
let mut blog = NewBlog::default();
blog.instance_id = instance.id;
blog.actor_id = random_hex().to_string();
blog.ap_url = random_hex().to_string();
blog.inbox_url = random_hex().to_string();
blog.outbox_url = random_hex().to_string();
let blog = Blog::insert(conn, blog).unwrap();
BlogAuthor::insert(
conn,
NewBlogAuthor {
blog_id: blog.id,
author_id: user.id,
is_owner: true,
},
)
.unwrap();
Ok((instance, user, blog))
})
.unwrap()
}
}

@ -1,3 +1,4 @@
pub mod actor;
mod query;
mod searcher;
mod tokenizer;
@ -7,12 +8,7 @@ pub use self::tokenizer::TokenizerKind;
#[cfg(test)]
pub(crate) mod tests {
use super::{Query, Searcher, TokenizerKind};
use diesel::Connection;
use plume_common::utils::random_hex;
use std::env::temp_dir;
use std::str::FromStr;
use super::{Query, Searcher};
use crate::{
blogs::tests::fill_database,
config::SearchTokenizerConfig,
@ -22,6 +18,10 @@ pub(crate) mod tests {
tests::db,
CONFIG,
};
use diesel::Connection;
use plume_common::utils::random_hex;
use std::env::temp_dir;
use std::str::FromStr;
pub(crate) fn get_searcher(tokenizers: &SearchTokenizerConfig) -> Searcher {
let dir = temp_dir().join(&format!("plume-test-{}", random_hex()));
@ -144,7 +144,6 @@ pub(crate) mod tests {
source: "".to_owned(),
cover_id: None,
},
&searcher,
)
.unwrap();
PostAuthor::insert(
@ -155,7 +154,7 @@ pub(crate) mod tests {
},
)
.unwrap();
searcher.add_document(&conn, &post).unwrap();
searcher.commit();
assert_eq!(
searcher.search_document(conn, Query::from_str(&title).unwrap(), (0, 1))[0].id,
@ -164,7 +163,8 @@ pub(crate) mod tests {
let newtitle = random_hex()[..8].to_owned();
post.title = newtitle.clone();
post.update(conn, &searcher).unwrap();
post.update(conn).unwrap();
searcher.update_document(conn, &post).unwrap();
searcher.commit();
assert_eq!(
searcher.search_document(conn, Query::from_str(&newtitle).unwrap(), (0, 1))[0].id,
@ -174,7 +174,7 @@ pub(crate) mod tests {
.search_document(conn, Query::from_str(&title).unwrap(), (0, 1))
.is_empty());
post.delete(conn, &searcher).unwrap();
searcher.delete_document(&post);
searcher.commit();
assert!(searcher
.search_document(conn, Query::from_str(&newtitle).unwrap(), (0, 1))
@ -213,7 +213,6 @@ pub(crate) mod tests {
source: "".to_owned(),
cover_id: None,
},
&searcher,
)
.unwrap();

@ -1,15 +1,17 @@
use crate::{
config::SearchTokenizerConfig, instance::Instance, posts::Post, schema::posts,
search::query::PlumeQuery, tags::Tag, Connection, Result,
search::query::PlumeQuery, tags::Tag, Connection, Error, Result,
};
use chrono::Datelike;
use chrono::{Datelike, Utc};
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use itertools::Itertools;
use std::fs;
use std::{cmp, fs::create_dir_all, io, path::Path, sync::Mutex};
use tantivy::{
collector::TopDocs, directory::MmapDirectory, schema::*, Index, IndexReader, IndexWriter,
ReloadPolicy, TantivyError, Term,
};
use tracing::warn;
use whatlang::{detect as detect_lang, Lang};
#[derive(Debug)]
@ -67,6 +69,58 @@ impl Searcher {
schema_builder.build()
}
pub fn open_or_recreate(path: &dyn AsRef<Path>, tokenizers: &SearchTokenizerConfig) -> Self {
let mut open_searcher = Self::open(path, tokenizers);
if let Err(Error::Search(SearcherError::InvalidIndexDataError)) = open_searcher {
if Self::create(path, tokenizers).is_err() {
let backup_path = format!("{}.{}", path.as_ref().display(), Utc::now().timestamp());
let backup_path = Path::new(&backup_path);
fs::rename(path, backup_path)
.expect("main: error on backing up search index directory for recreating");
if Self::create(path, tokenizers).is_ok() {
if fs::remove_dir_all(backup_path).is_err() {
warn!(
"error on removing backup directory: {}. it remains",
backup_path.display()
);
}
} else {
panic!("main: error on recreating search index in new index format. remove search index and run `plm search init` manually");
}
}
open_searcher = Self::open(path, tokenizers);
}
match open_searcher {
Ok(s) => s,
Err(Error::Search(e)) => match e {
SearcherError::WriteLockAcquisitionError => panic!(
r#"
Your search index is locked. Plume can't start. To fix this issue
make sure no other Plume instance is started, and run:
plm search unlock
Then try to restart Plume.
"#
),
SearcherError::IndexOpeningError => panic!(
r#"
Plume was unable to open the search index. If you created the index
before, make sure to run Plume in the same directory it was created in, or
to set SEARCH_INDEX accordingly. If you did not yet create the search
index, run this command:
plm search init
Then try to restart Plume
"#
),
e => Err(e).unwrap(),
},
_ => panic!("Unexpected error while opening search index"),
}
}
pub fn create(path: &dyn AsRef<Path>, tokenizers: &SearchTokenizerConfig) -> Result<Self> {
let schema = Self::schema();

@ -408,7 +408,6 @@ mod tests {
source: "you must say GNU/Linux, not Linux!!!".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
assert!(gnu_tl.matches(r, &gnu_post, Kind::Original).unwrap());
@ -428,7 +427,6 @@ mod tests {
source: "so is Microsoft".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
assert!(!gnu_tl.matches(r, &non_free_post, Kind::Original).unwrap());
@ -481,7 +479,6 @@ mod tests {
subtitle: "".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
assert!(my_tl.matches(r, &post, Kind::Original).unwrap()); // matches because of "blog in fav_blogs" (and there is no cover)
@ -503,7 +500,6 @@ mod tests {
subtitle: "".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
assert!(!my_tl.matches(r, &post, Kind::Like(&users[1])).unwrap());
@ -549,7 +545,6 @@ mod tests {
source: "you must say GNU/Linux, not Linux!!!".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
@ -568,7 +563,6 @@ mod tests {
source: "so is Microsoft".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
@ -608,7 +602,6 @@ mod tests {
source: "you must say GNU/Linux, not Linux!!!".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
gnu_post
@ -745,7 +738,6 @@ mod tests {
source: "you must say GNU/Linux, not Linux!!!".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();
gnu_post.update_tags(conn, vec![Tag::build_activity("free".to_owned()).unwrap()]).unwrap();
@ -779,7 +771,6 @@ mod tests {
source: "you must say GNU/Linux, not Linux!!!".to_string(),
cover_id: None,
},
&r.searcher,
)
.unwrap();

@ -1,8 +1,8 @@
use crate::{
ap_url, blocklisted_emails::BlocklistedEmail, blogs::Blog, db_conn::DbConn, follows::Follow,
instance::*, medias::Media, notifications::Notification, post_authors::PostAuthor, posts::Post,
safe_string::SafeString, schema::users, search::Searcher, timeline::Timeline, Connection,
Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE,
safe_string::SafeString, schema::users, timeline::Timeline, Connection, Error, PlumeRocket,
Result, CONFIG, ITEMS_PER_PAGE,
};
use activitypub::{
activity::Delete,
@ -129,14 +129,14 @@ impl User {
.map_err(Error::from)
}
pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> {
pub fn delete(&self, conn: &Connection) -> Result<()> {
use crate::schema::post_authors;
for blog in Blog::find_for_author(conn, self)?
.iter()
.filter(|b| b.count_authors(conn).map(|c| c <= 1).unwrap_or(false))
{
blog.delete(conn, searcher)?;
blog.delete(conn)?;
}
// delete the posts if they is the only author
let all_their_posts_ids: Vec<i32> = post_authors::table
@ -156,7 +156,7 @@ impl User {
.unwrap_or(&0)
> &0;
if !has_other_authors {
Post::get(conn, post_id)?.delete(conn, searcher)?;
Post::get(conn, post_id)?.delete(conn)?;
}
}
@ -1037,7 +1037,7 @@ impl AsObject<User, Delete, &PlumeRocket> for User {
fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> {
if self.id == actor.id {
self.delete(&c.conn, &c.searcher).map(|_| ())
self.delete(&c.conn).map(|_| ())
} else {
Err(Error::Unauthorized)
}
@ -1130,9 +1130,7 @@ impl NewUser {
pub(crate) mod tests {
use super::*;
use crate::{
config::CONFIG,
instance::{tests as instance_tests, Instance},
search::tests::get_searcher,
tests::{db, rockets},
Connection as Conn,
};
@ -1227,9 +1225,7 @@ pub(crate) mod tests {
let inserted = fill_database(conn);
assert!(User::get(conn, inserted[0].id).is_ok());
inserted[0]
.delete(conn, &get_searcher(&CONFIG.search_tokenizers))
.unwrap();
inserted[0].delete(conn).unwrap();
assert!(User::get(conn, inserted[0].id).is_err());
Ok(())
});
@ -1319,7 +1315,7 @@ pub(crate) mod tests {
let users = fill_database(conn);
let ap_repr = users[0].to_activity(conn).unwrap();
users[0].delete(conn, &*r.searcher).unwrap();
users[0].delete(conn).unwrap();
let user = User::from_activity(&r, ap_repr).unwrap();
assert_eq!(user.username, users[0].username);

@ -10,12 +10,17 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((n == 3) ? 3 : ((n == 6) ? 4 : 5))));\n"
"Plural-Forms: nplurals=6; plural=(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? "
"2 : ((n == 3) ? 3 : ((n == 6) ? 4 : 5))));\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: plume\n"
"X-Crowdin-Language: cy\n"
"X-Crowdin-File: /master/po/plume-front/plume-front.pot\n"
# plume-front/src/editor.rs:189
msgid "Do you want to load the local autosave last edited at {}?"
msgstr ""
# plume-front/src/editor.rs:114
msgid "Open the rich text editor"
msgstr ""
@ -24,8 +29,8 @@ msgstr ""
msgid "Title"
msgstr ""
# plume-front/src/editor.rs:147
msgid "Subtitle or summary"
# plume-front/src/editor.rs:319
msgid "Subtitle, or summary"
msgstr ""
# plume-front/src/editor.rs:154
@ -55,4 +60,3 @@ msgstr ""
# plume-front/src/editor.rs:259
msgid "Publish"
msgstr ""

@ -12,46 +12,46 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
# plume-front/src/editor.rs:189
# plume-front/src/editor.rs:188
msgid "Do you want to load the local autosave last edited at {}?"
msgstr ""
# plume-front/src/editor.rs:282
# plume-front/src/editor.rs:281
msgid "Open the rich text editor"
msgstr ""
# plume-front/src/editor.rs:315
# plume-front/src/editor.rs:314
msgid "Title"
msgstr ""
# plume-front/src/editor.rs:319
# plume-front/src/editor.rs:318
msgid "Subtitle, or summary"
msgstr ""
# plume-front/src/editor.rs:326
# plume-front/src/editor.rs:325
msgid "Write your article here. Markdown is supported."
msgstr ""
# plume-front/src/editor.rs:337
# plume-front/src/editor.rs:336
msgid "Around {} characters left"
msgstr ""
# plume-front/src/editor.rs:414
# plume-front/src/editor.rs:413
msgid "Tags"
msgstr ""
# plume-front/src/editor.rs:415
# plume-front/src/editor.rs:414
msgid "License"
msgstr ""
# plume-front/src/editor.rs:418
# plume-front/src/editor.rs:417
msgid "Cover"
msgstr ""
# plume-front/src/editor.rs:438
# plume-front/src/editor.rs:437
msgid "This is a draft"
msgstr ""
# plume-front/src/editor.rs:445
# plume-front/src/editor.rs:444
msgid "Publish"
msgstr ""

@ -72,27 +72,27 @@ msgstr ""
msgid "Your blog was successfully created!"
msgstr ""
# src/routes/blogs.rs:160
# src/routes/blogs.rs:159
msgid "Your blog was deleted."
msgstr ""
# src/routes/blogs.rs:168
# src/routes/blogs.rs:167
msgid "You are not allowed to delete this blog."
msgstr ""
# src/routes/blogs.rs:219
# src/routes/blogs.rs:218
msgid "You are not allowed to edit this blog."
msgstr ""
# src/routes/blogs.rs:275
# src/routes/blogs.rs:274
msgid "You can't use this media as a blog icon."
msgstr ""
# src/routes/blogs.rs:293
# src/routes/blogs.rs:292
msgid "You can't use this media as a blog banner."
msgstr ""
# src/routes/blogs.rs:327
# src/routes/blogs.rs:326
msgid "Your blog information have been updated."
msgstr ""
@ -104,39 +104,39 @@ msgstr ""
msgid "Your comment has been deleted."
msgstr ""
# src/routes/instance.rs:119
# src/routes/instance.rs:118
msgid "Instance settings have been saved."
msgstr ""
# src/routes/instance.rs:151
# src/routes/instance.rs:150
msgid "{} has been unblocked."
msgstr ""
# src/routes/instance.rs:153
# src/routes/instance.rs:152
msgid "{} has been blocked."
msgstr ""
# src/routes/instance.rs:202
# src/routes/instance.rs:201
msgid "Blocks deleted"
msgstr ""
# src/routes/instance.rs:217
# src/routes/instance.rs:216
msgid "Email already blocked"
msgstr ""
# src/routes/instance.rs:222
# src/routes/instance.rs:221
msgid "Email Blocked"
msgstr ""
# src/routes/instance.rs:313
# src/routes/instance.rs:312
msgid "You can't change your own rights."
msgstr ""
# src/routes/instance.rs:324
# src/routes/instance.rs:323
msgid "You are not allowed to take this action."
msgstr ""
# src/routes/instance.rs:361
# src/routes/instance.rs:359
msgid "Done."
msgstr ""
@ -188,31 +188,31 @@ msgstr ""
msgid "You are not allowed to publish on this blog."
msgstr ""
# src/routes/posts.rs:364
# src/routes/posts.rs:363
msgid "Your article has been updated."
msgstr ""
# src/routes/posts.rs:555
# src/routes/posts.rs:553
msgid "Your article has been saved."
msgstr ""
# src/routes/posts.rs:562
# src/routes/posts.rs:560
msgid "New article"
msgstr ""
# src/routes/posts.rs:599
# src/routes/posts.rs:597
msgid "You are not allowed to delete this article."
msgstr ""
# src/routes/posts.rs:624
# src/routes/posts.rs:622
msgid "Your article has been deleted."
msgstr ""
# src/routes/posts.rs:629
# src/routes/posts.rs:627
msgid "It looks like the article you tried to delete doesn't exist. Maybe it is already gone?"
msgstr ""
# src/routes/posts.rs:669
# src/routes/posts.rs:667
msgid "Couldn't obtain enough information about your account. Please make sure your username is correct."
msgstr ""

@ -105,7 +105,6 @@ pub fn create(
rockets: PlumeRocket,
) -> Api<PostData> {
let conn = &*rockets.conn;
let search = &rockets.searcher;
let worker = &rockets.worker;
let author = User::get(conn, auth.0.user_id)?;
@ -155,7 +154,6 @@ pub fn create(
source: payload.source.clone(),
cover_id: payload.cover_id,
},
search,
)?;
PostAuthor::insert(
@ -232,7 +230,7 @@ pub fn delete(auth: Authorization<Write, Post>, rockets: PlumeRocket, id: i32) -
let author = User::get(&*rockets.conn, auth.0.user_id)?;
if let Ok(post) = Post::get(&*rockets.conn, id) {
if post.is_author(&*rockets.conn, author.id).unwrap_or(false) {
post.delete(&*rockets.conn, &rockets.searcher)?;
post.delete(&*rockets.conn)?;
}
}
Ok(Json(()))

@ -10,20 +10,17 @@ extern crate serde_json;
#[macro_use]
extern crate validator_derive;
use chrono::Utc;
use clap::App;
use diesel::r2d2::ConnectionManager;
use plume_models::{
db_conn::{DbPool, PragmaForeignKey},
instance::Instance,
migrations::IMPORTED_MIGRATIONS,
search::{Searcher as UnmanagedSearcher, SearcherError},
Connection, Error, CONFIG,
search::{actor::SearchActor, Searcher as UnmanagedSearcher},
Connection, CONFIG,
};
use rocket_csrf::CsrfFairingBuilder;
use scheduled_thread_pool::ScheduledThreadPool;
use std::fs;
use std::path::Path;
use std::process::exit;
use std::sync::{Arc, Mutex};
use std::time::Duration;
@ -103,59 +100,11 @@ Then try to restart Plume.
}
let workpool = ScheduledThreadPool::with_name("worker {}", num_cpus::get());
// we want a fast exit here, so
let mut open_searcher =
UnmanagedSearcher::open(&CONFIG.search_index, &CONFIG.search_tokenizers);
if let Err(Error::Search(SearcherError::InvalidIndexDataError)) = open_searcher {
if UnmanagedSearcher::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_err() {
let current_path = Path::new(&CONFIG.search_index);
let backup_path = format!("{}.{}", &current_path.display(), Utc::now().timestamp());
let backup_path = Path::new(&backup_path);
fs::rename(current_path, backup_path)
.expect("main: error on backing up search index directory for recreating");
if UnmanagedSearcher::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_ok() {
if fs::remove_dir_all(backup_path).is_err() {
warn!(
"error on removing backup directory: {}. it remains",
backup_path.display()
);
}
} else {
panic!("main: error on recreating search index in new index format. remove search index and run `plm search init` manually");
}
}
open_searcher = UnmanagedSearcher::open(&CONFIG.search_index, &CONFIG.search_tokenizers);
}
#[allow(clippy::match_wild_err_arm)]
let searcher = match open_searcher {
Err(Error::Search(e)) => match e {
SearcherError::WriteLockAcquisitionError => panic!(
r#"
Your search index is locked. Plume can't start. To fix this issue
make sure no other Plume instance is started, and run:
plm search unlock
Then try to restart Plume.
"#
),
SearcherError::IndexOpeningError => panic!(
r#"
Plume was unable to open the search index. If you created the index
before, make sure to run Plume in the same directory it was created in, or
to set SEARCH_INDEX accordingly. If you did not yet create the search
index, run this command:
plm search init
Then try to restart Plume
"#
),
e => Err(e).unwrap(),
},
Err(_) => panic!("Unexpected error while opening search index"),
Ok(s) => Arc::new(s),
};
let searcher = Arc::new(UnmanagedSearcher::open_or_recreate(
&CONFIG.search_index,
&CONFIG.search_tokenizers,
));
SearchActor::init(searcher.clone(), dbpool.clone());
let commiter = searcher.clone();
workpool.execute_with_fixed_delay(
Duration::from_secs(5),

@ -153,8 +153,7 @@ pub fn delete(name: String, rockets: PlumeRocket) -> RespondOrRedirect {
.and_then(|u| u.is_author_in(&*conn, &blog).ok())
.unwrap_or(false)
{
blog.delete(&conn, &rockets.searcher)
.expect("blog::expect: deletion error");
blog.delete(&conn).expect("blog::expect: deletion error");
Flash::success(
Redirect::to(uri!(super::instance::index)),
i18n!(rockets.intl.catalog, "Your blog was deleted."),

@ -21,7 +21,6 @@ use plume_models::{
instance::*,
posts::Post,
safe_string::SafeString,
search::Searcher,
timeline::Timeline,
users::{Role, User},
Connection, Error, PlumeRocket, CONFIG,
@ -331,7 +330,6 @@ pub fn edit_users(
}
let conn = &rockets.conn;
let searcher = &*rockets.searcher;
let worker = &*rockets.worker;
match form.action {
UserActions::Admin => {
@ -351,7 +349,7 @@ pub fn edit_users(
}
UserActions::Ban => {
for u in form.ids.clone() {
ban(u, conn, searcher, worker)?;
ban(u, conn, worker)?;
}
}
}
@ -362,14 +360,9 @@ pub fn edit_users(
))
}
fn ban(
id: i32,
conn: &Connection,
searcher: &Searcher,
worker: &ScheduledThreadPool,
) -> Result<(), ErrorPage> {
fn ban(id: i32, conn: &Connection, worker: &ScheduledThreadPool) -> Result<(), ErrorPage> {
let u = User::get(&*conn, id)?;
u.delete(&*conn, searcher)?;
u.delete(&*conn)?;
if Instance::get_local()
.map(|i| u.instance_id == i.id)
.unwrap_or(false)

@ -298,8 +298,7 @@ pub fn update(
post.source = form.content.clone();
post.license = form.license.clone();
post.cover_id = form.cover;
post.update(&*conn, &rockets.searcher)
.expect("post::update: update error");
post.update(&*conn).expect("post::update: update error");
if post.published {
post.update_mentions(
@ -481,7 +480,6 @@ pub fn create(
source: form.content.clone(),
cover_id: form.cover,
},
&rockets.searcher,
)
.expect("post::create: post save error");

@ -421,7 +421,7 @@ pub fn delete(
) -> Result<Flash<Redirect>, ErrorPage> {
let account = User::find_by_fqn(&rockets, &name)?;
if user.id == account.id {
account.delete(&*rockets.conn, &rockets.searcher)?;
account.delete(&*rockets.conn)?;
let target = User::one_by_instance(&*rockets.conn)?;
let delete_act = account.delete_activity(&*rockets.conn)?;

Loading…
Cancel
Save