- rm -rfv target/debug/build/lemmy_server-*
- rm -rfv target/debug/deps/lemmy_server-*
- rm -rfv target/debug/lemmy_server.d
- - cargo clean
before_script:
- psql -c "create user lemmy with password 'password' superuser;" -U postgres
- psql -c 'create database lemmy with owner lemmy;' -U postgres
- { src: 'templates/docker-compose.yml', dest: '/lemmy/docker-compose.yml', mode: '0600' }
- { src: 'templates/nginx.conf', dest: '/etc/nginx/sites-enabled/lemmy.conf', mode: '0644' }
- { src: '../docker/iframely.config.local.js', dest: '/lemmy/iframely.config.local.js', mode: '0600' }
+ vars:
+ lemmy_docker_image: "dessalines/lemmy:{{ lookup('file', 'VERSION') }}"
+ lemmy_port: "8536"
+ pictshare_port: "8537"
+ iframely_port: "8538"
- name: add config file (only during initial setup)
template: src='templates/config.hjson' dest='/lemmy/lemmy.hjson' mode='0600' force='no' owner='1000' group='1000'
vars:
postgres_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/postgres chars=ascii_letters,digits') }}"
jwt_password: "{{ lookup('password', 'passwords/{{ inventory_hostname }}/jwt chars=ascii_letters,digits') }}"
- lemmy_docker_image: "dessalines/lemmy:{{ lookup('file', 'VERSION') }}"
- name: enable and start docker service
systemd:
- "127.0.0.1:8536:8536"
restart: always
environment:
- - RUST_LOG=debug
+ - RUST_LOG=error
volumes:
- ./lemmy.hjson:/config/config.hjson:ro
depends_on:
COPY ui /app/ui
RUN yarn build
-FROM ekidd/rust-musl-builder:1.40.0-openssl11 as rust
+FROM ekidd/rust-musl-builder:1.42.0-openssl11 as rust
# Cache deps
WORKDIR /app
# RUN cargo install diesel_cli --no-default-features --features postgres
-FROM ekidd/rust-musl-builder:1.40.0-openssl11 as docs
+FROM ekidd/rust-musl-builder:1.42.0-openssl11 as docs
WORKDIR /app
COPY docs ./docs
RUN sudo chown -R rust:rust .
RUN yarn build
-FROM rust:1.40 as rust
+FROM rust:1.42 as rust
# Cache deps
WORKDIR /app
#RUN cp /app/server/target/debug/lemmy_server /app/server/ready
-FROM rust:1.40 as docs
+FROM rust:1.42 as docs
WORKDIR /app
# interval length for registration limit
register_per_second: 3600
}
-# # email sending configuration
+# # optional: parameters for automatic configuration of new instance (only used at first start)
+# setup: {
+# # username for the admin user
+# admin_username: "lemmy"
+# # password for the admin user
+# admin_password: "lemmy"
+# # name of the site (can be changed later)
+# site_name: "Lemmy Test"
+# }
+# # optional: email sending configuration
# email: {
# # hostname of the smtp server
# smtp_server: ""
restart: always
lemmy:
- image: dessalines/lemmy:v0.6.39
+ image: dessalines/lemmy:v0.6.44
ports:
- "127.0.0.1:8536:8536"
restart: always
environment:
- - RUST_LOG=debug
+ - RUST_LOG=error
volumes:
- ./lemmy.hjson:/config/config.hjson:ro
depends_on:
- [Contributing](contributing.md)
- [Docker Development](contributing_docker_development.md)
- [Local Development](contributing_local_development.md)
+ - [Federation Development](contributing_federation_development.md)
- [Websocket/HTTP API](contributing_websocket_http_api.md)
- [ActivityPub API Outline](contributing_apub_api_outline.md)
- [Theming Guide](contributing_theming.md)
- https://docs.rs/activitypub/0.1.4/activitypub/
- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/)
- [Activitypub main](https://www.w3.org/TR/activitypub/)
+- [Federation.md](https://github.com/dariusk/gathio/blob/7fc93dbe9d4d99457a0e85c6c532112f415b7af2/FEDERATION.md)
+- [Activitypub implementers guide](https://socialhub.activitypub.rocks/t/draft-guide-for-new-activitypub-implementers/479)
+- [Data storage questions](https://socialhub.activitypub.rocks/t/data-storage-questions/579/3)
+- [Activitypub as it has been understood](https://flak.tedunangst.com/post/ActivityPub-as-it-has-been-understood)
# Ansible Installation
+This is the same as the [Docker installation](administration_install_docker.md), except that Ansible handles all of it automatically. It also does some extra things like setting up TLS and email for your Lemmy instance.
+
First, you need to [install Ansible on your local computer](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (e.g. using `sudo apt install ansible`) or the equivalent for you platform.
Then run the following commands on your local computer:
nano inventory # enter your server, domain, contact email
ansible-playbook lemmy.yml --become
```
+
+To update to a new version, just run the following in your local Lemmy repo:
+```bash
+git pull origin master
+cd ansible
+ansible-playbook lemmy.yml --become
+```
\ No newline at end of file
# Docker Installation
-Make sure you have both docker and docker-compose(>=`1.24.0`) installed:
+Make sure you have both docker and docker-compose(>=`1.24.0`) installed. On Ubuntu, just run `apt install docker-compose docker.io`. Next,
```bash
-mkdir lemmy/
-cd lemmy/
+# create a folder for the lemmy files. the location doesnt matter, you can put this anywhere you want
+mkdir /lemmy
+cd /lemmy
+# download default config files
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/lemmy.hjson
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/iframely.config.local.js
-# Edit lemmy.hjson, and docker-compose.yml to do more configuration (like adding a custom password)
docker-compose up -d
```
-and go to http://localhost:8536.
+After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname.
-[A sample nginx config](/ansible/templates/nginx.conf) (Note: Avatar / Image uploading won't work without this), could be setup with:
+To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](/ansible/templates/nginx.conf), could be setup with:
```bash
wget https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf
# Replace the {{ vars }}
sudo mv nginx.conf /etc/nginx/sites-enabled/lemmy.conf
```
+
+You will also need to setup TLS, for example with [Let's Encrypt](https://letsencrypt.org/). After this you need to restart Nginx to reload the config.
+
## Updating
-To update to the newest version, run:
+To update to the newest version, you can manually change the version in `docker-compose.yml`. Alternatively, fetch the latest version from our git repo:
```bash
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
Information about contributing to Lemmy, whether it is translating, testing, designing or programming.
+## Issue tracking / Repositories
+
+- [GitHub (for issues)](https://github.com/dessalines/lemmy)
+- [Gitea](https://yerbamate.dev/dessalines/lemmy)
+- [GitLab](https://gitlab.com/dessalines/lemmy)
+
## Translating
Go [here](https://github.com/dessalines/lemmy#translations) for translation instructions.
--- /dev/null
+# Federation Development
+
+## Setup
+
+If you don't have a local clone of the Lemmy repo yet, just run the following command:
+
+```bash
+git clone https://yerbamate.dev/nutomic/lemmy.git -b federation
+```
+
+If you already have the Lemmy repo cloned, you need to add a new remote:
+```bash
+git remote add federation https://yerbamate.dev/nutomic/lemmy.git
+git checkout federation
+git pull federation federation
+```
+
+## Running
+
+You need to have the following packages installed, the Docker service needs to be running.
+
+- docker
+- docker-compose
+- cargo
+- yarn
+
+Then run the following
+```bash
+cd dev/federation-test
+./run-federation-test.bash
+```
+
+After the build is finished and the docker-compose setup is running, open [127.0.0.1:8540](http://127.0.0.1:8540) and
+[127.0.0.1:8541](http://127.0.0.1:8541) in your browser to use the test instances. You can login as admin with
+username `lemmy` and password `lemmy`, or create new accounts.
+
+Please get in touch if you want to contribute to this, so we can coordinate things and avoid duplicate work.
\ No newline at end of file
# It is not intended for manual editing.
[[package]]
name = "activitystreams"
-version = "0.5.0-alpha.15"
+version = "0.5.0-alpha.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "activitystreams-derive 0.5.0-alpha.7 (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)",
[[package]]
name = "activitystreams-derive"
-version = "0.5.0-alpha.7"
+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)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "arc-swap"
version = "0.4.5"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "bytes"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "bytes"
version = "0.5.4"
]
[[package]]
-name = "chttp"
-version = "0.5.5"
+name = "clap"
+version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-channel 0.3.9 (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)",
- "futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "sluice 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "comrak"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "config"
version = "0.10.1"
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "crossbeam-channel"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "crossbeam-channel"
version = "0.4.2"
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "crossbeam-utils"
-version = "0.6.6"
-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)",
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "entities"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "enum-as-inner"
version = "0.3.2"
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "futures-channel-preview"
-version = "0.3.0-alpha.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "futures-core"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "futures-core-preview"
-version = "0.3.0-alpha.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "futures-executor"
version = "0.3.4"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "futures-io-preview"
-version = "0.3.0-alpha.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "futures-macro"
version = "0.3.4"
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "futures-util-preview"
-version = "0.3.0-alpha.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures-io-preview 0.3.0-alpha.17 (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)",
- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "fxhash"
version = "0.2.1"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "http"
-version = "0.1.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "http"
version = "0.2.0"
"winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "isahc"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+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.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)",
+ "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sluice 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "itoa"
version = "0.1.1"
name = "lemmy_server"
version = "0.0.1"
dependencies = [
- "activitystreams 0.5.0-alpha.15 (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)",
"actix-web-actors 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bcrypt 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "chttp 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "comrak 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "isahc 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonwebtoken 7.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"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)",
"sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "strum 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "strum_macros 0.17.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)",
]
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "maplit"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "match_cfg"
version = "0.1.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "pest"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest_meta 2.1.3 (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)",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "pin-project"
version = "0.4.8"
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "sha-1"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "sha1"
version = "0.6.0"
[[package]]
name = "sluice"
-version = "0.4.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures-io-preview 0.3.0-alpha.17 (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-io 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)",
]
[[package]]
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "strsim"
version = "0.9.3"
[[package]]
name = "strum"
-version = "0.17.1"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strum_macros"
-version = "0.17.1"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "thiserror"
version = "1.0.11"
"trust-dns-proto 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "twoway"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "typed-arena"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "typenum"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "ucd-trie"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unchecked-index"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "unicase"
version = "2.6.0"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "unicode-width"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "unicode_categories"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "untrusted"
version = "0.7.0"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "vec_map"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "version_check"
version = "0.1.5"
]
[metadata]
-"checksum activitystreams 0.5.0-alpha.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1ecff5b18578fac8cff5f139009cd0a4f605b6f5eddc91f2b8319bfef76cc2c3"
-"checksum activitystreams-derive 0.5.0-alpha.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d7498811842309cc5b54c123bcf328e33eebe9841037067b1e9b93caa820085d"
+"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"
"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.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.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 bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
-"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"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 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"
-"checksum chttp 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ca699a61cc91c90af209d6bf546fc69d29e9d474c77fa86b9410eb3cf1e6eb31"
+"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+"checksum comrak 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e17058cc536cf290563e88787d7b9e6030ce4742943017cc2ffb71f88034021c"
"checksum config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
"checksum copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127"
"checksum core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
"checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
-"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
-"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
"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 encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
"checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
+"checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
"checksum enum-as-inner 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4bfcfacb61d231109d1d55202c1f33263319668b168843e02ad4652725ec9c"
"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
-"checksum futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "21c71ed547606de08e9ae744bb3c6d80f5627527ef31ecf2a7210d0e67bc8fae"
"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
-"checksum futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4b141ccf9b7601ef987f36f1c0d9522f76df3bba1cf2e63bfacccc044c4558f5"
"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
-"checksum futures-io-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "082e402605fcb8b1ae1e5ba7d7fdfd3e31ef510e2a8367dd92927bb41ae41b3a"
"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
-"checksum futures-util-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "af8198c48b222f02326940ce2b3aa9e6e91a32886eeaad7ca3b8e4c70daa3f4e"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e"
"checksum hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
-"checksum http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
"checksum http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum ipconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa79fa216fbe60834a9c0737d7fcd30425b32d1c58854663e24d4c4b328ed83f"
+"checksum isahc 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50bdb3bdcbf6d534daaad1a686eda0d0dc1946818fa71e3edd3124d001adfdc2"
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
"checksum js-sys 0.3.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1cb931d43e71f560c81badb0191596562bafad2be06a3f9025b845c847c60df5"
"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
+"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
"checksum match_cfg 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1"
"checksum pem 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1581760c757a756a41f0ee3ff01256227bdf64cb752839779b95ffb01c59793"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+"checksum pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
+"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
+"checksum pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
+"checksum pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
"checksum pin-project 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7804a463a8d9572f13453c516a5faea534a2403d7ced2f0c7e100eeff072772c"
"checksum pin-project-internal 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "385322a45f2ecf3410c68d2a549a4a2685e8051d0f278e39743ff4e451cb9b3f"
"checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
+"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
"checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0"
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
"checksum simple_asn1 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b25ecba7165254f0c97d6c22a64b1122a03634b18d20a34daf21e18f892e618"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
-"checksum sluice 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec70d7c3b17c262d4a18f7291c6ce62bf47170915f3b795434d3c5c49a4e59b7"
+"checksum sluice 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fed13b7cb46f13a15db2c4740f087a848acc8b31af89f95844d40137451f89b1"
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
+"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
-"checksum strum 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "530efb820d53b712f4e347916c5e7ed20deb76a4f0457943b3182fb889b06d2c"
-"checksum strum_macros 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6e163a520367c465f59e0a61a23cfae3b10b6546d78b6f672a382be79f7110"
+"checksum strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
+"checksum strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thiserror 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ee14bf8e6767ab4c687c9e8bc003879e042a96fd67a3ba5934eadb6536bef4db"
"checksum thiserror-impl 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a7b51e1fbc44b5a0840be594fbc0f960be09050f2617e61e6aa43bef97cd3ef4"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
"checksum trust-dns-proto 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2a7f3a2ab8a919f5eca52a468866a67ed7d3efa265d48a652a9a3452272b413f"
"checksum trust-dns-resolver 0.18.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6f90b1502b226f8b2514c6d5b37bafa8c200d7ca4102d57dc36ee0f3b7a04a2f"
+"checksum twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
+"checksum typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
+"checksum ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+"checksum unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+"checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
"checksum untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece"
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum v_escape_derive 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c2ca2a14bc3fc5b64d188b087a7d3a927df87b152e941ccfbc66672e20c467ae"
"checksum v_htmlescape 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e33e939c0d8cf047514fb6ba7d5aac78bc56677a6938b2ee67000b91f2e97e41"
"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
+"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2", "64-column-tables"] }
diesel_migrations = "1.4.0"
dotenv = "0.15.0"
-bcrypt = "0.6.1"
-activitystreams = "0.5.0-alpha.15"
+activitystreams = "0.5.0-alpha.16"
+bcrypt = "0.6.2"
chrono = { version = "0.4.7", features = ["serde"] }
failure = "0.1.5"
-serde_json = { version = "1.0.45", features = ["preserve_order"]}
-serde = { version = "1.0.94", features = ["derive"] }
+serde_json = { version = "1.0.48", features = ["preserve_order"]}
+serde = { version = "1.0.105", features = ["derive"] }
actix = "0.9.0"
actix-web = "2.0.0"
actix-files = "0.2.1"
log = "0.4.0"
env_logger = "0.7.1"
rand = "0.7.3"
-strum = "0.17.1"
-strum_macros = "0.17.1"
+strum = "0.18.0"
+strum_macros = "0.18.0"
jsonwebtoken = "7.0.1"
-regex = "1.3.4"
+regex = "1.3.5"
lazy_static = "1.3.0"
lettre = "0.9.2"
lettre_email = "0.9.2"
hjson = "0.8.2"
url = "2.1.1"
percent-encoding = "2.1.0"
-chttp = "0.5.5"
+isahc = "0.9"
+comrak = "0.7"
+openssl = "0.10"
{
+# # optional: parameters for automatic configuration of new instance (only used at first start)
+# setup: {
+# # username for the admin user
+# admin_username: ""
+# # password for the admin user
+# admin_password: ""
+# # optional: email for the admin user (can be omitted and set later through the website)
+# admin_email: ""
+# # name of the site (can be changed later)
+# site_name: ""
+# }
# settings related to the postgresql database
database: {
# username to connect to postgres
--- /dev/null
+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;
--- /dev/null
+-- 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.
+
use super::*;
use crate::apub::puller::{get_all_communities, get_remote_community};
+use crate::apub::{gen_keypair_str, make_apub_endpoint, EndpointType};
use crate::settings::Settings;
use diesel::PgConnection;
use std::str::FromStr;
}
// 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(),
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,
};
let inserted_community = match Community::create(&conn, &community_form) {
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(),
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,
};
let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
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,
};
let _updated_community = match Community::update(&conn, data.community_id, &community_form) {
use super::*;
+use crate::api::user::Register;
+use crate::api::{Oper, Perform};
+use crate::settings::Settings;
use diesel::PgConnection;
+use log::info;
use std::str::FromStr;
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct CreateSite {
- name: String,
- description: Option<String>,
- enable_downvotes: bool,
- open_registration: bool,
- enable_nsfw: bool,
- auth: String,
+ pub name: String,
+ pub description: Option<String>,
+ pub enable_downvotes: bool,
+ pub open_registration: bool,
+ pub enable_nsfw: bool,
+ pub auth: String,
}
#[derive(Serialize, Deserialize)]
fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
let _data: &GetSite = &self.data;
- // It can return a null site in order to redirect
- let site_view = match Site::read(&conn, 1) {
- Ok(_site) => Some(SiteView::read(&conn)?),
- Err(_e) => None,
+ let site = Site::read(&conn, 1);
+ let site_view = if site.is_ok() {
+ Some(SiteView::read(&conn)?)
+ } else if let Some(setup) = Settings::get().setup.as_ref() {
+ let register = Register {
+ username: setup.admin_username.to_owned(),
+ email: setup.admin_email.to_owned(),
+ password: setup.admin_password.to_owned(),
+ password_verify: setup.admin_password.to_owned(),
+ admin: true,
+ show_nsfw: true,
+ };
+ let login_response = Oper::new(register).perform(&conn)?;
+ info!("Admin {} created", setup.admin_username);
+
+ let create_site = CreateSite {
+ name: setup.site_name.to_owned(),
+ description: None,
+ enable_downvotes: false,
+ open_registration: false,
+ enable_nsfw: false,
+ auth: login_response.jwt,
+ };
+ Oper::new(create_site).perform(&conn)?;
+ info!("Site {} created", setup.site_name);
+ Some(SiteView::read(&conn)?)
+ } else {
+ None
};
let mut admins = UserView::admins(&conn)?;
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;
#[derive(Serialize, Deserialize)]
pub struct Register {
- username: String,
- email: Option<String>,
- password: String,
- password_verify: String,
- admin: bool,
- show_nsfw: bool,
+ pub username: String,
+ pub email: Option<String>,
+ pub password: String,
+ pub password_verify: String,
+ pub admin: bool,
+ pub show_nsfw: bool,
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct LoginResponse {
- jwt: String,
+ pub jwt: String,
}
#[derive(Serialize, Deserialize)]
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(),
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
}
};
+ 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,
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,
};
Community::create(&conn, &community_form).unwrap()
}
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) {
lang: read_user.lang,
show_avatars: read_user.show_avatars,
send_notifications_to_email: read_user.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,
};
match User_::update(&conn, data.user_id, &user_form) {
lang: read_user.lang,
show_avatars: read_user.show_avatars,
send_notifications_to_email: read_user.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,
};
match User_::update(&conn, data.user_id, &user_form) {
pub mod puller;
pub mod user;
use crate::Settings;
+use openssl::{pkey::PKey, rsa::Rsa};
use activitystreams::actor::{properties::ApActorProperties, Group};
use activitystreams::ext::Ext;
.json(json)
}
-enum EndpointType {
+pub enum EndpointType {
Community,
User,
Post,
}
-fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
+pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
let point = match endpoint_type {
EndpointType::Community => "c",
EndpointType::User => "u",
"http"
}
}
+
+pub fn gen_keypair() -> (Vec<u8>, Vec<u8>) {
+ let rsa = Rsa::generate(2048).expect("sign::gen_keypair: key generation error");
+ let pkey = PKey::from_rsa(rsa).expect("sign::gen_keypair: parsing error");
+ (
+ pkey
+ .public_key_to_pem()
+ .expect("sign::gen_keypair: public key encoding error"),
+ pkey
+ .private_key_to_pem_pkcs8()
+ .expect("sign::gen_keypair: private key encoding error"),
+ )
+}
+
+pub fn gen_keypair_str() -> (String, String) {
+ let (public_key, private_key) = gen_keypair();
+ (vec_bytes_to_str(public_key), vec_bytes_to_str(private_key))
+}
+
+fn vec_bytes_to_str(bytes: Vec<u8>) -> String {
+ String::from_utf8_lossy(&bytes).into_owned()
+}
use activitystreams::collection::{OrderedCollection, UnorderedCollection};
use activitystreams::object::Page;
use activitystreams::BaseBox;
-use chttp::prelude::*;
use failure::Error;
+use isahc::prelude::*;
use log::warn;
use serde::Deserialize;
}
// TODO: should cache responses here when we are in production
// TODO: this function should return a future
- let text = chttp::get(uri)?.text()?;
+ let text = isahc::get(uri)?.text()?;
let res: Response = serde_json::from_str(&text)?;
Ok(res)
}
--- /dev/null
+// This is for db migrations that require code
+use super::community::{Community, CommunityForm};
+use super::user::{UserForm, User_};
+use super::*;
+use crate::apub::{gen_keypair_str, make_apub_endpoint, EndpointType};
+use crate::naive_now;
+use log::info;
+
+pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), Error> {
+ user_updates_2020_04_02(conn)?;
+ community_updates_2020_04_02(conn)?;
+
+ Ok(())
+}
+
+fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), Error> {
+ use crate::schema::user_::dsl::*;
+
+ info!("Running user_updates_2020_04_02");
+
+ // Update the actor_id, private_key, and public_key, last_refreshed_at
+ let incorrect_users = user_
+ .filter(actor_id.eq("changeme"))
+ .filter(local.eq(true))
+ .load::<User_>(conn)?;
+
+ for cuser in &incorrect_users {
+ let (user_public_key, user_private_key) = gen_keypair_str();
+
+ let form = UserForm {
+ name: cuser.name.to_owned(),
+ fedi_name: cuser.fedi_name.to_owned(),
+ email: cuser.email.to_owned(),
+ matrix_user_id: cuser.matrix_user_id.to_owned(),
+ avatar: cuser.avatar.to_owned(),
+ password_encrypted: cuser.password_encrypted.to_owned(),
+ preferred_username: cuser.preferred_username.to_owned(),
+ updated: None,
+ admin: cuser.admin,
+ banned: cuser.banned,
+ show_nsfw: cuser.show_nsfw,
+ theme: cuser.theme.to_owned(),
+ default_sort_type: cuser.default_sort_type,
+ default_listing_type: cuser.default_listing_type,
+ lang: cuser.lang.to_owned(),
+ show_avatars: cuser.show_avatars,
+ send_notifications_to_email: cuser.send_notifications_to_email,
+ actor_id: make_apub_endpoint(EndpointType::User, &cuser.name).to_string(),
+ bio: cuser.bio.to_owned(),
+ local: cuser.local,
+ private_key: Some(user_private_key),
+ public_key: Some(user_public_key),
+ last_refreshed_at: Some(naive_now()),
+ };
+
+ User_::update(&conn, cuser.id, &form)?;
+ }
+
+ info!("{} user rows updated.", incorrect_users.len());
+
+ Ok(())
+}
+
+fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), Error> {
+ use crate::schema::community::dsl::*;
+
+ info!("Running community_updates_2020_04_02");
+
+ // Update the actor_id, private_key, and public_key, last_refreshed_at
+ let incorrect_communities = community
+ .filter(actor_id.eq("changeme"))
+ .filter(local.eq(true))
+ .load::<Community>(conn)?;
+
+ for ccommunity in &incorrect_communities {
+ let (community_public_key, community_private_key) = gen_keypair_str();
+
+ let form = CommunityForm {
+ name: ccommunity.name.to_owned(),
+ title: ccommunity.title.to_owned(),
+ description: ccommunity.description.to_owned(),
+ category_id: ccommunity.category_id,
+ creator_id: ccommunity.creator_id,
+ removed: None,
+ deleted: None,
+ nsfw: ccommunity.nsfw,
+ updated: None,
+ actor_id: make_apub_endpoint(EndpointType::Community, &ccommunity.name).to_string(),
+ local: ccommunity.local,
+ private_key: Some(community_private_key),
+ public_key: Some(community_public_key),
+ last_refreshed_at: Some(naive_now()),
+ };
+
+ Community::update(&conn, ccommunity.id, &form)?;
+ }
+
+ info!("{} community rows updated.", incorrect_communities.len());
+
+ Ok(())
+}
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
deleted: None,
updated: None,
nsfw: false,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
deleted: None,
updated: None,
nsfw: false,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
pub nsfw: bool,
+ pub actor_id: String,
+ pub local: bool,
+ pub private_key: Option<String>,
+ pub public_key: Option<String>,
+ pub last_refreshed_at: chrono::NaiveDateTime,
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: Option<bool>,
pub nsfw: bool,
+ pub actor_id: String,
+ pub local: bool,
+ pub private_key: Option<String>,
+ pub public_key: Option<String>,
+ pub last_refreshed_at: Option<chrono::NaiveDateTime>,
}
impl Crud<CommunityForm> for Community {
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
removed: None,
deleted: None,
updated: None,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
deleted: false,
published: inserted_community.published,
updated: None,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: inserted_community.published,
};
let community_follower_form = CommunityFollowerForm {
-extern crate lazy_static;
use crate::settings::Settings;
use diesel::dsl::*;
use diesel::result::Error;
use serde::{Deserialize, Serialize};
pub mod category;
+pub mod code_migrations;
pub mod comment;
pub mod comment_view;
pub mod community;
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_mod = User_::create(&conn, &new_mod).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
deleted: None,
updated: None,
nsfw: false,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
deleted: None,
updated: None,
nsfw: false,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
deleted: None,
updated: None,
nsfw: false,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_creator = User_::create(&conn, &creator_form).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_recipient = User_::create(&conn, &recipient_form).unwrap();
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<String>,
+ pub actor_id: String,
+ pub bio: Option<String>,
+ pub local: bool,
+ pub private_key: Option<String>,
+ pub public_key: Option<String>,
+ pub last_refreshed_at: chrono::NaiveDateTime,
}
#[derive(Insertable, AsChangeset, Clone)]
pub show_avatars: bool,
pub send_notifications_to_email: bool,
pub matrix_user_id: Option<String>,
+ pub actor_id: String,
+ pub bio: Option<String>,
+ pub local: bool,
+ pub private_key: Option<String>,
+ pub public_key: Option<String>,
+ pub last_refreshed_at: Option<chrono::NaiveDateTime>,
}
impl Crud<UserForm> for User_ {
Self::create(&conn, &edited_user)
}
+ // TODO do more individual updates like these
pub fn update_password(
conn: &PgConnection,
user_id: i32,
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: inserted_user.published,
};
let read_user = User_::read(&conn, inserted_user.id).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
+ actor_id: "changeme".into(),
+ bio: None,
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_recipient = User_::create(&conn, &recipient_form).unwrap();
deleted: None,
updated: None,
nsfw: false,
+ actor_id: "changeme".into(),
+ local: true,
+ private_key: None,
+ public_key: None,
+ last_refreshed_at: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
pub extern crate actix_web;
pub extern crate bcrypt;
pub extern crate chrono;
+pub extern crate comrak;
pub extern crate dotenv;
pub extern crate jsonwebtoken;
pub extern crate lettre;
pub extern crate lettre_email;
extern crate log;
+pub extern crate openssl;
pub extern crate rand;
pub extern crate regex;
+pub extern crate rss;
pub extern crate serde;
pub extern crate serde_json;
pub extern crate sha2;
use crate::settings::Settings;
use chrono::{DateTime, FixedOffset, Local, NaiveDateTime};
-use chttp::prelude::*;
+use isahc::prelude::*;
use lettre::smtp::authentication::{Credentials, Mechanism};
use lettre::smtp::extension::ClientId;
use lettre::smtp::ConnectionReuseParameters;
pub fn fetch_iframely(url: &str) -> Result<IframelyResponse, failure::Error> {
let fetch_url = format!("http://iframely/oembed?url={}", url);
- let text = chttp::get(&fetch_url)?.text()?;
+ let text = isahc::get(&fetch_url)?.text()?;
let res: IframelyResponse = serde_json::from_str(&text)?;
Ok(res)
}
"http://pictshare/api/geturl.php?url={}",
utf8_percent_encode(image_url, NON_ALPHANUMERIC)
);
- let text = chttp::get(&fetch_url)?.text()?;
+ let text = isahc::get(&fetch_url)?.text()?;
let res: PictshareResponse = serde_json::from_str(&text)?;
Ok(res)
}
)
}
+pub fn markdown_to_html(text: &str) -> String {
+ comrak::markdown_to_html(text, &comrak::ComrakOptions::default())
+}
+
#[cfg(test)]
mod tests {
use crate::{extract_usernames, is_email_regex, remove_slurs, slur_check, slurs_vec_to_str};
use actix_web::*;
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection;
+use lemmy_server::db::code_migrations::run_advanced_migrations;
use lemmy_server::routes::{api, federation, feeds, index, nodeinfo, webfinger, websocket};
use lemmy_server::settings::Settings;
use lemmy_server::websocket::server::*;
// Run the migrations from code
let conn = pool.get().unwrap();
embedded_migrations::run(&conn).unwrap();
+ run_advanced_migrations(&conn).unwrap();
// Set up websocket server
let server = ChatServer::startup(pool.clone()).start();
-extern crate rss;
-
use super::*;
use crate::db::comment_view::{ReplyQueryBuilder, ReplyView};
use crate::db::community::Community;
use crate::db::user::{Claims, User_};
use crate::db::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
use crate::db::{ListingType, SortType};
-use crate::Settings;
+use crate::{markdown_to_html, Settings};
use actix_web::{web, HttpResponse, Result};
-use chrono::{DateTime, Utc};
+use chrono::{DateTime, NaiveDateTime, Utc};
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection;
use failure::Error;
pub fn config(cfg: &mut web::ServiceConfig) {
cfg
.route("/feeds/{type}/{name}.xml", web::get().to(feeds::get_feed))
- .route("/feeds/all.xml", web::get().to(feeds::get_all_feed))
.route("/feeds/all.xml", web::get().to(feeds::get_all_feed));
}
) -> Result<HttpResponse, actix_web::Error> {
let res = web::block(move || {
let conn = db.get()?;
-
- let sort_type = get_sort_type(info)?;
- get_feed_all_data(&conn, &sort_type)
+ get_feed_all_data(&conn, &get_sort_type(info)?)
})
.await
.map(|rss| {
Ok(res)
}
+fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> {
+ let site_view = SiteView::read(&conn)?;
+
+ let posts = PostQueryBuilder::create(&conn)
+ .listing_type(ListingType::All)
+ .sort(sort_type)
+ .list()?;
+
+ let items = create_post_items(posts);
+
+ let mut channel_builder = ChannelBuilder::default();
+ channel_builder
+ .title(&format!("{} - All", site_view.name))
+ .link(format!("https://{}", Settings::get().hostname))
+ .items(items);
+
+ if let Some(site_desc) = site_view.description {
+ channel_builder.description(&site_desc);
+ }
+
+ Ok(channel_builder.build().unwrap().to_string())
+}
+
async fn get_feed(
path: web::Path<(String, String)>,
info: web::Query<Params>,
}
})
.await
+ .map(|builder| builder.build().unwrap().to_string())
.map(|rss| {
HttpResponse::Ok()
.content_type("application/rss+xml")
SortType::from_str(&sort_query)
}
-fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> {
- let site_view = SiteView::read(&conn)?;
-
- let posts = PostQueryBuilder::create(&conn)
- .listing_type(ListingType::All)
- .sort(sort_type)
- .list()?;
-
- let items = create_post_items(posts);
-
- let mut channel_builder = ChannelBuilder::default();
- channel_builder
- .title(&format!("{} - All", site_view.name))
- .link(format!("https://{}", Settings::get().hostname))
- .items(items);
-
- if let Some(site_desc) = site_view.description {
- channel_builder.description(&site_desc);
- }
-
- Ok(channel_builder.build().unwrap().to_string())
-}
-
fn get_feed_user(
conn: &PgConnection,
sort_type: &SortType,
user_name: String,
-) -> Result<String, Error> {
+) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?;
let user = User_::find_by_username(&conn, &user_name)?;
let user_url = user.get_profile_url();
.link(user_url)
.items(items);
- Ok(channel_builder.build().unwrap().to_string())
+ Ok(channel_builder)
}
fn get_feed_community(
conn: &PgConnection,
sort_type: &SortType,
community_name: String,
-) -> Result<String, Error> {
+) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?;
let community = Community::read_from_name(&conn, community_name)?;
let community_url = community.get_url();
channel_builder.description(&community_desc);
}
- Ok(channel_builder.build().unwrap().to_string())
+ Ok(channel_builder)
}
-fn get_feed_front(conn: &PgConnection, sort_type: &SortType, jwt: String) -> Result<String, Error> {
+fn get_feed_front(
+ conn: &PgConnection,
+ sort_type: &SortType,
+ jwt: String,
+) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?;
let user_id = Claims::decode(&jwt)?.claims.id;
channel_builder.description(&site_desc);
}
- Ok(channel_builder.build().unwrap().to_string())
+ Ok(channel_builder)
}
-fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<String, Error> {
+fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?;
let user_id = Claims::decode(&jwt)?.claims.id;
channel_builder.description(&site_desc);
}
- Ok(channel_builder.build().unwrap().to_string())
+ Ok(channel_builder)
}
fn create_reply_and_mention_items(
replies: Vec<ReplyView>,
mentions: Vec<UserMentionView>,
) -> Vec<Item> {
- let mut items: Vec<Item> = Vec::new();
-
- for r in replies {
- let mut i = ItemBuilder::default();
-
- i.title(format!("Reply from {}", r.creator_name));
-
- let author_url = format!("https://{}/u/{}", Settings::get().hostname, r.creator_name);
- i.author(format!(
- "/u/{} <a href=\"{}\">(link)</a>",
- r.creator_name, author_url
- ));
-
- let dt = DateTime::<Utc>::from_utc(r.published, Utc);
- i.pub_date(dt.to_rfc2822());
-
- let reply_url = format!(
- "https://{}/post/{}/comment/{}",
- Settings::get().hostname,
- r.post_id,
- r.id
- );
- i.comments(reply_url.to_owned());
- let guid = GuidBuilder::default()
- .permalink(true)
- .value(&reply_url)
- .build();
- i.guid(guid.unwrap());
-
- i.link(reply_url);
-
- // TODO find a markdown to html parser here, do images, etc
- i.description(r.content);
-
- items.push(i.build().unwrap());
- }
-
- for m in mentions {
- let mut i = ItemBuilder::default();
-
- i.title(format!("Mention from {}", m.creator_name));
-
- let author_url = format!("https://{}/u/{}", Settings::get().hostname, m.creator_name);
- i.author(format!(
- "/u/{} <a href=\"{}\">(link)</a>",
- m.creator_name, author_url
- ));
-
- let dt = DateTime::<Utc>::from_utc(m.published, Utc);
- i.pub_date(dt.to_rfc2822());
-
- let mention_url = format!(
- "https://{}/post/{}/comment/{}",
- Settings::get().hostname,
- m.post_id,
- m.id
- );
- i.comments(mention_url.to_owned());
- let guid = GuidBuilder::default()
- .permalink(true)
- .value(&mention_url)
- .build();
- i.guid(guid.unwrap());
-
- i.link(mention_url);
-
- // TODO find a markdown to html parser here, do images, etc
- i.description(m.content);
-
- items.push(i.build().unwrap());
- }
+ let mut reply_items: Vec<Item> = replies
+ .iter()
+ .map(|r| {
+ let reply_url = format!(
+ "https://{}/post/{}/comment/{}",
+ Settings::get().hostname,
+ r.post_id,
+ r.id
+ );
+ build_item(&r.creator_name, &r.published, &reply_url, &r.content)
+ })
+ .collect();
+
+ let mut mention_items: Vec<Item> = mentions
+ .iter()
+ .map(|m| {
+ let mention_url = format!(
+ "https://{}/post/{}/comment/{}",
+ Settings::get().hostname,
+ m.post_id,
+ m.id
+ );
+ build_item(&m.creator_name, &m.published, &mention_url, &m.content)
+ })
+ .collect();
+
+ reply_items.append(&mut mention_items);
+ reply_items
+}
- items
+fn build_item(creator_name: &str, published: &NaiveDateTime, url: &str, content: &str) -> Item {
+ let mut i = ItemBuilder::default();
+ i.title(format!("Reply from {}", creator_name));
+ let author_url = format!("https://{}/u/{}", Settings::get().hostname, creator_name);
+ i.author(format!(
+ "/u/{} <a href=\"{}\">(link)</a>",
+ creator_name, author_url
+ ));
+ let dt = DateTime::<Utc>::from_utc(*published, Utc);
+ i.pub_date(dt.to_rfc2822());
+ i.comments(url.to_owned());
+ let guid = GuidBuilder::default().permalink(true).value(url).build();
+ i.guid(guid.unwrap());
+ i.link(url.to_owned());
+ // TODO add images
+ let html = markdown_to_html(&content.to_string());
+ i.description(html);
+ i.build().unwrap()
}
fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
i.link(url);
}
- // TODO find a markdown to html parser here, do images, etc
- let mut description = format!("
- submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
+ // TODO add images
+ let mut description = format!("submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
author_url,
p.creator_name,
community_url,
p.number_of_comments);
if let Some(body) = p.body {
- description.push_str(&format!("<br><br>{}", body));
+ let html = markdown_to_html(&body);
+ description.push_str(&html);
}
i.description(description);
-extern crate lazy_static;
use crate::apub::get_apub_protocol_string;
use crate::db::site_view::SiteView;
use crate::version;
table! {
- category (id) {
- id -> Int4,
- name -> Varchar,
- }
+ activity (id) {
+ id -> Int4,
+ user_id -> Int4,
+ data -> Jsonb,
+ local -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
}
table! {
- comment (id) {
- id -> Int4,
- creator_id -> Int4,
- post_id -> Int4,
- parent_id -> Nullable<Int4>,
- content -> Text,
- removed -> Bool,
- read -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- deleted -> Bool,
- }
+ category (id) {
+ id -> Int4,
+ name -> Varchar,
+ }
}
table! {
- comment_like (id) {
- id -> Int4,
- user_id -> Int4,
- comment_id -> Int4,
- post_id -> Int4,
- score -> Int2,
- published -> Timestamp,
- }
+ comment (id) {
+ id -> Int4,
+ creator_id -> Int4,
+ post_id -> Int4,
+ parent_id -> Nullable<Int4>,
+ content -> Text,
+ removed -> Bool,
+ read -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ deleted -> Bool,
+ }
}
table! {
- comment_saved (id) {
- id -> Int4,
- comment_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ comment_like (id) {
+ id -> Int4,
+ user_id -> Int4,
+ comment_id -> Int4,
+ post_id -> Int4,
+ score -> Int2,
+ published -> Timestamp,
+ }
}
table! {
- community (id) {
- id -> Int4,
- name -> Varchar,
- title -> Varchar,
- description -> Nullable<Text>,
- category_id -> Int4,
- creator_id -> Int4,
- removed -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- deleted -> Bool,
- nsfw -> Bool,
- }
+ comment_saved (id) {
+ id -> Int4,
+ comment_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
table! {
- community_follower (id) {
- id -> Int4,
- community_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ community (id) {
+ id -> Int4,
+ name -> Varchar,
+ title -> Varchar,
+ description -> Nullable<Text>,
+ category_id -> Int4,
+ creator_id -> Int4,
+ removed -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ deleted -> Bool,
+ nsfw -> Bool,
+ actor_id -> Varchar,
+ local -> Bool,
+ private_key -> Nullable<Text>,
+ public_key -> Nullable<Text>,
+ last_refreshed_at -> Timestamp,
+ }
}
table! {
- community_moderator (id) {
- id -> Int4,
- community_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ community_follower (id) {
+ id -> Int4,
+ community_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
table! {
- community_user_ban (id) {
- id -> Int4,
- community_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ community_moderator (id) {
+ id -> Int4,
+ community_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
table! {
- mod_add (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
+ community_user_ban (id) {
+ id -> Int4,
+ community_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
table! {
- mod_add_community (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- community_id -> Int4,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
+ mod_add (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_ban (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- reason -> Nullable<Text>,
- banned -> Nullable<Bool>,
- expires -> Nullable<Timestamp>,
- when_ -> Timestamp,
- }
+ mod_add_community (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ community_id -> Int4,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_ban_from_community (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- community_id -> Int4,
- reason -> Nullable<Text>,
- banned -> Nullable<Bool>,
- expires -> Nullable<Timestamp>,
- when_ -> Timestamp,
- }
+ mod_ban (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ reason -> Nullable<Text>,
+ banned -> Nullable<Bool>,
+ expires -> Nullable<Timestamp>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_lock_post (id) {
- id -> Int4,
- mod_user_id -> Int4,
- post_id -> Int4,
- locked -> Nullable<Bool>,
- when_ -> Timestamp,
- }
+ mod_ban_from_community (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ community_id -> Int4,
+ reason -> Nullable<Text>,
+ banned -> Nullable<Bool>,
+ expires -> Nullable<Timestamp>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_remove_comment (id) {
- id -> Int4,
- mod_user_id -> Int4,
- comment_id -> Int4,
- reason -> Nullable<Text>,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
+ mod_lock_post (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ post_id -> Int4,
+ locked -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_remove_community (id) {
- id -> Int4,
- mod_user_id -> Int4,
- community_id -> Int4,
- reason -> Nullable<Text>,
- removed -> Nullable<Bool>,
- expires -> Nullable<Timestamp>,
- when_ -> Timestamp,
- }
+ mod_remove_comment (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ comment_id -> Int4,
+ reason -> Nullable<Text>,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_remove_post (id) {
- id -> Int4,
- mod_user_id -> Int4,
- post_id -> Int4,
- reason -> Nullable<Text>,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
+ mod_remove_community (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ community_id -> Int4,
+ reason -> Nullable<Text>,
+ removed -> Nullable<Bool>,
+ expires -> Nullable<Timestamp>,
+ when_ -> Timestamp,
+ }
}
table! {
- mod_sticky_post (id) {
- id -> Int4,
- mod_user_id -> Int4,
- post_id -> Int4,
- stickied -> Nullable<Bool>,
- when_ -> Timestamp,
- }
+ mod_remove_post (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ post_id -> Int4,
+ reason -> Nullable<Text>,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
}
table! {
- password_reset_request (id) {
- id -> Int4,
- user_id -> Int4,
- token_encrypted -> Text,
- published -> Timestamp,
- }
+ mod_sticky_post (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ post_id -> Int4,
+ stickied -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
}
table! {
- post (id) {
- id -> Int4,
- name -> Varchar,
- url -> Nullable<Text>,
- body -> Nullable<Text>,
- creator_id -> Int4,
- community_id -> Int4,
- removed -> Bool,
- locked -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- deleted -> Bool,
- nsfw -> Bool,
- stickied -> Bool,
- embed_title -> Nullable<Text>,
- embed_description -> Nullable<Text>,
- embed_html -> Nullable<Text>,
- thumbnail_url -> Nullable<Text>,
- }
+ password_reset_request (id) {
+ id -> Int4,
+ user_id -> Int4,
+ token_encrypted -> Text,
+ published -> Timestamp,
+ }
}
table! {
- post_like (id) {
- id -> Int4,
- post_id -> Int4,
- user_id -> Int4,
- score -> Int2,
- published -> Timestamp,
- }
+ post (id) {
+ id -> Int4,
+ name -> Varchar,
+ url -> Nullable<Text>,
+ body -> Nullable<Text>,
+ creator_id -> Int4,
+ community_id -> Int4,
+ removed -> Bool,
+ locked -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ deleted -> Bool,
+ nsfw -> Bool,
+ stickied -> Bool,
+ embed_title -> Nullable<Text>,
+ embed_description -> Nullable<Text>,
+ embed_html -> Nullable<Text>,
+ thumbnail_url -> Nullable<Text>,
+ }
}
table! {
- post_read (id) {
- id -> Int4,
- post_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ post_like (id) {
+ id -> Int4,
+ post_id -> Int4,
+ user_id -> Int4,
+ score -> Int2,
+ published -> Timestamp,
+ }
}
table! {
- post_saved (id) {
- id -> Int4,
- post_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ post_read (id) {
+ id -> Int4,
+ post_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
table! {
- private_message (id) {
- id -> Int4,
- creator_id -> Int4,
- recipient_id -> Int4,
- content -> Text,
- deleted -> Bool,
- read -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- }
+ post_saved (id) {
+ id -> Int4,
+ post_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
table! {
- site (id) {
- id -> Int4,
- name -> Varchar,
- description -> Nullable<Text>,
- creator_id -> Int4,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- enable_downvotes -> Bool,
- open_registration -> Bool,
- enable_nsfw -> Bool,
- }
+ private_message (id) {
+ id -> Int4,
+ creator_id -> Int4,
+ recipient_id -> Int4,
+ content -> Text,
+ deleted -> Bool,
+ read -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
}
table! {
- user_ (id) {
- id -> Int4,
- name -> Varchar,
- fedi_name -> Varchar,
- preferred_username -> Nullable<Varchar>,
- password_encrypted -> Text,
- email -> Nullable<Text>,
- avatar -> Nullable<Text>,
- admin -> Bool,
- banned -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- show_nsfw -> Bool,
- theme -> Varchar,
- default_sort_type -> Int2,
- default_listing_type -> Int2,
- lang -> Varchar,
- show_avatars -> Bool,
- send_notifications_to_email -> Bool,
- matrix_user_id -> Nullable<Text>,
- }
+ site (id) {
+ id -> Int4,
+ name -> Varchar,
+ description -> Nullable<Text>,
+ creator_id -> Int4,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ enable_downvotes -> Bool,
+ open_registration -> Bool,
+ enable_nsfw -> Bool,
+ }
}
table! {
- user_ban (id) {
- id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
+ user_ (id) {
+ id -> Int4,
+ name -> Varchar,
+ fedi_name -> Varchar,
+ preferred_username -> Nullable<Varchar>,
+ password_encrypted -> Text,
+ email -> Nullable<Text>,
+ avatar -> Nullable<Text>,
+ admin -> Bool,
+ banned -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ show_nsfw -> Bool,
+ theme -> Varchar,
+ default_sort_type -> Int2,
+ default_listing_type -> Int2,
+ lang -> Varchar,
+ show_avatars -> Bool,
+ send_notifications_to_email -> Bool,
+ matrix_user_id -> Nullable<Text>,
+ actor_id -> Varchar,
+ bio -> Nullable<Text>,
+ local -> Bool,
+ private_key -> Nullable<Text>,
+ public_key -> Nullable<Text>,
+ last_refreshed_at -> Timestamp,
+ }
}
table! {
- user_mention (id) {
- id -> Int4,
- recipient_id -> Int4,
- comment_id -> Int4,
- read -> Bool,
- published -> Timestamp,
- }
+ user_ban (id) {
+ id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
}
+table! {
+ user_mention (id) {
+ id -> Int4,
+ recipient_id -> Int4,
+ comment_id -> Int4,
+ read -> Bool,
+ published -> Timestamp,
+ }
+}
+
+joinable!(activity -> user_ (user_id));
joinable!(comment -> post (post_id));
joinable!(comment -> user_ (creator_id));
joinable!(comment_like -> comment (comment_id));
joinable!(user_mention -> user_ (recipient_id));
allow_tables_to_appear_in_same_query!(
+ activity,
category,
comment,
comment_like,
-extern crate lazy_static;
use config::{Config, ConfigError, Environment, File};
use serde::Deserialize;
use std::env;
#[derive(Debug, Deserialize)]
pub struct Settings {
+ pub setup: Option<Setup>,
pub database: Database,
pub hostname: String,
pub bind: IpAddr,
pub federation: Federation,
}
+#[derive(Debug, Deserialize)]
+pub struct Setup {
+ pub admin_username: String,
+ pub admin_password: String,
+ pub admin_email: Option<String>,
+ pub site_name: String,
+}
+
#[derive(Debug, Deserialize)]
pub struct RateLimitConfig {
pub message: i32,
-pub const VERSION: &str = "v0.6.39";
+pub const VERSION: &str = "v0.6.44";
"inferno/no-direct-mutation-state": 0,
"inferno/no-unknown-property": 0,
"max-statements": 0,
+ "max-params": 0,
"new-cap": 0,
"no-console": 0,
"no-duplicate-imports": 0,
}
hr {
- border-top: 1px solid var(--secondary);
+ border-top: 1px solid var(--light);
}
.emoji {
max-height: 90vh;
}
-.vote-animate:active {
+.btn-animate:active {
transform: scale(1.2);
-webkit-transform: scale(1.2);
-ms-transform: scale(1.2);
"keywords": [],
"dependencies": {
"@types/autosize": "^3.0.6",
- "@types/js-cookie": "^2.2.1",
+ "@types/js-cookie": "^2.2.5",
"@types/jwt-decode": "^2.2.1",
"@types/markdown-it": "^0.0.9",
"@types/markdown-it-container": "^2.0.2",
- "@types/node": "^13.7.0",
+ "@types/node": "^13.9.2",
"autosize": "^4.0.2",
"bootswatch": "^4.3.1",
"classcat": "^1.1.3",
"dotenv": "^8.2.0",
"emoji-short-name": "^1.0.0",
- "husky": "^4.2.1",
- "i18next": "^19.0.3",
+ "husky": "^4.2.3",
+ "i18next": "^19.3.3",
"inferno": "^7.4.2",
"inferno-i18next": "nimbusec-oss/inferno-i18next",
"inferno-router": "^7.4.2",
"prettier": "^1.18.2",
"reconnecting-websocket": "^4.4.0",
"rxjs": "^6.4.0",
- "terser": "^4.6.3",
- "tippy.js": "^6.0.0",
- "toastify-js": "^1.6.2",
- "tributejs": "^5.0.0",
+ "terser": "^4.6.7",
+ "tippy.js": "^6.1.0",
+ "toastify-js": "^1.7.0",
+ "tributejs": "^5.1.2",
"twemoji": "^12.1.2",
- "ws": "^7.0.0"
+ "ws": "^7.2.3"
},
"devDependencies": {
"eslint": "^6.5.1",
"eslint-plugin-inferno": "^7.14.3",
- "eslint-plugin-jane": "^7.0.2",
+ "eslint-plugin-jane": "^7.2.0",
"fuse-box": "^3.1.3",
- "lint-staged": "^10.0.2",
- "sortpack": "^2.0.1",
- "ts-node": "^8.6.2",
+ "lint-staged": "^10.0.8",
+ "sortpack": "^2.1.2",
+ "ts-node": "^8.7.0",
"ts-transform-classcat": "^0.0.2",
"ts-transform-inferno": "^4.0.2",
"typescript": "^3.8.3"
upvotes: number;
downvotes: number;
borderColor: string;
+ readLoading: boolean;
+ saveLoading: boolean;
}
interface CommentNodeProps {
viewOnly?: boolean;
locked?: boolean;
markable?: boolean;
+ showContext?: boolean;
moderators: Array<CommunityUser>;
admins: Array<UserView>;
// TODO is this necessary, can't I get it from the node itself?
borderColor: this.props.node.comment.depth
? colorList[this.props.node.comment.depth % colorList.length]
: colorList[0],
+ readLoading: false,
+ saveLoading: false,
};
constructor(props: any, context: any) {
this.state.upvotes = nextProps.node.comment.upvotes;
this.state.downvotes = nextProps.node.comment.downvotes;
this.state.score = nextProps.node.comment.score;
+ this.state.readLoading = false;
+ this.state.saveLoading = false;
this.setState(this.state);
}
return (
<div
className={`comment ${
- node.comment.parent_id && !this.props.noIndent ? 'ml-2' : ''
+ node.comment.parent_id && !this.props.noIndent ? 'ml-1' : ''
}`}
>
- {!node.comment.parent_id && !this.props.noIndent && (
- <>
- <hr class="d-sm-none my-2" />
- <div class="d-none d-sm-block d-sm-none my-3" />
- </>
- )}
<div
id={`comment-${node.comment.id}`}
- className={`details comment-node mb-1 ${
+ className={`details comment-node border-top border-light ${
this.isCommentNew ? 'mark' : ''
}`}
style={
this.props.node.comment.parent_id &&
'ml-2'}`}
>
- <ul class="list-inline mb-1 text-muted small">
- <li className="list-inline-item">
- <Link
- className="text-body font-weight-bold"
- to={`/u/${node.comment.creator_name}`}
- >
- {node.comment.creator_avatar && showAvatars() && (
- <img
- height="32"
- width="32"
- src={pictshareAvatarThumbnail(
- node.comment.creator_avatar
- )}
- class="rounded-circle mr-1"
- />
- )}
- <span>{node.comment.creator_name}</span>
- </Link>
- </li>
+ <div class="d-flex flex-wrap align-items-center mb-1 mt-1 text-muted small">
+ <Link
+ className="mr-2 text-body font-weight-bold"
+ to={`/u/${node.comment.creator_name}`}
+ >
+ {node.comment.creator_avatar && showAvatars() && (
+ <img
+ height="32"
+ width="32"
+ src={pictshareAvatarThumbnail(node.comment.creator_avatar)}
+ class="rounded-circle mr-1"
+ />
+ )}
+ <span>{node.comment.creator_name}</span>
+ </Link>
{this.isMod && (
- <li className="list-inline-item badge badge-light">
+ <div className="badge badge-light d-none d-sm-inline mr-2">
{i18n.t('mod')}
- </li>
+ </div>
)}
{this.isAdmin && (
- <li className="list-inline-item badge badge-light">
+ <div className="badge badge-light d-none d-sm-inline mr-2">
{i18n.t('admin')}
- </li>
+ </div>
)}
{this.isPostCreator && (
- <li className="list-inline-item badge badge-light">
+ <div className="badge badge-light d-none d-sm-inline mr-2">
{i18n.t('creator')}
- </li>
+ </div>
)}
{(node.comment.banned_from_community || node.comment.banned) && (
- <li className="list-inline-item badge badge-danger">
+ <div className="badge badge-danger mr-2">
{i18n.t('banned')}
- </li>
+ </div>
)}
{this.props.showCommunity && (
- <li className="list-inline-item">
- <span> {i18n.t('to')} </span>
- <Link to={`/c/${node.comment.community_name}`}>
+ <>
+ <span class="mx-1">{i18n.t('to')}</span>
+ <Link class="mr-2" to={`/c/${node.comment.community_name}`}>
{node.comment.community_name}
</Link>
- </li>
+ </>
)}
- <li className="list-inline-item">•</li>
- <li className="list-inline-item">
- <span
- className={`unselectable pointer ${this.scoreColor}`}
- onClick={linkEvent(node, this.handleCommentUpvote)}
- data-tippy-content={this.pointsTippy}
- >
- <svg class="icon icon-inline mr-1">
- <use xlinkHref="#icon-zap"></use>
+ <div
+ className="mr-lg-4 flex-grow-1 flex-lg-grow-0 unselectable pointer mr-2"
+ onClick={linkEvent(this, this.handleCommentCollapse)}
+ >
+ {this.state.collapsed ? (
+ <svg class="icon icon-inline">
+ <use xlinkHref="#icon-plus-square"></use>
</svg>
- {this.state.score}
- </span>
- </li>
- <li className="list-inline-item">•</li>
- <li className="list-inline-item">
- <span>
- <MomentTime data={node.comment} />
- </span>
- </li>
- <li className="list-inline-item">
- <div
- className="unselectable pointer text-monospace"
- onClick={linkEvent(this, this.handleCommentCollapse)}
- >
- {this.state.collapsed ? (
- <svg class="icon icon-inline">
- <use xlinkHref="#icon-plus-square"></use>
- </svg>
- ) : (
- <svg class="icon icon-inline">
- <use xlinkHref="#icon-minus-square"></use>
- </svg>
- )}
- </div>
- </li>
- </ul>
+ ) : (
+ <svg class="icon icon-inline">
+ <use xlinkHref="#icon-minus-square"></use>
+ </svg>
+ )}
+ </div>
+ <span
+ className={`unselectable pointer ${this.scoreColor}`}
+ onClick={linkEvent(node, this.handleCommentUpvote)}
+ data-tippy-content={this.pointsTippy}
+ >
+ <svg class="icon icon-inline mr-1">
+ <use xlinkHref="#icon-zap"></use>
+ </svg>
+ <span class="mr-1">{this.state.score}</span>
+ </span>
+ <span className="mr-1">•</span>
+ <span>
+ <MomentTime data={node.comment} />
+ </span>
+ </div>
+ {/* end of user row */}
{this.state.showEdit && (
<CommentForm
node={node}
)}
/>
)}
- <ul class="list-inline mb-0 text-muted font-weight-bold h5">
+ <div class="d-flex justify-content-between justify-content-lg-start flex-wrap text-muted font-weight-bold">
+ {this.props.showContext && this.linkBtn}
{this.props.markable && (
- <li className="list-inline-item-action">
- <span
- class="pointer"
- onClick={linkEvent(this, this.handleMarkRead)}
- data-tippy-content={
- node.comment.read
- ? i18n.t('mark_as_unread')
- : i18n.t('mark_as_read')
- }
- >
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleMarkRead)}
+ data-tippy-content={
+ node.comment.read
+ ? i18n.t('mark_as_unread')
+ : i18n.t('mark_as_read')
+ }
+ >
+ {this.state.readLoading ? (
+ this.loadingIcon
+ ) : (
<svg
class={`icon icon-inline ${node.comment.read &&
'text-success'}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
- </span>
- </li>
+ )}
+ </button>
)}
{UserService.Instance.user && !this.props.viewOnly && (
<>
- <li className="list-inline-item-action">
+ <button
+ className={`btn btn-link btn-animate ${
+ this.state.my_vote == 1 ? 'text-info' : 'text-muted'
+ }`}
+ onClick={linkEvent(node, this.handleCommentUpvote)}
+ data-tippy-content={i18n.t('upvote')}
+ >
+ <svg class="icon icon-inline">
+ <use xlinkHref="#icon-arrow-up"></use>
+ </svg>
+ {this.state.upvotes !== this.state.score && (
+ <span class="ml-1">{this.state.upvotes}</span>
+ )}
+ </button>
+ {WebSocketService.Instance.site.enable_downvotes && (
<button
- className={`vote-animate btn btn-link p-0 mb-1 ${
- this.state.my_vote == 1 ? 'text-info' : 'text-muted'
+ className={`btn btn-link btn-animate ${
+ this.state.my_vote == -1
+ ? 'text-danger'
+ : 'text-muted'
}`}
- onClick={linkEvent(node, this.handleCommentUpvote)}
- data-tippy-content={i18n.t('upvote')}
+ onClick={linkEvent(node, this.handleCommentDownvote)}
+ data-tippy-content={i18n.t('downvote')}
>
<svg class="icon icon-inline">
- <use xlinkHref="#icon-arrow-up"></use>
+ <use xlinkHref="#icon-arrow-down"></use>
</svg>
{this.state.upvotes !== this.state.score && (
- <span class="ml-1">{this.state.upvotes}</span>
+ <span class="ml-1">{this.state.downvotes}</span>
)}
</button>
- </li>
- {WebSocketService.Instance.site.enable_downvotes && (
- <li className="list-inline-item-action">
- <button
- className={`vote-animate btn btn-link p-0 mb-1 ${
- this.state.my_vote == -1
- ? 'text-danger'
- : 'text-muted'
- }`}
- onClick={linkEvent(
- node,
- this.handleCommentDownvote
- )}
- data-tippy-content={i18n.t('downvote')}
- >
- <svg class="icon icon-inline">
- <use xlinkHref="#icon-arrow-down"></use>
- </svg>
- {this.state.upvotes !== this.state.score && (
- <span class="ml-1">{this.state.downvotes}</span>
- )}
- </button>
- </li>
)}
- <li className="list-inline-item-action">
- <span
- class="pointer"
- onClick={linkEvent(this, this.handleReplyClick)}
- data-tippy-content={i18n.t('reply')}
- >
- <svg class="icon icon-inline">
- <use xlinkHref="#icon-reply1"></use>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleSaveCommentClick)}
+ data-tippy-content={
+ node.comment.saved ? i18n.t('unsave') : i18n.t('save')
+ }
+ >
+ {this.state.saveLoading ? (
+ this.loadingIcon
+ ) : (
+ <svg
+ class={`icon icon-inline ${node.comment.saved &&
+ 'text-warning'}`}
+ >
+ <use xlinkHref="#icon-star"></use>
</svg>
- </span>
- </li>
- <li className="list-inline-item-action">
- <Link
- className="text-muted"
- to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
- title={i18n.t('link')}
+ )}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleReplyClick)}
+ data-tippy-content={i18n.t('reply')}
+ >
+ <svg class="icon icon-inline">
+ <use xlinkHref="#icon-reply1"></use>
+ </svg>
+ </button>
+ {!this.state.showAdvanced ? (
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleShowAdvanced)}
+ data-tippy-content={i18n.t('more')}
>
<svg class="icon icon-inline">
- <use xlinkHref="#icon-link"></use>
+ <use xlinkHref="#icon-more-vertical"></use>
</svg>
- </Link>
- </li>
- {!this.state.showAdvanced ? (
- <li className="list-inline-item-action">
- <span
- className="unselectable pointer"
- onClick={linkEvent(this, this.handleShowAdvanced)}
- data-tippy-content={i18n.t('more')}
- >
- <svg class="icon icon-inline">
- <use xlinkHref="#icon-more-vertical"></use>
- </svg>
- </span>
- </li>
+ </button>
) : (
<>
{!this.myComment && (
- <li className="list-inline-item-action">
+ <button class="btn btn-link btn-animate">
<Link
class="text-muted"
to={`/create_private_message?recipient_id=${node.comment.creator_id}`}
<use xlinkHref="#icon-mail"></use>
</svg>
</Link>
- </li>
+ </button>
)}
- <li className="list-inline-item-action">
- <span
- class="pointer"
- onClick={linkEvent(
- this,
- this.handleSaveCommentClick
- )}
- data-tippy-content={
- node.comment.saved
- ? i18n.t('unsave')
- : i18n.t('save')
- }
+ {!this.props.showContext && this.linkBtn}
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleViewSource)}
+ data-tippy-content={i18n.t('view_source')}
+ >
+ <svg
+ class={`icon icon-inline ${this.state
+ .viewSource && 'text-success'}`}
>
- <svg
- class={`icon icon-inline ${node.comment.saved &&
- 'text-warning'}`}
+ <use xlinkHref="#icon-file-text"></use>
+ </svg>
+ </button>
+ {this.myComment && (
+ <>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleEditClick)}
+ data-tippy-content={i18n.t('edit')}
>
- <use xlinkHref="#icon-star"></use>
- </svg>
- </span>
- </li>
- <li className="list-inline-item-action">
- <span
- className="pointer"
- onClick={linkEvent(this, this.handleViewSource)}
- data-tippy-content={i18n.t('view_source')}
- >
- <svg
- class={`icon icon-inline ${this.state
- .viewSource && 'text-success'}`}
+ <svg class="icon icon-inline">
+ <use xlinkHref="#icon-edit"></use>
+ </svg>
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleDeleteClick
+ )}
+ data-tippy-content={
+ !node.comment.deleted
+ ? i18n.t('delete')
+ : i18n.t('restore')
+ }
>
- <use xlinkHref="#icon-file-text"></use>
- </svg>
- </span>
- </li>
- {this.myComment && (
+ <svg
+ class={`icon icon-inline ${node.comment
+ .deleted && 'text-danger'}`}
+ >
+ <use xlinkHref="#icon-trash"></use>
+ </svg>
+ </button>
+ </>
+ )}
+ {/* Admins and mods can remove comments */}
+ {(this.canMod || this.canAdmin) && (
<>
- <li className="list-inline-item-action">•</li>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ {!node.comment.removed ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleEditClick
+ this.handleModRemoveShow
)}
- data-tippy-content={i18n.t('edit')}
>
- <svg class="icon icon-inline">
- <use xlinkHref="#icon-edit"></use>
- </svg>
- </span>
- </li>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ {i18n.t('remove')}
+ </button>
+ ) : (
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleDeleteClick
+ this.handleModRemoveSubmit
)}
- data-tippy-content={
- !node.comment.deleted
- ? i18n.t('delete')
- : i18n.t('restore')
- }
>
- <svg
- class={`icon icon-inline ${node.comment
- .deleted && 'text-danger'}`}
- >
- <use xlinkHref="#icon-trash"></use>
- </svg>
- </span>
- </li>
+ {i18n.t('restore')}
+ </button>
+ )}
</>
)}
- {/* Admins and mods can remove comments */}
- {(this.canMod || this.canAdmin) && (
+ {/* Mods can ban from community, and appoint as mods to community */}
+ {this.canMod && (
<>
- <li className="list-inline-item-action">
- {!node.comment.removed ? (
- <span
- class="pointer"
+ {!this.isMod &&
+ (!node.comment.banned_from_community ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleModRemoveShow
+ this.handleModBanFromCommunityShow
)}
>
- {i18n.t('remove')}
- </span>
+ {i18n.t('ban')}
+ </button>
) : (
- <span
- class="pointer"
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleModRemoveSubmit
+ this.handleModBanFromCommunitySubmit
)}
>
- {i18n.t('restore')}
- </span>
- )}
- </li>
- </>
- )}
- {/* Mods can ban from community, and appoint as mods to community */}
- {this.canMod && (
- <>
- {!this.isMod && (
- <li className="list-inline-item-action">
- {!node.comment.banned_from_community ? (
- <span
- class="pointer"
- onClick={linkEvent(
- this,
- this.handleModBanFromCommunityShow
- )}
- >
- {i18n.t('ban')}
- </span>
- ) : (
- <span
- class="pointer"
- onClick={linkEvent(
- this,
- this.handleModBanFromCommunitySubmit
- )}
- >
- {i18n.t('unban')}
- </span>
- )}
- </li>
- )}
- {!node.comment.banned_from_community && (
- <li className="list-inline-item-action">
- {!this.state.showConfirmAppointAsMod ? (
- <span
- class="pointer"
- onClick={linkEvent(
- this,
- this.handleShowConfirmAppointAsMod
- )}
- >
- {this.isMod
- ? i18n.t('remove_as_mod')
- : i18n.t('appoint_as_mod')}
- </span>
- ) : (
- <>
- <span class="d-inline-block mr-1">
- {i18n.t('are_you_sure')}
- </span>
- <span
- class="pointer d-inline-block mr-1"
- onClick={linkEvent(
- this,
- this.handleAddModToCommunity
- )}
- >
- {i18n.t('yes')}
- </span>
- <span
- class="pointer d-inline-block"
- onClick={linkEvent(
- this,
- this.handleCancelConfirmAppointAsMod
- )}
- >
- {i18n.t('no')}
- </span>
- </>
- )}
- </li>
- )}
- </>
- )}
- {/* Community creators and admins can transfer community to another mod */}
- {(this.amCommunityCreator || this.canAdmin) &&
- this.isMod && (
- <li className="list-inline-item-action">
- {!this.state.showConfirmTransferCommunity ? (
- <span
- class="pointer"
+ {i18n.t('unban')}
+ </button>
+ ))}
+ {!node.comment.banned_from_community &&
+ (!this.state.showConfirmAppointAsMod ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleShowConfirmTransferCommunity
+ this.handleShowConfirmAppointAsMod
)}
>
- {i18n.t('transfer_community')}
- </span>
+ {this.isMod
+ ? i18n.t('remove_as_mod')
+ : i18n.t('appoint_as_mod')}
+ </button>
) : (
<>
- <span class="d-inline-block mr-1">
+ <button class="btn btn-link btn-animate text-muted">
{i18n.t('are_you_sure')}
- </span>
- <span
- class="pointer d-inline-block mr-1"
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleTransferCommunity
+ this.handleAddModToCommunity
)}
>
{i18n.t('yes')}
- </span>
- <span
- class="pointer d-inline-block"
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this
- .handleCancelShowConfirmTransferCommunity
+ this.handleCancelConfirmAppointAsMod
)}
>
{i18n.t('no')}
- </span>
+ </button>
</>
+ ))}
+ </>
+ )}
+ {/* Community creators and admins can transfer community to another mod */}
+ {(this.amCommunityCreator || this.canAdmin) &&
+ this.isMod &&
+ (!this.state.showConfirmTransferCommunity ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleShowConfirmTransferCommunity
)}
- </li>
- )}
+ >
+ {i18n.t('transfer_community')}
+ </button>
+ ) : (
+ <>
+ <button class="btn btn-link btn-animate text-muted">
+ {i18n.t('are_you_sure')}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleTransferCommunity
+ )}
+ >
+ {i18n.t('yes')}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this
+ .handleCancelShowConfirmTransferCommunity
+ )}
+ >
+ {i18n.t('no')}
+ </button>
+ </>
+ ))}
{/* Admins can ban from all, and appoint other admins */}
{this.canAdmin && (
<>
- {!this.isAdmin && (
- <li className="list-inline-item-action">
- {!node.comment.banned ? (
- <span
- class="pointer"
- onClick={linkEvent(
- this,
- this.handleModBanShow
- )}
- >
- {i18n.t('ban_from_site')}
- </span>
- ) : (
- <span
- class="pointer"
+ {!this.isAdmin &&
+ (!node.comment.banned ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleModBanShow
+ )}
+ >
+ {i18n.t('ban_from_site')}
+ </button>
+ ) : (
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleModBanSubmit
+ )}
+ >
+ {i18n.t('unban_from_site')}
+ </button>
+ ))}
+ {!node.comment.banned &&
+ (!this.state.showConfirmAppointAsAdmin ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleShowConfirmAppointAsAdmin
+ )}
+ >
+ {this.isAdmin
+ ? i18n.t('remove_as_admin')
+ : i18n.t('appoint_as_admin')}
+ </button>
+ ) : (
+ <>
+ <button class="btn btn-link btn-animate text-muted">
+ {i18n.t('are_you_sure')}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleModBanSubmit
+ this.handleAddAdmin
)}
>
- {i18n.t('unban_from_site')}
- </span>
- )}
- </li>
- )}
- {!node.comment.banned && (
- <li className="list-inline-item-action">
- {!this.state.showConfirmAppointAsAdmin ? (
- <span
- class="pointer"
+ {i18n.t('yes')}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleShowConfirmAppointAsAdmin
+ this.handleCancelConfirmAppointAsAdmin
)}
>
- {this.isAdmin
- ? i18n.t('remove_as_admin')
- : i18n.t('appoint_as_admin')}
- </span>
- ) : (
- <>
- <span class="d-inline-block mr-1">
- {i18n.t('are_you_sure')}
- </span>
- <span
- class="pointer d-inline-block mr-1"
- onClick={linkEvent(
- this,
- this.handleAddAdmin
- )}
- >
- {i18n.t('yes')}
- </span>
- <span
- class="pointer d-inline-block"
- onClick={linkEvent(
- this,
- this.handleCancelConfirmAppointAsAdmin
- )}
- >
- {i18n.t('no')}
- </span>
- </>
- )}
- </li>
- )}
+ {i18n.t('no')}
+ </button>
+ </>
+ ))}
</>
)}
{/* Site Creator can transfer to another admin */}
- {this.amSiteCreator && this.isAdmin && (
- <li className="list-inline-item-action">
- {!this.state.showConfirmTransferSite ? (
- <span
- class="pointer"
+ {this.amSiteCreator &&
+ this.isAdmin &&
+ (!this.state.showConfirmTransferSite ? (
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleShowConfirmTransferSite
+ )}
+ >
+ {i18n.t('transfer_site')}
+ </button>
+ ) : (
+ <>
+ <button class="btn btn-link btn-animate text-muted">
+ {i18n.t('are_you_sure')}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleShowConfirmTransferSite
+ this.handleTransferSite
)}
>
- {i18n.t('transfer_site')}
- </span>
- ) : (
- <>
- <span class="d-inline-block mr-1">
- {i18n.t('are_you_sure')}
- </span>
- <span
- class="pointer d-inline-block mr-1"
- onClick={linkEvent(
- this,
- this.handleTransferSite
- )}
- >
- {i18n.t('yes')}
- </span>
- <span
- class="pointer d-inline-block"
- onClick={linkEvent(
- this,
- this.handleCancelShowConfirmTransferSite
- )}
- >
- {i18n.t('no')}
- </span>
- </>
- )}
- </li>
- )}
+ {i18n.t('yes')}
+ </button>
+ <button
+ class="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleCancelShowConfirmTransferSite
+ )}
+ >
+ {i18n.t('no')}
+ </button>
+ </>
+ ))}
</>
)}
</>
)}
- </ul>
+ </div>
+ {/* end of button group */}
</div>
)}
</div>
);
}
+ get linkBtn() {
+ let node = this.props.node;
+ return (
+ <button className="btn btn-link btn-animate">
+ <Link
+ class="text-muted"
+ to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
+ title={
+ this.props.showContext ? i18n.t('show_context') : i18n.t('link')
+ }
+ >
+ <svg class="icon icon-inline">
+ <use xlinkHref="#icon-link"></use>
+ </svg>
+ </Link>
+ </button>
+ );
+ }
+
+ get loadingIcon() {
+ return (
+ <svg class="icon icon-spinner spin">
+ <use xlinkHref="#icon-spinner"></use>
+ </svg>
+ );
+ }
+
get myComment(): boolean {
return (
UserService.Instance.user &&
};
WebSocketService.Instance.saveComment(form);
+
+ i.state.saveLoading = true;
+ i.setState(this.state);
}
handleReplyCancel() {
};
WebSocketService.Instance.editComment(form);
}
+
+ i.state.readLoading = true;
+ i.setState(this.state);
}
handleModBanFromCommunityShow(i: CommentNode) {
viewOnly?: boolean;
locked?: boolean;
markable?: boolean;
+ showContext?: boolean;
showCommunity?: boolean;
sort?: CommentSortType;
sortType?: SortType;
admins={this.props.admins}
postCreatorId={this.props.postCreatorId}
markable={this.props.markable}
+ showContext={this.props.showContext}
showCommunity={this.props.showCommunity}
sort={this.props.sort}
sortType={this.props.sortType}
nodes={commentsToFlatNodes(this.state.comments)}
noIndent
sortType={this.state.sort}
+ showContext
/>
);
}
import { Component, linkEvent } from 'inferno';
-import { Link } from 'inferno-router';
import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import {
import { PrivateMessage } from './private-message';
import { SortSelect } from './sort-select';
import { i18n } from '../i18next';
-import { T } from 'inferno-i18next';
enum UnreadOrAll {
Unread,
All,
}
-enum UnreadType {
+enum MessageType {
All,
Replies,
Mentions,
interface InboxState {
unreadOrAll: UnreadOrAll;
- unreadType: UnreadType;
+ messageType: MessageType;
replies: Array<Comment>;
mentions: Array<Comment>;
messages: Array<PrivateMessageI>;
private subscription: Subscription;
private emptyState: InboxState = {
unreadOrAll: UnreadOrAll.Unread,
- unreadType: UnreadType.All,
+ messageType: MessageType.All,
replies: [],
mentions: [],
messages: [],
}
render() {
- let user = UserService.Instance.user;
return (
<div class="container">
<div class="row">
<div class="col-12">
- <h5 class="mb-0">
- <T
- class="d-inline"
- i18nKey="inbox_for"
- interpolation={{ user: user.username }}
- >
- #<Link to={`/u/${user.username}`}>#</Link>
- </T>
+ <h5 class="mb-1">
+ {i18n.t('inbox')}
<small>
<a
href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
target="_blank"
title="RSS"
>
- <svg class="icon mx-2 text-muted small">
+ <svg class="icon ml-2 text-muted small">
<use xlinkHref="#icon-rss">#</use>
</svg>
</a>
</ul>
)}
{this.selects()}
- {this.state.unreadType == UnreadType.All && this.all()}
- {this.state.unreadType == UnreadType.Replies && this.replies()}
- {this.state.unreadType == UnreadType.Mentions && this.mentions()}
- {this.state.unreadType == UnreadType.Messages && this.messages()}
+ {this.state.messageType == MessageType.All && this.all()}
+ {this.state.messageType == MessageType.Replies && this.replies()}
+ {this.state.messageType == MessageType.Mentions && this.mentions()}
+ {this.state.messageType == MessageType.Messages && this.messages()}
{this.paginator()}
</div>
</div>
);
}
- selects() {
+ unreadOrAllRadios() {
return (
- <div className="mb-2">
- <select
- value={this.state.unreadOrAll}
- onChange={linkEvent(this, this.handleUnreadOrAllChange)}
- class="custom-select custom-select-sm w-auto mr-2"
+ <div class="btn-group btn-group-toggle">
+ <label
+ className={`btn btn-sm btn-secondary pointer
+ ${this.state.unreadOrAll == UnreadOrAll.Unread && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={UnreadOrAll.Unread}
+ checked={this.state.unreadOrAll == UnreadOrAll.Unread}
+ onChange={linkEvent(this, this.handleUnreadOrAllChange)}
+ />
+ {i18n.t('unread')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer
+ ${this.state.unreadOrAll == UnreadOrAll.All && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={UnreadOrAll.All}
+ checked={this.state.unreadOrAll == UnreadOrAll.All}
+ onChange={linkEvent(this, this.handleUnreadOrAllChange)}
+ />
+ {i18n.t('all')}
+ </label>
+ </div>
+ );
+ }
+
+ messageTypeRadios() {
+ return (
+ <div class="btn-group btn-group-toggle">
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.messageType == MessageType.All && 'active'}
+ `}
>
- <option disabled>{i18n.t('type')}</option>
- <option value={UnreadOrAll.Unread}>{i18n.t('unread')}</option>
- <option value={UnreadOrAll.All}>{i18n.t('all')}</option>
- </select>
- <select
- value={this.state.unreadType}
- onChange={linkEvent(this, this.handleUnreadTypeChange)}
- class="custom-select custom-select-sm w-auto mr-2"
+ <input
+ type="radio"
+ value={MessageType.All}
+ checked={this.state.messageType == MessageType.All}
+ onChange={linkEvent(this, this.handleMessageTypeChange)}
+ />
+ {i18n.t('all')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.messageType == MessageType.Replies && 'active'}
+ `}
>
- <option disabled>{i18n.t('type')}</option>
- <option value={UnreadType.All}>{i18n.t('all')}</option>
- <option value={UnreadType.Replies}>{i18n.t('replies')}</option>
- <option value={UnreadType.Mentions}>{i18n.t('mentions')}</option>
- <option value={UnreadType.Messages}>{i18n.t('messages')}</option>
- </select>
+ <input
+ type="radio"
+ value={MessageType.Replies}
+ checked={this.state.messageType == MessageType.Replies}
+ onChange={linkEvent(this, this.handleMessageTypeChange)}
+ />
+ {i18n.t('replies')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.messageType == MessageType.Mentions && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={MessageType.Mentions}
+ checked={this.state.messageType == MessageType.Mentions}
+ onChange={linkEvent(this, this.handleMessageTypeChange)}
+ />
+ {i18n.t('mentions')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.messageType == MessageType.Messages && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={MessageType.Messages}
+ checked={this.state.messageType == MessageType.Messages}
+ onChange={linkEvent(this, this.handleMessageTypeChange)}
+ />
+ {i18n.t('messages')}
+ </label>
+ </div>
+ );
+ }
+
+ selects() {
+ return (
+ <div className="mb-2">
+ <span class="mr-3">{this.unreadOrAllRadios()}</span>
+ <span class="mr-3">{this.messageTypeRadios()}</span>
<SortSelect
sort={this.state.sort}
onChange={this.handleSortChange}
<div>
{combined.map(i =>
isCommentType(i) ? (
- <CommentNodes nodes={[{ comment: i }]} noIndent markable />
+ <CommentNodes
+ nodes={[{ comment: i }]}
+ noIndent
+ markable
+ showContext
+ />
) : (
<PrivateMessage privateMessage={i} />
)
nodes={commentsToFlatNodes(this.state.replies)}
noIndent
markable
+ showContext
/>
</div>
);
return (
<div>
{this.state.mentions.map(mention => (
- <CommentNodes nodes={[{ comment: mention }]} noIndent markable />
+ <CommentNodes
+ nodes={[{ comment: mention }]}
+ noIndent
+ markable
+ showContext
+ />
))}
</div>
);
i.refetch();
}
- handleUnreadTypeChange(i: Inbox, event: any) {
- i.state.unreadType = Number(event.target.value);
+ handleMessageTypeChange(i: Inbox, event: any) {
+ i.state.messageType = Number(event.target.value);
i.state.page = 1;
i.setState(i.state);
i.refetch();
noIndent
showCommunity
sortType={this.state.sort}
+ showContext
/>
);
}
fetchLimit,
isCommentType,
toast,
+ messageToastify,
+ md,
} from '../utils';
import { version } from '../version';
import { i18n } from '../i18next';
<Link title={version} class="navbar-brand" to="/">
{this.state.siteName}
</Link>
+ {this.state.isLoggedIn && (
+ <Link
+ class="ml-auto p-0 navbar-toggler nav-link"
+ to="/inbox"
+ title={i18n.t('inbox')}
+ >
+ <svg class="icon">
+ <use xlinkHref="#icon-bell"></use>
+ </svg>
+ {this.state.unreadCount > 0 && (
+ <span class="ml-1 badge badge-light">
+ {this.state.unreadCount}
+ </span>
+ )}
+ </Link>
+ )}
<button
class="navbar-toggler"
type="button"
}
notify(reply: Comment | PrivateMessage) {
+ let creator_name = reply.creator_name;
+ let creator_avatar = reply.creator_avatar
+ ? reply.creator_avatar
+ : `${window.location.protocol}//${window.location.host}/static/assets/apple-touch-icon.png`;
+ let link = isCommentType(reply)
+ ? `/post/${reply.post_id}/comment/${reply.id}`
+ : `/inbox`;
+ let htmlBody = md.render(reply.content);
+ let body = reply.content; // Unfortunately the notifications API can't do html
+
+ messageToastify(
+ creator_name,
+ creator_avatar,
+ htmlBody,
+ link,
+ this.context.router
+ );
+
if (Notification.permission !== 'granted') Notification.requestPermission();
else {
var notification = new Notification(reply.creator_name, {
- icon: reply.creator_avatar
- ? reply.creator_avatar
- : `${window.location.protocol}//${window.location.host}/static/assets/apple-touch-icon.png`,
- body: `${reply.content}`,
+ icon: creator_avatar,
+ body: body,
});
notification.onclick = () => {
- this.context.router.history.push(
- isCommentType(reply)
- ? `/post/${reply.post_id}/comment/${reply.id}`
- : `/inbox`
- );
+ event.preventDefault();
+ this.context.router.history.push(link);
};
}
}
<div class="row">
<div className={`vote-bar col-1 pr-0 small text-center`}>
<button
- className={`vote-animate btn btn-link p-0 ${
+ className={`btn-animate btn btn-link p-0 ${
this.state.my_vote == 1 ? 'text-info' : 'text-muted'
}`}
onClick={linkEvent(this, this.handlePostLike)}
data-tippy-content={i18n.t('upvote')}
>
<svg class="icon upvote">
- <use xlinkHref="#icon-arrow-up"></use>
+ <use xlinkHref="#icon-arrow-up1"></use>
</svg>
</button>
<div
</div>
{WebSocketService.Instance.site.enable_downvotes && (
<button
- className={`vote-animate btn btn-link p-0 ${
+ className={`btn-animate btn btn-link p-0 ${
this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
}`}
onClick={linkEvent(this, this.handlePostDisLike)}
data-tippy-content={i18n.t('downvote')}
>
<svg class="icon downvote">
- <use xlinkHref="#icon-arrow-down"></use>
+ <use xlinkHref="#icon-arrow-down1"></use>
</svg>
</button>
)}
</Link>
</li>
</ul>
- <ul class="list-inline mb-1 small text-muted">
- {this.props.post.duplicates && (
+ {this.props.post.duplicates && (
+ <ul class="list-inline mb-1 small text-muted">
<>
<li className="list-inline-item mr-2">
{i18n.t('cross_posted_to')}
</li>
))}
</>
- )}
- </ul>
- <ul class="list-inline mb-1 text-muted h5 font-weight-bold">
+ </ul>
+ )}
+ <ul class="list-inline mb-1 text-muted font-weight-bold">
{UserService.Instance.user && (
<>
{this.props.showBody && (
<>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={
post.saved ? i18n.t('unsave') : i18n.t('save')
>
<use xlinkHref="#icon-star"></use>
</svg>
- </span>
+ </button>
</li>
- <li className="list-inline-item-action">
+ <li className="list-inline-item">
<Link
- className="text-muted"
+ class="btn btn-sm btn-link btn-animate text-muted"
to={`/create_post${this.crossPostParams}`}
title={i18n.t('cross_post')}
>
)}
{this.myPost && this.props.showBody && (
<>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
- </span>
+ </button>
</li>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
!post.deleted
>
<use xlinkHref="#icon-trash"></use>
</svg>
- </span>
+ </button>
</li>
</>
)}
{!this.state.showAdvanced && this.props.showBody ? (
- <li className="list-inline-item-action">
- <span
- className="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t('more')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-more-vertical"></use>
</svg>
- </span>
+ </button>
</li>
) : (
<>
{this.props.showBody && post.body && (
- <li className="list-inline-item-action">
- <span
- className="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
>
>
<use xlinkHref="#icon-file-text"></use>
</svg>
- </span>
+ </button>
</li>
)}
{this.canModOnSelf && (
<>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleModLock)}
data-tippy-content={
post.locked
>
<use xlinkHref="#icon-lock"></use>
</svg>
- </span>
+ </button>
</li>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-sm btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleModSticky)}
data-tippy-content={
post.stickied
>
<use xlinkHref="#icon-pin"></use>
</svg>
- </span>
+ </button>
</li>
</>
)}
post={post}
showCommunity={this.props.showCommunity}
/>
- <hr class="d-md-none my-2" />
- <div class="d-none d-md-block my-2"></div>
+ <hr class="my-2" />
</>
))
) : (
sortRadios() {
return (
- <div class="btn-group btn-group-toggle">
+ <div class="btn-group btn-group-toggle mb-2">
<label
className={`btn btn-sm btn-secondary pointer ${this.state
.commentSort === CommentSortType.Hot && 'active'}`}
moderators={this.state.moderators}
admins={this.state.admins}
postCreatorId={this.state.post.creator_id}
+ showContext
/>
</div>
</div>
render() {
let message = this.props.privateMessage;
return (
- <div class="mb-2">
+ <div class="border-top border-light">
<div>
<ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item">
dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
/>
)}
- <ul class="list-inline mb-1 text-muted h5 font-weight-bold">
+ <ul class="list-inline mb-0 text-muted font-weight-bold">
{!this.mine && (
<>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={
message.read
>
<use xlinkHref="#icon-check"></use>
</svg>
- </span>
+ </button>
</li>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-reply1"></use>
</svg>
- </span>
+ </button>
</li>
</>
)}
{this.mine && (
<>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
- </span>
+ </button>
</li>
- <li className="list-inline-item-action">
- <span
- class="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
!message.deleted
>
<use xlinkHref="#icon-trash"></use>
</svg>
- </span>
+ </button>
</li>
</>
)}
- <li className="list-inline-item-action">
- <span
- className="pointer"
+ <li className="list-inline-item">
+ <button
+ class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
>
>
<use xlinkHref="#icon-file-text"></use>
</svg>
- </span>
+ </button>
</li>
</ul>
</div>
<path d="M17 19h-12c-0.553 0-1-0.447-1-1s0.447-1 1-1h12c0.553 0 1 0.447 1 1s-0.447 1-1 1z"></path>
<path d="M17.5 5h-12.5v9c0 1.1 0.9 2 2 2h8c1.1 0 2-0.9 2-2v-2h0.5c1.93 0 3.5-1.57 3.5-3.5s-1.57-3.5-3.5-3.5zM15 14h-8v-7h8v7zM17.5 10h-1.5v-3h1.5c0.827 0 1.5 0.673 1.5 1.5s-0.673 1.5-1.5 1.5z"></path>
</symbol>
- <symbol id="icon-rss" viewBox="0 0 32 32">
- <path d="M4.259 23.467c-2.35 0-4.259 1.917-4.259 4.252 0 2.349 1.909 4.244 4.259 4.244 2.358 0 4.265-1.895 4.265-4.244-0-2.336-1.907-4.252-4.265-4.252zM0.005 10.873v6.133c3.993 0 7.749 1.562 10.577 4.391 2.825 2.822 4.384 6.595 4.384 10.603h6.16c-0-11.651-9.478-21.127-21.121-21.127zM0.012 0v6.136c14.243 0 25.836 11.604 25.836 25.864h6.152c0-17.64-14.352-32-31.988-32z"></path>
+ <symbol id="icon-rss" viewBox="0 0 24 24">
+ <path d="M4 12c2.209 0 4.208 0.894 5.657 2.343s2.343 3.448 2.343 5.657c0 0.552 0.448 1 1 1s1-0.448 1-1c0-2.761-1.12-5.263-2.929-7.071s-4.31-2.929-7.071-2.929c-0.552 0-1 0.448-1 1s0.448 1 1 1zM4 5c4.142 0 7.891 1.678 10.607 4.393s4.393 6.465 4.393 10.607c0 0.552 0.448 1 1 1s1-0.448 1-1c0-4.694-1.904-8.946-4.979-12.021s-7.327-4.979-12.021-4.979c-0.552 0-1 0.448-1 1s0.448 1 1 1zM7 19c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586-1.053 0.225-1.414 0.586-0.586 0.862-0.586 1.414 0.225 1.053 0.586 1.414 0.862 0.586 1.414 0.586 1.053-0.225 1.414-0.586 0.586-0.862 0.586-1.414z"></path>
</symbol>
- <symbol id="icon-arrow-down" viewBox="0 0 26 28">
- <path d="M25.172 13c0 0.531-0.219 1.047-0.578 1.406l-10.172 10.187c-0.375 0.359-0.891 0.578-1.422 0.578s-1.047-0.219-1.406-0.578l-10.172-10.187c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l1.156-1.172c0.375-0.359 0.891-0.578 1.422-0.578s1.047 0.219 1.406 0.578l4.594 4.594v-11c0-1.094 0.906-2 2-2h2c1.094 0 2 0.906 2 2v11l4.594-4.594c0.359-0.359 0.875-0.578 1.406-0.578s1.047 0.219 1.422 0.578l1.172 1.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
+ <symbol id="icon-arrow-down" viewBox="0 0 24 24">
+ <path d="M18.293 11.293l-5.293 5.293v-11.586c0-0.552-0.448-1-1-1s-1 0.448-1 1v11.586l-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414l7 7c0.092 0.092 0.202 0.166 0.324 0.217 0.245 0.101 0.521 0.101 0.766 0 0.118-0.049 0.228-0.121 0.324-0.217l7-7c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0z"></path>
+ </symbol>
+ <symbol id="icon-arrow-up" viewBox="0 0 24 24">
+ <path d="M5.707 12.707l5.293-5.293v11.586c0 0.552 0.448 1 1 1s1-0.448 1-1v-11.586l5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-7-7c-0.092-0.092-0.202-0.166-0.324-0.217s-0.253-0.076-0.383-0.076c-0.256 0-0.512 0.098-0.707 0.293l-7 7c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z"></path>
</symbol>
- <symbol id="icon-arrow-up" viewBox="0 0 26 28">
+ <symbol id="icon-arrow-up1" viewBox="0 0 26 28">
<path d="M25.172 15.172c0 0.531-0.219 1.031-0.578 1.406l-1.172 1.172c-0.375 0.375-0.891 0.594-1.422 0.594s-1.047-0.219-1.406-0.594l-4.594-4.578v11c0 1.125-0.938 1.828-2 1.828h-2c-1.062 0-2-0.703-2-1.828v-11l-4.594 4.578c-0.359 0.375-0.875 0.594-1.406 0.594s-1.047-0.219-1.406-0.594l-1.172-1.172c-0.375-0.375-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l10.172-10.172c0.359-0.375 0.875-0.578 1.406-0.578s1.047 0.203 1.422 0.578l10.172 10.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
</symbol>
+ <symbol id="icon-arrow-down1" viewBox="0 0 26 28">
+ <path d="M25.172 13c0 0.531-0.219 1.047-0.578 1.406l-10.172 10.187c-0.375 0.359-0.891 0.578-1.422 0.578s-1.047-0.219-1.406-0.578l-10.172-10.187c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l1.156-1.172c0.375-0.359 0.891-0.578 1.422-0.578s1.047 0.219 1.406 0.578l4.594 4.594v-11c0-1.094 0.906-2 2-2h2c1.094 0 2 0.906 2 2v11l4.594-4.594c0.359-0.359 0.875-0.578 1.406-0.578s1.047 0.219 1.422 0.578l1.172 1.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
+ </symbol>
<symbol id="icon-mail" viewBox="0 0 24 24">
<path d="M3 7.921l8.427 5.899c0.34 0.235 0.795 0.246 1.147 0l8.426-5.899v10.079c0 0.272-0.11 0.521-0.295 0.705s-0.433 0.295-0.705 0.295h-16c-0.272 0-0.521-0.11-0.705-0.295s-0.295-0.433-0.295-0.705zM1 5.983c0 0.010 0 0.020 0 0.030v11.987c0 0.828 0.34 1.579 0.88 2.12s1.292 0.88 2.12 0.88h16c0.828 0 1.579-0.34 2.12-0.88s0.88-1.292 0.88-2.12v-11.988c0-0.010 0-0.020 0-0.030-0.005-0.821-0.343-1.565-0.88-2.102-0.541-0.54-1.292-0.88-2.12-0.88h-16c-0.828 0-1.579 0.34-2.12 0.88-0.537 0.537-0.875 1.281-0.88 2.103zM20.894 5.554l-8.894 6.225-8.894-6.225c0.048-0.096 0.112-0.183 0.188-0.259 0.185-0.185 0.434-0.295 0.706-0.295h16c0.272 0 0.521 0.11 0.705 0.295 0.076 0.076 0.14 0.164 0.188 0.259z"></path>
</symbol>
);
}
- selects() {
+ viewRadios() {
return (
- <div className="mb-2">
- <select
- value={this.state.view}
- onChange={linkEvent(this, this.handleViewChange)}
- class="custom-select custom-select-sm w-auto"
+ <div class="btn-group btn-group-toggle">
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Overview && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={View.Overview}
+ checked={this.state.view == View.Overview}
+ onChange={linkEvent(this, this.handleViewChange)}
+ />
+ {i18n.t('overview')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Comments && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={View.Comments}
+ checked={this.state.view == View.Comments}
+ onChange={linkEvent(this, this.handleViewChange)}
+ />
+ {i18n.t('comments')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Posts && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={View.Posts}
+ checked={this.state.view == View.Posts}
+ onChange={linkEvent(this, this.handleViewChange)}
+ />
+ {i18n.t('posts')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Saved && 'active'}
+ `}
>
- <option disabled>{i18n.t('view')}</option>
- <option value={View.Overview}>{i18n.t('overview')}</option>
- <option value={View.Comments}>{i18n.t('comments')}</option>
- <option value={View.Posts}>{i18n.t('posts')}</option>
- <option value={View.Saved}>{i18n.t('saved')}</option>
- </select>
- <span class="ml-2">
- <SortSelect
- sort={this.state.sort}
- onChange={this.handleSortChange}
- hideHot
+ <input
+ type="radio"
+ value={View.Saved}
+ checked={this.state.view == View.Saved}
+ onChange={linkEvent(this, this.handleViewChange)}
/>
- </span>
+ {i18n.t('saved')}
+ </label>
+ </div>
+ );
+ }
+
+ selects() {
+ return (
+ <div className="mb-2">
+ <span class="mr-3">{this.viewRadios()}</span>
+ <SortSelect
+ sort={this.state.sort}
+ onChange={this.handleSortChange}
+ hideHot
+ />
<a
href={`/feeds/u/${this.state.username}.xml?sort=${
SortType[this.state.sort]
nodes={[{ comment: i.data as Comment }]}
admins={this.state.admins}
noIndent
+ showContext
/>
)}
</div>
nodes={commentsToFlatNodes(this.state.comments)}
admins={this.state.admins}
noIndent
+ showContext
/>
</div>
);
import 'moment/locale/fa';
import 'moment/locale/pt-br';
import 'moment/locale/ja';
+import 'moment/locale/ka';
import {
UserOperation,
{ code: 'eo', name: 'Esperanto' },
{ code: 'es', name: 'Español' },
{ code: 'de', name: 'Deutsch' },
+ { code: 'ka', name: 'ქართული ენა' },
{ code: 'fa', name: 'فارسی' },
{ code: 'ja', name: '日本語' },
{ code: 'pt_BR', name: 'Português Brasileiro' },
}
export function validEmail(email: string) {
- let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ let re = /^(([^\s"(),.:;<>@[\\\]]+(\.[^\s"(),.:;<>@[\\\]]+)*)|(".+"))@((\[(?:\d{1,3}\.){3}\d{1,3}])|(([\dA-Za-z\-]+\.)+[A-Za-z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
lang = 'pt-br';
} else if (lang.startsWith('ja')) {
lang = 'ja';
+ } else if (lang.startsWith('ka')) {
+ lang = 'ka';
} else {
lang = 'en';
}
}).showToast();
}
+export function messageToastify(
+ creator: string,
+ avatar: string,
+ body: string,
+ link: string,
+ router: any
+) {
+ let backgroundColor = `var(--light)`;
+
+ let toast = Toastify({
+ text: `${body}<br />${creator}`,
+ avatar: avatar,
+ backgroundColor: backgroundColor,
+ close: true,
+ gravity: 'top',
+ position: 'right',
+ duration: 0,
+ onClick: () => {
+ if (toast) {
+ toast.hideToast();
+ router.history.push(link);
+ }
+ },
+ }).showToast();
+}
+
export function setupTribute(): Tribute {
return new Tribute({
collection: [
-export const version: string = 'v0.6.39';
+export const version: string = 'v0.6.44';
"avatar": "Avatar",
"upload_avatar": "Upload Avatar",
"show_avatars": "Show Avatars",
+ "show_context": "Show context",
"formatting_help": "formatting help",
"sorting_help": "sorting help",
"view_source": "view source",
"upvote": "賛成票",
"downvote": "反対票",
"sorting_help": "並び順のヘルプ",
- "block_leaving": "このページから離れてもよろしいですか?"
+ "block_leaving": "このページから離れてもよろしいですか?",
+ "number_of_upvotes": "{{count}} 票の賛成",
+ "number_of_downvotes": "{{count}} 票の反対"
}
--- /dev/null
+{
+ "remove_post": "Usuń Post",
+ "no_posts": "Brak Postów.",
+ "create_a_post": "Stwórz post",
+ "create_post": "Stwórz Post",
+ "number_of_posts_0": "Post",
+ "number_of_posts_1": "Posty/ów",
+ "number_of_posts_2": "Posty/ów",
+ "posts": "Posty",
+ "related_posts": "Te posty mogą być powiązane",
+ "cross_posts": "Ten link został też zapostowany na:",
+ "comments": "Komentarze",
+ "number_of_comments_0": "Komentarz",
+ "number_of_comments_1": "Komentarzy/e",
+ "number_of_comments_2": "Komentarzy/e",
+ "post": "post",
+ "cross_post": "post zewnętrzny",
+ "cross_posted_to": "post wrzucony na zewnątrz: ",
+ "remove_comment": "Usuń Komentarz",
+ "communities": "Społeczności",
+ "users": "Użytkownicy",
+ "create_a_community": "Stwórz społeczność",
+ "create_community": "Stwórz Społeczność",
+ "remove_community": "Usuń Społeczność",
+ "subscribed_to_communities": "Subskrybowane <1>społeczności</1>",
+ "trending_communities": "Popularne <1>społeczności</1>",
+ "list_of_communities": "Lista społeczności",
+ "community_reqs": "małe litery, podkreślniki, bez spacji.",
+ "create_private_message": "Stwórz Prywatną Wiadomość",
+ "send_secure_message": "Wyślij Bezpieczną Wiadomość",
+ "send_message": "Wyślij Wiadomość",
+ "message": "Wiadomość",
+ "edit": "edytuj",
+ "reply": "odpowiedz",
+ "more": "więcej",
+ "cancel": "Anuluj",
+ "preview": "Podgląd",
+ "upload_image": "prześlij obraz",
+ "avatar": "Awatar",
+ "upload_avatar": "Prześlij Awatar",
+ "show_avatars": "Pokaż Awatary",
+ "formatting_help": "poradnik formatowania",
+ "lock": "zablokuj",
+ "messages": "Wiadomości",
+ "yes": "tak",
+ "number_of_communities_0": "Społeczność",
+ "number_of_communities_1": "Społeczności",
+ "number_of_communities_2": "Społeczności",
+ "sorting_help": "poradnik sortowania",
+ "view_source": "pokaż źródło",
+ "unlock": "odblokuj",
+ "sticky": "przyklej",
+ "unsticky": "odklej",
+ "link": "link",
+ "archive_link": "link archiwalny",
+ "mod": "moderator",
+ "mods": "moderatorzy",
+ "moderates": "Moderuje",
+ "settings": "Ustawienia",
+ "remove_as_mod": "zabierz uprawnienia moderatora",
+ "appoint_as_mod": "przyznaj uprawnienia moderatora",
+ "modlog": "Log moderatorski",
+ "admin": "administrator",
+ "admins": "administratorzy",
+ "remove_as_admin": "wycofaj uprawnienia administratora",
+ "appoint_as_admin": "przyznaj uprawnienia administratora",
+ "remove": "usuń",
+ "removed": "usunięte",
+ "locked": "zablokowane",
+ "stickied": "przyklejone",
+ "reason": "Powód",
+ "mark_as_read": "zaznacz jako przeczytane",
+ "mark_as_unread": "zaznacz jako nieprzeczytane",
+ "delete": "usuń",
+ "deleted": "usunięte",
+ "delete_account": "Usuń Konto",
+ "delete_account_confirm": "Ostrzeżenie: twoje dane zostaną bezpowrotnie usunięte. Wpisz swoje hasło aby potwierdzić.",
+ "restore": "przywróć",
+ "ban": "zbanuj",
+ "ban_from_site": "zbanuj ze strony",
+ "unban": "odbanuj",
+ "unban_from_site": "odbanuj ze strony",
+ "banned": "zbanowano",
+ "save": "zapisz",
+ "unsave": "cofnij zapis",
+ "create": "stwórz",
+ "creator": "autor",
+ "username": "Nazwa użytkownika",
+ "email_or_username": "Email lub Nazwa Użytkownika",
+ "number_of_users_0": "Użytkownik",
+ "number_of_users_1": "Użytkownicy/ków",
+ "number_of_users_2": "Użytkownicy/ków",
+ "number_of_subscribers_0": "Subskrybent",
+ "number_of_subscribers_1": "Subskrybenci/tów",
+ "number_of_subscribers_2": "Subskrybenci/tów",
+ "number_of_points_0": "Punkt",
+ "number_of_points_1": "Punkty/ów",
+ "number_of_points_2": "Punkty/ów",
+ "number_online_0": "Użytkownik Online",
+ "number_online_1": "Użytkowników Online",
+ "number_online_2": "Użytkowników Online",
+ "name": "Nazwa",
+ "title": "Tytuł",
+ "category": "Kategoria",
+ "subscribers": "Subskrybenci",
+ "both": "Obydwa",
+ "saved": "Zapisane",
+ "unsubscribe": "Odsubskrybuj",
+ "subscribe": "Subskrybuj",
+ "subscribed": "Zasubskrybowane",
+ "prev": "Wstecz",
+ "next": "Dalej",
+ "sidebar": "Pasek boczny",
+ "sort_type": "Sortuj typ",
+ "hot": "Popularne",
+ "new": "Nowe",
+ "old": "Stare",
+ "top_day": "Popularne dzisiaj",
+ "week": "Tydzień",
+ "month": "Miesiąc",
+ "year": "Rok",
+ "all": "Wszystko",
+ "top": "Popularne",
+ "api": "API",
+ "docs": "Dokumentacja",
+ "inbox": "Skrzynka odbiorcza",
+ "inbox_for": "Skrzynka odbiorcza <1>{{user}}</1>",
+ "mark_all_as_read": "zaznacz wszystko jako przeczytane",
+ "type": "Rodzaj",
+ "unread": "Nieprzeczytane",
+ "replies": "Odpowiedzi",
+ "mentions": "Wzmianki",
+ "reply_sent": "Odpowiedź wysłana",
+ "message_sent": "Wiadomość wysłana",
+ "search": "Szukaj",
+ "overview": "Podgląd",
+ "view": "Widok",
+ "logout": "Wyloguj",
+ "login_sign_up": "Zaloguj / Zarejestruj",
+ "login": "Zaloguj",
+ "sign_up": "Zarejestruj",
+ "notifications_error": "Powiadomienia na pulpicie są niedostępne w Twojej przeglądarce. Spróbuj przeglądarkę Firefox lub Chrome.",
+ "unread_messages": "Nieprzeczytane Wiadomości",
+ "password": "Hasło",
+ "verify_password": "Zweryfikuj Hasło",
+ "old_password": "Stare Hasło",
+ "forgot_password": "nie pamiętam hasła",
+ "reset_password_mail_sent": "Wysłano email w celu zresetowania hasła.",
+ "password_change": "Zmiana Hasła",
+ "new_password": "Nowe Hasło",
+ "no_email_setup": "Email nie został poprawnie ustawiony na tym serwerze.",
+ "email": "Email",
+ "matrix_user_id": "Użytkownik Matrixa",
+ "private_message_disclaimer": "Ostrzeżenie: Prywatne wiadomości w Lemmym nie są bezpieczne. Jeśli chcesz wysyłać i odbierać bezpieczne wiadomości załóż konto na <1>Riot.im</1>.",
+ "send_notifications_to_email": "Wysyłaj powiadomienia na Email",
+ "optional": "Opcjonalne",
+ "expires": "Wygasa",
+ "language": "Język",
+ "browser_default": "Domyślna wartość przeglądarki",
+ "downvotes_disabled": "Wdółgłosy wyłączone",
+ "enable_downvotes": "Włącz Wdółgłosy",
+ "upvote": "Wgóręgłos",
+ "number_of_upvotes_0": "Wgóręgłos",
+ "number_of_upvotes_1": "Wgóręgłosy/ów",
+ "number_of_upvotes_2": "Wgóręgłosy/ów",
+ "downvote": "Wdółgłos",
+ "number_of_downvotes_0": "Wdółgłos",
+ "number_of_downvotes_1": "Wdółgłosy/ów",
+ "number_of_downvotes_2": "Wdółgłosy/ów",
+ "open_registration": "Rejestracja Otwarta",
+ "registration_closed": "Rejestracja Zamknięta",
+ "enable_nsfw": "Włącz NSFW",
+ "url": "URL",
+ "body": "Treść",
+ "copy_suggested_title": "skopiuj sugerowany tytuł: {{title}}",
+ "community": "Społeczność",
+ "expand_here": "Rozwiń tutaj",
+ "subscribe_to_communities": "Zasubskrybuj kilka <1>społeczności</1>.",
+ "chat": "Czat",
+ "recent_comments": "Najnowsze Komentarze",
+ "no_results": "Brak wyników.",
+ "setup": "Instalacja",
+ "lemmy_instance_setup": "Instalacja Instancji Lemmy",
+ "setup_admin": "Ustaw Administratora Strony",
+ "your_site": "twoja witryna",
+ "modified": "zmodyfikowane",
+ "nsfw": "NSFW",
+ "show_nsfw": "Pokaż treści NSFW (+18)",
+ "theme": "Motyw",
+ "sponsors": "Sponsorzy",
+ "sponsors_of_lemmy": "Sponsorzy projektu Lemmy",
+ "sponsor_message": "Lemmy jest wolnym, <1>otwartoźródłowym</1> oprogramowaniem, co oznacza zero reklam, opłat, czy innych form kapitalizacji, od zawsze na zawsze. Twoje darowizny idą bezpośrednio na rozwój projektu w pełno-etatowym wymiarze. Specjalne wyrazy podziękowania dla następujących osób:",
+ "support_on_patreon": "Wspieraj w serwisie Patreon",
+ "support_on_liberapay": "Wspieraj na Liberapay",
+ "donate_to_lemmy": "Przekaż datek na Lemmiego",
+ "donate": "Przekaż datek",
+ "general_sponsors": "Główni Sponsorzy to osoby które wsparły Lemmiego kwotą od $10 do $39.",
+ "crypto": "Kryptowaluta",
+ "bitcoin": "Bitcoin",
+ "ethereum": "Ethereum",
+ "monero": "Monero",
+ "code": "Kod",
+ "joined": "Dołączono",
+ "by": "przez",
+ "to": "do",
+ "from": "od",
+ "transfer_community": "transfer społeczności",
+ "transfer_site": "transfer witryny",
+ "are_you_sure": "na pewno?",
+ "no": "nie",
+ "powered_by": "Powered by",
+ "landing": "Lemmy jest <1>agregatorem linków</1> / alternatywą dla reddita. Jest przeznaczony do działania w ramach cyfrowej przestrzeni nazywanej <2>fediverse<2>. <3></3>Opiera się na samodzielnym hostingu, posiada aktualizowane na żywo wątki z komentarzami, i zajmuje bardzo mało miejsce (<4>~80kB</4>). Federacja w ramach sieci ActivityPub jest w planach. <5></5>Ta wersja jest <6>bardzo wczesną wersją beta</6>, co oznacza, że wiele funkcji nadal nie działa tak jak powinny. <7></7><8>Pod tym adresem</8> można sugerować nową funkcjonalność i zgłaszać błędy.<9></9>Stworzono z wykorzystaniem <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
+ "not_logged_in": "Nie jesteś zalogowana/y.",
+ "logged_in": "Zalogowano.",
+ "community_ban": "Zostałaś/eś zbanowana/y z tej społeczności.",
+ "site_ban": "Zostałaś/eś zbanowana/y z tej witryny",
+ "couldnt_create_comment": "Nie udało się stworzyć komentarza.",
+ "couldnt_like_comment": "Polubienie komentarza nie powiodło się.",
+ "couldnt_update_comment": "Zaktualizowanie komentarza nie powiodło się.",
+ "couldnt_save_comment": "Zapisanie komentarza nie powiodło się.",
+ "couldnt_get_comments": "Pobranie komentarzy nie powiodło się.",
+ "no_comment_edit_allowed": "Nie masz uprawnień do edycji komentarza.",
+ "no_post_edit_allowed": "Nie masz uprawnień do edycji posta.",
+ "no_community_edit_allowed": "Nie masz uprawnień do edycji społeczności.",
+ "couldnt_find_community": "Nie udało się znaleźć społeczności.",
+ "couldnt_update_community": "Nie udało się zaktualizować Społeczności.",
+ "community_already_exists": "Społeczność już istnieje.",
+ "community_moderator_already_exists": "Moderator społeczności już istnieje.",
+ "community_follower_already_exists": "Osoba obserwująca społeczność już istnieje.",
+ "community_user_already_banned": "Użytkownik społeczności jest już zbanowany.",
+ "couldnt_create_post": "Nie udało się stworzyć posta.",
+ "post_title_too_long": "Tytuł posta zbyt długi.",
+ "couldnt_like_post": "Nie udało się polubić posta.",
+ "couldnt_find_post": "Nie udało się znaleźć posta.",
+ "couldnt_update_post": "Nie udało się zaktualizować postów",
+ "couldnt_get_posts": "Nie udało się pobrać postów",
+ "couldnt_save_post": "Nie udało się zapisać posta.",
+ "no_slurs": "Bez obelg.",
+ "not_an_admin": "Nie jest administratorem.",
+ "site_already_exists": "Witryna już istnieje.",
+ "couldnt_update_site": "Nie udało się zaktualizować witryny.",
+ "couldnt_find_that_username_or_email": "Nie udało się znaleźć takiej nazwy użytkownika lub adresu email.",
+ "password_incorrect": "Hasło niepoprawne.",
+ "passwords_dont_match": "Hasła nie pasują do siebie.",
+ "admin_already_created": "Wybacz, funkcja administratora jest już przypisana.",
+ "user_already_exists": "Użytkownik już istnieje.",
+ "email_already_exists": "Email już istnieje.",
+ "couldnt_update_user": "Nie udało się zaktualizować użytkownika.",
+ "system_err_login": "Błąd systemu. Spróbuj wylogować się i następnie zalogować ponownie.",
+ "couldnt_create_private_message": "Nie udało się stworzyć prywatnej wiadomości.",
+ "no_private_message_edit_allowed": "Brak uprawnień do edycji prywatnej wiadomości.",
+ "couldnt_update_private_message": "Nie udało się zaktualizować prywatnej wiadomości.",
+ "time": "Czas",
+ "action": "Akcja",
+ "block_leaving": "Czy na pewno chcesz wyjść?",
+ "show_context": "Pokaż kontekst"
+}
"upvote": "Voto positivo",
"downvote": "Voto negativo",
"block_leaving": "Tem certeza que quer sair?",
- "sorting_help": "ajuda sobre ordenação"
+ "sorting_help": "ajuda sobre ordenação",
+ "number_of_upvotes": "{{count}} voto positivo",
+ "number_of_upvotes_plural": "{{count}} votos positivos",
+ "number_of_downvotes": "{{count}} voto negativo",
+ "number_of_downvotes_plural": "{{count}} votos negativos",
+ "show_context": "Mostrar contexto"
}
"no_posts": "Нет записей.",
"create_a_post": "Создать запись",
"create_post": "Создать запись",
- "number_of_posts": "{{count}} записей",
+ "number_of_posts_0": "{{count}} запись",
+ "number_of_posts_1": "{{count}} записи",
+ "number_of_posts_2": "{{count}} записей",
"posts": "Записи",
"related_posts": "Эти записи могут быть связаны",
"comments": "Комментарии",
- "number_of_comments": "{{count}} комментариев",
+ "number_of_comments_0": "{{count}} комментарий",
+ "number_of_comments_1": "{{count}} комментария",
+ "number_of_comments_2": "{{count}} комментариев",
"remove_comment": "Удалить комментарий",
"communities": "Сообщества",
"users": "Пользователи",
"sticky": "",
"stickied": "закрепленный пост",
"delete_account": "Удалить аккаунт",
- "delete_account_confirm": "Предупреждение: это действите полностью уничтожит все данные вашего аккаунта. Введите свой пароль для подтверждения.",
+ "delete_account_confirm": "Предупреждение: это действие полностью уничтожит все данные вашего аккаунта. Введите свой пароль для подтверждения.",
"docs": "Документация",
"replies": "Ответы",
"mentions": "Упоминания",
"message_sent": "Сообщение отправлено",
"old_password": "Действующий пароль",
"forgot_password": "я забыл(а) пароль",
- "reset_password_mail_sent": "Ð\98мейл длÑ\8f воÑ\81Ñ\81Ñ\82ановлениÑ\8f паÑ\80олÑ\8f бÑ\8bл вÑ\8bÑ\81лан.",
+ "reset_password_mail_sent": "Ð\9fиÑ\81Ñ\8cмо длÑ\8f воÑ\81Ñ\81Ñ\82ановлениÑ\8f паÑ\80олÑ\8f бÑ\8bло вÑ\8bÑ\81лано.",
"private_message_disclaimer": "Предупреждение: Приватные сообщения Lemmy на данный момент не зашифрованы. Для безопасной коммуникации создайте аккаунт на <1>Riot.im</1>.",
"send_notifications_to_email": "Посылать уведомления на e-mail адрес",
"language": "Язык",
"theme": "Визуальная тема",
"post_title_too_long": "Длина названия поста превышает допустимый лимит.",
"time": "Время",
- "action": "Действие"
+ "action": "Действие",
+ "view_source": "исходный код сообщения",
+ "more": "больше",
+ "sorting_help": "справка по сортировке",
+ "by": "от",
+ "number_of_communities_0": "{{count}} сообщество",
+ "number_of_communities_1": "{{count}} сообщества",
+ "number_of_communities_2": "{{count}} сообществ",
+ "creator": "автор",
+ "old": "Старое",
+ "to": "в"
}
dependencies:
"@babel/highlight" "^7.8.3"
-"@babel/generator@^7.8.4":
- version "7.8.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e"
- integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==
+"@babel/generator@^7.8.6":
+ version "7.8.8"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.8.tgz#cdcd58caab730834cee9eeadb729e833b625da3e"
+ integrity sha512-HKyUVu69cZoclptr8t8U5b6sx6zoWjh8jiUhnuj3MpZuKT2dJ8zPTuiy31luq32swhI0SpwItCIlU8XW7BZeJg==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.8.7"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.5.0"
esutils "^2.0.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.0.0", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4":
+"@babel/parser@^7.7.0", "@babel/parser@^7.8.6":
+ version "7.8.8"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.8.tgz#4c3b7ce36db37e0629be1f0d50a571d2f86f6cd4"
+ integrity sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA==
+
+"@babel/parser@^7.8.3":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8"
integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.2"
+"@babel/runtime-corejs3@^7.8.3":
+ version "7.8.7"
+ resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz#8209d9dff2f33aa2616cb319c83fe159ffb07b8c"
+ integrity sha512-sc7A+H4I8kTd7S61dgB9RomXu/C+F4IrRr4Ytze4dnfx7AXEpCrejSNpjx7vq6y/Bak9S6Kbk65a/WgMLtg43Q==
+ dependencies:
+ core-js-pure "^3.0.0"
+ regenerator-runtime "^0.13.4"
+
"@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308"
"@babel/parser" "^7.8.3"
"@babel/types" "^7.8.3"
-"@babel/traverse@^7.0.0":
- version "7.8.4"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c"
- integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==
+"@babel/traverse@^7.7.0":
+ version "7.8.6"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff"
+ integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==
dependencies:
"@babel/code-frame" "^7.8.3"
- "@babel/generator" "^7.8.4"
+ "@babel/generator" "^7.8.6"
"@babel/helper-function-name" "^7.8.3"
"@babel/helper-split-export-declaration" "^7.8.3"
- "@babel/parser" "^7.8.4"
- "@babel/types" "^7.8.3"
+ "@babel/parser" "^7.8.6"
+ "@babel/types" "^7.8.6"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.13"
-"@babel/types@^7.0.0", "@babel/types@^7.8.3":
+"@babel/types@^7.7.0", "@babel/types@^7.8.6", "@babel/types@^7.8.7":
+ version "7.8.7"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d"
+ integrity sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==
+ dependencies:
+ esutils "^2.0.2"
+ lodash "^4.17.13"
+ to-fast-properties "^2.0.0"
+
+"@babel/types@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
lodash "^4.17.13"
to-fast-properties "^2.0.0"
-"@popperjs/core@^2.0.6":
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.0.6.tgz#5a39ac118811ca844155b0ad5190b8c24f35e533"
- integrity sha512-zj7Gw8QC4jmR92eKUvtrZUEpl2ypRbq+qlE4pwf9n2hnUO9BOAcWUs4/Ht+gNIbFt98xtqhLvccdCfD469MzpQ==
+"@popperjs/core@^2.1.1":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.1.1.tgz#12c572ab88ef7345b43f21883fca26631c223085"
+ integrity sha512-sLqWxCzC5/QHLhziXSCAksBxHfOnQlhPRVgPK0egEw+ktWvG75T2k+aYWVjVh9+WKeT3tlG3ZNbZQvZLmfuOIw==
"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0"
dependencies:
"@types/sizzle" "*"
-"@types/js-cookie@^2.2.1":
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.4.tgz#f79720b4755aa197c2e15e982e2f438f5748e348"
- integrity sha512-WTfSE1Eauak/Nrg6cA9FgPTFvVawejsai6zXoq0QYTQ3mxONeRtGhKxa7wMlUzWWmzrmTeV+rwLjHgsCntdrsA==
+"@types/js-cookie@^2.2.5":
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.5.tgz#38dfaacae8623b37cc0b0d27398e574e3fc28b1e"
+ integrity sha512-cpmwBRcHJmmZx0OGU7aPVwGWGbs4iKwVYchk9iuMtxNCA2zorwdaTz4GkLgs2WGxiRZRFKnV1k6tRUHX7tBMxg==
"@types/json-schema@^7.0.3":
version "7.0.4"
dependencies:
"@types/linkify-it" "*"
-"@types/node@^13.7.0":
- version "13.7.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4"
- integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==
+"@types/node@^13.9.2":
+ version "13.9.2"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.2.tgz#ace1880c03594cc3e80206d96847157d8e7fa349"
+ integrity sha512-bnoqK579sAYrQbp73wwglccjJ4sfRdKU7WNEZ5FW4K2U6Kc0/eZ5kvXG0JKsEKFB50zrFmfFt52/cvBbZa7eXg==
"@types/normalize-package-data@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
-"@typescript-eslint/eslint-plugin@2.18.0":
- version "2.18.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.18.0.tgz#f8cf272dfb057ecf1ea000fea1e0b3f06a32f9cb"
- integrity sha512-kuO8WQjV+RCZvAXVRJfXWiJ8iYEtfHlKgcqqqXg9uUkIolEHuUaMmm8/lcO4xwCOtaw6mY0gStn2Lg4/eUXXYQ==
+"@typescript-eslint/eslint-plugin@2.24.0":
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.24.0.tgz#a86cf618c965a462cddf3601f594544b134d6d68"
+ integrity sha512-wJRBeaMeT7RLQ27UQkDFOu25MqFOBus8PtOa9KaT5ZuxC1kAsd7JEHqWt4YXuY9eancX0GK9C68i5OROnlIzBA==
dependencies:
- "@typescript-eslint/experimental-utils" "2.18.0"
+ "@typescript-eslint/experimental-utils" "2.24.0"
eslint-utils "^1.4.3"
functional-red-black-tree "^1.0.1"
regexpp "^3.0.0"
tsutils "^3.17.1"
-"@typescript-eslint/experimental-utils@2.18.0", "@typescript-eslint/experimental-utils@^2.5.0":
+"@typescript-eslint/experimental-utils@2.24.0":
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.24.0.tgz#a5cb2ed89fedf8b59638dc83484eb0c8c35e1143"
+ integrity sha512-DXrwuXTdVh3ycNCMYmWhUzn/gfqu9N0VzNnahjiDJvcyhfBy4gb59ncVZVxdp5XzBC77dCncu0daQgOkbvPwBw==
+ dependencies:
+ "@types/json-schema" "^7.0.3"
+ "@typescript-eslint/typescript-estree" "2.24.0"
+ eslint-scope "^5.0.0"
+
+"@typescript-eslint/experimental-utils@^2.5.0":
version "2.18.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.18.0.tgz#e4eab839082030282496c1439bbf9fdf2a4f3da8"
integrity sha512-J6MopKPHuJYmQUkANLip7g9I82ZLe1naCbxZZW3O2sIxTiq/9YYoOELEKY7oPg0hJ0V/AQ225h2z0Yp+RRMXhw==
"@typescript-eslint/typescript-estree" "2.18.0"
eslint-scope "^5.0.0"
-"@typescript-eslint/parser@2.18.0":
- version "2.18.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.18.0.tgz#d5f7fc1839abd4a985394e40e9d2454bd56aeb1f"
- integrity sha512-SJJPxFMEYEWkM6pGfcnjLU+NJIPo+Ko1QrCBL+i0+zV30ggLD90huEmMMhKLHBpESWy9lVEeWlQibweNQzyc+A==
+"@typescript-eslint/parser@2.24.0":
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.24.0.tgz#2cf0eae6e6dd44d162486ad949c126b887f11eb8"
+ integrity sha512-H2Y7uacwSSg8IbVxdYExSI3T7uM1DzmOn2COGtCahCC3g8YtM1xYAPi2MAHyfPs61VKxP/J/UiSctcRgw4G8aw==
dependencies:
"@types/eslint-visitor-keys" "^1.0.0"
- "@typescript-eslint/experimental-utils" "2.18.0"
- "@typescript-eslint/typescript-estree" "2.18.0"
+ "@typescript-eslint/experimental-utils" "2.24.0"
+ "@typescript-eslint/typescript-estree" "2.24.0"
eslint-visitor-keys "^1.1.0"
"@typescript-eslint/typescript-estree@2.18.0":
semver "^6.3.0"
tsutils "^3.17.1"
+"@typescript-eslint/typescript-estree@2.24.0":
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.24.0.tgz#38bbc8bb479790d2f324797ffbcdb346d897c62a"
+ integrity sha512-RJ0yMe5owMSix55qX7Mi9V6z2FDuuDpN6eR5fzRJrp+8in9UF41IGNQHbg5aMK4/PjVaEQksLvz0IA8n+Mr/FA==
+ dependencies:
+ debug "^4.1.1"
+ eslint-visitor-keys "^1.1.0"
+ glob "^7.1.6"
+ is-glob "^4.0.1"
+ lodash "^4.17.15"
+ semver "^6.3.0"
+ tsutils "^3.17.1"
+
accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
"@babel/runtime" "^7.7.4"
"@babel/runtime-corejs3" "^7.7.4"
-babel-eslint@10.0.3:
- version "10.0.3"
- resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a"
- integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==
+babel-eslint@10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
+ integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/parser" "^7.0.0"
- "@babel/traverse" "^7.0.0"
- "@babel/types" "^7.0.0"
+ "@babel/parser" "^7.7.0"
+ "@babel/traverse" "^7.7.0"
+ "@babel/types" "^7.7.0"
eslint-visitor-keys "^1.0.0"
resolve "^1.12.0"
eslint-utils "^2.0.0"
regexpp "^3.0.0"
-eslint-plugin-import@2.20.0:
- version "2.20.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa"
- integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==
+eslint-plugin-import@2.20.1:
+ version "2.20.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3"
+ integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==
dependencies:
array-includes "^3.0.3"
array.prototype.flat "^1.2.1"
object.values "^1.1.0"
resolve "^1.12.0"
-eslint-plugin-jane@^7.0.2:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jane/-/eslint-plugin-jane-7.1.0.tgz#ee087405329e6bc9bfe9316fc5881c1d4e27bc71"
- integrity sha512-ScsxkkeTUnGYKLaiIk5zz/x7ZkDh7+rTj94daZboNmkJejdYka0sLFpfvDGm/7B8ImKacKdjRatQD0HjxlaPzA==
+eslint-plugin-jane@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jane/-/eslint-plugin-jane-7.2.0.tgz#a2454a6700c644e6c86821ca294adf303e75eddc"
+ integrity sha512-/BPZrfxWX9T45gJSf4/2GHfBYgsBYTW7StAQfxL8PxWABZIQKWPWy/5ZokX7UaJlgKHAoC42rJHCQLK5hmfJNA==
dependencies:
- "@typescript-eslint/eslint-plugin" "2.18.0"
- "@typescript-eslint/parser" "2.18.0"
- babel-eslint "10.0.3"
+ "@typescript-eslint/eslint-plugin" "2.24.0"
+ "@typescript-eslint/parser" "2.24.0"
+ babel-eslint "10.1.0"
eslint-config-prettier "6.10.0"
eslint-plugin-babel "5.3.0"
- eslint-plugin-import "2.20.0"
- eslint-plugin-jest "23.6.0"
+ eslint-plugin-import "2.20.1"
+ eslint-plugin-jest "23.8.2"
eslint-plugin-jsx-a11y "6.2.3"
eslint-plugin-node "11.0.0"
eslint-plugin-prettier "3.1.2"
eslint-plugin-promise "4.2.1"
- eslint-plugin-react "7.18.0"
- eslint-plugin-react-hooks "2.3.0"
- eslint-plugin-unicorn "15.0.1"
+ eslint-plugin-react "7.19.0"
+ eslint-plugin-react-hooks "2.5.0"
+ eslint-plugin-unicorn "17.2.0"
-eslint-plugin-jest@23.6.0:
- version "23.6.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.6.0.tgz#508b32f80d44058c8c01257c0ee718cfbd521e9d"
- integrity sha512-GH8AhcFXspOLqak7fqnddLXEJsrFyvgO8Bm60SexvKSn1+3rWYESnCiWUOCUcBTprNSDSE4CtAZdM4EyV6gPPw==
+eslint-plugin-jest@23.8.2:
+ version "23.8.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz#6f28b41c67ef635f803ebd9e168f6b73858eb8d4"
+ integrity sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==
dependencies:
"@typescript-eslint/experimental-utils" "^2.5.0"
- micromatch "^4.0.2"
eslint-plugin-jsx-a11y@6.2.3:
version "6.2.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
-eslint-plugin-react-hooks@2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.3.0.tgz#53e073961f1f5ccf8dd19558036c1fac8c29d99a"
- integrity sha512-gLKCa52G4ee7uXzdLiorca7JIQZPPXRAQDXV83J4bUEeUuc5pIEyZYAZ45Xnxe5IuupxEqHS+hUhSLIimK1EMw==
+eslint-plugin-react-hooks@2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.0.tgz#c50ab7ca5945ce6d1cf8248d9e185c80b54171b6"
+ integrity sha512-bzvdX47Jx847bgAYf0FPX3u1oxU+mKU8tqrpj4UX9A96SbAmj/HVEefEy6rJUog5u8QIlOPTKZcBpGn5kkKfAQ==
-eslint-plugin-react@7.18.0:
- version "7.18.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz#2317831284d005b30aff8afb7c4e906f13fa8e7e"
- integrity sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ==
+eslint-plugin-react@7.19.0:
+ version "7.19.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666"
+ integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==
dependencies:
array-includes "^3.1.1"
doctrine "^2.1.0"
object.fromentries "^2.0.2"
object.values "^1.1.1"
prop-types "^15.7.2"
- resolve "^1.14.2"
+ resolve "^1.15.1"
+ semver "^6.3.0"
+ string.prototype.matchall "^4.0.2"
+ xregexp "^4.3.0"
-eslint-plugin-unicorn@15.0.1:
- version "15.0.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-15.0.1.tgz#8379d1d6882f9f8631bec8025ac9e8fe89e43945"
- integrity sha512-yahqrPGFUzwH5cnmnj+iPlgPapAiBIZ/ZNSDkhTVPgPCo7/mOEjJ2gDhEclrtQVBE9olmec4N+CKDnJuZ9XpRA==
+eslint-plugin-unicorn@17.2.0:
+ version "17.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-17.2.0.tgz#8f147ba24d417dc5de948c7df7d006108a37a540"
+ integrity sha512-0kYjrywf0kQxevFz571KrDfYMIRZ5Kq6dDgPU1EEBFeC181r+fAaPatBScWX+/hisKJ4+eCRFebxTeVylsSYmw==
dependencies:
ci-info "^2.0.0"
clean-regexp "^1.0.0"
eslint-ast-utils "^1.1.0"
eslint-template-visitor "^1.1.0"
import-modules "^2.0.0"
- lodash.camelcase "^4.3.0"
- lodash.defaultsdeep "^4.6.1"
- lodash.kebabcase "^4.1.1"
- lodash.snakecase "^4.1.1"
- lodash.upperfirst "^4.3.1"
+ lodash "^4.17.15"
read-pkg-up "^7.0.1"
- regexp-tree "^0.1.17"
- regexpp "^3.0.0"
+ regexp-tree "^0.1.20"
reserved-words "^0.1.2"
safe-regex "^2.1.1"
- semver "^6.3.0"
+ semver "^7.1.2"
eslint-rule-composer@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
-husky@^4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.1.tgz#b09f1bd9129e6c323cc515dc17081d0615e2d7c1"
- integrity sha512-Qa0lRreeIf4Tl92sSs42ER6qc3hzoyQPPorzOrFWfPEVbdi6LuvJEqWKPk905fOWIR76iBpp7ECZNIwk+a8xuQ==
+husky@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.3.tgz#3b18d2ee5febe99e27f2983500202daffbc3151e"
+ integrity sha512-VxTsSTRwYveKXN4SaH1/FefRJYCtx+wx04sSVcOpD7N2zjoHxa+cEJ07Qg5NmV3HAK+IRKOyNVpi2YBIVccIfQ==
dependencies:
chalk "^3.0.0"
ci-info "^2.0.0"
slash "^3.0.0"
which-pm-runs "^1.0.0"
-i18next@^19.0.3:
- version "19.1.0"
- resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.1.0.tgz#fe1a1da3d208872946307c7d2d115da45d46159f"
- integrity sha512-ISbmukX4L6Dz0QoH9+EW1AnBw7j+NRLoMu9uLPMaNSSTP9Eie9/oUL0dOyWX15baB3gYOpkHJpGZRHOqcnl0ew==
+i18next@^19.3.3:
+ version "19.3.3"
+ resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.3.3.tgz#04bd79b315e5fe2c87ab8f411e5d55eda0a17bd8"
+ integrity sha512-CnuPqep5/JsltkGvQqzYN4d79eCe0TreCBRF3a8qHHi8x4SON1qqZ/pvR2X7BfNkNqpA5HXIqw0E731H+VsgSg==
dependencies:
"@babel/runtime" "^7.3.1"
strip-ansi "^5.1.0"
through "^2.3.6"
+internal-slot@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3"
+ integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==
+ dependencies:
+ es-abstract "^1.17.0-next.1"
+ has "^1.0.3"
+ side-channel "^1.0.2"
+
ipaddr.js@1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
dependencies:
uc.micro "^1.0.1"
-lint-staged@^10.0.2:
- version "10.0.7"
- resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.0.7.tgz#d205f92d9359419a23bc6aa3b6f8546b1998da64"
- integrity sha512-Byj0F4l7GYUpYYHEqyFH69NiI6ICTg0CeCKbhRorL+ickbzILKUlZLiyCkljZV02wnoh7yH7PmFyYm9PRNwk9g==
+lint-staged@^10.0.8:
+ version "10.0.8"
+ resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.0.8.tgz#0f7849cdc336061f25f5d4fcbcfa385701ff4739"
+ integrity sha512-Oa9eS4DJqvQMVdywXfEor6F4vP+21fPHF8LUXgBbVWUSWBddjqsvO6Bv1LwMChmgQZZqwUvgJSHlu8HFHAPZmA==
dependencies:
chalk "^3.0.0"
commander "^4.0.1"
dependencies:
p-locate "^4.1.0"
-lodash.camelcase@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
- integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
-
-lodash.defaultsdeep@^4.6.1:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
- integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==
-
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
-lodash.kebabcase@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
- integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
-
-lodash.snakecase@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
- integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40=
-
-lodash.upperfirst@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce"
- integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=
-
lodash.zip@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
+regenerator-runtime@^0.13.4:
+ version "0.13.5"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
+ integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+
regex-cache@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
-regexp-tree@^0.1.17, regexp-tree@~0.1.1:
+regexp-tree@^0.1.20:
+ version "0.1.21"
+ resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.21.tgz#55e2246b7f7d36f1b461490942fa780299c400d7"
+ integrity sha512-kUUXjX4AnqnR8KRTCrayAo9PzYMRKmVoGgaz2tBuz0MF3g1ZbGebmtW0yFHfFK9CmBjQKeYIgoL22pFLBJY7sw==
+
+regexp-tree@~0.1.1:
version "0.1.18"
resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.18.tgz#ed4819a9f03ec2de9613421d6eaf47512e7fdaf1"
integrity sha512-mKLUfTDU1GE5jGR7cn2IEPDzYjmOviZOHYAR1XGe8Lg48Mdk684waD1Fqhv2Nef+TsDVdmIj08m/GUKTMk7J2Q==
+regexp.prototype.flags@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
+ integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+
regexpp@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2:
+resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1:
version "1.15.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
dependencies:
path-parse "^1.0.6"
+resolve@^1.15.1:
+ version "1.15.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8"
+ integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==
+ dependencies:
+ path-parse "^1.0.6"
+
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+semver@^7.1.2:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
+ integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
+
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
resolved "https://registry.yarnpkg.com/shorthash/-/shorthash-0.0.2.tgz#59b268eecbde59038b30da202bcfbddeb2c4a4eb"
integrity sha1-WbJo7sveWQOLMNogK8+93rLEpOs=
+side-channel@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
+ integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==
+ dependencies:
+ es-abstract "^1.17.0-next.1"
+ object-inspect "^1.7.0"
+
signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
source-map-resolve "^0.5.0"
use "^3.1.0"
-sortpack@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/sortpack/-/sortpack-2.1.1.tgz#e94280616a517851257728721dd6749619aca309"
- integrity sha512-/jtQAzl9JeTXZxzznW6L729M+Q7uv9k9Dm89eF0UxMj4Rna3CmO0IYT0MUS6aLyHUOTnwpT7kIDs4PQmMTEhLw==
+sortpack@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/sortpack/-/sortpack-2.1.2.tgz#25bf86f2923c81f43a00a2166ff4d271fafeed11"
+ integrity sha512-43fSND1vmAdyfgC38aOkVxZBV331f4blF8acjwQmx7Gba4nuL2ene/Cq5eixNmDhKA/qQHnvSeAl+jEWb31rfg==
source-map-resolve@^0.5.0:
version "0.5.3"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
+string.prototype.matchall@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e"
+ integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0"
+ has-symbols "^1.0.1"
+ internal-slot "^1.0.2"
+ regexp.prototype.flags "^1.3.0"
+ side-channel "^1.0.2"
+
string.prototype.trimleft@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74"
slice-ansi "^2.1.0"
string-width "^3.0.0"
-terser@^4.6.3:
- version "4.6.3"
- resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87"
- integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==
+terser@^4.6.7:
+ version "4.6.7"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.7.tgz#478d7f9394ec1907f0e488c5f6a6a9a2bad55e72"
+ integrity sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
-tippy.js@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.0.0.tgz#6bc4f477ea82ef344db51ae34f106a8b25f2d02c"
- integrity sha512-2NVc5A8cnO9N/Fk+tTU6KEm6m8ZXT1u3pOY756zZ5BE38rWDl/hVyoWhTfM79HW1nEJSpn/VujqAMMZGHsE9qQ==
+tippy.js@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.1.0.tgz#9c58b94f92f3044d5e861b9d83da3c2a6d3d4323"
+ integrity sha512-cRFydlVZlvo4soQSUfVNbH2K77zDUhDAzaAjxseyn81gGIa+j72y98yDL2yB0n8gas/E+Zlr1iOyR5ckslUFqA==
dependencies:
- "@popperjs/core" "^2.0.6"
+ "@popperjs/core" "^2.1.1"
tmp@^0.0.33:
version "0.0.33"
regex-not "^1.0.2"
safe-regex "^1.1.0"
-toastify-js@^1.6.2:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/toastify-js/-/toastify-js-1.6.2.tgz#38af35625797d3d3f51fa09851f0bda449271423"
- integrity sha512-ECQzgjTjxaElfwp/8e8qoIYx7U5rU2G54e5aiPMv+UtmGOYEitrtNp/Kr8uMgntnQNrDZEQJNGjBtoNnEgR5EA==
+toastify-js@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/toastify-js/-/toastify-js-1.7.0.tgz#d6b44937ae2844a19c25fcc69ee5933165dbf666"
+ integrity sha512-GmPy4zJ/ulCfmCHlfCtgcB+K2xhx2AXW3T/ZZOSjyjaIGevhz+uvR8HSCTay/wBq4tt2mUnBqlObP1sSWGlsnQ==
toidentifier@1.0.0:
version "1.0.0"
psl "^1.1.24"
punycode "^1.4.1"
-tributejs@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-5.0.0.tgz#2c5301a79c19d7a72d23e995bf7c9f47c2a34f23"
- integrity sha512-aPUpq4+NTXRq1OcdoeiFg9d+wM+J0b7dpL7MNVxqo8JIgChtkx8HnsPVl/uZ4Z1ChTF9UI1ffbvTfJRHqJjjAw==
+tributejs@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-5.1.2.tgz#d8492d974d3098d6016248d689fb063cda6e77f7"
+ integrity sha512-R9ff/q6w4T5f3Y9+RL+qinog3X1eAj1UnR/yfZaGJ8D3wuJs4/vicrGYul9+fgS9EJ/iYgwARekTb92xwark0g==
-ts-node@^8.6.2:
- version "8.6.2"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35"
- integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==
+ts-node@^8.7.0:
+ version "8.7.0"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.7.0.tgz#266186947596bef9f3a034687595b30e31b20976"
+ integrity sha512-s659CsHrsxaRVDEleuOkGvbsA0rWHtszUNEt1r0CgAFN5ZZTQtDzpsluS7W5pOGJIa1xZE8R/zK4dEs+ldFezg==
dependencies:
arg "^4.1.0"
diff "^4.0.1"
options ">=0.0.5"
ultron "1.0.x"
-ws@^7.0.0:
- version "7.2.1"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
- integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
+ws@^7.2.3:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"
+ integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==
+
+xregexp@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50"
+ integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==
+ dependencies:
+ "@babel/runtime-corejs3" "^7.8.3"
yaml@^1.7.2:
version "1.7.2"