mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-22 20:31:19 +00:00
Merge branch 'master' into federation
This commit is contained in:
commit
31f835db86
31 changed files with 762 additions and 243 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,7 +2,6 @@
|
|||
ansible/inventory
|
||||
ansible/inventory_dev
|
||||
ansible/passwords/
|
||||
ansible/vars/
|
||||
|
||||
# docker build files
|
||||
docker/lemmy_mine.hjson
|
||||
|
|
1
.travis.yml
vendored
1
.travis.yml
vendored
|
@ -12,7 +12,6 @@ before_cache:
|
|||
- rm -rfv target/debug/build/lemmy_server-*
|
||||
- rm -rfv target/debug/deps/lemmy_server-*
|
||||
- rm -rfv target/debug/lemmy_server.d
|
||||
- cargo clean
|
||||
before_script:
|
||||
- psql -c "create user lemmy with password 'password' superuser;" -U postgres
|
||||
- psql -c 'create database lemmy with owner lemmy;' -U postgres
|
||||
|
|
50
ansible/lemmy_dev.yml
vendored
50
ansible/lemmy_dev.yml
vendored
|
@ -16,32 +16,6 @@
|
|||
- setup: # gather facts
|
||||
|
||||
tasks:
|
||||
# TODO: this task is running on all hosts at the same time so there is a race condition
|
||||
- name: xxx
|
||||
shell: |
|
||||
mkdir -p "vars/{{ inventory_hostname }}/"
|
||||
if [ ! -f "vars/{{ inventory_hostname }}/port_counter" ]; then
|
||||
if [ -f "vars/max_port_counter" ]; then
|
||||
MAX_PORT=$(cat vars/max_port_counter)
|
||||
else
|
||||
MAX_PORT=8000
|
||||
fi
|
||||
OUR_PORT=$(expr $MAX_PORT + 10)
|
||||
echo $OUR_PORT > "vars/{{ inventory_hostname }}/port_counter"
|
||||
echo $OUR_PORT > "vars/max_port_counter"
|
||||
fi
|
||||
cat "vars/{{ inventory_hostname }}/port_counter"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
delegate_to: localhost
|
||||
register: lemmy_port
|
||||
|
||||
- set_fact: "lemmy_port={{ lemmy_port.stdout_lines[0] }}"
|
||||
- set_fact: "pictshare_port={{ lemmy_port|int + 1 }}"
|
||||
- set_fact: "iframely_port={{ lemmy_port|int + 2 }}"
|
||||
- debug:
|
||||
msg: "lemmy_port={{ lemmy_port }} pictshare_port={{pictshare_port}} iframely_port={{iframely_port}}"
|
||||
|
||||
- name: install dependencies
|
||||
apt:
|
||||
pkg: ['nginx', 'docker-compose', 'docker.io', 'certbot', 'python-certbot-nginx']
|
||||
|
@ -51,29 +25,25 @@
|
|||
args:
|
||||
creates: '/etc/letsencrypt/live/{{domain}}/privkey.pem'
|
||||
|
||||
# TODO: need to use different path per domain
|
||||
- name: create lemmy folder
|
||||
file: path={{item.path}} state=directory
|
||||
with_items:
|
||||
- { path: '/lemmy/{{ domain }}/' }
|
||||
- { path: '/lemmy/{{ domain }}/volumes/' }
|
||||
- { path: '/var/cache/lemmy/{{ domain }}/' }
|
||||
- { path: '/lemmy/' }
|
||||
- { path: '/lemmy/volumes/' }
|
||||
|
||||
- block:
|
||||
- name: add template files
|
||||
template: src={{item.src}} dest={{item.dest}} mode={{item.mode}}
|
||||
with_items:
|
||||
- { src: 'templates/docker-compose.yml', dest: '/lemmy/{{domain}}/docker-compose.yml', mode: '0600' }
|
||||
- { src: 'templates/nginx.conf', dest: '/etc/nginx/sites-enabled/lemmy-{{ domain }}.conf', mode: '0644' }
|
||||
- { src: '../docker/iframely.config.local.js', dest: '/lemmy/{{ domain }}/iframely.config.local.js', mode: '0600' }
|
||||
- { src: 'templates/docker-compose.yml', dest: '/lemmy/docker-compose.yml', mode: '0600' }
|
||||
- { src: 'templates/nginx.conf', dest: '/etc/nginx/sites-enabled/lemmy.conf', mode: '0644' }
|
||||
- { src: '../docker/iframely.config.local.js', dest: '/lemmy/iframely.config.local.js', mode: '0600' }
|
||||
|
||||
- name: add config file (only during initial setup)
|
||||
template: src='templates/config.hjson' dest='/lemmy/{{domain}}/lemmy.hjson' mode='0600' force='no' owner='1000' group='1000'
|
||||
template: src='templates/config.hjson' dest='/lemmy/lemmy.hjson' mode='0600' force='no' owner='1000' group='1000'
|
||||
vars:
|
||||
# TODO: these paths are changed, need to move the files
|
||||
# TODO: not sure what to call the local var folder, its not mentioned in the ansible docs
|
||||
postgres_password: "{{ lookup('password', 'vars/{{ inventory_hostname }}/postgres_password chars=ascii_letters,digits') }}"
|
||||
jwt_password: "{{ lookup('password', 'vars/{{ inventory_hostname }}/jwt_password chars=ascii_letters,digits') }}"
|
||||
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: build the dev docker image
|
||||
local_action: shell cd .. && sudo docker build . -f docker/dev/Dockerfile -t lemmy:dev
|
||||
|
@ -115,7 +85,7 @@
|
|||
# be a problem for testing
|
||||
- name: start docker-compose
|
||||
docker_compose:
|
||||
project_src: "/lemmy/{{ domain }}/"
|
||||
project_src: /lemmy/
|
||||
state: present
|
||||
recreate: always
|
||||
ignore_errors: yes
|
||||
|
@ -126,6 +96,6 @@
|
|||
- name: certbot renewal cronjob
|
||||
cron:
|
||||
special_time=daily
|
||||
name=certbot-renew-lemmy-{{ domain }}
|
||||
name=certbot-renew-lemmy
|
||||
user=root
|
||||
job="certbot certonly --nginx -d '{{ domain }}' --deploy-hook 'nginx -s reload'"
|
||||
|
|
6
ansible/templates/docker-compose.yml
vendored
6
ansible/templates/docker-compose.yml
vendored
|
@ -4,7 +4,7 @@ services:
|
|||
lemmy:
|
||||
image: {{ lemmy_docker_image }}
|
||||
ports:
|
||||
- "127.0.0.1:{{ lemmy_port }}:8536"
|
||||
- "127.0.0.1:8536:8536"
|
||||
restart: always
|
||||
environment:
|
||||
- RUST_LOG=error
|
||||
|
@ -28,7 +28,7 @@ services:
|
|||
pictshare:
|
||||
image: shtripok/pictshare:latest
|
||||
ports:
|
||||
- "127.0.0.1:{{ pictshare_port }}:80"
|
||||
- "127.0.0.1:8537:80"
|
||||
volumes:
|
||||
- ./volumes/pictshare:/usr/share/nginx/html/data
|
||||
restart: always
|
||||
|
@ -36,7 +36,7 @@ services:
|
|||
iframely:
|
||||
image: dogbin/iframely:latest
|
||||
ports:
|
||||
- "127.0.0.1:{{ iframely_port }}:80"
|
||||
- "127.0.0.1:8061:80"
|
||||
volumes:
|
||||
- ./iframely.config.local.js:/iframely/config.local.js:ro
|
||||
restart: always
|
||||
|
|
14
ansible/templates/nginx.conf
vendored
14
ansible/templates/nginx.conf
vendored
|
@ -1,4 +1,4 @@
|
|||
proxy_cache_path /var/cache/lemmy/{{ domain }} levels=1:2 keys_zone=lemmy_frontend_cache_{{ domain }}:10m max_size=100m use_temp_path=off;
|
||||
proxy_cache_path /var/cache/lemmy_frontend levels=1:2 keys_zone=lemmy_frontend_cache:10m max_size=100m use_temp_path=off;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
@ -52,7 +52,7 @@ server {
|
|||
client_max_body_size 50M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://0.0.0.0:{{ lemmy_port }};
|
||||
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;
|
||||
|
@ -63,7 +63,7 @@ server {
|
|||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Proxy Cache
|
||||
proxy_cache lemmy_frontend_cache_{{ domain }};
|
||||
proxy_cache lemmy_frontend_cache;
|
||||
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
|
||||
proxy_cache_revalidate on;
|
||||
proxy_cache_lock on;
|
||||
|
@ -71,7 +71,7 @@ server {
|
|||
}
|
||||
|
||||
location /pictshare/ {
|
||||
proxy_pass http://0.0.0.0:{{ pictshare_port }}/;
|
||||
proxy_pass http://0.0.0.0:8537/;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
@ -82,7 +82,7 @@ server {
|
|||
}
|
||||
|
||||
location /iframely/ {
|
||||
proxy_pass http://0.0.0.0:{{ iframely_port }}/;
|
||||
proxy_pass http://0.0.0.0:8061/;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
@ -98,6 +98,6 @@ map $remote_addr $remote_addr_anon {
|
|||
::1 $remote_addr;
|
||||
default 0.0.0.0;
|
||||
}
|
||||
log_format main_{{ domain }} '$remote_addr_anon - $remote_user [$time_local] "$request" '
|
||||
log_format main '$remote_addr_anon - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" "$http_user_agent"';
|
||||
access_log /var/log/nginx/access.log main_{{ domain }};
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
|
16
ansible/uninstall.yml
vendored
16
ansible/uninstall.yml
vendored
|
@ -22,14 +22,24 @@
|
|||
|
||||
- name: stop docker-compose
|
||||
docker_compose:
|
||||
project_src: /lemmy/{{domain}}/
|
||||
project_src: /lemmy/
|
||||
state: absent
|
||||
|
||||
- name: delete data
|
||||
file: path={{item.path}} state=absent
|
||||
with_items:
|
||||
- { path: '/lemmy/{{domain}}/' }
|
||||
- { path: '/etc/nginx/sites-enabled/lemmy-{{ domain }}.conf' }
|
||||
- { path: '/lemmy/' }
|
||||
- { path: '/etc/nginx/sites-enabled/lemmy.conf' }
|
||||
|
||||
- name: Remove a volume
|
||||
docker_volume: name={{item.name}} state=absent
|
||||
with_items:
|
||||
- { name: 'lemmy_lemmy_db' }
|
||||
- { name: 'lemmy_lemmy_pictshare' }
|
||||
|
||||
- name: delete entire ecloud folder
|
||||
file: path='/mnt/repo-base/' state=absent
|
||||
when: delete_certs|bool
|
||||
|
||||
- name: remove certbot cronjob
|
||||
cron:
|
||||
|
|
11
docker/lemmy.hjson
vendored
11
docker/lemmy.hjson
vendored
|
@ -41,7 +41,16 @@
|
|||
# interval length for registration limit
|
||||
register_per_second: 3600
|
||||
}
|
||||
# # email sending configuration
|
||||
# # optional: parameters for automatic configuration of new instance (only used at first start)
|
||||
# setup: {
|
||||
# # username for the admin user
|
||||
# admin_username: "lemmy"
|
||||
# # password for the admin user
|
||||
# admin_password: "lemmy"
|
||||
# # name of the site (can be changed later)
|
||||
# site_name: "Lemmy Test"
|
||||
# }
|
||||
# # optional: email sending configuration
|
||||
# email: {
|
||||
# # hostname of the smtp server
|
||||
# smtp_server: ""
|
||||
|
|
1
docs/src/SUMMARY.md
vendored
1
docs/src/SUMMARY.md
vendored
|
@ -13,6 +13,7 @@
|
|||
- [Contributing](contributing.md)
|
||||
- [Docker Development](contributing_docker_development.md)
|
||||
- [Local Development](contributing_local_development.md)
|
||||
- [Federation Development](contributing_federation_development.md)
|
||||
- [Websocket/HTTP API](contributing_websocket_http_api.md)
|
||||
- [ActivityPub API Outline](contributing_apub_api_outline.md)
|
||||
- [Theming Guide](contributing_theming.md)
|
||||
|
|
1
docs/src/about_goals.md
vendored
1
docs/src/about_goals.md
vendored
|
@ -50,3 +50,4 @@
|
|||
- [Federation.md](https://github.com/dariusk/gathio/blob/7fc93dbe9d4d99457a0e85c6c532112f415b7af2/FEDERATION.md)
|
||||
- [Activitypub implementers guide](https://socialhub.activitypub.rocks/t/draft-guide-for-new-activitypub-implementers/479)
|
||||
- [Data storage questions](https://socialhub.activitypub.rocks/t/data-storage-questions/579/3)
|
||||
- [Activitypub as it has been understood](https://flak.tedunangst.com/post/ActivityPub-as-it-has-been-understood)
|
||||
|
|
9
docs/src/administration_install_ansible.md
vendored
9
docs/src/administration_install_ansible.md
vendored
|
@ -1,5 +1,7 @@
|
|||
# Ansible Installation
|
||||
|
||||
This is the same as the [Docker installation](administration_install_docker.md), except that Ansible handles all of it automatically. It also does some extra things like setting up TLS and email for your Lemmy instance.
|
||||
|
||||
First, you need to [install Ansible on your local computer](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (e.g. using `sudo apt install ansible`) or the equivalent for you platform.
|
||||
|
||||
Then run the following commands on your local computer:
|
||||
|
@ -11,3 +13,10 @@ cp inventory.example inventory
|
|||
nano inventory # enter your server, domain, contact email
|
||||
ansible-playbook lemmy.yml --become
|
||||
```
|
||||
|
||||
To update to a new version, just run the following in your local Lemmy repo:
|
||||
```bash
|
||||
git pull origin master
|
||||
cd ansible
|
||||
ansible-playbook lemmy.yml --become
|
||||
```
|
18
docs/src/administration_install_docker.md
vendored
18
docs/src/administration_install_docker.md
vendored
|
@ -1,29 +1,33 @@
|
|||
# Docker Installation
|
||||
|
||||
Make sure you have both docker and docker-compose(>=`1.24.0`) installed:
|
||||
Make sure you have both docker and docker-compose(>=`1.24.0`) installed. On Ubuntu, just run `apt install docker-compose docker.io`. Next,
|
||||
|
||||
```bash
|
||||
mkdir lemmy/
|
||||
cd lemmy/
|
||||
# create a folder for the lemmy files. the location doesnt matter, you can put this anywhere you want
|
||||
mkdir /lemmy
|
||||
cd /lemmy
|
||||
# download default config files
|
||||
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
|
||||
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/lemmy.hjson
|
||||
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/iframely.config.local.js
|
||||
# Edit lemmy.hjson, and docker-compose.yml to do more configuration (like adding a custom password)
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
and go to http://localhost:8536.
|
||||
After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname.
|
||||
|
||||
[A sample nginx config](/ansible/templates/nginx.conf) (Note: Avatar / Image uploading won't work without this), could be setup with:
|
||||
To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](/ansible/templates/nginx.conf), could be setup with:
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf
|
||||
# Replace the {{ vars }}
|
||||
sudo mv nginx.conf /etc/nginx/sites-enabled/lemmy.conf
|
||||
```
|
||||
|
||||
You will also need to setup TLS, for example with [Let's Encrypt](https://letsencrypt.org/). After this you need to restart Nginx to reload the config.
|
||||
|
||||
## Updating
|
||||
|
||||
To update to the newest version, run:
|
||||
To update to the newest version, you can manually change the version in `docker-compose.yml`. Alternatively, fetch the latest version from our git repo:
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
|
||||
|
|
37
docs/src/contributing_federation_development.md
vendored
Normal file
37
docs/src/contributing_federation_development.md
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Federation Development
|
||||
|
||||
## Setup
|
||||
|
||||
If you don't have a local clone of the Lemmy repo yet, just run the following command:
|
||||
|
||||
```bash
|
||||
git clone https://yerbamate.dev/nutomic/lemmy.git -b federation
|
||||
```
|
||||
|
||||
If you already have the Lemmy repo cloned, you need to add a new remote:
|
||||
```bash
|
||||
git remote add federation https://yerbamate.dev/nutomic/lemmy.git
|
||||
git checkout federation
|
||||
git pull federation federation
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
You need to have the following packages installed, the Docker service needs to be running.
|
||||
|
||||
- docker
|
||||
- docker-compose
|
||||
- cargo
|
||||
- yarn
|
||||
|
||||
Then run the following
|
||||
```bash
|
||||
cd dev/federation-test
|
||||
./run-federation-test.bash
|
||||
```
|
||||
|
||||
After the build is finished and the docker-compose setup is running, open [127.0.0.1:8540](http://127.0.0.1:8540) and
|
||||
[127.0.0.1:8541](http://127.0.0.1:8541) in your browser to use the test instances. You can login as admin with
|
||||
username `lemmy` and password `lemmy`, or create new accounts.
|
||||
|
||||
Please get in touch if you want to contribute to this, so we can coordinate things and avoid duplicate work.
|
253
server/Cargo.lock
generated
vendored
253
server/Cargo.lock
generated
vendored
|
@ -2,9 +2,9 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "activitystreams"
|
||||
version = "0.5.0-alpha.11"
|
||||
version = "0.5.0-alpha.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0fb876395ae7a1dd1c7d7de38f2cdb583918db16b46ee5b75d2e9bf7af1ef9f"
|
||||
checksum = "e7173513c9d586a1157f375835777e3b50498b6b7aab4411a7098b455ba995f0"
|
||||
dependencies = [
|
||||
"activitystreams-derive",
|
||||
"chrono",
|
||||
|
@ -17,9 +17,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "activitystreams-derive"
|
||||
version = "0.5.0-alpha.4"
|
||||
version = "0.5.0-alpha.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2bc640808dceb2efac81e6bcb77a7f4e2e76af7fb60e88f966b48123b625d2f"
|
||||
checksum = "c7ff4a2be3b67d763e78794f622ef2d53da077521229774837f61963c4067b36"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -46,7 +46,7 @@ dependencies = [
|
|||
"pin-project",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tokio-util 0.2.0",
|
||||
"trust-dns-proto",
|
||||
"trust-dns-resolver",
|
||||
]
|
||||
|
@ -63,7 +63,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"log",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tokio-util 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -378,6 +378,15 @@ dependencies = [
|
|||
"memchr 2.3.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.5"
|
||||
|
@ -401,9 +410,9 @@ checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.26"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21a03abb7c9b93ae229356151a083d26218c0358866a2a59d4280c856e9482e6"
|
||||
checksum = "bab5c215748dc1ad11a145359b1067107ae0f8ca5e99844fa64067ed5bf198e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -621,9 +630,9 @@ checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
|
|||
|
||||
[[package]]
|
||||
name = "bytestring"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc267467f58ef6cc8874064c62a0423eb0d099362c8a23edd1c6d044f46eead4"
|
||||
checksum = "fc7c05fa5172da78a62d9949d662d2ac89d4cc7355d7b49adee5163f1fb3f363"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
]
|
||||
|
@ -652,6 +661,21 @@ dependencies = [
|
|||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim 0.8.0",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
|
@ -661,6 +685,23 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "comrak"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17058cc536cf290563e88787d7b9e6030ce4742943017cc2ffb71f88034021c"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"entities",
|
||||
"lazy_static 1.4.0",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"regex 1.3.6",
|
||||
"twoway",
|
||||
"typed-arena",
|
||||
"unicode_categories",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.10.1"
|
||||
|
@ -999,6 +1040,12 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "entities"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
|
||||
|
||||
[[package]]
|
||||
name = "enum-as-inner"
|
||||
version = "0.3.2"
|
||||
|
@ -1238,9 +1285,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7938e6aa2a31df4e21f224dc84704bd31c089a6d1355c535b03667371cccc843"
|
||||
checksum = "377038bf3c89d18d6ca1431e7a5027194fbd724ca10592b9487ede5e8e144f42"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
|
@ -1252,7 +1299,7 @@ dependencies = [
|
|||
"log",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tokio-util 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1266,9 +1313,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.8"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||
checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -1483,6 +1530,7 @@ dependencies = [
|
|||
"actix-web-actors",
|
||||
"bcrypt",
|
||||
"chrono",
|
||||
"comrak",
|
||||
"config",
|
||||
"diesel",
|
||||
"diesel_migrations",
|
||||
|
@ -1625,6 +1673,12 @@ dependencies = [
|
|||
"linked-hash-map 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
|
||||
[[package]]
|
||||
name = "match_cfg"
|
||||
version = "0.1.0"
|
||||
|
@ -1931,6 +1985,49 @@ version = "2.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
dependencies = [
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
|
||||
dependencies = [
|
||||
"maplit",
|
||||
"pest",
|
||||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.8"
|
||||
|
@ -1986,9 +2083,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.14"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420"
|
||||
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
|
@ -1998,9 +2095,9 @@ checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
||||
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
@ -2363,21 +2460,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97bbedbe81904398b6ebb054b3e912f99d55807125790f3198ac990d98def5b0"
|
||||
checksum = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06fd2f23e31ef68dd2328cc383bd493142e46107a3a0e24f7d734e3f3b80fe4c"
|
||||
checksum = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
|
@ -2495,6 +2593,18 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.6.0"
|
||||
|
@ -2560,9 +2670,9 @@ checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.11"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"
|
||||
checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
@ -2588,6 +2698,12 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.9.3"
|
||||
|
@ -2659,19 +2775,28 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.13"
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3711fd1c4e75b3eff12ba5c40dba762b6b65c5476e8174c1a664772060c49bf"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0570dc61221295909abdb95c739f2e74325e14293b2026b0a7e195091ec54ae"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.13"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae2b85ba4c9aa32dd3343bd80eb8d22e9b54b7688c17ea3907f236885353b233"
|
||||
checksum = "227362df41d566be41a28f64401e07a043157c21c14b9785a0d8e256f940a8fd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2728,9 +2853,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.2.13"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa5e81d6bc4e67fe889d5783bd2a128ab2e0cfa487e0be16b6a8d177b101616"
|
||||
checksum = "619cdb2245c40c42d563089b72e80c5df659513d667a017598439ef7a7b1ffe1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
|
@ -2761,6 +2886,20 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
|
@ -2809,12 +2948,40 @@ dependencies = [
|
|||
"trust-dns-proto",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "twoway"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
|
||||
dependencies = [
|
||||
"memchr 2.3.3",
|
||||
"unchecked-index",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
|
||||
[[package]]
|
||||
name = "unchecked-index"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
|
@ -2848,12 +3015,24 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_categories"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.0"
|
||||
|
@ -2923,6 +3102,12 @@ version = "0.2.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
|
@ -3041,9 +3226,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
|
||||
checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
|
3
server/Cargo.toml
vendored
3
server/Cargo.toml
vendored
|
@ -8,7 +8,7 @@ edition = "2018"
|
|||
diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2", "64-column-tables"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
dotenv = "0.15.0"
|
||||
activitystreams = "0.5.0-alpha.10"
|
||||
activitystreams = "0.5.0-alpha.16"
|
||||
bcrypt = "0.6.2"
|
||||
chrono = { version = "0.4.7", features = ["serde"] }
|
||||
failure = "0.1.5"
|
||||
|
@ -37,3 +37,4 @@ hjson = "0.8.2"
|
|||
url = "2.1.1"
|
||||
percent-encoding = "2.1.0"
|
||||
isahc = "0.9"
|
||||
comrak = "0.7"
|
||||
|
|
11
server/config/defaults.hjson
vendored
11
server/config/defaults.hjson
vendored
|
@ -1,4 +1,15 @@
|
|||
{
|
||||
# # optional: parameters for automatic configuration of new instance (only used at first start)
|
||||
# setup: {
|
||||
# # username for the admin user
|
||||
# admin_username: ""
|
||||
# # password for the admin user
|
||||
# admin_password: ""
|
||||
# # optional: email for the admin user (can be omitted and set later through the website)
|
||||
# admin_email: ""
|
||||
# # name of the site (can be changed later)
|
||||
# site_name: ""
|
||||
# }
|
||||
# settings related to the postgresql database
|
||||
database: {
|
||||
# username to connect to postgres
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use super::*;
|
||||
use crate::api::user::Register;
|
||||
use crate::api::{Oper, Perform};
|
||||
use crate::settings::Settings;
|
||||
use diesel::PgConnection;
|
||||
use log::info;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -53,12 +57,12 @@ pub struct GetModlogResponse {
|
|||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CreateSite {
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
enable_downvotes: bool,
|
||||
open_registration: bool,
|
||||
enable_nsfw: bool,
|
||||
auth: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub enable_downvotes: bool,
|
||||
pub open_registration: bool,
|
||||
pub enable_nsfw: bool,
|
||||
pub auth: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -277,10 +281,34 @@ impl Perform<GetSiteResponse> for Oper<GetSite> {
|
|||
fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> {
|
||||
let _data: &GetSite = &self.data;
|
||||
|
||||
// It can return a null site in order to redirect
|
||||
let site_view = match Site::read(&conn, 1) {
|
||||
Ok(_site) => Some(SiteView::read(&conn)?),
|
||||
Err(_e) => None,
|
||||
let site = Site::read(&conn, 1);
|
||||
let site_view = if site.is_ok() {
|
||||
Some(SiteView::read(&conn)?)
|
||||
} else if let Some(setup) = Settings::get().setup.as_ref() {
|
||||
let register = Register {
|
||||
username: setup.admin_username.to_owned(),
|
||||
email: setup.admin_email.to_owned(),
|
||||
password: setup.admin_password.to_owned(),
|
||||
password_verify: setup.admin_password.to_owned(),
|
||||
admin: true,
|
||||
show_nsfw: true,
|
||||
};
|
||||
let login_response = Oper::new(register).perform(&conn)?;
|
||||
info!("Admin {} created", setup.admin_username);
|
||||
|
||||
let create_site = CreateSite {
|
||||
name: setup.site_name.to_owned(),
|
||||
description: None,
|
||||
enable_downvotes: false,
|
||||
open_registration: false,
|
||||
enable_nsfw: false,
|
||||
auth: login_response.jwt,
|
||||
};
|
||||
Oper::new(create_site).perform(&conn)?;
|
||||
info!("Site {} created", setup.site_name);
|
||||
Some(SiteView::read(&conn)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut admins = UserView::admins(&conn)?;
|
||||
|
|
|
@ -14,12 +14,12 @@ pub struct Login {
|
|||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Register {
|
||||
username: String,
|
||||
email: Option<String>,
|
||||
password: String,
|
||||
password_verify: String,
|
||||
admin: bool,
|
||||
show_nsfw: bool,
|
||||
pub username: String,
|
||||
pub email: Option<String>,
|
||||
pub password: String,
|
||||
pub password_verify: String,
|
||||
pub admin: bool,
|
||||
pub show_nsfw: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -42,7 +42,7 @@ pub struct SaveUserSettings {
|
|||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LoginResponse {
|
||||
jwt: String,
|
||||
pub jwt: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
|
|
@ -107,7 +107,7 @@ pub async fn get_apub_community_outbox(
|
|||
.set_id(base_url)?;
|
||||
collection
|
||||
.collection_props
|
||||
.set_many_items_object_boxs(
|
||||
.set_many_items_base_boxes(
|
||||
community_posts
|
||||
.iter()
|
||||
.map(|c| c.as_page().unwrap())
|
||||
|
|
|
@ -9,8 +9,8 @@ use crate::settings::Settings;
|
|||
use activitystreams::actor::{properties::ApActorProperties, Group};
|
||||
use activitystreams::collection::{OrderedCollection, UnorderedCollection};
|
||||
use activitystreams::ext::Ext;
|
||||
use activitystreams::object::ObjectBox;
|
||||
use activitystreams::object::Page;
|
||||
use activitystreams::BaseBox;
|
||||
use failure::Error;
|
||||
use isahc::prelude::*;
|
||||
use log::warn;
|
||||
|
@ -75,11 +75,11 @@ pub fn get_remote_community_posts(identifier: &str) -> Result<GetPostsResponse,
|
|||
fetch_remote_object::<Ext<Group, ApActorProperties>>(&get_remote_community_uri(identifier))?;
|
||||
let outbox_uri = &community.extension.get_outbox().to_string();
|
||||
let outbox = fetch_remote_object::<OrderedCollection>(outbox_uri)?;
|
||||
let items = outbox.collection_props.get_many_items_object_boxs();
|
||||
let items = outbox.collection_props.get_many_items_base_boxes();
|
||||
|
||||
let posts: Vec<PostView> = items
|
||||
.unwrap()
|
||||
.map(|obox: &ObjectBox| {
|
||||
.map(|obox: &BaseBox| {
|
||||
let page: Page = obox.clone().to_concrete::<Page>().unwrap();
|
||||
PostView {
|
||||
id: -1,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
extern crate lazy_static;
|
||||
use crate::settings::Settings;
|
||||
use diesel::dsl::*;
|
||||
use diesel::result::Error;
|
||||
|
|
|
@ -11,6 +11,7 @@ pub extern crate actix;
|
|||
pub extern crate actix_web;
|
||||
pub extern crate bcrypt;
|
||||
pub extern crate chrono;
|
||||
pub extern crate comrak;
|
||||
pub extern crate dotenv;
|
||||
pub extern crate jsonwebtoken;
|
||||
pub extern crate lettre;
|
||||
|
@ -18,6 +19,7 @@ pub extern crate lettre_email;
|
|||
extern crate log;
|
||||
pub extern crate rand;
|
||||
pub extern crate regex;
|
||||
pub extern crate rss;
|
||||
pub extern crate serde;
|
||||
pub extern crate serde_json;
|
||||
pub extern crate sha2;
|
||||
|
@ -220,6 +222,10 @@ fn fetch_iframely_and_pictshare_data(
|
|||
)
|
||||
}
|
||||
|
||||
pub fn markdown_to_html(text: &str) -> String {
|
||||
comrak::markdown_to_html(text, &comrak::ComrakOptions::default())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{extract_usernames, is_email_regex, remove_slurs, slur_check, slurs_vec_to_str};
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
extern crate rss;
|
||||
|
||||
use super::*;
|
||||
use crate::db::comment_view::{ReplyQueryBuilder, ReplyView};
|
||||
use crate::db::community::Community;
|
||||
|
@ -8,9 +6,9 @@ use crate::db::site_view::SiteView;
|
|||
use crate::db::user::{Claims, User_};
|
||||
use crate::db::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
|
||||
use crate::db::{ListingType, SortType};
|
||||
use crate::Settings;
|
||||
use crate::{markdown_to_html, Settings};
|
||||
use actix_web::{web, HttpResponse, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use diesel::r2d2::{ConnectionManager, Pool};
|
||||
use diesel::PgConnection;
|
||||
use failure::Error;
|
||||
|
@ -34,7 +32,6 @@ enum RequestType {
|
|||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg
|
||||
.route("/feeds/{type}/{name}.xml", web::get().to(feeds::get_feed))
|
||||
.route("/feeds/all.xml", web::get().to(feeds::get_all_feed))
|
||||
.route("/feeds/all.xml", web::get().to(feeds::get_all_feed));
|
||||
}
|
||||
|
||||
|
@ -44,9 +41,7 @@ async fn get_all_feed(
|
|||
) -> Result<HttpResponse, actix_web::Error> {
|
||||
let res = web::block(move || {
|
||||
let conn = db.get()?;
|
||||
|
||||
let sort_type = get_sort_type(info)?;
|
||||
get_feed_all_data(&conn, &sort_type)
|
||||
get_feed_all_data(&conn, &get_sort_type(info)?)
|
||||
})
|
||||
.await
|
||||
.map(|rss| {
|
||||
|
@ -58,6 +53,29 @@ async fn get_all_feed(
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> {
|
||||
let site_view = SiteView::read(&conn)?;
|
||||
|
||||
let posts = PostQueryBuilder::create(&conn)
|
||||
.listing_type(ListingType::All)
|
||||
.sort(sort_type)
|
||||
.list()?;
|
||||
|
||||
let items = create_post_items(posts);
|
||||
|
||||
let mut channel_builder = ChannelBuilder::default();
|
||||
channel_builder
|
||||
.title(&format!("{} - All", site_view.name))
|
||||
.link(format!("https://{}", Settings::get().hostname))
|
||||
.items(items);
|
||||
|
||||
if let Some(site_desc) = site_view.description {
|
||||
channel_builder.description(&site_desc);
|
||||
}
|
||||
|
||||
Ok(channel_builder.build().unwrap().to_string())
|
||||
}
|
||||
|
||||
async fn get_feed(
|
||||
path: web::Path<(String, String)>,
|
||||
info: web::Query<Params>,
|
||||
|
@ -86,6 +104,7 @@ async fn get_feed(
|
|||
}
|
||||
})
|
||||
.await
|
||||
.map(|builder| builder.build().unwrap().to_string())
|
||||
.map(|rss| {
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/rss+xml")
|
||||
|
@ -103,34 +122,11 @@ fn get_sort_type(info: web::Query<Params>) -> Result<SortType, ParseError> {
|
|||
SortType::from_str(&sort_query)
|
||||
}
|
||||
|
||||
fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> {
|
||||
let site_view = SiteView::read(&conn)?;
|
||||
|
||||
let posts = PostQueryBuilder::create(&conn)
|
||||
.listing_type(ListingType::All)
|
||||
.sort(sort_type)
|
||||
.list()?;
|
||||
|
||||
let items = create_post_items(posts);
|
||||
|
||||
let mut channel_builder = ChannelBuilder::default();
|
||||
channel_builder
|
||||
.title(&format!("{} - All", site_view.name))
|
||||
.link(format!("https://{}", Settings::get().hostname))
|
||||
.items(items);
|
||||
|
||||
if let Some(site_desc) = site_view.description {
|
||||
channel_builder.description(&site_desc);
|
||||
}
|
||||
|
||||
Ok(channel_builder.build().unwrap().to_string())
|
||||
}
|
||||
|
||||
fn get_feed_user(
|
||||
conn: &PgConnection,
|
||||
sort_type: &SortType,
|
||||
user_name: String,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<ChannelBuilder, Error> {
|
||||
let site_view = SiteView::read(&conn)?;
|
||||
let user = User_::find_by_username(&conn, &user_name)?;
|
||||
let user_url = user.get_profile_url();
|
||||
|
@ -149,14 +145,14 @@ fn get_feed_user(
|
|||
.link(user_url)
|
||||
.items(items);
|
||||
|
||||
Ok(channel_builder.build().unwrap().to_string())
|
||||
Ok(channel_builder)
|
||||
}
|
||||
|
||||
fn get_feed_community(
|
||||
conn: &PgConnection,
|
||||
sort_type: &SortType,
|
||||
community_name: String,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<ChannelBuilder, Error> {
|
||||
let site_view = SiteView::read(&conn)?;
|
||||
let community = Community::read_from_name(&conn, community_name)?;
|
||||
let community_url = community.get_url();
|
||||
|
@ -179,10 +175,14 @@ fn get_feed_community(
|
|||
channel_builder.description(&community_desc);
|
||||
}
|
||||
|
||||
Ok(channel_builder.build().unwrap().to_string())
|
||||
Ok(channel_builder)
|
||||
}
|
||||
|
||||
fn get_feed_front(conn: &PgConnection, sort_type: &SortType, jwt: String) -> Result<String, Error> {
|
||||
fn get_feed_front(
|
||||
conn: &PgConnection,
|
||||
sort_type: &SortType,
|
||||
jwt: String,
|
||||
) -> Result<ChannelBuilder, Error> {
|
||||
let site_view = SiteView::read(&conn)?;
|
||||
let user_id = Claims::decode(&jwt)?.claims.id;
|
||||
|
||||
|
@ -204,10 +204,10 @@ fn get_feed_front(conn: &PgConnection, sort_type: &SortType, jwt: String) -> Res
|
|||
channel_builder.description(&site_desc);
|
||||
}
|
||||
|
||||
Ok(channel_builder.build().unwrap().to_string())
|
||||
Ok(channel_builder)
|
||||
}
|
||||
|
||||
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<String, Error> {
|
||||
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Error> {
|
||||
let site_view = SiteView::read(&conn)?;
|
||||
let user_id = Claims::decode(&jwt)?.claims.id;
|
||||
|
||||
|
@ -233,86 +233,61 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<String, Error> {
|
|||
channel_builder.description(&site_desc);
|
||||
}
|
||||
|
||||
Ok(channel_builder.build().unwrap().to_string())
|
||||
Ok(channel_builder)
|
||||
}
|
||||
|
||||
fn create_reply_and_mention_items(
|
||||
replies: Vec<ReplyView>,
|
||||
mentions: Vec<UserMentionView>,
|
||||
) -> Vec<Item> {
|
||||
let mut items: Vec<Item> = Vec::new();
|
||||
let mut reply_items: Vec<Item> = replies
|
||||
.iter()
|
||||
.map(|r| {
|
||||
let reply_url = format!(
|
||||
"https://{}/post/{}/comment/{}",
|
||||
Settings::get().hostname,
|
||||
r.post_id,
|
||||
r.id
|
||||
);
|
||||
build_item(&r.creator_name, &r.published, &reply_url, &r.content)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for r in replies {
|
||||
let mut i = ItemBuilder::default();
|
||||
let mut mention_items: Vec<Item> = mentions
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let mention_url = format!(
|
||||
"https://{}/post/{}/comment/{}",
|
||||
Settings::get().hostname,
|
||||
m.post_id,
|
||||
m.id
|
||||
);
|
||||
build_item(&m.creator_name, &m.published, &mention_url, &m.content)
|
||||
})
|
||||
.collect();
|
||||
|
||||
i.title(format!("Reply from {}", r.creator_name));
|
||||
reply_items.append(&mut mention_items);
|
||||
reply_items
|
||||
}
|
||||
|
||||
let author_url = format!("https://{}/u/{}", Settings::get().hostname, r.creator_name);
|
||||
i.author(format!(
|
||||
"/u/{} <a href=\"{}\">(link)</a>",
|
||||
r.creator_name, author_url
|
||||
));
|
||||
|
||||
let dt = DateTime::<Utc>::from_utc(r.published, Utc);
|
||||
i.pub_date(dt.to_rfc2822());
|
||||
|
||||
let reply_url = format!(
|
||||
"https://{}/post/{}/comment/{}",
|
||||
Settings::get().hostname,
|
||||
r.post_id,
|
||||
r.id
|
||||
);
|
||||
i.comments(reply_url.to_owned());
|
||||
let guid = GuidBuilder::default()
|
||||
.permalink(true)
|
||||
.value(&reply_url)
|
||||
.build();
|
||||
i.guid(guid.unwrap());
|
||||
|
||||
i.link(reply_url);
|
||||
|
||||
// TODO find a markdown to html parser here, do images, etc
|
||||
i.description(r.content);
|
||||
|
||||
items.push(i.build().unwrap());
|
||||
}
|
||||
|
||||
for m in mentions {
|
||||
let mut i = ItemBuilder::default();
|
||||
|
||||
i.title(format!("Mention from {}", m.creator_name));
|
||||
|
||||
let author_url = format!("https://{}/u/{}", Settings::get().hostname, m.creator_name);
|
||||
i.author(format!(
|
||||
"/u/{} <a href=\"{}\">(link)</a>",
|
||||
m.creator_name, author_url
|
||||
));
|
||||
|
||||
let dt = DateTime::<Utc>::from_utc(m.published, Utc);
|
||||
i.pub_date(dt.to_rfc2822());
|
||||
|
||||
let mention_url = format!(
|
||||
"https://{}/post/{}/comment/{}",
|
||||
Settings::get().hostname,
|
||||
m.post_id,
|
||||
m.id
|
||||
);
|
||||
i.comments(mention_url.to_owned());
|
||||
let guid = GuidBuilder::default()
|
||||
.permalink(true)
|
||||
.value(&mention_url)
|
||||
.build();
|
||||
i.guid(guid.unwrap());
|
||||
|
||||
i.link(mention_url);
|
||||
|
||||
// TODO find a markdown to html parser here, do images, etc
|
||||
i.description(m.content);
|
||||
|
||||
items.push(i.build().unwrap());
|
||||
}
|
||||
|
||||
items
|
||||
fn build_item(creator_name: &str, published: &NaiveDateTime, url: &str, content: &str) -> Item {
|
||||
let mut i = ItemBuilder::default();
|
||||
i.title(format!("Reply from {}", creator_name));
|
||||
let author_url = format!("https://{}/u/{}", Settings::get().hostname, creator_name);
|
||||
i.author(format!(
|
||||
"/u/{} <a href=\"{}\">(link)</a>",
|
||||
creator_name, author_url
|
||||
));
|
||||
let dt = DateTime::<Utc>::from_utc(*published, Utc);
|
||||
i.pub_date(dt.to_rfc2822());
|
||||
i.comments(url.to_owned());
|
||||
let guid = GuidBuilder::default().permalink(true).value(url).build();
|
||||
i.guid(guid.unwrap());
|
||||
i.link(url.to_owned());
|
||||
// TODO add images
|
||||
let html = markdown_to_html(&content.to_string());
|
||||
i.description(html);
|
||||
i.build().unwrap()
|
||||
}
|
||||
|
||||
fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
|
||||
|
@ -359,9 +334,8 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
|
|||
i.link(url);
|
||||
}
|
||||
|
||||
// TODO find a markdown to html parser here, do images, etc
|
||||
let mut description = format!("
|
||||
submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
|
||||
// TODO add images
|
||||
let mut description = format!("submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
|
||||
author_url,
|
||||
p.creator_name,
|
||||
community_url,
|
||||
|
@ -371,7 +345,8 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
|
|||
p.number_of_comments);
|
||||
|
||||
if let Some(body) = p.body {
|
||||
description.push_str(&format!("<br><br>{}", body));
|
||||
let html = markdown_to_html(&body);
|
||||
description.push_str(&html);
|
||||
}
|
||||
|
||||
i.description(description);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
extern crate lazy_static;
|
||||
use crate::apub::get_apub_protocol_string;
|
||||
use crate::db::site_view::SiteView;
|
||||
use crate::version;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
extern crate lazy_static;
|
||||
use config::{Config, ConfigError, Environment, File};
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
|
@ -9,6 +8,7 @@ static CONFIG_FILE: &str = "config/config.hjson";
|
|||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Settings {
|
||||
pub setup: Option<Setup>,
|
||||
pub database: Database,
|
||||
pub hostname: String,
|
||||
pub bind: IpAddr,
|
||||
|
@ -20,6 +20,14 @@ pub struct Settings {
|
|||
pub federation: Federation,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Setup {
|
||||
pub admin_username: String,
|
||||
pub admin_password: String,
|
||||
pub admin_email: Option<String>,
|
||||
pub site_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RateLimitConfig {
|
||||
pub message: i32,
|
||||
|
|
5
ui/src/components/navbar.tsx
vendored
5
ui/src/components/navbar.tsx
vendored
|
@ -375,12 +375,13 @@ export class Navbar extends Component<any, NavbarState> {
|
|||
let link = isCommentType(reply)
|
||||
? `/post/${reply.post_id}/comment/${reply.id}`
|
||||
: `/inbox`;
|
||||
let body = md.render(reply.content);
|
||||
let htmlBody = md.render(reply.content);
|
||||
let body = reply.content; // Unfortunately the notifications API can't do html
|
||||
|
||||
messageToastify(
|
||||
creator_name,
|
||||
creator_avatar,
|
||||
body,
|
||||
htmlBody,
|
||||
link,
|
||||
this.context.router
|
||||
);
|
||||
|
|
8
ui/src/components/post-listing.tsx
vendored
8
ui/src/components/post-listing.tsx
vendored
|
@ -250,14 +250,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
<div class="row">
|
||||
<div className={`vote-bar col-1 pr-0 small text-center`}>
|
||||
<button
|
||||
className={`btn-animate btn btn-link btn-lg p-0 ${
|
||||
className={`btn-animate btn btn-link p-0 ${
|
||||
this.state.my_vote == 1 ? 'text-info' : 'text-muted'
|
||||
}`}
|
||||
onClick={linkEvent(this, this.handlePostLike)}
|
||||
data-tippy-content={i18n.t('upvote')}
|
||||
>
|
||||
<svg class="icon upvote">
|
||||
<use xlinkHref="#icon-arrow-up"></use>
|
||||
<use xlinkHref="#icon-arrow-up1"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
|
@ -268,14 +268,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
</div>
|
||||
{WebSocketService.Instance.site.enable_downvotes && (
|
||||
<button
|
||||
className={`btn-animate btn btn-link btn-lg p-0 ${
|
||||
className={`btn-animate btn btn-link p-0 ${
|
||||
this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
|
||||
}`}
|
||||
onClick={linkEvent(this, this.handlePostDisLike)}
|
||||
data-tippy-content={i18n.t('downvote')}
|
||||
>
|
||||
<svg class="icon downvote">
|
||||
<use xlinkHref="#icon-arrow-down"></use>
|
||||
<use xlinkHref="#icon-arrow-down1"></use>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
|
|
6
ui/src/components/symbols.tsx
vendored
6
ui/src/components/symbols.tsx
vendored
|
@ -97,6 +97,12 @@ export class Symbols extends Component<any, any> {
|
|||
<symbol id="icon-arrow-up" viewBox="0 0 24 24">
|
||||
<path d="M5.707 12.707l5.293-5.293v11.586c0 0.552 0.448 1 1 1s1-0.448 1-1v-11.586l5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-7-7c-0.092-0.092-0.202-0.166-0.324-0.217s-0.253-0.076-0.383-0.076c-0.256 0-0.512 0.098-0.707 0.293l-7 7c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-arrow-up1" viewBox="0 0 26 28">
|
||||
<path d="M25.172 15.172c0 0.531-0.219 1.031-0.578 1.406l-1.172 1.172c-0.375 0.375-0.891 0.594-1.422 0.594s-1.047-0.219-1.406-0.594l-4.594-4.578v11c0 1.125-0.938 1.828-2 1.828h-2c-1.062 0-2-0.703-2-1.828v-11l-4.594 4.578c-0.359 0.375-0.875 0.594-1.406 0.594s-1.047-0.219-1.406-0.594l-1.172-1.172c-0.375-0.375-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l10.172-10.172c0.359-0.375 0.875-0.578 1.406-0.578s1.047 0.203 1.422 0.578l10.172 10.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-arrow-down1" viewBox="0 0 26 28">
|
||||
<path d="M25.172 13c0 0.531-0.219 1.047-0.578 1.406l-10.172 10.187c-0.375 0.359-0.891 0.578-1.422 0.578s-1.047-0.219-1.406-0.578l-10.172-10.187c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l1.156-1.172c0.375-0.359 0.891-0.578 1.422-0.578s1.047 0.219 1.406 0.578l4.594 4.594v-11c0-1.094 0.906-2 2-2h2c1.094 0 2 0.906 2 2v11l4.594-4.594c0.359-0.359 0.875-0.578 1.406-0.578s1.047 0.219 1.422 0.578l1.172 1.172c0.359 0.375 0.578 0.891 0.578 1.422z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-mail" viewBox="0 0 24 24">
|
||||
<path d="M3 7.921l8.427 5.899c0.34 0.235 0.795 0.246 1.147 0l8.426-5.899v10.079c0 0.272-0.11 0.521-0.295 0.705s-0.433 0.295-0.705 0.295h-16c-0.272 0-0.521-0.11-0.705-0.295s-0.295-0.433-0.295-0.705zM1 5.983c0 0.010 0 0.020 0 0.030v11.987c0 0.828 0.34 1.579 0.88 2.12s1.292 0.88 2.12 0.88h16c0.828 0 1.579-0.34 2.12-0.88s0.88-1.292 0.88-2.12v-11.988c0-0.010 0-0.020 0-0.030-0.005-0.821-0.343-1.565-0.88-2.102-0.541-0.54-1.292-0.88-2.12-0.88h-16c-0.828 0-1.579 0.34-2.12 0.88-0.537 0.537-0.875 1.281-0.88 2.103zM20.894 5.554l-8.894 6.225-8.894-6.225c0.048-0.096 0.112-0.183 0.188-0.259 0.185-0.185 0.434-0.295 0.706-0.295h16c0.272 0 0.521 0.11 0.705 0.295 0.076 0.076 0.14 0.164 0.188 0.259z"></path>
|
||||
</symbol>
|
||||
|
|
4
ui/src/utils.ts
vendored
4
ui/src/utils.ts
vendored
|
@ -12,6 +12,7 @@ import 'moment/locale/ca';
|
|||
import 'moment/locale/fa';
|
||||
import 'moment/locale/pt-br';
|
||||
import 'moment/locale/ja';
|
||||
import 'moment/locale/ka';
|
||||
|
||||
import {
|
||||
UserOperation,
|
||||
|
@ -59,6 +60,7 @@ export const languages = [
|
|||
{ code: 'eo', name: 'Esperanto' },
|
||||
{ code: 'es', name: 'Español' },
|
||||
{ code: 'de', name: 'Deutsch' },
|
||||
{ code: 'ka', name: 'ქართული ენა' },
|
||||
{ code: 'fa', name: 'فارسی' },
|
||||
{ code: 'ja', name: '日本語' },
|
||||
{ code: 'pt_BR', name: 'Português Brasileiro' },
|
||||
|
@ -353,6 +355,8 @@ export function getMomentLanguage(): string {
|
|||
lang = 'pt-br';
|
||||
} else if (lang.startsWith('ja')) {
|
||||
lang = 'ja';
|
||||
} else if (lang.startsWith('ka')) {
|
||||
lang = 'ka';
|
||||
} else {
|
||||
lang = 'en';
|
||||
}
|
||||
|
|
2
ui/translations/ka.json
vendored
Normal file
2
ui/translations/ka.json
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
256
ui/translations/pl.json
vendored
256
ui/translations/pl.json
vendored
|
@ -1,3 +1,257 @@
|
|||
{
|
||||
"remove_post": "Usuń Post",
|
||||
"no_posts": "Brak Postów.",
|
||||
"create_a_post": "Stwórz post",
|
||||
"create_post": "Stwórz Post",
|
||||
"number_of_posts_0": "Post",
|
||||
"number_of_posts_1": "Posty/ów",
|
||||
"number_of_posts_2": "Posty/ów",
|
||||
"posts": "Posty",
|
||||
"related_posts": "Te posty mogą być powiązane",
|
||||
"cross_posts": "Ten link został też zapostowany na:",
|
||||
"comments": "Komentarze",
|
||||
"number_of_comments_0": "Komentarz",
|
||||
"number_of_comments_1": "Komentarzy/e",
|
||||
"number_of_comments_2": "Komentarzy/e",
|
||||
"post": "post",
|
||||
"cross_post": "post zewnętrzny",
|
||||
"cross_posted_to": "post wrzucony na zewnątrz: ",
|
||||
"remove_comment": "Usuń Komentarz",
|
||||
"communities": "Społeczności",
|
||||
"users": "Użytkownicy",
|
||||
"create_a_community": "Stwórz społeczność",
|
||||
"create_community": "Stwórz Społeczność",
|
||||
"remove_community": "Usuń Społeczność",
|
||||
"subscribed_to_communities": "Subskrybowane <1>społeczności</1>",
|
||||
"trending_communities": "Popularne <1>społeczności</1>",
|
||||
"list_of_communities": "Lista społeczności",
|
||||
"community_reqs": "małe litery, podkreślniki, bez spacji.",
|
||||
"create_private_message": "Stwórz Prywatną Wiadomość",
|
||||
"send_secure_message": "Wyślij Bezpieczną Wiadomość",
|
||||
"send_message": "Wyślij Wiadomość",
|
||||
"message": "Wiadomość",
|
||||
"edit": "edytuj",
|
||||
"reply": "odpowiedz",
|
||||
"more": "więcej",
|
||||
"cancel": "Anuluj",
|
||||
"preview": "Podgląd",
|
||||
"upload_image": "prześlij obraz",
|
||||
"avatar": "Awatar",
|
||||
"upload_avatar": "Prześlij Awatar",
|
||||
"show_avatars": "Pokaż Awatary",
|
||||
"formatting_help": "poradnik formatowania",
|
||||
"lock": "zablokuj",
|
||||
"messages": "Wiadomości",
|
||||
"yes": "tak",
|
||||
"number_of_communities_0": "Społeczność",
|
||||
"number_of_communities_1": "Społeczności",
|
||||
"number_of_communities_2": "Społeczności",
|
||||
"sorting_help": "poradnik sortowania",
|
||||
"view_source": "pokaż źródło",
|
||||
"unlock": "odblokuj",
|
||||
"sticky": "przyklej",
|
||||
"unsticky": "odklej",
|
||||
"link": "link",
|
||||
"archive_link": "link archiwalny",
|
||||
"mod": "moderator",
|
||||
"mods": "moderatorzy",
|
||||
"moderates": "Moderuje",
|
||||
"settings": "Ustawienia",
|
||||
"remove_as_mod": "zabierz uprawnienia moderatora",
|
||||
"appoint_as_mod": "przyznaj uprawnienia moderatora",
|
||||
"modlog": "Log moderatorski",
|
||||
"admin": "administrator",
|
||||
"admins": "administratorzy",
|
||||
"remove_as_admin": "wycofaj uprawnienia administratora",
|
||||
"appoint_as_admin": "przyznaj uprawnienia administratora",
|
||||
"remove": "usuń",
|
||||
"removed": "usunięte",
|
||||
"locked": "zablokowane",
|
||||
"stickied": "przyklejone",
|
||||
"reason": "Powód",
|
||||
"mark_as_read": "zaznacz jako przeczytane",
|
||||
"mark_as_unread": "zaznacz jako nieprzeczytane",
|
||||
"delete": "usuń",
|
||||
"deleted": "usunięte",
|
||||
"delete_account": "Usuń Konto",
|
||||
"delete_account_confirm": "Ostrzeżenie: twoje dane zostaną bezpowrotnie usunięte. Wpisz swoje hasło aby potwierdzić.",
|
||||
"restore": "przywróć",
|
||||
"ban": "zbanuj",
|
||||
"ban_from_site": "zbanuj ze strony",
|
||||
"unban": "odbanuj",
|
||||
"unban_from_site": "odbanuj ze strony",
|
||||
"banned": "zbanowano",
|
||||
"save": "zapisz",
|
||||
"unsave": "cofnij zapis",
|
||||
"create": "stwórz",
|
||||
"creator": "autor",
|
||||
"username": "Nazwa użytkownika",
|
||||
"email_or_username": "Email lub Nazwa Użytkownika",
|
||||
"number_of_users_0": "Użytkownik",
|
||||
"number_of_users_1": "Użytkownicy/ków",
|
||||
"number_of_users_2": "Użytkownicy/ków",
|
||||
"number_of_subscribers_0": "Subskrybent",
|
||||
"number_of_subscribers_1": "Subskrybenci/tów",
|
||||
"number_of_subscribers_2": "Subskrybenci/tów",
|
||||
"number_of_points_0": "Punkt",
|
||||
"number_of_points_1": "Punkty/ów",
|
||||
"number_of_points_2": "Punkty/ów",
|
||||
"number_online_0": "Użytkownik Online",
|
||||
"number_online_1": "Użytkowników Online",
|
||||
"number_online_2": "Użytkowników Online",
|
||||
"name": "Nazwa",
|
||||
"title": "Tytuł",
|
||||
"category": "Kategoria",
|
||||
"subscribers": "Subskrybenci",
|
||||
"both": "Obydwa",
|
||||
"saved": "Zapisane",
|
||||
"unsubscribe": "Odsubskrybuj",
|
||||
"subscribe": "Subskrybuj",
|
||||
"subscribed": "Zasubskrybowane",
|
||||
"prev": "Wstecz",
|
||||
"next": "Dalej",
|
||||
"sidebar": "Pasek boczny",
|
||||
"sort_type": "Sortuj typ",
|
||||
"hot": "Popularne",
|
||||
"new": "Nowe",
|
||||
"old": "Stare",
|
||||
"top_day": "Popularne dzisiaj",
|
||||
"week": "Tydzień",
|
||||
"month": "Miesiąc",
|
||||
"year": "Rok",
|
||||
"all": "Wszystko",
|
||||
"top": "Popularne",
|
||||
"api": "API",
|
||||
"docs": "Dokumentacja",
|
||||
"inbox": "Skrzynka odbiorcza",
|
||||
"inbox_for": "Skrzynka odbiorcza <1>{{user}}</1>",
|
||||
"mark_all_as_read": "zaznacz wszystko jako przeczytane",
|
||||
"type": "Rodzaj",
|
||||
"unread": "Nieprzeczytane",
|
||||
"replies": "Odpowiedzi",
|
||||
"mentions": "Wzmianki",
|
||||
"reply_sent": "Odpowiedź wysłana",
|
||||
"message_sent": "Wiadomość wysłana",
|
||||
"search": "Szukaj",
|
||||
"overview": "Podgląd",
|
||||
"view": "Widok",
|
||||
"logout": "Wyloguj",
|
||||
"login_sign_up": "Zaloguj / Zarejestruj",
|
||||
"login": "Zaloguj",
|
||||
"sign_up": "Zarejestruj",
|
||||
"notifications_error": "Powiadomienia na pulpicie są niedostępne w Twojej przeglądarce. Spróbuj przeglądarkę Firefox lub Chrome.",
|
||||
"unread_messages": "Nieprzeczytane Wiadomości",
|
||||
"password": "Hasło",
|
||||
"verify_password": "Zweryfikuj Hasło",
|
||||
"old_password": "Stare Hasło",
|
||||
"forgot_password": "nie pamiętam hasła",
|
||||
"reset_password_mail_sent": "Wysłano email w celu zresetowania hasła.",
|
||||
"password_change": "Zmiana Hasła",
|
||||
"new_password": "Nowe Hasło",
|
||||
"no_email_setup": "Email nie został poprawnie ustawiony na tym serwerze.",
|
||||
"email": "Email",
|
||||
"matrix_user_id": "Użytkownik Matrixa",
|
||||
"private_message_disclaimer": "Ostrzeżenie: Prywatne wiadomości w Lemmym nie są bezpieczne. Jeśli chcesz wysyłać i odbierać bezpieczne wiadomości załóż konto na <1>Riot.im</1>.",
|
||||
"send_notifications_to_email": "Wysyłaj powiadomienia na Email",
|
||||
"optional": "Opcjonalne",
|
||||
"expires": "Wygasa",
|
||||
"language": "Język",
|
||||
"browser_default": "Domyślna wartość przeglądarki",
|
||||
"downvotes_disabled": "Wdółgłosy wyłączone",
|
||||
"enable_downvotes": "Włącz Wdółgłosy",
|
||||
"upvote": "Wgóręgłos",
|
||||
"number_of_upvotes_0": "Wgóręgłos",
|
||||
"number_of_upvotes_1": "Wgóręgłosy/ów",
|
||||
"number_of_upvotes_2": "Wgóręgłosy/ów",
|
||||
"downvote": "Wdółgłos",
|
||||
"number_of_downvotes_0": "Wdółgłos",
|
||||
"number_of_downvotes_1": "Wdółgłosy/ów",
|
||||
"number_of_downvotes_2": "Wdółgłosy/ów",
|
||||
"open_registration": "Rejestracja Otwarta",
|
||||
"registration_closed": "Rejestracja Zamknięta",
|
||||
"enable_nsfw": "Włącz NSFW",
|
||||
"url": "URL",
|
||||
"body": "Treść",
|
||||
"copy_suggested_title": "skopiuj sugerowany tytuł: {{title}}",
|
||||
"community": "Społeczność",
|
||||
"expand_here": "Rozwiń tutaj",
|
||||
"subscribe_to_communities": "Zasubskrybuj kilka <1>społeczności</1>.",
|
||||
"chat": "Czat",
|
||||
"recent_comments": "Najnowsze Komentarze",
|
||||
"no_results": "Brak wyników.",
|
||||
"setup": "Instalacja",
|
||||
"lemmy_instance_setup": "Instalacja Instancji Lemmy",
|
||||
"setup_admin": "Ustaw Administratora Strony",
|
||||
"your_site": "twoja witryna",
|
||||
"modified": "zmodyfikowane",
|
||||
"nsfw": "NSFW",
|
||||
"show_nsfw": "Pokaż treści NSFW (+18)",
|
||||
"theme": "Motyw",
|
||||
"sponsors": "Sponsorzy",
|
||||
"sponsors_of_lemmy": "Sponsorzy projektu Lemmy",
|
||||
"sponsor_message": "Lemmy jest wolnym, <1>otwartoźródłowym</1> oprogramowaniem, co oznacza zero reklam, opłat, czy innych form kapitalizacji, od zawsze na zawsze. Twoje darowizny idą bezpośrednio na rozwój projektu w pełno-etatowym wymiarze. Specjalne wyrazy podziękowania dla następujących osób:",
|
||||
"support_on_patreon": "Wspieraj w serwisie Patreon",
|
||||
"support_on_liberapay": "Wspieraj na Liberapay",
|
||||
"donate_to_lemmy": "Przekaż datek na Lemmiego",
|
||||
"donate": "Przekaż datek",
|
||||
"general_sponsors": "Główni Sponsorzy to osoby które wsparły Lemmiego kwotą od $10 do $39.",
|
||||
"crypto": "Kryptowaluta",
|
||||
"bitcoin": "Bitcoin",
|
||||
"ethereum": "Ethereum",
|
||||
"monero": "Monero",
|
||||
"code": "Kod",
|
||||
"joined": "Dołączono",
|
||||
"by": "przez",
|
||||
"to": "do",
|
||||
"from": "od",
|
||||
"transfer_community": "transfer społeczności",
|
||||
"transfer_site": "transfer witryny",
|
||||
"are_you_sure": "na pewno?",
|
||||
"no": "nie",
|
||||
"powered_by": "Powered by",
|
||||
"landing": "Lemmy jest <1>agregatorem linków</1> / alternatywą dla reddita. Jest przeznaczony do działania w ramach cyfrowej przestrzeni nazywanej <2>fediverse<2>. <3></3>Opiera się na samodzielnym hostingu, posiada aktualizowane na żywo wątki z komentarzami, i zajmuje bardzo mało miejsce (<4>~80kB</4>). Federacja w ramach sieci ActivityPub jest w planach. <5></5>Ta wersja jest <6>bardzo wczesną wersją beta</6>, co oznacza, że wiele funkcji nadal nie działa tak jak powinny. <7></7><8>Pod tym adresem</8> można sugerować nową funkcjonalność i zgłaszać błędy.<9></9>Stworzono z wykorzystaniem <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
|
||||
"not_logged_in": "Nie jesteś zalogowana/y.",
|
||||
"logged_in": "Zalogowano.",
|
||||
"community_ban": "Zostałaś/eś zbanowana/y z tej społeczności.",
|
||||
"site_ban": "Zostałaś/eś zbanowana/y z tej witryny",
|
||||
"couldnt_create_comment": "Nie udało się stworzyć komentarza.",
|
||||
"couldnt_like_comment": "Polubienie komentarza nie powiodło się.",
|
||||
"couldnt_update_comment": "Zaktualizowanie komentarza nie powiodło się.",
|
||||
"couldnt_save_comment": "Zapisanie komentarza nie powiodło się.",
|
||||
"couldnt_get_comments": "Pobranie komentarzy nie powiodło się.",
|
||||
"no_comment_edit_allowed": "Nie masz uprawnień do edycji komentarza.",
|
||||
"no_post_edit_allowed": "Nie masz uprawnień do edycji posta.",
|
||||
"no_community_edit_allowed": "Nie masz uprawnień do edycji społeczności.",
|
||||
"couldnt_find_community": "Nie udało się znaleźć społeczności.",
|
||||
"couldnt_update_community": "Nie udało się zaktualizować Społeczności.",
|
||||
"community_already_exists": "Społeczność już istnieje.",
|
||||
"community_moderator_already_exists": "Moderator społeczności już istnieje.",
|
||||
"community_follower_already_exists": "Osoba obserwująca społeczność już istnieje.",
|
||||
"community_user_already_banned": "Użytkownik społeczności jest już zbanowany.",
|
||||
"couldnt_create_post": "Nie udało się stworzyć posta.",
|
||||
"post_title_too_long": "Tytuł posta zbyt długi.",
|
||||
"couldnt_like_post": "Nie udało się polubić posta.",
|
||||
"couldnt_find_post": "Nie udało się znaleźć posta.",
|
||||
"couldnt_update_post": "Nie udało się zaktualizować postów",
|
||||
"couldnt_get_posts": "Nie udało się pobrać postów",
|
||||
"couldnt_save_post": "Nie udało się zapisać posta.",
|
||||
"no_slurs": "Bez obelg.",
|
||||
"not_an_admin": "Nie jest administratorem.",
|
||||
"site_already_exists": "Witryna już istnieje.",
|
||||
"couldnt_update_site": "Nie udało się zaktualizować witryny.",
|
||||
"couldnt_find_that_username_or_email": "Nie udało się znaleźć takiej nazwy użytkownika lub adresu email.",
|
||||
"password_incorrect": "Hasło niepoprawne.",
|
||||
"passwords_dont_match": "Hasła nie pasują do siebie.",
|
||||
"admin_already_created": "Wybacz, funkcja administratora jest już przypisana.",
|
||||
"user_already_exists": "Użytkownik już istnieje.",
|
||||
"email_already_exists": "Email już istnieje.",
|
||||
"couldnt_update_user": "Nie udało się zaktualizować użytkownika.",
|
||||
"system_err_login": "Błąd systemu. Spróbuj wylogować się i następnie zalogować ponownie.",
|
||||
"couldnt_create_private_message": "Nie udało się stworzyć prywatnej wiadomości.",
|
||||
"no_private_message_edit_allowed": "Brak uprawnień do edycji prywatnej wiadomości.",
|
||||
"couldnt_update_private_message": "Nie udało się zaktualizować prywatnej wiadomości.",
|
||||
"time": "Czas",
|
||||
"action": "Akcja",
|
||||
"block_leaving": "Czy na pewno chcesz wyjść?",
|
||||
"show_context": "Pokaż kontekst"
|
||||
}
|
||||
|
||||
|
|
3
ui/translations/pt_BR.json
vendored
3
ui/translations/pt_BR.json
vendored
|
@ -243,5 +243,6 @@
|
|||
"number_of_upvotes": "{{count}} voto positivo",
|
||||
"number_of_upvotes_plural": "{{count}} votos positivos",
|
||||
"number_of_downvotes": "{{count}} voto negativo",
|
||||
"number_of_downvotes_plural": "{{count}} votos negativos"
|
||||
"number_of_downvotes_plural": "{{count}} votos negativos",
|
||||
"show_context": "Mostrar contexto"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue