Browse Source

Merge pull request 'Selfhosted frontend' (#319) from feature/frontend-selfhost into main

Reviewed-on: https://git.chapo.chat/hexbear-collective/lemmy-hexbear/pulls/319
main
DashEightMate 3 months ago
parent
commit
ab41c2035f
  1. 5
      .gitmodules
  2. 1
      README.md
  3. 11
      docker/chapo-dev/docker-compose.yml
  4. 18
      docker/chapo-dev/nginx-lemmy-dev.conf
  5. 11
      docker/chapo-prod/docker-compose.yml
  6. 8
      docker/dev/Dockerfile
  7. 5
      docker/dev/docker_update.sh
  8. 14
      docker/prod/Dockerfile
  9. 1
      docs/.gitignore
  10. 6
      docs/book.toml
  11. BIN
      docs/img/chat_screen.png
  12. BIN
      docs/img/main_screen.png
  13. BIN
      docs/img/rank_algorithm.png
  14. 22
      docs/src/SUMMARY.md
  15. 30
      docs/src/about.md
  16. 34
      docs/src/about_features.md
  17. 54
      docs/src/about_goals.md
  18. 42
      docs/src/about_guide.md
  19. 31
      docs/src/about_ranking.md
  20. 3
      docs/src/administration.md
  21. 83
      docs/src/administration_backup_and_restore.md
  22. 24
      docs/src/administration_configuration.md
  23. 25
      docs/src/administration_install_ansible.md
  24. 41
      docs/src/administration_install_docker.md
  25. 24
      docs/src/administration_install_kubernetes.md
  26. 39
      docs/src/contributing.md
  27. 378
      docs/src/contributing_apub_api_outline.md
  28. 40
      docs/src/contributing_docker_development.md
  29. 88
      docs/src/contributing_federation_development.md
  30. 151
      docs/src/contributing_local_development.md
  31. 16
      docs/src/contributing_tests.md
  32. 18
      docs/src/contributing_theming.md
  33. 1884
      docs/src/contributing_websocket_http_api.md
  34. 79
      docs/src/lemmy_council.md
  35. 1
      server/lemmy_utils/src/settings.rs
  36. 12
      server/src/main.rs
  37. 59
      server/src/routes/index.rs
  38. 1
      server/src/routes/mod.rs
  39. 1
      ui

5
.gitmodules

@ -1,5 +0,0 @@
[submodule "ui"]
path = ui
url = https://git.chapo.chat/chapo-collective/hexbear-frontend.git
[submodule "ui/"]
branch = main

1
README.md

@ -8,7 +8,6 @@
**Main Branch:** [![Build Status](https://drone.chapo.chat/api/badges/hexbear-collective/lemmy-hexbear/status.svg?ref=refs/heads/main)](https://drone.chapo.chat/hexbear-collective/lemmy-hexbear)
**Production:** [![Build Status](https://drone.chapo.chat/api/badges/hexbear-collective/lemmy-hexbear/status.svg?ref=refs/heads/prod)](https://drone.chapo.chat/hexbear-collective/lemmy-hexbear)
[Original Lemmy README](README-lemmy.md)
</div>

11
docker/chapo-dev/docker-compose.yml

@ -2,9 +2,14 @@ version: '3.3'
services:
hexbear-frontend:
image: registry.chapo.chat/hexbear-frontend:dev
volumes:
- frontend:/app/dist
image: registry.chapo.chat/hexbear-frontend:dev-latest
container_name: lemmy-dev-fe
ports:
- "127.0.0.1:4444:4444"
environment:
- PG_CONN_URL=postgres://lemmy:${LEMMYDEV_POSTGRES_PW}@postgres-dev:5433/lemmy
depends_on:
- postgres
lemmy:
image: registry.chapo.chat/hexbear:dev-latest

18
docker/chapo-dev/nginx-lemmy-dev.conf

@ -5,6 +5,12 @@ server {
return 301 https://thoseamongbranches.chapo.chat$request_uri;
}
#if the incoming client is another federated server, proxy them to the backend when they query /
map $http_accept $root_port {
default "4444";
application/activity+json "8536";
}
server {
listen 443 ssl http2;
server_name thoseamongbranches.chapo.chat;
@ -37,6 +43,12 @@ server {
#limit_req zone=lemmy_ratelimit burst=30 nodelay;
location / {
proxy_pass http://0.0.0.0:$root_port;
rewrite ^(.+)/+$ $1 permanent;
include proxy-set-headers.conf;
}
location /api {
proxy_pass http://0.0.0.0:8536;
rewrite ^(.+)/+$ $1 permanent;
include proxy-set-headers.conf;
@ -47,6 +59,12 @@ server {
proxy_set_header Connection "upgrade";
}
location /feeds {
proxy_pass http://0.0.0.0:8536;
rewrite ^(.+)/+$ $1 permanent;
include proxy-set-headers.conf;
}
# Redirect pictshare images to pictrs
location ~ /pictshare/(.*)$ {
return 301 /pictrs/image/$1;

11
docker/chapo-prod/docker-compose.yml

@ -2,9 +2,14 @@ version: '3.3'
services:
hexbear-frontend:
image: registry.chapo.chat/hexbear-frontend:prod
volumes:
- frontend:/app/dist
image: registry.chapo.chat/hexbear-frontend:prod-latest
container_name: lemmy-prod-fe
ports:
- "127.0.0.1:4444:4444"
environment:
- PG_CONN_URL=postgres://lemmy:${LEMMYPROD_POSTGRES_PW}@postgres-prod:5433/lemmy
depends_on:
- postgres
lemmy:
image: registry.chapo.chat/hexbear:prod-latest

8
docker/dev/Dockerfile

@ -41,13 +41,6 @@ RUN sudo chown -R rust:rust .
RUN cargo build
FROM ${RUST_BUILDER} as docs
WORKDIR /app
COPY docs ./docs
RUN sudo chown -R rust:rust .
RUN mdbook build docs/
FROM alpine:3.12 as runner
# Install libpq for postgres
@ -59,7 +52,6 @@ RUN apk add espeak
# Copy resources
COPY server/config/defaults.hjson /config/defaults.hjson
COPY --from=builder /app/server/target/x86_64-unknown-linux-musl/debug/lemmy_server /app/lemmy
COPY --from=docs /app/docs/book/ /app/dist/documentation/
RUN addgroup -g 1000 lemmy
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy

5
docker/dev/docker_update.sh

@ -1,6 +1,5 @@
#!/bin/sh
set -e
sudo chown -R 991:991 volumes/pictrs
sudo docker build ../../ --file ../dev/Dockerfile -t lemmy-dev:latest
sudo docker-compose up -d
docker build ../../ --file ../dev/Dockerfile -t lemmy-dev:latest
docker-compose up -d

14
docker/prod/Dockerfile

@ -36,17 +36,6 @@ RUN strip ./target/$CARGO_BUILD_TARGET/$RUSTRELEASEDIR/lemmy_server
RUN cp ./target/$CARGO_BUILD_TARGET/$RUSTRELEASEDIR/lemmy_server /app/server/
FROM $RUST_BUILDER_IMAGE as docs
WORKDIR /app
COPY --chown=rust:rust docs ./docs
RUN mdbook build docs/
ARG FRONTEND_TAG
ARG FRONTEND_REPO
RUN echo ${FRONTEND_REPO}:${FRONTEND_TAG}
FROM ${FRONTEND_REPO}:${FRONTEND_TAG} as frontend
FROM alpine:3.12 as lemmy
# Install libpq for postgres
@ -61,9 +50,6 @@ RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
# Copy resources
COPY --chown=lemmy:lemmy server/config/defaults.hjson /config/defaults.hjson
COPY --chown=lemmy:lemmy --from=rust /app/server/lemmy_server /app/lemmy
COPY --chown=lemmy:lemmy --from=docs /app/docs/book/ /app/dist/documentation/
COPY --chown=lemmy:lemmy --from=frontend /app/dist /app/dist
RUN chown lemmy:lemmy /app/lemmy
USER lemmy

1
docs/.gitignore

@ -1 +0,0 @@
book

6
docs/book.toml

@ -1,6 +0,0 @@
[book]
authors = ["Felix Ableitner"]
language = "en"
multilingual = false
src = "src"
title = "Lemmy Documentation"

BIN
docs/img/chat_screen.png

Before

Width: 1836  |  Height: 921  |  Size: 78 KiB

BIN
docs/img/main_screen.png

Before

Width: 1839  |  Height: 921  |  Size: 92 KiB

BIN
docs/img/rank_algorithm.png

Before

Width: 617  |  Height: 702  |  Size: 54 KiB

22
docs/src/SUMMARY.md

@ -1,22 +0,0 @@
# Summary
- [About](about.md)
- [Features](about_features.md)
- [Goals](about_goals.md)
- [Post and Comment Ranking](about_ranking.md)
- [Guide](about_guide.md)
- [Administration](administration.md)
- [Install with Docker](administration_install_docker.md)
- [Install with Ansible](administration_install_ansible.md)
- [Install with Kubernetes](administration_install_kubernetes.md)
- [Configuration](administration_configuration.md)
- [Backup and Restore](administration_backup_and_restore.md)
- [Contributing](contributing.md)
- [Docker Development](contributing_docker_development.md)
- [Local Development](contributing_local_development.md)
- [Tests](contributing_tests.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)
- [Lemmy Council](lemmy_council.md)

30
docs/src/about.md

@ -1,30 +0,0 @@
## About The Project
Front Page|Post
---|---
![main screen](https://raw.githubusercontent.com/LemmyNet/lemmy/main/docs/img/main_screen.png)|![chat screen](https://raw.githubusercontent.com/LemmyNet/lemmy/main/docs/img/chat_screen.png)
[Lemmy](https://github.com/LemmyNet/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.
The overall goal is to create an easily self-hostable, decentralized alternative to reddit and other link aggregators, outside of their corporate control and meddling.
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.
*Note: Federation is still in active development*
### Why's it called Lemmy?
- Lead singer from [Motörhead](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/).
### Built With
- [Rust](https://www.rust-lang.org)
- [Actix](https://actix.rs/)
- [Diesel](http://diesel.rs/)
- [Inferno](https://infernojs.org)
- [Typescript](https://www.typescriptlang.org/)

34
docs/src/about_features.md

@ -1,34 +0,0 @@
# Features
- Open source, [AGPL License](/LICENSE).
- Self hostable, easy to deploy.
- Comes with [Docker](#docker), [Ansible](#ansible), [Kubernetes](#kubernetes).
- Clean, mobile-friendly interface.
- Only a minimum of a username and password is required to sign up!
- User avatar support.
- Live-updating Comment threads.
- Full vote scores `(+/-)` like old reddit.
- Themes, including light, dark, and solarized.
- Emojis with autocomplete support. Start typing `:`
- User tagging using `@`, Community tagging using `#`.
- Integrated image uploading in both posts and comments.
- A post can consist of a title and any combination of self text, a URL, or nothing else.
- Notifications, on comment replies and when you're tagged.
- Notifications can be sent via email.
- i18n / internationalization support.
- RSS / Atom feeds for `All`, `Subscribed`, `Inbox`, `User`, and `Community`.
- Cross-posting support.
- A *similar post search* when creating new posts. Great for question / answer communities.
- Moderation abilities.
- Public Moderation Logs.
- Can sticky posts to the top of communities.
- Both site admins, and community moderators, who can appoint other moderators.
- Can lock, remove, and restore posts and comments.
- Can ban and unban users from communities and the site.
- Can transfer site and communities to others.
- Can fully erase your data, replacing all posts and comments.
- NSFW post / community support.
- High performance.
- Server is written in rust.
- Front end is `~80kB` gzipped.
- Supports arm64 / Raspberry Pi.

54
docs/src/about_goals.md

@ -1,54 +0,0 @@
# Goals
- Come up with a name / codename.
- Must have communities.
- Must have threaded comments.
- Must be federated: liking and following communities across instances.
- Be live-updating: have a right pane for new comments, and a main pain for the full threaded view.
- Use websockets for post / gets to your own instance.
# Questions
- How does voting work? Should we go back to the old way of showing up and downvote counts? Or just a score?
- Decide on tech to be used
- Backend: Actix, Diesel.
- Frontend: inferno, typescript and bootstrap for now.
- Should it allow bots?
- Should the comments / votes be static, or feel like a chat, like [flowchat?](https://flow-chat.com).
- Two pane model - Right pane is live comments, left pane is live tree view.
- On mobile, allow you to switch between them. Default?
# Resources / Potential Libraries
- [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/)
- [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)
- [Sticky Sidebar](https://stackoverflow.com/questions/38382043/how-to-use-css-position-sticky-to-keep-a-sidebar-visible-with-bootstrap-4/49111934)
- [RXJS websocket](https://stackoverflow.com/questions/44060315/reconnecting-a-websocket-in-angular-and-rxjs/44067972#44067972)
- [Rust JWT](https://github.com/Keats/jsonwebtoken)
- [Hierarchical tree building javascript](https://stackoverflow.com/a/40732240/1655478)
- [Hot sorting discussion](https://meta.stackexchange.com/questions/11602/what-formula-should-be-used-to-determine-hot-questions) [2](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9)
- [Classification types.](https://www.reddit.com/r/ModeratorDuck/wiki/subreddit_classification)
- [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)
- [TippyJS](https://github.com/atomiks/tippyjs)
## 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 the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/)
- https://docs.rs/activitypub/0.1.4/activitypub/
- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/)
- [Activitypub main](https://www.w3.org/TR/activitypub/)
- [Federation.md](https://github.com/dariusk/gathio/blob/7fc93dbe9d4d99457a0e85c6c532112f415b7af2/FEDERATION.md)
- [Activitypub implementers guide](https://socialhub.activitypub.rocks/t/draft-guide-for-new-activitypub-implementers/479)
- [Data storage questions](https://socialhub.activitypub.rocks/t/data-storage-questions/579/3)
- [Activitypub as it has been understood](https://flak.tedunangst.com/post/ActivityPub-as-it-has-been-understood)
- [Asonix http signatures in rust](https://git.asonix.dog/Aardwolf/http-signature-normalization)

42
docs/src/about_guide.md

@ -1,42 +0,0 @@
# Lemmy Guide
Start typing...
- `@a_user_name` to get a list of usernames.
- `!a_community` to get a list of communities.
- `:emoji` to get a list of emojis.
## Sorting
_Applies to both posts and comments_
| Type | Description |
| ------ | ----------------------------------------------------------------------------- |
| Active | Shows _trending_ posts, based on the score, and the most recent comment time. |
| Hot | Shows highest ranking posts, but decays over time |
| New | Newest posts. |
| Top | Shows the highest scoring posts in the given time frame. |
For more detail, check the [Post and Comment Ranking details](about_ranking.md).
## Markdown Guide
Type | Or | … to Get
--- | --- | ---
\*Italic\* | \_Italic\_ | _Italic_
\*\*Bold\*\* | \_\_Bold\_\_ | **Bold**
\# Heading 1 | Heading 1 <br> ========= | <h4>Heading 1</h4>
\## Heading 2 | Heading 2 <br>--------- | <h5>Heading 2</h5>
\[Link\](http://a.com) | \[Link\]\[1\]<br><br>\[1\]: http://b.org | [Link](https://commonmark.org/)
!\[Image\](http://url/a.png) | !\[Image\]\[1\]<br><br>\[1\]: http://url/b.jpg | ![Markdown](https://commonmark.org/help/images/favicon.png)
\> Blockquote | | <blockquote>Blockquote</blockquote>
\* List <br>\* List <br>\* List | \- List <br>\- List <br>\- List <br> | * List <br>* List <br>* List <br>
1\. One <br>2\. Two <br>3\. Three | 1) One<br>2) Two<br>3) Three | 1. One<br>2. Two<br>3. Three
Horizontal Rule <br>\--- | Horizontal Rule<br>\*\*\* | Horizontal Rule <br><hr>
\`Inline code\` with backticks | |`Inline code` with backticks
\`\`\`<br>\# code block <br>print '3 backticks or'<br>print 'indent 4 spaces' <br>\`\`\` | ····\# code block<br>····print '3 backticks or'<br>····print 'indent 4 spaces' | \# code block <br>print '3 backticks or'<br>print 'indent 4 spaces'
::: spoiler hidden or nsfw stuff<br>*a bunch of spoilers here*<br>::: | | <details><summary> hidden or nsfw stuff </summary><p><em>a bunch of spoilers here</em></p></details>
Some ~subscript~ text | | Some <sub>subscript</sub> text
Some ^superscript^ text | | Some <sup>superscript</sup> text
[CommonMark Tutorial](https://commonmark.org/help/tutorial/)

31
docs/src/about_ranking.md

@ -1,31 +0,0 @@
# Trending / Hot / Best Sorting algorithm
## Goals
- During the day, new posts and comments should be near the top, so they can be voted on.
- After a day or so, the time factor should go away.
- 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. 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.
## My Algorithm
```
Rank = ScaleFactor * log(Max(1, 3 + Score)) / (Time + 2)^Gravity
Score = Upvotes - Downvotes
Time = time since submission (in hours)
Gravity = Decay gravity, 1.8 is default
```
- Lemmy uses the same `Rank` algorithm above, in two sorts: `Active`, and `Hot`.
- `Active` uses the post votes, and latest comment time (limited to two days).
- `Hot` uses the post votes, and the post published time.
- Use Max(1, score) to make sure all comments are affected by time decay.
- Add 3 to the score, so that everything that has less than 3 downvotes will seem new. Otherwise all new comments would stay at zero, near the bottom.
- The sign and abs of the score are necessary for dealing with the log of negative scores.
- A scale factor of 10k gets the rank in integer form.
A plot of rank over 24 hours, of scores of 1, 5, 10, 100, 1000, with a scale factor of 10k.
![](https://raw.githubusercontent.com/LemmyNet/lemmy/main/docs/img/rank_algorithm.png)

3
docs/src/administration.md

@ -1,3 +0,0 @@
# Admin info
Information for Lemmy instance admins, and those who want to start an instance.

83
docs/src/administration_backup_and_restore.md

@ -1,83 +0,0 @@
# Backup and Restore Guide
## Docker and Ansible
When using docker or ansible, there should be a `volumes` folder, which contains both the database, and all the pictures. Copy this folder to the new instance to restore your data.
### Incremental Database backup
To incrementally backup the DB to an `.sql` file, you can run:
```bash
docker-compose exec postgres pg_dumpall -c -U lemmy > lemmy_dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql
```
### A Sample backup script
```bash
#!/bin/sh
# DB Backup
ssh [email protected]_IP "docker-compose exec postgres pg_dumpall -c -U lemmy" > ~/BACKUP_LOCATION/INSTANCE_NAME_dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql
# Volumes folder Backup
rsync -avP -zz --rsync-path="sudo rsync" [email protected]_IP:/LEMMY_LOCATION/volumes ~/BACKUP_LOCATION/FOLDERNAME
```
### Restoring the DB
If you need to restore from a `pg_dumpall` file, you need to first clear out your existing database
```bash
# Drop the existing DB
docker exec -i FOLDERNAME_postgres_1 psql -U lemmy -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
# Restore from the .sql backup
cat db_dump.sql | docker exec -i FOLDERNAME_postgres_1 psql -U lemmy # restores the db
# This also might be necessary when doing a db import with a different password.
docker exec -i FOLDERNAME_postgres_1 psql -U lemmy -c "alter user lemmy with password 'bleh'"
```
### Changing your domain name
If you haven't federated yet, you can change your domain name in the DB. **Warning: do not do this after you've federated, or it will break federation.**
Get into `psql` for your docker:
`docker-compose exec postgres psql -U lemmy`
```
-- Post
update post set ap_id = replace (ap_id, 'old_domain', 'new_domain');
update post set url = replace (url, 'old_domain', 'new_domain');
update post set body = replace (body, 'old_domain', 'new_domain');
update post set thumbnail_url = replace (thumbnail_url, 'old_domain', 'new_domain');
delete from post_aggregates_fast;
insert into post_aggregates_fast select * from post_aggregates_view;
-- Comments
update comment set ap_id = replace (ap_id, 'old_domain', 'new_domain');
update comment set content = replace (content, 'old_domain', 'new_domain');
delete from comment_aggregates_fast;
insert into comment_aggregates_fast select * from comment_aggregates_view;
-- User
update user_ set actor_id = replace (actor_id, 'old_domain', 'new_domain');
update user_ set avatar = replace (avatar, 'old_domain', 'new_domain');
delete from user_fast;
insert into user_fast select * from user_view;
-- Community
update community set actor_id = replace (actor_id, 'old_domain', 'new_domain');
delete from community_aggregates_fast;
insert into community_aggregates_fast select * from community_aggregates_view;
```
## More resources
- https://stackoverflow.com/questions/24718706/backup-restore-a-dockerized-postgresql-database

24
docs/src/administration_configuration.md

@ -1,24 +0,0 @@
# Configuration
The configuration is based on the file
[defaults.hjson](https://yerbamate.dev/LemmyNet/lemmy/src/branch/main/server/config/defaults.hjson).
This file also contains documentation for all the available options. To override the defaults, you
can copy the options you want to change into your local `config.hjson` file.
To use a different `config.hjson` location than the current directory, set the environment variable `LEMMY_CONFIG_LOCATION`. Make sure you copy the `defaults.hjson` if you do this, otherwise you will be missing settings.
Additionally, you can override any config files with environment variables. These have the same
name as the config options, and are prefixed with `LEMMY_`. For example, you can override the
`database.password` with `LEMMY_DATABASE__POOL_SIZE=10`.
An additional option `LEMMY_DATABASE_URL` is available, which can be used with a PostgreSQL
connection string like `postgres://lemmy:[email protected]_db:5432/lemmy`, passing all connection
details at once.
If the Docker container is not used, manually create the database specified above by running the
following commands:
```bash
cd server
./db-init.sh
```

25
docs/src/administration_install_ansible.md

@ -1,25 +0,0 @@
# 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:
```bash
git clone https://github.com/LemmyNet/lemmy.git
cd lemmy/ansible/
cp inventory.example inventory
nano inventory # enter your server, domain, contact email
# If the command below fails, you may need to comment out this line
# In the ansible.cfg file:
# interpreter_python=/usr/bin/python3
ansible-playbook lemmy.yml --become
```
To update to a new version, just run the following in your local Lemmy repo:
```bash
git pull origin main
cd ansible
ansible-playbook lemmy.yml --become
```

41
docs/src/administration_install_docker.md

@ -1,41 +0,0 @@
# Docker Installation
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
# 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/LemmyNet/lemmy/main/docker/prod/docker-compose.yml
wget https://raw.githubusercontent.com/LemmyNet/lemmy/main/docker/lemmy.hjson
wget https://raw.githubusercontent.com/LemmyNet/lemmy/main/docker/iframely.config.local.js
# Set correct permissions for pictrs folder
mkdir -p volumes/pictrs
sudo chown -R 991:991 volumes/pictrs
```
After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname, and possibly the db password. Then run:
`docker-compose up -d`
To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](https://raw.githubusercontent.com/LemmyNet/lemmy/main/ansible/templates/nginx.conf), could be setup with:
```bash
wget https://raw.githubusercontent.com/LemmyNet/lemmy/main/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, 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/LemmyNet/lemmy/main/docker/prod/docker-compose.yml
docker-compose up -d
```

24
docs/src/administration_install_kubernetes.md

@ -1,24 +0,0 @@
# Kubernetes Installation
You'll need to have an existing Kubernetes cluster and [storage class](https://kubernetes.io/docs/concepts/storage/storage-classes/).
Setting this up will vary depending on your provider.
To try it locally, you can use [MicroK8s](https://microk8s.io/) or [Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/).
Once you have a working cluster, edit the environment variables and volume sizes in `docker/k8s/*.yml`.
You may also want to change the service types to use `LoadBalancer`s depending on where you're running your cluster (add `type: LoadBalancer` to `ports)`, or `NodePort`s.
By default they will use `ClusterIP`s, which will allow access only within the cluster. See the [docs](https://kubernetes.io/docs/concepts/services-networking/service/) for more on networking in Kubernetes.
**Important** Running a database in Kubernetes will work, but is generally not recommended.
If you're deploying on any of the common cloud providers, you should consider using their managed database service instead (RDS, Cloud SQL, Azure Databse, etc.).
Now you can deploy:
```bash
# Add `-n foo` if you want to deploy into a specific namespace `foo`;
# otherwise your resources will be created in the `default` namespace.
kubectl apply -f docker/k8s/db.yml
kubectl apply -f docker/k8s/pictshare.yml
kubectl apply -f docker/k8s/lemmy.yml
```
If you used a `LoadBalancer`, you should see it in your cloud provider's console.

39
docs/src/contributing.md

@ -1,39 +0,0 @@
# Contributing
Information about contributing to Lemmy, whether it is translating, testing, designing or programming.
## Issue tracking / Repositories
- [GitHub (for issues and pull requests)](https://github.com/LemmyNet/lemmy)
- [Gitea (only for pull requests)](https://yerbamate.dev/LemmyNet/lemmy)
- [GitLab (only code-mirror)](https://gitlab.com/dessalines/lemmy)
## Translating
Check out [Lemmy's Weblate](https://weblate.yerbamate.dev/projects/lemmy/) for translations.
## Architecture
### Front end
- The front end is written in `typescript`, using a react-like framework called [inferno](https://infernojs.org/). All UI elements are reusable `.tsx` components.
- The main page and routing are in `ui/src/index.tsx`.
- The components are located in `ui/src/components`.
### Back end
- The back end is written in `rust`, using `diesel`, and `actix`.
- The server source code is split into main sections in `server/src`. These include:
- `db` - The low level database actions.
- Database additions are done using diesel migrations. Run `diesel migration generate xxxxx` to add new things.
- `api` - The high level user interactions (things like `CreateComment`)
- `routes` - The server endpoints .
- `apub` - The activitypub conversions.
- `websocket` - Creates the websocket server.
## Linting / Formatting
- Every front and back end commit is automatically formatted then linted using `husky`, and `lint-staged`.
- Rust with `cargo fmt` and `cargo clippy`.
- Typescript with `prettier` and `eslint`.

378
docs/src/contributing_apub_api_outline.md

@ -1,378 +0,0 @@
# Activitypub API outline
- Start with the [reddit API](https://www.reddit.com/dev/api), and find [Activitypub vocab](https://www.w3.org/TR/activitystreams-vocabulary/) to match it.
<!-- toc -->
- [Actors](#actors)
* [User / Person](#user--person)
* [Community / Group](#community--group)
- [Objects](#objects)
* [Post / Page](#post--page)
* [Post Listings / Ordered CollectionPage](#post-listings--ordered-collectionpage)
* [Comment / Note](#comment--note)
* [Comment Listings / Ordered CollectionPage](#comment-listings--ordered-collectionpage)
* [Deleted thing / Tombstone](#deleted-thing--tombstone)
- [Actions](#actions)
* [Comments](#comments)
+ [Create](#create)
+ [Delete](#delete)
+ [Update](#update)
+ [Read](#read)
+ [Like](#like)
+ [Dislike](#dislike)
* [Posts](#posts)
+ [Create](#create-1)
+ [Delete](#delete-1)
+ [Update](#update-1)
+ [Read](#read-1)
* [Communities](#communities)
+ [Create](#create-2)
+ [Delete](#delete-2)
+ [Update](#update-2)
+ [Join](#join)
+ [Leave](#leave)
* [Moderator](#moderator)
+ [Ban user from community / Block](#ban-user-from-community--block)
+ [Delete Comment](#delete-comment)
+ [Invite a moderator](#invite-a-moderator)
+ [Accept Invitation](#accept-invitation)
+ [Reject Invitation](#reject-invitation)
<!-- tocstop -->
## Actors
### [User / Person](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": "https://instance_url/api/v1/user/sally_smith",
"inbox": "https://instance_url/api/v1/user/sally_smith/inbox",
"outbox": "https://instance_url/api/v1/user/sally_smith/outbox",
"liked": "https://instance_url/api/v1/user/sally_smith/liked",
// TODO disliked?
"following": "https://instance_url/api/v1/user/sally_smith/following",
"name": "sally_smith",
"preferredUsername": "Sally",
"icon"?: {
"type": "Image",
"name": "User icon",
"url": "https://instance_url/api/v1/user/sally_smith/icon.png",
"width": 32,
"height": 32
},
"published": "2014-12-31T23:00:00-08:00",
"summary"?: "This is sally's profile."
}
```
### [Community / Group](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Group",
"id": "https://instance_url/api/v1/community/today_i_learned",
"name": "today_i_learned"
"attributedTo": [ // The moderators
"http://joe.example.org",
],
"followers": "https://instance_url/api/v1/community/today_i_learned/followers",
"published": "2014-12-31T23:00:00-08:00",
"summary"?: "The group's tagline",
"attachment: [{}] // TBD, these would be where strong types for custom styles, and images would work.
}
```
## Objects
### [Post / Page](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Page",
"id": "https://instance_url/api/v1/post/1",
"name": "The title of a post, maybe a link to imgur",
"url": "https://news.blah.com"
"attributedTo": "http://joe.example.org", // The poster
"published": "2014-12-31T23:00:00-08:00",
}
```
### [Post Listings / Ordered CollectionPage](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionpage)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "OrderedCollectionPage",
"id": "https://instance_url/api/v1/posts?type={all, best, front}&sort={}&page=1,
"partOf": "http://example.org/foo",
"orderedItems": [Posts]
}
```
### [Comment / Note](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"id": "https://instance_url/api/v1/comment/1",
"mediaType": "text/markdown",
"content": "Looks like it is going to rain today. Bring an umbrella *if necessary*!"
"attributedTo": john_id,
"inReplyTo": "comment or post id",
"published": "2014-12-31T23:00:00-08:00",
"updated"?: "2014-12-12T12:12:12Z"
"replies" // TODO, not sure if these objects should embed all replies in them or not.
"to": [sally_id, group_id]
}
```
### [Comment Listings / Ordered CollectionPage](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionpage)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "OrderedCollectionPage",
"id": "https://instance_url/api/v1/comments?type={all,user,community,post,parent_comment}&id=1&page=1,
"partOf": "http://example.org/foo",
"orderedItems": [Comments]
}
```
### [Deleted thing / Tombstone](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone)
```
{
"type": "Tombstone",
"formerType": "Note / Post",
"id": note / post_id,
"deleted": "2016-03-17T00:00:00Z"
}
```
## Actions
- These are all posts to a user's outbox.
- The server then creates a post to the necessary inbox of the recipient, or the followers.
- Whenever a user accesses the site, they do a get from their inbox.
### Comments
#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": id,
"object": comment_id, or post_id
}
```
#### [Delete](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Delete",
"actor": id,
"object": comment_id, or post_id
}
```
#### [Update](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": id,
"object": comment_id, or post_id
"content": "New comment",
"updated": "New Date"
}
```
#### [Read](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Read",
"actor": user_id
"object": comment_id
}
```
#### [Like](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like)
- TODO: Should likes be notifications? IE, have a to?
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Like",
"actor": user_id
"object": comment_id
// TODO different types of reactions, or no?
}
```
#### [Dislike](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Dislike",
"actor": user_id
"object": comment_id
// TODO different types of reactions, or no?
}
```
### Posts
#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": id,
"to": community_id/followers
"object": post_id
}
```
#### [Delete](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Delete",
"actor": id,
"object": comment_id, or post_id
}
```
#### [Update](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": id,
"object": comment_id, or post_id
TODO fields.
}
```
#### [Read](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Read",
"actor": user_id
"object": post_id
}
```
### Communities
#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": id,
"object": community_id
}
```
#### [Delete](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Delete",
"actor": id,
"object": community_id
}
```
#### [Update](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": id,
"object": community_id
TODO fields.
}
```
#### [Follow / Subscribe](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Follow",
"actor": id
"object": community_id
}
```
#### [Ignore/ Unsubscribe](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Follow",
"actor": id
"object": community_id
}
```
#### [Join / Become a Mod](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Join",
"actor": user_id,
"object": community_id
}
```
#### [Leave](https://www.w3.org/TR/activitystreams-vocabulary#dfn-leave)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Leave",
"actor": user_id,
"object": community_id
}
```
### Moderator
#### [Ban user from community / Block](https://www.w3.org/TR/activitystreams-vocabulary#dfn-block)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Remove",
"actor": mod_id,
"object": user_id,
"origin": group_id
}
```
#### [Delete Comment](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Delete",
"actor": id,
"object": community_id
}
```
#### [Invite a moderator](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Invite",
"id": "https://instance_url/api/v1/invite/1",
"actor": sally_id,
"object": group_id,
"target": john_id
}
```
#### [Accept Invitation](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Accept",
"actor": john_id,
"object": invite_id
}
```
#### [Reject Invitation](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Reject",
"actor": john_id,
"object": invite_id
}
```

40
docs/src/contributing_docker_development.md

@ -1,40 +0,0 @@
# Docker Development
## Setup
> **NOTE**: Workflow is designed for Mac/Linux - it will work on Windows with WSL, but you'll need to do some extra steps.
* **Mac** - Install [Docker Desktop for Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac) - this creates the VM that will build images, as well as installs other tools needed such as docker-compose. Once installed, go to settings and bump up the amount of RAM from 2gb to at least 4gb, or the build will fail. (8GB recommended)
* **Linux** - You'll need to install Docker and docker-compose - there is a different installation for Docker per distro, but here is the [Ubuntu/Debian](https://docs.docker.com/engine/install/ubuntu/) instructions. Once done, go to the [docker-compose install directions](https://docs.docker.com/compose/install/) and pick the Linux instructions.
## Running
```bash
sudo apt install git docker-compose
git clone https://github.com/LemmyNet/lemmy
cd lemmy/docker/dev
sudo docker-compose up --no-deps --build
```
Upon running this, it will take a while to build, especially on slower systems. Later builds will be faster, based on how Docker creates images (using point in time snapshots).
Also, trying to upload images will be broken until you set the permissions on your /volumes/pictrs folder - you need to run `chown -R 991:991 /volumes/pictrs` from the root of the project, and will likely need to restart the docker-compose after that.
Once everything is up and running, you can go to http://localhost:8536 to visit your local instance.
## Additional Steps
To speed up the Docker compile, add the following to `/etc/docker/daemon.json` and restart Docker.
```
{
"features": {
"buildkit": true
}
}
```
*(You can edit the daemon.json file on Docker Desktop under Settings > Docker Engine)*
If the build is still too slow, you will have to use a
[local build](contributing_local_development.md) instead.

88
docs/src/contributing_federation_development.md

@ -1,88 +0,0 @@
# 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://github.com/LemmyNet/lemmy
```
## Running locally
You need to have the following packages installed, the Docker service needs to be running.
- docker
- docker-compose
Then run the following
```bash
cd docker/federation
./start-local-instances.bash
```
The federation test sets up 5 instances:
Instance | Username | Location | Notes
--- | --- | --- | ---
lemmy-alpha | lemmy_alpha | [127.0.0.1:8540](http://127.0.0.1:8540) | federated with all other instances
lemmy-beta | lemmy_beta | [127.0.0.1:8550](http://127.0.0.1:8550) | federated with all other instances
lemmy-gamma | lemmy_gamma | [127.0.0.1:8560](http://127.0.0.1:8560) | federated with all other instances
lemmy-delta | lemmy_delta | [127.0.0.1:8570](http://127.0.0.1:8570) | only allows federation with lemmy-beta
lemmy-epsilon | lemmy_epsilon | [127.0.0.1:8580](http://127.0.0.1:8580) | uses blocklist, has lemmy-alpha blocked
You can log into each using the instance name, and `lemmy` as the password, IE (`lemmy_alpha`, `lemmy`).
To start federation between instances, visit one of them and search for a user, community or post, like this:
- `[email protected]:8540`
- `http://lemmy-beta:8550/post/3`
- `@[email protected]:8560`
Firefox containers are a good way to test them interacting.
## Integration tests
To run a suite of suite of federation integration tests:
```bash
cd docker/federation
./run-tests.bash
```
## Running on a server
Note that federation is currently in alpha. **Only use it for testing**, not on any production server, and be aware that turning on federation may break your instance.
Follow the normal installation instructions, either with [Ansible](administration_install_ansible.md) or
[manually](administration_install_docker.md). Then replace the line `image: dessalines/lemmy:v0.x.x` in
`/lemmy/docker-compose.yml` with `image: dessalines/lemmy:federation`. Also add the following in
`/lemmy/lemmy.hjson`:
```
federation: {
enabled: true
tls_enabled: true,
allowed_instances: example.com,
}
```
Afterwards, and whenever you want to update to the latest version, run these commands on the server:
```
cd /lemmy/
sudo docker-compose pull
sudo docker-compose up -d
```
## Security Model
- HTTP signature verify: This ensures that activity really comes from the activity that it claims
- check_is_apub_valid : Makes sure its in our allowed instances list
- Lower level checks: To make sure that the user that creates/updates/removes a post is actually on the same instance as that post
For the last point, note that we are *not* checking whether the actor that sends the create activity for a post is
actually identical to the post's creator, or that the user that removes a post is a mod/admin. These things are checked
by the API code, and its the responsibility of each instance to check user permissions. This does not leave any attack
vector, as a normal instance user cant do actions that violate the API rules. The only one who could do that is the
admin (and the software deployed by the admin). But the admin can do anything on the instance, including send activities
from other user accounts. So we wouldnt actually gain any security by checking mod permissions or similar.

151
docs/src/contributing_local_development.md

@ -1,151 +0,0 @@
### Install build requirements
#### Ubuntu
```
sudo apt install git cargo libssl-dev pkg-config libpq-dev yarn curl gnupg2 espeak
# install yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install yarn
```
#### macOS
Install Rust using [the recommended option on rust-lang.org](https://www.rust-lang.org/tools/install) (rustup).
Then, install [Homebrew](https://brew.sh/) if you don't already have it installed.
Finally, install Node and Yarn.
```
brew install node yarn
```
### Get the source code
```
git clone https://github.com/LemmyNet/lemmy.git
# or alternatively from gitea
# git clone https://yerbamate.dev/LemmyNet/lemmy.git
```
All the following commands need to be run either in `lemmy/server` or `lemmy/ui`, as indicated
by the `cd` command.
### Build the backend (Rust)
```
cd server
cargo build
# for development, use `cargo check` instead)
```
### Build the frontend (Typescript)
```
cd ui
yarn
yarn build
```
### Setup postgresql
#### Ubuntu
```
sudo apt install postgresql
sudo systemctl start postgresql
# Either execute server/db-init.sh, or manually initialize the postgres database:
sudo -u postgres psql -c "create user lemmy with password 'password' superuser;" -U postgres
sudo -u postgres psql -c 'create database lemmy with owner lemmy;' -U postgres
export LEMMY_DATABASE_URL=postgres://lemmy:[email protected]:5432/lemmy
```
#### macOS
```
brew install postgresql
brew services start postgresql
/usr/local/opt/postgres/bin/createuser -s postgres
# Either execute server/db-init.sh, or manually initialize the postgres database:
psql -c "create user lemmy with password 'password' superuser;" -U postgres
psql -c 'create database lemmy with owner lemmy;' -U postgres
export LEMMY_DATABASE_URL=postgres://lemmy:[email protected]:5432/lemmy
```
### Run a local development instance
```
# run each of these in a seperate terminal
cd server && cargo run
cd ui && yarn start
```
Then open [localhost:4444](http://localhost:4444) in your browser. It will auto-refresh if you edit
any frontend files. For backend coding, you will have to rerun `cargo run`. You can use
`cargo check` as a faster way to find compilation errors.
To speed up incremental builds, you can add the following to `~/.cargo/config`:
```
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Clink-arg=-fuse-ld=lld"]
```
Note that this setup doesn't include image uploads or link previews (provided by pict-rs and
iframely respectively). If you want to test those, you should use the
[Docker development](contributing_docker_development.md).
### macOS
#### Build Requirements
```
# install homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
brew install git cargo [email protected] pkg-config libpq yarn curl gnupg2
```
#### Get the source code
```
git clone https://github.com/LemmyNet/lemmy.git
# or alternatively from gitea
# git clone https://yerbamate.dev/LemmyNet/lemmy.git
```
All the following commands need to be run either in `lemmy/server` or `lemmy/ui`, as indicated
by the `cd` command.
#### Build the backend (Rust)
```
cd server
cargo build
# for development, use `cargo check` instead)
```
#### Build the frontend (Typescript)
```
cd ui
yarn
yarn build
```
#### Setup postgresql
```
brew instal postgresql
brew services start postgresql
/usr/local/opt/postgres/bin/createuser -s postgres
cd server
./db-init.sh
```
#### Run a local development instance
```
# run each of these in a seperate terminal
cd server && cargo run
ui & yarn start
```
Then open [localhost:4444](http://localhost:4444) in your browser. It will auto-refresh if you edit
any frontend files. For backend coding, you will have to rerun `cargo run`. You can use
`cargo check` as a faster way to find compilation errors.
To speed up incremental builds, you can add the following to `~/.cargo/config`:
```
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Clink-arg=-fuse-ld=lld"]
```

16
docs/src/contributing_tests.md

@ -1,16 +0,0 @@
### Tests
#### Rust
After installing [local development dependencies](contributing_local_development.md), run the
following commands in the `server` subfolder:
```bash
psql -U lemmy -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
./test.sh
```
### Federation
Install the [Docker development dependencies](contributing_docker_development.md), and execute
`docker/federation-test/run-tests.sh`

18
docs/src/contributing_theming.md

@ -1,18 +0,0 @@
# Theming Guide
Lemmy uses [Bootstrap v4](https://getbootstrap.com/), and very few custom css classes, so any bootstrap v4 compatible theme should work fine.
## Creating
- Use a tool like [bootstrap.build](https://bootstrap.build/) to create a bootstrap v4 theme. Export the `bootstrap.min.css` once you're done, and save the `_variables.scss` too.
## Testing
- To test out a theme, you can either use your browser's web tools, or a plugin like stylus to copy-paste a theme, when viewing Lemmy.
## Adding
1. Copy `{my-theme-name}.min.css` to `ui/assets/css/themes`. (You can also copy the `_variables.scss` here if you want).
1. Go to `ui/src/utils.ts` and add `{my-theme-name}` to the themes list.
1. Test locally
1. Do a pull request with those changes.

1884
docs/src/contributing_websocket_http_api.md
File diff suppressed because it is too large
View File

79
docs/src/lemmy_council.md

@ -1,79 +0,0 @@
# Lemmy Council
- A group of lemmy developers and users that use a well-defined democratic process to steer the project in a positive direction, keep it aligned to community goals, and resolve conflicts.
- Council members are also added as administrators to any official Lemmy instances.
## 1. What gets voted on
This section describes all the aspects of Lemmy where the council has decision making power, namely:
- Coding direction
- Priorities / Emphasis
- Controversial features (For example, an unpopular feature should be removed)
- Moderation and conflict resolution on:
- [dev.lemmy.ml](https://dev.lemmy.ml/)
- [github.com/LemmyNet/lemmy](https://github.com/LemmyNet/lemmy)
- [yerbamate.dev/LemmyNet/lemmy](https://yerbamate.dev/LemmyNet/lemmy)
- [weblate.yerbamate.dev/projects/lemmy/](https://weblate.yerbamate.dev/projects/lemmy/)
- Technical administration of dev.lemmy.ml
- Official Lemmy accounts
- [Mastodon](https://mastodon.social/@LemmyDev)
- [Liberapay](https://liberapay.com/Lemmy/)
- [Patreon](https://www.patreon.com/dessalines)
- Council membership changes
- Changes to these rules
## 2. Feedback and Activity Reports
Every week, the council should make a thread on Lemmy that details its activity during the past week, be it development, moderation, or anything else mentioned in 1.
At the same time, users can give feedback and suggestions in this thread. This should be taken into account by the council. Council members can call for a vote on any controversial issues, if they can't be resolved by discussion.
## 2. Voting Process
Most of the time, we keep each other up to date through the Matrix chat, and take informal decisions on uncontroversial issues. For example, a user clearly violating the site rules could be banned by a single person, or ideally after discussing it with at least one other member.
If an issue can not be resolved in this way, then any council member can call for a vote, which works in the following way:
- Any council member can call for a vote, on any topic mentioned in 1.
- This should be used if there is any controversy in the community, or between council members.
- Before taking any decision, there needs to be a discussion where every council member can
explain their position.
- Discussion should be taken with the goal of reaching a compromise that is acceptable for
everyone.
- After the discussion, voting is done through Matrix emojis (👍: yes, 👎: no, X: abstain) and must
stay open for at least two days.
- All members of the Lemmy council have equal voting power.
- Decisions should be reached unanimously, or nearly so. If this is not possible, at least
2/3 of votes must be in favour for the motion to pass.
- Once a decision is reached in this way, every member needs to abide by it.
## 4. Joining
- We use the following process: anyone who is active around Lemmy can recommend any other active person to join the council. This has to be approved by a majority of the council.
- Active users are defined as those who contribute to Lemmy in some way for at least an hour per week on average, doing things like reporting bugs, discussing rules and features, translating, promoting, developing, or doing other things that aim to improve Lemmy as a whole.
-> people should have joined at least a month ago.
- The member list is public.
- Note: we would like to have a process where community members can elect candidates for the council, but this is not realistic because a single user could easily create multiple accounts and cheat the vote.
- Limit growth to one new member per month at most.
## 5. Removing members
- Inactive members should be removed from the council after a few months of inactivity, and after receiving a notification about this.
- Members that dont follow binding council decisions should be removed.
- Any member can be removed in a vote.
## 6. Goals
- We encourage the membership of groups such as LGBT, religious or ethnic minorities, abuse victims, etc etc, and strive to create a safe space for them to express their opinions. We also support measures to increase participation by the previously mentioned groups.
- The following are banned, and will always be harshly punished: fascism, abuse, racism, sexism, etc etc,
## 7. Communication
- A private Matrix chat for all council members.
- (Once private communities are done) A private community on dev.lemmy.ml for issues.
## 8. Member List / Contact Info
General Contact [@LemmyDev Mastodon](https://mastodon.social/@LemmyDev)
- [Dessalines](https://dev.lemmy.ml/u/dessalines)
- [Nutomic](https://dev.lemmy.ml/u/nutomic)
- [AgreeableLandscape](https://dev.lemmy.ml/u/AgreeableLandscape)
- [fruechtchen](https://dev.lemmy.ml/u/fruechtchen)
- [kixiQu](https://dev.lemmy.ml/u/kixiQu)

1
server/lemmy_utils/src/settings.rs

@ -13,7 +13,6 @@ pub struct Settings {
pub bind: IpAddr,
pub port: u16,
pub jwt_secret: String,
pub front_end_dir: String,
pub pictrs_url: String,
pub rate_limit: RateLimitConfig,
pub email: Option<EmailConfig>,

12
server/src/main.rs

@ -98,7 +98,6 @@ async fn main() -> Result<(), LemmyError> {
.allow_any_header()
.max_age(3600);
let settings = Settings::get();
let rate_limiter = rate_limiter.clone();
App::new()
.wrap_fn(add_cache_headers)
@ -110,19 +109,8 @@ async fn main() -> Result<(), LemmyError> {
.configure(federation::config)
.configure(feeds::config)
.configure(|cfg| images::config(cfg, &rate_limiter))
.configure(index::config)
.configure(nodeinfo::config)
.configure(webfinger::config)
// static files
.service(
actix_files::Files::new("/static", settings.front_end_dir.to_owned())
.use_etag(true)
.use_last_modified(true),
)
.service(actix_files::Files::new(
"/docs",
settings.front_end_dir + "/documentation",
))
})
.bind((settings.bind, settings.port))?
.run()

59
server/src/routes/index.rs

@ -1,59 +0,0 @@
use actix_files::NamedFile;
use actix_web::*;
use lemmy_utils::settings::Settings;
pub fn config(cfg: &mut web::ServiceConfig) {
cfg
.route("/", web::get().to(index))
.route(
"/home/data_type/{data_type}/listing_type/{listing_type}/sort/{sort}/page/{page}",
web::get().to(index),
)
.route("/login", web::get().to(index))
.route("/create_post", web::get().to(index))
.route("/create_community", web::get().to(index))
.route("/create_private_message", web::get().to(index))
.route("/communities/page/{page}", web::get().to(index))
.route("/communities", web::get().to(index))
.route("/post/{id}/comment/{id2}", web::get().to(index))
.route("/post/{id}", web::get().to(index))
.route(
"/c/{name}/data_type/{data_type}/sort/{sort}/page/{page}",
web::get().to(index),
)
.route("/c/{name}", web::get().to(index))
.route("/community/{id}", web::get().to(index))
.route(
"/u/{username}/view/{view}/sort/{sort}/page/{page}",
web::get().to(index),
)
.route("/u/{username}", web::get().to(index))
.route("/user/{id}", web::get().to(index))
.route("/inbox", web::get().to(index))
.route("/modlog/community/{community_id}", web::get().to(index))
.route("/modlog", web::get().to(index))
.route("/setup", web::get().to(index))
.route("/admin", web::get().to(index))
.route("/sitemod", web::get().to(index))
.route(
"/search/q/{q}/type/{type}/sort/{sort}/page/{page}",
web::get().to(index),
)
.route("/search", web::get().to(index))
.route("/sponsors", web::get().to(index))
.route("/contributing", web::get().to(index))
.route("/welcome", web::get().to(index))
.route("/about", web::get().to(index))
.route("/ppb", web::get().to(index))
.route("/reports", web::get().to(index))
.route("/privacy_policy", web::get().to(index))
.route("/tos", web::get().to(index))
.route("/password_change/{token}", web::get().to(index))
.route("/instances", web::get().to(index));
}
async fn index() -> Result<NamedFile, Error> {
Ok(NamedFile::open(
Settings::get().front_end_dir + "/index.html",
)?)
}

1
server/src/routes/mod.rs

@ -2,7 +2,6 @@ pub mod api;
pub mod federation;
pub mod feeds;
pub mod images;
pub mod index;
pub mod nodeinfo;
pub mod webfinger;
pub mod websocket;

1
ui

@ -1 +0,0 @@
Subproject commit 2c5069567167c3a6ca4cc4e30685d5acd3a1efd5
Loading…
Cancel
Save