Merge pull request #70 from Plume-org/mentions

Mentions
This commit is contained in:
Baptiste Gelez 2018-06-21 11:27:48 +01:00 committed by GitHub
commit dbdcbe7104
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 319 additions and 215 deletions

137
Cargo.lock generated
View File

@ -71,14 +71,6 @@ dependencies = [
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "antidote" name = "antidote"
version = "1.0.0" version = "1.0.0"
@ -97,16 +89,6 @@ dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "atty"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.6" version = "0.3.6"
@ -231,20 +213,6 @@ dependencies = [
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "clap"
version = "2.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "colored" name = "colored"
version = "1.6.0" version = "1.6.0"
@ -253,22 +221,6 @@ dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "comrak"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
"entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"typed-arena 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "cookie" name = "cookie"
version = "0.11.0-dev" version = "0.11.0-dev"
@ -400,11 +352,6 @@ dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "entities"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "error-chain" name = "error-chain"
version = "0.11.0" version = "0.11.0"
@ -1008,7 +955,6 @@ dependencies = [
"bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1019,6 +965,7 @@ dependencies = [
"hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", "rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", "rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
@ -1070,6 +1017,14 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "pulldown-cmark"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "0.3.15" version = "0.3.15"
@ -1134,14 +1089,6 @@ name = "redox_syscall"
version = "0.1.37" version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "0.2.10" version = "0.2.10"
@ -1474,11 +1421,6 @@ name = "string_cache_shared"
version = "0.3.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.11.11" version = "0.11.11"
@ -1587,24 +1529,6 @@ dependencies = [
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "0.3.5" version = "0.3.5"
@ -1786,24 +1710,11 @@ name = "traitobject"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "twoway"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "typeable" name = "typeable"
version = "0.1.2" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "typed-arena"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.10.0" version = "1.10.0"
@ -1848,11 +1759,6 @@ name = "unicode-segmentation"
version = "1.2.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.0.4" version = "0.0.4"
@ -1863,11 +1769,6 @@ name = "unicode-xid"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode_categories"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unidecode" name = "unidecode"
version = "0.3.0" version = "0.3.0"
@ -1919,11 +1820,6 @@ name = "vcpkg"
version = "0.2.3" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.1.3" version = "0.1.3"
@ -1996,11 +1892,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477" "checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
"checksum array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271" "checksum array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
@ -2017,9 +1911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" "checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
"checksum comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "053b26c8ce23b4c505a9479beace98f95899e0bf5c5255cf0219e9b0f48cf6ea"
"checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "<none>" "checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "<none>"
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d"
@ -2034,7 +1926,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70de3c590ce18df70743cace1cf12565637a0b26fd8b04ef10c7d33fdc66cdc" "checksum dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70de3c590ce18df70743cace1cf12565637a0b26fd8b04ef10c7d33fdc66cdc"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d" "checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d"
"checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
@ -2110,6 +2001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" "checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
@ -2118,7 +2010,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb" "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a"
@ -2155,7 +2046,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
"checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" "checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" "checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
@ -2167,8 +2057,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
"checksum tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e815b67d44c26feb06630011fb58b5b243f4e9585aac1ed0592c5795de64cd75" "checksum tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e815b67d44c26feb06630011fb58b5b243f4e9585aac1ed0592c5795de64cd75"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
"checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" "checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922"
@ -2185,9 +2073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" "checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a"
"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
"checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
"checksum typed-arena 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5934776c3ac1bea4a9d56620d6bf2d483b20d394e49581db40f187e1118ff667"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
@ -2195,10 +2081,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
"checksum unidecode 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" "checksum unidecode 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum untrusted 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70afa43c8c5d23a53a3c39ec9b56232c5badc19f6bb5ad529c1d6448a7241365" "checksum untrusted 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70afa43c8c5d23a53a3c39ec9b56232c5badc19f6bb5ad529c1d6448a7241365"
@ -2207,7 +2091,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22" "checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380" "checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum webfinger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27a4e6d1de7050af8beb026c02bcef5340ec1f3af6d4a02248b7990908baa3ff" "checksum webfinger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27a4e6d1de7050af8beb026c02bcef5340ec1f3af6d4a02248b7990908baa3ff"

View File

@ -9,7 +9,6 @@ array_tool = "1.0"
base64 = "0.9" base64 = "0.9"
bcrypt = "0.2" bcrypt = "0.2"
colored = "1.6" colored = "1.6"
comrak = "0.2"
dotenv = "*" dotenv = "*"
failure = "0.1" failure = "0.1"
failure_derive = "0.1" failure_derive = "0.1"
@ -19,6 +18,7 @@ hex = "0.3"
hyper = "*" hyper = "*"
lazy_static = "*" lazy_static = "*"
openssl = "0.10.6" openssl = "0.10.6"
pulldown-cmark = { version = "0.1.2", default-features = false }
reqwest = "0.8" reqwest = "0.8"
rpassword = "2.0" rpassword = "2.0"
serde = "*" serde = "*"

View File

@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
DROP TABLE mentions;

View File

@ -0,0 +1,7 @@
-- Your SQL goes here
CREATE TABLE mentions (
id SERIAL PRIMARY KEY,
mentioned_id INTEGER REFERENCES users(id) ON DELETE CASCADE NOT NULL,
post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE,
comment_id INTEGER REFERENCES comments(id) ON DELETE CASCADE
)

View File

@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
ALTER TABLE mentions DROP COLUMN ap_url;

View File

@ -0,0 +1,2 @@
-- Your SQL goes here
ALTER TABLE mentions ADD COLUMN ap_url VARCHAR NOT NULL DEFAULT '';

View File

@ -280,3 +280,6 @@ msgstr ""
msgid "You are not author in this blog." msgid "You are not author in this blog."
msgstr "" msgstr ""
msgid "{{ data }} mentioned you."
msgstr ""

View File

@ -279,3 +279,6 @@ msgstr "Vous n'avez pas les droits."
msgid "You are not author in this blog." msgid "You are not author in this blog."
msgstr "Vous n'êtes pas auteur dans ce blog." msgstr "Vous n'êtes pas auteur dans ce blog."
msgid "{{ data }} mentioned you."
msgstr ""

View File

@ -285,5 +285,9 @@ msgstr ""
msgid "You are not author in this blog." msgid "You are not author in this blog."
msgstr "" msgstr ""
#, fuzzy
msgid "{{ data }} mentioned you."
msgstr "{{ data }} skomentował Twój artykuł"
#~ msgid "Logowanie" #~ msgid "Logowanie"
#~ msgstr "Zaloguj się" #~ msgstr "Zaloguj się"

View File

@ -275,3 +275,6 @@ msgstr ""
msgid "You are not author in this blog." msgid "You are not author in this blog."
msgstr "" msgstr ""
msgid "{{ data }} mentioned you."
msgstr ""

View File

@ -40,8 +40,8 @@ pub trait FromActivity<T: Object>: Sized {
} }
} }
pub trait Notify<T: Object> { pub trait Notify {
fn notify(conn: &PgConnection, act: T, actor: Id); fn notify(&self, conn: &PgConnection);
} }
pub trait Deletable { pub trait Deletable {

View File

@ -1,10 +1,12 @@
use diesel::{ use diesel::{
pg::PgConnection, pg::PgConnection,
r2d2::{ConnectionManager, Pool, PooledConnection} r2d2::{ConnectionManager, PooledConnection}
}; };
use rocket::{Request, State, Outcome, http::Status, request::{self, FromRequest}}; use rocket::{Request, State, Outcome, http::Status, request::{self, FromRequest}};
use std::ops::Deref; use std::ops::Deref;
use setup::PgPool;
// From rocket documentation // From rocket documentation
// Connection request guard type: a wrapper around an r2d2 pooled connection. // Connection request guard type: a wrapper around an r2d2 pooled connection.
@ -17,7 +19,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for DbConn {
type Error = (); type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let pool = request.guard::<State<Pool<ConnectionManager<PgConnection>>>>()?; let pool = request.guard::<State<PgPool>>()?;
match pool.get() { match pool.get() {
Ok(conn) => Outcome::Success(DbConn(conn)), Ok(conn) => Outcome::Success(DbConn(conn)),
Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())) Err(_) => Outcome::Failure((Status::ServiceUnavailable, ()))

View File

@ -1,4 +1,4 @@
#![feature(plugin, custom_derive, decl_macro, iterator_find_map)] #![feature(plugin, custom_derive, decl_macro, iterator_find_map, iterator_flatten)]
#![plugin(rocket_codegen)] #![plugin(rocket_codegen)]
extern crate activitypub; extern crate activitypub;
@ -8,7 +8,6 @@ extern crate base64;
extern crate bcrypt; extern crate bcrypt;
extern crate chrono; extern crate chrono;
extern crate colored; extern crate colored;
extern crate comrak;
extern crate failure; extern crate failure;
#[macro_use] #[macro_use]
extern crate failure_derive; extern crate failure_derive;
@ -23,6 +22,7 @@ extern crate dotenv;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate openssl; extern crate openssl;
extern crate pulldown_cmark;
extern crate reqwest; extern crate reqwest;
extern crate rocket; extern crate rocket;
extern crate rocket_contrib; extern crate rocket_contrib;

View File

@ -1,5 +1,6 @@
use activitypub::{ use activitypub::{
activity::Create, activity::Create,
link,
object::{Note, properties::ObjectProperties} object::{Note, properties::ObjectProperties}
}; };
use chrono; use chrono;
@ -13,6 +14,7 @@ use activity_pub::{
}; };
use models::{ use models::{
instance::Instance, instance::Instance,
mentions::Mention,
notifications::*, notifications::*,
posts::Post, posts::Post,
users::User users::User
@ -114,6 +116,16 @@ impl FromActivity<Note> for Comment {
fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment { fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment {
let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string(); let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string();
let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone()); let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone());
// save mentions
if let Some(serde_json::Value::Array(tags)) = note.object_props.tag.clone() {
for tag in tags.into_iter() {
serde_json::from_value::<link::Mention>(tag)
.map(|m| Mention::from_activity(conn, m, Id::new(note.clone().object_props.clone().url_string().unwrap_or(String::from("")))))
.ok();
}
}
let comm = Comment::insert(conn, NewComment { let comm = Comment::insert(conn, NewComment {
content: SafeString::new(&note.object_props.content_string().unwrap()), content: SafeString::new(&note.object_props.content_string().unwrap()),
spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")), spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")),
@ -125,27 +137,21 @@ impl FromActivity<Note> for Comment {
author_id: User::from_url(conn, actor.clone().into()).unwrap().id, author_id: User::from_url(conn, actor.clone().into()).unwrap().id,
sensitive: false // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate sensitive: false // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate
}); });
Comment::notify(conn, note, actor); comm.notify(conn);
comm comm
} }
} }
impl Notify<Note> for Comment { impl Notify for Comment {
fn notify(conn: &PgConnection, note: Note, _actor: Id) { fn notify(&self, conn: &PgConnection) {
match Comment::find_by_ap_url(conn, note.object_props.id_string().unwrap()) { for author in self.get_post(conn).get_authors(conn) {
Some(comment) => { Notification::insert(conn, NewNotification {
for author in comment.clone().get_post(conn).get_authors(conn) { title: "{{ data }} commented your article".to_string(),
let comment = comment.clone(); data: Some(self.get_author(conn).display_name.clone()),
Notification::insert(conn, NewNotification { content: Some(self.get_post(conn).title),
title: "{{ data }} commented your article".to_string(), link: self.ap_url.clone(),
data: Some(comment.get_author(conn).display_name.clone()), user_id: author.id
content: Some(comment.get_post(conn).title), });
link: comment.ap_url, }
user_id: author.id
});
}
},
None => println!("Couldn't find comment by AP id, to create a new notification")
};
} }
} }

View File

@ -62,15 +62,15 @@ impl FromActivity<FollowAct> for Follow {
} }
} }
impl Notify<FollowAct> for Follow { impl Notify for Follow {
fn notify(conn: &PgConnection, follow: FollowAct, actor: Id) { fn notify(&self, conn: &PgConnection) {
let follower = User::from_url(conn, actor.into()).unwrap(); let follower = User::get(conn, self.follower_id).unwrap();
Notification::insert(conn, NewNotification { Notification::insert(conn, NewNotification {
title: "{{ data }} started following you".to_string(), title: "{{ data }} started following you".to_string(),
data: Some(follower.display_name.clone()), data: Some(follower.display_name.clone()),
content: None, content: None,
link: Some(follower.ap_url), link: Some(follower.ap_url),
user_id: User::from_url(conn, follow.follow_props.object_link::<Id>().unwrap().into()).unwrap().id user_id: self.following_id
}); });
} }
} }

