ui/node_modules
ui/dist
server/target
+docs
.git
--- /dev/null
+* linguist-vendored
+*.rs linguist-vendored=false
--- /dev/null
+# These are supported funding model platforms
+
+patreon: dessalines
--- /dev/null
+ansible/inventory
+ansible/passwords/
-<h1><img src="https://image.flaticon.com/icons/svg/194/194242.svg" width="50px" height="50px" /> Lemmy</h1>
+<h1><img src="ui/assets/favicon.svg" width="50px" height="50px" style="vertical-align:bottom" /><span>Lemmy</span></h1>
+[![Github](https://img.shields.io/badge/-Github-blue)](https://github.com/dessalines/lemmy)
+[![Gitlab](https://img.shields.io/badge/-Gitlab-yellowgreen)](https://gitlab.com/dessalines/lemmy)
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/dessalines/lemmy.svg)
[![Build Status](https://travis-ci.org/dessalines/lemmy.svg?branch=master)](https://travis-ci.org/dessalines/lemmy)
-![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/dessalines/lemmy.svg)
[![star this repo](http://githubbadges.com/star.svg?user=dessalines&repo=lemmy&style=flat)](https://github.com/dessalines/lemmy)
[![fork this repo](http://githubbadges.com/fork.svg?user=dessalines&repo=lemmy&style=flat)](https://github.com/dessalines/lemmy/fork)
-![Docker Pulls](https://img.shields.io/docker/pulls/dessalines/lemmy.svg)
+[![Docker Pulls](https://img.shields.io/docker/pulls/dessalines/lemmy.svg)](https://cloud.docker.com/repository/docker/dessalines/lemmy/)
[![GitHub issues](https://img.shields.io/github/issues-raw/dessalines/lemmy.svg)](https://github.com/dessalines/lemmy/issues)
![GitHub repo size](https://img.shields.io/github/repo-size/dessalines/lemmy.svg)
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/dessalines/lemmy.svg)
[![License](https://img.shields.io/github/license/dessalines/lemmy.svg)](LICENSE)
-[![Mastodon](https://img.shields.io/badge/Mastodon-follow-lightgrey.svg)](https://mastodon.social/@LemmyDev)
+[![Mastodon](https://img.shields.io/badge/Mastodon-@LemmyDev-lightgrey.svg)](https://mastodon.social/@LemmyDev)
[![Matrix](https://img.shields.io/matrix/rust-reddit-fediverse:matrix.org.svg?label=matrix-chat)](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org)
[![Patreon](https://img.shields.io/badge/-Support%20on%20Patreon-blueviolet.svg)](https://www.patreon.com/dessalines)
---|---
![main screen](https://i.imgur.com/y64BtXC.png)|![chat screen](https://i.imgur.com/vsOr87q.png)
## Features
+
- Open source, [AGPL License](/LICENSE).
- Self hostable, easy to deploy.
- - Comes with [Docker](#docker), [Kubernetes](#kubernetes).
+ - Comes with [Docker](#docker), [Ansible](#ansible).
- Live-updating Comment threads.
- Full vote scores `(+/-)` like old reddit.
- Moderation abilities.
- Can lock, remove, and restore posts and comments.
- Can ban and unban users from communities and the site.
- Clean, mobile-friendly interface.
+- i18n / internationalization support.
+- NSFW post / community support.
+- Cross-posting support.
+- Can transfer site and communities to others.
- High performance.
- Server is written in rust.
- Front end is `~80kB` gzipped.
+
## About
+
[Lemmy](https://github.com/dessalines/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse).
For a link aggregator, this means a user registered on one server can subscribe to forums on any other server, and can have discussions with users registered elsewhere.
Each lemmy server can set its own moderation policy; appointing site-wide admins, and community moderators to keep out the trolls, and foster a healthy, non-toxic environment where all can feel comfortable contributing.
## Why's it called Lemmy?
+
- Lead singer from [motorhead](https://invidio.us/watch?v=pWB5JZRGl0U).
- The old school [video game](<https://en.wikipedia.org/wiki/Lemmings_(video_game)>).
- The [Koopa from Super Mario](https://www.mariowiki.com/Lemmy_Koopa).
- The [furry rodents](http://sunchild.fpwc.org/lemming-the-little-giant-of-the-north/).
Made with [Rust](https://www.rust-lang.org), [Actix](https://actix.rs/), [Inferno](https://www.infernojs.org), [Typescript](https://www.typescriptlang.org/) and [Diesel](http://diesel.rs/).
+
## Install
+
### Docker
-Make sure you have both docker and docker-compose installed.
-```
-git clone https://github.com/dessalines/lemmy
-cd lemmy/docker
+Make sure you have both docker and docker-compose(>=`1.24.0`) installed.
+
+```bash
+mkdir lemmy/
+cd lemmy/
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/.env
+# Edit the .env if you want custom passwords
docker-compose up -d
```
and goto http://localhost:8536
-## Develop
-### Docker Development
-```
-git clone https://github.com/dessalines/lemmy
-cd lemmy
-./docker_update.sh # This pulls the newest version, builds and runs it
-```
+[A sample nginx config](/docker/prod/nginx.conf), could be setup with:
-and goto http://localhost:8536
-### Kubernetes
-#### Requirements
-- Local or remote Kubernetes cluster, i.e. [`minikube`](https://kubernetes.io/docs/tasks/tools/install-minikube/)
-- [`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
-- [`skaffold`](https://skaffold.dev/)
-#### Production
```bash
-# Deploy the Traefik Ingress
-kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-rbac.yaml
-kubectl apply -f https://raw.githubusercontent.com/containous/traefik/v1.7/examples/k8s/traefik-ds.yaml
-# Replace ${IP} with your Ingress' IP
-echo "${IP} dev.lemmy.local" >> /etc/hosts
+wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/nginx.conf
+# Replace the {{ vars }}
+sudo mv nginx.conf /etc/nginx/sites-enabled/lemmy.conf
```
+### Ansible
+
+First, you need to [install Ansible on your local computer](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html),
+eg using `sudo apt install ansible`, or the equivalent for you platform.
+
+Then run the following commands on your local computer:
+
```bash
-skaffold run -p lemmy--prod
+git clone https://github.com/dessalines/lemmy.git
+cd lemmy/ansible/
+cp inventory.example inventory
+nano inventory # enter your server, domain, contact email
+ansible-playbook lemmy.yml
```
-Now go to http://dev.lemmy.local.
-#### Development
+## Develop
+
+### Docker Development
+
```bash
-skaffold dev -p lemmy--dev
+git clone https://github.com/dessalines/lemmy
+cd lemmy/docker/dev
+./docker_update.sh # This builds and runs it, updating for your changes
```
-Now go to http://localhost:4444. It automatically proxies to localhost, both if the cluster is local or remote; it also hot-reloads the UI and automatically recompiles and restarts the server.
+and goto http://localhost:8536
+
### Local Development
+
#### Requirements
+
- [Rust](https://www.rust-lang.org/)
- [Yarn](https://yarnpkg.com/en/)
-- [Postgres](https://www.sqlite.org/index.html)
+- [Postgres](https://www.postgresql.org/)
+
#### Set up Postgres DB
+
+```bash
+ psql -c "create user lemmy with password 'password' superuser;" -U postgres
+ psql -c 'create database lemmy with owner lemmy;' -U postgres
+ export DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
```
- psql -c "create user rrr with password 'rrr' superuser;" -U postgres
- psql -c 'create database rrr with owner rrr;' -U postgres
-```
+
#### Running
-```
+
+```bash
git clone https://github.com/dessalines/lemmy
cd lemmy
./install.sh
# cd server && cargo watch -x run
```
-and goto http://localhost:8536
## Documentation
+
- [Websocket API for App developers](docs/api.md)
- [ActivityPub API.md](docs/apub_api_outline.md)
- [Goals](docs/goals.md)
- [Ranking Algorithm](docs/ranking.md)
+
## Support
+
Lemmy is free, open-source software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project.
- [Support on Patreon](https://www.patreon.com/dessalines).
-- [Sponsor List](https://dev.lemmy.ml/#/sponsors).
+- [Sponsor List](https://dev.lemmy.ml/sponsors).
- bitcoin: `1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK`
- ethereum: `0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01`
+- monero: `41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV`
+
+## Translations
+
+If you'd like to add translations, take a look a look at the [english translation file](ui/src/translations/en.ts).
+
+- Languages supported: English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`).
+
+### Report
+
+lang | done | missing
+--- | --- | ---
+de | 88% | cross_posts,cross_post,users,number_of_communities,settings,subscribed,expires,recent_comments,nsfw,show_nsfw,crypto,monero,joined,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+eo | 98% | number_of_communities,are_you_sure,yes,no
+es | 98% | number_of_communities,are_you_sure,yes,no
+fr | 91% | cross_posts,cross_post,users,number_of_communities,settings,recent_comments,nsfw,show_nsfw,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+nl | 100% |
+ru | 93% | cross_posts,cross_post,number_of_communities,recent_comments,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+sv | 91% | cross_posts,cross_post,number_of_communities,settings,recent_comments,nsfw,show_nsfw,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+zh | 91% | cross_posts,cross_post,users,number_of_communities,settings,recent_comments,nsfw,show_nsfw,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
+
## Credits
-Icons made by [Freepik](https://www.freepik.com/) licensed by [CC 3.0](http://creativecommons.org/licenses/by/3.0/)
+
+Logo made by Andy Cuccaro (@andycuccaro) under the CC-BY-SA 4.0 license
--- /dev/null
+[defaults]
+inventory=inventory
+
+[ssh_connection]
+pipelining = True
--- /dev/null
+[lemmy]
+# define the username and hostname that you use for ssh connection, and specify the domain
+myuser@example.com domain=example.com letsencrypt_contact_email=your@email.com
+
+[all:vars]
+ansible_connection=ssh
--- /dev/null
+---
+- hosts: all
+
+ # Install python if required
+ # https://www.josharcher.uk/code/ansible-python-connection-failure-ubuntu-server-1604/
+ gather_facts: False
+ pre_tasks:
+ - name: install python for Ansible
+ raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal python-setuptools)
+ args:
+ executable: /bin/bash
+ register: output
+ changed_when: output.stdout != ""
+ - setup: # gather facts
+
+ tasks:
+ - name: install dependencies
+ apt:
+ pkg: ['nginx', 'docker-compose', 'docker.io', 'certbot', 'python-certbot-nginx']
+
+ - name: request initial letsencrypt certificate
+ command: certbot certonly --nginx --agree-tos -d '{{ domain }}' -m '{{ letsencrypt_contact_email }}'
+ args:
+ creates: '/etc/letsencrypt/live/{{domain}}/privkey.pem'
+
+ - name: create lemmy folder
+ file: path={{item.path}} state=directory
+ with_items:
+ - { path: '/lemmy/' }
+ - { path: '/lemmy/volumes/' }
+
+ - name: add all template files
+ template: src={{item.src}} dest={{item.dest}}
+ with_items:
+ - { src: 'templates/env', dest: '/lemmy/.env' }
+ - { src: '../docker/prod/docker-compose.yml', dest: '/lemmy/docker-compose.yml' }
+ - { src: 'templates/nginx.conf', dest: '/etc/nginx/sites-enabled/lemmy.conf' }
+ 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') }}"
+
+ - name: set env file permissions
+ file:
+ path: "/lemmy/.env"
+ state: touch
+ mode: 0600
+ access_time: preserve
+ modification_time: preserve
+
+ - name: enable and start docker service
+ systemd:
+ name: docker
+ enabled: yes
+ state: started
+
+ - name: start docker-compose
+ docker_compose:
+ project_src: /lemmy/
+ state: present
+ pull: yes
+
+ - name: reload nginx with new config
+ shell: nginx -s reload
+
+ - name: certbot renewal cronjob
+ cron:
+ special_time=daily
+ name=certbot-renew-lemmy
+ user=root
+ job="certbot certonly --nginx -d '{{ domain }}' --deploy-hook 'docker-compose -f /peertube/docker-compose.yml exec nginx nginx -s reload'"
--- /dev/null
+DOMAIN={{ domain }}
+DATABASE_PASSWORD={{ postgres_password }}
+DATABASE_URL=postgres://lemmy:{{ postgres_password }}@db:5432/lemmy
+JWT_SECRET={{ jwt_password }}
--- /dev/null
+server {
+ listen 80;
+ server_name {{ domain }};
+ location /.well-known/acme-challenge/ {
+ root /var/www/certbot;
+ }
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ server_name {{ domain }};
+
+ ssl_certificate /etc/letsencrypt/live/{{domain}}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/{{domain}}/privkey.pem;
+
+ # Various TLS hardening settings
+ # https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_prefer_server_ciphers on;
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+ ssl_session_timeout 10m;
+ ssl_session_cache shared:SSL:10m;
+ ssl_session_tickets off;
+ ssl_stapling on;
+ ssl_stapling_verify on;
+
+ # Hide nginx version
+ server_tokens off;
+
+ # Enable compression for JS/CSS/HTML bundle, for improved client load times.
+ # It might be nice to compress JSON, but leaving that out to protect against potential
+ # compression+encryption information leak attacks like BREACH.
+ gzip on;
+ gzip_types text/css application/javascript;
+ gzip_vary on;
+
+ # Only connect to this site via HTTPS for the two years
+ add_header Strict-Transport-Security "max-age=63072000";
+
+ # Various content security headers
+ add_header Referrer-Policy "same-origin";
+ add_header X-Content-Type-Options "nosniff";
+ add_header X-Frame-Options "DENY";
+ add_header X-XSS-Protection "1; mode=block";
+
+ location / {
+ rewrite (\/(user|u\/|inbox|post|community|c\/|login|search|sponsors|communities|modlog|home)+) /static/index.html break;
+ proxy_pass http://0.0.0.0:8536;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ # WebSocket support
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ }
+}
+++ /dev/null
-version: '2.4'
-
-services:
- db:
- image: postgres
- restart: always
- environment:
- POSTGRES_USER: rrr
- POSTGRES_PASSWORD: rrr
- POSTGRES_DB: rrr
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U rrr"]
- interval: 5s
- timeout: 5s
- retries: 20
- lemmy:
- build:
- context: .
- ports:
- - "8536:8536"
- environment:
- LEMMY_FRONT_END_DIR: /app/dist
- DATABASE_URL: postgres://rrr:rrr@db:5432/rrr
- JWT_SECRET: changeme
- HOSTNAME: rrr
- restart: always
- depends_on:
- db:
- condition: service_healthy
--- /dev/null
+DOMAIN=my_domain
+DATABASE_PASSWORD=password
+DATABASE_URL=postgres://lemmy:password@lemmy_db:5432/lemmy
+JWT_SECRET=changeme
FROM node:10-jessie as node
+
WORKDIR /app/ui
# Cache deps
COPY ui /app/ui
RUN yarn build
-FROM rust:latest as rust
+FROM rust:1.37 as rust
# Install musl
RUN apt-get update
# Get diesel-cli on there just in case
# RUN cargo install diesel_cli --no-default-features --features postgres
-FROM alpine:latest
+FROM alpine:3.10
# Install libpq for postgres
RUN apk add libpq
--- /dev/null
+#!/bin/sh
+git checkout master
+
+# Creating the new tag
+new_tag="$1"
+git tag $new_tag
+
+# Setting the version on the front end
+pushd ../../ui/
+node set_version.js
+git add src/version.ts
+popd
+
+# Changing the docker-compose prod
+sed -i "s/dessalines\/lemmy:.*/dessalines\/lemmy:$new_tag/" ../prod/docker-compose.yml
+git add ../prod/docker-compose.yml
+
+# The commit
+git commit -m"Upping version."
+
+git push origin $new_tag
+git push
+
+# Rebuilding docker
+./docker_update.sh
+docker tag dev_lemmy:latest dessalines/lemmy:$new_tag
+docker push dessalines/lemmy:$new_tag
--- /dev/null
+version: '3.3'
+
+services:
+ lemmy_db:
+ image: postgres:12-alpine
+ environment:
+ - POSTGRES_USER=lemmy
+ - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
+ - POSTGRES_DB=lemmy
+ volumes:
+ - lemmy_db:/var/lib/postgresql/data
+ lemmy:
+ build:
+ context: ../../
+ dockerfile: docker/dev/Dockerfile
+ ports:
+ - "8536:8536"
+ environment:
+ - LEMMY_FRONT_END_DIR=/app/dist
+ - DATABASE_URL=${DATABASE_URL}
+ - JWT_SECRET=${JWT_SECRET}
+ - HOSTNAME=${DOMAIN}
+ depends_on:
+ - lemmy_db
+volumes:
+ lemmy_db:
#!/bin/sh
-set -e
-
-git pull
docker-compose up -d --no-deps --build
+++ /dev/null
-version: '2.4'
-
-services:
- db:
- image: postgres
- restart: always
- environment:
- POSTGRES_USER: rrr
- POSTGRES_PASSWORD: rrr
- POSTGRES_DB: rrr
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U rrr"]
- interval: 5s
- timeout: 5s
- retries: 20
- lemmy:
- image: dessalines/lemmy:latest
- ports:
- - "8536:8536"
- environment:
- LEMMY_FRONT_END_DIR: /app/dist
- DATABASE_URL: postgres://rrr:rrr@db:5432/rrr
- JWT_SECRET: changeme
- HOSTNAME: rrr
- restart: always
- depends_on:
- db:
- condition: service_healthy
--- /dev/null
+docker exec -it dev_lemmy_db_1 pg_dumpall -c -U rrr > dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql
--- /dev/null
+DOMAIN=my_domain
+DATABASE_PASSWORD=password
+DATABASE_URL=postgres://lemmy:password@lemmy_db:5432/lemmy
+JWT_SECRET=changeme
--- /dev/null
+version: '3.3'
+
+services:
+ lemmy_db:
+ image: postgres:12-alpine
+ environment:
+ - POSTGRES_USER=lemmy
+ - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
+ - POSTGRES_DB=lemmy
+ volumes:
+ - lemmy_db:/var/lib/postgresql/data
+ lemmy:
+ image: dessalines/lemmy:v0.0.8.7
+ ports:
+ - "8536:8536"
+ environment:
+ - LEMMY_FRONT_END_DIR=/app/dist
+ - DATABASE_URL=${DATABASE_URL}
+ - JWT_SECRET=${JWT_SECRET}
+ - HOSTNAME=${DOMAIN}
+ depends_on:
+ - lemmy_db
+volumes:
+ lemmy_db:
--- /dev/null
+server {
+ listen 80;
+ server_name {{ your domain }};
+ location /.well-known/acme-challenge/ {
+ root /var/www/certbot;
+ }
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ server_name {{ your domain }};
+
+ ssl_certificate /etc/letsencrypt/live/{{ your domain }}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/{{ your domain }}/privkey.pem;
+
+ # Various TLS hardening settings
+ # https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_prefer_server_ciphers on;
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+ ssl_session_timeout 10m;
+ ssl_session_cache shared:SSL:10m;
+ ssl_session_tickets off;
+ ssl_stapling on;
+ ssl_stapling_verify on;
+
+ # Hide nginx version
+ server_tokens off;
+
+ # Enable compression for JS/CSS/HTML bundle, for improved client load times.
+ # It might be nice to compress JSON, but leaving that out to protect against potential
+ # compression+encryption information leak attacks like BREACH.
+ gzip on;
+ gzip_types text/css application/javascript;
+ gzip_vary on;
+
+ # Only connect to this site via HTTPS for the two years
+ add_header Strict-Transport-Security "max-age=63072000";
+
+ # Various content security headers
+ add_header Referrer-Policy "same-origin";
+ add_header X-Content-Type-Options "nosniff";
+ add_header X-Frame-Options "DENY";
+ add_header X-XSS-Protection "1; mode=block";
+
+ location / {
+ rewrite (\/(user|u|inbox|post|community|c|login|search|sponsors|communities|modlog|home)+) /static/index.html break;
+ proxy_pass http://0.0.0.0:8536;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ # WebSocket support
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ }
+}
+++ /dev/null
-docker exec -it lemmy_db_1 pg_dumpall -c -U rrr > dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql
## API
### List
-`Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead`
+`Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead, SaveUserSettings, TransferCommunity,
+TransferSite`
### Sort Types
These go wherever there is a `sort` field.
posts: Vec<PostView>,
}
```
-
+#### Save User Settings
+##### Request
+```rust
+{
+ show_nsfw: bool,
+ auth: String,
+}
+```
+##### Response
+```rust
+{
+ op: String,
+ jwt: String
+}
+```
#### Get Replies / Inbox
##### Request
```rust
}
```
+#### Transfer Site
+##### Request
+```rust
+{
+ op: "TransferSite",
+ data: {
+ user_id: i32,
+ auth: String
+ }
+}
+```
+##### Response
+```rust
+{
+ op: String,
+ site: Option<SiteView>,
+ admins: Vec<UserView>,
+ banned: Vec<UserView>,
+}
+```
+
### Community
#### Get Community
##### Request
}
```
+#### Transfer Community
+##### Request
+```rust
+{
+ op: "TransferCommunity",
+ data: {
+ community_id: i32,
+ user_id: i32,
+ auth: String
+ }
+}
+```
+##### Response
+```rust
+{
+ op: String,
+ community: CommunityView,
+ moderators: Vec<CommunityModeratorView>,
+ admins: Vec<UserView>,
+}
+```
+
### Post
#### Create Post
##### Request
- [Activitypub main](https://www.w3.org/TR/activitypub/)
- [Diesel to Postgres data types](https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html)
- [helpful diesel examples](http://siciarz.net/24-days-rust-diesel/)
-- [Mastodan public key server example](https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/)
+- [Mastodon public key server example](https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/)
- [Recursive query for adjacency list for nested comments](https://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way-to-parse-a-flat-table-into-a-tree/192462#192462)
- https://github.com/sparksuite/simplemde-markdown-editor
- [Markdown-it](https://github.com/markdown-it/markdown-it)
- [RES expando - Possibly make this into a switching react component.](https://github.com/honestbleeps/Reddit-Enhancement-Suite/tree/d21f55c21e734f47d8ed03fe0ebce5b16653b0bd/lib/modules/hosts)
- [Temp Icon](https://www.flaticon.com/free-icon/mouse_194242)
- [Rust docker build](https://shaneutt.com/blog/rust-fast-small-docker-image-builds/)
+- [Zurb mentions](https://github.com/zurb/tribute)
- Activitypub guides
- https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/
- https://raw.githubusercontent.com/w3c/activitypub/gh-pages/activitypub-tutorial.txt
- https://github.com/tOkeshu/activitypub-example
+ - https://blog.joinmastodon.org/2018/07/how-to-make-friends-and-verify-requests/
- Use a log scale, since votes tend to snowball, and so the first 10 votes are just as important as the next hundred.
## Reddit Sorting
-[Reddit's comment sorting algorithm](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9), the wilson confidence sort, is inadequate, because it completely ignores time. What ends up happening, especially in smaller subreddits, is that the early comments end up getting upvoted, and newer comments stay at the bottom, never to be seen.
+[Reddit's comment sorting algorithm](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9), the wilson confidence sort, is inadequate, because it completely ignores time. What ends up happening, especially in smaller subreddits, is that the early comments end up getting upvoted, and newer comments stay at the bottom, never to be seen. Research showed that nearly all top comments are just the [first ones posted.](https://minimaxir.com/2016/11/first-comment/)
## Hacker News Sorting
The [Hacker New's ranking algorithm](https://medium.com/hacking-and-gonzo/how-hacker-news-ranking-algorithm-works-1d9b0cf2c08d) is great, but it doesn't use a log scale for the scores.
# It is not intended for manual editing.
[[package]]
name = "activitypub"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "activitystreams-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "activitystreams-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "activitystreams-types 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "activitystreams-derive"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "activitystreams-types"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "activitystreams-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "actix"
-version = "0.7.9"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "actix_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-http 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-rt 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hashbrown 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "trust-dns-resolver 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "actix-net"
-version = "0.2.6"
+name = "actix-codec"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-connect"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-utils 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "tower-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "trust-dns-resolver 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "actix-web"
-version = "0.7.18"
+name = "actix-files"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "actix-net 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-http 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-web 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "v_htmlescape 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-http"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-connect 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-server-config 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-threadpool 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-utils 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "trust-dns-resolver 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-router"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-rt"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "actix-threadpool 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-server"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "actix-rt 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-server-config 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-server-config"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-service"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-threadpool"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-utils"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "actix-web"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-http 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-router 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-rt 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-server 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-server-config 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-threadpool 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-utils 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-web-codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "awc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "v_htmlescape 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "actix_derive"
-version = "0.3.2"
+name = "actix-web-actors"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-http 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-web 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "adler32"
-version = "1.0.3"
+name = "actix-web-codegen"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
-name = "aho-corasick"
-version = "0.6.10"
+name = "actix_derive"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "arc-swap"
-version = "0.3.7"
+name = "adler32"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "arrayvec"
-version = "0.4.10"
+name = "aho-corasick"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "arc-swap"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "atty"
-version = "0.2.11"
+version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
-version = "0.1.2"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "backtrace"
-version = "0.3.14"
+name = "awc"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-http 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "backtrace-sys"
-version = "0.1.28"
+name = "backtrace"
+version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "base64"
-version = "0.9.3"
+name = "backtrace-sys"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bcrypt"
-version = "0.3.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
-version = "1.0.4"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "build_const"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "byteorder"
-version = "1.3.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "c2-chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "cc"
-version = "1.0.29"
+version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
-version = "0.1.6"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "cookie"
-version = "0.11.0"
+name = "copyless"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "crc"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "crc32fast"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "crossbeam-deque"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "crossbeam-epoch"
-version = "0.7.1"
+name = "crossbeam-utils"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "crossbeam-queue"
-version = "0.1.2"
+name = "derive_more"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "crossbeam-utils"
-version = "0.6.5"
+name = "derive_more"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pq-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "dotenv"
-version = "0.9.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
-version = "0.4.3"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "either"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "env_logger"
-version = "0.6.0"
+name = "encoding_rs"
+version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "error-chain"
-version = "0.8.1"
+name = "enum-as-inner"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
- "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "flate2"
-version = "1.0.6"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures"
-version = "0.1.25"
+version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "futures-cpupool"
-version = "0.1.8"
+name = "generic-array"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "generic-array"
-version = "0.12.0"
+name = "getrandom"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "h2"
-version = "0.1.16"
+version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "hashbrown"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "hashbrown"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "http"
-version = "0.1.16"
+version = "0.1.17"
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.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "httparse"
-version = "1.3.3"
+version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ipconfig"
-version = "0.1.9"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winreg 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
-version = "0.4.3"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jsonwebtoken"
-version = "5.0.1"
+version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
name = "lazy_static"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "lazycell"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "lemmy_server"
version = "0.0.1"
dependencies = [
- "activitypub 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "actix-web 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "bcrypt 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "activitypub 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-files 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-web 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "actix-web-actors 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bcrypt 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "dotenv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dotenv 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonwebtoken 6.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
- "strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
-version = "0.2.49"
+version = "0.2.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "linked-hash-map"
-version = "0.4.2"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "lock_api"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "log"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lru-cache"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "linked-hash-map 0.4.2 (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]]
[[package]]
name = "memchr"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "memoffset"
-version = "0.2.1"
+version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "miniz-sys"
-version = "0.1.11"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miniz_oxide"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "miniz_oxide_c_api"
-version = "0.2.1"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
-version = "0.6.16"
+version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "nodrop"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "nom"
-version = "4.2.2"
+version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
-version = "0.1.39"
+version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
-version = "0.2.6"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "num_cpus"
-version = "1.10.0"
+version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "parking_lot"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "parking_lot_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "ppv-lite86"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "pq-sys"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "proc-macro2"
-version = "0.4.27"
+version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "quote"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand"
-version = "0.5.6"
+version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rand_chacha"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rand_core"
version = "0.3.1"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "rand_core"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rand_hc"
version = "0.1.0"
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rand_isaac"
version = "0.1.1"
[[package]]
name = "rand_jitter"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
-version = "0.1.2"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
-version = "0.1.51"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "redox_termios"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex"
-version = "0.2.11"
+version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "regex"
-version = "1.1.2"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.5"
+version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "ring"
-version = "0.13.5"
+version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.13"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "ryu"
-version = "0.2.7"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "safemem"
-version = "0.3.0"
+name = "scopeguard"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
-version = "0.3.3"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "serde"
-version = "1.0.88"
+version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
-version = "1.0.88"
+version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
-version = "1.0.38"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_urlencoded"
-version = "0.5.4"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "signal-hook"
-version = "0.1.8"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "smallvec"
-version = "0.6.9"
+version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "socket2"
-version = "0.3.8"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "spin"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "stable_deref_trait"
version = "1.1.1"
[[package]]
name = "string"
-version = "0.1.3"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "strum"
-version = "0.14.0"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strum_macros"
-version = "0.14.0"
+version = "0.15.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)",
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "syn"
-version = "0.15.26"
+version = "0.15.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
-version = "0.10.1"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
-version = "1.0.4"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "termion"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "thread_local"
version = "0.3.6"
]
[[package]]
-name = "time"
-version = "0.1.42"
+name = "threadpool"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "tokio"
-version = "0.1.16"
+name = "time"
+version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-current-thread"
-version = "0.1.5"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-executor"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "tokio-fs"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-sync"
-version = "0.1.3"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "tokio-threadpool"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "tokio-timer"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "tokio-uds"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "tower-service"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "trust-dns-proto"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "trust-dns-proto"
-version = "0.6.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "enum-as-inner 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "trust-dns-resolver"
-version = "0.10.3"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ipconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "trust-dns-proto 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "ucd-util"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "unicase"
-version = "2.2.0"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
-version = "1.2.1"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "utf8-ranges"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "uuid"
-version = "0.7.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "v_escape"
-version = "0.3.2"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "v_escape_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "v_escape_derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "v_escape_derive"
-version = "0.2.1"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "v_htmlescape"
-version = "0.3.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "v_escape 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "v_escape 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vcpkg"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "widestring"
-version = "0.2.2"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "winapi"
-version = "0.3.6"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winreg"
-version = "0.5.1"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
]
[metadata]
-"checksum activitypub 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08018b04725f5107d4a64e850f8a44a1f8a7e72abf0ca09125e3054921d26fd9"
-"checksum activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48db826c588a009960d74530e7c215e21fae130f585362504dc6b6357e5ce86b"
+"checksum activitypub 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dbb11d9099278667d3723c6491f25ea34dcae3eb54d73070e665d312c4455b25"
+"checksum activitystreams-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "176bdecfca82b1980e4769e3d54b6a392284b724083e0bff68272e290f17458f"
"checksum activitystreams-traits 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542"
-"checksum activitystreams-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "224d1e28d043f4275139445475da8866f0a430ecfc9047c9a15fbe3c70c22b04"
-"checksum actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c616db5fa4b0c40702fb75201c2af7f8aa8f3a2e2c1dda3b0655772aa949666"
-"checksum actix-net 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8bebfbe6629e0131730746718c9e032b58f02c6ce06ed7c982b9fef6c8545acd"
-"checksum actix-web 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "e9f33c941e5e69a58a6bfef33853228042ed3799fc4b5a4923a36a85776fb690"
-"checksum actix_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4300e9431455322ae393d43a2ba1ef96b8080573c0fc23b196219efedfb6ba69"
+"checksum activitystreams-types 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ff74c5765278614a009f97b9ec12f9a7c732bbcc5e0337fcfcab619b784860ec"
+"checksum actix 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "671ce3d27313f236827a5dd153a1073ad03ef31fc77f562020263e7830cf1ef7"
+"checksum actix-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2c11af4b06dc935d8e1b1491dad56bfb32febc49096a91e773f8535c176453"
+"checksum actix-connect 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d161322a26e6b76d6598f48654afbdcfee644c900d4368e9962ec68abd0713b"
+"checksum actix-files 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e4640b28cd96059541c932f6f350c63c76688e43d68305cdb88e0004da12b5"
+"checksum actix-http 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59698e11ceb42ea16a2e491bd5a9b48adc7268323a5b600522d408d09783828c"
+"checksum actix-router 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "23224bb527e204261d0291102cb9b52713084def67d94f7874923baefe04ccf7"
+"checksum actix-rt 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "18d9054b1cfacfa441846b9b99001010cb8fbb02130e6cfdb25cea36d3e98e87"
+"checksum actix-server 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb3038e9e457e0a498ea682723e0f4e6cc2c4f362a1868d749808355275ad959"
+"checksum actix-server-config 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "483a34989c682d93142bacad6300375bb6ad8002d2e0bb249dbad86128b9ff30"
+"checksum actix-service 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aaecc01bbc595ebd7a563a7d4f8a607d0b964bb55273c6f362b0b02c26508cf2"
+"checksum actix-threadpool 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1c29f7c554d56b3841f4bb85d5b3dee01ba536e1307679f56eb54de28aaec3fb"
+"checksum actix-utils 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea501068a0173533704be321f149853f702d9e3c3ce9d57e7a96d94b1ab5aca"
+"checksum actix-web 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0147b2fd52ced64145c8370af627f12f098222a1c6ba67d021e21cd0d806f574"
+"checksum actix-web-actors 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "008c1b686048a16fef4ef2fc6b6e5fcf5f29829891ad87fc0848ade26b285627"
+"checksum actix-web-codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe9e3cdec1e645b675f354766e0688c5705021c85ab3cf739be1c8999b91c76"
+"checksum actix_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bf5f6d7bf2d220ae8b4a7ae02a572bb35b7c4806b24049af905ab8110de156c"
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
-"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
-"checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6"
-"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
-"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
-"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
-"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
-"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
+"checksum aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b7aa1ccb7d7ea3f437cf025a2ab1c47cc6c1bc9fc84918ff449def12f5e282"
+"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
+"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
+"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
+"checksum awc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4c4763e6aa29a801d761dc3464f081d439ea5249ba90c3c3bdfc8dd3f739d233"
+"checksum backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)" = "88fb679bc9af8fa639198790a77f52d345fe13656c08b43afa9424c206b731c6"
+"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
-"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
-"checksum bcrypt 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a426ab63025c1d21e4e12a218c915fa22097b89ab7ed5765fa803101e004b27"
-"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum bcrypt 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4fd6a91ff640809cfab4ea74312a892238a7bbae53adbf717b71122deb0c85"
+"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
"checksum brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd"
"checksum brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e"
-"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
-"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
+"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
-"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
-"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
-"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
+"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
+"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
+"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
+"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
-"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
+"checksum copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
-"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
-"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4"
-"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
+"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839"
+"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe"
"checksum diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d24935ba50c4a8dc375a0fd1f8a2ba6bdbdc4125713126a74b965d6a01a06d7"
"checksum diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62a27666098617d52c487a41f70de23d44a1dc1f3aa5877ceba2790fb1f1cab4"
"checksum diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c"
-"checksum dotenv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "400b347fe65ccfbd8f545c9d9a75d04b0caf23fec49aaa838a9a05398f94c019"
-"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
+"checksum dotenv 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4424bad868b0ffe6ae351ee463526ba625bbca817978293bbe6bb7dc1804a175"
+"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
+"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
"checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
"checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
"checksum encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
"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 env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
-"checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46"
+"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
+"checksum enum-as-inner 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d58266c97445680766be408285e798d3401c6d4c378ec5552e78737e681e37d"
+"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
-"checksum flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2291c165c8e703ee54ef3055ad6188e3d51108e2ded18e9f2476e774fc5ad3d4"
+"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
-"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
-"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
-"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
-"checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e"
+"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
+"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55"
+"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392"
+"checksum hashbrown 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "29fba9abe4742d586dfd0c06ae4f7e73a1c2d86b856933509b269d82cdf06e18"
+"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e"
-"checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a"
-"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
+"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"
+"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
-"checksum ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "08f7eadeaf4b52700de180d147c4805f199854600b36faa963d91114827b2ffc"
-"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
-"checksum jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8d438ea707d465c230305963b67f8357a1d56fcfad9434797d7cb1c46c2e41df"
+"checksum ipconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa79fa216fbe60834a9c0737d7fcd30425b32d1c58854663e24d4c4b328ed83f"
+"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
+"checksum jsonwebtoken 6.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a81d1812d731546d2614737bee92aa071d37e9afa1409bc374da9e5e70e70b22"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
-"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
-"checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e"
-"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
+"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
+"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
-"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
-"checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21"
+"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff"
+"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
+"checksum log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c275b6ad54070ac2d665eef9197db647b32239c9d244bfb6f041a766d00da5b3"
+"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
-"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
-"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
+"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum migrations_internals 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8089920229070f914b9ce9b07ef60e175b2b9bc2d35c3edd8bf4433604e863b9"
"checksum migrations_macros 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1664412abf7db2b8a6d58be42a38b099780cc542b5b350383b805d88932833fe"
"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed"
-"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
-"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e"
-"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab"
-"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
+"checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202"
+"checksum miniz_oxide 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c061edee74a88eb35d876ce88b94d77a0448a201de111c244b70d047f5820516"
+"checksum miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6c675792957b0d19933816c4e1d56663c341dd9bfa31cb2140ff2267c1d8ecf4"
+"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
-"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
-"checksum nom 4.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22293d25d3f33a8567cc8a1dc20f40c7eeb761ce83d0fcca059858580790cac3"
-"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
-"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
-"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
+"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
+"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
+"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
+"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
+"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
+"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
+"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
+"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum pq-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7"
-"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
+"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
-"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
-"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
+"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
+"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
-"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
-"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
+"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
+"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
-"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
-"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
-"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
-"checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f"
-"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
-"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
+"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc"
+"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c"
"checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb"
-"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
-"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
+"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c"
+"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
-"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
+"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
+"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850"
-"checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4"
-"checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9"
-"checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2"
+"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72"
+"checksum serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "c22a0820adfe2f257b098714323563dd06426502abbbce4f51b72ef544c5027f"
+"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
+"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
-"checksum signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "97a47ae722318beceb0294e6f3d601205a1e6abaa4437d9d33e3a212233e3021"
+"checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68"
+"checksum signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cded4ffa32146722ec54ab1f16320568465aa922aa9ab4708129599740da85d7"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
-"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
-"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7"
+"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
+"checksum socket2 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "4e626972d3593207547f14bf5fc9efa4d0e7283deb73fef1dff313dae9ab8878"
+"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
-"checksum string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b639411d0b9c738748b5397d5ceba08e648f4f1992231aa859af1a017f31f60b"
-"checksum strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1810e25f576e7ffce1ff5243b37066da5ded0310b3274c20baaeccb1145b2806"
-"checksum strum_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "572a2f4e53dd4c3483fd79e5cc10ddd773a3acb1169bbfe8762365e107110579"
+"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
+"checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f"
+"checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b"
-"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
+"checksum syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)" = "bc945221ccf4a7e8c31222b9d1fc77aefdd6638eb901a6ce457a3dc29d4c31e8"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
-"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
-"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
-"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
+"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
+"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
+"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
-"checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230"
"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
-"checksum tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c756b04680eea21902a46fca4e9f410a2332c04995af590e07ff262e2193a9a3"
-"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0"
-"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af"
+"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
+"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac"
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce"
"checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296"
-"checksum tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363"
+"checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7"
"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
-"checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801"
-"checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6"
+"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e"
"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92"
-"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
-"checksum tower-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b32f72af77f1bfe3d3d4da8516a238ebe7039b51dd8637a09841ac7f16d2c987"
-"checksum trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0838272e89f1c693b4df38dc353412e389cf548ceed6f9fd1af5a8d6e0e7cf74"
-"checksum trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09144f0992b0870fa8d2972cc069cbf1e3c0fda64d1f3d45c4d68d0e0b52ad4e"
-"checksum trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a9f877f7a1ad821ab350505e1f1b146a4960402991787191d6d8cab2ce2de2c"
+"checksum trust-dns-proto 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5559ebdf6c2368ddd11e20b11d6bbaf9e46deb803acd7815e93f5a7b4a6d2901"
+"checksum trust-dns-resolver 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c9992e58dba365798803c0b91018ff6c8d3fc77e06977c4539af2a6bfe0a039"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
-"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
+"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
-"checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90"
+"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
-"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
+"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
-"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
-"checksum uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0238db0c5b605dd1cf51de0f21766f97fba2645897024461d6a00c036819a768"
-"checksum v_escape 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b50688edb86f4c092a1a9fe8bda004b0faa3197100897653809e97e09a2814"
-"checksum v_escape_derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7cd994c63b487fef7aad31e5394ec04b9e24de7b32ea5251c9fb499cd2cbf44c"
-"checksum v_htmlescape 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "020cae817dc82693aa523f01087b291b1c7a9ac8cea5c12297963f21769fb27f"
-"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
+"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
+"checksum v_escape 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8865501b78eef9193c1b45486acf18ba889e5662eba98854d6fc59d8ecf3542d"
+"checksum v_escape_derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "306896ff4b75998501263a1dc000456de442e21d68fe8c8bdf75c66a33a58e23"
+"checksum v_htmlescape 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbbe0fa88dd36f9c8cf61a218d4b953ba669de4d0785832f33cc72bd081e1be"
+"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
-"checksum widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb"
+"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
-"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
+"checksum winreg 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73f1f3c6c4d3cab118551b96c476a2caab920701e28875b64a458f2ecb96ec9d"
"checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
name = "lemmy_server"
version = "0.0.1"
authors = ["Dessalines <happydooby@gmail.com>"]
+edition = "2018"
[dependencies]
diesel = { version = "1.4.2", features = ["postgres","chrono"] }
-diesel_migrations = "*"
-dotenv = "0.9.0"
-bcrypt = "0.3"
-activitypub = "0.1.4"
-chrono = { version = "0.4", features = ["serde"] }
+diesel_migrations = "1.4.0"
+dotenv = "0.14.1"
+bcrypt = "0.5.0"
+activitypub = "0.1.5"
+chrono = { version = "0.4.7", features = ["serde"] }
failure = "0.1.5"
-serde_json = "*"
-serde = { version = "1.0", features = ["derive"] }
-actix = "*"
-actix-web = "*"
-env_logger = "*"
-rand = "0.6.5"
-strum = "0.14.0"
-strum_macros = "0.14.0"
-jsonwebtoken = "*"
-regex = "*"
-lazy_static = "*"
+serde_json = "1.0.40"
+serde = { version = "1.0.94", features = ["derive"] }
+actix = "0.8.3"
+actix-web = "1.0"
+actix-files = "0.1.3"
+actix-web-actors = "1.0"
+env_logger = "0.6.2"
+rand = "0.7.0"
+strum = "0.15.0"
+strum_macros = "0.15.0"
+jsonwebtoken = "6.0.1"
+regex = "1.1.9"
+lazy_static = "1.3.0"
+
+++ /dev/null
-# Setup env
-FROM rust:1.33 AS build
-RUN USER=root cargo new --bin /opt/lemmy/server--dev
-WORKDIR /opt/lemmy/server--dev
-# Enable deps caching
-RUN mkdir -p src/bin
-RUN echo 'fn main() { println!("Dummy") }' >src/bin/main.rs
-# Install deps
-COPY Cargo.toml .
-COPY Cargo.lock .
-RUN cargo build --release
-RUN rm src/bin/main.rs
-# Add app
-COPY src/ src/
-COPY migrations/ migrations/
-RUN rm target/release/deps/lemmy*
-RUN cargo build --release
-
-# Setup env (no Alpine because Rust requires glibc)
-FROM ubuntu:18.04
-RUN apt update
-RUN apt install postgresql-client -y
-# Create empty directory where the frontend would normally be
-RUN mkdir -p /opt/lemmy/ui--dev/dist
-# Add app
-COPY --from=build /opt/lemmy/server--dev/target/release/lemmy .
-# Run app
-CMD ["./lemmy"]
+++ /dev/null
-# Setup env
-FROM rust:1.33 AS build
-RUN USER=root cargo new --bin /opt/lemmy/server--prod
-WORKDIR /opt/lemmy/server--prod
-# Enable deps caching
-RUN mkdir -p src/bin
-RUN echo 'fn main() { println!("Dummy") }' >src/bin/main.rs
-# Install deps
-COPY Cargo.toml .
-COPY Cargo.lock .
-RUN cargo build --release
-RUN rm src/bin/main.rs
-# Add app
-COPY src/ src/
-COPY migrations/ migrations/
-RUN rm target/release/deps/lemmy*
-RUN cargo build --release
-
-# Setup env (no Alpine because Rust requires glibc)
-FROM ubuntu:18.04
-RUN apt update
-RUN apt install postgresql-client -y
-# Create empty directory where the frontend would normally be
-RUN mkdir -p /opt/lemmy/ui--prod/dist
-# Add app
-COPY --from=build /opt/lemmy/server--prod/target/release/lemmy .
-# Run app
-CMD ["./lemmy"]
--- /dev/null
+insert into user_ (name, fedi_name, password_encrypted) values ('admin', 'TBD', 'TBD');
--- /dev/null
+delete from user_ where name like 'admin';
--- /dev/null
+drop view community_view;
+drop view post_view;
+alter table community drop column nsfw;
+alter table post drop column nsfw;
+alter table user_ drop column show_nsfw;
+
+-- the views
+create view community_view as
+with all_community as
+(
+ select *,
+ (select name from user_ u where c.creator_id = u.id) as creator_name,
+ (select name from category ct where c.category_id = ct.id) as category_name,
+ (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
+ (select count(*) from post p where p.community_id = c.id) as number_of_posts,
+ (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments,
+ hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank
+ from community c
+)
+
+select
+ac.*,
+u.id as user_id,
+(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed
+from user_ u
+cross join all_community ac
+
+union all
+
+select
+ac.*,
+null as user_id,
+null as subscribed
+from all_community ac
+;
+
+
+-- Post view
+create view post_view as
+with all_post as
+(
+ select
+ p.*,
+ (select name from user_ where p.creator_id = user_.id) as creator_name,
+ (select name from community where p.community_id = community.id) as community_name,
+ (select removed from community c where p.community_id = c.id) as community_removed,
+ (select deleted from community c where p.community_id = c.id) as community_deleted,
+ (select count(*) from comment where comment.post_id = p.id) as number_of_comments,
+ coalesce(sum(pl.score), 0) as score,
+ count (case when pl.score = 1 then 1 else null end) as upvotes,
+ count (case when pl.score = -1 then 1 else null end) as downvotes,
+ hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank
+ from post p
+ left join post_like pl on p.id = pl.post_id
+ group by p.id
+)
+
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
--- /dev/null
+alter table community add column nsfw boolean default false not null;
+alter table post add column nsfw boolean default false not null;
+alter table user_ add column show_nsfw boolean default false not null;
+
+-- The views
+drop view community_view;
+create view community_view as
+with all_community as
+(
+ select *,
+ (select name from user_ u where c.creator_id = u.id) as creator_name,
+ (select name from category ct where c.category_id = ct.id) as category_name,
+ (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
+ (select count(*) from post p where p.community_id = c.id) as number_of_posts,
+ (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments,
+ hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank
+ from community c
+)
+
+select
+ac.*,
+u.id as user_id,
+(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed
+from user_ u
+cross join all_community ac
+
+union all
+
+select
+ac.*,
+null as user_id,
+null as subscribed
+from all_community ac
+;
+
+-- Post view
+drop view post_view;
+create view post_view as
+with all_post as
+(
+ select
+ p.*,
+ (select name from user_ where p.creator_id = user_.id) as creator_name,
+ (select name from community where p.community_id = community.id) as community_name,
+ (select removed from community c where p.community_id = c.id) as community_removed,
+ (select deleted from community c where p.community_id = c.id) as community_deleted,
+ (select nsfw from community c where p.community_id = c.id) as community_nsfw,
+ (select count(*) from comment where comment.post_id = p.id) as number_of_comments,
+ coalesce(sum(pl.score), 0) as score,
+ count (case when pl.score = 1 then 1 else null end) as upvotes,
+ count (case when pl.score = -1 then 1 else null end) as downvotes,
+ hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank
+ from post p
+ left join post_like pl on p.id = pl.post_id
+ group by p.id
+)
+
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
--- /dev/null
+drop view site_view;
+
+create view site_view as
+select *,
+(select name from user_ u where s.creator_id = u.id) as creator_name,
+(select count(*) from user_) as number_of_users,
+(select count(*) from post) as number_of_posts,
+(select count(*) from comment) as number_of_comments
+from site s;
--- /dev/null
+drop view site_view;
+
+create view site_view as
+select *,
+(select name from user_ u where s.creator_id = u.id) as creator_name,
+(select count(*) from user_) as number_of_users,
+(select count(*) from post) as number_of_posts,
+(select count(*) from comment) as number_of_comments,
+(select count(*) from community) as number_of_communities
+from site s;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
// Check for a community ban
let post = Post::read(&conn, data.post_id)?;
if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
- return Err(APIError::err(&self.op, "You have been banned from this community"))?
+ return Err(APIError::err(&self.op, "community_ban"))?
}
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
let content_slurs_removed = remove_slurs(&data.content.to_owned());
let inserted_comment = match Comment::create(&conn, &comment_form) {
Ok(comment) => comment,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't create Comment"))?
+ return Err(APIError::err(&self.op, "couldnt_create_comment"))?
}
};
let _inserted_like = match CommentLike::like(&conn, &like_form) {
Ok(like) => like,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't like comment."))?
+ return Err(APIError::err(&self.op, "couldnt_like_comment"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
);
if !editors.contains(&user_id) {
- return Err(APIError::err(&self.op, "Not allowed to edit comment."))?
+ return Err(APIError::err(&self.op, "no_comment_edit_allowed"))?
}
// Check for a community ban
if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() {
- return Err(APIError::err(&self.op, "You have been banned from this community"))?
+ return Err(APIError::err(&self.op, "community_ban"))?
}
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
}
let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) {
Ok(comment) => comment,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update Comment"))?
+ return Err(APIError::err(&self.op, "couldnt_update_comment"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
match CommentSaved::save(&conn, &comment_saved_form) {
Ok(comment) => comment,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldnt do comment save"))?
+ return Err(APIError::err(&self.op, "couldnt_save_comment"))?
}
};
} else {
match CommentSaved::unsave(&conn, &comment_saved_form) {
Ok(comment) => comment,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldnt do comment save"))?
+ return Err(APIError::err(&self.op, "couldnt_save_comment"))?
}
};
}
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
// Check for a community ban
let post = Post::read(&conn, data.post_id)?;
if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
- return Err(APIError::err(&self.op, "You have been banned from this community"))?
+ return Err(APIError::err(&self.op, "community_ban"))?
}
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
let like_form = CommentLikeForm {
let _inserted_like = match CommentLike::like(&conn, &like_form) {
Ok(like) => like,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't like comment."))?
+ return Err(APIError::err(&self.op, "couldnt_like_comment"))?
}
};
}
name: String,
title: String,
description: Option<String>,
- category_id: i32 ,
+ category_id: i32,
+ nsfw: bool,
auth: String
}
category_id: i32,
removed: Option<bool>,
deleted: Option<bool>,
+ nsfw: bool,
reason: Option<String>,
expires: Option<i64>,
auth: String
communities: Vec<CommunityFollowerView>
}
+#[derive(Serialize, Deserialize)]
+pub struct TransferCommunity {
+ community_id: i32,
+ user_id: i32,
+ auth: String
+}
+
impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
fn perform(&self) -> Result<GetCommunityResponse, Error> {
let data: &GetCommunity = &self.data;
let community_view = match CommunityView::read(&conn, community_id, user_id) {
Ok(community) => community,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't find Community"))?
+ return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
};
let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
Ok(moderators) => moderators,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't find Community"))?
+ return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
};
- let admins = UserView::admins(&conn)?;
+ let site_creator_id = Site::read(&conn, 1)?.creator_id;
+ let mut admins = UserView::admins(&conn)?;
+ let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
+ let creator_user = admins.remove(creator_index);
+ admins.insert(0, creator_user);
// Return the jwt
Ok(
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
if has_slurs(&data.name) ||
has_slurs(&data.title) ||
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
let user_id = claims.id;
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
// When you create a community, make sure the user becomes a moderator and a follower
creator_id: user_id,
removed: None,
deleted: None,
+ nsfw: data.nsfw,
updated: None,
};
let inserted_community = match Community::create(&conn, &community_form) {
Ok(community) => community,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community already exists."))?
+ return Err(APIError::err(&self.op, "community_already_exists"))?
}
};
let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community moderator already exists."))?
+ return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
}
};
let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community follower already exists."))?
+ return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
};
let data: &EditCommunity = &self.data;
if has_slurs(&data.name) || has_slurs(&data.title) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
let conn = establish_connection();
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
// Verify its a mod
.collect()
);
if !editors.contains(&user_id) {
- return Err(APIError::err(&self.op, "Not allowed to edit community"))?
+ return Err(APIError::err(&self.op, "no_community_edit_allowed"))?
}
let community_form = CommunityForm {
creator_id: user_id,
removed: data.removed.to_owned(),
deleted: data.deleted.to_owned(),
+ nsfw: data.nsfw,
updated: Some(naive_now())
};
let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
Ok(community) => community,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update Community"))?
+ return Err(APIError::err(&self.op, "couldnt_update_community"))?
}
};
let data: &ListCommunities = &self.data;
let conn = establish_connection();
- let user_id: Option<i32> = match &data.auth {
+ let user_claims: Option<Claims> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Ok(claims) => {
- let user_id = claims.claims.id;
- Some(user_id)
+ Some(claims.claims)
}
Err(_e) => None
}
}
None => None
};
+
+ let user_id = match &user_claims {
+ Some(claims) => Some(claims.id),
+ None => None
+ };
+
+ let show_nsfw = match &user_claims {
+ Some(claims) => claims.show_nsfw,
+ None => false
+ };
let sort = SortType::from_str(&data.sort)?;
- let communities: Vec<CommunityView> = CommunityView::list(&conn, user_id, sort, data.page, data.limit)?;
+ let communities: Vec<CommunityView> = CommunityView::list(
+ &conn,
+ &sort,
+ user_id,
+ show_nsfw,
+ None,
+ data.page,
+ data.limit)?;
// Return the jwt
Ok(
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community follower already exists."))?
+ return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
};
} else {
match CommunityFollower::ignore(&conn, &community_follower_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community follower already exists."))?
+ return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
};
}
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) {
Ok(communities) => communities,
Err(_e) => {
- return Err(APIError::err(&self.op, "System error, try logging out and back in."))?
+ return Err(APIError::err(&self.op, "system_err_login"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
match CommunityUserBan::ban(&conn, &community_user_ban_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community user ban already exists"))?
+ return Err(APIError::err(&self.op, "community_user_already_banned"))?
}
};
} else {
match CommunityUserBan::unban(&conn, &community_user_ban_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community user ban already exists"))?
+ return Err(APIError::err(&self.op, "community_user_already_banned"))?
}
};
}
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community moderator already exists."))?
+ return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
}
};
} else {
match CommunityModerator::leave(&conn, &community_moderator_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community moderator already exists."))?
+ return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
}
};
}
)
}
}
+
+impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
+ fn perform(&self) -> Result<GetCommunityResponse, Error> {
+ let data: &TransferCommunity = &self.data;
+ let conn = establish_connection();
+
+ let claims = match Claims::decode(&data.auth) {
+ Ok(claims) => claims.claims,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "not_logged_in"))?
+ }
+ };
+
+ let user_id = claims.id;
+
+ let read_community = Community::read(&conn, data.community_id)?;
+
+ let site_creator_id = Site::read(&conn, 1)?.creator_id;
+ let mut admins = UserView::admins(&conn)?;
+ let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
+ let creator_user = admins.remove(creator_index);
+ admins.insert(0, creator_user);
+
+
+ // Make sure user is the creator, or an admin
+ if user_id != read_community.creator_id && !admins.iter().map(|a| a.id).collect::<Vec<i32>>().contains(&user_id) {
+ return Err(APIError::err(&self.op, "not_an_admin"))?
+ }
+
+ let community_form = CommunityForm {
+ name: read_community.name,
+ title: read_community.title,
+ description: read_community.description,
+ category_id: read_community.category_id,
+ creator_id: data.user_id,
+ removed: None,
+ deleted: None,
+ nsfw: read_community.nsfw,
+ updated: Some(naive_now())
+ };
+
+ let _updated_community = match Community::update(&conn, data.community_id, &community_form) {
+ Ok(community) => community,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "couldnt_update_community"))?
+ }
+ };
+
+ // You also have to re-do the community_moderator table, reordering it.
+ let mut community_mods = CommunityModeratorView::for_community(&conn, data.community_id)?;
+ let creator_index = community_mods.iter().position(|r| r.user_id == data.user_id).unwrap();
+ let creator_user = community_mods.remove(creator_index);
+ community_mods.insert(0, creator_user);
+
+ CommunityModerator::delete_for_community(&conn, data.community_id)?;
+
+ for cmod in &community_mods {
+
+ let community_moderator_form = CommunityModeratorForm {
+ community_id: cmod.community_id,
+ user_id: cmod.user_id
+ };
+
+ let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
+ Ok(user) => user,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
+ }
+ };
+ }
+
+ // Mod tables
+ let form = ModAddCommunityForm {
+ mod_user_id: user_id,
+ other_user_id: data.user_id,
+ community_id: data.community_id,
+ removed: Some(false),
+ };
+ ModAddCommunity::create(&conn, &form)?;
+
+ let community_view = match CommunityView::read(&conn, data.community_id, Some(user_id)) {
+ Ok(community) => community,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "couldnt_find_community"))?
+ }
+ };
+
+ let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) {
+ Ok(moderators) => moderators,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "couldnt_find_community"))?
+ }
+ };
+
+
+ // Return the jwt
+ Ok(
+ GetCommunityResponse {
+ op: self.op.to_string(),
+ community: community_view,
+ moderators: moderators,
+ admins: admins,
+ }
+ )
+ }
+}
use serde::{Deserialize, Serialize};
use failure::Error;
-use db::*;
-use db::community::*;
-use db::user::*;
-use db::post::*;
-use db::comment::*;
-use db::post_view::*;
-use db::comment_view::*;
-use db::category::*;
-use db::community_view::*;
-use db::user_view::*;
-use db::moderator_views::*;
-use db::moderator::*;
-use {has_slurs, remove_slurs, Settings, naive_now, naive_from_unix};
+use crate::db::*;
+use crate::db::community::*;
+use crate::db::user::*;
+use crate::db::post::*;
+use crate::db::comment::*;
+use crate::db::post_view::*;
+use crate::db::comment_view::*;
+use crate::db::category::*;
+use crate::db::community_view::*;
+use crate::db::user_view::*;
+use crate::db::moderator_views::*;
+use crate::db::moderator::*;
+use crate::{has_slurs, remove_slurs, Settings, naive_now, naive_from_unix};
pub mod user;
pub mod community;
#[derive(EnumString,ToString,Debug)]
pub enum UserOperation {
- Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead
+ Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead, SaveUserSettings, TransferCommunity, TransferSite
}
#[derive(Fail, Debug)]
name: String,
url: Option<String>,
body: Option<String>,
+ nsfw: bool,
community_id: i32,
auth: String
}
body: Option<String>,
removed: Option<bool>,
deleted: Option<bool>,
+ nsfw: bool,
locked: Option<bool>,
reason: Option<String>,
auth: String
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
if has_slurs(&data.name) ||
(data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
let user_id = claims.id;
// Check for a community ban
if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() {
- return Err(APIError::err(&self.op, "You have been banned from this community"))?
+ return Err(APIError::err(&self.op, "community_ban"))?
}
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
let post_form = PostForm {
creator_id: user_id,
removed: None,
deleted: None,
+ nsfw: data.nsfw,
locked: None,
updated: None
};
let inserted_post = match Post::create(&conn, &post_form) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't create Post"))?
+ return Err(APIError::err(&self.op, "couldnt_create_post"))?
}
};
let _inserted_like = match PostLike::like(&conn, &like_form) {
Ok(like) => like,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't like post."))?
+ return Err(APIError::err(&self.op, "couldnt_like_post"))?
}
};
let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't find Post"))?
+ return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
};
let post_view = match PostView::read(&conn, data.id, user_id) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't find Post"))?
+ return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
};
let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
- let admins = UserView::admins(&conn)?;
+ let site_creator_id = Site::read(&conn, 1)?.creator_id;
+ let mut admins = UserView::admins(&conn)?;
+ let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
+ let creator_user = admins.remove(creator_index);
+ admins.insert(0, creator_user);
// Return the jwt
Ok(
let data: &GetPosts = &self.data;
let conn = establish_connection();
- let user_id: Option<i32> = match &data.auth {
+ let user_claims: Option<Claims> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Ok(claims) => {
- let user_id = claims.claims.id;
- Some(user_id)
+ Some(claims.claims)
}
Err(_e) => None
}
}
None => None
};
+
+ let user_id = match &user_claims {
+ Some(claims) => Some(claims.id),
+ None => None
+ };
+
+ let show_nsfw = match &user_claims {
+ Some(claims) => claims.show_nsfw,
+ None => false
+ };
let type_ = PostListingType::from_str(&data.type_)?;
let sort = SortType::from_str(&data.sort)?;
- let posts = match PostView::list(&conn,
- type_,
- &sort,
- data.community_id,
- None,
- None,
- user_id,
- false,
- false,
- data.page,
- data.limit) {
+ let posts = match PostView::list(
+ &conn,
+ type_,
+ &sort,
+ data.community_id,
+ None,
+ None,
+ None,
+ user_id,
+ show_nsfw,
+ false,
+ false,
+ data.page,
+ data.limit) {
Ok(posts) => posts,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't get posts"))?
+ return Err(APIError::err(&self.op, "couldnt_get_posts"))?
}
};
- // Return the jwt
Ok(
GetPostsResponse {
op: self.op.to_string(),
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
// Check for a community ban
let post = Post::read(&conn, data.post_id)?;
if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
- return Err(APIError::err(&self.op, "You have been banned from this community"))?
+ return Err(APIError::err(&self.op, "community_ban"))?
}
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
let like_form = PostLikeForm {
let _inserted_like = match PostLike::like(&conn, &like_form) {
Ok(like) => like,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't like post."))?
+ return Err(APIError::err(&self.op, "couldnt_like_post"))?
}
};
}
let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't find Post"))?
+ return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
};
let data: &EditPost = &self.data;
if has_slurs(&data.name) ||
(data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
let conn = establish_connection();
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
.collect()
);
if !editors.contains(&user_id) {
- return Err(APIError::err(&self.op, "Not allowed to edit post."))?
+ return Err(APIError::err(&self.op, "no_post_edit_allowed"))?
}
// Check for a community ban
if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() {
- return Err(APIError::err(&self.op, "You have been banned from this community"))?
+ return Err(APIError::err(&self.op, "community_ban"))?
}
// Check for a site ban
if UserView::read(&conn, user_id)?.banned {
- return Err(APIError::err(&self.op, "You have been banned from the site"))?
+ return Err(APIError::err(&self.op, "site_ban"))?
}
let post_form = PostForm {
community_id: data.community_id,
removed: data.removed.to_owned(),
deleted: data.deleted.to_owned(),
+ nsfw: data.nsfw,
locked: data.locked.to_owned(),
updated: Some(naive_now())
};
let _updated_post = match Post::update(&conn, data.edit_id, &post_form) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update Post"))?
+ return Err(APIError::err(&self.op, "couldnt_update_post"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
match PostSaved::save(&conn, &post_saved_form) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldnt do post save"))?
+ return Err(APIError::err(&self.op, "couldnt_save_post"))?
}
};
} else {
match PostSaved::unsave(&conn, &post_saved_form) {
Ok(post) => post,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldnt do post save"))?
+ return Err(APIError::err(&self.op, "couldnt_save_post"))?
}
};
}
#[derive(Serialize, Deserialize)]
pub struct SearchResponse {
op: String,
+ type_: String,
comments: Vec<CommentView>,
posts: Vec<PostView>,
+ communities: Vec<CommunityView>,
+ users: Vec<UserView>,
}
#[derive(Serialize, Deserialize)]
}
#[derive(Serialize, Deserialize)]
-pub struct GetSite {
-}
+pub struct GetSite;
#[derive(Serialize, Deserialize)]
pub struct SiteResponse {
banned: Vec<UserView>,
}
+#[derive(Serialize, Deserialize)]
+pub struct TransferSite {
+ user_id: i32,
+ auth: String
+}
+
impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
fn perform(&self) -> Result<ListCategoriesResponse, Error> {
let _data: &ListCategories = &self.data;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
if has_slurs(&data.name) ||
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
let user_id = claims.id;
// Make sure user is an admin
if !UserView::read(&conn, user_id)?.admin {
- return Err(APIError::err(&self.op, "Not an admin."))?
+ return Err(APIError::err(&self.op, "not_an_admin"))?
}
let site_form = SiteForm {
match Site::create(&conn, &site_form) {
Ok(site) => site,
Err(_e) => {
- return Err(APIError::err(&self.op, "Site exists already"))?
+ return Err(APIError::err(&self.op, "site_already_exists"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
if has_slurs(&data.name) ||
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
let user_id = claims.id;
// Make sure user is an admin
if UserView::read(&conn, user_id)?.admin == false {
- return Err(APIError::err(&self.op, "Not an admin."))?
+ return Err(APIError::err(&self.op, "not_an_admin"))?
}
let found_site = Site::read(&conn, 1)?;
match Site::update(&conn, 1, &site_form) {
Ok(site) => site,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update site."))?
+ return Err(APIError::err(&self.op, "couldnt_update_site"))?
}
};
Err(_e) => None
};
- let admins = UserView::admins(&conn)?;
+ let mut admins = UserView::admins(&conn)?;
+ if site_view.is_some() {
+ let site_creator_id = site_view.to_owned().unwrap().creator_id;
+ let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
+ let creator_user = admins.remove(creator_index);
+ admins.insert(0, creator_user);
+ }
+
let banned = UserView::banned(&conn)?;
Ok(
let mut posts = Vec::new();
let mut comments = Vec::new();
+ let mut communities = Vec::new();
+ let mut users = Vec::new();
+
+ // TODO no clean / non-nsfw searching rn
match type_ {
SearchType::Posts => {
- posts = PostView::list(&conn,
- PostListingType::All,
- &sort,
- data.community_id,
- None,
- Some(data.q.to_owned()),
- None,
- false,
- false,
- data.page,
- data.limit)?;
+ posts = PostView::list(
+ &conn,
+ PostListingType::All,
+ &sort,
+ data.community_id,
+ None,
+ Some(data.q.to_owned()),
+ None,
+ None,
+ true,
+ false,
+ false,
+ data.page,
+ data.limit)?;
},
SearchType::Comments => {
- comments = CommentView::list(&conn,
- &sort,
- None,
- None,
- Some(data.q.to_owned()),
- None,
- false,
- data.page,
- data.limit)?;
+ comments = CommentView::list(
+ &conn,
+ &sort,
+ None,
+ None,
+ Some(data.q.to_owned()),
+ None,
+ false,
+ data.page,
+ data.limit)?;
+ },
+ SearchType::Communities => {
+ communities = CommunityView::list(
+ &conn,
+ &sort,
+ None,
+ true,
+ Some(data.q.to_owned()),
+ data.page,
+ data.limit)?;
+ },
+ SearchType::Users => {
+ users = UserView::list(
+ &conn,
+ &sort,
+ Some(data.q.to_owned()),
+ data.page,
+ data.limit)?;
},
- SearchType::Both => {
- posts = PostView::list(&conn,
- PostListingType::All,
- &sort,
- data.community_id,
- None,
- Some(data.q.to_owned()),
- None,
- false,
- false,
- data.page,
- data.limit)?;
- comments = CommentView::list(&conn,
- &sort,
- None,
- None,
- Some(data.q.to_owned()),
- None,
- false,
- data.page,
- data.limit)?;
+ SearchType::All => {
+ posts = PostView::list(
+ &conn,
+ PostListingType::All,
+ &sort,
+ data.community_id,
+ None,
+ Some(data.q.to_owned()),
+ None,
+ None,
+ true,
+ false,
+ false,
+ data.page,
+ data.limit)?;
+ comments = CommentView::list(
+ &conn,
+ &sort,
+ None,
+ None,
+ Some(data.q.to_owned()),
+ None,
+ false,
+ data.page,
+ data.limit)?;
+ communities = CommunityView::list(
+ &conn,
+ &sort,
+ None,
+ true,
+ Some(data.q.to_owned()),
+ data.page,
+ data.limit)?;
+ users = UserView::list(
+ &conn,
+ &sort,
+ Some(data.q.to_owned()),
+ data.page,
+ data.limit)?;
+ },
+ SearchType::Url => {
+ posts = PostView::list(
+ &conn,
+ PostListingType::All,
+ &sort,
+ data.community_id,
+ None,
+ None,
+ Some(data.q.to_owned()),
+ None,
+ true,
+ false,
+ false,
+ data.page,
+ data.limit)?;
}
};
Ok(
SearchResponse {
op: self.op.to_string(),
+ type_: data.type_.to_owned(),
comments: comments,
posts: posts,
+ communities: communities,
+ users: users,
}
)
}
}
+
+impl Perform<GetSiteResponse> for Oper<TransferSite> {
+ fn perform(&self) -> Result<GetSiteResponse, Error> {
+ let data: &TransferSite = &self.data;
+ let conn = establish_connection();
+
+ let claims = match Claims::decode(&data.auth) {
+ Ok(claims) => claims.claims,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "not_logged_in"))?
+ }
+ };
+
+ let user_id = claims.id;
+
+ let read_site = Site::read(&conn, 1)?;
+
+ // Make sure user is the creator
+ if read_site.creator_id != user_id {
+ return Err(APIError::err(&self.op, "not_an_admin"))?
+ }
+
+ let site_form = SiteForm {
+ name: read_site.name,
+ description: read_site.description,
+ creator_id: data.user_id,
+ updated: Some(naive_now()),
+ };
+
+ match Site::update(&conn, 1, &site_form) {
+ Ok(site) => site,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "couldnt_update_site"))?
+ }
+ };
+
+ // Mod tables
+ let form = ModAddForm {
+ mod_user_id: user_id,
+ other_user_id: data.user_id,
+ removed: Some(false),
+ };
+
+ ModAdd::create(&conn, &form)?;
+
+ let site_view = SiteView::read(&conn)?;
+
+ let mut admins = UserView::admins(&conn)?;
+ let creator_index = admins.iter().position(|r| r.id == site_view.creator_id).unwrap();
+ let creator_user = admins.remove(creator_index);
+ admins.insert(0, creator_user);
+
+ let banned = UserView::banned(&conn)?;
+
+ Ok(
+ GetSiteResponse {
+ op: self.op.to_string(),
+ site: Some(site_view),
+ admins: admins,
+ banned: banned,
+ }
+ )
+ }
+}
+
password: String,
password_verify: String,
admin: bool,
+ show_nsfw: bool,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct SaveUserSettings {
+ show_nsfw: bool,
+ auth: String,
}
#[derive(Serialize, Deserialize)]
// Fetch that username / email
let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) {
Ok(user) => user,
- Err(_e) => return Err(APIError::err(&self.op, "Couldn't find that username or email"))?
+ Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email"))?
};
// Verify the password
let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
if !valid {
- return Err(APIError::err(&self.op, "Password incorrect"))?
+ return Err(APIError::err(&self.op, "password_incorrect"))?
}
// Return the jwt
// Make sure passwords match
if &data.password != &data.password_verify {
- return Err(APIError::err(&self.op, "Passwords do not match."))?
+ return Err(APIError::err(&self.op, "passwords_dont_match"))?
}
if has_slurs(&data.username) {
- return Err(APIError::err(&self.op, "No slurs"))?
+ return Err(APIError::err(&self.op, "no_slurs"))?
}
// Make sure there are no admins
if data.admin && UserView::admins(&conn)?.len() > 0 {
- return Err(APIError::err(&self.op, "Sorry, there's already an admin."))?
+ return Err(APIError::err(&self.op, "admin_already_created"))?
}
// Register the new user
updated: None,
admin: data.admin,
banned: false,
+ show_nsfw: data.show_nsfw,
};
// Create the user
let inserted_user = match User_::register(&conn, &user_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "User already exists."))?
+ return Err(APIError::err(&self.op, "user_already_exists"))?
+ }
+ };
+
+ // Create the main community if it doesn't exist
+ let main_community: Community = match Community::read(&conn, 2) {
+ Ok(c) => c,
+ Err(_e) => {
+ let community_form = CommunityForm {
+ name: "main".to_string(),
+ title: "The Default Community".to_string(),
+ description: Some("The Default Community".to_string()),
+ category_id: 1,
+ nsfw: false,
+ creator_id: inserted_user.id,
+ removed: None,
+ deleted: None,
+ updated: None,
+ };
+ Community::create(&conn, &community_form).unwrap()
}
};
// Sign them up for main community no matter what
let community_follower_form = CommunityFollowerForm {
- community_id: 1,
+ community_id: main_community.id,
user_id: inserted_user.id,
};
let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community follower already exists."))?
+ return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
};
// If its an admin, add them as a mod and follower to main
if data.admin {
let community_moderator_form = CommunityModeratorForm {
- community_id: 1,
+ community_id: main_community.id,
user_id: inserted_user.id,
};
let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Community moderator already exists."))?
+ return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
}
};
}
}
+impl Perform<LoginResponse> for Oper<SaveUserSettings> {
+ fn perform(&self) -> Result<LoginResponse, Error> {
+ let data: &SaveUserSettings = &self.data;
+ let conn = establish_connection();
+
+ let claims = match Claims::decode(&data.auth) {
+ Ok(claims) => claims.claims,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "not_logged_in"))?
+ }
+ };
+
+ let user_id = claims.id;
+
+ let read_user = User_::read(&conn, user_id)?;
+
+ let user_form = UserForm {
+ name: read_user.name,
+ fedi_name: read_user.fedi_name,
+ email: read_user.email,
+ password_encrypted: read_user.password_encrypted,
+ preferred_username: read_user.preferred_username,
+ updated: Some(naive_now()),
+ admin: read_user.admin,
+ banned: read_user.banned,
+ show_nsfw: data.show_nsfw,
+ };
+
+ let updated_user = match User_::update(&conn, user_id, &user_form) {
+ Ok(user) => user,
+ Err(_e) => {
+ return Err(APIError::err(&self.op, "couldnt_update_user"))?
+ }
+ };
+
+ // Return the jwt
+ Ok(
+ LoginResponse {
+ op: self.op.to_string(),
+ jwt: updated_user.jwt()
+ }
+ )
+ }
+}
impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
fn perform(&self) -> Result<GetUserDetailsResponse, Error> {
let data: &GetUserDetails = &self.data;
let conn = establish_connection();
- let user_id: Option<i32> = match &data.auth {
+ let user_claims: Option<Claims> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Ok(claims) => {
- let user_id = claims.claims.id;
- Some(user_id)
+ Some(claims.claims)
}
Err(_e) => None
}
}
None => None
};
+
+ let user_id = match &user_claims {
+ Some(claims) => Some(claims.id),
+ None => None
+ };
+
+ let show_nsfw = match &user_claims {
+ Some(claims) => claims.show_nsfw,
+ None => false
+ };
//TODO add save
let sort = SortType::from_str(&data.sort)?;
// If its saved only, you don't care what creator it was
let posts = if data.saved_only {
- PostView::list(&conn,
- PostListingType::All,
- &sort,
- data.community_id,
- None,
- None,
- Some(user_details_id),
- data.saved_only,
- false,
- data.page,
- data.limit)?
+ PostView::list(
+ &conn,
+ PostListingType::All,
+ &sort,
+ data.community_id,
+ None,
+ None,
+ None,
+ Some(user_details_id),
+ show_nsfw,
+ data.saved_only,
+ false,
+ data.page,
+ data.limit)?
} else {
- PostView::list(&conn,
- PostListingType::All,
- &sort,
- data.community_id,
- Some(user_details_id),
- None,
- user_id,
- data.saved_only,
- false,
- data.page,
- data.limit)?
+ PostView::list(
+ &conn,
+ PostListingType::All,
+ &sort,
+ data.community_id,
+ Some(user_details_id),
+ None,
+ None,
+ user_id,
+ show_nsfw,
+ data.saved_only,
+ false,
+ data.page,
+ data.limit)?
};
let comments = if data.saved_only {
- CommentView::list(&conn,
- &sort,
- None,
- None,
- None,
- Some(user_details_id),
- data.saved_only,
- data.page,
- data.limit)?
+ CommentView::list(
+ &conn,
+ &sort,
+ None,
+ None,
+ None,
+ Some(user_details_id),
+ data.saved_only,
+ data.page,
+ data.limit)?
} else {
- CommentView::list(&conn,
- &sort,
- None,
- Some(user_details_id),
- None,
- user_id,
- data.saved_only,
- data.page,
- data.limit)?
+ CommentView::list(
+ &conn,
+ &sort,
+ None,
+ Some(user_details_id),
+ None,
+ user_id,
+ data.saved_only,
+ data.page,
+ data.limit)?
};
let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
// Make sure user is an admin
if UserView::read(&conn, user_id)?.admin == false {
- return Err(APIError::err(&self.op, "Not an admin."))?
+ return Err(APIError::err(&self.op, "not_an_admin"))?
}
let read_user = User_::read(&conn, data.user_id)?;
updated: Some(naive_now()),
admin: data.added,
banned: read_user.banned,
+ show_nsfw: read_user.show_nsfw,
};
match User_::update(&conn, data.user_id, &user_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update user"))?
+ return Err(APIError::err(&self.op, "couldnt_update_user"))?
}
};
ModAdd::create(&conn, &form)?;
- let admins = UserView::admins(&conn)?;
+ let site_creator_id = Site::read(&conn, 1)?.creator_id;
+ let mut admins = UserView::admins(&conn)?;
+ let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap();
+ let creator_user = admins.remove(creator_index);
+ admins.insert(0, creator_user);
Ok(
AddAdminResponse {
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
// Make sure user is an admin
if UserView::read(&conn, user_id)?.admin == false {
- return Err(APIError::err(&self.op, "Not an admin."))?
+ return Err(APIError::err(&self.op, "not_an_admin"))?
}
let read_user = User_::read(&conn, data.user_id)?;
updated: Some(naive_now()),
admin: read_user.admin,
banned: data.ban,
+ show_nsfw: read_user.show_nsfw,
};
match User_::update(&conn, data.user_id, &user_form) {
Ok(user) => user,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update user"))?
+ return Err(APIError::err(&self.op, "couldnt_update_user"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
- return Err(APIError::err(&self.op, "Not logged in."))?
+ return Err(APIError::err(&self.op, "not_logged_in"))?
}
};
let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
Ok(comment) => comment,
Err(_e) => {
- return Err(APIError::err(&self.op, "Couldn't update Comment"))?
+ return Err(APIError::err(&self.op, "couldnt_update_comment"))?
}
};
}
extern crate activitypub;
use self::activitypub::{context, actor::Person};
-use db::user::User_;
+use crate::db::user::User_;
impl User_ {
pub fn person(&self) -> Person {
- use {Settings, to_datetime_utc};
+ use crate::{Settings, to_datetime_utc};
let base_url = &format!("{}/user/{}", Settings::get().api_endpoint(), self.name);
let mut person = Person::default();
person.object_props.set_context_object(context()).ok();
#[cfg(test)]
mod tests {
use super::User_;
- use naive_now;
+ use crate::naive_now;
#[test]
fn test_person() {
published: naive_now(),
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let person = expected_user.person();
-use schema::{category};
-use schema::category::dsl::*;
+use crate::schema::{category};
+use crate::schema::category::dsl::*;
use super::*;
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-use schema::{comment, comment_like, comment_saved};
+use crate::schema::{comment, comment_like, comment_saved};
use super::*;
use super::post::Post;
impl Crud<CommentForm> for Comment {
fn read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
- use schema::comment::dsl::*;
+ use crate::schema::comment::dsl::*;
comment.find(comment_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, comment_id: i32) -> Result<usize, Error> {
- use schema::comment::dsl::*;
+ use crate::schema::comment::dsl::*;
diesel::delete(comment.find(comment_id))
.execute(conn)
}
fn create(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
- use schema::comment::dsl::*;
+ use crate::schema::comment::dsl::*;
insert_into(comment)
.values(comment_form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, comment_id: i32, comment_form: &CommentForm) -> Result<Self, Error> {
- use schema::comment::dsl::*;
+ use crate::schema::comment::dsl::*;
diesel::update(comment.find(comment_id))
.set(comment_form)
.get_result::<Self>(conn)
impl Likeable <CommentLikeForm> for CommentLike {
fn read(conn: &PgConnection, comment_id_from: i32) -> Result<Vec<Self>, Error> {
- use schema::comment_like::dsl::*;
+ use crate::schema::comment_like::dsl::*;
comment_like
.filter(comment_id.eq(comment_id_from))
.load::<Self>(conn)
}
fn like(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<Self, Error> {
- use schema::comment_like::dsl::*;
+ use crate::schema::comment_like::dsl::*;
insert_into(comment_like)
.values(comment_like_form)
.get_result::<Self>(conn)
}
fn remove(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<usize, Error> {
- use schema::comment_like::dsl::*;
- diesel::delete(comment_like
- .filter(comment_id.eq(comment_like_form.comment_id))
- .filter(user_id.eq(comment_like_form.user_id)))
+ use crate::schema::comment_like::dsl::*;
+ diesel::delete(
+ comment_like
+ .filter(comment_id.eq(comment_like_form.comment_id))
+ .filter(user_id.eq(comment_like_form.user_id)))
.execute(conn)
}
}
impl CommentLike {
pub fn from_post(conn: &PgConnection, post_id_from: i32) -> Result<Vec<Self>, Error> {
- use schema::comment_like::dsl::*;
+ use crate::schema::comment_like::dsl::*;
comment_like
.filter(post_id.eq(post_id_from))
.load::<Self>(conn)
impl Saveable <CommentSavedForm> for CommentSaved {
fn save(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<Self, Error> {
- use schema::comment_saved::dsl::*;
+ use crate::schema::comment_saved::dsl::*;
insert_into(comment_saved)
.values(comment_saved_form)
.get_result::<Self>(conn)
}
fn unsave(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<usize, Error> {
- use schema::comment_saved::dsl::*;
+ use crate::schema::comment_saved::dsl::*;
diesel::delete(comment_saved
.filter(comment_id.eq(comment_saved_form.comment_id))
.filter(user_id.eq(comment_saved_form.user_id)))
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
creator_id: inserted_user.id,
removed: None,
deleted: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
removed: None,
deleted: None,
locked: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_post = Post::create(&conn, &new_post).unwrap();
}
query = match sort {
- // SortType::Hot => query.order_by(hot_rank.desc()),
+ // SortType::Hot => query.order(hot_rank.desc(), published.desc()),
SortType::New => query.order_by(published.desc()),
SortType::TopAll => query.order_by(score.desc()),
SortType::TopYear => query
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
creator_id: inserted_user.id,
removed: None,
deleted: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
removed: None,
deleted: None,
locked: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_post = Post::create(&conn, &new_post).unwrap();
-use schema::{community, community_moderator, community_follower, community_user_ban, site};
+use crate::schema::{community, community_moderator, community_follower, community_user_ban, site};
use super::*;
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
+ pub nsfw: bool,
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
pub removed: Option<bool>,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: Option<bool>,
+ pub nsfw: bool,
}
impl Crud<CommunityForm> for Community {
fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> {
- use schema::community::dsl::*;
+ use crate::schema::community::dsl::*;
community.find(community_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> {
- use schema::community::dsl::*;
+ use crate::schema::community::dsl::*;
diesel::delete(community.find(community_id))
.execute(conn)
}
fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
- use schema::community::dsl::*;
+ use crate::schema::community::dsl::*;
insert_into(community)
.values(new_community)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, community_id: i32, new_community: &CommunityForm) -> Result<Self, Error> {
- use schema::community::dsl::*;
+ use crate::schema::community::dsl::*;
diesel::update(community.find(community_id))
.set(new_community)
.get_result::<Self>(conn)
impl Community {
pub fn read_from_name(conn: &PgConnection, community_name: String) -> Result<Self, Error> {
- use schema::community::dsl::*;
+ use crate::schema::community::dsl::*;
community.filter(name.eq(community_name))
.first::<Self>(conn)
}
impl Joinable<CommunityModeratorForm> for CommunityModerator {
fn join(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<Self, Error> {
- use schema::community_moderator::dsl::*;
+ use crate::schema::community_moderator::dsl::*;
insert_into(community_moderator)
.values(community_user_form)
.get_result::<Self>(conn)
}
fn leave(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<usize, Error> {
- use schema::community_moderator::dsl::*;
+ use crate::schema::community_moderator::dsl::*;
diesel::delete(community_moderator
.filter(community_id.eq(community_user_form.community_id))
.filter(user_id.eq(community_user_form.user_id)))
}
}
+impl CommunityModerator {
+ pub fn delete_for_community(conn: &PgConnection, for_community_id: i32) -> Result<usize, Error> {
+ use crate::schema::community_moderator::dsl::*;
+ diesel::delete(
+ community_moderator
+ .filter(community_id.eq(for_community_id)))
+ .execute(conn)
+ }
+}
+
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Community)]
#[table_name = "community_user_ban"]
impl Bannable<CommunityUserBanForm> for CommunityUserBan {
fn ban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<Self, Error> {
- use schema::community_user_ban::dsl::*;
+ use crate::schema::community_user_ban::dsl::*;
insert_into(community_user_ban)
.values(community_user_ban_form)
.get_result::<Self>(conn)
}
fn unban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<usize, Error> {
- use schema::community_user_ban::dsl::*;
+ use crate::schema::community_user_ban::dsl::*;
diesel::delete(community_user_ban
.filter(community_id.eq(community_user_ban_form.community_id))
.filter(user_id.eq(community_user_ban_form.user_id)))
impl Followable<CommunityFollowerForm> for CommunityFollower {
fn follow(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<Self, Error> {
- use schema::community_follower::dsl::*;
+ use crate::schema::community_follower::dsl::*;
insert_into(community_follower)
.values(community_follower_form)
.get_result::<Self>(conn)
}
fn ignore(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<usize, Error> {
- use schema::community_follower::dsl::*;
+ use crate::schema::community_follower::dsl::*;
diesel::delete(community_follower
.filter(community_id.eq(&community_follower_form.community_id))
.filter(user_id.eq(&community_follower_form.user_id)))
impl Crud<SiteForm> for Site {
fn read(conn: &PgConnection, _site_id: i32) -> Result<Self, Error> {
- use schema::site::dsl::*;
+ use crate::schema::site::dsl::*;
site.first::<Self>(conn)
}
fn delete(conn: &PgConnection, site_id: i32) -> Result<usize, Error> {
- use schema::site::dsl::*;
+ use crate::schema::site::dsl::*;
diesel::delete(site.find(site_id))
.execute(conn)
}
fn create(conn: &PgConnection, new_site: &SiteForm) -> Result<Self, Error> {
- use schema::site::dsl::*;
+ use crate::schema::site::dsl::*;
insert_into(site)
.values(new_site)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result<Self, Error> {
- use schema::site::dsl::*;
+ use crate::schema::site::dsl::*;
diesel::update(site.find(site_id))
.set(new_site)
.get_result::<Self>(conn)
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
title: "nada".to_owned(),
description: None,
category_id: 1,
+ nsfw: false,
removed: None,
deleted: None,
updated: None,
title: "nada".to_owned(),
description: None,
category_id: 1,
+ nsfw: false,
removed: false,
deleted: false,
published: inserted_community.published,
published -> Timestamp,
updated -> Nullable<Timestamp>,
deleted -> Bool,
+ nsfw -> Bool,
creator_name -> Varchar,
category_name -> Varchar,
number_of_subscribers -> BigInt,
}
table! {
- site_view (id) {
- id -> Int4,
- name -> Varchar,
- description -> Nullable<Text>,
- creator_id -> Int4,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- creator_name -> Varchar,
- number_of_users -> BigInt,
- number_of_posts -> BigInt,
- number_of_comments -> BigInt,
- }
+ site_view (id) {
+ id -> Int4,
+ name -> Varchar,
+ description -> Nullable<Text>,
+ creator_id -> Int4,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ creator_name -> Varchar,
+ number_of_users -> BigInt,
+ number_of_posts -> BigInt,
+ number_of_comments -> BigInt,
+ number_of_communities -> BigInt,
+ }
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
+ pub nsfw: bool,
pub creator_name: String,
pub category_name: String,
pub number_of_subscribers: i64,
query.first::<Self>(conn)
}
- pub fn list(conn: &PgConnection,
- from_user_id: Option<i32>,
- sort: SortType,
- page: Option<i64>,
- limit: Option<i64>,
- ) -> Result<Vec<Self>, Error> {
+ pub fn list(
+ conn: &PgConnection,
+ sort: &SortType,
+ from_user_id: Option<i32>,
+ show_nsfw: bool,
+ search_term: Option<String>,
+ page: Option<i64>,
+ limit: Option<i64>,
+ ) -> Result<Vec<Self>, Error> {
use super::community_view::community_view::dsl::*;
let mut query = community_view.into_boxed();
let (limit, offset) = limit_and_offset(page, limit);
+ if let Some(search_term) = search_term {
+ query = query.filter(name.ilike(fuzzy_search(&search_term)));
+ };
+
// The view lets you pass a null user_id, if you're not logged in
match sort {
- SortType::Hot => query = query.order_by(hot_rank.desc()).filter(user_id.is_null()),
- SortType::New => query = query.order_by(published.desc()).filter(user_id.is_null()),
- SortType::TopAll => {
- match from_user_id {
- Some(from_user_id) => query = query.filter(user_id.eq(from_user_id)).order_by((subscribed.asc(), number_of_subscribers.desc())),
- None => query = query.order_by(number_of_subscribers.desc()).filter(user_id.is_null())
+ SortType::Hot => query = query.order_by(hot_rank.desc())
+ .then_order_by(number_of_subscribers.desc())
+ .filter(user_id.is_null()),
+ SortType::New => query = query.order_by(published.desc()).filter(user_id.is_null()),
+ SortType::TopAll => {
+ match from_user_id {
+ Some(from_user_id) => query = query.filter(user_id.eq(from_user_id)).order_by((subscribed.asc(), number_of_subscribers.desc())),
+ None => query = query.order_by(number_of_subscribers.desc()).filter(user_id.is_null())
+ }
}
- }
_ => ()
};
+ if !show_nsfw {
+ query = query.filter(nsfw.eq(false));
+ };
+
query
.limit(limit)
.offset(offset)
pub number_of_users: i64,
pub number_of_posts: i64,
pub number_of_comments: i64,
+ pub number_of_communities: i64,
}
impl SiteView {
use diesel::*;
use diesel::dsl::*;
use diesel::result::Error;
-use {Settings};
+use crate::{Settings};
use serde::{Deserialize, Serialize};
pub mod user;
#[derive(EnumString,ToString,Debug, Serialize, Deserialize)]
pub enum SearchType {
- Both, Comments, Posts
+ All, Comments, Posts, Communities, Users, Url
}
pub fn fuzzy_search(q: &str) -> String {
-use schema::{mod_remove_post, mod_lock_post, mod_remove_comment, mod_remove_community, mod_ban_from_community, mod_ban, mod_add_community, mod_add};
+use crate::schema::{mod_remove_post, mod_lock_post, mod_remove_comment, mod_remove_community, mod_ban_from_community, mod_ban, mod_add_community, mod_add};
use super::*;
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
impl Crud<ModRemovePostForm> for ModRemovePost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_remove_post::dsl::*;
+ use crate::schema::mod_remove_post::dsl::*;
mod_remove_post.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_remove_post::dsl::*;
+ use crate::schema::mod_remove_post::dsl::*;
diesel::delete(mod_remove_post.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModRemovePostForm) -> Result<Self, Error> {
- use schema::mod_remove_post::dsl::*;
+ use crate::schema::mod_remove_post::dsl::*;
insert_into(mod_remove_post)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModRemovePostForm) -> Result<Self, Error> {
- use schema::mod_remove_post::dsl::*;
+ use crate::schema::mod_remove_post::dsl::*;
diesel::update(mod_remove_post.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModLockPostForm> for ModLockPost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_lock_post::dsl::*;
+ use crate::schema::mod_lock_post::dsl::*;
mod_lock_post.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_lock_post::dsl::*;
+ use crate::schema::mod_lock_post::dsl::*;
diesel::delete(mod_lock_post.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModLockPostForm) -> Result<Self, Error> {
- use schema::mod_lock_post::dsl::*;
+ use crate::schema::mod_lock_post::dsl::*;
insert_into(mod_lock_post)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModLockPostForm) -> Result<Self, Error> {
- use schema::mod_lock_post::dsl::*;
+ use crate::schema::mod_lock_post::dsl::*;
diesel::update(mod_lock_post.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModRemoveCommentForm> for ModRemoveComment {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_remove_comment::dsl::*;
+ use crate::schema::mod_remove_comment::dsl::*;
mod_remove_comment.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_remove_comment::dsl::*;
+ use crate::schema::mod_remove_comment::dsl::*;
diesel::delete(mod_remove_comment.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModRemoveCommentForm) -> Result<Self, Error> {
- use schema::mod_remove_comment::dsl::*;
+ use crate::schema::mod_remove_comment::dsl::*;
insert_into(mod_remove_comment)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModRemoveCommentForm) -> Result<Self, Error> {
- use schema::mod_remove_comment::dsl::*;
+ use crate::schema::mod_remove_comment::dsl::*;
diesel::update(mod_remove_comment.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_remove_community::dsl::*;
+ use crate::schema::mod_remove_community::dsl::*;
mod_remove_community.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_remove_community::dsl::*;
+ use crate::schema::mod_remove_community::dsl::*;
diesel::delete(mod_remove_community.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModRemoveCommunityForm) -> Result<Self, Error> {
- use schema::mod_remove_community::dsl::*;
+ use crate::schema::mod_remove_community::dsl::*;
insert_into(mod_remove_community)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModRemoveCommunityForm) -> Result<Self, Error> {
- use schema::mod_remove_community::dsl::*;
+ use crate::schema::mod_remove_community::dsl::*;
diesel::update(mod_remove_community.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_ban_from_community::dsl::*;
+ use crate::schema::mod_ban_from_community::dsl::*;
mod_ban_from_community.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_ban_from_community::dsl::*;
+ use crate::schema::mod_ban_from_community::dsl::*;
diesel::delete(mod_ban_from_community.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModBanFromCommunityForm) -> Result<Self, Error> {
- use schema::mod_ban_from_community::dsl::*;
+ use crate::schema::mod_ban_from_community::dsl::*;
insert_into(mod_ban_from_community)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModBanFromCommunityForm) -> Result<Self, Error> {
- use schema::mod_ban_from_community::dsl::*;
+ use crate::schema::mod_ban_from_community::dsl::*;
diesel::update(mod_ban_from_community.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModBanForm> for ModBan {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_ban::dsl::*;
+ use crate::schema::mod_ban::dsl::*;
mod_ban.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_ban::dsl::*;
+ use crate::schema::mod_ban::dsl::*;
diesel::delete(mod_ban.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModBanForm) -> Result<Self, Error> {
- use schema::mod_ban::dsl::*;
+ use crate::schema::mod_ban::dsl::*;
insert_into(mod_ban)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModBanForm) -> Result<Self, Error> {
- use schema::mod_ban::dsl::*;
+ use crate::schema::mod_ban::dsl::*;
diesel::update(mod_ban.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModAddCommunityForm> for ModAddCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_add_community::dsl::*;
+ use crate::schema::mod_add_community::dsl::*;
mod_add_community.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_add_community::dsl::*;
+ use crate::schema::mod_add_community::dsl::*;
diesel::delete(mod_add_community.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModAddCommunityForm) -> Result<Self, Error> {
- use schema::mod_add_community::dsl::*;
+ use crate::schema::mod_add_community::dsl::*;
insert_into(mod_add_community)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModAddCommunityForm) -> Result<Self, Error> {
- use schema::mod_add_community::dsl::*;
+ use crate::schema::mod_add_community::dsl::*;
diesel::update(mod_add_community.find(from_id))
.set(form)
.get_result::<Self>(conn)
impl Crud<ModAddForm> for ModAdd {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
- use schema::mod_add::dsl::*;
+ use crate::schema::mod_add::dsl::*;
mod_add.find(from_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
- use schema::mod_add::dsl::*;
+ use crate::schema::mod_add::dsl::*;
diesel::delete(mod_add.find(from_id))
.execute(conn)
}
fn create(conn: &PgConnection, form: &ModAddForm) -> Result<Self, Error> {
- use schema::mod_add::dsl::*;
+ use crate::schema::mod_add::dsl::*;
insert_into(mod_add)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModAddForm) -> Result<Self, Error> {
- use schema::mod_add::dsl::*;
+ use crate::schema::mod_add::dsl::*;
diesel::update(mod_add.find(from_id))
.set(form)
.get_result::<Self>(conn)
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_mod = User_::create(&conn, &new_mod).unwrap();
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
creator_id: inserted_user.id,
removed: None,
deleted: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
removed: None,
deleted: None,
locked: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_post = Post::create(&conn, &new_post).unwrap();
-use schema::{post, post_like, post_saved, post_read};
+use crate::schema::{post, post_like, post_saved, post_read};
use super::*;
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
+ pub nsfw: bool,
}
#[derive(Insertable, AsChangeset, Clone)]
pub locked: Option<bool>,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: Option<bool>,
+ pub nsfw: bool,
}
impl Crud<PostForm> for Post {
fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
- use schema::post::dsl::*;
+ use crate::schema::post::dsl::*;
post.find(post_id)
.first::<Self>(conn)
}
fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> {
- use schema::post::dsl::*;
+ use crate::schema::post::dsl::*;
diesel::delete(post.find(post_id))
.execute(conn)
}
fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
- use schema::post::dsl::*;
+ use crate::schema::post::dsl::*;
insert_into(post)
.values(new_post)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> {
- use schema::post::dsl::*;
+ use crate::schema::post::dsl::*;
diesel::update(post.find(post_id))
.set(new_post)
.get_result::<Self>(conn)
impl Likeable <PostLikeForm> for PostLike {
fn read(conn: &PgConnection, post_id_from: i32) -> Result<Vec<Self>, Error> {
- use schema::post_like::dsl::*;
+ use crate::schema::post_like::dsl::*;
post_like
.filter(post_id.eq(post_id_from))
.load::<Self>(conn)
}
fn like(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<Self, Error> {
- use schema::post_like::dsl::*;
+ use crate::schema::post_like::dsl::*;
insert_into(post_like)
.values(post_like_form)
.get_result::<Self>(conn)
}
fn remove(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<usize, Error> {
- use schema::post_like::dsl::*;
+ use crate::schema::post_like::dsl::*;
diesel::delete(post_like
.filter(post_id.eq(post_like_form.post_id))
.filter(user_id.eq(post_like_form.user_id)))
impl Saveable <PostSavedForm> for PostSaved {
fn save(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<Self, Error> {
- use schema::post_saved::dsl::*;
+ use crate::schema::post_saved::dsl::*;
insert_into(post_saved)
.values(post_saved_form)
.get_result::<Self>(conn)
}
fn unsave(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
- use schema::post_saved::dsl::*;
+ use crate::schema::post_saved::dsl::*;
diesel::delete(post_saved
.filter(post_id.eq(post_saved_form.post_id))
.filter(user_id.eq(post_saved_form.user_id)))
impl Readable <PostReadForm> for PostRead {
fn mark_as_read(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<Self, Error> {
- use schema::post_read::dsl::*;
+ use crate::schema::post_read::dsl::*;
insert_into(post_read)
.values(post_read_form)
.get_result::<Self>(conn)
}
fn mark_as_unread(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<usize, Error> {
- use schema::post_read::dsl::*;
+ use crate::schema::post_read::dsl::*;
diesel::delete(post_read
.filter(post_id.eq(post_read_form.post_id))
.filter(user_id.eq(post_read_form.user_id)))
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
creator_id: inserted_user.id,
removed: None,
deleted: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
removed: None,
deleted: None,
locked: None,
+ nsfw: false,
updated: None
};
published: inserted_post.published,
removed: false,
locked: false,
+ nsfw: false,
deleted: false,
updated: None
};
published -> Timestamp,
updated -> Nullable<Timestamp>,
deleted -> Bool,
+ nsfw -> Bool,
creator_name -> Varchar,
community_name -> Varchar,
community_removed -> Bool,
community_deleted -> Bool,
+ community_nsfw -> Bool,
number_of_comments -> BigInt,
score -> BigInt,
upvotes -> BigInt,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool,
+ pub nsfw: bool,
pub creator_name: String,
pub community_name: String,
pub community_removed: bool,
pub community_deleted: bool,
+ pub community_nsfw: bool,
pub number_of_comments: i64,
pub score: i64,
pub upvotes: i64,
}
impl PostView {
- pub fn list(conn: &PgConnection,
- type_: PostListingType,
- sort: &SortType,
- for_community_id: Option<i32>,
- for_creator_id: Option<i32>,
- search_term: Option<String>,
- my_user_id: Option<i32>,
- saved_only: bool,
- unread_only: bool,
- page: Option<i64>,
- limit: Option<i64>,
- ) -> Result<Vec<Self>, Error> {
+ pub fn list(
+ conn: &PgConnection,
+ type_: PostListingType,
+ sort: &SortType,
+ for_community_id: Option<i32>,
+ for_creator_id: Option<i32>,
+ search_term: Option<String>,
+ url_search: Option<String>,
+ my_user_id: Option<i32>,
+ show_nsfw: bool,
+ saved_only: bool,
+ unread_only: bool,
+ page: Option<i64>,
+ limit: Option<i64>,
+ ) -> Result<Vec<Self>, Error> {
use super::post_view::post_view::dsl::*;
let (limit, offset) = limit_and_offset(page, limit);
query = query.filter(name.ilike(fuzzy_search(&search_term)));
};
+ if let Some(url_search) = url_search {
+ query = query.filter(url.eq(url_search));
+ };
+
// TODO these are wrong, bc they'll only show saved for your logged in user, not theirs
if saved_only {
query = query.filter(saved.eq(true));
query = query.filter(user_id.is_null());
}
+ if !show_nsfw {
+ query = query
+ .filter(nsfw.eq(false))
+ .filter(community_nsfw.eq(false));
+ };
+
query = match sort {
- SortType::Hot => query.order_by(hot_rank.desc()),
+ SortType::Hot => query.order_by(hot_rank.desc())
+ .then_order_by(published.desc()),
SortType::New => query.order_by(published.desc()),
SortType::TopAll => query.order_by(score.desc()),
SortType::TopYear => query
updated: None,
admin: false,
banned: false,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
category_id: 1,
removed: None,
deleted: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
removed: None,
deleted: None,
locked: None,
- updated: None
+ updated: None,
+ nsfw: false,
};
let inserted_post = Post::create(&conn, &new_post).unwrap();
community_name: community_name.to_owned(),
community_removed: false,
community_deleted: false,
+ community_nsfw: false,
number_of_comments: 0,
score: 1,
upvotes: 1,
subscribed: None,
read: None,
saved: None,
+ nsfw: false,
};
let expected_post_listing_with_user = PostView {
community_name: community_name.to_owned(),
community_removed: false,
community_deleted: false,
+ community_nsfw: false,
number_of_comments: 0,
score: 1,
upvotes: 1,
subscribed: None,
read: None,
saved: None,
+ nsfw: false,
};
- let read_post_listings_with_user = PostView::list(&conn,
- PostListingType::Community,
- &SortType::New, Some(inserted_community.id),
- None,
- None,
- Some(inserted_user.id),
- false,
- false,
- None,
- None).unwrap();
- let read_post_listings_no_user = PostView::list(&conn,
- PostListingType::Community,
- &SortType::New,
- Some(inserted_community.id),
- None,
- None,
- None,
- false,
- false,
- None,
- None).unwrap();
+ let read_post_listings_with_user = PostView::list(
+ &conn,
+ PostListingType::Community,
+ &SortType::New,
+ Some(inserted_community.id),
+ None,
+ None,
+ None,
+ Some(inserted_user.id),
+ false,
+ false,
+ false,
+ None,
+ None).unwrap();
+ let read_post_listings_no_user = PostView::list(
+ &conn,
+ PostListingType::Community,
+ &SortType::New,
+ Some(inserted_community.id),
+ None,
+ None,
+ None,
+ None,
+ false,
+ false,
+ false,
+ None,
+ None).unwrap();
let read_post_listing_no_user = PostView::read(&conn, inserted_post.id, None).unwrap();
let read_post_listing_with_user = PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap();
-use schema::user_;
-use schema::user_::dsl::*;
+use crate::schema::user_;
+use crate::schema::user_::dsl::*;
use super::*;
-use {Settings, is_email_regex};
+use crate::{Settings, is_email_regex};
use jsonwebtoken::{encode, decode, Header, Validation, TokenData};
use bcrypt::{DEFAULT_COST, hash};
pub admin: bool,
pub banned: bool,
pub published: chrono::NaiveDateTime,
- pub updated: Option<chrono::NaiveDateTime>
+ pub updated: Option<chrono::NaiveDateTime>,
+ pub show_nsfw: bool,
}
#[derive(Insertable, AsChangeset, Clone)]
pub admin: bool,
pub banned: bool,
pub email: Option<String>,
- pub updated: Option<chrono::NaiveDateTime>
+ pub updated: Option<chrono::NaiveDateTime>,
+ pub show_nsfw: bool,
}
impl Crud<UserForm> for User_ {
fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
- use schema::user_::dsl::*;
+ use crate::schema::user_::dsl::*;
user_.find(user_id)
.first::<Self>(conn)
}
pub id: i32,
pub username: String,
pub iss: String,
+ pub show_nsfw: bool,
}
impl Claims {
id: self.id,
username: self.name.to_owned(),
iss: self.fedi_name.to_owned(),
+ show_nsfw: self.show_nsfw,
};
encode(&Header::default(), &my_claims, Settings::get().jwt_secret.as_ref()).unwrap()
}
email: None,
admin: false,
banned: false,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
admin: false,
banned: false,
published: inserted_user.published,
- updated: None
+ updated: None,
+ show_nsfw: false,
};
let read_user = User_::read(&conn, inserted_user.id).unwrap();
}
impl UserView {
+
+ pub fn list(conn: &PgConnection,
+ sort: &SortType,
+ search_term: Option<String>,
+ page: Option<i64>,
+ limit: Option<i64>,
+ ) -> Result<Vec<Self>, Error> {
+ use super::user_view::user_view::dsl::*;
+
+ let (limit, offset) = limit_and_offset(page, limit);
+
+ let mut query = user_view.into_boxed();
+
+ if let Some(search_term) = search_term {
+ query = query.filter(name.ilike(fuzzy_search(&search_term)));
+ };
+
+ query = match sort {
+ SortType::Hot => query.order_by(comment_score.desc())
+ .then_order_by(published.desc()),
+ SortType::New => query.order_by(published.desc()),
+ SortType::TopAll => query.order_by(comment_score.desc()),
+ SortType::TopYear => query
+ .filter(published.gt(now - 1.years()))
+ .order_by(comment_score.desc()),
+ SortType::TopMonth => query
+ .filter(published.gt(now - 1.months()))
+ .order_by(comment_score.desc()),
+ SortType::TopWeek => query
+ .filter(published.gt(now - 1.weeks()))
+ .order_by(comment_score.desc()),
+ SortType::TopDay => query
+ .filter(published.gt(now - 1.days()))
+ .order_by(comment_score.desc())
+ };
+
+ query = query
+ .limit(limit)
+ .offset(offset);
+
+ query.load::<Self>(conn)
+ }
+
pub fn read(conn: &PgConnection, from_user_id: i32) -> Result<Self, Error> {
use super::user_view::user_view::dsl::*;
+#![recursion_limit = "512"]
#[macro_use] pub extern crate strum_macros;
#[macro_use] pub extern crate lazy_static;
#[macro_use] pub extern crate failure;
#[cfg(test)]
mod tests {
- use {Settings, is_email_regex, remove_slurs, has_slurs};
+ use crate::{Settings, is_email_regex, remove_slurs, has_slurs};
#[test]
fn test_api() {
assert_eq!(Settings::get().api_endpoint(), "rrr/api/v1");
extern crate lemmy_server;
-#[macro_use] extern crate diesel_migrations;
+#[macro_use]
+extern crate diesel_migrations;
-use std::time::{Instant, Duration};
-use std::env;
-use lemmy_server::actix::*;
-use lemmy_server::actix_web::server::HttpServer;
-use lemmy_server::actix_web::{ws, App, Error, HttpRequest, HttpResponse, fs::NamedFile, fs};
-use lemmy_server::websocket::server::*;
+use actix::prelude::*;
+use actix_files::NamedFile;
+use actix_web::*;
+use actix_web_actors::ws;
use lemmy_server::db::establish_connection;
+use lemmy_server::websocket::server::*;
+use std::env;
+use std::time::{Duration, Instant};
embed_migrations!();
/// How long before lack of client response causes a timeout
const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);
-/// This is our websocket route state, this state is shared with all route
-/// instances via `HttpContext::state()`
-struct WsChatSessionState {
- addr: Addr<ChatServer>,
-}
-
/// Entry point for our route
-fn chat_route(req: &HttpRequest<WsChatSessionState>) -> Result<HttpResponse, Error> {
+fn chat_route(
+ req: HttpRequest,
+ stream: web::Payload,
+ chat_server: web::Data<Addr<ChatServer>>,
+ ) -> Result<HttpResponse, Error> {
ws::start(
- req,
WSSession {
+ cs_addr: chat_server.get_ref().to_owned(),
id: 0,
hb: Instant::now(),
- ip: req.connection_info()
+ ip: req
+ .connection_info()
.remote()
.unwrap_or("127.0.0.1:12345")
.split(":")
.next()
.unwrap_or("127.0.0.1")
- .to_string()
+ .to_string(),
},
+ &req,
+ stream,
)
}
struct WSSession {
+ cs_addr: Addr<ChatServer>,
/// unique session id
id: usize,
ip: String,
/// Client must send ping at least once per 10 seconds (CLIENT_TIMEOUT),
/// otherwise we drop connection.
- hb: Instant
+ hb: Instant,
}
impl Actor for WSSession {
- type Context = ws::WebsocketContext<Self, WsChatSessionState>;
+ type Context = ws::WebsocketContext<Self>;
/// Method is called on actor start.
/// We register ws session with ChatServer
// register self in chat server. `AsyncContext::wait` register
// future within context, but context waits until this future resolves
// before processing any other events.
- // HttpContext::state() is instance of WsChatSessionState, state is shared
// across all routes within application
let addr = ctx.address();
- ctx.state()
- .addr
+ self.cs_addr
.send(Connect {
addr: addr.recipient(),
ip: self.ip.to_owned(),
.wait(ctx);
}
- fn stopping(&mut self, ctx: &mut Self::Context) -> Running {
+ fn stopping(&mut self, _ctx: &mut Self::Context) -> Running {
// notify chat server
- ctx.state().addr.do_send(Disconnect {
+ self.cs_addr.do_send(Disconnect {
id: self.id,
ip: self.ip.to_owned(),
});
ws::Message::Text(text) => {
let m = text.trim().to_owned();
println!("WEBSOCKET MESSAGE: {:?} from id: {}", &m, self.id);
-
- ctx.state()
- .addr
+
+ self.cs_addr
.send(StandardMessage {
id: self.id,
msg: m,
ws::Message::Binary(_bin) => println!("Unexpected binary"),
ws::Message::Close(_) => {
ctx.stop();
- },
+ }
+ _ => {}
}
}
}
/// helper method that sends ping to client every second.
///
/// also this method checks heartbeats from client
- fn hb(&self, ctx: &mut ws::WebsocketContext<Self, WsChatSessionState>) {
+ fn hb(&self, ctx: &mut ws::WebsocketContext<Self>) {
ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
// check client heartbeats
if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
println!("Websocket Client heartbeat failed, disconnecting!");
// notify chat server
- ctx.state()
- .addr
- .do_send(Disconnect { id: act.id, ip: act.ip.to_owned() });
+ act.cs_addr.do_send(Disconnect {
+ id: act.id,
+ ip: act.ip.to_owned(),
+ });
// stop actor
ctx.stop();
embedded_migrations::run(&conn).unwrap();
// Start chat server actor in separate thread
- let server = Arbiter::start(|_| ChatServer::default());
-
+ let server = ChatServer::default().start();
// Create Http server with websocket support
HttpServer::new(move || {
- // Websocket sessions state
- let state = WsChatSessionState {
- addr: server.clone(),
- };
-
- App::with_state(state)
- // .resource("/api/v1/rest", |r| r.method(http::Method::POST).f(|_| {})
- .resource("/api/v1/ws", |r| r.route().f(chat_route))
+ App::new()
+ .data(server.clone())
+ .service(web::resource("/api/v1/ws").to(chat_route))
+ // .service(web::resource("/api/v1/rest").route(web::post().to(||{})))
+ .service(web::resource("/").to(index))
// static resources
- .resource("/", |r| r.route().f(index))
- .handler(
- "/static",
- fs::StaticFiles::new(front_end_dir()).unwrap()
- )
- .finish()
- }).bind("0.0.0.0:8536")
- .unwrap()
+ .service(actix_files::Files::new("/static", front_end_dir()))
+ })
+ .bind("0.0.0.0:8536")
+ .unwrap()
.start();
println!("Started http server: 0.0.0.0:8536");
let _ = sys.run();
}
-fn index(_req: &HttpRequest<WsChatSessionState>) -> Result<NamedFile, actix_web::error::Error> {
+fn index() -> Result<NamedFile, actix_web::error::Error> {
Ok(NamedFile::open(front_end_dir() + "/index.html")?)
}
published -> Timestamp,
updated -> Nullable<Timestamp>,
deleted -> Bool,
+ nsfw -> Bool,
}
}
published -> Timestamp,
updated -> Nullable<Timestamp>,
deleted -> Bool,
+ nsfw -> Bool,
}
}
banned -> Bool,
published -> Timestamp,
updated -> Nullable<Timestamp>,
+ show_nsfw -> Bool,
}
}
use failure::Error;
use std::time::{SystemTime};
-use api::*;
-use api::user::*;
-use api::community::*;
-use api::post::*;
-use api::comment::*;
-use api::site::*;
+use crate::api::*;
+use crate::api::user::*;
+use crate::api::community::*;
+use crate::api::post::*;
+use crate::api::comment::*;
+use crate::api::site::*;
const RATE_LIMIT_MESSAGES: i32 = 30;
const RATE_LIMIT_PER_SECOND: i32 = 60;
fn join_room(&mut self, room_id: i32, id: usize) {
// remove session from all rooms
- for (_n, mut sessions) in &mut self.rooms {
+ for (_n, sessions) in &mut self.rooms {
sessions.remove(&id);
}
}
fn send_community_message(&self, community_id: &i32, message: &str, skip_id: usize) -> Result<(), Error> {
- use db::*;
- use db::post_view::*;
+ use crate::db::*;
+ use crate::db::post_view::*;
let conn = establish_connection();
- let posts = PostView::list(&conn,
- PostListingType::Community,
- &SortType::New,
- Some(*community_id),
- None,
- None,
- None,
- false,
- false,
- None,
- Some(9999))?;
+ let posts = PostView::list(
+ &conn,
+ PostListingType::Community,
+ &SortType::New,
+ Some(*community_id),
+ None,
+ None,
+ None,
+ None,
+ false,
+ false,
+ false,
+ None,
+ Some(9999))?;
for post in posts {
self.send_room_message(&post.id, message, skip_id);
}
let res = Oper::new(user_operation, get_user_details).perform()?;
Ok(serde_json::to_string(&res)?)
},
+ UserOperation::SaveUserSettings => {
+ let save_user_settings: SaveUserSettings = serde_json::from_str(data)?;
+ let res = Oper::new(user_operation, save_user_settings).perform()?;
+ Ok(serde_json::to_string(&res)?)
+ },
UserOperation::AddAdmin => {
let add_admin: AddAdmin = serde_json::from_str(data)?;
let res = Oper::new(user_operation, add_admin).perform()?;
let res = Oper::new(user_operation, search).perform()?;
Ok(serde_json::to_string(&res)?)
},
+ UserOperation::TransferCommunity => {
+ let transfer_community: TransferCommunity = serde_json::from_str(data)?;
+ let res = Oper::new(user_operation, transfer_community).perform()?;
+ Ok(serde_json::to_string(&res)?)
+ },
+ UserOperation::TransferSite => {
+ let transfer_site: TransferSite = serde_json::from_str(data)?;
+ let res = Oper::new(user_operation, transfer_site).perform()?;
+ Ok(serde_json::to_string(&res)?)
+ },
}
}
+++ /dev/null
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: postgres
-data:
- POSTGRES_PASSWORD: rrr
- POSTGRES_USER: rrr
- POSTGRES_DB: rrr
- PGDATA: /var/lib/postgresql/data/pgdata
- DATABASE_URL: postgres://rrr:rrr@postgres:5432/rrr
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
- name: postgres
-spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 5Gi
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: postgres
-spec:
- selector:
- matchLabels:
- app: postgres
- template:
- metadata:
- labels:
- app: postgres
- spec:
- containers:
- - name: postgres
- image: postgres:11.2-alpine
- resources:
- limits:
- memory: 256Mi
- cpu: 512m
- ports:
- - containerPort: 5432
- envFrom:
- - configMapRef:
- name: postgres
- volumeMounts:
- - name: postgres
- mountPath: /var/lib/postgresql/data
- volumes:
- - name: postgres
- persistentVolumeClaim:
- claimName: postgres
----
-apiVersion: v1
-kind: Service
-metadata:
- name: postgres
-spec:
- selector:
- app: postgres
- ports:
- - port: 5432
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: lemmy-server--dev
-data:
- LEMMY_FRONT_END_DIR: /opt/lemmy/ui--dev/dist # not actually used here, polyfill for monolith
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: lemmy-server--dev
-spec:
- selector:
- matchLabels:
- app: lemmy-server--dev
- template:
- metadata:
- labels:
- app: lemmy-server--dev
- spec:
- containers:
- - name: lemmy-server--dev
- image: registry.gitlab.com/pojntfx/lemmy/server.dev
- envFrom:
- - configMapRef:
- name: postgres
- - configMapRef:
- name: lemmy-server--dev
- resources:
- limits:
- memory: 512Mi
- cpu: 512m
- ports:
- - containerPort: 8536
----
-apiVersion: v1
-kind: Service
-metadata:
- name: lemmy-server--dev
-spec:
- type: NodePort
- selector:
- app: lemmy-server--dev
- ports:
- - port: 8536
- nodePort: 30001
+++ /dev/null
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: postgres
-data:
- POSTGRES_PASSWORD: rrr
- POSTGRES_USER: rrr
- POSTGRES_DB: rrr
- PGDATA: /var/lib/postgresql/data/pgdata
- DATABASE_URL: postgres://rrr:rrr@postgres:5432/rrr
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
- name: postgres
-spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 5Gi
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: postgres
-spec:
- selector:
- matchLabels:
- app: postgres
- template:
- metadata:
- labels:
- app: postgres
- spec:
- containers:
- - name: postgres
- image: postgres:11.2-alpine
- resources:
- limits:
- memory: 256Mi
- cpu: 512m
- ports:
- - containerPort: 5432
- envFrom:
- - configMapRef:
- name: postgres
- volumeMounts:
- - name: postgres
- mountPath: /var/lib/postgresql/data
- volumes:
- - name: postgres
- persistentVolumeClaim:
- claimName: postgres
----
-apiVersion: v1
-kind: Service
-metadata:
- name: postgres
-spec:
- selector:
- app: postgres
- ports:
- - port: 5432
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: lemmy-server--prod
-data:
- LEMMY_FRONT_END_DIR: /opt/lemmy/ui--prod/dist # not actually used here, polyfill for monolith
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: lemmy-server--prod
-spec:
- selector:
- matchLabels:
- app: lemmy-server--prod
- template:
- metadata:
- labels:
- app: lemmy-server--prod
- spec:
- containers:
- - name: lemmy-server--prod
- image: registry.gitlab.com/pojntfx/lemmy/server.prod
- envFrom:
- - configMapRef:
- name: postgres
- - configMapRef:
- name: lemmy-server--prod
- resources:
- limits:
- memory: 512Mi
- cpu: 512m
- ports:
- - containerPort: 8536
----
-apiVersion: v1
-kind: Service
-metadata:
- name: lemmy-server--prod
-spec:
- selector:
- app: lemmy-server--prod
- ports:
- - port: 8536
- targetPort: 8536
+++ /dev/null
-apiVersion: skaffold/v1beta9
-kind: Config
-profiles:
- - name: lemmy--dev
- build:
- artifacts:
- - image: registry.gitlab.com/pojntfx/lemmy/server.dev
- context: server
- docker:
- dockerfile: Dockerfile.dev
- - image: registry.gitlab.com/pojntfx/lemmy/ui.dev
- context: ui
- docker:
- dockerfile: Dockerfile.dev
- sync:
- "***/*.ts": .
- "***/*.tsx": .
- "***/*.css": .
- deploy:
- kubectl:
- manifests:
- - "**/*.dev.yaml"
- - name: lemmy--prod
- build:
- artifacts:
- - image: registry.gitlab.com/pojntfx/lemmy/server.prod
- context: server
- docker:
- dockerfile: Dockerfile.prod
- - image: registry.gitlab.com/pojntfx/lemmy/ui.prod
- context: ui
- docker:
- dockerfile: Dockerfile.prod
- deploy:
- kubectl:
- manifests:
- - "**/*.prod.yaml"
+++ /dev/null
-# Setup env
-FROM node:10-alpine
-RUN mkdir -p /opt/lemmy/ui--dev
-WORKDIR /opt/lemmy/ui--dev
-# Install deps
-COPY package.json .
-COPY yarn.lock .
-RUN npm install
-# Add app
-COPY . .
-# Run app
-CMD ["npm", "start"]
+++ /dev/null
-# Setup env
-FROM node:10-alpine AS build
-RUN mkdir -p /opt/lemmy/ui--prod
-WORKDIR /opt/lemmy/ui--prod
-# Install deps
-COPY package.json .
-COPY yarn.lock .
-RUN npm install
-# Add app
-COPY . .
-# Build app
-RUN npm run build
-
-# Setup env
-FROM node:10-alpine
-RUN mkdir -p /opt/lemmy/ui--prod
-WORKDIR /opt/lemmy/ui--prod
-RUN npm install serve
-# Add app
-COPY --from=build /opt/lemmy/ui--prod/dist .
-# Run app
-CMD ["/opt/lemmy/ui--prod/node_modules/.bin/serve", "."]
-<?xml version="1.0" encoding="iso-8859-1"?>\r
-<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->\r
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"\r
- viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">\r
-<g>\r
- <g>\r
- <path d="M499.059,323.505l-7.52-32.532l-70.047,16.19c1.513-11.983,2.297-24.042,2.297-36.037c0-18.334-1.801-35.785-5.316-52.19\r
- c29.365-12.101,55.143-28.885,69.372-45.529c17.524-20.498,25.985-46.568,23.822-73.406\r
- c-2.163-26.862-14.706-51.268-35.316-68.724C433.879-4.694,369.917,0.439,333.774,42.718\r
- c-9.546,11.168-18.318,27.381-25.379,46.649c-16.512-5.419-34.132-8.243-52.395-8.243s-35.885,2.824-52.395,8.243\r
- c-7.06-19.267-15.832-35.481-25.379-46.649C142.082,0.44,78.123-4.695,35.648,31.277C15.038,48.733,2.494,73.141,0.332,100.001\r
- c-2.161,26.838,6.297,52.907,23.822,73.406c14.229,16.644,40.006,33.427,69.372,45.529c-3.515,16.405-5.316,33.856-5.316,52.189\r
- c0,11.995,0.785,24.053,2.297,36.037l-70.047-16.19l-7.52,32.532l84.337,19.492c4.349,17.217,10.201,33.953,17.421,49.752\r
- L12.941,416.27l7.52,32.532l110.634-25.57c1.38,2.197,2.779,4.373,4.218,6.509c32.548,48.323,75.409,74.934,120.687,74.934\r
- c45.278,0,88.138-26.612,120.687-74.934c1.439-2.136,2.839-4.313,4.218-6.509l110.634,25.57l7.52-32.532l-101.758-23.519\r
- c7.221-15.799,13.072-32.535,17.421-49.752L499.059,323.505z M183.578,220.372c0-11.41,9.189-20.65,20.482-20.65\r
- c11.306,0,20.494,9.24,20.494,20.65c0,11.408-9.188,20.656-20.494,20.656C192.768,241.028,183.578,231.78,183.578,220.372z\r
- M256,413.29c-29.895,0-54.216-19.471-54.216-43.403c0-23.932,24.322-43.403,54.216-43.403s54.216,19.471,54.216,43.403\r
- C310.216,393.819,285.895,413.29,256,413.29z M307.785,241.183c-11.402,0-20.65-9.317-20.65-20.81\r
- c0-11.494,9.248-20.81,20.65-20.81c11.387,0,20.635,9.317,20.635,20.81C328.422,231.866,319.173,241.183,307.785,241.183z"/>\r
- </g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-<g>\r
-</g>\r
-</svg>\r
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1024"
+ height="1024"
+ viewBox="0 0 1024 1024"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.4 (unknown)"
+ sodipodi:docname="lemmy-logo-border.svg"
+ inkscape:export-filename="/home/andres/Pictures/References/Logos/Lemmy/lemmy-logo-border.png"
+ inkscape:export-xdpi="300"
+ inkscape:export-ydpi="300"
+ enable-background="new">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.49497475"
+ inkscape:cx="452.38625"
+ inkscape:cy="470.53357"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ units="px"
+ inkscape:showpageshadow="false"
+ inkscape:window-width="1366"
+ inkscape:window-height="740"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:snap-global="true"
+ inkscape:snap-midpoints="false"
+ inkscape:snap-smooth-nodes="false"
+ inkscape:object-paths="false"
+ inkscape:pagecheckerboard="true" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-26.066658)"
+ style="display:inline">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 167.03908,270.78735 c -0.94784,-0.002 -1.8939,0.004 -2.83789,0.0215 -4.31538,0.0778 -8.58934,0.3593 -12.8125,0.8457 -33.78522,3.89116 -64.215716,21.86394 -82.871086,53.27344 -18.27982,30.77718 -22.77749,64.66635 -13.46094,96.06837 9.31655,31.40203 31.88488,59.93174 65.296886,82.5332 0.20163,0.13618 0.40678,0.26709 0.61523,0.39258 28.65434,17.27768 57.18167,28.93179 87.74218,34.95508 -0.74566,12.61339 -0.72532,25.5717 0.082,38.84375 2.43989,40.10943 16.60718,77.03742 38.0957,109.67187 l -77.00781,31.4375 c -8.30605,3.25932 -12.34178,12.68234 -8.96967,20.94324 3.37211,8.2609 12.84919,12.16798 21.06342,8.68371 l 84.69727,-34.57617 c 15.70675,18.72702 33.75346,35.68305 53.12109,50.57032 0.74013,0.56891 1.4904,1.12236 2.23437,1.68554 l -49.61132,65.69141 c -5.45446,7.0474 -4.10058,17.19288 3.01098,22.5634 7.11156,5.37052 17.24028,3.89649 22.52612,-3.27824 l 50.38672,-66.71876 c 27.68572,17.53469 57.07524,31.20388 86.07227,40.25196 14.88153,27.28008 43.96965,44.64648 77.58789,44.64648 33.93762,0 63.04252,-18.68693 77.80082,-45.4375 28.7072,-9.21295 57.7527,-22.93196 85.1484,-40.40234 l 51.0977,67.66016 c 5.2858,7.17473 15.4145,8.64876 22.5261,3.27824 7.1115,-5.37052 8.4654,-15.516 3.011,-22.5634 l -50.3614,-66.68555 c 0.334,-0.25394 0.6727,-0.50077 1.0059,-0.75586 19.1376,-14.64919 37.0259,-31.28581 52.7031,-49.63476 l 82.5625,33.70507 c 8.2143,3.48427 17.6913,-0.42281 21.0634,-8.68371 3.3722,-8.2609 -0.6636,-17.68392 -8.9696,-20.94324 l -74.5391,-30.42773 c 22.1722,-32.82971 37.0383,-70.03397 40.1426,-110.46094 1.0253,-13.35251 1.2292,-26.42535 0.6387,-39.17578 30.3557,-6.05408 58.7164,-17.66833 87.2011,-34.84375 0.2085,-0.12549 0.4136,-0.2564 0.6153,-0.39258 33.412,-22.60147 55.9803,-51.13117 65.2968,-82.5332 9.3166,-31.40202 4.8189,-65.29118 -13.4609,-96.06837 -18.6553,-31.40951 -49.0859,-49.38228 -82.8711,-53.27344 -4.2231,-0.4864 -8.4971,-0.76791 -12.8125,-0.8457 -30.2077,-0.54448 -62.4407,8.82427 -93.4316,26.71484 -22.7976,13.16063 -43.3521,33.31423 -59.4375,55.30469 -44.9968,-25.75094 -103.5444,-40.25065 -175.4785,-41.43945 -6.4522,-0.10663 -13.0125,-0.10696 -19.67974,0.002 -80.18875,1.30929 -144.38284,16.5086 -192.87109,43.9922 -0.11914,-0.19111 -0.24287,-0.37932 -0.37109,-0.56446 -16.29,-22.764 -37.41085,-43.73706 -60.89649,-57.29493 -30.02247,-17.33149 -61.21051,-26.66489 -90.59375,-26.73633 z"
+ id="path817-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccssccccccscccccscccscccscccccsccscccssccscscccscc"
+ inkscape:label="white-border"
+ sodipodi:insensitive="true" />
+ <path
+ id="path1087"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 716.85595,362.96478 c 15.29075,-21.36763 35.36198,-41.10921 56.50979,-53.31749 66.66377,-38.48393 137.02617,-33.22172 170.08018,22.43043 33.09493,55.72093 14.98656,117.48866 -47.64399,159.85496 -31.95554,19.26819 -62.93318,30.92309 -97.22892,35.54473 M 307.14407,362.96478 C 291.85332,341.59715 271.78209,321.85557 250.63429,309.64729 183.97051,271.16336 113.60811,276.42557 80.554051,332.07772 47.459131,387.79865 65.56752,449.56638 128.19809,491.93268 c 31.95554,19.26819 62.93319,30.92309 97.22893,35.54473"
+ inkscape:connector-curvature="0"
+ inkscape:label="ears"
+ sodipodi:insensitive="true" />
+ <path
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 801.23205,576.8699 C 812.73478,427.06971 720.58431,321.98291 511.99999,325.38859 303.41568,328.79426 213.71393,428.0311 222.76794,576.8699 c 8.64289,142.08048 176.80223,246.40388 288.12038,246.40388 111.31815,0 279.45076,-104.5447 290.34373,-246.40388 z"
+ id="path969"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="szszs"
+ inkscape:label="head"
+ sodipodi:insensitive="true" />
+ <path
+ id="path1084"
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 610.4991,644.28932 c 0,23.11198 18.70595,41.84795 41.78091,41.84795 23.07495,0 41.7809,-18.73597 41.7809,-41.84795 0,-23.112 -18.70594,-41.84796 -41.7809,-41.84796 -23.07496,0 -41.78091,18.73596 -41.78091,41.84796 z m -280.56002,0 c 0,23.32492 18.87829,42.23352 42.16586,42.23352 23.28755,0 42.16585,-18.9086 42.16585,-42.23352 0,-23.32494 -18.87829,-42.23353 -42.16585,-42.23353 -23.28757,0 -42.16586,18.90859 -42.16586,42.23353 z"
+ inkscape:connector-curvature="0"
+ inkscape:label="eyes"
+ sodipodi:nodetypes="ssssssssss"
+ sodipodi:insensitive="true" />
+ <path
+ id="path1008"
+ style="display:inline;opacity:1;fill:none;stroke:#000000;stroke-width:32;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 339.72919,769.2467 -54.54422,72.22481 m 399.08582,-72.22481 54.54423,72.22481 M 263.68341,697.82002 175.92752,733.64353 m 579.85765,-35.82351 87.7559,35.82351"
+ inkscape:connector-curvature="0"
+ inkscape:label="whiskers"
+ sodipodi:nodetypes="cccccccc"
+ sodipodi:insensitive="true" />
+ <path
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 512.00082,713.08977 c -45.86417,0 -75.13006,31.84485 -74.14159,71.10084 1.07048,42.51275 32.46865,71.10323 74.14159,71.10323 41.67296,0 74.05118,-32.99608 74.14161,-71.10323 0.0932,-39.26839 -28.27742,-71.10084 -74.14161,-71.10084 z"
+ id="path1115"
+ inkscape:connector-curvature="0"
+ inkscape:label="nose"
+ sodipodi:nodetypes="zszsz"
+ sodipodi:insensitive="true" />
+ </g>
+</svg>
transformers: {
before: [transformClasscat(), transformInferno()],
},
+ alias: {
+ 'locale': 'moment/locale'
+ },
plugins: [
EnvPlugin({ NODE_ENV: isProduction ? 'production' : 'development' }),
CSSPlugin(),
// Sparky.task('version', _ => setVersion());
Sparky.task('clean', _ => Sparky.src('dist/').clean('dist/'));
Sparky.task('env', _ => (isProduction = true));
-Sparky.task('copy-assets', () => Sparky.src('assets/**/**.*').dest('dist/'));
+Sparky.task('copy-assets', () => Sparky.src('assets/**/**.*').dest(isProduction ? 'dist/' : 'dist/static'));
Sparky.task('dev', ['clean', 'config', 'copy-assets'], _ => {
fuse.dev();
app.hmr().watch();
"autosize": "^4.0.2",
"classcat": "^1.1.3",
"dotenv": "^6.1.0",
+ "i18next": "^17.0.9",
"inferno": "^7.0.1",
+ "inferno-i18next": "nimbusec-oss/inferno-i18next",
"inferno-router": "^7.0.1",
"js-cookie": "^2.2.0",
"jwt-decode": "^2.2.0",
"markdown-it-emoji": "^1.4.0",
"moment": "^2.24.0",
"rxjs": "^6.4.0",
- "terser": "^3.17.0"
+ "terser": "^3.17.0",
+ "ws": "^7.0.0"
},
"devDependencies": {
+ "@types/i18next": "^12.1.0",
"fuse-box": "^3.1.3",
"ts-transform-classcat": "^0.0.2",
"ts-transform-inferno": "^4.0.2",
- "typescript": "^3.3.3333"
+ "typescript": "^3.5.3"
}
}
import { Component, linkEvent } from 'inferno';
import { CommentNode as CommentNodeI, CommentForm as CommentFormI } from '../interfaces';
+import { capitalizeFirstLetter } from '../utils';
import { WebSocketService, UserService } from '../services';
import * as autosize from 'autosize';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface CommentFormProps {
postId?: number;
post_id: this.props.node ? this.props.node.comment.post_id : this.props.postId,
creator_id: UserService.Instance.user ? UserService.Instance.user.id : null,
},
- buttonTitle: !this.props.node ? "Post" : this.props.edit ? "Edit" : "Reply",
+ buttonTitle: !this.props.node ? capitalizeFirstLetter(i18n.t('post')) : this.props.edit ? capitalizeFirstLetter(i18n.t('edit')) : capitalizeFirstLetter(i18n.t('reply')),
}
constructor(props: any, context: any) {
super(props, context);
+
this.state = this.emptyState;
if (this.props.node) {
render() {
return (
- <div>
+ <div class="mb-3">
<form onSubmit={linkEvent(this, this.handleCommentSubmit)}>
<div class="form-group row">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-12">
<button type="submit" class="btn btn-sm btn-secondary mr-2" disabled={this.props.disabled}>{this.state.buttonTitle}</button>
- {this.props.node && <button type="button" class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}>Cancel</button>}
+ {this.props.node && <button type="button" class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}><T i18nKey="cancel">#</T></button>}
</div>
</div>
</form>
if (i.props.node) {
i.props.onReplyCancel();
}
+
+ autosize.update(document.querySelector('textarea'));
}
handleCommentContentChange(i: CommentForm, event: any) {
import { Component, linkEvent } from 'inferno';
import { Link } from 'inferno-router';
-import { CommentNode as CommentNodeI, CommentLikeForm, CommentForm as CommentFormI, SaveCommentForm, BanFromCommunityForm, BanUserForm, CommunityUser, UserView, AddModToCommunityForm, AddAdminForm } from '../interfaces';
+import { CommentNode as CommentNodeI, CommentLikeForm, CommentForm as CommentFormI, SaveCommentForm, BanFromCommunityForm, BanUserForm, CommunityUser, UserView, AddModToCommunityForm, AddAdminForm, TransferCommunityForm, TransferSiteForm } from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { mdToHtml, getUnixTime, canMod, isMod } from '../utils';
import * as moment from 'moment';
import { MomentTime } from './moment-time';
import { CommentForm } from './comment-form';
import { CommentNodes } from './comment-nodes';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
enum BanType {Community, Site};
banReason: string;
banExpires: string;
banType: BanType;
+ collapsed: boolean;
+ showConfirmTransferSite: boolean;
+ showConfirmTransferCommunity: boolean;
}
interface CommentNodeProps {
showBanDialog: false,
banReason: null,
banExpires: null,
- banType: BanType.Community
+ banType: BanType.Community,
+ collapsed: false,
+ showConfirmTransferSite: false,
+ showConfirmTransferCommunity: false,
}
constructor(props: any, context: any) {
let node = this.props.node;
return (
<div className={`comment ${node.comment.parent_id && !this.props.noIndent ? 'ml-4' : ''}`}>
- <div className={`mr-1 float-left small text-center ${this.props.viewOnly && 'no-click'}`}>
- <div className={`pointer ${node.comment.my_vote == 1 ? 'text-info' : 'text-muted'}`} onClick={linkEvent(node, this.handleCommentLike)}>
+ <div className={`vote-bar mr-2 float-left small text-center ${this.props.viewOnly && 'no-click'}`}>
+ <button className={`btn p-0 ${node.comment.my_vote == 1 ? 'text-info' : 'text-muted'}`} onClick={linkEvent(node, this.handleCommentLike)}>
<svg class="icon upvote"><use xlinkHref="#icon-arrow-up"></use></svg>
- </div>
+ </button>
<div class={`font-weight-bold text-muted`}>{node.comment.score}</div>
- <div className={`pointer ${node.comment.my_vote == -1 ? 'text-danger' : 'text-muted'}`} onClick={linkEvent(node, this.handleCommentDisLike)}>
+ <button className={`btn p-0 ${node.comment.my_vote == -1 ? 'text-danger' : 'text-muted'}`} onClick={linkEvent(node, this.handleCommentDisLike)}>
<svg class="icon downvote"><use xlinkHref="#icon-arrow-down"></use></svg>
- </div>
+ </button>
</div>
- <div id={`comment-${node.comment.id}`} className={`details ml-4 ${this.isCommentNew ? 'mark' : ''}`}>
+ <div id={`comment-${node.comment.id}`} className={`details comment-node ml-4 ${this.isCommentNew ? 'mark' : ''}`}>
<ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item">
<Link className="text-info" to={`/u/${node.comment.creator_name}`}>{node.comment.creator_name}</Link>
</li>
{this.isMod &&
- <li className="list-inline-item badge badge-light">mod</li>
+ <li className="list-inline-item badge badge-light"><T i18nKey="mod">#</T></li>
}
{this.isAdmin &&
- <li className="list-inline-item badge badge-light">admin</li>
+ <li className="list-inline-item badge badge-light"><T i18nKey="admin">#</T></li>
}
<li className="list-inline-item">
<span>(
<li className="list-inline-item">
<span><MomentTime data={node.comment} /></span>
</li>
+ <li className="list-inline-item">
+ <div className="pointer text-monospace" onClick={linkEvent(this, this.handleCommentCollapse)}>{this.state.collapsed ? '[+]' : '[-]'}</div>
+ </li>
</ul>
{this.state.showEdit && <CommentForm node={node} edit onReplyCancel={this.handleReplyCancel} disabled={this.props.locked} />}
- {!this.state.showEdit &&
+ {!this.state.showEdit && !this.state.collapsed &&
<div>
- <div className="md-div" dangerouslySetInnerHTML={mdToHtml(node.comment.removed ? '*removed*' : node.comment.deleted ? '*deleted*' : node.comment.content)} />
+ <div className="md-div" dangerouslySetInnerHTML={mdToHtml(node.comment.removed ? `*${i18n.t('removed')}*` : node.comment.deleted ? `*${i18n.t('deleted')}*` : node.comment.content)} />
<ul class="list-inline mb-1 text-muted small font-weight-bold">
{UserService.Instance.user && !this.props.viewOnly &&
<>
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleReplyClick)}>reply</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleReplyClick)}><T i18nKey="reply">#</T></span>
</li>
<li className="list-inline-item mr-2">
- <span class="pointer" onClick={linkEvent(this, this.handleSaveCommentClick)}>{node.comment.saved ? 'unsave' : 'save'}</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleSaveCommentClick)}>{node.comment.saved ? i18n.t('unsave') : i18n.t('save')}</span>
</li>
{this.myComment &&
<>
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}><T i18nKey="edit">#</T></span>
</li>
<li className="list-inline-item">
<span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>
- {!this.props.node.comment.deleted ? 'delete' : 'restore'}
+ {!this.props.node.comment.deleted ? i18n.t('delete') : i18n.t('restore')}
</span>
</li>
</>
{this.canMod &&
<li className="list-inline-item">
{!this.props.node.comment.removed ?
- <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}>remove</span> :
- <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}>restore</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}><T i18nKey="remove">#</T></span> :
+ <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}><T i18nKey="restore">#</T></span>
}
</li>
}
{!this.isMod &&
<li className="list-inline-item">
{!this.props.node.comment.banned_from_community ?
- <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunityShow)}>ban</span> :
- <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunitySubmit)}>unban</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunityShow)}><T i18nKey="ban">#</T></span> :
+ <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunitySubmit)}><T i18nKey="unban">#</T></span>
}
</li>
}
{!this.props.node.comment.banned_from_community &&
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleAddModToCommunity)}>{`${this.isMod ? 'remove' : 'appoint'} as mod`}</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleAddModToCommunity)}>{this.isMod ? i18n.t('remove_as_mod') : i18n.t('appoint_as_mod')}</span>
</li>
}
</>
}
+ {/* Community creators and admins can transfer community to another mod */}
+ {(this.amCommunityCreator || this.canAdmin) && this.isMod &&
+ <li className="list-inline-item">
+ {!this.state.showConfirmTransferCommunity ?
+ <span class="pointer" onClick={linkEvent(this, this.handleShowConfirmTransferCommunity)}><T i18nKey="transfer_community">#</T>
+ </span> : <>
+ <span class="d-inline-block mr-1"><T i18nKey="are_you_sure">#</T></span>
+ <span class="pointer d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferCommunity)}><T i18nKey="yes">#</T></span>
+ <span class="pointer d-inline-block" onClick={linkEvent(this, this.handleCancelShowConfirmTransferCommunity)}><T i18nKey="no">#</T></span>
+ </>
+ }
+ </li>
+ }
{/* Admins can ban from all, and appoint other admins */}
{this.canAdmin &&
<>
{!this.isAdmin &&
<li className="list-inline-item">
{!this.props.node.comment.banned ?
- <span class="pointer" onClick={linkEvent(this, this.handleModBanShow)}>ban from site</span> :
- <span class="pointer" onClick={linkEvent(this, this.handleModBanSubmit)}>unban from site</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleModBanShow)}><T i18nKey="ban_from_site">#</T></span> :
+ <span class="pointer" onClick={linkEvent(this, this.handleModBanSubmit)}><T i18nKey="unban_from_site">#</T></span>
}
</li>
}
{!this.props.node.comment.banned &&
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleAddAdmin)}>{`${this.isAdmin ? 'remove' : 'appoint'} as admin`}</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleAddAdmin)}>{this.isAdmin ? i18n.t('remove_as_admin') : i18n.t('appoint_as_admin')}</span>
</li>
}
</>
}
+ {/* Site Creator can transfer to another admin */}
+ {this.amSiteCreator && this.isAdmin &&
+ <li className="list-inline-item">
+ {!this.state.showConfirmTransferSite ?
+ <span class="pointer" onClick={linkEvent(this, this.handleShowConfirmTransferSite)}><T i18nKey="transfer_site">#</T>
+ </span> : <>
+ <span class="d-inline-block mr-1"><T i18nKey="are_you_sure">#</T></span>
+ <span class="pointer d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferSite)}><T i18nKey="yes">#</T></span>
+ <span class="pointer d-inline-block" onClick={linkEvent(this, this.handleCancelShowConfirmTransferSite)}><T i18nKey="no">#</T></span>
+ </>
+ }
+ </li>
+ }
</>
}
<li className="list-inline-item">
- <Link className="text-muted" to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}>link</Link>
+ <Link className="text-muted" to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}><T i18nKey="link">#</T></Link>
</li>
{this.props.markable &&
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleMarkRead)}>{`mark as ${node.comment.read ? 'unread' : 'read'}`}</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleMarkRead)}>{node.comment.read ? i18n.t('mark_as_unread') : i18n.t('mark_as_read')}</span>
</li>
}
</ul>
</div>
{this.state.showRemoveDialog &&
<form class="form-inline" onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
- <input type="text" class="form-control mr-2" placeholder="Reason" value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />
- <button type="submit" class="btn btn-secondary">Remove Comment</button>
+ <input type="text" class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />
+ <button type="submit" class="btn btn-secondary"><T i18nKey="remove_comment">#</T></button>
</form>
}
{this.state.showBanDialog &&
<form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
<div class="form-group row">
- <label class="col-form-label">Reason</label>
- <input type="text" class="form-control mr-2" placeholder="Optional" value={this.state.banReason} onInput={linkEvent(this, this.handleModBanReasonChange)} />
+ <label class="col-form-label"><T i18nKey="reason">#</T></label>
+ <input type="text" class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.banReason} onInput={linkEvent(this, this.handleModBanReasonChange)} />
</div>
{/* TODO hold off on expires until later */}
{/* <div class="form-group row"> */}
{/* <label class="col-form-label">Expires</label> */}
- {/* <input type="date" class="form-control mr-2" placeholder="Expires" value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
+ {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* </div> */}
<div class="form-group row">
- <button type="submit" class="btn btn-secondary">Ban {this.props.node.comment.creator_name}</button>
+ <button type="submit" class="btn btn-secondary">{i18n.t('ban')} {this.props.node.comment.creator_name}</button>
</div>
</form>
}
disabled={this.props.locked}
/>
}
- {this.props.node.children &&
+ {this.props.node.children && !this.state.collapsed &&
<CommentNodes
nodes={this.props.node.children}
locked={this.props.locked}
admins={this.props.admins}
/>
}
+ {/* A collapsed clearfix */}
+ {this.state.collapsed && <div class="row col-12"></div>}
</div>
)
}
return this.props.admins && canMod(UserService.Instance.user, this.props.admins.map(a => a.id), this.props.node.comment.creator_id);
}
+ get amCommunityCreator(): boolean {
+ return this.props.moderators &&
+ UserService.Instance.user &&
+ (this.props.node.comment.creator_id != UserService.Instance.user.id) &&
+ (UserService.Instance.user.id == this.props.moderators[0].user_id);
+ }
+
+ get amSiteCreator(): boolean {
+ return this.props.admins &&
+ UserService.Instance.user &&
+ (this.props.node.comment.creator_id != UserService.Instance.user.id) &&
+ (UserService.Instance.user.id == this.props.admins[0].id);
+ }
+
handleReplyClick(i: CommentNode) {
i.state.showReply = true;
i.setState(i.state);
handleModBanBothSubmit(i: CommentNode) {
event.preventDefault();
- console.log(BanType[i.state.banType]);
- console.log(i.props.node.comment.banned);
-
if (i.state.banType == BanType.Community) {
let form: BanFromCommunityForm = {
user_id: i.props.node.comment.creator_id,
i.setState(i.state);
}
+ handleShowConfirmTransferCommunity(i: CommentNode) {
+ i.state.showConfirmTransferCommunity = true;
+ i.setState(i.state);
+ }
+
+ handleCancelShowConfirmTransferCommunity(i: CommentNode) {
+ i.state.showConfirmTransferCommunity = false;
+ i.setState(i.state);
+ }
+
+ handleTransferCommunity(i: CommentNode) {
+ let form: TransferCommunityForm = {
+ community_id: i.props.node.comment.community_id,
+ user_id: i.props.node.comment.creator_id,
+ };
+ WebSocketService.Instance.transferCommunity(form);
+ i.state.showConfirmTransferCommunity = false;
+ i.setState(i.state);
+ }
+
+ handleShowConfirmTransferSite(i: CommentNode) {
+ i.state.showConfirmTransferSite = true;
+ i.setState(i.state);
+ }
+
+ handleCancelShowConfirmTransferSite(i: CommentNode) {
+ i.state.showConfirmTransferSite = false;
+ i.setState(i.state);
+ }
+
+ handleTransferSite(i: CommentNode) {
+ let form: TransferSiteForm = {
+ user_id: i.props.node.comment.creator_id,
+ };
+ WebSocketService.Instance.transferSite(form);
+ i.state.showConfirmTransferSite = false;
+ i.setState(i.state);
+ }
+
get isCommentNew(): boolean {
let now = moment.utc().subtract(10, 'minutes');
let then = moment.utc(this.props.node.comment.published);
return now.isBefore(then);
}
+
+ handleCommentCollapse(i: CommentNode) {
+ i.state.collapsed = !i.state.collapsed;
+ i.setState(i.state);
+ }
}
moderators={this.props.moderators}
admins={this.props.admins}
markable={this.props.markable}
- />
+ />
)}
</div>
)
import { UserOperation, Community, ListCommunitiesResponse, CommunityResponse, FollowCommunityForm, ListCommunitiesForm, SortType } from '../interfaces';
import { WebSocketService } from '../services';
import { msgOp } from '../utils';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
declare const Sortable: any;
super(props, context);
this.state = this.emptyState;
this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- (msg) => this.parseMessage(msg),
+ .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
+ .subscribe(
+ (msg) => this.parseMessage(msg),
(err) => console.error(err),
() => console.log('complete')
- );
+ );
this.refetch();
}
componentDidMount() {
- document.title = "Communities - Lemmy";
- let table = document.querySelector('#community_table');
- Sortable.initTable(table);
+ document.title = `${i18n.t('communities')} - ${WebSocketService.Instance.site.name}`;
}
// Necessary for back button for some reason
{this.state.loading ?
<h5 class=""><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> :
<div>
- <h5>List of communities</h5>
+ <h5><T i18nKey="list_of_communities">#</T></h5>
<div class="table-responsive">
<table id="community_table" class="table table-sm table-hover">
<thead class="pointer">
<tr>
- <th>Name</th>
- <th class="d-none d-lg-table-cell">Title</th>
- <th>Category</th>
- <th class="text-right">Subscribers</th>
- <th class="text-right d-none d-lg-table-cell">Posts</th>
- <th class="text-right d-none d-lg-table-cell">Comments</th>
+ <th><T i18nKey="name">#</T></th>
+ <th class="d-none d-lg-table-cell"><T i18nKey="title">#</T></th>
+ <th><T i18nKey="category">#</T></th>
+ <th class="text-right"><T i18nKey="subscribers">#</T></th>
+ <th class="text-right d-none d-lg-table-cell"><T i18nKey="posts">#</T></th>
+ <th class="text-right d-none d-lg-table-cell"><T i18nKey="comments">#</T></th>
<th></th>
</tr>
</thead>
<td class="text-right d-none d-lg-table-cell">{community.number_of_comments}</td>
<td class="text-right">
{community.subscribed ?
- <span class="pointer btn-link" onClick={linkEvent(community.id, this.handleUnsubscribe)}>Unsubscribe</span> :
- <span class="pointer btn-link" onClick={linkEvent(community.id, this.handleSubscribe)}>Subscribe</span>
+ <span class="pointer btn-link" onClick={linkEvent(community.id, this.handleUnsubscribe)}><T i18nKey="unsubscribe">#</T></span> :
+ <span class="pointer btn-link" onClick={linkEvent(community.id, this.handleSubscribe)}><T i18nKey="subscribe">#</T></span>
}
</td>
</tr>
return (
<div class="mt-2">
{this.state.page > 1 &&
- <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
+ <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
}
- <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
+ <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
</div>
);
}
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.ListCommunities) {
let res: ListCommunitiesResponse = msg;
this.state.loading = false;
window.scrollTo(0,0);
this.setState(this.state);
+ let table = document.querySelector('#community_table');
+ Sortable.initTable(table);
} else if (op == UserOperation.FollowCommunity) {
let res: CommunityResponse = msg;
let found = this.state.communities.find(c => c.id == res.community.id);
import { retryWhen, delay, take } from 'rxjs/operators';
import { CommunityForm as CommunityFormI, UserOperation, Category, ListCategoriesResponse, CommunityResponse } from '../interfaces';
import { WebSocketService } from '../services';
-import { msgOp } from '../utils';
+import { msgOp, capitalizeFirstLetter } from '../utils';
import * as autosize from 'autosize';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
import { Community } from '../interfaces';
communityForm: {
name: null,
title: null,
- category_id: null
+ category_id: null,
+ nsfw: false,
},
categories: [],
loading: false
category_id: this.props.community.category_id,
description: this.props.community.description,
edit_id: this.props.community.id,
+ nsfw: this.props.community.nsfw,
auth: null
}
}
return (
<form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
<div class="form-group row">
- <label class="col-12 col-form-label">Name</label>
+ <label class="col-12 col-form-label"><T i18nKey="name">#</T></label>
<div class="col-12">
- <input type="text" class="form-control" value={this.state.communityForm.name} onInput={linkEvent(this, this.handleCommunityNameChange)} required minLength={3} maxLength={20} pattern="[a-z0-9_]+" title="lowercase, underscores, and no spaces."/>
+ <input type="text" class="form-control" value={this.state.communityForm.name} onInput={linkEvent(this, this.handleCommunityNameChange)} required minLength={3} maxLength={20} pattern="[a-z0-9_]+" title={i18n.t('community_reqs')}/>
</div>
</div>
<div class="form-group row">
- <label class="col-12 col-form-label">Title</label>
+ <label class="col-12 col-form-label"><T i18nKey="title">#</T></label>
<div class="col-12">
<input type="text" value={this.state.communityForm.title} onInput={linkEvent(this, this.handleCommunityTitleChange)} class="form-control" required minLength={3} maxLength={100} />
</div>
</div>
<div class="form-group row">
- <label class="col-12 col-form-label">Sidebar</label>
+ <label class="col-12 col-form-label"><T i18nKey="sidebar">#</T></label>
<div class="col-12">
<textarea value={this.state.communityForm.description} onInput={linkEvent(this, this.handleCommunityDescriptionChange)} class="form-control" rows={3} maxLength={10000} />
</div>
</div>
<div class="form-group row">
- <label class="col-12 col-form-label">Category</label>
+ <label class="col-12 col-form-label"><T i18nKey="category">#</T></label>
<div class="col-12">
<select class="form-control" value={this.state.communityForm.category_id} onInput={linkEvent(this, this.handleCommunityCategoryChange)}>
{this.state.categories.map(category =>
</select>
</div>
</div>
+ <div class="form-group row">
+ <div class="col-12">
+ <div class="form-check">
+ <input class="form-check-input" type="checkbox" checked={this.state.communityForm.nsfw} onChange={linkEvent(this, this.handleCommunityNsfwChange)}/>
+ <label class="form-check-label"><T i18nKey="nsfw">#</T></label>
+ </div>
+ </div>
+ </div>
<div class="form-group row">
<div class="col-12">
<button type="submit" class="btn btn-secondary mr-2">
{this.state.loading ?
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> :
- this.props.community ? 'Save' : 'Create'}</button>
- {this.props.community && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}>Cancel</button>}
+ this.props.community ? capitalizeFirstLetter(i18n.t('save')) : capitalizeFirstLetter(i18n.t('create'))}</button>
+ {this.props.community && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}><T i18nKey="cancel">#</T></button>}
</div>
</div>
</form>
i.setState(i.state);
}
+ handleCommunityNsfwChange(i: CommunityForm, event: any) {
+ i.state.communityForm.nsfw = event.target.checked;
+ i.setState(i.state);
+ }
+
handleCancel(i: CommunityForm) {
i.props.onCancel();
}
let op: UserOperation = msgOp(msg);
console.log(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
this.state.loading = false;
this.setState(this.state);
return;
this.state.loading = false;
this.props.onCreate(res.community);
}
-
- // TODO is this necessary?
+ // TODO is ths necessary
else if (op == UserOperation.EditCommunity) {
let res: CommunityResponse = msg;
this.state.loading = false;
import { PostListings } from './post-listings';
import { Sidebar } from './sidebar';
import { msgOp, routeSortTypeToEnum, fetchLimit } from '../utils';
+import { T, i18n } from 'inferno-i18next';
interface State {
community: CommunityI;
number_of_comments: null,
published: null,
removed: null,
+ nsfw: false,
deleted: null,
},
moderators: [],
<div class="col-12 col-md-8">
<h5>{this.state.community.title}
{this.state.community.removed &&
- <small className="ml-2 text-muted font-italic">removed</small>
+ <small className="ml-2 text-muted font-italic"><T i18nKey="removed">#</T></small>
+ }
+ {this.state.community.nsfw &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small>
}
</h5>
{this.selects()}
return (
<div className="mb-2">
<select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="custom-select custom-select-sm w-auto">
- <option disabled>Sort Type</option>
- <option value={SortType.Hot}>Hot</option>
- <option value={SortType.New}>New</option>
- <option disabled>──────────</option>
- <option value={SortType.TopDay}>Top Day</option>
- <option value={SortType.TopWeek}>Week</option>
- <option value={SortType.TopMonth}>Month</option>
- <option value={SortType.TopYear}>Year</option>
- <option value={SortType.TopAll}>All</option>
+ <option disabled><T i18nKey="sort_type">#</T></option>
+ <option value={SortType.Hot}><T i18nKey="hot">#</T></option>
+ <option value={SortType.New}><T i18nKey="new">#</T></option>
+ <option disabled>──────</option>
+ <option value={SortType.TopDay}><T i18nKey="top_day">#</T></option>
+ <option value={SortType.TopWeek}><T i18nKey="week">#</T></option>
+ <option value={SortType.TopMonth}><T i18nKey="month">#</T></option>
+ <option value={SortType.TopYear}><T i18nKey="year">#</T></option>
+ <option value={SortType.TopAll}><T i18nKey="all">#</T></option>
</select>
</div>
)
paginator() {
return (
- <div class="mt-2">
+ <div class="my-2">
{this.state.page > 1 &&
- <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
+ <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
}
- <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
+ <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
</div>
);
}
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.GetCommunity) {
let res: GetCommunityResponse = msg;
this.state.community = res.community;
this.state.moderators = res.moderators;
this.state.admins = res.admins;
- document.title = `/c/${this.state.community.name} - Lemmy`;
+ document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`;
this.setState(this.state);
this.fetchPosts();
} else if (op == UserOperation.EditCommunity) {
import { Component } from 'inferno';
import { CommunityForm } from './community-form';
import { Community } from '../interfaces';
+import { WebSocketService } from '../services';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
export class CreateCommunity extends Component<any, any> {
}
componentDidMount() {
- document.title = "Create Community - Lemmy";
+ document.title = `${i18n.t('create_community')} - ${WebSocketService.Instance.site.name}`;
}
render() {
return (
<div class="container">
<div class="row">
- <div class="col-12 col-lg-6 mb-4">
- <h5>Create Community</h5>
+ <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+ <h5><T i18nKey="create_community">#</T></h5>
<CommunityForm onCreate={this.handleCommunityCreate}/>
</div>
</div>
import { Component } from 'inferno';
import { PostForm } from './post-form';
+import { WebSocketService } from '../services';
+import { PostFormParams } from '../interfaces';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
export class CreatePost extends Component<any, any> {
}
componentDidMount() {
- document.title = "Create Post - Lemmy";
+ document.title = `${i18n.t('create_post')} - ${WebSocketService.Instance.site.name}`;
}
render() {
return (
<div class="container">
<div class="row">
- <div class="col-12 col-lg-6 mb-4">
- <h5>Create a Post</h5>
- <PostForm onCreate={this.handlePostCreate} prevCommunityName={this.prevCommunityName} />
+ <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+ <h5><T i18nKey="create_post">#</T></h5>
+ <PostForm onCreate={this.handlePostCreate} params={this.params} />
</div>
</div>
</div>
)
}
+ get params(): PostFormParams {
+ let urlParams = new URLSearchParams(this.props.location.search);
+ let params: PostFormParams = {
+ name: urlParams.get("name"),
+ community: urlParams.get("community") || this.prevCommunityName,
+ body: urlParams.get("body"),
+ url: urlParams.get("url"),
+ };
+
+ return params;
+ }
+
get prevCommunityName(): string {
if (this.props.match.params.name) {
return this.props.match.params.name;
import { Link } from 'inferno-router';
import { repoUrl } from '../utils';
import { version } from '../version';
+import { T } from 'inferno-i18next';
export class Footer extends Component<any, any> {
<span class="navbar-text">{version}</span>
</li>
<li class="nav-item">
- <Link class="nav-link" to="/modlog">Modlog</Link>
+ <Link class="nav-link" to="/modlog"><T i18nKey="modlog">#</T></Link>
</li>
<li class="nav-item">
- <a class="nav-link" href={`${repoUrl}/blob/master/docs/api.md`}>API</a>
+ <a class="nav-link" href={`${repoUrl}/blob/master/docs/api.md`}><T i18nKey="api">#</T></a>
</li>
<li class="nav-item">
- <Link class="nav-link" to="/sponsors">Sponsors</Link>
+ <Link class="nav-link" to="/sponsors"><T i18nKey="sponsors">#</T></Link>
</li>
<li class="nav-item">
- <a class="nav-link" href={repoUrl}>Code</a>
+ <a class="nav-link" href={repoUrl}><T i18nKey="code">#</T></a>
</li>
</ul>
</div>
import { WebSocketService, UserService } from '../services';
import { msgOp } from '../utils';
import { CommentNodes } from './comment-nodes';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
enum UnreadType {
Unread, All
}
componentDidMount() {
- document.title = `/u/${UserService.Instance.user.username} Inbox - Lemmy`;
+ document.title = `/u/${UserService.Instance.user.username} ${i18n.t('inbox')} - ${WebSocketService.Instance.site.name}`;
}
render() {
<div class="row">
<div class="col-12">
<h5 class="mb-0">
- <span>Inbox for <Link to={`/u/${user.username}`}>{user.username}</Link></span>
+ <span><T i18nKey="inbox_for" interpolation={{user: user.username}}>#<Link to={`/u/${user.username}`}>#</Link></T></span>
</h5>
{this.state.replies.length > 0 && this.state.unreadType == UnreadType.Unread &&
<ul class="list-inline mb-1 text-muted small font-weight-bold">
<li className="list-inline-item">
- <span class="pointer" onClick={this.markAllAsRead}>mark all as read</span>
+ <span class="pointer" onClick={this.markAllAsRead}><T i18nKey="mark_all_as_read">#</T></span>
</li>
</ul>
}
return (
<div className="mb-2">
<select value={this.state.unreadType} onChange={linkEvent(this, this.handleUnreadTypeChange)} class="custom-select custom-select-sm w-auto">
- <option disabled>Type</option>
- <option value={UnreadType.Unread}>Unread</option>
- <option value={UnreadType.All}>All</option>
+ <option disabled><T i18nKey="type">#</T></option>
+ <option value={UnreadType.Unread}><T i18nKey="unread">#</T></option>
+ <option value={UnreadType.All}><T i18nKey="all">#</T></option>
</select>
<select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="custom-select custom-select-sm w-auto ml-2">
- <option disabled>Sort Type</option>
- <option value={SortType.New}>New</option>
- <option value={SortType.TopDay}>Top Day</option>
- <option value={SortType.TopWeek}>Week</option>
- <option value={SortType.TopMonth}>Month</option>
- <option value={SortType.TopYear}>Year</option>
- <option value={SortType.TopAll}>All</option>
+ <option disabled><T i18nKey="sort_type">#</T></option>
+ <option value={SortType.New}><T i18nKey="new">#</T></option>
+ <option value={SortType.TopDay}><T i18nKey="top_day">#</T></option>
+ <option value={SortType.TopWeek}><T i18nKey="week">#</T></option>
+ <option value={SortType.TopMonth}><T i18nKey="month">#</T></option>
+ <option value={SortType.TopYear}><T i18nKey="year">#</T></option>
+ <option value={SortType.TopAll}><T i18nKey="all">#</T></option>
</select>
</div>
)
return (
<div class="mt-2">
{this.state.page > 1 &&
- <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
+ <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
}
- <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
+ <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
</div>
);
}
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.GetReplies || op == UserOperation.MarkAllAsRead) {
let res: GetRepliesResponse = msg;
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
// let res: CommentResponse = msg;
- alert('Reply sent');
+ alert(i18n.t('reply_sent'));
// this.state.replies.unshift(res.comment); // TODO do this right
// this.setState(this.state);
} else if (op == UserOperation.SaveComment) {
import { LoginForm, RegisterForm, LoginResponse, UserOperation } from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { msgOp } from '../utils';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface State {
loginForm: LoginForm;
password: undefined,
password_verify: undefined,
admin: false,
+ show_nsfw: false,
},
loginLoading: false,
registerLoading: false,
}
componentDidMount() {
- document.title = "Login - Lemmy";
+ document.title = `${i18n.t('login')} - ${WebSocketService.Instance.site.name}`;
}
render() {
<form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
<h5>Login</h5>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Email or Username</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="email_or_username">#</T></label>
<div class="col-sm-10">
<input type="text" class="form-control" value={this.state.loginForm.username_or_email} onInput={linkEvent(this, this.handleLoginUsernameChange)} required minLength={3} />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Password</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="password">#</T></label>
<div class="col-sm-10">
<input type="password" value={this.state.loginForm.password} onInput={linkEvent(this, this.handleLoginPasswordChange)} class="form-control" required />
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">{this.state.loginLoading ?
- <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : 'Login'}</button>
+ <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : i18n.t('login')}</button>
</div>
</div>
</form>
- {/* Forgot your password or deleted your account? Reset your password. TODO */}
</div>
);
}
registerForm() {
return (
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
- <h5>Sign Up</h5>
+ <h5><T i18nKey="sign_up">#</T></h5>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Username</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="username">#</T></label>
<div class="col-sm-10">
<input type="text" class="form-control" value={this.state.registerForm.username} onInput={linkEvent(this, this.handleRegisterUsernameChange)} required minLength={3} maxLength={20} pattern="[a-zA-Z0-9_]+" />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Email</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="email">#</T></label>
<div class="col-sm-10">
- <input type="email" class="form-control" placeholder="Optional" value={this.state.registerForm.email} onInput={linkEvent(this, this.handleRegisterEmailChange)} minLength={3} />
+ <input type="email" class="form-control" placeholder={i18n.t('optional')} value={this.state.registerForm.email} onInput={linkEvent(this, this.handleRegisterEmailChange)} minLength={3} />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Password</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="password">#</T></label>
<div class="col-sm-10">
<input type="password" value={this.state.registerForm.password} onInput={linkEvent(this, this.handleRegisterPasswordChange)} class="form-control" required />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Verify Password</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="verify_password">#</T></label>
<div class="col-sm-10">
<input type="password" value={this.state.registerForm.password_verify} onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)} class="form-control" required />
</div>
</div>
+ <div class="form-group row">
+ <div class="col-sm-10">
+ <div class="form-check">
+ <input class="form-check-input" type="checkbox" checked={this.state.registerForm.show_nsfw} onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}/>
+ <label class="form-check-label"><T i18nKey="show_nsfw">#</T></label>
+ </div>
+ </div>
+ </div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">{this.state.registerLoading ?
- <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : 'Sign Up'}</button>
-
+ <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : i18n.t('sign_up')}</button>
</div>
</div>
</form>
i.setState(i.state);
}
+ handleRegisterShowNsfwChange(i: Login, event: any) {
+ i.state.registerForm.show_nsfw = event.target.checked;
+ i.setState(i.state);
+ }
+
parseMessage(msg: any) {
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
this.state = this.emptyState;
this.setState(this.state);
return;
import { PostListings } from './post-listings';
import { SiteForm } from './site-form';
import { msgOp, repoUrl, mdToHtml, fetchLimit, routeSortTypeToEnum, routeListingTypeToEnum } from '../utils';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface MainState {
subscribedCommunities: Array<CommunityUser>;
number_of_users: null,
number_of_posts: null,
number_of_comments: null,
+ number_of_communities: null,
},
admins: [],
banned: [],
super(props, context);
this.state = this.emptyState;
+ this.handleEditCancel = this.handleEditCancel.bind(this);
this.subscription = WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
this.subscription.unsubscribe();
}
- componentDidMount() {
- document.title = "Lemmy";
- }
-
// Necessary for back button for some reason
componentWillReceiveProps(nextProps: any) {
if (nextProps.history.action == 'POP') {
{this.posts()}
</div>
<div class="col-12 col-md-4">
- {!this.state.loading &&
- <div>
+ {this.my_sidebar()}
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ my_sidebar() {
+ return(
+ <div>
+ {!this.state.loading &&
+ <div>
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
{this.trendingCommunities()}
{UserService.Instance.user && this.state.subscribedCommunities.length > 0 &&
<div>
- <h5>Subscribed <Link class="text-white" to="/communities">communities</Link></h5>
+ <h5>
+ <T i18nKey="subscribed_to_communities">#<Link class="text-white" to="/communities">#</Link></T>
+ </h5>
<ul class="list-inline">
{this.state.subscribedCommunities.map(community =>
<li class="list-inline-item"><Link to={`/c/${community.community_name}`}>{community.community_name}</Link></li>
</ul>
</div>
}
- <Link class="btn btn-sm btn-secondary btn-block mb-3"
- to="/create_community">Create a Community</Link>
- {this.sidebar()}
+ <Link class="btn btn-sm btn-secondary btn-block"
+ to="/create_community">
+ <T i18nKey="create_a_community">#</T>
+ </Link>
</div>
- }
+ </div>
+ {this.sidebar()}
+ {this.landing()}
</div>
- </div>
+ }
</div>
)
}
trendingCommunities() {
return (
<div>
- <h5>Trending <Link class="text-white" to="/communities">communities</Link></h5>
+ <h5>
+ <T i18nKey="trending_communities">#<Link class="text-white" to="/communities">#</Link></T>
+ </h5>
<ul class="list-inline">
{this.state.trendingCommunities.map(community =>
<li class="list-inline-item"><Link to={`/c/${community.name}`}>{community.name}</Link></li>
onCancel={this.handleEditCancel}
/>
}
- {this.landing()}
</div>
)
}
siteInfo() {
return (
<div>
- <h5 class="mb-0">{`${this.state.site.site.name}`}</h5>
- {this.canAdmin &&
- <ul class="list-inline mb-1 text-muted small font-weight-bold">
- <li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span>
- </li>
- </ul>
- }
- <ul class="my-2 list-inline">
- <li className="list-inline-item badge badge-light">{this.state.site.site.number_of_users} Users</li>
- <li className="list-inline-item badge badge-light">{this.state.site.site.number_of_posts} Posts</li>
- <li className="list-inline-item badge badge-light">{this.state.site.site.number_of_comments} Comments</li>
- <li className="list-inline-item"><Link className="badge badge-light" to="/modlog">Modlog</Link></li>
- </ul>
- <ul class="my-1 list-inline small">
- <li class="list-inline-item">admins: </li>
- {this.state.site.admins.map(admin =>
- <li class="list-inline-item"><Link class="text-info" to={`/u/${admin.name}`}>{admin.name}</Link></li>
- )}
- </ul>
- {this.state.site.site.description &&
- <div>
- <hr />
- <div className="md-div" dangerouslySetInnerHTML={mdToHtml(this.state.site.site.description)} />
- <hr />
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ <h5 class="mb-0">{`${this.state.site.site.name}`}</h5>
+ {this.canAdmin &&
+ <ul class="list-inline mb-1 text-muted small font-weight-bold">
+ <li className="list-inline-item">
+ <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>
+ <T i18nKey="edit">#</T>
+ </span>
+ </li>
+ </ul>
+ }
+ <ul class="my-2 list-inline">
+ <li className="list-inline-item badge badge-secondary">
+ <T i18nKey="number_of_users" interpolation={{count: this.state.site.site.number_of_users}}>#</T>
+ </li>
+ <li className="list-inline-item badge badge-secondary">
+ <T i18nKey="number_of_communities" interpolation={{count: this.state.site.site.number_of_communities}}>#</T>
+ </li>
+ <li className="list-inline-item badge badge-secondary">
+ <T i18nKey="number_of_posts" interpolation={{count: this.state.site.site.number_of_posts}}>#</T>
+ </li>
+ <li className="list-inline-item badge badge-secondary">
+ <T i18nKey="number_of_comments" interpolation={{count: this.state.site.site.number_of_comments}}>#</T>
+ </li>
+ <li className="list-inline-item">
+ <Link className="badge badge-secondary" to="/modlog">
+ <T i18nKey="modlog">#</T>
+ </Link>
+ </li>
+ </ul>
+ <ul class="mt-1 list-inline small mb-0">
+ <li class="list-inline-item">
+ <T i18nKey="admins" class="d-inline">#</T>:
+ </li>
+ {this.state.site.admins.map(admin =>
+ <li class="list-inline-item"><Link class="text-info" to={`/u/${admin.name}`}>{admin.name}</Link></li>
+ )}
+ </ul>
+ </div>
</div>
- }
- </div>
+ {this.state.site.site.description &&
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ <div className="md-div" dangerouslySetInnerHTML={mdToHtml(this.state.site.site.description)} />
+ </div>
+ </div>
+ }
+ </div>
)
}
landing() {
return (
- <div>
- <h5>Powered by
- <svg class="icon mx-2"><use xlinkHref="#icon-mouse"></use></svg>
- <a href={repoUrl}>Lemmy<sup>Beta</sup></a>
- </h5>
- <p>Lemmy is a <a href="https://en.wikipedia.org/wiki/Link_aggregation">link aggregator</a> / reddit alternative, intended to work in the <a href="https://en.wikipedia.org/wiki/Fediverse">fediverse</a>.</p>
- <p>Its self-hostable, has live-updating comment threads, and is tiny (<code>~80kB</code>). Federation into the ActivityPub network is on the roadmap.</p>
- <p>This is a <b>very early beta version</b>, and a lot of features are currently broken or missing.</p>
- <p>Suggest new features or report bugs <a href={repoUrl}>here.</a></p>
- <p>Made with <a href="https://www.rust-lang.org">Rust</a>, <a href="https://actix.rs/">Actix</a>, <a href="https://www.infernojs.org">Inferno</a>, <a href="https://www.typescriptlang.org/">Typescript</a>.</p>
+ <div class="card border-secondary">
+ <div class="card-body">
+ <h5>
+ <T i18nKey="powered_by" class="d-inline">#</T>
+ <svg class="icon mx-2"><use xlinkHref="#icon-mouse">#</use></svg>
+ <a href={repoUrl}>Lemmy<sup>beta</sup></a>
+ </h5>
+ <p class="mb-0">
+ <T i18nKey="landing_0">#<a href="https://en.wikipedia.org/wiki/Link_aggregation">#</a><a href="https://en.wikipedia.org/wiki/Fediverse">#</a><br></br><code>#</code><br></br><b>#</b><br></br><a href={repoUrl}>#</a><br></br><a href="https://www.rust-lang.org">#</a><a href="https://actix.rs/">#</a><a href="https://infernojs.org">#</a><a href="https://www.typescriptlang.org/">#</a>
+ </T>
+ </p>
</div>
+ </div>
)
}
selects() {
return (
- <div className="mb-2">
+ <div className="mb-3">
<div class="btn-group btn-group-toggle">
<label className={`btn btn-sm btn-secondary
${this.state.type_ == ListingType.Subscribed && 'active'}
onChange={linkEvent(this, this.handleTypeChange)}
disabled={UserService.Instance.user == undefined}
/>
- Subscribed
+ {i18n.t('subscribed')}
</label>
<label className={`pointer btn btn-sm btn-secondary ${this.state.type_ == ListingType.All && 'active'}`}>
<input type="radio"
checked={this.state.type_ == ListingType.All}
onChange={linkEvent(this, this.handleTypeChange)}
/>
- All
+ {i18n.t('all')}
</label>
</div>
<select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="ml-2 custom-select custom-select-sm w-auto">
- <option disabled>Sort Type</option>
- <option value={SortType.Hot}>Hot</option>
- <option value={SortType.New}>New</option>
- <option disabled>──────────</option>
- <option value={SortType.TopDay}>Top Day</option>
- <option value={SortType.TopWeek}>Week</option>
- <option value={SortType.TopMonth}>Month</option>
- <option value={SortType.TopYear}>Year</option>
- <option value={SortType.TopAll}>All</option>
+ <option disabled><T i18nKey="sort_type">#</T></option>
+ <option value={SortType.Hot}><T i18nKey="hot">#</T></option>
+ <option value={SortType.New}><T i18nKey="new">#</T></option>
+ <option disabled>─────</option>
+ <option value={SortType.TopDay}><T i18nKey="top_day">#</T></option>
+ <option value={SortType.TopWeek}><T i18nKey="week">#</T></option>
+ <option value={SortType.TopMonth}><T i18nKey="month">#</T></option>
+ <option value={SortType.TopYear}><T i18nKey="year">#</T></option>
+ <option value={SortType.TopAll}><T i18nKey="all">#</T></option>
</select>
</div>
)
paginator() {
return (
- <div class="mt-2">
+ <div class="my-2">
{this.state.page > 1 &&
- <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
+ <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
}
- <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
+ <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
</div>
);
}
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.GetFollowedCommunities) {
let res: GetFollowedCommunitiesResponse = msg;
this.state.site.site = res.site;
this.state.site.banned = res.banned;
this.setState(this.state);
+ document.title = `${WebSocketService.Instance.site.name}`;
+
} else if (op == UserOperation.EditSite) {
let res: SiteResponse = msg;
this.state.site.site = res.site;
}
componentDidMount() {
- document.title = "Modlog - Lemmy";
+ document.title = `Modlog - ${WebSocketService.Instance.site.name}`;
}
setCombined(res: GetModlogResponse) {
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.GetModlog) {
let res: GetModlogResponse = msg;
import { Component } from 'inferno';
import * as moment from 'moment';
+import { getMomentLanguage } from '../utils';
+import { i18n } from '../i18next';
interface MomentTimeProps {
data: {
constructor(props: any, context: any) {
super(props, context);
+
+ let lang = getMomentLanguage();
+
+ moment.locale(lang);
}
render() {
if (this.props.data.updated) {
return (
- <span title={this.props.data.updated} className="font-italics">modified {moment.utc(this.props.data.updated).fromNow()}</span>
+ <span title={this.props.data.updated} className="font-italics">{i18n.t('modified')} {moment.utc(this.props.data.updated).fromNow()}</span>
)
} else {
let str = this.props.data.published || this.props.data.when_;
import { UserOperation, GetRepliesForm, GetRepliesResponse, SortType, GetSiteResponse, Comment} from '../interfaces';
import { msgOp } from '../utils';
import { version } from '../version';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface NavbarState {
isLoggedIn: boolean;
// TODO class active corresponding to current page
navbar() {
return (
- <nav class="container navbar navbar-expand-md navbar-light navbar-bg p-0 px-3">
+ <nav class="container-fluid navbar navbar-expand-md navbar-light shadow p-0 px-3">
<Link title={version} class="navbar-brand" to="/">
- <svg class="icon mr-2 mouse-icon"><use xlinkHref="#icon-mouse"></use></svg>
{this.state.siteName}
</Link>
<button class="navbar-toggler" type="button" onClick={linkEvent(this, this.expandNavbar)}>
<div className={`${!this.state.expanded && 'collapse'} navbar-collapse`}>
<ul class="navbar-nav mr-auto">
<li class="nav-item">
- <Link class="nav-link" to="/communities">Communities</Link>
+ <Link class="nav-link" to="/communities"><T i18nKey="communities">#</T></Link>
</li>
<li class="nav-item">
- <Link class="nav-link" to="/search">Search</Link>
+ <Link class="nav-link" to="/search"><T i18nKey="search">#</T></Link>
</li>
<li class="nav-item">
- <Link class="nav-link" to={{pathname: '/create_post', state: { prevPath: this.currentLocation }}}>Create Post</Link>
+ <Link class="nav-link" to={{pathname: '/create_post', state: { prevPath: this.currentLocation }}}><T i18nKey="create_post">#</T></Link>
</li>
<li class="nav-item">
- <Link class="nav-link" to="/create_community">Create Community</Link>
+ <Link class="nav-link" to="/create_community"><T i18nKey="create_community">#</T></Link>
</li>
</ul>
<ul class="navbar-nav ml-auto mr-2">
<>
{
<li className="nav-item">
- <Link class="inbox nav-link" to="/inbox">
+ <Link class="nav-link" to="/inbox">
<svg class="icon"><use xlinkHref="#icon-mail"></use></svg>
{this.state.unreadCount> 0 && <span class="ml-1 badge badge-light">{this.state.unreadCount}</span>}
</Link>
{UserService.Instance.user.username}
</a>
<div className={`dropdown-menu dropdown-menu-right ${this.state.expandUserDropdown && 'show'}`}>
- <a role="button" class="dropdown-item pointer" onClick={linkEvent(this, this.handleOverviewClick)}>Overview</a>
- <a role="button" class="dropdown-item pointer" onClick={ linkEvent(this, this.handleLogoutClick) }>Logout</a>
+ <a role="button" class="dropdown-item pointer" onClick={linkEvent(this, this.handleOverviewClick)}><T i18nKey="overview">#</T></a>
+ <a role="button" class="dropdown-item pointer" onClick={ linkEvent(this, this.handleLogoutClick) }><T i18nKey="logout">#</T></a>
</div>
</li>
</>
:
- <Link class="nav-link" to="/login">Login / Sign up</Link>
+ <Link class="nav-link" to="/login"><T i18nKey="login_sign_up">#</T></Link>
}
</ul>
</div>
parseMessage(msg: any) {
let op: UserOperation = msgOp(msg);
if (msg.error) {
- if (msg.error == "Not logged in.") {
+ if (msg.error == "not_logged_in") {
UserService.Instance.logout();
location.reload();
}
if (UserService.Instance.user) {
document.addEventListener('DOMContentLoaded', function () {
if (!Notification) {
- alert('Desktop notifications not available in your browser. Try Chromium.');
+ alert(i18n.t('notifications_error'));
return;
}
if (Notification.permission !== 'granted')
Notification.requestPermission();
else {
- var notification = new Notification(`${replies.length} Unread Messages`, {
+ var notification = new Notification(`${replies.length} ${i18n.t('unread_messages')}`, {
icon: `${window.location.protocol}//${window.location.host}/static/assets/apple-touch-icon.png`,
body: `${recentReply.creator_name}: ${recentReply.content}`
});
import { Component, linkEvent } from 'inferno';
+import { PostListings } from './post-listings';
import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators';
-import { PostForm as PostFormI, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse, ListCommunitiesForm, SortType } from '../interfaces';
+import { PostForm as PostFormI, PostFormParams, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse, ListCommunitiesForm, SortType, SearchForm, SearchType, SearchResponse } from '../interfaces';
import { WebSocketService, UserService } from '../services';
-import { msgOp, getPageTitle } from '../utils';
+import { msgOp, getPageTitle, debounce, validURL, capitalizeFirstLetter } from '../utils';
import * as autosize from 'autosize';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface PostFormProps {
post?: Post; // If a post is given, that means this is an edit
- prevCommunityName?: string;
+ params?: PostFormParams;
onCancel?(): any;
onCreate?(id: number): any;
onEdit?(post: Post): any;
communities: Array<Community>;
loading: boolean;
suggestedTitle: string;
+ suggestedPosts: Array<Post>;
+ crossPosts: Array<Post>;
}
export class PostForm extends Component<PostFormProps, PostFormState> {
private emptyState: PostFormState = {
postForm: {
name: null,
+ nsfw: false,
auth: null,
community_id: null,
creator_id: (UserService.Instance.user) ? UserService.Instance.user.id : null,
communities: [],
loading: false,
suggestedTitle: undefined,
+ suggestedPosts: [],
+ crossPosts: [],
}
constructor(props: any, context: any) {
edit_id: this.props.post.id,
creator_id: this.props.post.creator_id,
url: this.props.post.url,
+ nsfw: this.props.post.nsfw,
auth: null
}
}
+ if (this.props.params) {
+ this.state.postForm.name = this.props.params.name;
+ if (this.props.params.url) {
+ this.state.postForm.url = this.props.params.url;
+ }
+ if (this.props.params.body) {
+ this.state.postForm.body = this.props.params.body;
+ }
+ }
+
this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- (msg) => this.parseMessage(msg),
+ .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
+ .subscribe(
+ (msg) => this.parseMessage(msg),
(err) => console.error(err),
() => console.log('complete')
- );
+ );
- let listCommunitiesForm: ListCommunitiesForm = {
- sort: SortType[SortType.TopAll],
- limit: 9999,
- }
+ let listCommunitiesForm: ListCommunitiesForm = {
+ sort: SortType[SortType.TopAll],
+ limit: 9999,
+ }
- WebSocketService.Instance.listCommunities(listCommunitiesForm);
+ WebSocketService.Instance.listCommunities(listCommunitiesForm);
}
componentDidMount() {
<div>
<form onSubmit={linkEvent(this, this.handlePostSubmit)}>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">URL</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="url">#</T></label>
<div class="col-sm-10">
<input type="url" class="form-control" value={this.state.postForm.url} onInput={linkEvent(this, this.handlePostUrlChange)} />
{this.state.suggestedTitle &&
- <span class="text-muted small font-weight-bold pointer" onClick={linkEvent(this, this.copySuggestedTitle)}>copy suggested title: {this.state.suggestedTitle}</span>
+ <div class="mt-1 text-muted small font-weight-bold pointer" onClick={linkEvent(this, this.copySuggestedTitle)}><T i18nKey="copy_suggested_title" interpolation={{title: this.state.suggestedTitle}}>#</T></div>
+ }
+ {this.state.crossPosts.length > 0 &&
+ <>
+ <div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div>
+ <PostListings showCommunity posts={this.state.crossPosts} />
+ </>
}
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Title</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="title">#</T></label>
<div class="col-sm-10">
<textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={2} minLength={3} maxLength={100} />
+ {this.state.suggestedPosts.length > 0 &&
+ <>
+ <div class="my-1 text-muted small font-weight-bold"><T i18nKey="related_posts">#</T></div>
+ <PostListings posts={this.state.suggestedPosts} />
+ </>
+ }
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Body</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="body">#</T></label>
<div class="col-sm-10">
<textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={4} maxLength={10000} />
</div>
</div>
- {/* Cant change a community from an edit */}
{!this.props.post &&
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Community</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="community">#</T></label>
<div class="col-sm-10">
<select class="form-control" value={this.state.postForm.community_id} onInput={linkEvent(this, this.handlePostCommunityChange)}>
{this.state.communities.map(community =>
</div>
</div>
}
+ <div class="form-group row">
+ <div class="col-sm-10">
+ <div class="form-check">
+ <input class="form-check-input" type="checkbox" checked={this.state.postForm.nsfw} onChange={linkEvent(this, this.handlePostNsfwChange)}/>
+ <label class="form-check-label"><T i18nKey="nsfw">#</T></label>
+ </div>
+ </div>
+ </div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary mr-2">
{this.state.loading ?
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> :
- this.props.post ? 'Save' : 'Create'}</button>
- {this.props.post && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}>Cancel</button>}
+ this.props.post ? capitalizeFirstLetter(i18n.t('save')) : capitalizeFirstLetter(i18n.t('create'))}</button>
+ {this.props.post && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}><T i18nKey="cancel">#</T></button>}
</div>
</div>
</form>
handlePostUrlChange(i: PostForm, event: any) {
i.state.postForm.url = event.target.value;
- getPageTitle(i.state.postForm.url).then(d => {
- i.state.suggestedTitle = d;
- i.setState(i.state);
- });
+ if (validURL(i.state.postForm.url)) {
+
+ let form: SearchForm = {
+ q: i.state.postForm.url,
+ type_: SearchType[SearchType.Url],
+ sort: SortType[SortType.TopAll],
+ page: 1,
+ limit: 6,
+ };
+
+ WebSocketService.Instance.search(form);
+
+ // Fetch the page title
+ getPageTitle(i.state.postForm.url).then(d => {
+ i.state.suggestedTitle = d;
+ i.setState(i.state);
+ });
+ } else {
+ i.state.suggestedTitle = undefined;
+ i.state.crossPosts = [];
+ }
+
i.setState(i.state);
}
handlePostNameChange(i: PostForm, event: any) {
i.state.postForm.name = event.target.value;
+ let form: SearchForm = {
+ q: i.state.postForm.name,
+ type_: SearchType[SearchType.Posts],
+ sort: SortType[SortType.TopAll],
+ community_id: i.state.postForm.community_id,
+ page: 1,
+ limit: 6,
+ };
+
+ if (i.state.postForm.name !== '') {
+ WebSocketService.Instance.search(form);
+ } else {
+ i.state.suggestedPosts = [];
+ }
+
i.setState(i.state);
}
i.setState(i.state);
}
+ handlePostNsfwChange(i: PostForm, event: any) {
+ i.state.postForm.nsfw = event.target.checked;
+ i.setState(i.state);
+ }
+
handleCancel(i: PostForm) {
i.props.onCancel();
}
parseMessage(msg: any) {
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
this.state.loading = false;
this.setState(this.state);
return;
this.state.communities = res.communities;
if (this.props.post) {
this.state.postForm.community_id = this.props.post.community_id;
- } else if (this.props.prevCommunityName) {
- let foundCommunityId = res.communities.find(r => r.name == this.props.prevCommunityName).id;
+ } else if (this.props.params && this.props.params.community) {
+ let foundCommunityId = res.communities.find(r => r.name == this.props.params.community).id;
this.state.postForm.community_id = foundCommunityId;
} else {
this.state.postForm.community_id = res.communities[0].id;
this.state.loading = false;
let res: PostResponse = msg;
this.props.onEdit(res.post);
+ } else if (op == UserOperation.Search) {
+ let res: SearchResponse = msg;
+
+ if (res.type_ == SearchType[SearchType.Posts]) {
+ this.state.suggestedPosts = res.posts;
+ } else if (res.type_ == SearchType[SearchType.Url]) {
+ this.state.crossPosts = res.posts;
+ }
+ this.setState(this.state);
}
}
import { MomentTime } from './moment-time';
import { PostForm } from './post-form';
import { mdToHtml, canMod, isMod, isImage } from '../utils';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface PostListingState {
showEdit: boolean;
render() {
return (
- <div>
+ <div class="row">
{!this.state.showEdit
? this.listing()
: <PostForm post={this.props.post} onEdit={this.handleEditPost} onCancel={this.handleEditCancel}/>
listing() {
let post = this.props.post;
return (
- <div class="listing">
- <div className={`mr-1 float-left small text-center ${this.props.viewOnly && 'no-click'}`}>
- <div className={`pointer ${post.my_vote == 1 ? 'text-info' : 'text-muted'}`} onClick={linkEvent(this, this.handlePostLike)}>
+ <div class="listing col-12">
+ <div className={`vote-bar mr-2 float-left small text-center ${this.props.viewOnly && 'no-click'}`}>
+ <button className={`btn p-0 ${post.my_vote == 1 ? 'text-info' : 'text-muted'}`} onClick={linkEvent(this, this.handlePostLike)}>
<svg class="icon upvote"><use xlinkHref="#icon-arrow-up"></use></svg>
- </div>
+ </button>
<div class={`font-weight-bold text-muted`}>{post.score}</div>
- <div className={`pointer ${post.my_vote == -1 ? 'text-danger' : 'text-muted'}`} onClick={linkEvent(this, this.handlePostDisLike)}>
+ <button className={`btn p-0 ${post.my_vote == -1 ? 'text-danger' : 'text-muted'}`} onClick={linkEvent(this, this.handlePostDisLike)}>
<svg class="icon downvote"><use xlinkHref="#icon-arrow-down"></use></svg>
- </div>
+ </button>
</div>
{post.url && isImage(post.url) &&
- <span title="Expand here" class="pointer" onClick={linkEvent(this, this.handleImageExpandClick)}><img class="mx-2 float-left img-fluid thumbnail rounded" src={post.url} /></span>
+ <span title={i18n.t('expand_here')} class="pointer" onClick={linkEvent(this, this.handleImageExpandClick)}><img class="mx-2 mt-1 float-left img-fluid thumbnail rounded" src={post.url} /></span>
}
<div className="ml-4">
- <div>
+ <div className="post-title">
<h5 className="mb-0 d-inline">
{post.url ?
<a className="text-white" href={post.url} target="_blank" title={post.url}>{post.name}</a> :
- <Link className="text-white" to={`/post/${post.id}`} title="Comments">{post.name}</Link>
+ <Link className="text-white" to={`/post/${post.id}`} title={i18n.t('comments')}>{post.name}</Link>
}
</h5>
{post.url &&
<a className="ml-2 text-muted font-italic" href={post.url} target="_blank" title={post.url}>{(new URL(post.url)).hostname}</a>
</small>
}
- {post.removed &&
- <small className="ml-2 text-muted font-italic">removed</small>
- }
- {post.deleted &&
- <small className="ml-2 text-muted font-italic">deleted</small>
- }
- {post.locked &&
- <small className="ml-2 text-muted font-italic">locked</small>
- }
{ post.url && isImage(post.url) &&
<>
{ !this.state.imageExpanded
- ? <span class="badge badge-light pointer ml-2 text-muted small" title="Expand here" onClick={linkEvent(this, this.handleImageExpandClick)}>+</span>
+ ? <span class="text-monospace pointer ml-2 text-muted small" title={i18n.t('expand_here')} onClick={linkEvent(this, this.handleImageExpandClick)}>[+]</span>
:
<span>
- <span class="pointer ml-2 badge badge-light text-muted small" onClick={linkEvent(this, this.handleImageExpandClick)}>-</span>
+ <span class="text-monospace pointer ml-2 text-muted small" onClick={linkEvent(this, this.handleImageExpandClick)}>[-]</span>
<div>
<span class="pointer" onClick={linkEvent(this, this.handleImageExpandClick)}><img class="img-fluid" src={post.url} /></span>
</div>
}
</>
}
+ {post.removed &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="removed">#</T></small>
+ }
+ {post.deleted &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="deleted">#</T></small>
+ }
+ {post.locked &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="locked">#</T></small>
+ }
+ {post.nsfw &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small>
+ }
</div>
</div>
- <div className="details ml-4 mb-1">
+ <div className="details ml-4">
<ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item">
- <span>by </span>
+ <span>{i18n.t('by')} </span>
<Link className="text-info" to={`/u/${post.creator_name}`}>{post.creator_name}</Link>
{this.isMod &&
- <span className="mx-1 badge badge-light">mod</span>
+ <span className="mx-1 badge badge-light"><T i18nKey="mod">#</T></span>
}
{this.isAdmin &&
- <span className="mx-1 badge badge-light">admin</span>
+ <span className="mx-1 badge badge-light"><T i18nKey="admin">#</T></span>
}
{this.props.showCommunity &&
<span>
- <span> to </span>
+ <span> {i18n.t('to')} </span>
<Link to={`/c/${post.community_name}`}>{post.community_name}</Link>
</span>
}
</span>
</li>
<li className="list-inline-item">
- <Link className="text-muted" to={`/post/${post.id}`}>{post.number_of_comments} Comments</Link>
+ <Link className="text-muted" to={`/post/${post.id}`}><T i18nKey="number_of_comments" interpolation={{count: post.number_of_comments}}>#</T></Link>
</li>
</ul>
{UserService.Instance.user && this.props.editable &&
<ul class="list-inline mb-1 text-muted small font-weight-bold">
<li className="list-inline-item mr-2">
- <span class="pointer" onClick={linkEvent(this, this.handleSavePostClick)}>{post.saved ? 'unsave' : 'save'}</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleSavePostClick)}>{post.saved ? i18n.t('unsave') : i18n.t('save')}</span>
+ </li>
+ <li className="list-inline-item mr-2">
+ <Link className="text-muted" to={`/create_post${this.crossPostParams}`}><T i18nKey="cross_post">#</T></Link>
</li>
{this.myPost &&
<>
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}><T i18nKey="edit">#</T></span>
</li>
<li className="list-inline-item mr-2">
<span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>
- {!post.deleted ? 'delete' : 'restore'}
+ {!post.deleted ? i18n.t('delete') : i18n.t('restore')}
</span>
</li>
</>
<span>
<li className="list-inline-item">
{!this.props.post.removed ?
- <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}>remove</span> :
- <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}>restore</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}><T i18nKey="remove">#</T></span> :
+ <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}><T i18nKey="restore">#</T></span>
}
</li>
<li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleModLock)}>{this.props.post.locked ? 'unlock' : 'lock'}</span>
+ <span class="pointer" onClick={linkEvent(this, this.handleModLock)}>{this.props.post.locked ? i18n.t('unlock') : i18n.t('lock')}</span>
</li>
</span>
}
}
{this.state.showRemoveDialog &&
<form class="form-inline" onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
- <input type="text" class="form-control mr-2" placeholder="Reason" value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />
- <button type="submit" class="btn btn-secondary">Remove Post</button>
+ <input type="text" class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />
+ <button type="submit" class="btn btn-secondary"><T i18nKey="remove_post">#</T></button>
</form>
}
{this.props.showBody && this.props.post.body && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(post.body)} />}
edit_id: i.props.post.id,
creator_id: i.props.post.creator_id,
deleted: !i.props.post.deleted,
+ nsfw: i.props.post.nsfw,
auth: null
};
WebSocketService.Instance.editPost(deleteForm);
WebSocketService.Instance.savePost(form);
}
+ get crossPostParams(): string {
+ let params = `?name=${this.props.post.name}`;
+ if (this.props.post.url) {
+ params += `&url=${this.props.post.url}`;
+ }
+ if (this.props.post.body) {
+ params += `&body=${this.props.post.body}`;
+ }
+ return params;
+ }
+
handleModRemoveShow(i: PostListing) {
i.state.showRemoveDialog = true;
i.setState(i.state);
creator_id: i.props.post.creator_id,
removed: !i.props.post.removed,
reason: i.state.removeReason,
+ nsfw: i.props.post.nsfw,
auth: null,
};
WebSocketService.Instance.editPost(form);
community_id: i.props.post.community_id,
edit_id: i.props.post.id,
creator_id: i.props.post.creator_id,
+ nsfw: i.props.post.nsfw,
locked: !i.props.post.locked,
auth: null,
};
import { Link } from 'inferno-router';
import { Post } from '../interfaces';
import { PostListing } from './post-listing';
+import { T } from 'inferno-i18next';
interface PostListingsProps {
posts: Array<Post>;
return (
<div>
{this.props.posts.length > 0 ? this.props.posts.map(post =>
- <PostListing post={post} showCommunity={this.props.showCommunity} />) :
- <div>No posts. {this.props.showCommunity !== undefined && <span>Subscribe to some <Link to="/communities">communities</Link>.</span>}
- </div>
+ <>
+ <PostListing post={post} showCommunity={this.props.showCommunity} />
+ <hr class="my-2" />
+ </>
+ ) :
+ <>
+ <div><T i18nKey="no_posts">#</T></div>
+ {this.props.showCommunity !== undefined && <div><T i18nKey="subscribe_to_communities">#<Link to="/communities">#</Link></T></div>}
+ </>
}
</div>
)
import { Component, linkEvent } from 'inferno';
import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators';
-import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentSortType, CreatePostLikeResponse, CommunityUser, CommunityResponse, CommentNode as CommentNodeI, BanFromCommunityResponse, BanUserResponse, AddModToCommunityResponse, AddAdminResponse, UserView } from '../interfaces';
+import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentSortType, CreatePostLikeResponse, CommunityUser, CommunityResponse, CommentNode as CommentNodeI, BanFromCommunityResponse, BanUserResponse, AddModToCommunityResponse, AddAdminResponse, UserView, SearchType, SortType, SearchForm, SearchResponse, GetSiteResponse, GetCommunityResponse } from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { msgOp, hotRank } from '../utils';
import { PostListing } from './post-listing';
+import { PostListings } from './post-listings';
import { Sidebar } from './sidebar';
import { CommentForm } from './comment-form';
import { CommentNodes } from './comment-nodes';
import * as autosize from 'autosize';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface PostState {
post: PostI;
scrolled?: boolean;
scrolled_comment_id?: number;
loading: boolean;
+ crossPosts: Array<PostI>;
}
export class Post extends Component<any, PostState> {
moderators: [],
admins: [],
scrolled: false,
- loading: true
+ loading: true,
+ crossPosts: [],
}
constructor(props: any, context: any) {
this.state.scrolled = true;
this.markScrolledAsRead(this.state.scrolled_comment_id);
}
+
+ // Necessary if you are on a post and you click another post (same route)
+ if (_lastProps.location.pathname !== _lastProps.history.location.pathname) {
+ // Couldnt get a refresh working. This does for now.
+ location.reload();
+
+ // let currentId = this.props.match.params.id;
+ // WebSocketService.Instance.getPost(currentId);
+ // this.context.router.history.push('/sponsors');
+ // this.context.refresh();
+ // this.context.router.history.push(_lastProps.location.pathname);
+
+ }
}
markScrolledAsRead(commentId: number) {
{this.state.loading ?
<h5><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> :
<div class="row">
- <div class="col-12 col-md-8 col-lg-6 mb-3">
+ <div class="col-12 col-md-8 mb-3">
<PostListing
post={this.state.post}
showBody
moderators={this.state.moderators}
admins={this.state.admins}
/>
+ {this.state.crossPosts.length > 0 &&
+ <>
+ <div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div>
+ <PostListings showCommunity posts={this.state.crossPosts} />
+ </>
+ }
<div className="mb-2" />
<CommentForm postId={this.state.post.id} disabled={this.state.post.locked} />
{this.sortRadios()}
{this.commentsTree()}
</div>
- <div class="col-12 col-md-4 col-lg-3 mb-3 d-none d-md-block px-0">
- {this.state.comments.length > 0 && this.newComments()}
- </div>
- <div class="col-12 col-sm-12 col-lg-3">
+ <div class="col-12 col-sm-12 col-md-4">
{this.sidebar()}
+ {this.state.comments.length > 0 && this.newComments()}
</div>
</div>
}
sortRadios() {
return (
<div class="btn-group btn-group-toggle mb-3">
- <label className={`btn btn-sm btn-secondary pointer ${this.state.commentSort === CommentSortType.Hot && 'active'}`}>Hot
+ <label className={`btn btn-sm btn-secondary pointer ${this.state.commentSort === CommentSortType.Hot && 'active'}`}>{i18n.t('hot')}
<input type="radio" value={CommentSortType.Hot}
checked={this.state.commentSort === CommentSortType.Hot}
onChange={linkEvent(this, this.handleCommentSortChange)} />
</label>
- <label className={`btn btn-sm btn-secondary pointer ${this.state.commentSort === CommentSortType.Top && 'active'}`}>Top
+ <label className={`btn btn-sm btn-secondary pointer ${this.state.commentSort === CommentSortType.Top && 'active'}`}>{i18n.t('top')}
<input type="radio" value={CommentSortType.Top}
checked={this.state.commentSort === CommentSortType.Top}
onChange={linkEvent(this, this.handleCommentSortChange)} />
</label>
- <label className={`btn btn-sm btn-secondary pointer ${this.state.commentSort === CommentSortType.New && 'active'}`}>New
+ <label className={`btn btn-sm btn-secondary pointer ${this.state.commentSort === CommentSortType.New && 'active'}`}>{i18n.t('new')}
<input type="radio" value={CommentSortType.New}
checked={this.state.commentSort === CommentSortType.New}
onChange={linkEvent(this, this.handleCommentSortChange)} />
newComments() {
return (
- <div class="container-fluid sticky-top new-comments">
- <h5>Chat</h5>
- <CommentForm postId={this.state.post.id} disabled={this.state.post.locked} />
- {this.state.comments.map(comment =>
- <CommentNodes
- nodes={[{comment: comment}]}
- noIndent
- locked={this.state.post.locked}
- moderators={this.state.moderators}
- admins={this.state.admins}
- />
- )}
+ <div class="d-none d-md-block sticky-top new-comments card border-secondary">
+ <div class="card-body small">
+ <h6><T i18nKey="recent_comments">#</T></h6>
+ {this.state.comments.map(comment =>
+ <CommentNodes
+ nodes={[{comment: comment}]}
+ noIndent
+ locked={this.state.post.locked}
+ moderators={this.state.moderators}
+ admins={this.state.admins}
+ />
+ )}
+ </div>
</div>
)
}
sidebar() {
return (
- <div class="">
+ <div class="mb-3">
<Sidebar
community={this.state.community}
moderators={this.state.moderators}
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.GetPost) {
let res: GetPostResponse = msg;
this.state.post = res.post;
- this.state.post = res.post;
this.state.comments = res.comments;
this.state.community = res.community;
this.state.moderators = res.moderators;
this.state.admins = res.admins;
this.state.loading = false;
- document.title = `${this.state.post.name} - Lemmy`;
+ document.title = `${this.state.post.name} - ${WebSocketService.Instance.site.name}`;
+
+ // Get cross-posts
+ if (this.state.post.url) {
+ let form: SearchForm = {
+ q: this.state.post.url,
+ type_: SearchType[SearchType.Url],
+ sort: SortType[SortType.TopAll],
+ page: 1,
+ limit: 6,
+ };
+ WebSocketService.Instance.search(form);
+ }
+
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
let res: CommentResponse = msg;
let res: AddAdminResponse = msg;
this.state.admins = res.admins;
this.setState(this.state);
+ } else if (op == UserOperation.Search) {
+ let res: SearchResponse = msg;
+ this.state.crossPosts = res.posts.filter(p => p.id != this.state.post.id);
+ this.setState(this.state);
+ } else if (op == UserOperation.TransferSite) {
+ let res: GetSiteResponse = msg;
+
+ this.state.admins = res.admins;
+ this.setState(this.state);
+ } else if (op == UserOperation.TransferCommunity) {
+ let res: GetCommunityResponse = msg;
+ this.state.community = res.community;
+ this.state.moderators = res.moderators;
+ this.state.admins = res.admins;
+ this.setState(this.state);
}
}
import { Component, linkEvent } from 'inferno';
+import { Link } from 'inferno-router';
import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators';
-import { UserOperation, Post, Comment, SortType, SearchForm, SearchResponse, SearchType } from '../interfaces';
+import { UserOperation, Post, Comment, Community, UserView, SortType, SearchForm, SearchResponse, SearchType } from '../interfaces';
import { WebSocketService } from '../services';
import { msgOp, fetchLimit } from '../utils';
import { PostListing } from './post-listing';
import { CommentNodes } from './comment-nodes';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface SearchState {
q: string,
private subscription: Subscription;
private emptyState: SearchState = {
q: undefined,
- type_: SearchType.Both,
+ type_: SearchType.All,
sort: SortType.TopAll,
page: 1,
searchResponse: {
op: null,
+ type_: null,
posts: [],
comments: [],
+ communities: [],
+ users: [],
},
loading: false,
}
}
componentDidMount() {
- document.title = "Search - Lemmy";
+ document.title = `${i18n.t('search')} - ${WebSocketService.Instance.site.name}`;
}
render() {
<div class="container">
<div class="row">
<div class="col-12">
- <h5>Search</h5>
+ <h5><T i18nKey="search">#</T></h5>
{this.selects()}
{this.searchForm()}
- {this.state.type_ == SearchType.Both &&
- this.both()
+ {this.state.type_ == SearchType.All &&
+ this.all()
}
{this.state.type_ == SearchType.Comments &&
this.comments()
{this.state.type_ == SearchType.Posts &&
this.posts()
}
+ {this.state.type_ == SearchType.Communities &&
+ this.communities()
+ }
+ {this.state.type_ == SearchType.Users &&
+ this.users()
+ }
{this.noResults()}
{this.paginator()}
</div>
searchForm() {
return (
<form class="form-inline" onSubmit={linkEvent(this, this.handleSearchSubmit)}>
- <input type="text" class="form-control mr-2" value={this.state.q} placeholder="Search..." onInput={linkEvent(this, this.handleQChange)} required minLength={3} />
+ <input type="text" class="form-control mr-2" value={this.state.q} placeholder={`${i18n.t('search')}...`} onInput={linkEvent(this, this.handleQChange)} required minLength={3} />
<button type="submit" class="btn btn-secondary mr-2">
{this.state.loading ?
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> :
- <span>Search</span>
+ <span><T i18nKey="search">#</T></span>
}
</button>
</form>
return (
<div className="mb-2">
<select value={this.state.type_} onChange={linkEvent(this, this.handleTypeChange)} class="custom-select custom-select-sm w-auto">
- <option disabled>Type</option>
- <option value={SearchType.Both}>Both</option>
- <option value={SearchType.Comments}>Comments</option>
- <option value={SearchType.Posts}>Posts</option>
+ <option disabled><T i18nKey="type">#</T></option>
+ <option value={SearchType.All}><T i18nKey="all">#</T></option>
+ <option value={SearchType.Comments}><T i18nKey="comments">#</T></option>
+ <option value={SearchType.Posts}><T i18nKey="posts">#</T></option>
+ <option value={SearchType.Communities}><T i18nKey="communities">#</T></option>
+ <option value={SearchType.Users}><T i18nKey="users">#</T></option>
</select>
<select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="custom-select custom-select-sm w-auto ml-2">
- <option disabled>Sort Type</option>
- <option value={SortType.New}>New</option>
- <option value={SortType.TopDay}>Top Day</option>
- <option value={SortType.TopWeek}>Week</option>
- <option value={SortType.TopMonth}>Month</option>
- <option value={SortType.TopYear}>Year</option>
- <option value={SortType.TopAll}>All</option>
+ <option disabled><T i18nKey="sort_type">#</T></option>
+ <option value={SortType.New}><T i18nKey="new">#</T></option>
+ <option value={SortType.TopDay}><T i18nKey="top_day">#</T></option>
+ <option value={SortType.TopWeek}><T i18nKey="week">#</T></option>
+ <option value={SortType.TopMonth}><T i18nKey="month">#</T></option>
+ <option value={SortType.TopYear}><T i18nKey="year">#</T></option>
+ <option value={SortType.TopAll}><T i18nKey="all">#</T></option>
</select>
</div>
)
}
- both() {
- let combined: Array<{type_: string, data: Comment | Post}> = [];
+ all() {
+ let combined: Array<{type_: string, data: Comment | Post | Community | UserView}> = [];
let comments = this.state.searchResponse.comments.map(e => {return {type_: "comments", data: e}});
let posts = this.state.searchResponse.posts.map(e => {return {type_: "posts", data: e}});
+ let communities = this.state.searchResponse.communities.map(e => {return {type_: "communities", data: e}});
+ let users = this.state.searchResponse.users.map(e => {return {type_: "users", data: e}});
combined.push(...comments);
combined.push(...posts);
+ combined.push(...communities);
+ combined.push(...users);
// Sort it
if (this.state.sort == SortType.New) {
combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
} else {
- combined.sort((a, b) => b.data.score - a.data.score);
+ combined.sort((a, b) => ((b.data as Comment | Post).score
+ | (b.data as Community).number_of_subscribers
+ | (b.data as UserView).comment_score)
+ - ((a.data as Comment | Post).score
+ | (a.data as Community).number_of_subscribers
+ | (a.data as UserView).comment_score));
}
return (
<div>
{combined.map(i =>
<div>
- {i.type_ == "posts"
- ? <PostListing post={i.data as Post} showCommunity viewOnly />
- : <CommentNodes nodes={[{comment: i.data as Comment}]} viewOnly noIndent />
+ {i.type_ == "posts" &&
+ <PostListing post={i.data as Post} showCommunity viewOnly />
+ }
+ {i.type_ == "comments" &&
+ <CommentNodes nodes={[{comment: i.data as Comment}]} viewOnly noIndent />
+ }
+ {i.type_ == "communities" &&
+ <div>
+ <span><Link to={`/c/${(i.data as Community).name}`}>{`/c/${(i.data as Community).name}`}</Link></span>
+ <span>{` - ${(i.data as Community).title} - ${(i.data as Community).number_of_subscribers} subscribers`}</span>
+ </div>
+ }
+ {i.type_ == "users" &&
+ <div>
+ <span><Link className="text-info" to={`/u/${(i.data as UserView).name}`}>{`/u/${(i.data as UserView).name}`}</Link></span>
+ <span>{` - ${(i.data as UserView).comment_score} comment karma`}</span>
+ </div>
}
</div>
)
);
}
+ // Todo possibly create UserListing and CommunityListing
+ communities() {
+ return (
+ <div>
+ {this.state.searchResponse.communities.map(community =>
+ <div>
+ <span><Link to={`/c/${community.name}`}>{`/c/${community.name}`}</Link></span>
+ <span>{` - ${community.title} - ${community.number_of_subscribers} subscribers`}</span>
+ </div>
+ )}
+ </div>
+ );
+ }
+
+ users() {
+ return (
+ <div>
+ {this.state.searchResponse.users.map(user =>
+ <div>
+ <span><Link className="text-info" to={`/u/${user.name}`}>{`/u/${user.name}`}</Link></span>
+ <span>{` - ${user.comment_score} comment karma`}</span>
+ </div>
+ )}
+ </div>
+ );
+ }
+
paginator() {
return (
<div class="mt-2">
{this.state.page > 1 &&
- <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
+ <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
}
- <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
+ <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
</div>
);
}
return (
<div>
{res && res.op && res.posts.length == 0 && res.comments.length == 0 &&
- <span>No Results</span>
+ <span><T i18nKey="no_results">#</T></span>
}
</div>
)
i.state.sort = Number(event.target.value);
i.state.page = 1;
i.setState(i.state);
- i.search();
}
handleTypeChange(i: Search, event: any) {
i.state.type_ = Number(event.target.value);
i.state.page = 1;
i.setState(i.state);
- i.search();
}
handleSearchSubmit(i: Search, event: any) {
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.Search) {
let res: SearchResponse = msg;
this.state.searchResponse = res;
this.state.loading = false;
- document.title = `Search - ${this.state.q} - Lemmy`;
+ document.title = `${i18n.t('search')} - ${this.state.q} - ${WebSocketService.Instance.site.name}`;
window.scrollTo(0,0);
this.setState(this.state);
-
}
}
}
import { WebSocketService, UserService } from '../services';
import { msgOp } from '../utils';
import { SiteForm } from './site-form';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface State {
userForm: RegisterForm;
password: undefined,
password_verify: undefined,
admin: true,
+ show_nsfw: true,
},
doneRegisteringUser: false,
userLoading: false,
}
componentDidMount() {
- document.title = "Setup - Lemmy";
+ document.title = `${i18n.t('setup')} - Lemmy`;
}
render() {
<div class="container">
<div class="row">
<div class="col-12 offset-lg-3 col-lg-6">
- <h3>Lemmy Instance Setup</h3>
+ <h3><T i18nKey="lemmy_instance_setup">#</T></h3>
{!this.state.doneRegisteringUser ? this.registerUser() : <SiteForm />}
</div>
</div>
registerUser() {
return (
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
- <h5>Set up Site Administrator</h5>
+ <h5><T i18nKey="setup_admin">#</T></h5>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Username</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="username">#</T></label>
<div class="col-sm-10">
<input type="text" class="form-control" value={this.state.userForm.username} onInput={linkEvent(this, this.handleRegisterUsernameChange)} required minLength={3} maxLength={20} pattern="[a-zA-Z0-9_]+" />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Email</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="email">#</T></label>
<div class="col-sm-10">
- <input type="email" class="form-control" placeholder="Optional" value={this.state.userForm.email} onInput={linkEvent(this, this.handleRegisterEmailChange)} minLength={3} />
+ <input type="email" class="form-control" placeholder={i18n.t('optional')} value={this.state.userForm.email} onInput={linkEvent(this, this.handleRegisterEmailChange)} minLength={3} />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Password</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="password">#</T></label>
<div class="col-sm-10">
<input type="password" value={this.state.userForm.password} onInput={linkEvent(this, this.handleRegisterPasswordChange)} class="form-control" required />
</div>
</div>
<div class="form-group row">
- <label class="col-sm-2 col-form-label">Verify Password</label>
+ <label class="col-sm-2 col-form-label"><T i18nKey="verify_password">#</T></label>
<div class="col-sm-10">
<input type="password" value={this.state.userForm.password_verify} onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)} class="form-control" required />
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">{this.state.userLoading ?
- <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : 'Sign Up'}</button>
+ <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : i18n.t('sign_up')}</button>
</div>
</div>
parseMessage(msg: any) {
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
this.state.userLoading = false;
this.setState(this.state);
return;
import { WebSocketService, UserService } from '../services';
import { mdToHtml, getUnixTime } from '../utils';
import { CommunityForm } from './community-form';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface SidebarProps {
community: Community;
let community = this.props.community;
return (
<div>
- <h5 className="mb-0">{community.title}
- {community.removed &&
- <small className="ml-2 text-muted font-italic">removed</small>
- }
- {community.deleted &&
- <small className="ml-2 text-muted font-italic">deleted</small>
- }
- </h5>
- <Link className="text-muted" to={`/c/${community.name}`}>/c/{community.name}</Link>
- <ul class="list-inline mb-1 text-muted small font-weight-bold">
- {this.canMod &&
- <>
- <li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span>
- </li>
- {this.amCreator &&
- <li className="list-inline-item">
- <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>
- {!community.deleted ? 'delete' : 'restore'}
- </span>
- </li>
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ <h5 className="mb-0">
+ <span>{community.title}</span>
+ {community.removed &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="removed">#</T></small>
+ }
+ {community.deleted &&
+ <small className="ml-2 text-muted font-italic"><T i18nKey="deleted">#</T></small>
+ }
+ </h5>
+ <Link className="text-muted" to={`/c/${community.name}`}>/c/{community.name}</Link>
+ <ul class="list-inline mb-1 text-muted small font-weight-bold">
+ {this.canMod &&
+ <>
+ <li className="list-inline-item">
+ <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}><T i18nKey="edit">#</T></span>
+ </li>
+ {this.amCreator &&
+ <li className="list-inline-item">
+ <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>
+ {!community.deleted ? i18n.t('delete') : i18n.t('restore')}
+ </span>
+ </li>
+ }
+ </>
+ }
+ {this.canAdmin &&
+ <li className="list-inline-item">
+ {!this.props.community.removed ?
+ <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}><T i18nKey="remove">#</T></span> :
+ <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}><T i18nKey="restore">#</T></span>
+ }
+ </li>
+
+ }
+ </ul>
+ {this.state.showRemoveDialog &&
+ <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
+ <div class="form-group row">
+ <label class="col-form-label"><T i18nKey="reason">#</T></label>
+ <input type="text" class="form-control mr-2" placeholder={i18n.t('optional')} value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />
+ </div>
+ {/* TODO hold off on expires for now */}
+ {/* <div class="form-group row"> */}
+ {/* <label class="col-form-label">Expires</label> */}
+ {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
+ {/* </div> */}
+ <div class="form-group row">
+ <button type="submit" class="btn btn-secondary"><T i18nKey="remove_community">#</T></button>
+ </div>
+ </form>
}
- </>
- }
- {this.canAdmin &&
- <li className="list-inline-item">
- {!this.props.community.removed ?
- <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}>remove</span> :
- <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}>restore</span>
+ <ul class="my-1 list-inline">
+ <li className="list-inline-item"><Link className="badge badge-secondary" to="/communities">{community.category_name}</Link></li>
+ <li className="list-inline-item badge badge-secondary"><T i18nKey="number_of_subscribers" interpolation={{count: community.number_of_subscribers}}>#</T></li>
+ <li className="list-inline-item badge badge-secondary"><T i18nKey="number_of_posts" interpolation={{count: community.number_of_posts}}>#</T></li>
+ <li className="list-inline-item badge badge-secondary"><T i18nKey="number_of_comments" interpolation={{count: community.number_of_comments}}>#</T></li>
+ <li className="list-inline-item"><Link className="badge badge-secondary" to={`/modlog/community/${this.props.community.id}`}><T i18nKey="modlog">#</T></Link></li>
+ </ul>
+ <ul class="list-inline small">
+ <li class="list-inline-item">{i18n.t('mods')}: </li>
+ {this.props.moderators.map(mod =>
+ <li class="list-inline-item"><Link class="text-info" to={`/u/${mod.user_name}`}>{mod.user_name}</Link></li>
+ )}
+ </ul>
+ <Link class={`btn btn-sm btn-secondary btn-block mb-3 ${(community.deleted || community.removed) && 'no-click'}`}
+ to={`/create_post?community=${community.name}`}><T i18nKey="create_a_post">#</T></Link>
+ <div>
+ {community.subscribed
+ ? <button class="btn btn-sm btn-secondary btn-block" onClick={linkEvent(community.id, this.handleUnsubscribe)}><T i18nKey="unsubscribe">#</T></button>
+ : <button class="btn btn-sm btn-secondary btn-block" onClick={linkEvent(community.id, this.handleSubscribe)}><T i18nKey="subscribe">#</T></button>
}
- </li>
-
- }
- </ul>
- {this.state.showRemoveDialog &&
- <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
- <div class="form-group row">
- <label class="col-form-label">Reason</label>
- <input type="text" class="form-control mr-2" placeholder="Optional" value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />
</div>
- {/* TODO hold off on expires for now */}
- {/* <div class="form-group row"> */}
- {/* <label class="col-form-label">Expires</label> */}
- {/* <input type="date" class="form-control mr-2" placeholder="Expires" value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
- {/* </div> */}
- <div class="form-group row">
- <button type="submit" class="btn btn-secondary">Remove Community</button>
+ </div>
+ </div>
+ {community.description &&
+ <div class="card border-secondary">
+ <div class="card-body">
+ <div className="md-div" dangerouslySetInnerHTML={mdToHtml(community.description)} />
+ </div>
</div>
- </form>
- }
- <ul class="my-1 list-inline">
- <li className="list-inline-item"><Link className="badge badge-light" to="/communities">{community.category_name}</Link></li>
- <li className="list-inline-item badge badge-light">{community.number_of_subscribers} Subscribers</li>
- <li className="list-inline-item badge badge-light">{community.number_of_posts} Posts</li>
- <li className="list-inline-item badge badge-light">{community.number_of_comments} Comments</li>
- <li className="list-inline-item"><Link className="badge badge-light" to={`/modlog/community/${this.props.community.id}`}>Modlog</Link></li>
- </ul>
- <ul class="list-inline small">
- <li class="list-inline-item">mods: </li>
- {this.props.moderators.map(mod =>
- <li class="list-inline-item"><Link class="text-info" to={`/u/${mod.user_name}`}>{mod.user_name}</Link></li>
- )}
- </ul>
- <Link class="btn btn-sm btn-secondary btn-block mb-3"
- to={`/create_post/c/${community.name}`}>Create a Post</Link>
- <div>
- {community.subscribed
- ? <button class="btn btn-sm btn-secondary btn-block mb-3" onClick={linkEvent(community.id, this.handleUnsubscribe)}>Unsubscribe</button>
- : <button class="btn btn-sm btn-secondary btn-block mb-3" onClick={linkEvent(community.id, this.handleSubscribe)}>Subscribe</button>
}
- </div>
- {community.description &&
- <div>
- <hr />
- <div className="md-div" dangerouslySetInnerHTML={mdToHtml(community.description)} />
- <hr />
</div>
- }
- </div>
);
}
category_id: i.props.community.category_id,
edit_id: i.props.community.id,
deleted: !i.props.community.deleted,
+ nsfw: i.props.community.nsfw,
auth: null,
};
WebSocketService.Instance.editCommunity(deleteForm);
removed: !i.props.community.removed,
reason: i.state.removeReason,
expires: getUnixTime(i.state.removeExpires),
+ nsfw: i.props.community.nsfw,
auth: null,
};
WebSocketService.Instance.editCommunity(deleteForm);
import { Component, linkEvent } from 'inferno';
import { Site, SiteForm as SiteFormI } from '../interfaces';
import { WebSocketService } from '../services';
+import { capitalizeFirstLetter } from '../utils';
import * as autosize from 'autosize';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
interface SiteFormProps {
site?: Site; // If a site is given, that means this is an edit
render() {
return (
<form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
- <h5>{`${this.props.site ? 'Edit' : 'Name'} your Site`}</h5>
+ <h5>{`${this.props.site ? capitalizeFirstLetter(i18n.t('edit')) : capitalizeFirstLetter(i18n.t('name'))} ${i18n.t('your_site')}`}</h5>
<div class="form-group row">
- <label class="col-12 col-form-label">Name</label>
+ <label class="col-12 col-form-label"><T i18nKey="name">#</T></label>
<div class="col-12">
<input type="text" class="form-control" value={this.state.siteForm.name} onInput={linkEvent(this, this.handleSiteNameChange)} required minLength={3} maxLength={20} />
</div>
</div>
<div class="form-group row">
- <label class="col-12 col-form-label">Sidebar</label>
+ <label class="col-12 col-form-label"><T i18nKey="sidebar">#</T></label>
<div class="col-12">
<textarea value={this.state.siteForm.description} onInput={linkEvent(this, this.handleSiteDescriptionChange)} class="form-control" rows={3} maxLength={10000} />
</div>
<button type="submit" class="btn btn-secondary mr-2">
{this.state.loading ?
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> :
- this.props.site ? 'Save' : 'Create'}</button>
- {this.props.site && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}>Cancel</button>}
+ this.props.site ? capitalizeFirstLetter(i18n.t('save')) : capitalizeFirstLetter(i18n.t('create'))}</button>
+ {this.props.site && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}><T i18nKey="cancel">#</T></button>}
</div>
</div>
</form>
import { Component } from 'inferno';
+import { WebSocketService } from '../services';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
let general =
[
}
componentDidMount() {
- document.title = "Sponsors - Lemmy";
+ document.title = `${i18n.t('sponsors')} - ${WebSocketService.Instance.site.name}`;
}
render() {
topMessage() {
return (
<div>
- <h5>Sponsors of Lemmy</h5>
+ <h5><T i18nKey="sponsors_of_lemmy">#</T></h5>
<p>
- Lemmy is free, <a href="https://github.com/dessalines/lemmy">open-source</a> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:
+ <T i18nKey="sponsor_message">#<a href="https://github.com/dessalines/lemmy">#</a></T>
</p>
- <a class="btn btn-secondary" href="https://www.patreon.com/dessalines">Support on Patreon</a>
+ <a class="btn btn-secondary" href="https://www.patreon.com/dessalines"><T i18nKey="support_on_patreon">#</T></a>
</div>
)
}
sponsors() {
return (
<div class="container">
- <h5>Sponsors</h5>
- <p>General Sponsors are those that pledged $10 to $39 to Lemmy.</p>
+ <h5><T i18nKey="sponsors">#</T></h5>
+ <p><T i18nKey="general_sponsors">#</T></p>
<div class="row card-columns">
{general.map(s =>
<div class="card col-12 col-md-2">
bitcoin() {
return (
<div>
- <h5>Crypto</h5>
+ <h5><T i18nKey="crypto">#</T></h5>
<div class="table-responsive">
<table class="table table-hover text-center">
<tbody>
<tr>
- <td>Bitcoin</td>
+ <td><T i18nKey="bitcoin">#</T></td>
<td><code>1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK</code></td>
</tr>
<tr>
- <td>Ethereum</td>
+ <td><T i18nKey="ethereum">#</T></td>
<td><code>0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01</code></td>
</tr>
+ <tr>
+ <td><T i18nKey="monero">#</T></td>
+ <td>
+ <code>41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV</code>
+ </td>
+ </tr>
</tbody>
</table>
</div>
<path d="M28 5h-24c-2.209 0-4 1.792-4 4v13c0 2.209 1.791 4 4 4h24c2.209 0 4-1.791 4-4v-13c0-2.208-1.791-4-4-4zM2 10.25l6.999 5.25-6.999 5.25v-10.5zM30 22c0 1.104-0.898 2-2 2h-24c-1.103 0-2-0.896-2-2l7.832-5.875 4.368 3.277c0.533 0.398 1.166 0.6 1.8 0.6 0.633 0 1.266-0.201 1.799-0.6l4.369-3.277 7.832 5.875zM30 20.75l-7-5.25 7-5.25v10.5zM17.199 18.602c-0.349 0.262-0.763 0.4-1.199 0.4s-0.851-0.139-1.2-0.4l-12.8-9.602c0-1.103 0.897-2 2-2h24c1.102 0 2 0.897 2 2l-12.801 9.602z"></path>
</symbol>
<symbol id="icon-mouse" version="1.1" x="0px" y="0px"
- viewBox="0 0 512 512">
- <g>
- <g>
- <path d="M499.059,323.505l-7.52-32.532l-70.047,16.19c1.513-11.983,2.297-24.042,2.297-36.037c0-18.334-1.801-35.785-5.316-52.19
- c29.365-12.101,55.143-28.885,69.372-45.529c17.524-20.498,25.985-46.568,23.822-73.406
- c-2.163-26.862-14.706-51.268-35.316-68.724C433.879-4.694,369.917,0.439,333.774,42.718
- c-9.546,11.168-18.318,27.381-25.379,46.649c-16.512-5.419-34.132-8.243-52.395-8.243s-35.885,2.824-52.395,8.243
- c-7.06-19.267-15.832-35.481-25.379-46.649C142.082,0.44,78.123-4.695,35.648,31.277C15.038,48.733,2.494,73.141,0.332,100.001
- c-2.161,26.838,6.297,52.907,23.822,73.406c14.229,16.644,40.006,33.427,69.372,45.529c-3.515,16.405-5.316,33.856-5.316,52.189
- c0,11.995,0.785,24.053,2.297,36.037l-70.047-16.19l-7.52,32.532l84.337,19.492c4.349,17.217,10.201,33.953,17.421,49.752
- L12.941,416.27l7.52,32.532l110.634-25.57c1.38,2.197,2.779,4.373,4.218,6.509c32.548,48.323,75.409,74.934,120.687,74.934
- c45.278,0,88.138-26.612,120.687-74.934c1.439-2.136,2.839-4.313,4.218-6.509l110.634,25.57l7.52-32.532l-101.758-23.519
- c7.221-15.799,13.072-32.535,17.421-49.752L499.059,323.505z M183.578,220.372c0-11.41,9.189-20.65,20.482-20.65
- c11.306,0,20.494,9.24,20.494,20.65c0,11.408-9.188,20.656-20.494,20.656C192.768,241.028,183.578,231.78,183.578,220.372z
- M256,413.29c-29.895,0-54.216-19.471-54.216-43.403c0-23.932,24.322-43.403,54.216-43.403s54.216,19.471,54.216,43.403
- C310.216,393.819,285.895,413.29,256,413.29z M307.785,241.183c-11.402,0-20.65-9.317-20.65-20.81
- c0-11.494,9.248-20.81,20.65-20.81c11.387,0,20.635,9.317,20.635,20.81C328.422,231.866,319.173,241.183,307.785,241.183z"/>
- </g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
- <g>
- </g>
+ viewBox="0 0 1024 1024">
+ <g
+ id="layer1"
+ transform="translate(0,-26.066658)"
+ style="display:inline">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 167.03908,270.78735 c -0.94784,-0.002 -1.8939,0.004 -2.83789,0.0215 -4.31538,0.0778 -8.58934,0.3593 -12.8125,0.8457 -33.78522,3.89116 -64.215716,21.86394 -82.871086,53.27344 -18.27982,30.77718 -22.77749,64.66635 -13.46094,96.06837 9.31655,31.40203 31.88488,59.93174 65.296886,82.5332 0.20163,0.13618 0.40678,0.26709 0.61523,0.39258 28.65434,17.27768 57.18167,28.93179 87.74218,34.95508 -0.74566,12.61339 -0.72532,25.5717 0.082,38.84375 2.43989,40.10943 16.60718,77.03742 38.0957,109.67187 l -77.00781,31.4375 c -8.30605,3.25932 -12.34178,12.68234 -8.96967,20.94324 3.37211,8.2609 12.84919,12.16798 21.06342,8.68371 l 84.69727,-34.57617 c 15.70675,18.72702 33.75346,35.68305 53.12109,50.57032 0.74013,0.56891 1.4904,1.12236 2.23437,1.68554 l -49.61132,65.69141 c -5.45446,7.0474 -4.10058,17.19288 3.01098,22.5634 7.11156,5.37052 17.24028,3.89649 22.52612,-3.27824 l 50.38672,-66.71876 c 27.68572,17.53469 57.07524,31.20388 86.07227,40.25196 14.88153,27.28008 43.96965,44.64648 77.58789,44.64648 33.93762,0 63.04252,-18.68693 77.80082,-45.4375 28.7072,-9.21295 57.7527,-22.93196 85.1484,-40.40234 l 51.0977,67.66016 c 5.2858,7.17473 15.4145,8.64876 22.5261,3.27824 7.1115,-5.37052 8.4654,-15.516 3.011,-22.5634 l -50.3614,-66.68555 c 0.334,-0.25394 0.6727,-0.50077 1.0059,-0.75586 19.1376,-14.64919 37.0259,-31.28581 52.7031,-49.63476 l 82.5625,33.70507 c 8.2143,3.48427 17.6913,-0.42281 21.0634,-8.68371 3.3722,-8.2609 -0.6636,-17.68392 -8.9696,-20.94324 l -74.5391,-30.42773 c 22.1722,-32.82971 37.0383,-70.03397 40.1426,-110.46094 1.0253,-13.35251 1.2292,-26.42535 0.6387,-39.17578 30.3557,-6.05408 58.7164,-17.66833 87.2011,-34.84375 0.2085,-0.12549 0.4136,-0.2564 0.6153,-0.39258 33.412,-22.60147 55.9803,-51.13117 65.2968,-82.5332 9.3166,-31.40202 4.8189,-65.29118 -13.4609,-96.06837 -18.6553,-31.40951 -49.0859,-49.38228 -82.8711,-53.27344 -4.2231,-0.4864 -8.4971,-0.76791 -12.8125,-0.8457 -30.2077,-0.54448 -62.4407,8.82427 -93.4316,26.71484 -22.7976,13.16063 -43.3521,33.31423 -59.4375,55.30469 -44.9968,-25.75094 -103.5444,-40.25065 -175.4785,-41.43945 -6.4522,-0.10663 -13.0125,-0.10696 -19.67974,0.002 -80.18875,1.30929 -144.38284,16.5086 -192.87109,43.9922 -0.11914,-0.19111 -0.24287,-0.37932 -0.37109,-0.56446 -16.29,-22.764 -37.41085,-43.73706 -60.89649,-57.29493 -30.02247,-17.33149 -61.21051,-26.66489 -90.59375,-26.73633 z"
+ id="path817-3"
+ />
+ <path
+ id="path1087"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 716.85595,362.96478 c 15.29075,-21.36763 35.36198,-41.10921 56.50979,-53.31749 66.66377,-38.48393 137.02617,-33.22172 170.08018,22.43043 33.09493,55.72093 14.98656,117.48866 -47.64399,159.85496 -31.95554,19.26819 -62.93318,30.92309 -97.22892,35.54473 M 307.14407,362.96478 C 291.85332,341.59715 271.78209,321.85557 250.63429,309.64729 183.97051,271.16336 113.60811,276.42557 80.554051,332.07772 47.459131,387.79865 65.56752,449.56638 128.19809,491.93268 c 31.95554,19.26819 62.93319,30.92309 97.22893,35.54473"
+ />
+ <path
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 801.23205,576.8699 C 812.73478,427.06971 720.58431,321.98291 511.99999,325.38859 303.41568,328.79426 213.71393,428.0311 222.76794,576.8699 c 8.64289,142.08048 176.80223,246.40388 288.12038,246.40388 111.31815,0 279.45076,-104.5447 290.34373,-246.40388 z"
+ id="path969"
+ />
+ <path
+ id="path1084"
+ style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 610.4991,644.28932 c 0,23.11198 18.70595,41.84795 41.78091,41.84795 23.07495,0 41.7809,-18.73597 41.7809,-41.84795 0,-23.112 -18.70594,-41.84796 -41.7809,-41.84796 -23.07496,0 -41.78091,18.73596 -41.78091,41.84796 z m -280.56002,0 c 0,23.32492 18.87829,42.23352 42.16586,42.23352 23.28755,0 42.16585,-18.9086 42.16585,-42.23352 0,-23.32494 -18.87829,-42.23353 -42.16585,-42.23353 -23.28757,0 -42.16586,18.90859 -42.16586,42.23353 z"
+ />
+ <path
+ id="path1008"
+ style="display:inline;opacity:1;fill:none;stroke:#000000;stroke-width:32;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 339.72919,769.2467 -54.54422,72.22481 m 399.08582,-72.22481 54.54423,72.22481 M 263.68341,697.82002 175.92752,733.64353 m 579.85765,-35.82351 87.7559,35.82351"
+ />
+ <path
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 512.00082,713.08977 c -45.86417,0 -75.13006,31.84485 -74.14159,71.10084 1.07048,42.51275 32.46865,71.10323 74.14159,71.10323 41.67296,0 74.05118,-32.99608 74.14161,-71.10323 0.0932,-39.26839 -28.27742,-71.10084 -74.14161,-71.10084 z"
+ id="path1115"
+ />
+ </g>
</symbol>
<symbol id="icon-search" viewBox="0 0 32 32">
<title>search</title>
import { Link } from 'inferno-router';
import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators';
-import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse } from '../interfaces';
-import { WebSocketService } from '../services';
+import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse } from '../interfaces';
+import { WebSocketService, UserService } from '../services';
import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter } from '../utils';
import { PostListing } from './post-listing';
import { CommentNodes } from './comment-nodes';
import { MomentTime } from './moment-time';
+import { i18n } from '../i18next';
+import { T } from 'inferno-i18next';
enum View {
Overview, Comments, Posts, Saved
sort: SortType;
page: number;
loading: boolean;
+ userSettingsForm: UserSettingsForm;
+ userSettingsLoading: boolean;
}
export class User extends Component<any, UserState> {
view: this.getViewFromProps(this.props),
sort: this.getSortTypeFromProps(this.props),
page: this.getPageFromProps(this.props),
+ userSettingsForm: {
+ show_nsfw: null,
+ auth: null,
+ },
+ userSettingsLoading: null,
}
constructor(props: any, context: any) {
this.refetch();
}
+ get isCurrentUser() {
+ return UserService.Instance.user && UserService.Instance.user.id == this.state.user.id;
+ }
+
getViewFromProps(props: any): View {
return (props.match.params.view) ?
View[capitalizeFirstLetter(props.match.params.view)] :
{this.state.loading ?
<h5><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> :
<div class="row">
- <div class="col-12 col-md-9">
+ <div class="col-12 col-md-8">
<h5>/u/{this.state.user.name}</h5>
{this.selects()}
{this.state.view == View.Overview &&
}
{this.paginator()}
</div>
- <div class="col-12 col-md-3">
+ <div class="col-12 col-md-4">
{this.userInfo()}
+ {this.isCurrentUser &&
+ this.userSettings()
+ }
{this.moderates()}
{this.follows()}
</div>
return (
<div className="mb-2">
<select value={this.state.view} onChange={linkEvent(this, this.handleViewChange)} class="custom-select custom-select-sm w-auto">
- <option disabled>View</option>
- <option value={View.Overview}>Overview</option>
- <option value={View.Comments}>Comments</option>
- <option value={View.Posts}>Posts</option>
- <option value={View.Saved}>Saved</option>
+ <option disabled><T i18nKey="view">#</T></option>
+ <option value={View.Overview}><T i18nKey="overview">#</T></option>
+ <option value={View.Comments}><T i18nKey="comments">#</T></option>
+ <option value={View.Posts}><T i18nKey="posts">#</T></option>
+ <option value={View.Saved}><T i18nKey="saved">#</T></option>
</select>
<select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="custom-select custom-select-sm w-auto ml-2">
- <option disabled>Sort Type</option>
- <option value={SortType.New}>New</option>
- <option value={SortType.TopDay}>Top Day</option>
- <option value={SortType.TopWeek}>Week</option>
- <option value={SortType.TopMonth}>Month</option>
- <option value={SortType.TopYear}>Year</option>
- <option value={SortType.TopAll}>All</option>
+ <option disabled><T i18nKey="sort_type">#</T></option>
+ <option value={SortType.New}><T i18nKey="new">#</T></option>
+ <option value={SortType.TopDay}><T i18nKey="top_day">#</T></option>
+ <option value={SortType.TopWeek}><T i18nKey="week">#</T></option>
+ <option value={SortType.TopMonth}><T i18nKey="month">#</T></option>
+ <option value={SortType.TopYear}><T i18nKey="year">#</T></option>
+ <option value={SortType.TopAll}><T i18nKey="all">#</T></option>
</select>
</div>
)
let user = this.state.user;
return (
<div>
- <h5>{user.name}</h5>
- <div>Joined <MomentTime data={user} /></div>
- <table class="table table-bordered table-sm mt-2">
- <tr>
- <td>{user.post_score} points</td>
- <td>{user.number_of_posts} posts</td>
- </tr>
- <tr>
- <td>{user.comment_score} points</td>
- <td>{user.number_of_comments} comments</td>
- </tr>
- </table>
- <hr />
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ <h5>{user.name}</h5>
+ <div>{i18n.t('joined')} <MomentTime data={user} /></div>
+ <div class="table-responsive">
+ <table class="table table-bordered table-sm mt-2 mb-0">
+ <tr>
+ <td><T i18nKey="number_of_points" interpolation={{count: user.post_score}}>#</T></td>
+ <td><T i18nKey="number_of_posts" interpolation={{count: user.number_of_posts}}>#</T></td>
+ </tr>
+ <tr>
+ <td><T i18nKey="number_of_points" interpolation={{count: user.comment_score}}>#</T></td>
+ <td><T i18nKey="number_of_comments" interpolation={{count: user.number_of_comments}}>#</T></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+ }
+
+ userSettings() {
+ return (
+ <div>
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ <h5><T i18nKey="settings">#</T></h5>
+ <form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}>
+ <div class="form-group row">
+ <div class="col-12">
+ <div class="form-check">
+ <input class="form-check-input" type="checkbox" checked={this.state.userSettingsForm.show_nsfw} onChange={linkEvent(this, this.handleUserSettingsShowNsfwChange)}/>
+ <label class="form-check-label"><T i18nKey="show_nsfw">#</T></label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group row mb-0">
+ <div class="col-12">
+ <button type="submit" class="btn btn-secondary">{this.state.userSettingsLoading ?
+ <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('save'))}</button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
</div>
)
}
moderates() {
return (
<div>
- {this.state.moderates.length > 0 &&
- <div>
- <h5>Moderates</h5>
- <ul class="list-unstyled">
- {this.state.moderates.map(community =>
- <li><Link to={`/c/${community.community_name}`}>{community.community_name}</Link></li>
- )}
- </ul>
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ {this.state.moderates.length > 0 &&
+ <div>
+ <h5><T i18nKey="moderates">#</T></h5>
+ <ul class="list-unstyled mb-0">
+ {this.state.moderates.map(community =>
+ <li><Link to={`/c/${community.community_name}`}>{community.community_name}</Link></li>
+ )}
+ </ul>
+ </div>
+ }
</div>
- }
+ </div>
</div>
)
}
return (
<div>
{this.state.follows.length > 0 &&
- <div>
- <hr />
- <h5>Subscribed</h5>
- <ul class="list-unstyled">
- {this.state.follows.map(community =>
- <li><Link to={`/c/${community.community_name}`}>{community.community_name}</Link></li>
- )}
- </ul>
+ <div class="card border-secondary mb-3">
+ <div class="card-body">
+ <h5><T i18nKey="subscribed">#</T></h5>
+ <ul class="list-unstyled mb-0">
+ {this.state.follows.map(community =>
+ <li><Link to={`/c/${community.community_name}`}>{community.community_name}</Link></li>
+ )}
+ </ul>
+ </div>
</div>
}
</div>
paginator() {
return (
- <div class="mt-2">
+ <div class="my-2">
{this.state.page > 1 &&
- <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
+ <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
}
- <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
+ <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
</div>
);
}
i.refetch();
}
+ handleUserSettingsShowNsfwChange(i: User, event: any) {
+ i.state.userSettingsForm.show_nsfw = event.target.checked;
+ i.setState(i.state);
+ }
+
+ handleUserSettingsSubmit(i: User, event: any) {
+ event.preventDefault();
+ i.state.userSettingsLoading = true;
+ i.setState(i.state);
+
+ WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
+ }
+
parseMessage(msg: any) {
console.log(msg);
let op: UserOperation = msgOp(msg);
if (msg.error) {
- alert(msg.error);
+ alert(i18n.t(msg.error));
return;
} else if (op == UserOperation.GetUserDetails) {
let res: UserDetailsResponse = msg;
this.state.moderates = res.moderates;
this.state.posts = res.posts;
this.state.loading = false;
- document.title = `/u/${this.state.user.name} - Lemmy`;
+ if (this.isCurrentUser) {
+ this.state.userSettingsForm.show_nsfw = UserService.Instance.user.show_nsfw;
+ }
+ document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
window.scrollTo(0,0);
this.setState(this.state);
} else if (op == UserOperation.EditComment) {
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
// let res: CommentResponse = msg;
- alert('Reply sent');
+ alert(i18n.t('reply_sent'));
// this.state.comments.unshift(res.comment); // TODO do this right
// this.setState(this.state);
} else if (op == UserOperation.SaveComment) {
if (res.comment.my_vote !== null)
found.my_vote = res.comment.my_vote;
this.setState(this.state);
+ } else if (op == UserOperation.SaveUserSettings) {
+ this.state = this.emptyState;
+ this.state.userSettingsLoading = false;
+ this.setState(this.state);
+ let res: LoginResponse = msg;
+ UserService.Instance.login(res);
}
}
}
color: #dedede !important;
}
+.navbar-toggler {
+ border: 0px;
+}
+
.pointer {
cursor: pointer;
}
color: var(--info);
}
+.upvote {
+ margin-bottom: -5px;
+}
+
.downvote:hover {
color: var(--danger);
}
+.downvote {
+ margin-top: -10px;
+}
+
.form-control, .form-control:focus {
background-color: var(--secondary);
color: #fff;
background-color: #444 !important;
}
-.md-div p {
+.md-div p:last-child {
margin-bottom: 0px;
}
height: auto;
}
-.listing {
- min-height: 61px;
+.comment-node {
+ margin-bottom: 10px;
+}
+
+.vote-bar {
+ margin-top: -6.5px;
+}
+
+.post-title {
+ line-height: 1.0;
}
.icon {
z-index: 2000;
}
-.navbar-bg {
- background-color: #222;
-}
-
blockquote {
border-left: 3px solid #ccc;
margin: 0.5em 5px;
padding: 0.1em 5px;
}
-.inbox {
- margin-top: 6px;
-}
-
.mouse-icon {
margin-top: -4px;
}
}
.thumbnail {
- max-height: 50px;
- max-width: 50px;
+ max-height: 62px;
+ max-width: 400px;
}
.no-s-hows {
top: -9999px !important;
left: -9999px !important;
}
+
+hr {
+ border-top: 1px solid var(--secondary);
+}
--- /dev/null
+import * as i18n from 'i18next';
+import { getLanguage } from './utils';
+import { en } from './translations/en';
+import { eo } from './translations/eo';
+import { es } from './translations/es';
+import { de } from './translations/de';
+import { fr } from './translations/fr';
+import { sv } from './translations/sv';
+import { ru } from './translations/ru';
+import { zh } from './translations/zh';
+import { nl } from './translations/nl';
+
+// https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
+// TODO don't forget to add moment locales for new languages.
+const resources = {
+ en,
+ eo,
+ es,
+ de,
+ zh,
+ fr,
+ sv,
+ ru,
+ nl,
+}
+
+function format(value: any, format: any, lng: any) {
+ if (format === 'uppercase') return value.toUpperCase();
+ return value;
+}
+
+i18n
+.init({
+ debug: true,
+ // load: 'languageOnly',
+
+ // initImmediate: false,
+ lng: getLanguage(),
+ fallbackLng: 'en',
+ resources,
+ interpolation: {
+ format: format
+
+ }
+});
+
+export { i18n, resources };
+<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
+ <meta name="Description" content="Lemmy">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/favicon.svg" />
<link rel="apple-touch-icon" href="/static/assets/apple-touch-icon.png" />
- <title>Lemmy</title>
- <link rel="stylesheet" href="/static/assets/libs/balloon-css/balloon.min.css" type="text/css">
- <script src="/static/assets/libs/sortable/sortable.min.js" type="text/javascript"></script>
- <script src="/static/assets/libs/markdown-it-emoji/markdown-it-emoji.min.js" type="text/javascript"></script>
+ <script async src="/static/assets/libs/sortable/sortable.min.js"></script>
+ <script src="/static/assets/libs/markdown-it-emoji/markdown-it-emoji.min.js" type="text/javascript"></script>
</head>
<body>
import { render, Component } from 'inferno';
-import { HashRouter, BrowserRouter, Route, Switch } from 'inferno-router';
+import { BrowserRouter, Route, Switch } from 'inferno-router';
+import { Provider } from 'inferno-i18next';
import { Main } from './components/main';
import { Navbar } from './components/navbar';
import { Footer } from './components/footer';
import { Search } from './components/search';
import { Sponsors } from './components/sponsors';
import { Symbols } from './components/symbols';
+import { i18n } from './i18next';
import './css/bootstrap.min.css';
import './css/main.css';
render() {
return (
- <HashRouter>
- <Navbar />
- <div class="mt-1 p-0">
- <Switch>
- <Route path={`/home/type/:type/sort/:sort/page/:page`} component={Main} />
- <Route exact path={`/`} component={Main} />
- <Route path={`/login`} component={Login} />
- <Route path={`/create_post/c/:name`} component={CreatePost} />
- <Route path={`/create_post`} component={CreatePost} />
- <Route path={`/create_community`} component={CreateCommunity} />
- <Route path={`/communities/page/:page`} component={Communities} />
- <Route path={`/communities`} component={Communities} />
- <Route path={`/post/:id/comment/:comment_id`} component={Post} />
- <Route path={`/post/:id`} component={Post} />
- <Route path={`/c/:name/sort/:sort/page/:page`} component={Community} />
- <Route path={`/community/:id`} component={Community} />
- <Route path={`/c/:name`} component={Community} />
- <Route path={`/u/:username/view/:view/sort/:sort/page/:page`} component={User} />
- <Route path={`/user/:id`} component={User} />
- <Route path={`/u/:username`} component={User} />
- <Route path={`/inbox`} component={Inbox} />
- <Route path={`/modlog/community/:community_id`} component={Modlog} />
- <Route path={`/modlog`} component={Modlog} />
- <Route path={`/setup`} component={Setup} />
- <Route path={`/search`} component={Search} />
- <Route path={`/sponsors`} component={Sponsors} />
- </Switch>
- <Symbols />
- </div>
- <Footer />
- </HashRouter>
+ <Provider i18next={i18n}>
+ <BrowserRouter>
+ <Navbar />
+ <div class="mt-4 p-0">
+ <Switch>
+ <Route path={`/home/type/:type/sort/:sort/page/:page`} component={Main} />
+ <Route exact path={`/`} component={Main} />
+ <Route path={`/login`} component={Login} />
+ <Route path={`/create_post`} component={CreatePost} />
+ <Route path={`/create_community`} component={CreateCommunity} />
+ <Route path={`/communities/page/:page`} component={Communities} />
+ <Route path={`/communities`} component={Communities} />
+ <Route path={`/post/:id/comment/:comment_id`} component={Post} />
+ <Route path={`/post/:id`} component={Post} />
+ <Route path={`/c/:name/sort/:sort/page/:page`} component={Community} />
+ <Route path={`/community/:id`} component={Community} />
+ <Route path={`/c/:name`} component={Community} />
+ <Route path={`/u/:username/view/:view/sort/:sort/page/:page`} component={User} />
+ <Route path={`/user/:id`} component={User} />
+ <Route path={`/u/:username`} component={User} />
+ <Route path={`/inbox`} component={Inbox} />
+ <Route path={`/modlog/community/:community_id`} component={Modlog} />
+ <Route path={`/modlog`} component={Modlog} />
+ <Route path={`/setup`} component={Setup} />
+ <Route path={`/search`} component={Search} />
+ <Route path={`/sponsors`} component={Sponsors} />
+ </Switch>
+ <Symbols />
+ </div>
+ <Footer />
+ </BrowserRouter>
+ </Provider>
);
}
export enum UserOperation {
- Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead
+ Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead, SaveUserSettings, TransferCommunity, TransferSite
}
export enum CommentSortType {
}
export enum SearchType {
- Both, Comments, Posts
+ All, Comments, Posts, Communities, Users, Url
}
export interface User {
id: number;
iss: string;
username: string;
+ show_nsfw: boolean;
}
export interface UserView {
creator_id: number;
removed: boolean;
deleted: boolean;
+ nsfw: boolean;
published: string;
updated?: string;
creator_name: string;
removed: boolean;
deleted: boolean;
locked: boolean;
+ nsfw: boolean;
published: string;
updated?: string;
creator_name: string;
community_name: string;
community_removed: boolean;
+ community_deleted: boolean;
+ community_nsfw: boolean;
number_of_comments: number;
score: number;
upvotes: number;
number_of_users: number;
number_of_posts: number;
number_of_comments: number;
+ number_of_communities: number;
}
export interface FollowCommunityForm {
auth?: string;
}
+export interface TransferCommunityForm {
+ community_id: number;
+ user_id: number;
+ auth?: string;
+}
+
+export interface TransferSiteForm {
+ user_id: number;
+ auth?: string;
+}
+
export interface AddModToCommunityResponse {
op: string;
moderators: Array<CommunityUser>;
}
export interface ModRemovePost {
- id: number;
- mod_user_id: number;
- post_id: number;
- reason?: string;
- removed?: boolean;
- when_: string
- mod_user_name: string;
- post_name: string;
- community_id: number;
- community_name: string;
+ id: number;
+ mod_user_id: number;
+ post_id: number;
+ reason?: string;
+ removed?: boolean;
+ when_: string
+ mod_user_name: string;
+ post_name: string;
+ community_id: number;
+ community_name: string;
}
export interface ModLockPost {
password: string;
password_verify: string;
admin: boolean;
+ show_nsfw: boolean;
}
export interface LoginResponse {
jwt: string;
}
-
+export interface UserSettingsForm {
+ show_nsfw: boolean;
+ auth: string;
+}
export interface CommunityForm {
name: string;
edit_id?: number;
removed?: boolean;
deleted?: boolean;
+ nsfw: boolean;
reason?: string;
expires?: number;
auth?: string;
creator_id: number;
removed?: boolean;
deleted?: boolean;
+ nsfw: boolean;
locked?: boolean;
reason?: string;
auth: string;
}
+export interface PostFormParams {
+ name: string;
+ url?: string;
+ body?: string;
+ community?: string;
+}
+
export interface GetPostResponse {
op: string;
post: Post;
export interface SearchResponse {
op: string;
+ type_: string;
posts?: Array<Post>;
comments?: Array<Comment>;
+ communities: Array<Community>;
+ users: Array<UserView>;
}
} else {
console.log('No JWT cookie found.');
}
-
}
public login(res: LoginResponse) {
this.setUser(res.jwt);
- Cookies.set("jwt", res.jwt);
+ Cookies.set("jwt", res.jwt, { expires: 365 });
console.log("jwt cookie set");
}
import { wsUri } from '../env';
-import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, AddAdminForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm } from '../interfaces';
+import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm } from '../interfaces';
import { webSocket } from 'rxjs/webSocket';
import { Subject } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import { UserService } from './';
+import { i18n } from '../i18next';
export class WebSocketService {
private static _instance: WebSocketService;
public subject: Subject<any>;
- public instanceName: string;
public site: Site;
public admins: Array<UserView>;
this.subject.next(this.wsSendWrapper(UserOperation.AddModToCommunity, form));
}
+ public transferCommunity(form: TransferCommunityForm) {
+ this.setAuth(form);
+ this.subject.next(this.wsSendWrapper(UserOperation.TransferCommunity, form));
+ }
+
+ public transferSite(form: TransferSiteForm) {
+ this.setAuth(form);
+ this.subject.next(this.wsSendWrapper(UserOperation.TransferSite, form));
+ }
+
public banUser(form: BanUserForm) {
this.setAuth(form);
this.subject.next(this.wsSendWrapper(UserOperation.BanUser, form));
}
public getSite() {
- this.subject.next(this.wsSendWrapper(UserOperation.GetSite, {}));
+ this.subject.next(this.wsSendWrapper(UserOperation.GetSite, undefined));
}
public search(form: SearchForm) {
this.subject.next(this.wsSendWrapper(UserOperation.MarkAllAsRead, form));
}
+ public saveUserSettings(userSettingsForm: UserSettingsForm) {
+ this.setAuth(userSettingsForm);
+ this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm));
+ }
+
private wsSendWrapper(op: UserOperation, data: any) {
let send = { op: UserOperation[op], data: data };
console.log(send);
private setAuth(obj: any, throwErr: boolean = true) {
obj.auth = UserService.Instance.auth;
if (obj.auth == null && throwErr) {
- alert("Not logged in.");
+ alert(i18n.t('not_logged_in'));
throw "Not logged in";
}
}
--- /dev/null
+export const de = {
+ translation: {
+ post: 'post',
+ remove_post: 'Beitrag löschen',
+ no_posts: 'Keine Beiträge.',
+ create_a_post: 'Einen Beitrag anlegen',
+ create_post: 'Beitrag anlegen',
+ number_of_posts:'{{count}} Beiträge',
+ posts: 'Beiträge',
+ related_posts: 'Diese Beiträge könnten verwandt sein',
+ comments: 'Kommentare',
+ number_of_comments:'{{count}} Kommentare',
+ remove_comment: 'Kommentar löschen',
+ communities: 'Communities',
+ create_a_community: 'Eine community anlegen',
+ create_community: 'Community anlegen',
+ remove_community: 'Community entfernen',
+ subscribed_to_communities:'Abonnierte <1>communities</1>',
+ trending_communities:'Trending <1>communities</1>',
+ list_of_communities: 'Liste von communities',
+ community_reqs: 'Kleinbuchstaben, Großbuchstaben und keine Leerzeichen.',
+ edit: 'editieren',
+ reply: 'antworten',
+ cancel: 'Abbrechen',
+ unlock: 'entsperren',
+ lock: 'sperren',
+ link: 'link',
+ mod: 'mod',
+ mods: 'mods',
+ moderates: 'Moderiert',
+ remove_as_mod: 'Als mod entfernen',
+ appoint_as_mod: 'Zum mod ernennen',
+ modlog: 'Modlog',
+ admin: 'admin',
+ admins: 'admins',
+ remove_as_admin: 'Als admin entfernen',
+ appoint_as_admin: 'Zum admin ernennen',
+ remove: 'entfernen',
+ removed: 'entfernt',
+ locked: 'gesperrt',
+ reason: 'Grund',
+ mark_as_read: 'als gelesen markieren',
+ mark_as_unread: 'als ungelesen markieren',
+ delete: 'löschen',
+ deleted: 'gelöscht',
+ restore: 'wiederherstellen',
+ ban: 'bannen',
+ ban_from_site: 'Von der Seite bannen',
+ unban: 'entbannen',
+ unban_from_site: 'Von der Seite entbannen',
+ save: 'speichern',
+ unsave: 'unsave',
+ create: 'anlegen',
+ username: 'Username',
+ email_or_username: 'Email oder Username',
+ number_of_users:'{{count}} Benutzer',
+ number_of_subscribers:'{{count}} Abonnenten',
+ number_of_points:'{{count}} Punkte',
+ name: 'Name',
+ title: 'Titel',
+ category: 'Kategorie',
+ subscribers: 'Abonnenten',
+ both: 'Beide',
+ saved: 'Gespeichert',
+ unsubscribe: 'Abbestellen',
+ subscribe: 'Abonnieren',
+ prev: 'Zurück',
+ next: 'Weiter',
+ sidebar: 'Sidebar',
+ sort_type: 'Sortieren nach',
+ hot: 'Hot',
+ new: 'Neu',
+ top_day: 'Top täglich',
+ week: 'Woche',
+ month: 'Monat',
+ year: 'Jahr',
+ all: 'Alle',
+ top: 'Top',
+ api: 'API',
+ inbox: 'Posteingang',
+ inbox_for: 'Posteingang für <1>{{user}}</1>',
+ mark_all_as_read: 'Alle als gelesen markieren',
+ type: 'Typ',
+ unread: 'Ungelesen',
+ reply_sent: 'Antwort gesendet',
+ search: 'Suchen',
+ overview: 'Übersicht',
+ view: 'Ansicht',
+ logout: 'Ausloggen',
+ login_sign_up: 'Einloggen / Registrieren',
+ notifications_error: 'Desktop-Benachrichtigungen sind in deinem browser nicht verfügbar. Versuche Firefox oder Chrome.',
+ unread_messages: 'Ungelesene Nachrichten',
+ password: 'Passwort',
+ verify_password: 'Passwort überprüfen',
+ login: 'Einloggen',
+ sign_up: 'Registrieren',
+ email: 'Email',
+ optional: 'Optional',
+ url: 'URL',
+ body: 'Text',
+ copy_suggested_title: 'Vorgeschlagenen Titel übernehmen: {{title}}',
+ community: 'Community',
+ expand_here: 'Expand here',
+ subscribe_to_communities: 'Abonniere ein paar <1>communities</1>.',
+ chat: 'Chat',
+ no_results: 'Keine Ergebnisse.',
+ setup: 'Setup',
+ lemmy_instance_setup: 'Lemmy Instanz Setup',
+ setup_admin: 'Seiten Administrator konfigurieren',
+ your_site: 'deine Seite',
+ modified: 'verändert',
+ sponsors: 'Sponsoren',
+ sponsors_of_lemmy: 'Sponsoren von Lemmy',
+ sponsor_message: 'Lemmy ist freie <1>Open-Source</1> Software, also ohne Werbung, Monetarisierung oder Venturekapital, Punkt. Deine Spenden gehen direkt an die Vollzeit Entwicklung des Projekts. Vielen Dank an die folgenden Personen:',
+ support_on_patreon: 'Auf Patreon unterstützen',
+ general_sponsors:'Allgemeine Sponsoren sind die, die zwischen $10 und $39 zu Lemmy beitragen.',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ code: 'Code',
+ powered_by: 'Bereitgestellt durch',
+ landing_0: 'Lemmy ist ein <1>Link Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: 'Nicht eingeloggt.',
+ community_ban: 'Du wurdest von dieser Community gebannt.',
+ site_ban: 'Du wurdest von dieser Seite gebannt',
+ couldnt_create_comment: 'Konnte Kommentar nicht anlegen.',
+ couldnt_like_comment: 'Konnte nicht liken.',
+ couldnt_update_comment: 'Konnte Kommentar nicht aktualisieren.',
+ couldnt_save_comment: 'Konnte Kommentar nicht speichern.',
+ no_comment_edit_allowed: 'Keine Erlaubnis Kommentar zu editieren.',
+ no_post_edit_allowed: 'Keine Erlaubnis Beitrag zu editieren.',
+ no_community_edit_allowed: 'Keine Erlaubnis Community zu editieren.',
+ couldnt_find_community: 'Konnte Community nicht finden.',
+ couldnt_update_community: 'Konnte Community nicht aktualisieren.',
+ community_already_exists: 'Community existiert bereits.',
+ community_moderator_already_exists: 'Community Moderator existiert bereits.',
+ community_follower_already_exists: 'Community Follower existiert bereits.',
+ community_user_already_banned: 'Community Nutzer schon gebannt.',
+ couldnt_create_post: 'Konnte Beitrag nicht anlegen.',
+ couldnt_like_post: 'Konnte Beitrag nicht liken.',
+ couldnt_find_post: 'Konnte Beitrag nicht finden.',
+ couldnt_get_posts: 'Konnte Beiträge nicht holen.',
+ couldnt_update_post: 'Konnte Beitrag nicht aktualisieren.',
+ couldnt_save_post: 'Konnte Beitrag nicht speichern.',
+ no_slurs: 'Keine Beleidigungen.',
+ not_an_admin: 'Kein Administrator.',
+ site_already_exists: 'Seite existiert bereits.',
+ couldnt_update_site: 'Konnte Seite nicht aktualisieren.',
+ couldnt_find_that_username_or_email: 'Konnte Username oder E-Mail nicht finden.',
+ password_incorrect: 'Passwort falsch.',
+ passwords_dont_match: 'Passwörter stimmen nicht überein.',
+ admin_already_created: 'Entschuldigung, es gibt schon einen Administrator.',
+ user_already_exists: 'Nutzer existiert bereits.',
+ couldnt_update_user: 'Konnte Nutzer nicht aktualisieren',
+ system_err_login: 'Systemfehler. Versuche dich aus- und wieder einzuloggen.',
+ },
+}
+
--- /dev/null
+export const en = {
+ translation: {
+ post: 'post',
+ remove_post: 'Remove Post',
+ no_posts: 'No Posts.',
+ create_a_post: 'Create a post',
+ create_post: 'Create Post',
+ number_of_posts:'{{count}} Posts',
+ posts: 'Posts',
+ related_posts: 'These posts might be related',
+ cross_posts: 'This link has also been posted to:',
+ cross_post: 'cross-post',
+ comments: 'Comments',
+ number_of_comments:'{{count}} Comments',
+ remove_comment: 'Remove Comment',
+ communities: 'Communities',
+ users: 'Users',
+ create_a_community: 'Create a community',
+ create_community: 'Create Community',
+ remove_community: 'Remove Community',
+ subscribed_to_communities:'Subscribed to <1>communities</1>',
+ trending_communities:'Trending <1>communities</1>',
+ list_of_communities: 'List of communities',
+ number_of_communities:'{{count}} Communities',
+ community_reqs: 'lowercase, underscores, and no spaces.',
+ edit: 'edit',
+ reply: 'reply',
+ cancel: 'Cancel',
+ unlock: 'unlock',
+ lock: 'lock',
+ link: 'link',
+ mod: 'mod',
+ mods: 'mods',
+ moderates: 'Moderates',
+ settings: 'Settings',
+ remove_as_mod: 'remove as mod',
+ appoint_as_mod: 'appoint as mod',
+ modlog: 'Modlog',
+ admin: 'admin',
+ admins: 'admins',
+ remove_as_admin: 'remove as admin',
+ appoint_as_admin: 'appoint as admin',
+ remove: 'remove',
+ removed: 'removed',
+ locked: 'locked',
+ reason: 'Reason',
+ mark_as_read: 'mark as read',
+ mark_as_unread: 'mark as unread',
+ delete: 'delete',
+ deleted: 'deleted',
+ restore: 'restore',
+ ban: 'ban',
+ ban_from_site: 'ban from site',
+ unban: 'unban',
+ unban_from_site: 'unban from site',
+ save: 'save',
+ unsave: 'unsave',
+ create: 'create',
+ username: 'Username',
+ email_or_username: 'Email or Username',
+ number_of_users:'{{count}} Users',
+ number_of_subscribers:'{{count}} Subscribers',
+ number_of_points:'{{count}} Points',
+ name: 'Name',
+ title: 'Title',
+ category: 'Category',
+ subscribers: 'Subscribers',
+ both: 'Both',
+ saved: 'Saved',
+ unsubscribe: 'Unsubscribe',
+ subscribe: 'Subscribe',
+ subscribed: 'Subscribed',
+ prev: 'Prev',
+ next: 'Next',
+ sidebar: 'Sidebar',
+ sort_type: 'Sort type',
+ hot: 'Hot',
+ new: 'New',
+ top_day: 'Top day',
+ week: 'Week',
+ month: 'Month',
+ year: 'Year',
+ all: 'All',
+ top: 'Top',
+ api: 'API',
+ inbox: 'Inbox',
+ inbox_for: 'Inbox for <1>{{user}}</1>',
+ mark_all_as_read: 'mark all as read',
+ type: 'Type',
+ unread: 'Unread',
+ reply_sent: 'Reply sent',
+ search: 'Search',
+ overview: 'Overview',
+ view: 'View',
+ logout: 'Logout',
+ login_sign_up: 'Login / Sign up',
+ login: 'Login',
+ sign_up: 'Sign Up',
+ notifications_error: 'Desktop notifications not available in your browser. Try Firefox or Chrome.',
+ unread_messages: 'Unread Messages',
+ password: 'Password',
+ verify_password: 'Verify Password',
+ email: 'Email',
+ optional: 'Optional',
+ expires: 'Expires',
+ url: 'URL',
+ body: 'Body',
+ copy_suggested_title: 'copy suggested title: {{title}}',
+ community: 'Community',
+ expand_here: 'Expand here',
+ subscribe_to_communities: 'Subscribe to some <1>communities</1>.',
+ chat: 'Chat',
+ recent_comments: 'Recent Comments',
+ no_results: 'No results.',
+ setup: 'Setup',
+ lemmy_instance_setup: 'Lemmy Instance Setup',
+ setup_admin: 'Set Up Site Administrator',
+ your_site: 'your site',
+ modified: 'modified',
+ nsfw: 'NSFW',
+ show_nsfw: 'Show NSFW content',
+ sponsors: 'Sponsors',
+ sponsors_of_lemmy: 'Sponsors of Lemmy',
+ sponsor_message: 'Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:',
+ support_on_patreon: 'Support on Patreon',
+ general_sponsors:'General Sponsors are those that pledged $10 to $39 to Lemmy.',
+ crypto: 'Crypto',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ monero: 'Monero',
+ code: 'Code',
+ joined: 'Joined',
+ by: 'by',
+ to: 'to',
+ transfer_community: 'transfer community',
+ transfer_site: 'transfer site',
+ are_you_sure: 'are you sure?',
+ yes: 'yes',
+ no: 'no',
+ powered_by: 'Powered by',
+ landing_0: 'Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It\'s self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: 'Not logged in.',
+ community_ban: 'You have been banned from this community.',
+ site_ban: 'You have been banned from the site',
+ couldnt_create_comment: 'Couldn\'t create comment.',
+ couldnt_like_comment: 'Couldn\'t like comment.',
+ couldnt_update_comment: 'Couldn\'t update comment.',
+ couldnt_save_comment: 'Couldn\'t save comment.',
+ no_comment_edit_allowed: 'Not allowed to edit comment.',
+ no_post_edit_allowed: 'Not allowed to edit post.',
+ no_community_edit_allowed: 'Not allowed to edit community.',
+ couldnt_find_community: 'Couldn\'t find community.',
+ couldnt_update_community: 'Couldn\'t update Community.',
+ community_already_exists: 'Community already exists.',
+ community_moderator_already_exists: 'Community moderator already exists.',
+ community_follower_already_exists: 'Community follower already exists.',
+ community_user_already_banned: 'Community user already banned.',
+ couldnt_create_post: 'Couldn\'t create post.',
+ couldnt_like_post: 'Couldn\'t like post.',
+ couldnt_find_post: 'Couldn\'t find post.',
+ couldnt_get_posts: 'Couldn\'t get posts',
+ couldnt_update_post: 'Couldn\'t update post',
+ couldnt_save_post: 'Couldn\'t save post.',
+ no_slurs: 'No slurs.',
+ not_an_admin: 'Not an admin.',
+ site_already_exists: 'Site already exists.',
+ couldnt_update_site: 'Couldn\'t update site.',
+ couldnt_find_that_username_or_email: 'Couldn\'t find that username or email.',
+ password_incorrect: 'Password incorrect.',
+ passwords_dont_match: 'Passwords do not match.',
+ admin_already_created: 'Sorry, there\'s already an admin.',
+ user_already_exists: 'User already exists.',
+ couldnt_update_user: 'Couldn\'t update user.',
+ system_err_login: 'System error. Try logging out and back in.',
+ },
+}
+
--- /dev/null
+export const eo = {
+ translation: {
+ post: 'Poŝti',
+ remove_post: 'Fortiri Poŝton',
+ no_posts: 'Ne Poŝtoj.',
+ create_a_post: 'Verki Poŝton',
+ create_post: 'Verki Poŝton',
+ number_of_posts:'{{count}} Poŝtoj',
+ posts: 'Poŝtoj',
+ related_posts: 'Tiuj poŝtoj eble rilatas',
+ cross_posts: 'Tiuj ligilo ankaŭ estas poŝtinta al:',
+ cross_post: 'laŭapoŝto',
+ comments: 'Komentoj',
+ number_of_comments:'{{count}} Komentoj',
+ remove_comment: 'Fortiri Komentojn',
+ communities: 'Komunumoj',
+ users: 'Uzantoj',
+ create_a_community: 'Krei komunumon',
+ create_community: 'Krei Komunumon',
+ remove_community: 'Forigi Komunumon',
+ subscribed_to_communities:'Abonita al <1>komunumoj</1>',
+ trending_communities:'Furora <1>komunumoj</1>',
+ list_of_communities: 'Listo de komunumoj',
+ community_reqs: 'minusklaj leteroj, substrekoj, kaj ne spacetoj.',
+ edit: 'redakti',
+ reply: 'repliki',
+ cancel: 'nuligi',
+ unlock: 'malŝlosi',
+ lock: 'ŝlosi',
+ link: 'ligi',
+ mod: 'moderanto',
+ mods: 'moderantoj',
+ moderates: 'Moderigas',
+ settings: 'Agordoj',
+ remove_as_mod: 'forigi per moderanto',
+ appoint_as_mod: 'nomumi per moderanto',
+ modlog: 'Moderlogo',
+ admin: 'administranto',
+ admins: 'administrantoj',
+ remove_as_admin: 'forigi per administranto',
+ appoint_as_admin: 'nomumi per administranto',
+ remove: 'fortiri',
+ removed: 'fortirita',
+ locked: 'ŝlosita',
+ reason: 'Kialo',
+ mark_as_read: 'marki kiel legita',
+ mark_as_unread: 'marki kiel nelegita',
+ delete: 'forigi',
+ deleted: 'forigita',
+ restore: 'restaŭri',
+ ban: 'forbari',
+ ban_from_site: 'forbari de retejo',
+ unban: 'malforbari',
+ unban_from_site: 'malforbari de retejo',
+ save: 'konservi',
+ unsave: 'malkonservi',
+ create: 'krei',
+ username: 'Uzantnomo',
+ email_or_username: 'Retadreso aŭ Uzantnomo',
+ number_of_users:'{{count}} Uzantoj',
+ number_of_subscribers:'{{count}} Abonantoj',
+ number_of_points:'{{count}} Voĉdonoj',
+ name: 'Nomo',
+ title: 'Titolo',
+ category: 'Kategorio',
+ subscribers: 'Abonantoj',
+ both: 'Ambaŭ',
+ saved: 'Konservita',
+ unsubscribe: 'Malaboni',
+ subscribe: 'Aboni',
+ subscribed: 'Abonita',
+ prev: 'Antaŭe',
+ next: 'Poste',
+ sidebar: 'Flankstango',
+ sort_type: 'Klasi per kia',
+ hot: 'Varmaj',
+ new: 'Novaj',
+ top_day: 'Supraj tagaj',
+ week: 'Semajno',
+ month: 'Monato',
+ year: 'Jaro',
+ all: 'Ĉiam',
+ top: 'Supraj',
+ api: 'API',
+ inbox: 'Ricevujo',
+ inbox_for: 'Ricevujo de <1>{{user}}</1>',
+ mark_all_as_read: 'marki ĉiujn kiel legitaj',
+ type: 'Tipo',
+ unread: 'Nelegitaj',
+ reply_sent: 'Repliko sendis',
+ search: 'Serĉi',
+ overview: 'Resumo',
+ view: 'Rigardi',
+ logout: 'Elsaluti',
+ login_sign_up: 'Ensaluti / Registriĝi',
+ login: 'Ensaluti',
+ sign_up: 'Registriĝi',
+ notifications_error: 'Labortablaj avizoj estas nehavebla en via retumilo. Provu Firefox-on aŭ Chrome-on.',
+ unread_messages: 'Nelegitaj Mesaĝoj',
+ password: 'Pasvorto',
+ verify_password: 'Konfirmu Vian Pasvorton',
+ email: 'Retadreso',
+ optional: 'Fakultativa',
+ expires: 'Finiĝos',
+ url: 'URL',
+ body: 'Ĉefparto',
+ copy_suggested_title: 'kopii la sugestiitan titolon: {{title}}',
+ community: 'Komunumo',
+ expand_here: 'Ekspansii ĉi tie',
+ subscribe_to_communities: 'Aboni al iuj <1>komunumoj</1>.',
+ chat: 'Babilo',
+ recent_comments: 'Freŝaj Komentoj',
+ no_results: 'Ne rezultoj.',
+ setup: 'Agordi',
+ lemmy_instance_setup: 'Agordi Instancon de Lemmy',
+ setup_admin: 'Agordi Retejan Administranton',
+ your_site: 'via retejo',
+ modified: 'modifita',
+ nsfw: 'NSFW',
+ show_nsfw: 'Vidigi NSFW-an enhavon',
+ sponsors: 'Subtenantoj',
+ sponsors_of_lemmy: 'Subtenantoj de Lemmy',
+ sponsor_message: 'Lemmy estas senpaga, <1>liberkoda</1> programaro. Tio signifas ne reklami, pagigi, aŭ riska kapitalo, ĉiam. Viaj donacoj rekte subtenas plentempan evoluon de la projekto. Dankon al tiuj homoj:',
+ support_on_patreon: 'Subteni per Patreon',
+ general_sponsors:'Ĝeneralaj Subtenantoj estas tiuj ke donacis inter $10 kaj $39 al Lemmy.',
+ crypto: 'Crypto',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ monero: 'Monero',
+ code: 'Kodo',
+ joined: 'Unuiĝis',
+ by: 'de',
+ to: 'al',
+ transfer_community: 'transdoni la komunumon',
+ transfer_site: 'transdoni la retejon',
+ powered_by: 'Konstruis per',
+ landing_0: 'Lemmy estas <1>ligila agregatilo</1> / Reddit anstataŭo ke intenciĝas funkci en la <2>federacio-universo</2>.<3></3>ĝi estas mem-gastigebla, havas nuna-ĝisdatigajn komentarojn, kaj estas malgrandega (<4>~80kB</4>). Federacio en la ActivityPub-an reton estas planizita. <5></5>Estas <6>fruega beta versio</6>, kaj multaj trajtoj estas nune difektaj aŭ mankaj. <7></7>Sugestias novajn trajtojn aŭ raportas cimojn <8>ĉi tie.</8><9></9>Faris per <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: 'Ne estas ensalutinta.',
+ community_ban: 'Vi estas forbarita de la komunumo.',
+ site_ban: 'Vi estas forbarita de la retejo',
+ couldnt_create_comment: 'Ne povis krei la komenton.',
+ couldnt_like_comment: 'Ne povis ŝati la komenton.',
+ couldnt_update_comment: 'Ne povis ĝisdatigi komenton.',
+ couldnt_save_comment: 'Ne povis konservi komenton.',
+ no_comment_edit_allowed: 'Ne rajtas redakti la komenton.',
+ no_post_edit_allowed: 'Ne rajtas redakti la poŝton.',
+ no_community_edit_allowed: 'Ne rajtas redakti la komunumon.',
+ couldnt_find_community: 'Ne povis trovi la komunumon.',
+ couldnt_update_community: 'Ne povis ĝisdatigi la komunumon.',
+ community_already_exists: 'Komunumo jam ekzistas.',
+ community_moderator_already_exists: 'Komunuma moderanto jam ekzistas.',
+ community_follower_already_exists: 'Komunuma sekvanto.',
+ community_user_already_banned: 'Komunuma uzanto jam estas forbarita.',
+ couldnt_create_post: 'Ne povis krei la poŝton.',
+ couldnt_like_post: 'Ne povis ŝati la poŝton.',
+ couldnt_find_post: 'Ne povis trovi la poŝton.',
+ couldnt_get_posts: 'Ne povis irpreni poŝtojn',
+ couldnt_update_post: 'Ne povis ĝisdatigi la poŝton',
+ couldnt_save_post: 'Ne povis konservi la poŝton.',
+ no_slurs: 'Ne bigotaj vortoj.',
+ not_an_admin: 'Ne estas administranto.',
+ site_already_exists: 'Retejo jam ekzistas.',
+ couldnt_update_site: 'Ne povis ĝisdatigi la retejon.',
+ couldnt_find_that_username_or_email: 'Ne povis trovi tiun uzantnomon aŭ retadreson.',
+ password_incorrect: 'Pasvorto malĝustas.',
+ passwords_dont_match: 'Pasvortoj ne samas.',
+ admin_already_created: 'Pardonu, jam estas administranto.',
+ user_already_exists: 'Uzanto jam ekzistas.',
+ couldnt_update_user: 'Ne povis ĝisdatigi la uzanton.',
+ system_err_login: 'Sistema eraro. Provu elsaluti kaj ensaluti.',
+ },
+}
+
--- /dev/null
+export const es = {
+ translation: {
+ post: 'Publicar',
+ remove_post: 'Remover publicación',
+ no_posts: 'Sin publicaciones.',
+ create_a_post: 'Crear una publicación',
+ create_post: 'Crear Publicación',
+ number_of_posts:'{{count}} Publicaciones',
+ posts: 'Publicaciones',
+ related_posts: 'Estas publicaciones podrían estar relacionadas',
+ cross_posts: 'Este link también ha sido publicado en:',
+ cross_post: 'cross-post',
+ comments: 'Comentarios',
+ number_of_comments:'{{count}} Comentarios',
+ remove_comment: 'Remover Comentarios',
+ communities: 'Comunidades',
+ users: 'Usuarios',
+ create_a_community: 'Crear una comunidad',
+ create_community: 'Crear Comunidad',
+ remove_community: 'Remover Comunidad',
+ subscribed_to_communities:'Suscrito a <1>comunidades</1>',
+ trending_communities:'<1>Comunidades</1> en tendencia',
+ list_of_communities: 'Lista de comunidades',
+ community_reqs: 'minúsculas, guión bajo, y sin espacios.',
+ edit: 'editar',
+ reply: 'responder',
+ cancel: 'Cancelar',
+ unlock: 'desbloquear',
+ lock: 'bloquear',
+ link: 'link',
+ mod: 'Moderador',
+ mods: 'Moderadores',
+ moderates: 'Modera',
+ settings: 'Configuración',
+ remove_as_mod: 'remover como moderador',
+ appoint_as_mod: 'designar como moderador',
+ modlog: 'Historial de moderación',
+ admin: 'administrador',
+ admins: 'administradores',
+ remove_as_admin: 'remover como administrador',
+ appoint_as_admin: 'designar como administrador',
+ remove: 'remover',
+ removed: 'removido',
+ locked: 'bloqueado',
+ reason: 'Razón',
+ mark_as_read: 'marcar como leído',
+ mark_as_unread: 'marcar como no leído',
+ delete: 'eliminar',
+ deleted: 'eliminado',
+ restore: 'restaurar',
+ ban: 'expulsar',
+ ban_from_site: 'expulsión del sitio',
+ unban: 'admitir',
+ unban_from_site: 'admitir al sitio',
+ save: 'guardar',
+ unsave: 'descartar',
+ create: 'crear',
+ username: 'Nombre de Usuario',
+ email_or_username: 'Correo electrónico o Nombre de Usuario',
+ number_of_users:'{{count}} Usuarios',
+ number_of_subscribers:'{{count}} Suscriptores',
+ number_of_points:'{{count}} Puntos',
+ name: 'Nombre',
+ title: 'Titulo',
+ category: 'Categoría',
+ subscribers: 'Suscriptores',
+ both: 'Ambos',
+ saved: 'Guardado',
+ unsubscribe: 'Abandonar comunidad',
+ subscribe: 'Suscribir',
+ subscribed: 'Suscrito',
+ prev: 'Anterior',
+ next: 'Siguiente',
+ sidebar: 'Descripción de la comunidad',
+ sort_type: 'Tipo de orden',
+ hot: 'Popular',
+ new: 'Nuevo',
+ top_day: 'Lo mejor del día',
+ week: 'Semana',
+ month: 'Mes',
+ year: 'Año',
+ all: 'Todo',
+ top: 'Mejor',
+ api: 'API',
+ inbox: 'Buzón de entrada',
+ inbox_for: 'Buzón de entrada para <1>{{user}}</1>',
+ mark_all_as_read: 'marcar todo como leído',
+ type: 'Tipo',
+ unread: 'No leído',
+ reply_sent: 'Respuesta enviada',
+ search: 'Buscar',
+ overview: 'Resumen',
+ view: 'Vista',
+ logout: 'Cerrar sesión',
+ login_sign_up: 'Iniciar sesión / Crear cuenta',
+ login: 'Iniciar sesión',
+ sign_up: 'Crear cuenta',
+ notifications_error: 'Notificaciones de escritorio no disponibles en tu navegador. Prueba Firefox o Chrome.',
+ unread_messages: 'Mensajes no leídos',
+ password: 'Contraseña',
+ verify_password: 'Verificar contraseña',
+ email: 'Correo electrónico',
+ optional: 'Opcional',
+ expires: 'Expira',
+ url: 'URL',
+ body: 'Descripción',
+ copy_suggested_title: 'Copiar el título sugerido: {{title}}',
+ community: 'Comunidad',
+ expand_here: 'Expandir aquí',
+ subscribe_to_communities: 'Suscribirse a algunas <1>comunidades</1>.',
+ chat: 'Chat',
+ recent_comments: 'Comentarios recientes',
+ no_results: 'Sin resultados.',
+ setup: 'Configurar',
+ lemmy_instance_setup: 'Configuración de instancia de Lemmy',
+ setup_admin: 'Configurar administrador del Sitio',
+ your_site: 'tu sitio',
+ modified: 'modificado',
+ nsfw: 'NSFW',
+ show_nsfw: 'Mostrar contenido NSFW',
+ sponsors: 'Patrocinadores',
+ sponsors_of_lemmy: 'Patrocinadores of Lemmy',
+ sponsor_message: 'Lemmy es software libre y de <1>código abierto</1>, lo que significa que no tendrá publicidades, monetización, ni capitales emprendedores, nunca. Tus donaciones apoyan directamente el desarrollo a tiempo completo del proyecto. Muchas gracias a las siguientes personas:',
+ support_on_patreon: 'Apoyo en Patreon',
+ general_sponsors:'Patrocinadores Generales son aquellos que señaron entre $10 y $39 a Lemmy.',
+ crypto: 'Crypto',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ monero: 'Monero',
+ code: 'Código',
+ joined: 'Se unió',
+ by: 'por',
+ to: 'en',
+ transfer_community: 'transferir comunidad',
+ transfer_site: 'transferir sitio',
+ powered_by: 'Impulsado por',
+ landing_0: 'Lemmy es un <1>agregador de links</1> / alternativa a reddit, con la intención de funcionar en el <2>fediverso</2>.<3></3>Es alojable por uno mismo (sin necesidad de grandes compañías), tiene actualización en vivo de cadenas de comentarios, y es pequeño (<4>~80kB</4>). Federar con el sistema de redes ActivityPub forma parte de los objetivos del proyecto. <5></5>Esta es una <6>version beta muy prematura</6>, y actualmente muchas de las características están rotas o faltan. <7></7>Sugiere nuevas características o reporta errores <8>aquí</8>.<9></9>Hecho con <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: 'No has iniciado sesión.',
+ community_ban: 'Has sido expulsado de esta comunidad.',
+ site_ban: 'Has sido expulsado del sitio',
+ couldnt_create_comment: 'No se pudo crear el comentario.',
+ couldnt_like_comment: 'No se pudo gustar el comentario.',
+ couldnt_update_comment: 'No se pudo actualizar el comentario.',
+ couldnt_save_comment: 'No se pudo guardar el comentario.',
+ no_comment_edit_allowed: 'No tiene permitido editar el comentario.',
+ no_post_edit_allowed: 'No tiene permitido editar la publicación.',
+ no_community_edit_allowed: 'No tiene permitido editar la comunidad.',
+ couldnt_find_community: 'No se pudo encontrar la comunidad.',
+ couldnt_update_community: 'No se pudo actualizar la comunidad.',
+ community_already_exists: 'Esta comunidad ya existe.',
+ community_moderator_already_exists: 'Este moderador de la comunidad ya existe.',
+ community_follower_already_exists: 'Este seguidor de la comunidad ya existe.',
+ community_user_already_banned: 'Este usuario de la comunidad ya fue expulsado.',
+ couldnt_create_post: 'No se pudo crear la publicación.',
+ couldnt_like_post: 'No se pudo gustar la publicación.',
+ couldnt_find_post: 'No se pudo encontrar la publicación.',
+ couldnt_get_posts: 'No se pudo obtener las publicaciones',
+ couldnt_update_post: 'No se pudo actualizar la publicación',
+ couldnt_save_post: 'No se pudo guardar la publicación.',
+ no_slurs: 'Prohibido insultar.',
+ not_an_admin: 'No es un administrador.',
+ site_already_exists: 'El sitio ya existe.',
+ couldnt_update_site: 'No se pudo actualizar el sitio.',
+ couldnt_find_that_username_or_email: 'No se pudo encontrar ese nombre de usuario o correo electrónico.',
+ password_incorrect: 'Contraseña incorrecta.',
+ passwords_dont_match: 'Las contraseñas no coinciden.',
+ admin_already_created: 'Lo sentimos, ya hay un adminisitrador.',
+ user_already_exists: 'El usuario ya existe.',
+ couldnt_update_user: 'No se pudo actualizar el usuario.',
+ system_err_login: 'Error del sistema. Intente cerrar sesión e ingresar de nuevo.',
+ },
+}
+
--- /dev/null
+export const fr = {
+ translation: {
+ post: 'sujet',
+ remove_post: 'Supprimer le sujet',
+ no_posts: 'Pas de sujets.',
+ create_a_post: 'Créer un sujet',
+ create_post: 'Créer le sujet',
+ number_of_posts:'{{count}} Sujets',
+ posts: 'Sujets',
+ related_posts: 'Ces sujets peuvent être corrélés',
+ comments: 'Commentaires',
+ number_of_comments:'{{count}} Commentaires',
+ remove_comment: 'Supprimer le commentaire',
+ communities: 'Communautés',
+ create_a_community: 'Créer une communauté',
+ create_community: 'Créer la communauté',
+ remove_community: 'Supprimer la Communauté',
+ subscribed_to_communities:'Abonné à ces <1>communautés</1>',
+ trending_communities:'<1>Communauté</1> en vogue',
+ list_of_communities: 'Liste des communautés',
+ community_reqs: 'en minuscule, sans espace et avec tiret du bas.',
+ edit: 'éditer',
+ reply: 'répondre',
+ cancel: 'Annuler',
+ unlock: 'débloquer',
+ lock: 'bloquer',
+ link: 'lien',
+ mod: 'modérateur',
+ mods: 'modérateurs',
+ moderates: 'Modération',
+ remove_as_mod: 'Supprimer comme modérateur',
+ appoint_as_mod: 'Nommer comme modérateur',
+ modlog: 'Historique de modération',
+ admin: 'admin',
+ admins: 'admins',
+ remove_as_admin: 'Supprimer comme admin',
+ appoint_as_admin: 'Nommer comme admin',
+ remove: 'retirer',
+ removed: 'retiré',
+ locked: 'bloqué',
+ reason: 'Raison',
+ mark_as_read: 'marquer comme lu',
+ mark_as_unread: 'marquer comme non-lu',
+ delete: 'supprimer',
+ deleted: 'supprimé',
+ restore: 'restaurer',
+ ban: 'bannir',
+ ban_from_site: 'bannir du site',
+ unban: 'débannir',
+ unban_from_site: 'débannir du site',
+ save: 'sauvegarder',
+ unsave: 'retirer',
+ create: 'créer',
+ username: 'Nom d\'utilisateur',
+ email_or_username: 'Email ou Nom d\'utilisateur',
+ number_of_users:'{{count}} Utilisateurs',
+ number_of_subscribers:'{{count}} Abonnés',
+ number_of_points:'{{count}} Points',
+ name: 'Nom',
+ title: 'Titre',
+ category: 'Catégorie',
+ subscribers: 'Abonnés',
+ both: 'Les deux',
+ saved: 'Sauvegardé',
+ unsubscribe: 'Se désincrire',
+ subscribe: 'S\'inscrire',
+ subscribed: 'Inscris',
+ prev: 'Précédent',
+ next: 'Suivant',
+ sidebar: 'Texte latéral',
+ sort_type: 'Trier',
+ hot: 'Chaud',
+ new: 'Nouveau',
+ top_day: 'Top jour',
+ week: 'Semaine',
+ month: 'Mois',
+ year: 'Année',
+ all: 'Tout',
+ top: 'Top',
+ api: 'API',
+ inbox: 'Boîte de réception',
+ inbox_for: 'Boîte de réception de <1>{{user}}</1>',
+ mark_all_as_read: 'Tout marquer comme lu',
+ type: 'Type',
+ unread: 'Non-lu',
+ reply_sent: 'Réponse envoyée',
+ search: 'Rechercher',
+ overview: 'Général',
+ view: 'Voir',
+ logout: 'Se déconnecter',
+ login_sign_up: 'Se connecter / S\'inscrire',
+ login: 'Se connecter',
+ sign_up: 'S\'inscrire',
+ notifications_error: 'Les notifications de bureau ne sont pas discponibles sur votre navigateur. Essayez Firefox ou Chrome.',
+ unread_messages: 'Messages non-lu',
+ password: 'Mot de passe',
+ verify_password: 'Vérifiez le mot de passe',
+ email: 'Email',
+ optional: 'Optionnel',
+ expires: 'Expire',
+ url: 'URL',
+ body: 'Texte',
+ copy_suggested_title: 'Ajouter le titre suggéré: {{title}}',
+ community: 'Communauté',
+ expand_here: 'Développer ici',
+ subscribe_to_communities: 'S\'abonner à quelques <1>communautés</1>.',
+ chat: 'Chat',
+ no_results: 'Pas de résultats.',
+ setup: 'Installation',
+ lemmy_instance_setup: 'Installation d\'une instance Lemmy',
+ setup_admin: 'Créer un administrateur',
+ your_site: 'votre site',
+ modified: 'modifié',
+ sponsors: 'Sponsors',
+ sponsors_of_lemmy: 'Sponsors de Lemmy',
+ sponsor_message: 'Lemmy est gratuit et <1>open-source</1>, c\'est à dire sans publicité et sans monétisation. Pour toujours. Vos dons soutiennent directement le développement du projet. Merci à nos soutiens.',
+ support_on_patreon: 'Soutenir sur Patreon',
+ general_sponsors:'General Sponsors are those that pledged $10 to $39 to Lemmy.',
+ crypto: 'Crypto',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ code: 'Code',
+ joined: 'Membre depuis',
+ powered_by: 'Propulsé par',
+ landing_0: 'Lemmy est un <1>aggrégateur de lien</1>, similaire à reddit et conçu pour fonctionner sur le <2>fédiverse</2>.<3></3>Il est auto-hébergeable, se met à jour en direct et est léger (<4>~80kB</4>). La fédération via Activitypub est prévue sur la feuille de route. <5></5>Lemmy est une <6>version beta très précoce</6>, et de nombreuses fonctionnalités sont manquantes ou non fonctionnelles. <7></7>Vous pouvez rapporter des bugs et suggérez de nouvelles fonctionnalités <8>ici.</8><9></9>Crée avec <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: 'Vous n\'êtes pas connecté.',
+ community_ban: 'Vous avez été banni de cette communauté.',
+ site_ban: 'Vous avez été banni du site',
+ couldnt_create_comment: 'Impossible de poster le commentaire.',
+ couldnt_like_comment: 'Impossible d\'aimer le commentaire.',
+ couldnt_update_comment: 'Impossible de mettre à jour le commentaire.',
+ couldnt_save_comment: 'Impossible de sauvegarder le commentaire.',
+ no_comment_edit_allowed: 'Vous n\'êtes pas autorisé à éditer ce commentaire.',
+ no_post_edit_allowed: 'ous n\'êtes pas autorisé à éditer sujet.',
+ no_community_edit_allowed: 'ous n\'êtes pas autorisé à éditer cette communauté.',
+ couldnt_find_community: 'Impossible de trouver cette communauté.',
+ couldnt_update_community: 'Impossible d\'éditer cette communauté.',
+ community_already_exists: 'Cette communauté existe déjà.',
+ community_moderator_already_exists: 'Ce membre est déjà modérateur.',
+ community_follower_already_exists: 'Ce membre est déjà abonné.',
+ community_user_already_banned: 'Ce membre est déjà banni.',
+ couldnt_create_post: 'Impossible dae créer le sujet.',
+ couldnt_like_post: 'Impossible d\'aimer le sujet.',
+ couldnt_find_post: 'Impossible de trouver le sujet.',
+ couldnt_get_posts: 'Impossible d\'obtenir les sujets',
+ couldnt_update_post: 'Impossible de mettre à jour le sujet',
+ couldnt_save_post: 'Impossible de sauvegarder le sujet.',
+ no_slurs: 'Pas d\'insultes.',
+ not_an_admin: 'Pas administrateur.',
+ site_already_exists: 'Le site existe déjà.',
+ couldnt_update_site: 'Impossible de mettre à jour le site.',
+ couldnt_find_that_username_or_email: 'Impossible de trouver cet utilisateur ou cet email.',
+ password_incorrect: 'Mot de passe incorrect.',
+ passwords_dont_match: 'Les mots de passes ne correspondent pas..',
+ admin_already_created: 'Désolé, il y a déjà un admin.',
+ user_already_exists: 'L\'utilisateur existe déjà.',
+ couldnt_update_user: 'Impossible de mettre à jour l\'utilisateur.',
+ system_err_login: 'Erreur système. Essayez de vous déconneter puis de vous reconnecter.',
+ },
+}
--- /dev/null
+export const nl = {
+ translation: {
+ post: 'post',
+ remove_post: 'Verwijder post',
+ no_posts: 'Geen posts.',
+ create_a_post: 'Plaats een post',
+ create_post: 'Plaats post',
+ number_of_posts:'{{count}} posts',
+ posts: 'posts',
+ related_posts: 'Deze posts kunnen gerelateerd zijn',
+ cross_posts: 'Deze link is ook geplaatst in:',
+ cross_post: 'cross-post',
+ comments: 'Reacties',
+ number_of_comments:'{{count}} reacties',
+ remove_comment: 'Verwijder reactie',
+ communities: 'Communities',
+ users: 'Gebruikers',
+ create_a_community: 'Maak een community',
+ create_community: 'Maak community',
+ remove_community: 'Verwijder community',
+ subscribed_to_communities:'Geabonneerd op <1>communities</1>',
+ trending_communities:'Populaire <1>communities</1>',
+ list_of_communities: 'Lijst van communities',
+ number_of_communities:'{{count}} communities',
+ community_reqs: 'kleine letters, onderstrepingsteken en geen spaties',
+ edit: 'bewerk',
+ reply: 'reageer',
+ cancel: 'Annuleer',
+ unlock: 'ontsluiten',
+ lock: 'sluiten',
+ link: 'link',
+ mod: 'moderator',
+ mods: 'moderators',
+ moderates: 'Modereert',
+ settings: 'Instellingen',
+ remove_as_mod: 'Verwijder als moderator',
+ appoint_as_mod: 'Benoemen tot moderator',
+ modlog: 'Moderatorlog',
+ admin: 'beheerder',
+ admins: 'beheerders',
+ remove_as_admin: 'verwijder als beheerder',
+ appoint_as_admin: 'benoemen tot beheerder',
+ remove: 'weghalen',
+ removed: 'weggehaald',
+ locked: 'gesloten',
+ reason: 'Reden',
+ mark_as_read: 'markeer als gelezen',
+ mark_as_unread: 'markeer als ongelezen',
+ delete: 'verwijder',
+ deleted: 'verwijderd',
+ restore: 'herstellen',
+ ban: 'verban',
+ ban_from_site: 'verban van site',
+ unban: 'verbanning opzeggen',
+ unban_from_site: 'verbanning van site opzeggen',
+ save: 'opslaan',
+ unsave: 'unsave',
+ create: 'maak',
+ username: 'Gebruikersnaam',
+ email_or_username: 'E-mail of gebruikersnaam',
+ number_of_users:'{{count}} gebruikers',
+ number_of_subscribers:'{{count}} abonnees',
+ number_of_points:'{{count}} punten',
+ name: 'Naam',
+ title: 'Titel',
+ category: 'Categorie',
+ subscribers: 'Abonnees',
+ both: 'Beide',
+ saved: 'Opgeslagen',
+ unsubscribe: 'Afmelden',
+ subscribe: 'Abonneren',
+ subscribed: 'Geabonneerd',
+ prev: 'Vorige',
+ next: 'Volgende',
+ sidebar: 'Zijbalk',
+ sort_type: 'Sorteertype',
+ hot: 'Populair',
+ new: 'Nieuw',
+ top_day: 'Dagelijkse top',
+ week: 'Week',
+ month: 'Maand',
+ year: 'Jaar',
+ all: 'Alle',
+ top: 'Top',
+ api: 'API',
+ inbox: 'Postvak-in',
+ inbox_for: 'Postvak-in voor <1>{{user}}</1>',
+ mark_all_as_read: 'markeer alle als gelezen',
+ type: 'Type',
+ unread: 'Ongelezen',
+ reply_sent: 'Reactie gestuurd',
+ search: 'Zoek',
+ overview: 'Overzicht',
+ view: 'Beeld',
+ logout: 'Log uit',
+ login_sign_up: 'Log in / Aanmelden',
+ login: 'Log in',
+ sign_up: 'Aanmelden',
+ notifications_error: 'Bureabladberichten niet beschikbaar in je browser. Probeer Firefox of Chrome.',
+ unread_messages: 'Ongelezen berichten',
+ password: 'Wachtwoord',
+ verify_password: 'Herhaal wachtwoord',
+ email: 'E-mail',
+ optional: 'Optioneel',
+ expires: 'Verloopt',
+ url: 'url',
+ body: 'Tekst',
+ copy_suggested_title: 'neem voorgestelde titel over: {{title}}',
+ community: 'Community',
+ expand_here: 'Breid hier uit',
+ subscribe_to_communities: 'Abonneer je op een paar <1>communities</1>.',
+ chat: 'Praat',
+ recent_comments: 'Recente reacties',
+ no_results: 'Geen resultaten',
+ setup: 'Installatie',
+ lemmy_instance_setup: 'Installatie van Lemmy-instantie',
+ setup_admin: 'Maak een administrator',
+ your_site: 'jouw site',
+ modified: 'bewerkt',
+ nsfw: 'NSFW',
+ show_nsfw: 'Laat NSFW-inhoud zien',
+ sponsors: 'Sponsoren',
+ sponsors_of_lemmy: 'Sponsoren van Lemmy',
+ sponsor_message: 'Lemmy is vrije, <1>open-source</1> software, dus zonder reclame, winstoogmerk en durfkapitaal, punt. Jouw donaties gaan direct naar de full-time-ontwikkeling van het project. Met veel dank aan de volgende mensen:',
+ support_on_patreon: 'Ondersteun op Patreon',
+ general_sponsors:'Algemene sponsors zijn sponsors die tussen de $10 en $39 hebben gegeven aan Lemmy.',
+ crypto: 'Cryptovaluta',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ monero: 'Monero',
+ code: 'Code',
+ joined: 'toegetreden',
+ by: 'door',
+ to: 'aan',
+ transfer_community: 'community overplaatsen',
+ transfer_site: 'site overplaatsen',
+ are_you_sure: 'weet je het zeker?',
+ yes: 'ja',
+ no: 'nee',
+ powered_by: 'Mogelijk gemaakt door',
+ landing_0: 'Lemmy is een <1>linkverzameler</1> / reddit-alternatief, bedoeld om in de <2>fediverse</2> te werken.<3></3>Lemmy kan door om het even wie gehost worden, heeft live-bijgewerkte reacties en is superklein (<4>ca. 80 kB</4>). Federatie in hte ActivityPub-netwerk is gepland. <5></5>Dit is een <6>erg vroege bèta-versie</6>, en een hoop functies zijn stuk of afwezig. <7></7>Stel nieuwe functies voor of meldt fouten <8>hier</8>.<9></9>Gemaakt met <10>Rust</10>, <11>Actix</11>, <12>Inferno</12> en <13>Typescript</13>.',
+ not_logged_in: 'Niet ingelogd.',
+ community_ban: 'Je bent verbannen uit deze community.',
+ site_ban: 'Je bent verbannen van deze site.',
+ couldnt_create_comment: 'Kon reactie niet maken.',
+ couldnt_like_comment: 'Kon reactie niet leuk vinden.',
+ couldnt_update_comment: 'Kon reactie niet bijwerken.',
+ couldnt_save_comment: 'Kon reactie niet opslaan.',
+ no_comment_edit_allowed: 'Niet toegestaan om reactie te bewerken.',
+ no_post_edit_allowed: 'Niet toegestaan om posts te bewerken.',
+ no_community_edit_allowed: 'Niet toegestaan om community te bewerken.',
+ couldnt_find_community: 'Kon community niet vinden.',
+ couldnt_update_community: 'Kon community niet bijwerken.',
+ community_already_exists: 'Community bestaat al.',
+ community_moderator_already_exists: 'Community-moderator bestaat al.',
+ community_follower_already_exists: 'Community-volger bestaat al.',
+ community_user_already_banned: 'Community-gebruiker reeds verbannen.',
+ couldnt_create_post: 'Kon post niet maken.',
+ couldnt_like_post: 'Kon post niet leuk vinden.',
+ couldnt_find_post: 'Kon post niet vinden.',
+ couldnt_get_posts: 'Kon posts niet ophalen.',
+ couldnt_update_post: 'Kon post niet bijwerken.',
+ couldnt_save_post: 'Kon post niet opslaan.',
+ no_slurs: 'Geen beledigingen.',
+ not_an_admin: 'Niet een beheerder.',
+ site_already_exists: 'Site bestaat al.',
+ couldnt_update_site: 'Kon site niet bijwerken.',
+ couldnt_find_that_username_or_email: 'Kon gebruikersnaam of e-mailadres niet vinden.',
+ password_incorrect: 'Wachtwoord incorrect.',
+ passwords_dont_match: 'Wachtwoorden zijn niet gelijk.',
+ admin_already_created: 'Sorry, er is al een beheerder.',
+ user_already_exists: 'Gebruiker bestaat al.',
+ couldnt_update_user: 'Kon gebruiker niet bijwerken.',
+ system_err_login: 'Systeemfout. Probeer uit te loggen en weer in te loggen.',
+ },
+}
--- /dev/null
+export const ru = {
+ translation: {
+ post: 'запись',
+ remove_post: 'Удалить запись',
+ no_posts: 'Нет записей.',
+ create_a_post: 'Создать запись',
+ create_post: 'Создать запись',
+ number_of_posts:'{{count}} записей',
+ posts: 'Записи',
+ related_posts: 'Эти записи могут быть связаны',
+ comments: 'Комментарии',
+ number_of_comments:'{{count}} комментариев',
+ remove_comment: 'Удалить комментарий',
+ communities: 'Сообщества',
+ users: 'Пользователи',
+ create_a_community: 'Создать сообщество',
+ create_community: 'Создать сообщество',
+ remove_community: 'Удалить сообщество',
+ subscribed_to_communities:'Подписаны на <1>сообщества</1>',
+ trending_communities:'<1>Сообщества</1> в тренде',
+ list_of_communities: 'Список сообществ',
+ community_reqs: 'строчными буквами, подчеркиваниями и без пробелов.',
+ edit: 'редактировать',
+ reply: 'ответить',
+ cancel: 'Отмена',
+ unlock: 'разблокировать',
+ lock: 'заблокировать',
+ link: 'ссылка',
+ mod: 'модератор',
+ mods: 'модераторы',
+ moderates: 'Модерация',
+ settings: 'Настройки',
+ remove_as_mod: 'снять из модераторов',
+ appoint_as_mod: 'назначить модератором',
+ modlog: 'Модлог',
+ admin: 'администратор',
+ admins: 'администраторы',
+ remove_as_admin: 'снять из администраторов',
+ appoint_as_admin: 'назначить администратором',
+ remove: 'убрать',
+ removed: 'убрано',
+ locked: 'заблокировано',
+ reason: 'Причина',
+ mark_as_read: 'пометить как прочитанное',
+ mark_as_unread: 'пометить как непрочитанное',
+ delete: 'удалить',
+ deleted: 'удалено',
+ restore: 'восстановить',
+ ban: 'заблокировать',
+ ban_from_site: 'заблокировать на сайте',
+ unban: 'разблокировать',
+ unban_from_site: 'разблокировать на сайте',
+ save: 'сохранить',
+ unsave: 'не сохранять',
+ create: 'создать',
+ username: 'Имя пользователя',
+ email_or_username: 'Электронная почта или имя пользователя',
+ number_of_users:'{{count}} пользователей',
+ number_of_subscribers:'{{count}} подписчиков',
+ number_of_points:'{{count}} баллов',
+ name: 'Имя',
+ title: 'Название',
+ category: 'Категория',
+ subscribers: 'Подписчики',
+ both: 'Оба',
+ saved: 'Сохранено',
+ unsubscribe: 'Отписаться',
+ subscribe: 'Подписаться',
+ subscribed: 'Подписаны',
+ prev: 'Назад',
+ next: 'Далее',
+ sidebar: 'Боковая панель',
+ sort_type: 'Тип сортировки',
+ hot: 'Популярно',
+ new: 'Новое',
+ top_day: 'Лучшее за день',
+ week: 'Неделя',
+ month: 'Месяц',
+ year: 'Год',
+ all: 'Всё',
+ top: 'Лучшее',
+ api: 'API',
+ inbox: 'Входящие',
+ inbox_for: 'Входящие сообщения для <1>{{user}}</1>',
+ mark_all_as_read: 'пометить все как прочитанные',
+ type: 'Тип',
+ unread: 'Не прочитано',
+ reply_sent: 'Ответ отправлен',
+ search: 'Поиск',
+ overview: 'Обзор',
+ view: 'Просмотр',
+ logout: 'Выйти',
+ login_sign_up: 'Войти / Регистрация',
+ login: 'Авторизация',
+ sign_up: 'Регистрация',
+ notifications_error: 'Уведомления на рабочем столе недоступны в вашем браузере. Попробуйте Firefox или Chrome.',
+ unread_messages: 'Непрочитанные сообщения',
+ password: 'Пароль',
+ verify_password: 'Повторите пароль',
+ email: 'Электронная почта',
+ optional: 'Необязательно',
+ expires: 'Истёк',
+ url: 'URL',
+ body: 'Тело',
+ copy_suggested_title: 'предложенное название: {{title}}',
+ community: 'Сообщество',
+ expand_here: 'Расширить здесь',
+ subscribe_to_communities: 'Подпишитесь на некоторые <1>сообщества</1>.',
+ chat: 'Чат',
+ no_results: 'Нет результатов.',
+ setup: 'Установка',
+ lemmy_instance_setup: 'Установка инстанции Lemmy',
+ setup_admin: 'Настройка администратора сайта',
+ your_site: 'ваш сайт',
+ modified: 'изменено',
+ nsfw: 'NSFW',
+ show_nsfw: 'Показывать NSFW-контент',
+ sponsors: 'Спонсоры',
+ sponsors_of_lemmy: 'Спонсоры Lemmy',
+ sponsor_message: 'Lemmy это бесплатное, <1>открытое</1> программное обеспечение, что означает отсутствие рекламы, монетизации или венчурного капитала, никогда. Ваши пожертвования напрямую поддерживают развитие проекта. Спасибо нижеуказанным людям:',
+ support_on_patreon: 'Поддержать на Patreon',
+ general_sponsors:'Генеральные спонсоры - это те, кто пообещал Lemmy от $10 до $39.',
+ crypto: 'Крипто',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ code: 'Код',
+ joined: 'Присоединился',
+ powered_by: 'Работает на',
+ landing_0: 'Lemmy - это <1>агрегатор ссылок</1> / альтернатива reddit, предназначенный для работы в <2>федиверсе</2>.<3></3>Это самодостаточная система, с обновляемыми комментариями, и эта система крошечная (<4>~80 Кб</4>). Федерация в сети ActivityPub находится в разработке. <5></5>Это <6>очень ранняя бета-версия</6>, и многие функции в настоящее время сломаны или отсутствуют. <7></7>Предлагать новые функции или сообщать об ошибках можно <8>здесь.</8><9></9>Сделано на <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: 'Не авторизованы.',
+ community_ban: 'Вы были заблокированы на данном сообществе.',
+ site_ban: 'Вы были заблокированы на данном сайте',
+ couldnt_create_comment: 'Не получилось создать комментарий.',
+ couldnt_like_comment: 'Не получилось лайкнуть комментарий.',
+ couldnt_update_comment: 'Не получилось обновить комментарий.',
+ couldnt_save_comment: 'Не получилось сохранить комментарий.',
+ no_comment_edit_allowed: 'Невозможно отредактировать комментарий.',
+ no_post_edit_allowed: 'Невозможно отредактировать запись.',
+ no_community_edit_allowed: 'Невозможно отредактировать сообщество.',
+ couldnt_find_community: 'Не получилось найти сообщество.',
+ couldnt_update_community: 'Не получилось обновить сообщество.',
+ community_already_exists: 'Сообщество уже существует.',
+ community_moderator_already_exists: 'Модератор сообщества уже существует.',
+ community_follower_already_exists: 'Подписчик сообщества уже существует.',
+ community_user_already_banned: 'Пользователь сообщества уже заблокирован.',
+ couldnt_create_post: 'Не получилось создать запись.',
+ couldnt_like_post: 'Не получилось лайкнуть запись.',
+ couldnt_find_post: 'Не получилось найти запись.',
+ couldnt_get_posts: 'Не получилось найти записи',
+ couldnt_update_post: 'Не получилось обновить запись',
+ couldnt_save_post: 'Не получилось сохранить запись.',
+ no_slurs: 'Без оскорблений.',
+ not_an_admin: 'Не администратор.',
+ site_already_exists: 'Сайт уже существует.',
+ couldnt_update_site: 'Не получилось обновить сайт.',
+ couldnt_find_that_username_or_email: 'Не получилось найти данное имя пользователя или электронную почту.',
+ password_incorrect: 'Неверный пароль.',
+ passwords_dont_match: 'Пароли не совпадают.',
+ admin_already_created: 'Извините, уже есть администратор.',
+ user_already_exists: 'Пользователь уже существует.',
+ couldnt_update_user: 'Не получилось обновить пользователя.',
+ system_err_login: 'Системная ошибка. Попробуйте выйти из системы и вернуться обратно.',
+ },
+}
+
--- /dev/null
+export const sv = {
+ translation: {
+ post: 'inlägg',
+ remove_post: 'Radera inlägg',
+ no_posts: 'Inga inlägg.',
+ create_a_post: 'Skriv ett inlägg',
+ create_post: 'Skapa inlägg',
+ number_of_posts:'{{count}} inlägg',
+ posts: 'Inlägg',
+ related_posts: 'Dessa inlägg kan vara relaterade',
+ comments: 'Kommentarer',
+ number_of_comments:'{{count}} kommentarer',
+ remove_comment: 'Radera kommentar',
+ communities: 'Gemenskaper',
+ users: 'Användare',
+ create_a_community: 'Skapa en gemenskap',
+ create_community: 'Skapa gemenskap',
+ remove_community: 'Radera gemenskap',
+ subscribed_to_communities:'Prenumererar på <1>gemenskaper</1>',
+ trending_communities:'Populära <1>gemenskaper</1>',
+ list_of_communities: 'Lista över gemenskaper',
+ community_reqs: 'gemener, understreck och inga blanksteg.',
+ edit: 'redigera',
+ reply: 'svara',
+ cancel: 'Avbryt',
+ unlock: 'lås upp',
+ lock: 'lås',
+ link: 'länk',
+ mod: 'moderator',
+ mods: 'moderatorer',
+ moderates: 'Modererar',
+ remove_as_mod: 'tag bort som moderator',
+ appoint_as_mod: 'lägg till som moderator',
+ modlog: 'Moderationslogg',
+ admin: 'administratör',
+ admins: 'administratörer',
+ remove_as_admin: 'tag bort som administratör',
+ appoint_as_admin: 'lägg till som administratör',
+ remove: 'ta bort',
+ removed: 'borttagen',
+ locked: 'låst',
+ reason: 'Anledning',
+ mark_as_read: 'markera som läst',
+ mark_as_unread: 'markera som oläst',
+ delete: 'radera',
+ deleted: 'raderad',
+ restore: 'återställ',
+ ban: 'blockera',
+ ban_from_site: 'blockera från webbplats',
+ unban: 'ta bort blockering',
+ unban_from_site: 'ta bort blockering från webbplats',
+ save: 'spara',
+ unsave: 'förkasta', // Is perhaps 'ångra' more appropriate?
+ create: 'skapa',
+ username: 'Användarnamn',
+ email_or_username: 'E-postadress eller användarnamn',
+ number_of_users:'{{count}} användare',
+ number_of_subscribers:'{{count}} prenumeranter',
+ number_of_points:'{{count}} poäng',
+ name: 'Namn',
+ title: 'Titel',
+ category: 'Kategori',
+ subscribers: 'Prenumeranter',
+ both: 'Båda',
+ saved: 'Sparade',
+ unsubscribe: 'Avbryt prenumeration',
+ subscribe: 'Prenumerera',
+ subscribed: 'Prenumererar',
+ prev: 'Föregående',
+ next: 'Nästa',
+ sidebar: 'Sidlist',
+ sort_type: 'Sorteringstyp',
+ hot: 'Hett',
+ new: 'Nytt',
+ top_day: 'Dagstoppen',
+ week: 'Vecka',
+ month: 'Månad',
+ year: 'År',
+ all: 'Samtliga',
+ top: 'Topp',
+ api: 'API',
+ inbox: 'Inkorg',
+ inbox_for: 'Inkorg tillhörande <1>{{user}}</1>',
+ mark_all_as_read: 'markera alla som lästa',
+ type: 'Typ',
+ unread: 'Oläst',
+ reply_sent: 'Svar skickat',
+ search: 'Sök',
+ overview: 'Översikt',
+ view: 'Vy',
+ logout: 'Logga ut',
+ login_sign_up: 'Logga in eller skapa konto',
+ login: 'Logga in',
+ sign_up: 'Skapa konto',
+ notifications_error: 'Din webbläsare har inte stöd för skrivbordsaviseringar. Testa Firefox eller Chrome.',
+ unread_messages: 'Olästa meddelanden',
+ password: 'Lösenord',
+ verify_password: 'Bekräfta lösenord',
+ email: 'E-postadress',
+ optional: 'Valfritt',
+ expires: 'Går ut',
+ url: 'URL',
+ body: 'Brödtext', // Probably not the best in context.
+ copy_suggested_title: 'kopiera föreslagen titel: {{title}}',
+ community: 'Gemenskap',
+ expand_here: 'Utvidga här',
+ subscribe_to_communities: 'Prenumerera på några <1>gemenskaper</1>.',
+ chat: 'Chatta',
+ no_results: 'Inga resultat.',
+ setup: 'Installering',
+ lemmy_instance_setup: 'Installering av Lemmy-instans',
+ setup_admin: 'Skapa en administratör',
+ your_site: 'din webbplats',
+ modified: 'ändrades',
+ sponsors: 'Sponsorer',
+ sponsors_of_lemmy: 'Lemmys sponsorer',
+ sponsor_message: 'Lemmy är fri mjukvara med <1>öppen källkod</1>, vilket innebär att ingen reklam, vinstindrivning eller venturekapital förekommer, någonsin. Dina donationer går direkt till att stöda utvecklingen av projektet. Stort tack till följande personer:',
+ support_on_patreon: 'Stöd på Patreon',
+ general_sponsors:'Allmänna sponsorer är dem som givit mellan 10 och 39\u00a0dollar till Lemmy.',
+ crypto: 'Kryptovaluta',
+ bitcoin: 'Bitcoin',
+ ethereum: 'Ethereum',
+ code: 'Kod',
+ joined: 'Gick med',
+ powered_by: 'Drivs av',
+ landing_0: 'Lemmy är en <1>länksamlare</1> och alternativ till reddit, ämnad att fungera i <2>Fediversumet</2>.<3></3>Lemmy kan drivas av vem som helst, har kommentarstrådar som updateras i realid och är mycket liten (<4>ca 80\u00a0kB</4>). Federering med ActivityPub-nätverket är planerat. <5></5>Detta är en <6>väldigt tidig betaversion</6> och många funktioner saknas därför eller är trasiga.<7></7>Föreslå nya funktioner eller anmäl buggar <8>här</8>.<9></9>Skapad i <10>Rust</10>, <11>Actix</11>, <12>Inferno</12> och <13>Typescript</13>.',
+ not_logged_in: 'Inte inloggad.',
+ community_ban: 'Du har blockerats från den här gemenskapen.',
+ site_ban: 'Du har blockerats från webbplatsen.',
+ couldnt_create_comment: 'Kunde inte skapa kommentar.',
+ couldnt_like_comment: 'Kunde inte gilla kommentar.',
+ couldnt_update_comment: 'Kunde inte uppdatera kommentar.',
+ couldnt_save_comment: 'Kunde inte spara kommentar.',
+ no_comment_edit_allowed: 'Har inte behörighet att redigera komentar.',
+ no_post_edit_allowed: 'Har inte behörighet att redigera inlägg.',
+ no_community_edit_allowed: 'Har inte behörighet att redigera gemenskap.',
+ couldnt_find_community: 'Kunde inte hitta gemenskap.',
+ couldnt_update_community: 'Kunde inte uppdatera gemenskap.',
+ community_already_exists: 'Gemenskapen finns redan.',
+ community_moderator_already_exists: 'Gemenskapsmoderatorn finns redan.',
+ community_follower_already_exists: 'Gemenskapsföljaren finns redan.',
+ community_user_already_banned: 'Gemenskapsanvändaren redan blockerad.',
+ couldnt_create_post: 'Kunde inte skapa inlägg.',
+ couldnt_like_post: 'Kunde inte gilla inlägg.',
+ couldnt_find_post: 'Kunde inte hitta inlägg.',
+ couldnt_get_posts: 'Kunde inte hämta inlägg.',
+ couldnt_update_post: 'Kunde inte uppdatera inlägg.',
+ couldnt_save_post: 'Kunde inte spara inlägg.',
+ no_slurs: 'Inga förolämpningar.',
+ not_an_admin: 'Inte en administratör.',
+ site_already_exists: 'Webbplatsen finns redan.',
+ couldnt_update_site: 'Kunde inte uppdatera webbplats.',
+ couldnt_find_that_username_or_email: 'Kunde inte hitta det användarnamnet eller e-postadressen.',
+ password_incorrect: 'Ogiltigt lösenord.',
+ passwords_dont_match: 'Lösenorden stämmer inte överens.',
+ admin_already_created: 'Beklagar, men det finns redan en administratör.',
+ user_already_exists: 'Användaren finns redan.',
+ couldnt_update_user: 'Kunde inte uppdatera användare.',
+ system_err_login: 'Systemfel. Försök att logga ut och sedan in igen.',
+ },
+}
--- /dev/null
+export const zh = {
+ translation: {
+ post: '帖子',
+ remove_post: '移除帖子',
+ no_posts: '没有帖子.',
+ create_a_post: '创建新帖子',
+ create_post: '创建帖子',
+ number_of_posts:'{{count}} 帖子',
+ posts: '帖子',
+ related_posts: '相关的帖子',
+ comments: '评论',
+ number_of_comments:'{{count}} 评论',
+ remove_comment: '移除评论',
+ communities: '节点',
+ create_a_community: '创建新节点',
+ create_community: '创建节点',
+ remove_community: '移除节点',
+ subscribed_to_communities:'订阅新 <1>节点</1>',
+ trending_communities:'<1>节点</1>趋势',
+ list_of_communities: '节点列表',
+ community_reqs: '包含小写与下划线且没有空格的字符串.',
+ edit: '编辑',
+ reply: '回应',
+ cancel: '取消',
+ unlock: '解锁',
+ lock: '加锁',
+ link: '链接',
+ mod: 'mod',
+ mods: 'mods',
+ moderates: 'Moderates',
+ remove_as_mod: 'remove as mod',
+ appoint_as_mod: 'appoint as mod',
+ modlog: 'Modlog',
+ admin: 'admin',
+ admins: 'admins',
+ remove_as_admin: '移除管理权限',
+ appoint_as_admin: '添加管理权限',
+ remove: '移除',
+ removed: '已移除',
+ locked: '已加锁',
+ reason: '原因',
+ mark_as_read: '标记未读',
+ mark_as_unread: '标记已读',
+ delete: '删除',
+ deleted: '已删除',
+ restore: '恢复',
+ ban: '禁止',
+ ban_from_site: '禁止此站点',
+ unban: '取消',
+ unban_from_site: '取消禁止',
+ save: '保存',
+ unsave: '取消保存',
+ create: '创建',
+ username: '用户名',
+ email_or_username: '邮箱或用户名',
+ number_of_users:'{{count}} 用户',
+ number_of_subscribers:'{{count}} 订阅',
+ number_of_points:'{{count}} 分',
+ name: '名字',
+ title: '标题',
+ category: '分类',
+ subscribers: '订阅',
+ both: '全部',
+ saved: '保存',
+ unsubscribe: '取消订阅',
+ subscribe: '订阅',
+ subscribed: '已订阅',
+ prev: '上一页',
+ next: '下一页',
+ sidebar: '侧边栏',
+ sort_type: '排序方式',
+ hot: '最热',
+ new: '最新',
+ top_day: '今日',
+ week: '周',
+ month: '月',
+ year: '年',
+ all: '所有',
+ top: '最热',
+ api: 'API',
+ inbox: '收件箱',
+ inbox_for: '<1>{{user}}</1> 收件箱',
+ mark_all_as_read: '标记所有已读',
+ type: '类型',
+ unread: '未读',
+ reply_sent: '回复发送',
+ search: '搜索',
+ overview: '个人中心',
+ view: '查看',
+ logout: '注销',
+ login_sign_up: '登录/注册',
+ login: '登录',
+ sign_up: '注册',
+ notifications_error: '你的浏览器不支持桌面通知,尝试 Firefox 或 Chrome',
+ unread_messages: '未读消息',
+ password: '密码',
+ verify_password: '确认密码',
+ email: '邮箱',
+ optional: '选项',
+ expires: '过期',
+ url: 'URL',
+ body: '内容',
+ copy_suggested_title: '复制建议的标题: {{title}}',
+ community: '节点',
+ expand_here: '展开',
+ subscribe_to_communities: '订阅一些 <1>节点</1>.',
+ chat: '聊天',
+ no_results: '没有结果.',
+ setup: '设置',
+ lemmy_instance_setup: 'Lemmy Instance Setup',
+ setup_admin: '设置管理员',
+ your_site: '你的站点',
+ modified: '修改',
+ sponsors: 'Sponsors',
+ sponsors_of_lemmy: 'Sponsors of Lemmy',
+ sponsor_message: 'Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:',
+ support_on_patreon: 'Support on Patreon',
+ general_sponsors:'General Sponsors are those that pledged $10 to $39 to Lemmy.',
+ crypto: '加密',
+ bitcoin: '比特币',
+ ethereum: '以太币',
+ code: '代码',
+ joined: '已加入',
+ powered_by: '保留所有权利',
+ landing_0: 'Lemmy is a <1>link aggregator</1> / reddit alternative, intended to work in the <2>fediverse</2>.<3></3>It\'s self-hostable, has live-updating comment threads, and is tiny (<4>~80kB</4>). Federation into the ActivityPub network is on the roadmap. <5></5>This is a <6>very early beta version</6>, and a lot of features are currently broken or missing. <7></7>Suggest new features or report bugs <8>here.</8><9></9>Made with <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.',
+ not_logged_in: '未登录.',
+ community_ban: '你被此节点禁止.',
+ site_ban: '你被此站点禁止',
+ couldnt_create_comment: '不能创建评论.',
+ couldnt_like_comment: '不能收藏评论.',
+ couldnt_update_comment: '不能更新评论.',
+ couldnt_save_comment: '不能保存评论.',
+ no_comment_edit_allowed: '不允许编辑评论.',
+ no_post_edit_allowed: '不运行编辑帖子.',
+ no_community_edit_allowed: '不允许编辑节点.',
+ couldnt_find_community: '不能找到节点.',
+ couldnt_update_community: '不能更新节点.',
+ community_already_exists: '节点已存在.',
+ community_moderator_already_exists: '节点 moderator 已存在.',
+ community_follower_already_exists: '节点 follower 已存在.',
+ community_user_already_banned: '节点用户已禁止.',
+ couldnt_create_post: '不能创建帖子.',
+ couldnt_like_post: '不能收藏帖子.',
+ couldnt_find_post: '不能搜寻帖子.',
+ couldnt_get_posts: '不能获取帖子',
+ couldnt_update_post: '不能更新帖子',
+ couldnt_save_post: '不能保持帖子.',
+ no_slurs: '和谐.',
+ not_an_admin: '不是管理员.',
+ site_already_exists: '站点已存在.',
+ couldnt_update_site: '不能更新站点.',
+ couldnt_find_that_username_or_email: '用户名/邮箱不存在.',
+ password_incorrect: '密码不正确.',
+ passwords_dont_match: '密码不匹配.',
+ admin_already_created: '抱歉,管理员已存在.',
+ user_already_exists: '用户已存在.',
+ couldnt_update_user: '不可以更新用户.',
+ system_err_login: '系统错误. 尝试注销再登录',
+ },
+}
+
+import 'moment/locale/es';
+import 'moment/locale/eo';
+import 'moment/locale/de';
+import 'moment/locale/zh-cn';
+import 'moment/locale/fr';
+import 'moment/locale/sv';
+import 'moment/locale/ru';
+import 'moment/locale/nl';
+
import { UserOperation, Comment, User, SortType, ListingType } from './interfaces';
import * as markdown_it from 'markdown-it';
declare var markdownitEmoji: any;
}
var md = new markdown_it({
- html: true,
+ html: false,
linkify: true,
typographer: true
}).use(markdown_it_container, 'spoiler', {
return imageRegex.test(url);
}
+export function validURL(str: string) {
+ var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
+ '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
+ '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
+ '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
+ return !!pattern.test(str);
+}
+
export let fetchLimit: number = 20;
export function capitalizeFirstLetter(str: string): string {
return data;
}
+export function debounce(func: any, wait: number = 500, immediate: boolean = false) {
+ // 'private' variable for instance
+ // The returned function will be able to reference this due to closure.
+ // Each call to the returned function will share this common timer.
+ let timeout: number;
+
+ // Calling debounce returns a new anonymous function
+ return function() {
+ // reference the context and args for the setTimeout function
+ var context = this,
+ args = arguments;
+
+ // Should the function be called now? If immediate is true
+ // and not already in a timeout then the answer is: Yes
+ var callNow = immediate && !timeout;
+
+ // This is the basic debounce behaviour where you can call this
+ // function several times, but it will only execute once
+ // [before or after imposing a delay].
+ // Each time the returned function is called, the timer starts over.
+ clearTimeout(timeout);
+
+ // Set the new timeout
+ timeout = setTimeout(function() {
+
+ // Inside the timeout function, clear the timeout variable
+ // which will let the next execution run when in 'immediate' mode
+ timeout = null;
+
+ // Check if the function already ran with the immediate flag
+ if (!immediate) {
+ // Call the original function with apply
+ // apply lets you define the 'this' object as well as the arguments
+ // (both captured before setTimeout)
+ func.apply(context, args);
+ }
+ }, wait);
+
+ // Immediate mode and no wait timer? Execute the function..
+ if (callNow) func.apply(context, args);
+ }
+}
+
+export function getLanguage(): string {
+ return (navigator.language || navigator.userLanguage);
+}
+
+export function getMomentLanguage(): string {
+ let lang = getLanguage();
+ if (lang.startsWith('zh')) {
+ lang = 'zh-cn';
+ } else if (lang.startsWith('sv')) {
+ lang = 'sv';
+ } else if (lang.startsWith('fr')) {
+ lang = 'fr';
+ } else if (lang.startsWith('de')) {
+ lang = 'de';
+ } else if (lang.startsWith('ru')) {
+ lang = 'ru';
+ } else if (lang.startsWith('es')) {
+ lang = 'es';
+ } else if (lang.startsWith('eo')) {
+ lang = 'eo';
+ } else if (lang.startsWith('nl')) {
+ lang = 'nl';
+ } else {
+ lang = 'en';
+ }
+ return lang;
+}
-export let version: string = "v0.0.5-16-gc7d8d5f";
\ No newline at end of file
+export let version: string = "v0.0.8.7-0-g614c4f8";
\ No newline at end of file
+++ /dev/null
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: lemmy-ui--dev
-spec:
- selector:
- matchLabels:
- app: lemmy-ui--dev
- template:
- metadata:
- labels:
- app: lemmy-ui--dev
- spec:
- containers:
- - name: lemmy-ui--dev
- image: registry.gitlab.com/pojntfx/lemmy/ui.dev
- resources:
- limits:
- memory: 1024Mi
- cpu: 512m
- ports:
- - containerPort: 4444
----
-apiVersion: v1
-kind: Service
-metadata:
- name: lemmy-ui--dev
-spec:
- type: NodePort
- selector:
- app: lemmy-ui--dev
- ports:
- - port: 4444
- nodePort: 30002
+++ /dev/null
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: lemmy-ui--prod
-spec:
- selector:
- matchLabels:
- app: lemmy-ui--prod
- template:
- metadata:
- labels:
- app: lemmy-ui--prod
- spec:
- containers:
- - name: lemmy-ui--prod
- image: registry.gitlab.com/pojntfx/lemmy/ui.prod
- resources:
- limits:
- memory: 1024Mi
- cpu: 512m
- ports:
- - containerPort: 4444
----
-apiVersion: v1
-kind: Service
-metadata:
- name: lemmy-ui--prod
-spec:
- selector:
- app: lemmy-ui--prod
- ports:
- - port: 5000
- targetPort: 5000
----
-apiVersion: extensions/v1beta1
-kind: Ingress
-metadata:
- name: lemmy-server--prod
- annotations:
- traefik.ingress.kubernetes.io/request-modifier: "ReplacePathRegex: ^/static/(.*) /$1"
-spec:
- rules:
- - host: dev.lemmy.local
- http:
- paths:
- - path: /
- backend:
- serviceName: lemmy-ui--prod
- servicePort: 5000
- - path: /api/v1/ws
- backend:
- serviceName: lemmy-server--prod
- servicePort: 8536
--- /dev/null
+import { en } from './src/translations/en';
+import { eo } from './src/translations/eo';
+import { es } from './src/translations/es';
+import { de } from './src/translations/de';
+import { zh } from './src/translations/zh';
+import { fr } from './src/translations/fr';
+import { sv } from './src/translations/sv';
+import { ru } from './src/translations/ru';
+import { nl } from './src/translations/nl';
+
+let files = [
+ {t: de, n: 'de'},
+ {t: eo, n: 'eo'},
+ {t: es, n: 'es'},
+ {t: fr, n: 'fr'},
+ {t: nl, n: 'nl'},
+ {t: ru, n: 'ru'},
+ {t: sv, n: 'sv'},
+ {t: zh, n: 'zh'},
+];
+let masterKeys = Object.keys(en.translation);
+
+let report = 'lang | done | missing\n';
+report += '--- | --- | ---\n';
+
+for (let file of files) {
+ let keys = Object.keys(file.t.translation);
+ let pct: number = (keys.length / masterKeys.length * 100);
+ let missing = difference(masterKeys, keys);
+ report += `${file.n} | ${pct.toFixed(0)}% | ${missing} \n`;
+}
+
+console.log(report);
+
+function difference(a: Array<string>, b: Array<string>): Array<string> {
+ return a.filter(x => !b.includes(x));
+}
"extends": "tslint:recommended",
"rules": {
"forin": false,
- "indent": [ true, "tabs" ],
+ "indent": [ true, "spaces" ],
"interface-name": false,
"ban-types": true,
"max-classes-per-file": true,
# yarn lockfile v1
-"@babel/runtime@^7.1.2":
- version "7.4.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
- integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1":
+ version "7.5.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
+ integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
dependencies:
regenerator-runtime "^0.13.2"
dependencies:
"@types/jquery" "*"
+"@types/i18next@^12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@types/i18next/-/i18next-12.1.0.tgz#7c3fd3dbe03f9531147033773bbd0ca4f474a180"
+ integrity sha512-qLyqTkp3ZKHsSoX8CNVYcTyTkxlm0aRCUpaUVetgkSlSpiNCdWryOgaYwgbO04tJIfLgBXPcy0tJ3Nl/RagllA==
+
"@types/jquery@*":
- version "3.3.29"
- resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.29.tgz#680a2219ce3c9250483722fccf5570d1e2d08abd"
- integrity sha512-FhJvBninYD36v3k6c+bVk1DSZwh7B5Dpb/Pyk3HKVsiohn0nhbefZZ+3JXbWQhFyt0MxSl2jRDdGQPHeOHFXrQ==
+ version "3.3.31"
+ resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b"
+ integrity sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg==
dependencies:
"@types/sizzle" "*"
dependencies:
"@types/markdown-it" "*"
-"@types/markdown-it@*", "@types/markdown-it@^0.0.7":
+"@types/markdown-it@*":
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.8.tgz#9af8704acde87fec70475369ba0413d50717bd8d"
+ integrity sha512-ouaTOi5kAdkTPl97u6uDkth9od4pQffPF9STcjYVZKFrEwLYf15s7Z772WxWE3IOcYBJglaT0XqdyNEiEfGgYg==
+ dependencies:
+ "@types/linkify-it" "*"
+
+"@types/markdown-it@^0.0.7":
version "0.0.7"
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.7.tgz#75070485a3d8ad11e7deb8287f4430be15bf4d39"
integrity sha512-WyL6pa76ollQFQNEaLVa41ZUUvDvPY+qAUmlsphnrpL6I9p1m868b26FyeoOmo7X3/Ta/S9WKXcEYXUSHnxoVQ==
utils-extend "^1.0.7"
ajv@^6.5.5:
- version "6.10.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
- integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
+ version "6.10.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
+ integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
+async-limiter@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
+ integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
file-system "^2.1.0"
base64-js@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
- integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
+ integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
base@^0.11.1:
version "0.11.2"
type-is "~1.6.17"
bowser@^2.0.0-beta.3:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.4.0.tgz#fcfbca3d7659ba88afabbb8a45b33d2e4876a90c"
- integrity sha512-DA9Opnb8S8TBLPPszrHDtCCATbAMkrxF+AxPs/d95r99frBioGpNwL1cbG3AHeV3FnoZW655vEvEryBHFeGrMg==
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.5.3.tgz#811b0a24219c566c9a6ab3402bc8a13f35a18a96"
+ integrity sha512-aWCA+CKfKNL/WGzNgjmK+Whp57JMzboZMwJ5gy2jDj2bEIjbMCb3ImGX+V++5wsJftyFiDIbOjRXl60ycniVqg==
brace-expansion@^1.1.7:
version "1.1.11"
fsevents "^1.0.0"
chownr@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
- integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
+ integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==
class-utils@^0.3.5:
version "0.3.6"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
escodegen@^1.8.1:
- version "1.11.1"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.1.tgz#c485ff8d6b4cdb89e27f4a856e91f118401ca510"
- integrity sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.0.tgz#f763daf840af172bb3a2b6dd7219c0e17f7ff541"
+ integrity sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==
dependencies:
esprima "^3.1.3"
estraverse "^4.2.0"
integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=
estraverse@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
- integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
esutils@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
- integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
etag@~1.8.1:
version "1.8.1"
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
getopts@^2.1.1:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.4.tgz#3137fe8a5fddf304904059a851bdc1c22f0f54fb"
- integrity sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ==
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b"
+ integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==
getpass@^0.1.1:
version "0.1.7"
path-is-absolute "^1.0.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
- version "4.1.15"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
- integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02"
+ integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hoist-non-inferno-statics/-/hoist-non-inferno-statics-1.1.3.tgz#7d870f4160bfb6a59269b45c343c027f0e30ab35"
integrity sha1-fYcPQWC/tqWSabRcNDwCfw4wqzU=
-http-errors@1.7.2, http-errors@~1.7.2:
+html-parse-stringify2@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
+ integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
+ dependencies:
+ void-elements "^2.0.1"
+
+http-errors@1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
+http-errors@~1.7.2:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
+ integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.4"
+ setprototypeof "1.1.1"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.0"
+
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
jsprim "^1.2.2"
sshpk "^1.7.0"
+i18next@^17.0.9:
+ version "17.0.13"
+ resolved "https://registry.yarnpkg.com/i18next/-/i18next-17.0.13.tgz#3c639e15de86e0523f8f286f6cf07db355ee0a4f"
+ integrity sha512-tCBpekVs95IsN3kdi/6HhnfzHDlpXerOmOsf2ZMWtct9YbMYKI54HVdQ6XxsHGXBxY+UgjbQJwqghKCd2sYQWw==
+ dependencies:
+ "@babel/runtime" "^7.3.1"
+
iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
dependencies:
minimatch "^3.0.4"
+inferno-clone-vnode@^7.1.12:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/inferno-clone-vnode/-/inferno-clone-vnode-7.3.1.tgz#7dc75d58ce818188beb77acb49f672568cd817a8"
+ integrity sha512-Nu+jrwOVXlaMsxtxRbPiB51SySgI9FrGKt0wR9NNWSOoaW9fXbQewcPdI5Jn9MYin/oQrpJ8+BI9pZ9Bu7Z6bQ==
+ dependencies:
+ inferno "7.3.1"
+
+inferno-create-element@^7.1.12:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/inferno-create-element/-/inferno-create-element-7.3.1.tgz#b85f8ede233b19653662d6ac3bd88892319b09e4"
+ integrity sha512-HyC4UTmSB+3+erVp/0Y5BYioBxKLZpKrIBYEHTzeDXfsJv9wEsJ5KbZ5vsmQDh+jj6NRd72cCPMBXmN9pyyMCA==
+ dependencies:
+ inferno "7.3.1"
+
+inferno-i18next@nimbusec-oss/inferno-i18next:
+ version "7.1.12"
+ resolved "https://codeload.github.com/nimbusec-oss/inferno-i18next/tar.gz/f8c1403e60be70141c558e36f12f22c106cb7463"
+ dependencies:
+ html-parse-stringify2 "^2.0.1"
+ inferno "^7.1.12"
+ inferno-clone-vnode "^7.1.12"
+ inferno-create-element "^7.1.12"
+ inferno-shared "^7.1.12"
+ inferno-vnode-flags "^7.1.12"
+
inferno-router@^7.0.1:
- version "7.1.13"
- resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.1.13.tgz#7f72ca8deaa5bf8c2f49bcb3db253e294c134f77"
- integrity sha512-y97fF0IG70+nAlHRtxaH/8QsMUsSWeS375MC416NomP5tohSxmBLB0WQGTYFHvnMpqb/QSq2ojsifBAWqSHnuw==
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.3.1.tgz#cdb81349dd1b51fa03c65bdd938e6b050006e44b"
+ integrity sha512-Hav1iCti9u6oc8ZIGmUhDHQOBRK/uJpDdbk0naEmMZ4zfu/6hbk7q7mObRVtO5QVBL2Y343SKb43LAJWv3C/rw==
dependencies:
history "^4.9.0"
hoist-non-inferno-statics "^1.1.3"
- inferno "7.1.13"
+ inferno "7.3.1"
path-to-regexp-es6 "1.7.0"
-inferno-shared@7.1.13:
- version "7.1.13"
- resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.1.13.tgz#2c70af637873b58fbfc3897813076dec4850a6b0"
- integrity sha512-HNWpvCFO9vw5I9XNvsZamhe7UcSMBN62AOCyyGHlBGPB996/f3xwwgBWi0uHQ2rBtiM4Hp3rn65PQ5wSVd6/hg==
+inferno-shared@7.3.1, inferno-shared@^7.1.12:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.3.1.tgz#93e269cb46838780b68fa5113c9a29b6109882de"
+ integrity sha512-7I1ZJG+MFcGtlXjuyvkwFSGcT46Vs9NTzA0Sr1EkF9EMqVskVflP1r5f+quASMhby2OY7AGXnAaSsM7AbxsOlA==
-inferno-vnode-flags@7.1.13:
- version "7.1.13"
- resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.1.13.tgz#8c98e69079fe85feffe0ded79e6d7c05ae0d59b1"
- integrity sha512-RELi78Y2bs81hSxgVOY2oZ+E6mHqtXFFdsuslWYwmaYbEDYV2qZQp4ayu5MyHQU+Ip8dkjKvIkN/yrYoBAvJgw==
+inferno-vnode-flags@7.3.1, inferno-vnode-flags@^7.1.12:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.3.1.tgz#27f767a03d8f0775f8bc5ad03c9ea07ec66aa2c7"
+ integrity sha512-7LKuUGfFVSiFdRH6NVLTetrDbft4BxUePUIjXm4f+g9hginYuBwPbFJbbHK700Ysy4rapTqYnFxSk0k5JBZr+A==
-inferno@7.1.13, inferno@^7.0.1:
- version "7.1.13"
- resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.1.13.tgz#d8ce8384a07de5138897f9f79c25d04141228b93"
- integrity sha512-CrdzQRHMRkhrRTAB2tYBxnqe1umYkuKparHOHd7R37okd1TGp/Q8bQa58002Qh4pY+BU272mz3FuQC5LDQOLRg==
+inferno@7.3.1, inferno@^7.0.1, inferno@^7.1.12:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.3.1.tgz#5e356d9a5a218809eb4da49c333d324126515683"
+ integrity sha512-9t4G/YjhbiC65d8GHxzfn41qALVf2fvykMdH92ySUiSLr3EQak8gs6rno52KuW7puDZcmJgmMHVA0vTVegtfsQ==
dependencies:
- inferno-shared "7.1.13"
- inferno-vnode-flags "7.1.13"
+ inferno-shared "7.3.1"
+ inferno-vnode-flags "7.3.1"
opencollective-postinstall "^2.0.2"
inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
-is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
js-cookie@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb"
- integrity sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s=
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
+ integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
type-check "~0.3.2"
linkify-it@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.1.0.tgz#c4caf38a6cd7ac2212ef3c7d2bde30a91561f9db"
- integrity sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
+ integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
dependencies:
uc.micro "^1.0.1"
lodash@^4.3.0:
- version "4.17.11"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
- integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
+ version "4.17.15"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+ integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
loose-envify@^1.2.0:
version "1.4.0"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
minipass@^2.2.1, minipass@^2.3.5:
- version "2.3.5"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
- integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.5.0.tgz#dddb1d001976978158a05badfcbef4a771612857"
+ integrity sha512-9FwMVYhn6ERvMR8XFdOavRz4QK/VJV8elU1x50vYexf9lslDcWe/f4HBRxCPd185ekRSjU6CfYyJCECa/CQy7Q==
dependencies:
safe-buffer "^5.1.2"
yallist "^3.0.0"
minipass "^2.2.1"
mixin-deep@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
- integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+ integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
dependencies:
for-in "^1.0.2"
is-extendable "^1.0.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-ms@2.1.1, ms@^2.1.1:
+ms@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+ms@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
mustache@^2.3.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.2.tgz#a6d4d9c3f91d13359ab889a812954f9230a3d0c5"
integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
npm-packlist@^1.1.6:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
- integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44"
+ integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==
dependencies:
ignore-walk "^3.0.1"
npm-bundled "^1.0.1"
integrity sha1-FK//amReWRpN3xxykZwjtBRhgaE=
process-nextick-args@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
- integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
proxy-addr@~2.0.5:
version "2.0.5"
ipaddr.js "1.9.0"
psl@^1.1.24:
- version "1.1.32"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.32.tgz#3f132717cf2f9c169724b2b6caf373cf694198db"
- integrity sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.3.0.tgz#e1ebf6a3b5564fa8376f3da2275da76d875ca1bd"
+ integrity sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==
punycode@^1.4.1:
version "1.4.1"
app-root-path "^1.3.0"
mkdirp "^0.5.1"
-regenerate-unicode-properties@^8.0.2:
+regenerate-unicode-properties@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
regenerator-runtime@^0.13.2:
- version "0.13.2"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
- integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
+ version "0.13.3"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"
+ integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==
regex-cache@^0.4.2:
version "0.4.4"
safe-regex "^1.1.0"
regexpu-core@^4.1.3:
- version "4.5.4"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
- integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
+ version "4.5.5"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.5.tgz#aaffe61c2af58269b3e516b61a73790376326411"
+ integrity sha512-FpI67+ky9J+cDizQUJlIlNZFKual/lUkFr1AG6zOCpwZ9cLrg8UUVakyUQJD7fCDIe9Z2nwTQJNPyonatNmDFQ==
dependencies:
regenerate "^1.4.0"
- regenerate-unicode-properties "^8.0.2"
+ regenerate-unicode-properties "^8.1.0"
regjsgen "^0.5.0"
regjsparser "^0.6.0"
unicode-match-property-ecmascript "^1.0.4"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
rimraf@^2.6.1:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
- integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+ integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
dependencies:
tslib "^1.9.0"
-safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+safe-buffer@^5.0.1, safe-buffer@^5.1.2:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+ integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
safe-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
semver@^5.3.0:
- version "5.7.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
- integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
-set-value@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
- integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE=
- dependencies:
- extend-shallow "^2.0.1"
- is-extendable "^0.1.1"
- is-plain-object "^2.0.1"
- to-object-path "^0.3.0"
-
-set-value@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
- integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==
+set-value@^2.0.0, set-value@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+ integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
urix "^0.1.0"
source-map-support@~0.5.10:
- version "0.5.12"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
- integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
+ version "0.5.13"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
+ integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
has-flag "^3.0.0"
tar@^4:
- version "4.4.9"
- resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.9.tgz#058fbb152f6fc45733e84585a40c39e59302e1b3"
- integrity sha512-xisFa7Q2i3HOgfn+nmnWLGHD6Tm23hxjkx6wwGmgxkJFr6wxwXnJOdJYcZjL453PSdF0+bemO03+flAzkIdLBQ==
+ version "4.4.10"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1"
+ integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==
dependencies:
chownr "^1.1.1"
fs-minipass "^1.2.5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
tiny-invariant@^1.0.2:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.4.tgz#346b5415fd93cb696b0c4e8a96697ff590f92463"
- integrity sha512-lMhRd/djQJ3MoaHEBrw8e2/uM4rs9YMNk0iOr8rHQ0QdbM7D4l0gFl3szKdeixrlyfm9Zqi4dxHCM2qVG8ND5g==
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
+ integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
tiny-warning@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.2.tgz#1dfae771ee1a04396bdfde27a3adcebc6b648b28"
- integrity sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q==
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tmp@^0.0.33:
version "0.0.33"
integrity sha512-CZb4+w/2l2zikPZ/c51fi3n+qnR2HCEfAS73oGQB80aqRLffkZqm25kYYTMmqUW2+oVfs4M5AZa0z14cvxlQ5w==
tslib@^1.8.0, tslib@^1.9.0:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
- integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
+ integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
-typescript@^3.3.3333:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202"
- integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==
+typescript@^3.5.3:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54"
+ integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"
integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
union-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
- integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+ integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
dependencies:
arr-union "^3.1.0"
get-value "^2.0.6"
is-extendable "^0.1.1"
- set-value "^0.4.3"
+ set-value "^2.0.1"
universalify@^0.1.0:
version "0.1.2"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
uuid@^3.3.2:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
- integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
+ integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
value-equal@^0.4.0:
version "0.4.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
+void-elements@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
+ integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
+
watch@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c"
options ">=0.0.5"
ultron "1.0.x"
+ws@^7.0.0:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.1.2.tgz#c672d1629de8bb27a9699eb599be47aeeedd8f73"
+ integrity sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==
+ dependencies:
+ async-limiter "^1.0.0"
+
yallist@^3.0.0, yallist@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"