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)",
]
[[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]]
name = "antidote"
version = "1.0.0"
@ -97,16 +89,6 @@ dependencies = [
"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]]
name = "backtrace"
version = "0.3.6"
@ -231,20 +213,6 @@ dependencies = [
"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]]
name = "colored"
version = "1.6.0"
@ -253,22 +221,6 @@ dependencies = [
"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]]
name = "cookie"
version = "0.11.0-dev"
@ -400,11 +352,6 @@ dependencies = [
"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]]
name = "error-chain"
version = "0.11.0"
@ -1008,7 +955,6 @@ dependencies = [
"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)",
"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)",
"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)",
@ -1019,6 +965,7 @@ dependencies = [
"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)",
"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)",
"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)",
@ -1070,6 +1017,14 @@ dependencies = [
"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]]
name = "quote"
version = "0.3.15"
@ -1134,14 +1089,6 @@ name = "redox_syscall"
version = "0.1.37"
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]]
name = "regex"
version = "0.2.10"
@ -1474,11 +1421,6 @@ name = "string_cache_shared"
version = "0.3.0"
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]]
name = "syn"
version = "0.11.11"
@ -1587,24 +1529,6 @@ dependencies = [
"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]]
name = "thread_local"
version = "0.3.5"
@ -1786,24 +1710,11 @@ name = "traitobject"
version = "0.1.0"
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]]
name = "typeable"
version = "0.1.2"
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]]
name = "typenum"
version = "1.10.0"
@ -1848,11 +1759,6 @@ name = "unicode-segmentation"
version = "1.2.0"
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]]
name = "unicode-xid"
version = "0.0.4"
@ -1863,11 +1769,6 @@ name = "unicode-xid"
version = "0.1.0"
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]]
name = "unidecode"
version = "0.3.0"
@ -1919,11 +1820,6 @@ name = "vcpkg"
version = "0.2.3"
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]]
name = "version_check"
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 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 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 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 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-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"
@ -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 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 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 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 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"
@ -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 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 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 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"
@ -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.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 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.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"
@ -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.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_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-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"
@ -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_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 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.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"
@ -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 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 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 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"
@ -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 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 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 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 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"
@ -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-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-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.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 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"
@ -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 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 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 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"

View File

@ -9,7 +9,6 @@ array_tool = "1.0"
base64 = "0.9"
bcrypt = "0.2"
colored = "1.6"
comrak = "0.2"
dotenv = "*"
failure = "0.1"
failure_derive = "0.1"
@ -19,6 +18,7 @@ hex = "0.3"
hyper = "*"
lazy_static = "*"
openssl = "0.10.6"
pulldown-cmark = { version = "0.1.2", default-features = false }
reqwest = "0.8"
rpassword = "2.0"
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."
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."
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."
msgstr ""
#, fuzzy
msgid "{{ data }} mentioned you."
msgstr "{{ data }} skomentował Twój artykuł"
#~ msgid "Logowanie"
#~ msgstr "Zaloguj się"

View File

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

View File

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

View File

@ -1,10 +1,12 @@
use diesel::{
pg::PgConnection,
r2d2::{ConnectionManager, Pool, PooledConnection}
r2d2::{ConnectionManager, PooledConnection}
};
use rocket::{Request, State, Outcome, http::Status, request::{self, FromRequest}};
use std::ops::Deref;
use setup::PgPool;
// From rocket documentation
// 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 = ();
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() {
Ok(conn) => Outcome::Success(DbConn(conn)),
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)]
extern crate activitypub;
@ -8,7 +8,6 @@ extern crate base64;
extern crate bcrypt;
extern crate chrono;
extern crate colored;
extern crate comrak;
extern crate failure;
#[macro_use]
extern crate failure_derive;
@ -23,6 +22,7 @@ extern crate dotenv;
#[macro_use]
extern crate lazy_static;
extern crate openssl;
extern crate pulldown_cmark;
extern crate reqwest;
extern crate rocket;
extern crate rocket_contrib;