View File

@ -77,7 +77,7 @@ impl Like {
} }
impl FromActivity<activity::Like> for Like { impl FromActivity<activity::Like> for Like {
fn from_activity(conn: &PgConnection, like: activity::Like, actor: Id) -> Like { fn from_activity(conn: &PgConnection, like: activity::Like, _actor: Id) -> Like {
let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string()); let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string());
let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string());
let res = Like::insert(conn, NewLike { let res = Like::insert(conn, NewLike {
@ -85,15 +85,15 @@ impl FromActivity<activity::Like> for Like {
user_id: liker.unwrap().id, user_id: liker.unwrap().id,
ap_url: like.object_props.id_string().unwrap_or(String::from("")) ap_url: like.object_props.id_string().unwrap_or(String::from(""))
}); });
Like::notify(conn, like, actor); res.notify(conn);
res res
} }
} }
impl Notify<activity::Like> for Like { impl Notify for Like {
fn notify(conn: &PgConnection, like: activity::Like, actor: Id) { fn notify(&self, conn: &PgConnection) {
let liker = User::from_url(conn, actor.into()).unwrap(); let liker = User::get(conn, self.user_id).unwrap();
let post = Post::find_by_ap_url(conn, like.like_props.object_link::<Id>().unwrap().into()).unwrap(); let post = Post::get(conn, self.post_id).unwrap();
for author in post.get_authors(conn) { for author in post.get_authors(conn) {
let post = post.clone(); let post = post.clone();
Notification::insert(conn, NewNotification { Notification::insert(conn, NewNotification {

113
src/models/mentions.rs Normal file
View File

@ -0,0 +1,113 @@
use activitypub::link;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use activity_pub::{Id, inbox::Notify};
use models::{
comments::Comment,
notifications::*,
posts::Post,
users::User
};
use schema::mentions;
#[derive(Queryable, Identifiable)]
pub struct Mention {
pub id: i32,
pub mentioned_id: i32,
pub post_id: Option<i32>,
pub comment_id: Option<i32>,
pub ap_url: String
}
#[derive(Insertable)]
#[table_name = "mentions"]
pub struct NewMention {
pub mentioned_id: i32,
pub post_id: Option<i32>,
pub comment_id: Option<i32>,
pub ap_url: String
}
impl Mention {
insert!(mentions, NewMention);
get!(mentions);
find_by!(mentions, find_by_ap_url, ap_url as String);
list_by!(mentions, list_for_user, mentioned_id as i32);
list_by!(mentions, list_for_post, post_id as i32);
pub fn get_mentioned(&self, conn: &PgConnection) -> Option<User> {
User::get(conn, self.mentioned_id)
}
pub fn get_post(&self, conn: &PgConnection) -> Option<Post> {
self.post_id.and_then(|id| Post::get(conn, id))
}
pub fn get_comment(&self, conn: &PgConnection) -> Option<Comment> {
self.post_id.and_then(|id| Comment::get(conn, id))
}
pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention {
let user = User::find_by_fqn(conn, ment.clone());
println!("building act : {} -> {:?}", ment, user);
let mut mention = link::Mention::default();
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
mention.link_props.set_name_string(format!("@{}", ment)).expect("Error setting mention's name");
mention
}
pub fn to_activity(&self, conn: &PgConnection) -> link::Mention {
let user = self.get_mentioned(conn);
let mut mention = link::Mention::default();
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
mention.link_props.set_name_string(user.map(|u| format!("@{}", u.get_fqn(conn))).unwrap_or(String::new())).expect("Error setting mention's name");
mention
}
pub fn from_activity(conn: &PgConnection, ment: link::Mention, inside: Id) -> Option<Self> {
let ap_url = ment.link_props.href_string().unwrap();
let mentioned = User::find_by_ap_url(conn, ap_url).unwrap();
if let Some(post) = Post::find_by_ap_url(conn, inside.clone().into()) {
let res = Mention::insert(conn, NewMention {
mentioned_id: mentioned.id,
post_id: Some(post.id),
comment_id: None,
ap_url: ment.link_props.href_string().unwrap_or(String::new())
});
res.notify(conn);
Some(res)
} else {
if let Some(comment) = Comment::find_by_ap_url(conn, inside.into()) {
let res = Mention::insert(conn, NewMention {
mentioned_id: mentioned.id,
post_id: None,
comment_id: Some(comment.id),
ap_url: ment.link_props.href_string().unwrap_or(String::new())
});
res.notify(conn);
Some(res)
} else {
None
}
}
}
}
impl Notify for Mention {
fn notify(&self, conn: &PgConnection) {
let author = self.get_comment(conn)
.map(|c| c.get_author(conn).display_name.clone())
.unwrap_or(self.get_post(conn).unwrap().get_authors(conn)[0].display_name.clone());
self.get_mentioned(conn).map(|m| {
Notification::insert(conn, NewNotification {
title: "{{ data }} mentioned you.".to_string(),
data: Some(author),
content: None,
link: Some(self.get_post(conn).map(|p| p.ap_url).unwrap_or_else(|| self.get_comment(conn).unwrap().ap_url.unwrap_or(String::new()))),
user_id: m.id
});
});
}
}

View File

@ -12,6 +12,18 @@ macro_rules! find_by {
}; };
} }
macro_rules! list_by {
($table:ident, $fn:ident, $($col:ident as $type:ident),+) => {
/// Try to find a $table with a given $col
pub fn $fn(conn: &PgConnection, $($col: $type),+) -> Vec<Self> {
$table::table
$(.filter($table::$col.eq($col)))+
.load::<Self>(conn)
.expect("Error loading $table by $col")
}
};
}
macro_rules! get { macro_rules! get {
($table:ident) => { ($table:ident) => {
pub fn get(conn: &PgConnection, id: i32) -> Option<Self> { pub fn get(conn: &PgConnection, id: i32) -> Option<Self> {
@ -41,6 +53,7 @@ pub mod comments;
pub mod follows; pub mod follows;
pub mod instance; pub mod instance;
pub mod likes; pub mod likes;
pub mod mentions;
pub mod notifications; pub mod notifications;
pub mod post_authors; pub mod post_authors;
pub mod posts; pub mod posts;

View File

@ -1,5 +1,6 @@
use activitypub::{ use activitypub::{
activity::Create, activity::Create,
link,
object::{Article, properties::ObjectProperties} object::{Article, properties::ObjectProperties}
}; };
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
@ -9,13 +10,13 @@ use serde_json;
use BASE_URL; use BASE_URL;
use activity_pub::{ use activity_pub::{
PUBLIC_VISIBILTY, ap_url, Id, IntoId, PUBLIC_VISIBILTY, ap_url, Id, IntoId,
actor::Actor,
inbox::FromActivity inbox::FromActivity
}; };
use models::{ use models::{
blogs::Blog, blogs::Blog,
instance::Instance, instance::Instance,
likes::Like, likes::Like,
mentions::Mention,
post_authors::PostAuthor, post_authors::PostAuthor,
reshares::Reshare, reshares::Reshare,
users::User users::User
@ -144,6 +145,8 @@ impl Post {
let mut to = self.get_receivers_urls(conn); let mut to = self.get_receivers_urls(conn);
to.push(PUBLIC_VISIBILTY.to_string()); to.push(PUBLIC_VISIBILTY.to_string());
let mentions = Mention::list_for_post(conn, self.id).into_iter().map(|m| m.to_activity(conn)).collect::<Vec<link::Mention>>();
let mut article = Article::default(); let mut article = Article::default();
article.object_props = ObjectProperties { article.object_props = ObjectProperties {
name: Some(serde_json::to_value(self.title.clone()).unwrap()), name: Some(serde_json::to_value(self.title.clone()).unwrap()),
@ -151,7 +154,7 @@ impl Post {
attributed_to: Some(serde_json::to_value(self.get_authors(conn).into_iter().map(|x| x.ap_url).collect::<Vec<String>>()).unwrap()), attributed_to: Some(serde_json::to_value(self.get_authors(conn).into_iter().map(|x| x.ap_url).collect::<Vec<String>>()).unwrap()),
content: Some(serde_json::to_value(self.content.clone()).unwrap()), content: Some(serde_json::to_value(self.content.clone()).unwrap()),
published: Some(serde_json::to_value(self.creation_date).unwrap()), published: Some(serde_json::to_value(self.creation_date).unwrap()),
tag: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()), tag: Some(serde_json::to_value(mentions).unwrap()),
url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()), url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()),
to: Some(serde_json::to_value(to).unwrap()), to: Some(serde_json::to_value(to).unwrap()),
cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()), cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()),
@ -184,6 +187,15 @@ impl Post {
impl FromActivity<Article> for Post { impl FromActivity<Article> for Post {
fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post { fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post {
// save mentions
if let Some(serde_json::Value::Array(tags)) = article.object_props.tag.clone() {
for tag in tags.into_iter() {
serde_json::from_value::<link::Mention>(tag)
.map(|m| Mention::from_activity(conn, m, Id::new(article.clone().object_props.clone().url_string().unwrap_or(String::from("")))))
.ok();
}
}
Post::insert(conn, NewPost { Post::insert(conn, NewPost {
blog_id: 0, // TODO blog_id: 0, // TODO
slug: String::from(""), // TODO slug: String::from(""), // TODO

View File

@ -73,7 +73,7 @@ impl Reshare {
} }
impl FromActivity<Announce> for Reshare { impl FromActivity<Announce> for Reshare {
fn from_activity(conn: &PgConnection, announce: Announce, actor: Id) -> Reshare { fn from_activity(conn: &PgConnection, announce: Announce, _actor: Id) -> Reshare {
let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string()); let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string());
let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string());
let reshare = Reshare::insert(conn, NewReshare { let reshare = Reshare::insert(conn, NewReshare {
@ -81,15 +81,15 @@ impl FromActivity<Announce> for Reshare {
user_id: user.unwrap().id, user_id: user.unwrap().id,
ap_url: announce.object_props.id_string().unwrap_or(String::from("")) ap_url: announce.object_props.id_string().unwrap_or(String::from(""))
}); });
Reshare::notify(conn, announce, actor); reshare.notify(conn);
reshare reshare
} }
} }
impl Notify<Announce> for Reshare { impl Notify for Reshare {
fn notify(conn: &PgConnection, announce: Announce, actor: Id) { fn notify(&self, conn: &PgConnection) {
let actor = User::from_url(conn, actor.into()).unwrap(); let actor = User::get(conn, self.user_id).unwrap();
let post = Post::find_by_ap_url(conn, announce.announce_props.object_link::<Id>().unwrap().into()).unwrap(); let post = self.get_post(conn).unwrap();
for author in post.get_authors(conn) { for author in post.get_authors(conn) {
let post = post.clone(); let post = post.clone();
Notification::insert(conn, NewNotification { Notification::insert(conn, NewNotification {

View File

@ -47,7 +47,7 @@ use safe_string::SafeString;
pub const AUTH_COOKIE: &'static str = "user_id"; pub const AUTH_COOKIE: &'static str = "user_id";
#[derive(Queryable, Identifiable, Serialize, Deserialize, Clone)] #[derive(Queryable, Identifiable, Serialize, Deserialize, Clone, Debug)]
pub struct User { pub struct User {
pub id: i32, pub id: i32,
pub username: String, pub username: String,
@ -89,7 +89,7 @@ impl User {
get!(users); get!(users);
find_by!(users, find_by_email, email as String); find_by!(users, find_by_email, email as String);
find_by!(users, find_by_name, username as String, instance_id as i32); find_by!(users, find_by_name, username as String, instance_id as i32);
find_by!(users, find_by_ap_url, ap_url as String);
pub fn grant_admin_rights(&self, conn: &PgConnection) { pub fn grant_admin_rights(&self, conn: &PgConnection) {
diesel::update(self) diesel::update(self)
@ -419,23 +419,15 @@ impl APActor for User {
} }
fn from_url(conn: &PgConnection, url: String) -> Option<User> { fn from_url(conn: &PgConnection, url: String) -> Option<User> {
let in_db = users::table.filter(users::ap_url.eq(url.clone())) User::find_by_ap_url(conn, url.clone()).or_else(|| {
.limit(1) // The requested user was not in the DB
.load::<User>(conn) // We try to fetch it if it is remote
.expect("Error loading user by AP url") if Url::parse(url.as_ref()).unwrap().host_str().unwrap() != BASE_URL.as_str() {
.into_iter().nth(0); Some(User::fetch_from_url(conn, url).unwrap())
match in_db { } else {
Some(u) => Some(u), None
None => {
// The requested user was not in the DB
// We try to fetch it if it is remote
if Url::parse(url.as_ref()).unwrap().host_str().unwrap() != BASE_URL.as_str() {
Some(User::fetch_from_url(conn, url).unwrap())
} else {
None
}
} }
} })
} }
} }

View File

@ -4,7 +4,7 @@ use rocket::{
}; };
use rocket_contrib::Template; use rocket_contrib::Template;
use activity_pub::{broadcast, IntoId, inbox::Notify}; use activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::Blog, blogs::Blog,
@ -53,12 +53,12 @@ fn create(blog_name: String, slug: String, query: CommentQuery, data: Form<NewCo
in_response_to_id: query.responding_to, in_response_to_id: query.responding_to,
post_id: post.id, post_id: post.id,
author_id: user.id, author_id: user.id,
ap_url: None, ap_url: None, // TODO: set it
sensitive: false, sensitive: false,
spoiler_text: "".to_string() spoiler_text: "".to_string()
}); });
comment.notify(&*conn);
Comment::notify(&*conn, comment.into_activity(&*conn), user.clone().into_id());
broadcast(&*conn, &user, comment.create_activity(&*conn), user.get_followers(&*conn)); broadcast(&*conn, &user, comment.create_activity(&*conn), user.get_followers(&*conn));
Redirect::to(format!("/~/{}/{}/#comment-{}", blog_name, slug, comment.id)) Redirect::to(format!("/~/{}/{}/#comment-{}", blog_name, slug, comment.id))

View File

@ -1,6 +1,6 @@
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, IntoId, inbox::Notify}; use activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::Blog, blogs::Blog,
@ -23,8 +23,8 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
ap_url: "".to_string() ap_url: "".to_string()
}); });
like.update_ap_url(&*conn); like.update_ap_url(&*conn);
like.notify(&*conn);
likes::Like::notify(&*conn, like.into_activity(&*conn), user.clone().into_id());
broadcast(&*conn, &user, like.into_activity(&*conn), user.get_followers(&*conn)); broadcast(&*conn, &user, like.into_activity(&*conn), user.get_followers(&*conn));
} else { } else {
let like = likes::Like::find_by_user_on_post(&*conn, user.id, post.id).unwrap(); let like = likes::Like::find_by_user_on_post(&*conn, user.id, post.id).unwrap();

View File

@ -1,21 +1,21 @@
use comrak::{markdown_to_html, ComrakOptions};
use heck::KebabCase; use heck::KebabCase;
use rocket::request::Form; use rocket::request::Form;
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use rocket_contrib::Template; use rocket_contrib::Template;
use serde_json; use serde_json;
use activity_pub::{broadcast, context, activity_pub, ActivityPub}; use activity_pub::{broadcast, context, activity_pub, ActivityPub, Id};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::*, blogs::*,
comments::Comment, comments::Comment,
mentions::Mention,
post_authors::*, post_authors::*,
posts::*, posts::*,
users::User users::User
}; };
use utils;
use safe_string::SafeString; use safe_string::SafeString;
use utils;
#[get("/~/<blog>/<slug>", rank = 4)] #[get("/~/<blog>/<slug>", rank = 4)]
fn details(blog: String, slug: String, conn: DbConn, user: Option<User>) -> Template { fn details(blog: String, slug: String, conn: DbConn, user: Option<User>) -> Template {
@ -88,19 +88,7 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
if slug == "new" || Post::find_by_slug(&*conn, slug.clone(), blog.id).is_some() { if slug == "new" || Post::find_by_slug(&*conn, slug.clone(), blog.id).is_some() {
Redirect::to(uri!(new: blog = blog_name)) Redirect::to(uri!(new: blog = blog_name))
} else { } else {
let content = markdown_to_html(form.content.to_string().as_ref(), &ComrakOptions{ let (content, mentions) = utils::md_to_html(form.content.to_string().as_ref());
smart: true,
safe: true,
ext_strikethrough: true,
ext_tagfilter: true,
ext_table: true,
ext_autolink: true,
ext_tasklist: true,
ext_superscript: true,
ext_header_ids: Some("title".to_string()),
ext_footnotes: true,
..ComrakOptions::default()
});
let post = Post::insert(&*conn, NewPost { let post = Post::insert(&*conn, NewPost {
blog_id: blog.id, blog_id: blog.id,
@ -117,6 +105,10 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
author_id: user.id author_id: user.id
}); });
for m in mentions.into_iter() {
Mention::from_activity(&*conn, Mention::build_activity(&*conn, m), Id::new(post.compute_id(&*conn)));
}
let act = post.create_activity(&*conn); let act = post.create_activity(&*conn);
broadcast(&*conn, &user, act, user.get_followers(&*conn)); broadcast(&*conn, &user, act, user.get_followers(&*conn));

View File

@ -1,6 +1,6 @@
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, IntoId, inbox::Notify}; use activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::Blog, blogs::Blog,
@ -23,8 +23,8 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
ap_url: "".to_string() ap_url: "".to_string()
}); });
reshare.update_ap_url(&*conn); reshare.update_ap_url(&*conn);
reshare.notify(&*conn);
Reshare::notify(&*conn, reshare.into_activity(&*conn), user.clone().into_id());
broadcast(&*conn, &user, reshare.into_activity(&*conn), user.get_followers(&*conn)); broadcast(&*conn, &user, reshare.into_activity(&*conn), user.get_followers(&*conn));
} else { } else {
let reshare = Reshare::find_by_user_on_post(&*conn, user.id, post.id).unwrap(); let reshare = Reshare::find_by_user_on_post(&*conn, user.id, post.id).unwrap();

View File

@ -71,16 +71,17 @@ fn dashboard_auth() -> Flash<Redirect> {
#[get("/@/<name>/follow")] #[get("/@/<name>/follow")]
fn follow(name: String, conn: DbConn, user: User) -> Redirect { fn follow(name: String, conn: DbConn, user: User) -> Redirect {
let target = User::find_by_fqn(&*conn, name.clone()).unwrap(); let target = User::find_by_fqn(&*conn, name.clone()).unwrap();
follows::Follow::insert(&*conn, follows::NewFollow { let f = follows::Follow::insert(&*conn, follows::NewFollow {
follower_id: user.id, follower_id: user.id,
following_id: target.id following_id: target.id
}); });
f.notify(&*conn);
let mut act = Follow::default(); let mut act = Follow::default();
act.follow_props.set_actor_link::<Id>(user.clone().into_id()).unwrap(); act.follow_props.set_actor_link::<Id>(user.clone().into_id()).unwrap();
act.follow_props.set_object_object(user.into_activity(&*conn)).unwrap(); act.follow_props.set_object_object(user.into_activity(&*conn)).unwrap();
act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap(); act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap();
follows::Follow::notify(&*conn, act.clone(), user.clone().into_id());
broadcast(&*conn, &user, act, vec![target]); broadcast(&*conn, &user, act, vec![target]);
Redirect::to(uri!(details: name = name)) Redirect::to(uri!(details: name = name))
} }

View File

@ -66,6 +66,16 @@ table! {
} }
} }
table! {
mentions (id) {
id -> Int4,
mentioned_id -> Int4,
post_id -> Nullable<Int4>,
comment_id -> Nullable<Int4>,
ap_url -> Varchar,
}
}
table! { table! {
notifications (id) { notifications (id) {
id -> Int4, id -> Int4,
@ -137,6 +147,9 @@ joinable!(comments -> posts (post_id));
joinable!(comments -> users (author_id)); joinable!(comments -> users (author_id));
joinable!(likes -> posts (post_id)); joinable!(likes -> posts (post_id));
joinable!(likes -> users (user_id)); joinable!(likes -> users (user_id));
joinable!(mentions -> comments (comment_id));
joinable!(mentions -> posts (post_id));
joinable!(mentions -> users (mentioned_id));
joinable!(notifications -> users (user_id)); joinable!(notifications -> users (user_id));
joinable!(post_authors -> posts (post_id)); joinable!(post_authors -> posts (post_id));
joinable!(post_authors -> users (author_id)); joinable!(post_authors -> users (author_id));
@ -152,6 +165,7 @@ allow_tables_to_appear_in_same_query!(
follows, follows,
instances, instances,
likes, likes,
mentions,
notifications, notifications,
post_authors, post_authors,
posts, posts,

View File

@ -12,7 +12,7 @@ use db_conn::DbConn;
use models::instance::*; use models::instance::*;
use models::users::*; use models::users::*;
type PgPool = Pool<ConnectionManager<PgConnection>>; pub type PgPool = Pool<ConnectionManager<PgConnection>>;
/// Initializes a database pool. /// Initializes a database pool.
fn init_pool() -> Option<PgPool> { fn init_pool() -> Option<PgPool> {

View File

@ -1,5 +1,6 @@
use gettextrs::gettext; use gettextrs::gettext;
use heck::CamelCase; use heck::CamelCase;
use pulldown_cmark::{Event, Parser, Options, Tag, html};
use rocket::{ use rocket::{
http::uri::Uri, http::uri::Uri,
response::{Redirect, Flash} response::{Redirect, Flash}
@ -18,3 +19,52 @@ pub fn make_actor_id(name: String) -> String {
pub fn requires_login(message: &str, url: Uri) -> Flash<Redirect> { pub fn requires_login(message: &str, url: Uri) -> Flash<Redirect> {
Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str()) Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str())
} }
/// Returns (HTML, mentions)
pub fn md_to_html(md: &str) -> (String, Vec<String>) {
let parser = Parser::new_ext(md, Options::all());
let (parser, mentions): (Vec<Vec<Event>>, Vec<Vec<String>>) = parser.map(|evt| match evt {
Event::Text(txt) => {
let (evts, _, _, _, new_mentions) = txt.chars().fold((vec![], false, String::new(), 0, vec![]), |(mut events, in_mention, text_acc, n, mut mentions), c| {
if in_mention {
if (c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_') && (n < (txt.chars().count() - 1)) {
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1, mentions)
} else {
let mention = text_acc + c.to_string().as_ref();
let short_mention = mention.clone();
let short_mention = short_mention.splitn(1, '@').nth(0).unwrap_or("");
let link = Tag::Link(format!("/@/{}/", mention).into(), short_mention.to_string().into());
mentions.push(mention);
events.push(Event::Start(link.clone()));
events.push(Event::Text(format!("@{}", short_mention).into()));
events.push(Event::End(link));
(events, false, c.to_string(), n + 1, mentions)
}
} else {
if c == '@' {
events.push(Event::Text(text_acc.into()));
(events, true, String::new(), n + 1, mentions)
} else {
if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention.
events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into()))
}
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1, mentions)
}
}
});
(evts, new_mentions)
},
_ => (vec![evt], vec![])
}).unzip();
let parser = parser.into_iter().flatten();
let mentions = mentions.into_iter().flatten().map(|m| String::from(m.trim()));
// TODO: fetch mentionned profiles in background, if needed
let mut buf = String::new();
html::push_html(&mut buf, parser);
(buf, mentions.collect())
}