From: Dessalines Date: Tue, 14 Apr 2020 20:07:20 +0000 (-0400) Subject: Merge branch 'dev' into federation X-Git-Url: http://these/git/?a=commitdiff_plain;h=1336b4ed6023e7fcf0fd40be63569966ee4b1b45;hp=641e4c5d96d9d152bc75318b3ea08f789d920b2b;p=lemmy.git Merge branch 'dev' into federation --- diff --git a/.dockerignore b/.dockerignore index a29cd2ec..4f186bcd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,11 @@ +# build folders and similar which are not needed for the docker build ui/node_modules -ui/dist server/target docker/dev/volumes docker/federation/volumes .git +ansible + +# exceptions, needed for federation-test build + +!server/target/debug/lemmy_server diff --git a/.gitignore b/.gitignore index 9f7fa1e3..5e9fd40d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,17 @@ +# local ansible configuration ansible/inventory ansible/inventory_dev ansible/passwords/ + +# docker build files docker/lemmy_mine.hjson docker/dev/env_deploy.sh +docker/federation/volumes +docker/dev/volumes + +# local build files build/ -.idea/ ui/src/translations -docker/dev/volumes -docker/federation-test/volumes + +# ide config +.idea/ diff --git a/docker/federation/Dockerfile b/docker/federation/Dockerfile new file mode 100644 index 00000000..d8302ea7 --- /dev/null +++ b/docker/federation/Dockerfile @@ -0,0 +1,17 @@ +FROM ekidd/rust-musl-builder:1.38.0-openssl11 + +USER root +RUN mkdir /app/dist/documentation/ -p \ + && addgroup --gid 1001 lemmy \ + && adduser --disabled-password --shell /bin/sh -u 1001 --ingroup lemmy lemmy + +# Copy resources +COPY server/config/defaults.hjson /app/config/defaults.hjson +COPY ui/dist /app/dist +COPY server/target/debug/lemmy_server /app/lemmy + +RUN chown lemmy:lemmy /app/ -R +USER lemmy +EXPOSE 8536 +WORKDIR /app +CMD ["/app/lemmy"] diff --git a/docker/federation/docker-compose.yml b/docker/federation/docker-compose.yml new file mode 100644 index 00000000..216ac9a1 --- /dev/null +++ b/docker/federation/docker-compose.yml @@ -0,0 +1,91 @@ +version: '3.3' + +services: + nginx: + image: nginx:1.17-alpine + ports: + - "8540:8540" + - "8550:8550" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: + - lemmy_alpha + - pictshare_alpha + - lemmy_beta + - pictshare_beta + - iframely + restart: "always" + + lemmy_alpha: + image: lemmy-federation:latest + environment: + - LEMMY_HOSTNAME=lemmy_alpha:8540 + - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_alpha:5432/lemmy + - LEMMY_JWT_SECRET=changeme + - LEMMY_FRONT_END_DIR=/app/dist + - LEMMY_FEDERATION__ENABLED=true + - LEMMY_FEDERATION__FOLLOWED_INSTANCES=lemmy_beta:8550 + - LEMMY_FEDERATION__TLS_ENABLED=false + - LEMMY_PORT=8540 + - LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha + - LEMMY_SETUP__ADMIN_PASSWORD=lemmy + - LEMMY_SETUP__SITE_NAME=lemmy_alpha + - RUST_BACKTRACE=1 + - RUST_LOG=actix_web=debug + restart: always + depends_on: + - postgres_alpha + postgres_alpha: + image: postgres:12-alpine + environment: + - POSTGRES_USER=lemmy + - POSTGRES_PASSWORD=password + - POSTGRES_DB=lemmy + volumes: + - ./volumes/postgres_alpha:/var/lib/postgresql/data + restart: always + pictshare_alpha: + image: shtripok/pictshare:latest + volumes: + - ./volumes/pictshare_alpha:/usr/share/nginx/html/data + restart: always + + lemmy_beta: + image: lemmy-federation:latest + environment: + - LEMMY_HOSTNAME=lemmy_beta:8550 + - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_beta:5432/lemmy + - LEMMY_JWT_SECRET=changeme + - LEMMY_FRONT_END_DIR=/app/dist + - LEMMY_FEDERATION__ENABLED=true + - LEMMY_FEDERATION__FOLLOWED_INSTANCES=lemmy_alpha:8540 + - LEMMY_FEDERATION__TLS_ENABLED=false + - LEMMY_PORT=8550 + - LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta + - LEMMY_SETUP__ADMIN_PASSWORD=lemmy + - LEMMY_SETUP__SITE_NAME=lemmy_beta + - RUST_BACKTRACE=1 + - RUST_LOG=actix_web=debug + restart: always + depends_on: + - postgres_beta + postgres_beta: + image: postgres:12-alpine + environment: + - POSTGRES_USER=lemmy + - POSTGRES_PASSWORD=password + - POSTGRES_DB=lemmy + volumes: + - ./volumes/postgres_beta:/var/lib/postgresql/data + restart: always + pictshare_beta: + image: shtripok/pictshare:latest + volumes: + - ./volumes/pictshare_beta:/usr/share/nginx/html/data + restart: always + + iframely: + image: dogbin/iframely:latest + volumes: + - ../iframely.config.local.js:/iframely/config.local.js:ro + restart: always diff --git a/docker/federation/nginx.conf b/docker/federation/nginx.conf new file mode 100644 index 00000000..c0633ea4 --- /dev/null +++ b/docker/federation/nginx.conf @@ -0,0 +1,75 @@ +events { + worker_connections 1024; +} + +http { + server { + listen 8540; + server_name 127.0.0.1; + access_log off; + + # Upload limit for pictshare + client_max_body_size 50M; + + location / { + proxy_pass http://lemmy_alpha:8540; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # WebSocket support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location /pictshare/ { + proxy_pass http://pictshare_alpha:80/; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location /iframely/ { + proxy_pass http://iframely:80/; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } + + server { + listen 8550; + server_name 127.0.0.1; + access_log off; + + # Upload limit for pictshare + client_max_body_size 50M; + + location / { + proxy_pass http://lemmy_beta:8550; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # WebSocket support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location /pictshare/ { + proxy_pass http://pictshare_beta:80/; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location /iframely/ { + proxy_pass http://iframely:80/; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } +} diff --git a/docker/federation/run-federation-test.bash b/docker/federation/run-federation-test.bash new file mode 100755 index 00000000..62bc1e8b --- /dev/null +++ b/docker/federation/run-federation-test.bash @@ -0,0 +1,16 @@ +#!/bin/bash +set -e + +if [ "$1" = "-yarn" ]; then + pushd ../../ui/ || exit + yarn build + popd || exit +fi + +pushd ../../server/ || exit +cargo build +popd || exit + +sudo docker build ../../ -f Dockerfile -t lemmy-federation:latest + +sudo docker-compose up \ No newline at end of file diff --git a/server/Cargo.lock b/server/Cargo.lock index 2a3bc033..b17f4d60 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1,21 +1,22 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "activitypub" -version = "0.2.0" +name = "activitystreams" +version = "0.5.0-alpha.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "activitystreams-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "activitystreams-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "activitystreams-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "activitystreams-derive 0.5.0-alpha.8 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "activitystreams-derive" -version = "0.2.0" +version = "0.5.0-alpha.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -23,30 +24,6 @@ dependencies = [ "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "activitystreams-traits" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "activitystreams-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "activitystreams-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "activitystreams-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "actix" version = "0.9.0" @@ -143,7 +120,7 @@ dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -372,7 +349,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -388,7 +365,7 @@ dependencies = [ [[package]] name = "arc-swap" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -420,7 +397,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -461,19 +438,19 @@ name = "backtrace" version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -563,7 +540,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -572,7 +549,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -608,14 +585,6 @@ dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cc" version = "1.0.50" @@ -701,7 +670,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -738,11 +707,11 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.4.28+curl-7.69.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.30+curl-7.69.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -752,11 +721,11 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.28+curl-7.69.0" +version = "0.4.30+curl-7.69.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "libnghttp2-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1043,12 +1012,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1137,7 +1106,7 @@ name = "futures-macro" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1166,8 +1135,8 @@ dependencies = [ "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1193,7 +1162,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1228,7 +1197,7 @@ name = "hermit-abi" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1247,7 +1216,7 @@ name = "hostname" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1256,7 +1225,7 @@ name = "hostname" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1317,7 +1286,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1339,8 +1308,8 @@ dependencies = [ "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.28+curl-7.69.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.30+curl-7.69.1 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)", "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1412,7 +1381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "lemmy_server" version = "0.0.1" dependencies = [ - "activitypub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "activitystreams 0.5.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", "actix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "actix-files 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "actix-rt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1435,6 +1404,7 @@ dependencies = [ "lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "lettre_email 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1444,6 +1414,7 @@ dependencies = [ "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1484,13 +1455,13 @@ dependencies = [ "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libc" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1499,7 +1470,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1508,7 +1479,7 @@ version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1576,7 +1547,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1635,7 +1606,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1649,7 +1620,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1670,7 +1641,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1687,7 +1658,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1756,7 +1727,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1773,7 +1744,7 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1789,7 +1760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1810,7 +1781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1918,7 +1889,7 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1928,7 +1899,7 @@ dependencies = [ [[package]] name = "proc-macro-nested" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1977,7 +1948,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1989,7 +1960,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2007,8 +1978,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2024,10 +1995,10 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2081,7 +2052,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2093,7 +2064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2146,7 +2117,7 @@ name = "regex" version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2186,7 +2157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2227,7 +2198,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2274,7 +2245,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2355,7 +2326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2410,8 +2381,8 @@ name = "signal-hook-registry" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2451,7 +2422,7 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2524,7 +2495,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2571,7 +2542,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2603,7 +2574,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2618,7 +2589,7 @@ dependencies = [ "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2772,6 +2743,7 @@ dependencies = [ "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2974,10 +2946,8 @@ dependencies = [ ] [metadata] -"checksum activitypub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d538a21b137ec0f63cc579ef4afa4ab13aa85b4f8af15a033683edd97c50718d" -"checksum activitystreams-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "65608fdeae5eb05485d5b71a3d2242d76b2b7413608c196d47eb4dff3eed7b85" -"checksum activitystreams-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c2a3958d240f40eff1f31b5f679a6e0d4ce2a16812886a3ec0164f3a2ca517" -"checksum activitystreams-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0598820663a59e5eaafeeedd3a7f7efc93db4ed6172905baec05503095ba5c0e" +"checksum activitystreams 0.5.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e7173513c9d586a1157f375835777e3b50498b6b7aab4411a7098b455ba995f0" +"checksum activitystreams-derive 0.5.0-alpha.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7ff4a2be3b67d763e78794f622ef2d53da077521229774837f61963c4067b36" "checksum actix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4af87564ff659dee8f9981540cac9418c45e910c8072fdedd643a262a38fcaf" "checksum actix-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09e55f0a5c2ca15795035d90c46bd0e73a5123b72f68f12596d6ba5282051380" "checksum actix-connect 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c95cc9569221e9802bf4c377f6c18b90ef10227d787611decf79fd47d2a8e76c" @@ -2998,9 +2968,9 @@ dependencies = [ "checksum actix_derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c" "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" -"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" +"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" +"checksum arc-swap 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d663a8e9a99154b5fb793032533f6328da35e23aac63d5c152279aa8ba356825" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" "checksum async-trait 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "750b1c38a1dfadd108da0f01c08f4cdc7ff1bb39b325f9c82cc972361780a6e1" @@ -3009,7 +2979,7 @@ dependencies = [ "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum awc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7601d4d1d7ef2335d6597a41b5fe069f6ab799b85f53565ab390e7b7065aac5" "checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" -"checksum backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35" +"checksum backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3" @@ -3028,7 +2998,6 @@ dependencies = [ "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" "checksum bytestring 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fc267467f58ef6cc8874064c62a0423eb0d099362c8a23edd1c6d044f46eead4" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" @@ -3042,8 +3011,8 @@ dependencies = [ "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum curl 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "ecb534fed9060d04bccaa8b8e1e2d3d5a0d7a9ec6d9c667691c80a3c6b7d19ef" -"checksum curl-sys 0.4.28+curl-7.69.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c6b7fa5d36aa192e410788b77af65f339af24c8786419e8b48173689a484bf" +"checksum curl 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)" = "eda1c0c03cacf3365d84818a40293f0e3f3953db8759c9c565a3b434edf0b52e" +"checksum curl-sys 0.4.30+curl-7.69.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923b38e423a8f47a4058e96f2a1fa2865a6231097ee860debd678d244277d50c" "checksum darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" "checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" "checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" @@ -3075,7 +3044,7 @@ dependencies = [ "checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4" -"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" +"checksum flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" @@ -3121,7 +3090,7 @@ dependencies = [ "checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728" "checksum lettre_email 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bbb68ca999042d965476e47bbdbacd52db0927348b6f8062c44dd04a3b1fd43b" "checksum lexical-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d7043aa5c05dd34fb73b47acb8c3708eac428de4545ea3682ed2f11293ebd890" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum libnghttp2-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b359f5ec8106bc297694c9a562ace312be2cfd17a5fc68dc12249845aa144b11" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" @@ -3172,8 +3141,8 @@ dependencies = [ "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum pq-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" -"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" -"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" +"checksum proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f918f2b601f93baa836c1c2945faef682ba5b6d4828ecb45eeb7cc3c71b811b4" +"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" "checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quick-xml 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fe1e430bdcf30c9fdc25053b9c459bb1a4672af4617b6c783d7d91dc17c6bbb0" @@ -3183,7 +3152,7 @@ dependencies = [ "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" @@ -3208,7 +3177,7 @@ dependencies = [ "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum schannel 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "507a9e6e8ffe0a4e0ebb9a10293e62fdf7657c06f1b8bb07a8fcf697d2abf295" "checksum scheduled-thread-pool 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f5de7bc31f28f8e6c28df5e1bf3d10610f5fdc14cc95f272853512c70a2bd779" diff --git a/server/Cargo.toml b/server/Cargo.toml index 5a4fdcec..03bbfbee 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2", "64-column-tables"] } diesel_migrations = "1.4.0" dotenv = "0.15.0" +activitystreams = "0.5.0-alpha.16" bcrypt = "0.6.2" -activitypub = "0.2.0" chrono = { version = "0.4.7", features = ["serde"] } failure = "0.1.5" serde_json = { version = "1.0.48", features = ["preserve_order"]} @@ -34,6 +34,8 @@ rss = "1.9.0" htmlescape = "0.3.1" config = "0.10.1" hjson = "0.8.2" +url = { version = "2.1.1", features = ["serde"] } percent-encoding = "2.1.0" isahc = "0.9" comrak = "0.7" +openssl = "0.10" diff --git a/server/config/config.hjson b/server/config/config.hjson new file mode 100644 index 00000000..96eff45d --- /dev/null +++ b/server/config/config.hjson @@ -0,0 +1,4 @@ +{ + hostname: "localhost:8536" + federation_enabled: true +} \ No newline at end of file diff --git a/server/config/defaults.hjson b/server/config/defaults.hjson index 97b9429c..8603e49a 100644 --- a/server/config/defaults.hjson +++ b/server/config/defaults.hjson @@ -26,7 +26,7 @@ pool_size: 5 } # the domain name of your instance (eg "dev.lemmy.ml") - hostname: "my_domain" + hostname: null # address where lemmy should listen for incoming requests bind: "0.0.0.0" # port where lemmy should listen for incoming requests @@ -35,9 +35,6 @@ jwt_secret: "changeme" # The dir for the front end front_end_dir: "../ui/dist" - # whether to enable activitypub federation. this feature is in alpha, do not enable in production, as might - # cause problems like remote instances fetching and permanently storing bad data. - federation_enabled: false # rate limits for various user actions, by user ip rate_limit: { # maximum number of messages created in interval @@ -53,6 +50,15 @@ # interval length for registration limit register_per_second: 3600 } + # settings related to activitypub federation + federation: { + # whether to enable activitypub federation. this feature is in alpha, do not enable in production. + enabled: false + # comma seperated list of instances to follow + followed_instances: "" + # whether tls is required for activitypub. only disable this for debugging, never for producion. + tls_enabled: true + } # # email sending configuration # email: { # # hostname of the smtp server diff --git a/server/migrations/2020-03-26-192410_add_activitypub_tables/down.sql b/server/migrations/2020-03-26-192410_add_activitypub_tables/down.sql new file mode 100644 index 00000000..b1710623 --- /dev/null +++ b/server/migrations/2020-03-26-192410_add_activitypub_tables/down.sql @@ -0,0 +1,16 @@ +drop table activity; + +alter table user_ +drop column actor_id, +drop column private_key, +drop column public_key, +drop column bio, +drop column local, +drop column last_refreshed_at; + +alter table community +drop column actor_id, +drop column private_key, +drop column public_key, +drop column local, +drop column last_refreshed_at; diff --git a/server/migrations/2020-03-26-192410_add_activitypub_tables/up.sql b/server/migrations/2020-03-26-192410_add_activitypub_tables/up.sql new file mode 100644 index 00000000..8fe3b8ed --- /dev/null +++ b/server/migrations/2020-03-26-192410_add_activitypub_tables/up.sql @@ -0,0 +1,36 @@ +-- The Activitypub activity table +-- All user actions must create a row here. +create table activity ( + id serial primary key, + user_id int references user_ on update cascade on delete cascade not null, -- Ensures that the user is set up here. + data jsonb not null, + local boolean not null default true, + published timestamp not null default now(), + updated timestamp +); + +-- Making sure that id is unique +create unique index idx_activity_unique_apid on activity ((data ->> 'id'::text)); + +-- Add federation columns to the two actor tables +alter table user_ +-- TODO uniqueness constraints should be added on these 3 columns later +add column actor_id character varying(255) not null default 'changeme', -- This needs to be checked and updated in code, building from the site url if local +add column bio text, -- not on community, already has description +add column local boolean not null default true, +add column private_key text, -- These need to be generated from code +add column public_key text, +add column last_refreshed_at timestamp not null default now() -- Used to re-fetch federated actor periodically +; + +-- Community +alter table community +add column actor_id character varying(255) not null default 'changeme', -- This needs to be checked and updated in code, building from the site url if local +add column local boolean not null default true, +add column private_key text, -- These need to be generated from code +add column public_key text, +add column last_refreshed_at timestamp not null default now() -- Used to re-fetch federated actor periodically +; + +-- Don't worry about rebuilding the views right now. + diff --git a/server/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql b/server/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql new file mode 100644 index 00000000..50c95bb2 --- /dev/null +++ b/server/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/down.sql @@ -0,0 +1,7 @@ +alter table post +drop column ap_id, +drop column local; + +alter table comment +drop column ap_id, +drop column local; diff --git a/server/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql b/server/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql new file mode 100644 index 00000000..a3fb9562 --- /dev/null +++ b/server/migrations/2020-04-03-194936_add_activitypub_for_posts_and_comments/up.sql @@ -0,0 +1,14 @@ +-- Add federation columns to post, comment + +alter table post +-- TODO uniqueness constraints should be added on these 3 columns later +add column ap_id character varying(255) not null default 'changeme', -- This needs to be checked and updated in code, building from the site url if local +add column local boolean not null default true +; + +alter table comment +-- TODO uniqueness constraints should be added on these 3 columns later +add column ap_id character varying(255) not null default 'changeme', -- This needs to be checked and updated in code, building from the site url if local +add column local boolean not null default true +; + diff --git a/server/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql b/server/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql new file mode 100644 index 00000000..faf24fdc --- /dev/null +++ b/server/migrations/2020-04-07-135912_add_user_community_apub_constraints/down.sql @@ -0,0 +1,36 @@ +-- User table +drop view user_view cascade; + +alter table user_ +add column fedi_name varchar(40) not null default 'changeme'; + +alter table user_ +add constraint user__name_fedi_name_key unique (name, fedi_name); + +-- Community +alter table community +add constraint community_name_key unique (name); + + +create view user_view as +select +u.id, +u.name, +u.avatar, +u.email, +u.matrix_user_id, +u.fedi_name, +u.admin, +u.banned, +u.show_avatars, +u.send_notifications_to_email, +u.published, +(select count(*) from post p where p.creator_id = u.id) as number_of_posts, +(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, +(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, +(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score +from user_ u; + +create materialized view user_mview as select * from user_view; + +create unique index idx_user_mview_id on user_mview (id); diff --git a/server/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql b/server/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql new file mode 100644 index 00000000..de65191d --- /dev/null +++ b/server/migrations/2020-04-07-135912_add_user_community_apub_constraints/up.sql @@ -0,0 +1,38 @@ +-- User table + +-- Need to regenerate user_view, user_mview +drop view user_view cascade; + +-- Remove the fedi_name constraint, drop that useless column +alter table user_ +drop constraint user__name_fedi_name_key; + +alter table user_ +drop column fedi_name; + +-- Community +alter table community +drop constraint community_name_key; + +create view user_view as +select +u.id, +u.name, +u.avatar, +u.email, +u.matrix_user_id, +u.admin, +u.banned, +u.show_avatars, +u.send_notifications_to_email, +u.published, +(select count(*) from post p where p.creator_id = u.id) as number_of_posts, +(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, +(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, +(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score +from user_ u; + +create materialized view user_mview as select * from user_view; + +create unique index idx_user_mview_id on user_mview (id); + diff --git a/server/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql b/server/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql new file mode 100644 index 00000000..ce2dde39 --- /dev/null +++ b/server/migrations/2020-04-14-163701_update_views_for_activitypub/down.sql @@ -0,0 +1,440 @@ +-- user_view +drop view user_view cascade; + +create view user_view as +select +u.id, +u.name, +u.avatar, +u.email, +u.matrix_user_id, +u.admin, +u.banned, +u.show_avatars, +u.send_notifications_to_email, +u.published, +(select count(*) from post p where p.creator_id = u.id) as number_of_posts, +(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, +(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, +(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score +from user_ u; + +create materialized view user_mview as select * from user_view; + +create unique index idx_user_mview_id on user_mview (id); + +-- community_view +drop view community_aggregates_view cascade; +create view community_aggregates_view as +select c.*, +(select name from user_ u where c.creator_id = u.id) as creator_name, +(select avatar from user_ u where c.creator_id = u.id) as creator_avatar, +(select name from category ct where c.category_id = ct.id) as category_name, +(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, +(select count(*) from post p where p.community_id = c.id) as number_of_posts, +(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, +hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank +from community c; + +create materialized view community_aggregates_mview as select * from community_aggregates_view; + +create unique index idx_community_aggregates_mview_id on community_aggregates_mview (id); + +create view community_view as +with all_community as +( + select + ca.* + from community_aggregates_view ca +) + +select +ac.*, +u.id as user_id, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed +from user_ u +cross join all_community ac + +union all + +select +ac.*, +null as user_id, +null as subscribed +from all_community ac +; + +create view community_mview as +with all_community as +( + select + ca.* + from community_aggregates_mview ca +) + +select +ac.*, +u.id as user_id, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed +from user_ u +cross join all_community ac + +union all + +select +ac.*, +null as user_id, +null as subscribed +from all_community ac +; + +-- community views +drop view community_moderator_view; +drop view community_follower_view; +drop view community_user_ban_view; + +create view community_moderator_view as +select *, +(select name from user_ u where cm.user_id = u.id) as user_name, +(select avatar from user_ u where cm.user_id = u.id), +(select name from community c where cm.community_id = c.id) as community_name +from community_moderator cm; + +create view community_follower_view as +select *, +(select name from user_ u where cf.user_id = u.id) as user_name, +(select avatar from user_ u where cf.user_id = u.id), +(select name from community c where cf.community_id = c.id) as community_name +from community_follower cf; + +create view community_user_ban_view as +select *, +(select name from user_ u where cm.user_id = u.id) as user_name, +(select avatar from user_ u where cm.user_id = u.id), +(select name from community c where cm.community_id = c.id) as community_name +from community_user_ban cm; + +-- post_view +drop view post_view; +drop view post_mview; +drop materialized view post_aggregates_mview; +drop view post_aggregates_view; + +-- regen post view +create view post_aggregates_view as +select +p.*, +(select u.banned from user_ u where p.creator_id = u.id) as banned, +(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, +(select name from user_ where p.creator_id = user_.id) as creator_name, +(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, +(select name from community where p.community_id = community.id) as community_name, +(select removed from community c where p.community_id = c.id) as community_removed, +(select deleted from community c where p.community_id = c.id) as community_deleted, +(select nsfw from community c where p.community_id = c.id) as community_nsfw, +(select count(*) from comment where comment.post_id = p.id) as number_of_comments, +coalesce(sum(pl.score), 0) as score, +count (case when pl.score = 1 then 1 else null end) as upvotes, +count (case when pl.score = -1 then 1 else null end) as downvotes, +hot_rank(coalesce(sum(pl.score) , 0), + ( + case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps + else greatest(c.recent_comment_time, p.published) + end + ) +) as hot_rank, +( + case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps + else greatest(c.recent_comment_time, p.published) + end +) as newest_activity_time +from post p +left join post_like pl on p.id = pl.post_id +left join ( + select post_id, + max(published) as recent_comment_time + from comment + group by 1 +) c on p.id = c.post_id +group by p.id, c.recent_comment_time; + +create materialized view post_aggregates_mview as select * from post_aggregates_view; + +create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); + +create view post_view as +with all_post as ( + select + pa.* + from post_aggregates_view pa +) +select +ap.*, +u.id as user_id, +coalesce(pl.score, 0) as my_vote, +(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, +(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, +(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved +from user_ u +cross join all_post ap +left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id + +union all + +select +ap.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from all_post ap +; + +create view post_mview as +with all_post as ( + select + pa.* + from post_aggregates_mview pa +) +select +ap.*, +u.id as user_id, +coalesce(pl.score, 0) as my_vote, +(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, +(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, +(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved +from user_ u +cross join all_post ap +left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id + +union all + +select +ap.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from all_post ap +; + + +-- reply_view, comment_view, user_mention +drop view reply_view; +drop view user_mention_view; +drop view user_mention_mview; +drop view comment_view; +drop view comment_mview; +drop materialized view comment_aggregates_mview; +drop view comment_aggregates_view; + +-- reply and comment view +create view comment_aggregates_view as +select +c.*, +(select community_id from post p where p.id = c.post_id), +(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name, +(select u.banned from user_ u where c.creator_id = u.id) as banned, +(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, +(select name from user_ where c.creator_id = user_.id) as creator_name, +(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, +coalesce(sum(cl.score), 0) as score, +count (case when cl.score = 1 then 1 else null end) as upvotes, +count (case when cl.score = -1 then 1 else null end) as downvotes, +hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank +from comment c +left join comment_like cl on c.id = cl.comment_id +group by c.id; + +create materialized view comment_aggregates_mview as select * from comment_aggregates_view; + +create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); + +create view comment_view as +with all_comment as +( + select + ca.* + from comment_aggregates_view ca +) + +select +ac.*, +u.id as user_id, +coalesce(cl.score, 0) as my_vote, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, +(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved +from user_ u +cross join all_comment ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id + +union all + +select + ac.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from all_comment ac +; + +create view comment_mview as +with all_comment as +( + select + ca.* + from comment_aggregates_mview ca +) + +select +ac.*, +u.id as user_id, +coalesce(cl.score, 0) as my_vote, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, +(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved +from user_ u +cross join all_comment ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id + +union all + +select + ac.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from all_comment ac +; + +-- Do the reply_view referencing the comment_mview +create view reply_view as +with closereply as ( + select + c2.id, + c2.creator_id as sender_id, + c.creator_id as recipient_id + from comment c + inner join comment c2 on c.id = c2.parent_id + where c2.creator_id != c.creator_id + -- Do union where post is null + union + select + c.id, + c.creator_id as sender_id, + p.creator_id as recipient_id + from comment c, post p + where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +) +select cv.*, +closereply.recipient_id +from comment_mview cv, closereply +where closereply.id = cv.id +; + +-- user mention +create view user_mention_view as +select + c.id, + um.id as user_mention_id, + c.creator_id, + c.post_id, + c.parent_id, + c.content, + c.removed, + um.read, + c.published, + c.updated, + c.deleted, + c.community_id, + c.community_name, + c.banned, + c.banned_from_community, + c.creator_name, + c.creator_avatar, + c.score, + c.upvotes, + c.downvotes, + c.hot_rank, + c.user_id, + c.my_vote, + c.saved, + um.recipient_id +from user_mention um, comment_view c +where um.comment_id = c.id; + + +create view user_mention_mview as +with all_comment as +( + select + ca.* + from comment_aggregates_mview ca +) + +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + um.recipient_id +from user_ u +cross join all_comment ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id +left join user_mention um on um.comment_id = ac.id + +union all + +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + null as user_id, + null as my_vote, + null as saved, + um.recipient_id +from all_comment ac +left join user_mention um on um.comment_id = ac.id +; + diff --git a/server/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql b/server/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql new file mode 100644 index 00000000..02499fc2 --- /dev/null +++ b/server/migrations/2020-04-14-163701_update_views_for_activitypub/up.sql @@ -0,0 +1,497 @@ +-- user_view +drop view user_view cascade; + +create view user_view as +select +u.id, +u.actor_id, +u.name, +u.avatar, +u.email, +u.matrix_user_id, +u.bio, +u.local, +u.admin, +u.banned, +u.show_avatars, +u.send_notifications_to_email, +u.published, +(select count(*) from post p where p.creator_id = u.id) as number_of_posts, +(select coalesce(sum(score), 0) from post p, post_like pl where u.id = p.creator_id and p.id = pl.post_id) as post_score, +(select count(*) from comment c where c.creator_id = u.id) as number_of_comments, +(select coalesce(sum(score), 0) from comment c, comment_like cl where u.id = c.creator_id and c.id = cl.comment_id) as comment_score +from user_ u; + +create materialized view user_mview as select * from user_view; + +create unique index idx_user_mview_id on user_mview (id); + +-- community_view +drop view community_aggregates_view cascade; +create view community_aggregates_view as +-- Now that there's public and private keys, you have to be explicit here +select c.id, +c.name, +c.title, +c.description, +c.category_id, +c.creator_id, +c.removed, +c.published, +c.updated, +c.deleted, +c.nsfw, +c.actor_id, +c.local, +c.last_refreshed_at, +(select actor_id from user_ u where c.creator_id = u.id) as creator_actor_id, +(select local from user_ u where c.creator_id = u.id) as creator_local, +(select name from user_ u where c.creator_id = u.id) as creator_name, +(select avatar from user_ u where c.creator_id = u.id) as creator_avatar, +(select name from category ct where c.category_id = ct.id) as category_name, +(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, +(select count(*) from post p where p.community_id = c.id) as number_of_posts, +(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments, +hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank +from community c; + +create materialized view community_aggregates_mview as select * from community_aggregates_view; + +create unique index idx_community_aggregates_mview_id on community_aggregates_mview (id); + +create view community_view as +with all_community as +( + select + ca.* + from community_aggregates_view ca +) + +select +ac.*, +u.id as user_id, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed +from user_ u +cross join all_community ac + +union all + +select +ac.*, +null as user_id, +null as subscribed +from all_community ac +; + +create view community_mview as +with all_community as +( + select + ca.* + from community_aggregates_mview ca +) + +select +ac.*, +u.id as user_id, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed +from user_ u +cross join all_community ac + +union all + +select +ac.*, +null as user_id, +null as subscribed +from all_community ac +; + +-- community views +drop view community_moderator_view; +drop view community_follower_view; +drop view community_user_ban_view; + +create view community_moderator_view as +select *, +(select actor_id from user_ u where cm.user_id = u.id) as user_actor_id, +(select local from user_ u where cm.user_id = u.id) as user_local, +(select name from user_ u where cm.user_id = u.id) as user_name, +(select avatar from user_ u where cm.user_id = u.id), +(select actor_id from community c where cm.community_id = c.id) as community_actor_id, +(select local from community c where cm.community_id = c.id) as community_local, +(select name from community c where cm.community_id = c.id) as community_name +from community_moderator cm; + +create view community_follower_view as +select *, +(select actor_id from user_ u where cf.user_id = u.id) as user_actor_id, +(select local from user_ u where cf.user_id = u.id) as user_local, +(select name from user_ u where cf.user_id = u.id) as user_name, +(select avatar from user_ u where cf.user_id = u.id), +(select actor_id from community c where cf.community_id = c.id) as community_actor_id, +(select local from community c where cf.community_id = c.id) as community_local, +(select name from community c where cf.community_id = c.id) as community_name +from community_follower cf; + +create view community_user_ban_view as +select *, +(select actor_id from user_ u where cm.user_id = u.id) as user_actor_id, +(select local from user_ u where cm.user_id = u.id) as user_local, +(select name from user_ u where cm.user_id = u.id) as user_name, +(select avatar from user_ u where cm.user_id = u.id), +(select actor_id from community c where cm.community_id = c.id) as community_actor_id, +(select local from community c where cm.community_id = c.id) as community_local, +(select name from community c where cm.community_id = c.id) as community_name +from community_user_ban cm; + +-- post_view +drop view post_view; +drop view post_mview; +drop materialized view post_aggregates_mview; +drop view post_aggregates_view; + +-- regen post view +create view post_aggregates_view as +select +p.*, +(select u.banned from user_ u where p.creator_id = u.id) as banned, +(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, +(select actor_id from user_ where p.creator_id = user_.id) as creator_actor_id, +(select local from user_ where p.creator_id = user_.id) as creator_local, +(select name from user_ where p.creator_id = user_.id) as creator_name, +(select avatar from user_ where p.creator_id = user_.id) as creator_avatar, +(select actor_id from community where p.community_id = community.id) as community_actor_id, +(select local from community where p.community_id = community.id) as community_local, +(select name from community where p.community_id = community.id) as community_name, +(select removed from community c where p.community_id = c.id) as community_removed, +(select deleted from community c where p.community_id = c.id) as community_deleted, +(select nsfw from community c where p.community_id = c.id) as community_nsfw, +(select count(*) from comment where comment.post_id = p.id) as number_of_comments, +coalesce(sum(pl.score), 0) as score, +count (case when pl.score = 1 then 1 else null end) as upvotes, +count (case when pl.score = -1 then 1 else null end) as downvotes, +hot_rank(coalesce(sum(pl.score) , 0), + ( + case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps + else greatest(c.recent_comment_time, p.published) + end + ) +) as hot_rank, +( + case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps + else greatest(c.recent_comment_time, p.published) + end +) as newest_activity_time +from post p +left join post_like pl on p.id = pl.post_id +left join ( + select post_id, + max(published) as recent_comment_time + from comment + group by 1 +) c on p.id = c.post_id +group by p.id, c.recent_comment_time; + +create materialized view post_aggregates_mview as select * from post_aggregates_view; + +create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id); + +create view post_view as +with all_post as ( + select + pa.* + from post_aggregates_view pa +) +select +ap.*, +u.id as user_id, +coalesce(pl.score, 0) as my_vote, +(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, +(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, +(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved +from user_ u +cross join all_post ap +left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id + +union all + +select +ap.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from all_post ap +; + +create view post_mview as +with all_post as ( + select + pa.* + from post_aggregates_mview pa +) +select +ap.*, +u.id as user_id, +coalesce(pl.score, 0) as my_vote, +(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, +(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, +(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved +from user_ u +cross join all_post ap +left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id + +union all + +select +ap.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from all_post ap +; + + +-- reply_view, comment_view, user_mention +drop view reply_view; +drop view user_mention_view; +drop view user_mention_mview; +drop view comment_view; +drop view comment_mview; +drop materialized view comment_aggregates_mview; +drop view comment_aggregates_view; + +-- reply and comment view +create view comment_aggregates_view as +select +c.*, +(select community_id from post p where p.id = c.post_id), +(select co.actor_id from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_actor_id, +(select co.local from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_local, +(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name, +(select u.banned from user_ u where c.creator_id = u.id) as banned, +(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community, +(select actor_id from user_ where c.creator_id = user_.id) as creator_actor_id, +(select local from user_ where c.creator_id = user_.id) as creator_local, +(select name from user_ where c.creator_id = user_.id) as creator_name, +(select avatar from user_ where c.creator_id = user_.id) as creator_avatar, +coalesce(sum(cl.score), 0) as score, +count (case when cl.score = 1 then 1 else null end) as upvotes, +count (case when cl.score = -1 then 1 else null end) as downvotes, +hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank +from comment c +left join comment_like cl on c.id = cl.comment_id +group by c.id; + +create materialized view comment_aggregates_mview as select * from comment_aggregates_view; + +create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id); + +create view comment_view as +with all_comment as +( + select + ca.* + from comment_aggregates_view ca +) + +select +ac.*, +u.id as user_id, +coalesce(cl.score, 0) as my_vote, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, +(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved +from user_ u +cross join all_comment ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id + +union all + +select + ac.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from all_comment ac +; + +create view comment_mview as +with all_comment as +( + select + ca.* + from comment_aggregates_mview ca +) + +select +ac.*, +u.id as user_id, +coalesce(cl.score, 0) as my_vote, +(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed, +(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved +from user_ u +cross join all_comment ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id + +union all + +select + ac.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from all_comment ac +; + +-- Do the reply_view referencing the comment_mview +create view reply_view as +with closereply as ( + select + c2.id, + c2.creator_id as sender_id, + c.creator_id as recipient_id + from comment c + inner join comment c2 on c.id = c2.parent_id + where c2.creator_id != c.creator_id + -- Do union where post is null + union + select + c.id, + c.creator_id as sender_id, + p.creator_id as recipient_id + from comment c, post p + where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +) +select cv.*, +closereply.recipient_id +from comment_mview cv, closereply +where closereply.id = cv.id +; + +-- user mention +create view user_mention_view as +select + c.id, + um.id as user_mention_id, + c.creator_id, + c.creator_actor_id, + c.creator_local, + c.post_id, + c.parent_id, + c.content, + c.removed, + um.read, + c.published, + c.updated, + c.deleted, + c.community_id, + c.community_actor_id, + c.community_local, + c.community_name, + c.banned, + c.banned_from_community, + c.creator_name, + c.creator_avatar, + c.score, + c.upvotes, + c.downvotes, + c.hot_rank, + c.user_id, + c.my_vote, + c.saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from user_mention um, comment_view c +where um.comment_id = c.id; + + +create view user_mention_mview as +with all_comment as +( + select + ca.* + from comment_aggregates_mview ca +) + +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.creator_actor_id, + ac.creator_local, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_actor_id, + ac.community_local, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from user_ u +cross join all_comment ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id +left join user_mention um on um.comment_id = ac.id + +union all + +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.creator_actor_id, + ac.creator_local, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_actor_id, + ac.community_local, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + null as user_id, + null as my_vote, + null as saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from all_comment ac +left join user_mention um on um.comment_id = ac.id +; + diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs index 8373a338..1528f509 100644 --- a/server/src/api/comment.rs +++ b/server/src/api/comment.rs @@ -99,6 +99,8 @@ impl Perform for Oper { deleted: None, read: None, updated: None, + ap_id: "changeme".into(), + local: true, }; let inserted_comment = match Comment::create(&conn, &comment_form) { @@ -106,6 +108,11 @@ impl Perform for Oper { Err(_e) => return Err(APIError::err("couldnt_create_comment").into()), }; + match Comment::update_ap_id(&conn, inserted_comment.id) { + Ok(comment) => comment, + Err(_e) => return Err(APIError::err("couldnt_create_comment").into()), + }; + let mut recipient_ids = Vec::new(); // Scan the comment for user mentions, add those rows @@ -272,6 +279,8 @@ impl Perform for Oper { let content_slurs_removed = remove_slurs(&data.content.to_owned()); + let read_comment = Comment::read(&conn, data.edit_id)?; + let comment_form = CommentForm { content: content_slurs_removed, parent_id: data.parent_id, @@ -285,6 +294,8 @@ impl Perform for Oper { } else { Some(naive_now()) }, + ap_id: read_comment.ap_id, + local: read_comment.local, }; let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) { diff --git a/server/src/api/community.rs b/server/src/api/community.rs index 936e54cd..35ca1d26 100644 --- a/server/src/api/community.rs +++ b/server/src/api/community.rs @@ -1,19 +1,22 @@ use super::*; +use crate::apub::activities::follow_community; +use crate::apub::{format_community_name, gen_keypair_str, make_apub_endpoint, EndpointType}; use diesel::PgConnection; use std::str::FromStr; +use url::Url; #[derive(Serialize, Deserialize)] pub struct GetCommunity { id: Option, - name: Option, + pub name: Option, auth: Option, } #[derive(Serialize, Deserialize)] pub struct GetCommunityResponse { pub community: CommunityView, - moderators: Vec, - admins: Vec, + pub moderators: Vec, + pub admins: Vec, pub online: usize, } @@ -32,17 +35,17 @@ pub struct CommunityResponse { pub community: CommunityView, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct ListCommunities { - sort: String, - page: Option, - limit: Option, - auth: Option, + pub sort: String, + pub page: Option, + pub limit: Option, + pub auth: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct ListCommunitiesResponse { - communities: Vec, + pub communities: Vec, } #[derive(Serialize, Deserialize, Clone)] @@ -128,25 +131,25 @@ impl Perform for Oper { None => None, }; - let community_id = match data.id { - Some(id) => id, + let community = match data.id { + Some(id) => Community::read(&conn, id)?, None => { match Community::read_from_name( &conn, data.name.to_owned().unwrap_or_else(|| "main".to_string()), ) { - Ok(community) => community.id, + Ok(community) => community, Err(_e) => return Err(APIError::err("couldnt_find_community").into()), } } }; - let community_view = match CommunityView::read(&conn, community_id, user_id) { + let mut community_view = match CommunityView::read(&conn, community.id, user_id) { Ok(community) => community, Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; - let moderators = match CommunityModeratorView::for_community(&conn, community_id) { + let moderators = match CommunityModeratorView::for_community(&conn, community.id) { Ok(moderators) => moderators, Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; @@ -157,6 +160,12 @@ impl Perform for Oper { let creator_user = admins.remove(creator_index); admins.insert(0, creator_user); + if !community.local { + let domain = Url::parse(&community.actor_id)?; + community_view.name = + format_community_name(&community_view.name.to_string(), domain.host_str().unwrap()); + } + // Return the jwt Ok(GetCommunityResponse { community: community_view, @@ -198,6 +207,8 @@ impl Perform for Oper { } // When you create a community, make sure the user becomes a moderator and a follower + let (community_public_key, community_private_key) = gen_keypair_str(); + let community_form = CommunityForm { name: data.name.to_owned(), title: data.title.to_owned(), @@ -208,6 +219,12 @@ impl Perform for Oper { deleted: None, nsfw: data.nsfw, updated: None, + actor_id: make_apub_endpoint(EndpointType::Community, &data.name).to_string(), + local: true, + private_key: Some(community_private_key), + public_key: Some(community_public_key), + last_refreshed_at: None, + published: None, }; let inserted_community = match Community::create(&conn, &community_form) { @@ -288,6 +305,8 @@ impl Perform for Oper { return Err(APIError::err("no_community_edit_allowed").into()); } + let read_community = Community::read(&conn, data.edit_id)?; + let community_form = CommunityForm { name: data.name.to_owned(), title: data.title.to_owned(), @@ -298,6 +317,12 @@ impl Perform for Oper { deleted: data.deleted.to_owned(), nsfw: data.nsfw, updated: Some(naive_now()), + actor_id: read_community.actor_id, + local: read_community.local, + private_key: read_community.private_key, + public_key: read_community.public_key, + last_refreshed_at: None, + published: None, }; let _updated_community = match Community::update(&conn, data.edit_id, &community_form) { @@ -377,21 +402,29 @@ impl Perform for Oper { let user_id = claims.id; - let community_follower_form = CommunityFollowerForm { - community_id: data.community_id, - user_id, - }; - - if data.follow { - match CommunityFollower::follow(&conn, &community_follower_form) { - Ok(user) => user, - Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), + let community = Community::read(conn, data.community_id)?; + if community.local { + let community_follower_form = CommunityFollowerForm { + community_id: data.community_id, + user_id, }; + + if data.follow { + match CommunityFollower::follow(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), + }; + } else { + match CommunityFollower::ignore(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), + }; + } } else { - match CommunityFollower::ignore(&conn, &community_follower_form) { - Ok(user) => user, - Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), - }; + // TODO: still have to implement unfollow + let user = User_::read(conn, user_id)?; + follow_community(&community, &user, conn)?; + // TODO: this needs to return a "pending" state, until Accept is received from the remote server } let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?; @@ -554,6 +587,12 @@ impl Perform for Oper { deleted: None, nsfw: read_community.nsfw, updated: Some(naive_now()), + actor_id: read_community.actor_id, + local: read_community.local, + private_key: read_community.private_key, + public_key: read_community.public_key, + last_refreshed_at: None, + published: None, }; let _updated_community = match Community::update(&conn, data.community_id, &community_form) { diff --git a/server/src/api/post.rs b/server/src/api/post.rs index fb022589..eb8909b2 100644 --- a/server/src/api/post.rs +++ b/server/src/api/post.rs @@ -1,8 +1,9 @@ use super::*; +use crate::apub::activities::{post_create, post_update}; use diesel::PgConnection; use std::str::FromStr; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct CreatePost { name: String, url: Option, @@ -33,7 +34,7 @@ pub struct GetPostResponse { pub online: usize, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct GetPosts { type_: String, sort: String, @@ -43,9 +44,9 @@ pub struct GetPosts { auth: Option, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct GetPostsResponse { - posts: Vec, + pub posts: Vec, } #[derive(Serialize, Deserialize)] @@ -106,7 +107,8 @@ impl Perform for Oper { } // Check for a site ban - if UserView::read(&conn, user_id)?.banned { + let user = User_::read(&conn, user_id)?; + if user.banned { return Err(APIError::err("site_ban").into()); } @@ -130,6 +132,9 @@ impl Perform for Oper { embed_description: iframely_description, embed_html: iframely_html, thumbnail_url: pictshare_thumbnail, + ap_id: "changeme".into(), + local: true, + published: None, }; let inserted_post = match Post::create(&conn, &post_form) { @@ -145,6 +150,13 @@ impl Perform for Oper { } }; + let updated_post = match Post::update_ap_id(&conn, inserted_post.id) { + Ok(post) => post, + Err(_e) => return Err(APIError::err("couldnt_create_post").into()), + }; + + post_create(&updated_post, &user, conn)?; + // They like their own post by default let like_form = PostLikeForm { post_id: inserted_post.id, @@ -357,7 +369,8 @@ impl Perform for Oper { } // Check for a site ban - if UserView::read(&conn, user_id)?.banned { + let user = User_::read(&conn, user_id)?; + if user.banned { return Err(APIError::err("site_ban").into()); } @@ -365,6 +378,8 @@ impl Perform for Oper { let (iframely_title, iframely_description, iframely_html, pictshare_thumbnail) = fetch_iframely_and_pictshare_data(data.url.to_owned()); + let read_post = Post::read(&conn, data.edit_id)?; + let post_form = PostForm { name: data.name.to_owned(), url: data.url.to_owned(), @@ -381,9 +396,12 @@ impl Perform for Oper { embed_description: iframely_description, embed_html: iframely_html, thumbnail_url: pictshare_thumbnail, + ap_id: read_post.ap_id, + local: read_post.local, + published: None, }; - let _updated_post = match Post::update(&conn, data.edit_id, &post_form) { + let updated_post = match Post::update(&conn, data.edit_id, &post_form) { Ok(post) => post, Err(e) => { let err_type = if e.to_string() == "value too long for type character varying(200)" { @@ -425,6 +443,8 @@ impl Perform for Oper { ModStickyPost::create(&conn, &form)?; } + post_update(&updated_post, &user, conn)?; + let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?; Ok(PostResponse { post: post_view }) diff --git a/server/src/api/site.rs b/server/src/api/site.rs index 3720a2c4..4202fea0 100644 --- a/server/src/api/site.rs +++ b/server/src/api/site.rs @@ -297,8 +297,7 @@ impl Perform for Oper { fn perform(&self, conn: &PgConnection) -> Result { let _data: &GetSite = &self.data; - let site = Site::read(&conn, 1); - let site_view = if site.is_ok() { + let site_view = if let Ok(_site) = Site::read(&conn, 1) { Some(SiteView::read(&conn)?) } else if let Some(setup) = Settings::get().setup.as_ref() { let register = Register { @@ -328,11 +327,16 @@ impl Perform for Oper { }; let mut admins = UserView::admins(&conn)?; - if site_view.is_some() { - let site_creator_id = site_view.to_owned().unwrap().creator_id; - let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap(); - let creator_user = admins.remove(creator_index); - admins.insert(0, creator_user); + + // Make sure the site creator is the top admin + if let Some(site_view) = site_view.to_owned() { + let site_creator_id = site_view.creator_id; + // TODO investigate why this is sometimes coming back null + // Maybe user_.admin isn't being set to true? + if let Some(creator_index) = admins.iter().position(|r| r.id == site_creator_id) { + let creator_user = admins.remove(creator_index); + admins.insert(0, creator_user); + } } let banned = UserView::banned(&conn)?; diff --git a/server/src/api/user.rs b/server/src/api/user.rs index 40e09969..fbdead53 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -1,4 +1,5 @@ use super::*; +use crate::apub::{gen_keypair_str, make_apub_endpoint, EndpointType}; use crate::settings::Settings; use crate::{generate_random_string, send_email}; use bcrypt::verify; @@ -250,10 +251,11 @@ impl Perform for Oper { return Err(APIError::err("admin_already_created").into()); } + let (user_public_key, user_private_key) = gen_keypair_str(); + // Register the new user let user_form = UserForm { name: data.username.to_owned(), - fedi_name: Settings::get().hostname, email: data.email.to_owned(), matrix_user_id: None, avatar: None, @@ -269,6 +271,12 @@ impl Perform for Oper { lang: "browser".into(), show_avatars: true, send_notifications_to_email: false, + actor_id: make_apub_endpoint(EndpointType::User, &data.username).to_string(), + bio: None, + local: true, + private_key: Some(user_private_key), + public_key: Some(user_public_key), + last_refreshed_at: None, }; // Create the user @@ -287,12 +295,15 @@ impl Perform for Oper { } }; + let (community_public_key, community_private_key) = gen_keypair_str(); + // Create the main community if it doesn't exist let main_community: Community = match Community::read(&conn, 2) { Ok(c) => c, Err(_e) => { + let default_community_name = "main"; let community_form = CommunityForm { - name: "main".to_string(), + name: default_community_name.to_string(), title: "The Default Community".to_string(), description: Some("The Default Community".to_string()), category_id: 1, @@ -301,6 +312,12 @@ impl Perform for Oper { removed: None, deleted: None, updated: None, + actor_id: make_apub_endpoint(EndpointType::Community, default_community_name).to_string(), + local: true, + private_key: Some(community_private_key), + public_key: Some(community_public_key), + last_refreshed_at: None, + published: None, }; Community::create(&conn, &community_form).unwrap() } @@ -387,7 +404,6 @@ impl Perform for Oper { let user_form = UserForm { name: read_user.name, - fedi_name: read_user.fedi_name, email, matrix_user_id: data.matrix_user_id.to_owned(), avatar: data.avatar.to_owned(), @@ -403,6 +419,12 @@ impl Perform for Oper { lang: data.lang.to_owned(), show_avatars: data.show_avatars, send_notifications_to_email: data.send_notifications_to_email, + actor_id: read_user.actor_id, + bio: read_user.bio, + local: read_user.local, + private_key: read_user.private_key, + public_key: read_user.public_key, + last_refreshed_at: None, }; let updated_user = match User_::update(&conn, user_id, &user_form) { @@ -540,30 +562,7 @@ impl Perform for Oper { return Err(APIError::err("not_an_admin").into()); } - let read_user = User_::read(&conn, data.user_id)?; - - // TODO make addadmin easier - let user_form = UserForm { - name: read_user.name, - fedi_name: read_user.fedi_name, - email: read_user.email, - matrix_user_id: read_user.matrix_user_id, - avatar: read_user.avatar, - password_encrypted: read_user.password_encrypted, - preferred_username: read_user.preferred_username, - updated: Some(naive_now()), - admin: data.added, - banned: read_user.banned, - show_nsfw: read_user.show_nsfw, - theme: read_user.theme, - default_sort_type: read_user.default_sort_type, - default_listing_type: read_user.default_listing_type, - lang: read_user.lang, - show_avatars: read_user.show_avatars, - send_notifications_to_email: read_user.send_notifications_to_email, - }; - - match User_::update(&conn, data.user_id, &user_form) { + match User_::add_admin(&conn, user_id, data.added) { Ok(user) => user, Err(_e) => return Err(APIError::err("couldnt_update_user").into()), }; @@ -603,30 +602,7 @@ impl Perform for Oper { return Err(APIError::err("not_an_admin").into()); } - let read_user = User_::read(&conn, data.user_id)?; - - // TODO make bans and addadmins easier - let user_form = UserForm { - name: read_user.name, - fedi_name: read_user.fedi_name, - email: read_user.email, - matrix_user_id: read_user.matrix_user_id, - avatar: read_user.avatar, - password_encrypted: read_user.password_encrypted, - preferred_username: read_user.preferred_username, - updated: Some(naive_now()), - admin: read_user.admin, - banned: data.ban, - show_nsfw: read_user.show_nsfw, - theme: read_user.theme, - default_sort_type: read_user.default_sort_type, - default_listing_type: read_user.default_listing_type, - lang: read_user.lang, - show_avatars: read_user.show_avatars, - send_notifications_to_email: read_user.send_notifications_to_email, - }; - - match User_::update(&conn, data.user_id, &user_form) { + match User_::ban_user(&conn, user_id, data.ban) { Ok(user) => user, Err(_e) => return Err(APIError::err("couldnt_update_user").into()), }; @@ -755,18 +731,7 @@ impl Perform for Oper { .list()?; for reply in &replies { - let comment_form = CommentForm { - content: reply.to_owned().content, - parent_id: reply.to_owned().parent_id, - post_id: reply.to_owned().post_id, - creator_id: reply.to_owned().creator_id, - removed: None, - deleted: None, - read: Some(true), - updated: reply.to_owned().updated, - }; - - let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) { + match Comment::mark_as_read(&conn, reply.id) { Ok(comment) => comment, Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; @@ -847,18 +812,7 @@ impl Perform for Oper { .list()?; for comment in &comments { - let comment_form = CommentForm { - content: "*Permananently Deleted*".to_string(), - parent_id: comment.to_owned().parent_id, - post_id: comment.to_owned().post_id, - creator_id: comment.to_owned().creator_id, - removed: None, - deleted: Some(true), - read: None, - updated: Some(naive_now()), - }; - - let _updated_comment = match Comment::update(&conn, comment.id, &comment_form) { + let _updated_comment = match Comment::permadelete(&conn, comment.id) { Ok(comment) => comment, Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; @@ -872,25 +826,7 @@ impl Perform for Oper { .list()?; for post in &posts { - let post_form = PostForm { - name: "*Permananently Deleted*".to_string(), - url: Some("https://deleted.com".to_string()), - body: Some("*Permananently Deleted*".to_string()), - creator_id: post.to_owned().creator_id, - community_id: post.to_owned().community_id, - removed: None, - deleted: Some(true), - nsfw: post.to_owned().nsfw, - locked: None, - stickied: None, - updated: Some(naive_now()), - embed_title: None, - embed_description: None, - embed_html: None, - thumbnail_url: None, - }; - - let _updated_post = match Post::update(&conn, post.id, &post_form) { + let _updated_post = match Post::permadelete(&conn, post.id) { Ok(post) => post, Err(_e) => return Err(APIError::err("couldnt_update_post").into()), }; diff --git a/server/src/apub/activities.rs b/server/src/apub/activities.rs new file mode 100644 index 00000000..a1707267 --- /dev/null +++ b/server/src/apub/activities.rs @@ -0,0 +1,143 @@ +use crate::apub::{get_apub_protocol_string, get_following_instances}; +use crate::db::community::Community; +use crate::db::post::Post; +use crate::db::user::User_; +use crate::db::Crud; +use activitystreams::activity::{Accept, Create, Follow, Update}; +use activitystreams::object::properties::ObjectProperties; +use activitystreams::BaseBox; +use activitystreams::{context, public}; +use diesel::PgConnection; +use failure::Error; +use failure::_core::fmt::Debug; +use isahc::prelude::*; +use serde::Serialize; + +fn populate_object_props( + props: &mut ObjectProperties, + addressed_to: &str, + object_id: &str, +) -> Result<(), Error> { + props + .set_context_xsd_any_uri(context())? + // TODO: the activity needs a seperate id from the object + .set_id(object_id)? + // TODO: should to/cc go on the Create, or on the Post? or on both? + // TODO: handle privacy on the receiving side (at least ignore anything thats not public) + .set_to_xsd_any_uri(public())? + .set_cc_xsd_any_uri(addressed_to)?; + Ok(()) +} + +fn send_activity(activity: &A, to: Vec) -> Result<(), Error> +where + A: Serialize + Debug, +{ + let json = serde_json::to_string(&activity)?; + println!("sending data {}", json); + for t in to { + println!("to: {}", t); + let res = Request::post(t) + .header("Content-Type", "application/json") + .body(json.to_owned())? + .send()?; + dbg!(res); + } + Ok(()) +} + +fn get_followers(_community: &Community) -> Vec { + // TODO: this is wrong, needs to go to the (non-local) followers of the community + get_following_instances() + .iter() + .map(|i| { + format!( + "{}://{}/federation/inbox", + get_apub_protocol_string(), + i.domain + ) + }) + .collect() +} + +pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> { + let page = post.as_page(conn)?; + let community = Community::read(conn, post.community_id)?; + let mut create = Create::new(); + populate_object_props( + &mut create.object_props, + &community.get_followers_url(), + &post.ap_id, + )?; + create + .create_props + .set_actor_xsd_any_uri(creator.actor_id.to_owned())? + .set_object_base_box(page)?; + send_activity(&create, get_followers(&community))?; + Ok(()) +} + +pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<(), Error> { + let page = post.as_page(conn)?; + let community = Community::read(conn, post.community_id)?; + let mut update = Update::new(); + populate_object_props( + &mut update.object_props, + &community.get_followers_url(), + &post.ap_id, + )?; + update + .update_props + .set_actor_xsd_any_uri(creator.actor_id.to_owned())? + .set_object_base_box(page)?; + send_activity(&update, get_followers(&community))?; + Ok(()) +} + +pub fn follow_community( + community: &Community, + user: &User_, + _conn: &PgConnection, +) -> Result<(), Error> { + let mut follow = Follow::new(); + follow + .object_props + .set_context_xsd_any_uri(context())? + // TODO: needs proper id + .set_id(user.actor_id.clone())?; + follow + .follow_props + .set_actor_xsd_any_uri(user.actor_id.clone())? + .set_object_xsd_any_uri(community.actor_id.clone())?; + let to = format!("{}/inbox", community.actor_id); + send_activity(&follow, vec![to])?; + Ok(()) +} + +pub fn accept_follow(follow: &Follow) -> Result<(), Error> { + let mut accept = Accept::new(); + accept + .object_props + .set_context_xsd_any_uri(context())? + // TODO: needs proper id + .set_id( + follow + .follow_props + .get_actor_xsd_any_uri() + .unwrap() + .to_string(), + )?; + accept + .accept_props + .set_object_base_box(BaseBox::from_concrete(follow.clone())?)?; + let to = format!( + "{}/inbox", + follow + .follow_props + .get_actor_xsd_any_uri() + .unwrap() + .to_string() + ); + send_activity(&accept, vec![to])?; + Ok(()) +} diff --git a/server/src/apub/community.rs b/server/src/apub/community.rs index 32f14eeb..0bea4705 100644 --- a/server/src/apub/community.rs +++ b/server/src/apub/community.rs @@ -1,109 +1,202 @@ -use crate::apub::make_apub_endpoint; -use crate::db::community::Community; +use crate::apub::fetcher::{fetch_remote_object, fetch_remote_user}; +use crate::apub::signatures::PublicKey; +use crate::apub::*; +use crate::db::community::{Community, CommunityForm}; use crate::db::community_view::CommunityFollowerView; use crate::db::establish_unpooled_connection; -use crate::to_datetime_utc; -use activitypub::{actor::Group, collection::UnorderedCollection, context}; +use crate::db::post::Post; +use crate::db::user::User_; +use crate::db::Crud; +use crate::settings::Settings; +use crate::{convert_datetime, naive_now}; +use activitystreams::actor::properties::ApActorProperties; +use activitystreams::collection::OrderedCollection; +use activitystreams::{ + actor::Group, collection::UnorderedCollection, context, ext::Extensible, + object::properties::ObjectProperties, +}; use actix_web::body::Body; use actix_web::web::Path; use actix_web::HttpResponse; +use actix_web::{web, Result}; +use diesel::r2d2::{ConnectionManager, Pool}; +use diesel::PgConnection; +use failure::Error; use serde::Deserialize; +use url::Url; -impl Community { - pub fn as_group(&self) -> Group { - let base_url = make_apub_endpoint("c", &self.name); +#[derive(Deserialize)] +pub struct CommunityQuery { + community_name: String, +} - let mut group = Group::default(); +pub async fn get_apub_community_list( + db: web::Data>>, +) -> Result, Error> { + // TODO: implement pagination + let communities = Community::list_local(&db.get().unwrap())? + .iter() + .map(|c| c.as_group(&db.get().unwrap())) + .collect::, Error>>()?; + let mut collection = UnorderedCollection::default(); + let oprops: &mut ObjectProperties = collection.as_mut(); + oprops.set_context_xsd_any_uri(context())?.set_id(format!( + "{}://{}/federation/communities", + get_apub_protocol_string(), + Settings::get().hostname + ))?; + + collection + .collection_props + .set_total_items(communities.len() as u64)? + .set_many_items_base_boxes(communities)?; + Ok(create_apub_response(&collection)) +} - group.object_props.set_context_object(context()).ok(); - group.object_props.set_id_string(base_url.to_string()).ok(); - group - .object_props - .set_name_string(self.name.to_owned()) - .ok(); - group - .object_props - .set_published_utctime(to_datetime_utc(self.published)) - .ok(); - if let Some(updated) = self.updated { - group - .object_props - .set_updated_utctime(to_datetime_utc(updated)) - .ok(); +impl Community { + fn as_group(&self, conn: &PgConnection) -> Result { + let mut group = Group::default(); + let oprops: &mut ObjectProperties = group.as_mut(); + + let creator = User_::read(conn, self.creator_id)?; + oprops + .set_context_xsd_any_uri(context())? + .set_id(self.actor_id.to_owned())? + .set_name_xsd_string(self.name.to_owned())? + .set_published(convert_datetime(self.published))? + .set_attributed_to_xsd_any_uri(creator.actor_id)?; + + if let Some(u) = self.updated.to_owned() { + oprops.set_updated(convert_datetime(u))?; } - - if let Some(description) = &self.description { - group - .object_props - .set_summary_string(description.to_string()) - .ok(); + if let Some(d) = self.description.to_owned() { + // TODO: this should be html, also add source field with raw markdown + // -> same for post.content and others + oprops.set_summary_xsd_string(d)?; } - group - .ap_actor_props - .set_inbox_string(format!("{}/inbox", &base_url)) - .ok(); - group - .ap_actor_props - .set_outbox_string(format!("{}/outbox", &base_url)) - .ok(); - group - .ap_actor_props - .set_followers_string(format!("{}/followers", &base_url)) - .ok(); - - group - } - - pub fn followers_as_collection(&self) -> UnorderedCollection { - let base_url = make_apub_endpoint("c", &self.name); + let mut actor_props = ApActorProperties::default(); - let mut collection = UnorderedCollection::default(); - collection.object_props.set_context_object(context()).ok(); - collection.object_props.set_id_string(base_url).ok(); + actor_props + .set_preferred_username(self.title.to_owned())? + .set_inbox(self.get_inbox_url())? + .set_outbox(self.get_outbox_url())? + .set_followers(self.get_followers_url())?; - let connection = establish_unpooled_connection(); - //As we are an object, we validated that the community id was valid - let community_followers = CommunityFollowerView::for_community(&connection, self.id).unwrap(); + let public_key = PublicKey { + id: format!("{}#main-key", self.actor_id), + owner: self.actor_id.to_owned(), + public_key_pem: self.public_key.to_owned().unwrap(), + }; - let ap_followers = community_followers - .iter() - .map(|follower| make_apub_endpoint("u", &follower.user_name)) - .collect(); + Ok(group.extend(actor_props).extend(public_key.to_ext())) + } - collection - .collection_props - .set_items_string_vec(ap_followers) - .unwrap(); - collection + pub fn get_followers_url(&self) -> String { + format!("{}/followers", &self.actor_id) + } + pub fn get_inbox_url(&self) -> String { + format!("{}/inbox", &self.actor_id) + } + pub fn get_outbox_url(&self) -> String { + format!("{}/outbox", &self.actor_id) } } -#[derive(Deserialize)] -pub struct CommunityQuery { - community_name: String, +impl CommunityForm { + pub fn from_group(group: &GroupExt, conn: &PgConnection) -> Result { + let oprops = &group.base.base.object_props; + let aprops = &group.base.extension; + let public_key: &PublicKey = &group.extension.public_key; + + let followers_uri = Url::parse(&aprops.get_followers().unwrap().to_string())?; + let outbox_uri = Url::parse(&aprops.get_outbox().to_string())?; + let _outbox = fetch_remote_object::(&outbox_uri)?; + let _followers = fetch_remote_object::(&followers_uri)?; + let apub_id = Url::parse(&oprops.get_attributed_to_xsd_any_uri().unwrap().to_string())?; + let creator = fetch_remote_user(&apub_id, conn)?; + + Ok(CommunityForm { + name: oprops.get_name_xsd_string().unwrap().to_string(), + title: aprops.get_preferred_username().unwrap().to_string(), + // TODO: should be parsed as html and tags like