View File

@ -1,5 +1,6 @@
use activitypub::{
activity::Create,
link,
object::{Note, properties::ObjectProperties}
};
use chrono;
@ -13,6 +14,7 @@ use activity_pub::{
};
use models::{
instance::Instance,
mentions::Mention,
notifications::*,
posts::Post,
users::User
@ -114,6 +116,16 @@ impl FromActivity<Note> for 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_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 {
content: SafeString::new(&note.object_props.content_string().unwrap()),
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,
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
}
}
impl Notify<Note> for Comment {
fn notify(conn: &PgConnection, note: Note, _actor: Id) {
match Comment::find_by_ap_url(conn, note.object_props.id_string().unwrap()) {
Some(comment) => {
for author in comment.clone().get_post(conn).get_authors(conn) {
let comment = comment.clone();
impl Notify for Comment {
fn notify(&self, conn: &PgConnection) {
for author in self.get_post(conn).get_authors(conn) {
Notification::insert(conn, NewNotification {
title: "{{ data }} commented your article".to_string(),
data: Some(comment.get_author(conn).display_name.clone()),
content: Some(comment.get_post(conn).title),
link: comment.ap_url,
data: Some(self.get_author(conn).display_name.clone()),
content: Some(self.get_post(conn).title),
link: self.ap_url.clone(),
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 {
fn notify(conn: &PgConnection, follow: FollowAct, actor: Id) {
let follower = User::from_url(conn, actor.into()).unwrap();
impl Notify for Follow {
fn notify(&self, conn: &PgConnection) {
let follower = User::get(conn, self.follower_id).unwrap();
Notification::insert(conn, NewNotification {
title: "{{ data }} started following you".to_string(),
data: Some(follower.display_name.clone()),
content: None,
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 {
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 post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string());
let res = Like::insert(conn, NewLike {
@ -85,15 +85,15 @@ impl FromActivity<activity::Like> for Like {
user_id: liker.unwrap().id,
ap_url: like.object_props.id_string().unwrap_or(String::from(""))
});
Like::notify(conn, like, actor);
res.notify(conn);
res
}
}
impl Notify<activity::Like> for Like {
fn notify(conn: &PgConnection, like: activity::Like, actor: Id) {
let liker = User::from_url(conn, actor.into()).unwrap();
let post = Post::find_by_ap_url(conn, like.like_props.object_link::<Id>().unwrap().into()).unwrap();
impl Notify for Like {
fn notify(&self, conn: &PgConnection) {
let liker = User::get(conn, self.user_id).unwrap();
let post = Post::get(conn, self.post_id).unwrap();
for author in post.get_authors(conn) {
let post = post.clone();
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 {
($table:ident) => {
pub fn get(conn: &PgConnection, id: i32) -> Option<Self> {
@ -41,6 +53,7 @@ pub mod comments;
pub mod follows;
pub mod instance;
pub mod likes;
pub mod mentions;
pub mod notifications;
pub mod post_authors;
pub mod posts;

View File

@ -1,5 +1,6 @@
use activitypub::{
activity::Create,
link,
object::{Article, properties::ObjectProperties}
};
use chrono::NaiveDateTime;
@ -9,13 +10,13 @@ use serde_json;
use BASE_URL;
use activity_pub::{
PUBLIC_VISIBILTY, ap_url, Id, IntoId,
actor::Actor,
inbox::FromActivity
};
use models::{
blogs::Blog,
instance::Instance,
likes::Like,
mentions::Mention,
post_authors::PostAuthor,
reshares::Reshare,
users::User
@ -144,6 +145,8 @@ impl Post {
let mut to = self.get_receivers_urls(conn);
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();
article.object_props = ObjectProperties {
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()),
content: Some(serde_json::to_value(self.content.clone()).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()),
to: Some(serde_json::to_value(to).unwrap()),
cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()),
@ -184,6 +187,15 @@ impl Post {
impl FromActivity<Article> for 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 {
blog_id: 0, // TODO
slug: String::from(""), // TODO

View File

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

View File

@ -47,7 +47,7 @@ use safe_string::SafeString;
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 id: i32,
pub username: String,
@ -89,7 +89,7 @@ impl User {
get!(users);
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_ap_url, ap_url as String);
pub fn grant_admin_rights(&self, conn: &PgConnection) {
diesel::update(self)
@ -419,14 +419,7 @@ impl APActor for User {
}
fn from_url(conn: &PgConnection, url: String) -> Option<User> {
let in_db = users::table.filter(users::ap_url.eq(url.clone()))
.limit(1)
.load::<User>(conn)
.expect("Error loading user by AP url")
.into_iter().nth(0);
match in_db {
Some(u) => Some(u),
None => {
User::find_by_ap_url(conn, url.clone()).or_else(|| {
// 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() {
@ -434,8 +427,7 @@ impl APActor for User {
} else {
None
}
}
}
})
}
}

View File

@ -4,7 +4,7 @@ use rocket::{
};
use rocket_contrib::Template;
use activity_pub::{broadcast, IntoId, inbox::Notify};
use activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn;
use models::{
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,
post_id: post.id,
author_id: user.id,
ap_url: None,
ap_url: None, // TODO: set it
sensitive: false,
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));
Redirect::to(format!("/~/{}/{}/#comment-{}", blog_name, slug, comment.id))

View File

@ -1,6 +1,6 @@
use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, IntoId, inbox::Notify};
use activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn;
use models::{
blogs::Blog,
@ -23,8 +23,8 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
ap_url: "".to_string()
});
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));
} else {
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 rocket::request::Form;
use rocket::response::{Redirect, Flash};
use rocket_contrib::Template;
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 models::{
blogs::*,
comments::Comment,
mentions::Mention,
post_authors::*,
posts::*,
users::User
};
use utils;
use safe_string::SafeString;
use utils;
#[get("/~/<blog>/<slug>", rank = 4)]
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() {
Redirect::to(uri!(new: blog = blog_name))
} else {
let content = markdown_to_html(form.content.to_string().as_ref(), &ComrakOptions{
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 (content, mentions) = utils::md_to_html(form.content.to_string().as_ref());
let post = Post::insert(&*conn, NewPost {
blog_id: blog.id,
@ -117,6 +105,10 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
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);
broadcast(&*conn, &user, act, user.get_followers(&*conn));

View File

@ -1,6 +1,6 @@
use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, IntoId, inbox::Notify};
use activity_pub::{broadcast, inbox::Notify};
use db_conn::DbConn;
use models::{
blogs::Blog,
@ -23,8 +23,8 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
ap_url: "".to_string()
});
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));
} else {
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")]
fn follow(name: String, conn: DbConn, user: User) -> Redirect {
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,
following_id: target.id
});
f.notify(&*conn);
let mut act = Follow::default();
act.follow_props.set_actor_link::<Id>(user.clone().into_id()).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();
follows::Follow::notify(&*conn, act.clone(), user.clone().into_id());
broadcast(&*conn, &user, act, vec![target]);
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! {
notifications (id) {
id -> Int4,
@ -137,6 +147,9 @@ joinable!(comments -> posts (post_id));
joinable!(comments -> users (author_id));
joinable!(likes -> posts (post_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!(post_authors -> posts (post_id));
joinable!(post_authors -> users (author_id));
@ -152,6 +165,7 @@ allow_tables_to_appear_in_same_query!(
follows,
instances,
likes,
mentions,
notifications,
post_authors,
posts,

View File

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

View File

@ -1,5 +1,6 @@
use gettextrs::gettext;
use heck::CamelCase;
use pulldown_cmark::{Event, Parser, Options, Tag, html};
use rocket::{
http::uri::Uri,
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> {
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())
}