From 4ea071e7099d3da33a149053ed49c40469dcd5c5 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 15:29:19 +0100 Subject: [PATCH 01/10] Switch to pulldown-cmark for markdown parsing + Try to parse mentions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not working correctly yet for some reason… --- Cargo.lock | 137 ++++---------------------------------------- Cargo.toml | 2 +- src/main.rs | 2 +- src/routes/posts.rs | 15 +---- src/utils.rs | 53 +++++++++++++++++ 5 files changed, 66 insertions(+), 143 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc705f35..02988cfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)" = "" "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" diff --git a/Cargo.toml b/Cargo.toml index 62865e72..957e6938 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = "*" diff --git a/src/main.rs b/src/main.rs index 57ecff65..21210e5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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; diff --git a/src/routes/posts.rs b/src/routes/posts.rs index 5cc3262e..ae1de52d 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -1,4 +1,3 @@ -use comrak::{markdown_to_html, ComrakOptions}; use heck::KebabCase; use rocket::request::Form; use rocket::response::{Redirect, Flash}; @@ -88,19 +87,7 @@ fn create(blog_name: String, data: Form, 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 = utils::md_to_html(form.content.to_string().as_ref()); let post = Post::insert(&*conn, NewPost { blog_id: blog.id, diff --git a/src/utils.rs b/src/utils.rs index d93b7819..597ad09c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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,55 @@ pub fn make_actor_id(name: String) -> String { pub fn requires_login(message: &str, url: Uri) -> Flash { Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str()) } + + +pub fn md_to_html(md: &str) -> String { + let parser = Parser::new_ext(md, Options::all()); + let parser = parser.flat_map(|evt| match evt { + Event::Text(txt) => txt.chars().fold((vec![], false, String::new(), 0), |(mut events, in_mention, text_acc, n), c| { + if in_mention { + if c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_' { + (events, in_mention, text_acc + c.to_string().as_ref(), n + 1) + } else { + let short_mention = text_acc.clone(); + let short_mention = short_mention.splitn(1, '@').nth(0).unwrap_or(""); + let link = Tag::Link(format!("/@/{}/", text_acc).into(), short_mention.to_string().into()); + + 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) + } + } else { + if c == '@' { + events.push(Event::Text(text_acc.into())); + (events, true, String::new(), n + 1) + } else { + if n >= (txt.len() - 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) + } + } + }).0, + _ => vec![evt] + }); + let mut buf = String::new(); + html::push_html(&mut buf, parser); + buf + + // let root = parse_document(&arena, md, &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() + // }); +} From 24ef3d00d1ac884a53208f7ca1bb6265db90f710 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 16:25:09 +0100 Subject: [PATCH 02/10] Fix the bugs with markdown rendering when there was mentions --- src/utils.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 597ad09c..787adcbc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -26,12 +26,13 @@ pub fn md_to_html(md: &str) -> String { let parser = parser.flat_map(|evt| match evt { Event::Text(txt) => txt.chars().fold((vec![], false, String::new(), 0), |(mut events, in_mention, text_acc, n), c| { if in_mention { - if c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_' { + 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) } else { - let short_mention = text_acc.clone(); + 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!("/@/{}/", text_acc).into(), short_mention.to_string().into()); + let link = Tag::Link(format!("/@/{}/", mention).into(), short_mention.to_string().into()); events.push(Event::Start(link.clone())); events.push(Event::Text(format!("@{}", short_mention).into())); @@ -44,7 +45,7 @@ pub fn md_to_html(md: &str) -> String { events.push(Event::Text(text_acc.into())); (events, true, String::new(), n + 1) } else { - if n >= (txt.len() - 1) { // Add the text after at the end, even if it is not followed by a mention. + 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) From e074af57ffbf69487925d77af1680da00c3d19b8 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 19:22:34 +0100 Subject: [PATCH 03/10] Add a Mention model --- .../down.sql | 2 + .../2018-06-20-175532_create_mentions/up.sql | 7 ++++ src/db_conn.rs | 6 ++- src/models/mentions.rs | 37 +++++++++++++++++++ src/models/mod.rs | 1 + src/routes/posts.rs | 2 +- src/schema.rs | 13 +++++++ src/setup.rs | 2 +- src/utils.rs | 18 ++------- 9 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 migrations/2018-06-20-175532_create_mentions/down.sql create mode 100644 migrations/2018-06-20-175532_create_mentions/up.sql create mode 100644 src/models/mentions.rs diff --git a/migrations/2018-06-20-175532_create_mentions/down.sql b/migrations/2018-06-20-175532_create_mentions/down.sql new file mode 100644 index 00000000..e860c9ad --- /dev/null +++ b/migrations/2018-06-20-175532_create_mentions/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE mentions; diff --git a/migrations/2018-06-20-175532_create_mentions/up.sql b/migrations/2018-06-20-175532_create_mentions/up.sql new file mode 100644 index 00000000..7640e35b --- /dev/null +++ b/migrations/2018-06-20-175532_create_mentions/up.sql @@ -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 +) diff --git a/src/db_conn.rs b/src/db_conn.rs index c12b011d..7f75f359 100644 --- a/src/db_conn.rs +++ b/src/db_conn.rs @@ -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 { - let pool = request.guard::>>>()?; + let pool = request.guard::>()?; match pool.get() { Ok(conn) => Outcome::Success(DbConn(conn)), Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())) diff --git a/src/models/mentions.rs b/src/models/mentions.rs new file mode 100644 index 00000000..dd29dda5 --- /dev/null +++ b/src/models/mentions.rs @@ -0,0 +1,37 @@ +use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; + +use models::{ + comments::Comment, + posts::Post +}; +use schema::mentions; + +#[derive(Queryable, Identifiable)] +pub struct Mention { + pub id: i32, + pub mentioned_id: i32, + pub post_id: Option, + pub comment_id: Option +} + +#[derive(Insertable)] +#[table_name = "mentions"] +pub struct NewMention { + pub mentioned_id: i32, + pub post_id: Option, + pub comment_id: Option +} + +impl Mention { + insert!(mentions, NewMention); + get!(mentions); + find_by!(mentions, find_for_user, mentioned_id as i32); + + pub fn get_post(&self, conn: &PgConnection) -> Option { + self.post_id.and_then(|id| Post::get(conn, id)) + } + + pub fn get_comment(&self, conn: &PgConnection) -> Option { + self.post_id.and_then(|id| Comment::get(conn, id)) + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index d0f01f3c..13edc569 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -41,6 +41,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; diff --git a/src/routes/posts.rs b/src/routes/posts.rs index ae1de52d..0755d57b 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -13,8 +13,8 @@ use models::{ posts::*, users::User }; -use utils; use safe_string::SafeString; +use utils; #[get("/~//", rank = 4)] fn details(blog: String, slug: String, conn: DbConn, user: Option) -> Template { diff --git a/src/schema.rs b/src/schema.rs index 6614f449..87563fd5 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -66,6 +66,15 @@ table! { } } +table! { + mentions (id) { + id -> Int4, + mentioned_id -> Int4, + post_id -> Nullable, + comment_id -> Nullable, + } +} + table! { notifications (id) { id -> Int4, @@ -137,6 +146,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 +164,7 @@ allow_tables_to_appear_in_same_query!( follows, instances, likes, + mentions, notifications, post_authors, posts, diff --git a/src/setup.rs b/src/setup.rs index da366d09..9c67ed66 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -12,7 +12,7 @@ use db_conn::DbConn; use models::instance::*; use models::users::*; -type PgPool = Pool>; +pub type PgPool = Pool>; /// Initializes a database pool. fn init_pool() -> Option { diff --git a/src/utils.rs b/src/utils.rs index 787adcbc..77745286 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -23,6 +23,7 @@ pub fn requires_login(message: &str, url: Uri) -> Flash { pub fn md_to_html(md: &str) -> String { let parser = Parser::new_ext(md, Options::all()); + let parser = parser.flat_map(|evt| match evt { Event::Text(txt) => txt.chars().fold((vec![], false, String::new(), 0), |(mut events, in_mention, text_acc, n), c| { if in_mention { @@ -54,21 +55,10 @@ pub fn md_to_html(md: &str) -> String { }).0, _ => vec![evt] }); + + // TODO: fetch mentionned profiles in background, if needed + let mut buf = String::new(); html::push_html(&mut buf, parser); buf - - // let root = parse_document(&arena, md, &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() - // }); } From ddd840d31d1bf5eb39950754ad254b90a636326d Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 19:23:54 +0100 Subject: [PATCH 04/10] Add a list_by! macro --- src/models/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/models/mod.rs b/src/models/mod.rs index 13edc569..fa4a4c82 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -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 { + $table::table + $(.filter($table::$col.eq($col)))+ + .load::(conn) + .expect("Error loading $table by $col") + } + }; +} + macro_rules! get { ($table:ident) => { pub fn get(conn: &PgConnection, id: i32) -> Option { From 356cc20e34f804d839386e6ffec30fa246372902 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 19:25:43 +0100 Subject: [PATCH 05/10] List mentions for user, instead of getting only the first one --- src/models/mentions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/mentions.rs b/src/models/mentions.rs index dd29dda5..0a2964ed 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -25,7 +25,7 @@ pub struct NewMention { impl Mention { insert!(mentions, NewMention); get!(mentions); - find_by!(mentions, find_for_user, mentioned_id as i32); + list_by!(mentions, list_for_user, mentioned_id as i32); pub fn get_post(&self, conn: &PgConnection) -> Option { self.post_id.and_then(|id| Post::get(conn, id)) From 215b5775738b0834454d01a52eca18dccb617898 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 20:06:34 +0100 Subject: [PATCH 06/10] Add some ActivityPub function to Mention --- src/activity_pub/inbox.rs | 2 +- src/models/mentions.rs | 40 ++++++++++++++++++++++++++++++++++++++- src/models/users.rs | 26 +++++++++---------------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/activity_pub/inbox.rs b/src/activity_pub/inbox.rs index a20af1ea..8b0856f2 100644 --- a/src/activity_pub/inbox.rs +++ b/src/activity_pub/inbox.rs @@ -40,7 +40,7 @@ pub trait FromActivity: Sized { } } -pub trait Notify { +pub trait Notify { fn notify(conn: &PgConnection, act: T, actor: Id); } diff --git a/src/models/mentions.rs b/src/models/mentions.rs index 0a2964ed..934618fa 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -1,8 +1,11 @@ +use activitypub::link; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; +use activity_pub::Id; use models::{ comments::Comment, - posts::Post + posts::Post, + users::User }; use schema::mentions; @@ -27,6 +30,10 @@ impl Mention { get!(mentions); list_by!(mentions, list_for_user, mentioned_id as i32); + pub fn get_mentioned(&self, conn: &PgConnection) -> Option { + User::get(conn, self.mentioned_id) + } + pub fn get_post(&self, conn: &PgConnection) -> Option { self.post_id.and_then(|id| Post::get(conn, id)) } @@ -34,4 +41,35 @@ impl Mention { pub fn get_comment(&self, conn: &PgConnection) -> Option { self.post_id.and_then(|id| Comment::get(conn, id)) } + + 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 { + let mentioned = User::find_by_ap_url(conn, ment.link_props.href_string().unwrap()).unwrap(); + + if let Some(post) = Post::find_by_ap_url(conn, inside.clone().into()) { + Some(Mention::insert(conn, NewMention { + mentioned_id: mentioned.id, + post_id: Some(post.id), + comment_id: None + })) + } else { + if let Some(comment) = Comment::find_by_ap_url(conn, inside.into()) { + Some(Mention::insert(conn, NewMention { + mentioned_id: mentioned.id, + post_id: None, + comment_id: Some(comment.id) + })) + } else { + None + } + } + } } + diff --git a/src/models/users.rs b/src/models/users.rs index c0dc4902..5a075487 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -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,23 +419,15 @@ impl APActor for User { } fn from_url(conn: &PgConnection, url: String) -> Option { - let in_db = users::table.filter(users::ap_url.eq(url.clone())) - .limit(1) - .load::(conn) - .expect("Error loading user by AP url") - .into_iter().nth(0); - match in_db { - Some(u) => Some(u), - 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 - } + 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() { + Some(User::fetch_from_url(conn, url).unwrap()) + } else { + None } - } + }) } } From c9f29955a0efc2add075a60e4895c8e3d014225d Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 20:42:16 +0100 Subject: [PATCH 07/10] Save incoming mentions --- src/models/comments.rs | 12 ++++++++++++ src/models/mentions.rs | 1 - src/models/posts.rs | 12 +++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/models/comments.rs b/src/models/comments.rs index 5926170a..988ce3af 100644 --- a/src/models/comments.rs +++ b/src/models/comments.rs @@ -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 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::(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(¬e.object_props.content_string().unwrap()), spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")), diff --git a/src/models/mentions.rs b/src/models/mentions.rs index 934618fa..f43a76f4 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -72,4 +72,3 @@ impl Mention { } } } - diff --git a/src/models/posts.rs b/src/models/posts.rs index b0915a63..f4a6408f 100644 --- a/src/models/posts.rs +++ b/src/models/posts.rs @@ -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 @@ -184,6 +185,15 @@ impl Post { impl FromActivity
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::(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 From c4cc4a4e139cdc3da3c9ffced2b46b47fc3bf79c Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 21:05:30 +0100 Subject: [PATCH 08/10] Notify when receiving a mention --- .../down.sql | 2 + .../up.sql | 2 + po/en.po | 3 ++ po/fr.po | 3 ++ po/pl.po | 4 ++ po/plume.pot | 3 ++ src/models/mentions.rs | 51 +++++++++++++++---- src/schema.rs | 1 + 8 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 migrations/2018-06-20-194538_add_mentions_ap_url/down.sql create mode 100644 migrations/2018-06-20-194538_add_mentions_ap_url/up.sql diff --git a/migrations/2018-06-20-194538_add_mentions_ap_url/down.sql b/migrations/2018-06-20-194538_add_mentions_ap_url/down.sql new file mode 100644 index 00000000..4e626f3b --- /dev/null +++ b/migrations/2018-06-20-194538_add_mentions_ap_url/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE mentions DROP COLUMN ap_url; diff --git a/migrations/2018-06-20-194538_add_mentions_ap_url/up.sql b/migrations/2018-06-20-194538_add_mentions_ap_url/up.sql new file mode 100644 index 00000000..df9c3c79 --- /dev/null +++ b/migrations/2018-06-20-194538_add_mentions_ap_url/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE mentions ADD COLUMN ap_url VARCHAR NOT NULL DEFAULT ''; diff --git a/po/en.po b/po/en.po index 899ae1a8..cd7fe411 100644 --- a/po/en.po +++ b/po/en.po @@ -280,3 +280,6 @@ msgstr "" msgid "You are not author in this blog." msgstr "" + +msgid "{{ data }} mentioned you." +msgstr "" diff --git a/po/fr.po b/po/fr.po index ebf655b2..1442a26f 100644 --- a/po/fr.po +++ b/po/fr.po @@ -280,3 +280,6 @@ msgstr "" msgid "You are not author in this blog." msgstr "" + +msgid "{{ data }} mentioned you." +msgstr "" diff --git a/po/pl.po b/po/pl.po index f2910acd..2724bb48 100644 --- a/po/pl.po +++ b/po/pl.po @@ -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ę" diff --git a/po/plume.pot b/po/plume.pot index 0ba8c259..8f0cd9b7 100644 --- a/po/plume.pot +++ b/po/plume.pot @@ -275,3 +275,6 @@ msgstr "" msgid "You are not author in this blog." msgstr "" + +msgid "{{ data }} mentioned you." +msgstr "" diff --git a/src/models/mentions.rs b/src/models/mentions.rs index f43a76f4..f40f9f37 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -1,9 +1,10 @@ use activitypub::link; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; -use activity_pub::Id; +use activity_pub::{Id, inbox::Notify}; use models::{ comments::Comment, + notifications::*, posts::Post, users::User }; @@ -14,7 +15,8 @@ pub struct Mention { pub id: i32, pub mentioned_id: i32, pub post_id: Option, - pub comment_id: Option + pub comment_id: Option, + pub ap_url: String } #[derive(Insertable)] @@ -22,12 +24,14 @@ pub struct Mention { pub struct NewMention { pub mentioned_id: i32, pub post_id: Option, - pub comment_id: Option + pub comment_id: Option, + 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); pub fn get_mentioned(&self, conn: &PgConnection) -> Option { @@ -54,21 +58,50 @@ impl Mention { let mentioned = User::find_by_ap_url(conn, ment.link_props.href_string().unwrap()).unwrap(); if let Some(post) = Post::find_by_ap_url(conn, inside.clone().into()) { - Some(Mention::insert(conn, NewMention { + let res = Some(Mention::insert(conn, NewMention { mentioned_id: mentioned.id, post_id: Some(post.id), - comment_id: None - })) + comment_id: None, + ap_url: ment.link_props.href_string().unwrap_or(String::new()) + })); + Mention::notify(conn, ment, Id::new(String::new())); + res } else { if let Some(comment) = Comment::find_by_ap_url(conn, inside.into()) { - Some(Mention::insert(conn, NewMention { + let res =Some(Mention::insert(conn, NewMention { mentioned_id: mentioned.id, post_id: None, - comment_id: Some(comment.id) - })) + comment_id: Some(comment.id), + ap_url: ment.link_props.href_string().unwrap_or(String::new()) + })); + Mention::notify(conn, ment, Id::new(String::new())); + res } else { None } } } } + +impl Notify for Mention { + fn notify(conn: &PgConnection, ment: link::Mention, _actor: Id) { + match Mention::find_by_ap_url(conn, ment.link_props.href_string().unwrap()) { + Some(mention) => { + let author = mention.get_comment(conn) + .map(|c| c.get_author(conn).display_name.clone()) + .unwrap_or(mention.get_post(conn).unwrap().get_authors(conn)[0].display_name.clone()); + + mention.get_mentioned(conn).map(|m| { + Notification::insert(conn, NewNotification { + title: "{{ data }} mentioned you.".to_string(), + data: Some(author), + content: None, + link: Some(mention.get_post(conn).map(|p| p.ap_url).unwrap_or(mention.get_comment(conn).unwrap().ap_url.unwrap_or(String::new()))), + user_id: m.id + }); + }); + }, + None => println!("Couldn't find mention by AP URL, to create a new notification") + }; + } +} diff --git a/src/schema.rs b/src/schema.rs index 87563fd5..42184146 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -72,6 +72,7 @@ table! { mentioned_id -> Int4, post_id -> Nullable, comment_id -> Nullable, + ap_url -> Varchar, } } From d7b71848fc164e2abb9ed39f7cf0cc4ad35a0a83 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 21:58:11 +0100 Subject: [PATCH 09/10] Save mentions --- src/main.rs | 2 +- src/models/mentions.rs | 9 ++++++ src/models/posts.rs | 6 ++-- src/routes/posts.rs | 9 ++++-- src/utils.rs | 66 +++++++++++++++++++++++------------------- 5 files changed, 57 insertions(+), 35 deletions(-) diff --git a/src/main.rs b/src/main.rs index 21210e5b..793376a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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; diff --git a/src/models/mentions.rs b/src/models/mentions.rs index f40f9f37..aebdc7ae 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -33,6 +33,7 @@ impl Mention { 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::get(conn, self.mentioned_id) @@ -46,6 +47,14 @@ impl Mention { 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()); + 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(); diff --git a/src/models/posts.rs b/src/models/posts.rs index f4a6408f..368d2834 100644 --- a/src/models/posts.rs +++ b/src/models/posts.rs @@ -145,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::>(); + let mut article = Article::default(); article.object_props = ObjectProperties { name: Some(serde_json::to_value(self.title.clone()).unwrap()), @@ -152,11 +154,11 @@ impl Post { attributed_to: Some(serde_json::to_value(self.get_authors(conn).into_iter().map(|x| x.ap_url).collect::>()).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::::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::::new()).unwrap()), - ..ObjectProperties::default() + ..ObjectProperties::default() }; article } diff --git a/src/routes/posts.rs b/src/routes/posts.rs index 0755d57b..fe56629d 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -4,11 +4,12 @@ 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 @@ -87,7 +88,7 @@ fn create(blog_name: String, data: Form, 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 = utils::md_to_html(form.content.to_string().as_ref()); + let (content, mentions) = utils::md_to_html(form.content.to_string().as_ref()); let post = Post::insert(&*conn, NewPost { blog_id: blog.id, @@ -104,6 +105,10 @@ fn create(blog_name: String, data: Form, 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)); diff --git a/src/utils.rs b/src/utils.rs index 77745286..f65ff1c9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,45 +20,51 @@ pub fn requires_login(message: &str, url: Uri) -> Flash { Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str()) } - -pub fn md_to_html(md: &str) -> String { +/// Returns (HTML, mentions) +pub fn md_to_html(md: &str) -> (String, Vec) { let parser = Parser::new_ext(md, Options::all()); - let parser = parser.flat_map(|evt| match evt { - Event::Text(txt) => txt.chars().fold((vec![], false, String::new(), 0), |(mut events, in_mention, text_acc, n), 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) - } 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()); + let (parser, mentions): (Vec>, Vec>) = 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()); - events.push(Event::Start(link.clone())); - events.push(Event::Text(format!("@{}", short_mention).into())); - events.push(Event::End(link)); + 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) - } - } else { - if c == '@' { - events.push(Event::Text(text_acc.into())); - (events, true, String::new(), n + 1) - } 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, 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) } - (events, in_mention, text_acc + c.to_string().as_ref(), n + 1) } - } - }).0, - _ => vec![evt] - }); + }); + (evts, new_mentions) + }, + _ => (vec![evt], vec![]) + }).unzip(); + let parser = parser.into_iter().flatten(); + let mentions = mentions.into_iter().flatten(); // TODO: fetch mentionned profiles in background, if needed let mut buf = String::new(); html::push_html(&mut buf, parser); - buf + (buf, mentions.collect()) } From 3551bef8951087b1c07bc385e8ab10b491a0c4d3 Mon Sep 17 00:00:00 2001 From: Bat Date: Wed, 20 Jun 2018 22:51:47 +0100 Subject: [PATCH 10/10] Simplify the activity_pub::inbox::Notify trait + Fix notifications Also fix a bug with the list of mentions that was returned --- src/activity_pub/inbox.rs | 4 +-- src/models/comments.rs | 30 +++++++++------------- src/models/follows.rs | 8 +++--- src/models/likes.rs | 12 ++++----- src/models/mentions.rs | 53 ++++++++++++++++++--------------------- src/models/reshares.rs | 12 ++++----- src/models/users.rs | 2 +- src/routes/comments.rs | 6 ++--- src/routes/likes.rs | 4 +-- src/routes/reshares.rs | 4 +-- src/routes/user.rs | 5 ++-- src/utils.rs | 2 +- 12 files changed, 67 insertions(+), 75 deletions(-) diff --git a/src/activity_pub/inbox.rs b/src/activity_pub/inbox.rs index 8b0856f2..03055675 100644 --- a/src/activity_pub/inbox.rs +++ b/src/activity_pub/inbox.rs @@ -40,8 +40,8 @@ pub trait FromActivity: Sized { } } -pub trait Notify { - fn notify(conn: &PgConnection, act: T, actor: Id); +pub trait Notify { + fn notify(&self, conn: &PgConnection); } pub trait Deletable { diff --git a/src/models/comments.rs b/src/models/comments.rs index 988ce3af..f943ddb5 100644 --- a/src/models/comments.rs +++ b/src/models/comments.rs @@ -137,27 +137,21 @@ impl FromActivity 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 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(); - 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, - user_id: author.id - }); - } - }, - None => println!("Couldn't find comment by AP id, to create a new notification") - }; +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(self.get_author(conn).display_name.clone()), + content: Some(self.get_post(conn).title), + link: self.ap_url.clone(), + user_id: author.id + }); + } } } diff --git a/src/models/follows.rs b/src/models/follows.rs index 06548625..35188165 100644 --- a/src/models/follows.rs +++ b/src/models/follows.rs @@ -62,15 +62,15 @@ impl FromActivity for Follow { } } -impl Notify 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::().unwrap().into()).unwrap().id + user_id: self.following_id }); } } diff --git a/src/models/likes.rs b/src/models/likes.rs index 3efe9f76..38a4a193 100644 --- a/src/models/likes.rs +++ b/src/models/likes.rs @@ -77,7 +77,7 @@ impl Like { } impl FromActivity 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 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 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::().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 { diff --git a/src/models/mentions.rs b/src/models/mentions.rs index aebdc7ae..fe4fe90a 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -49,6 +49,7 @@ impl Mention { 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"); @@ -64,27 +65,28 @@ impl Mention { } pub fn from_activity(conn: &PgConnection, ment: link::Mention, inside: Id) -> Option { - let mentioned = User::find_by_ap_url(conn, ment.link_props.href_string().unwrap()).unwrap(); + 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 = Some(Mention::insert(conn, NewMention { + 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()) - })); - Mention::notify(conn, ment, Id::new(String::new())); - res + }); + res.notify(conn); + Some(res) } else { if let Some(comment) = Comment::find_by_ap_url(conn, inside.into()) { - let res =Some(Mention::insert(conn, NewMention { + 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()) - })); - Mention::notify(conn, ment, Id::new(String::new())); - res + }); + res.notify(conn); + Some(res) } else { None } @@ -92,25 +94,20 @@ impl Mention { } } -impl Notify for Mention { - fn notify(conn: &PgConnection, ment: link::Mention, _actor: Id) { - match Mention::find_by_ap_url(conn, ment.link_props.href_string().unwrap()) { - Some(mention) => { - let author = mention.get_comment(conn) - .map(|c| c.get_author(conn).display_name.clone()) - .unwrap_or(mention.get_post(conn).unwrap().get_authors(conn)[0].display_name.clone()); +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()); - mention.get_mentioned(conn).map(|m| { - Notification::insert(conn, NewNotification { - title: "{{ data }} mentioned you.".to_string(), - data: Some(author), - content: None, - link: Some(mention.get_post(conn).map(|p| p.ap_url).unwrap_or(mention.get_comment(conn).unwrap().ap_url.unwrap_or(String::new()))), - user_id: m.id - }); - }); - }, - None => println!("Couldn't find mention by AP URL, to create a new notification") - }; + 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 + }); + }); } } diff --git a/src/models/reshares.rs b/src/models/reshares.rs index f1858cea..40a210d3 100644 --- a/src/models/reshares.rs +++ b/src/models/reshares.rs @@ -73,7 +73,7 @@ impl Reshare { } impl FromActivity 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 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 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::().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 { diff --git a/src/models/users.rs b/src/models/users.rs index 5a075487..ee7639c8 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -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, diff --git a/src/routes/comments.rs b/src/routes/comments.rs index 49e678be..e7fe466a 100644 --- a/src/routes/comments.rs +++ b/src/routes/comments.rs @@ -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 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(); diff --git a/src/routes/reshares.rs b/src/routes/reshares.rs index 6da07f77..5212faae 100644 --- a/src/routes/reshares.rs +++ b/src/routes/reshares.rs @@ -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(); diff --git a/src/routes/user.rs b/src/routes/user.rs index 7a778469..da78cf6a 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -71,16 +71,17 @@ fn dashboard_auth() -> Flash { #[get("/@//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::(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)) } diff --git a/src/utils.rs b/src/utils.rs index f65ff1c9..8b14959c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -60,7 +60,7 @@ pub fn md_to_html(md: &str) -> (String, Vec) { _ => (vec![evt], vec![]) }).unzip(); let parser = parser.into_iter().flatten(); - let mentions = mentions.into_iter().flatten(); + let mentions = mentions.into_iter().flatten().map(|m| String::from(m.trim())); // TODO: fetch mentionned profiles in background, if needed