From d80e8fc075bc9afb699afd1d6e5e5f79a0db9cd1 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 31 Dec 2019 15:31:34 +0100 Subject: Use mdbook for documentation (fixes #375) --- docs/.gitignore | 1 + docs/api.md | 1031 ------------------------- docs/apub_api_outline.md | 378 --------- docs/book.toml | 6 + docs/goals.md | 44 -- docs/ranking.md | 29 - docs/src/SUMMARY.md | 17 + docs/src/about.md | 22 + docs/src/about_features.md | 26 + docs/src/about_goals.md | 44 ++ docs/src/about_ranking.md | 29 + docs/src/administration.md | 1 + docs/src/administration_configuration.md | 6 + docs/src/administration_install_ansible.md | 11 + docs/src/administration_install_docker.md | 28 + docs/src/administration_install_kubernetes.md | 22 + docs/src/contributing.md | 1 + docs/src/contributing_apub_api_outline.md | 378 +++++++++ docs/src/contributing_docker_development.md | 11 + docs/src/contributing_local_development.md | 24 + docs/src/contributing_translations.md | 23 + docs/src/contributing_websocket_api.md | 1031 +++++++++++++++++++++++++ 22 files changed, 1681 insertions(+), 1482 deletions(-) create mode 100644 docs/.gitignore delete mode 100644 docs/api.md delete mode 100644 docs/apub_api_outline.md create mode 100644 docs/book.toml delete mode 100644 docs/goals.md delete mode 100644 docs/ranking.md create mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/about.md create mode 100644 docs/src/about_features.md create mode 100644 docs/src/about_goals.md create mode 100644 docs/src/about_ranking.md create mode 100644 docs/src/administration.md create mode 100644 docs/src/administration_configuration.md create mode 100644 docs/src/administration_install_ansible.md create mode 100644 docs/src/administration_install_docker.md create mode 100644 docs/src/administration_install_kubernetes.md create mode 100644 docs/src/contributing.md create mode 100644 docs/src/contributing_apub_api_outline.md create mode 100644 docs/src/contributing_docker_development.md create mode 100644 docs/src/contributing_local_development.md create mode 100644 docs/src/contributing_translations.md create mode 100644 docs/src/contributing_websocket_api.md (limited to 'docs') diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..7585238e --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 16383d53..00000000 --- a/docs/api.md +++ /dev/null @@ -1,1031 +0,0 @@ -# Lemmy API -*Note: this may lag behind the actual API endpoints [here](../server/src/api).* - - - -- [Data types](#data-types) -- [Basic usage](#basic-usage) - * [WebSocket Endpoint](#websocket-endpoint) - * [Testing with Websocat](#testing-with-websocat) - * [Testing with the WebSocket JavaScript API](#testing-with-the-websocket-javascript-api) -- [Rate limits](#rate-limits) -- [Errors](#errors) -- [API documentation](#api-documentation) - * [Sort Types](#sort-types) - * [User / Authentication / Admin actions](#user--authentication--admin-actions) - + [Login](#login) - - [Request](#request) - - [Response](#response) - + [Register](#register) - - [Request](#request-1) - - [Response](#response-1) - + [Get User Details](#get-user-details) - - [Request](#request-2) - - [Response](#response-2) - + [Save User Settings](#save-user-settings) - - [Request](#request-3) - - [Response](#response-3) - + [Get Replies / Inbox](#get-replies--inbox) - - [Request](#request-4) - - [Response](#response-4) - + [Get User Mentions](#get-user-mentions) - - [Request](#request-5) - - [Response](#response-5) - + [Mark All As Read](#mark-all-as-read) - - [Request](#request-6) - - [Response](#response-6) - + [Delete Account](#delete-account) - - [Request](#request-7) - - [Response](#response-7) - + [Add admin](#add-admin) - - [Request](#request-8) - - [Response](#response-8) - + [Ban user](#ban-user) - - [Request](#request-9) - - [Response](#response-9) - * [Site](#site) - + [List Categories](#list-categories) - - [Request](#request-10) - - [Response](#response-10) - + [Search](#search) - - [Request](#request-11) - - [Response](#response-11) - + [Get Modlog](#get-modlog) - - [Request](#request-12) - - [Response](#response-12) - + [Create Site](#create-site) - - [Request](#request-13) - - [Response](#response-13) - + [Edit Site](#edit-site) - - [Request](#request-14) - - [Response](#response-14) - + [Get Site](#get-site) - - [Request](#request-15) - - [Response](#response-15) - + [Transfer Site](#transfer-site) - - [Request](#request-16) - - [Response](#response-16) - * [Community](#community) - + [Get Community](#get-community) - - [Request](#request-17) - - [Response](#response-17) - + [Create Community](#create-community) - - [Request](#request-18) - - [Response](#response-18) - + [List Communities](#list-communities) - - [Request](#request-19) - - [Response](#response-19) - + [Ban from Community](#ban-from-community) - - [Request](#request-20) - - [Response](#response-20) - + [Add Mod to Community](#add-mod-to-community) - - [Request](#request-21) - - [Response](#response-21) - + [Edit Community](#edit-community) - - [Request](#request-22) - - [Response](#response-22) - + [Follow Community](#follow-community) - - [Request](#request-23) - - [Response](#response-23) - + [Get Followed Communities](#get-followed-communities) - - [Request](#request-24) - - [Response](#response-24) - + [Transfer Community](#transfer-community) - - [Request](#request-25) - - [Response](#response-25) - * [Post](#post) - + [Create Post](#create-post) - - [Request](#request-26) - - [Response](#response-26) - + [Get Post](#get-post) - - [Request](#request-27) - - [Response](#response-27) - + [Get Posts](#get-posts) - - [Request](#request-28) - - [Response](#response-28) - + [Create Post Like](#create-post-like) - - [Request](#request-29) - - [Response](#response-29) - + [Edit Post](#edit-post) - - [Request](#request-30) - - [Response](#response-30) - + [Save Post](#save-post) - - [Request](#request-31) - - [Response](#response-31) - * [Comment](#comment) - + [Create Comment](#create-comment) - - [Request](#request-32) - - [Response](#response-32) - + [Edit Comment](#edit-comment) - - [Request](#request-33) - - [Response](#response-33) - + [Save Comment](#save-comment) - - [Request](#request-34) - - [Response](#response-34) - + [Create Comment Like](#create-comment-like) - - [Request](#request-35) - - [Response](#response-35) - * [RSS / Atom feeds](#rss--atom-feeds) - + [All](#all) - + [Community](#community-1) - + [User](#user) - - - -## Data types - -- `i16`, `i32` and `i64` are respectively [16-bit](https://en.wikipedia.org/wiki/16-bit), [32-bit](https://en.wikipedia.org/wiki/32-bit) and [64-bit](https://en.wikipedia.org/wiki/64-bit_computing) integers. -- Option<***SomeType***> designates an option which may be omitted in requests and not be present in responses. It will be of type ***SomeType***. -- Vec<***SomeType***> is a list which contains objects of type ***SomeType***. -- `chrono::NaiveDateTime` is a timestamp string in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format. Timestamps will be UTC. -- Other data types are listed [here](../server/src/db). - -## Basic usage - -Request and response strings are in [JSON format](https://www.json.org). - -### WebSocket Endpoint - -Connect to ws://***host***/api/v1/ws to get started. - -If the ***`host`*** supports secure connections, you can use wss://***host***/api/v1/ws. - -### Testing with Websocat - -[Websocat link](https://github.com/vi/websocat) - -`websocat ws://127.0.0.1:8536/api/v1/ws -nt` - -A simple test command: -`{"op": "ListCategories"}` - -### Testing with the WebSocket JavaScript API - -[WebSocket JavaScript API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) -```javascript -var ws = new WebSocket("ws://" + host + "/api/v1/ws"); -ws.onopen = function () { - console.log("Connection succeed!"); - ws.send(JSON.stringify({ - op: "ListCategories" - })); -}; -``` - -## Rate limits - -- 1 per hour for signups and community creation. -- 1 per 10 minutes for post creation. -- 30 actions per minute for post voting and comment creation. -- Everything else is not rate-limited. - -## Errors -```rust -{ - op: String, - message: String, -} -``` - -## API documentation - -### Sort Types - -These go wherever there is a `sort` field. The available sort types are: - -- `Hot` - the hottest posts/communities, depending on votes, views, comments and publish date -- `New` - the newest posts/communities -- `TopDay` - the most upvoted posts/communities of the current day. -- `TopWeek` - the most upvoted posts/communities of the current week. -- `TopMonth` - the most upvoted posts/communities of the current month. -- `TopYear` - the most upvoted posts/communities of the current year. -- `TopAll` - the most upvoted posts/communities on the current instance. - -### User / Authentication / Admin actions - -#### Login - -The `jwt` string should be stored and used anywhere `auth` is called for. - -##### Request -```rust -{ - op: "Login", - data: { - username_or_email: String, - password: String - } -} -``` -##### Response -```rust -{ - op: String, - jwt: String -} -``` - - -#### Register -Only the first user will be able to be the admin. - -##### Request -```rust -{ - op: "Register", - data: { - username: String, - email: Option, - password: String, - password_verify: String, - admin: bool - } -} -``` -##### Response -```rust -{ - op: String, - jwt: String -} -``` - -#### Get User Details -##### Request -```rust -{ - op: "GetUserDetails", - data: { - user_id: Option, - username: Option, - sort: String, - page: Option, - limit: Option, - community_id: Option, - saved_only: bool, - auth: Option, - } -} -``` -##### Response -```rust -{ - op: String, - user: UserView, - follows: Vec, - moderates: Vec, - comments: Vec, - posts: Vec, -} -``` -#### Save User Settings -##### Request -```rust -{ - op: "SaveUserSettings", - data: { - show_nsfw: bool, - theme: String, // Default 'darkly' - default_sort_type: i16, // The Sort types from above, zero indexed as a number - default_listing_type: i16, // Post listing types are `All, Subscribed, Community` - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - jwt: String -} -``` -#### Get Replies / Inbox -##### Request -```rust -{ - op: "GetReplies", - data: { - sort: String, - page: Option, - limit: Option, - unread_only: bool, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - replies: Vec, -} -``` - -#### Get User Mentions -##### Request -```rust -{ - op: "GetUserMentions", - data: { - sort: String, - page: Option, - limit: Option, - unread_only: bool, - auth: String, - } -} -``` -##### Response -```rust -{ - op: String, - mentions: Vec, -} -``` - -#### Mark All As Read - -Marks all user replies and mentions as read. - -##### Request -```rust -{ - op: "MarkAllAsRead", - data: { - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - replies: Vec, -} -``` - -#### Delete Account - -*Permananently deletes your posts and comments* - -##### Request -```rust -{ - op: "DeleteAccount", - data: { - password: String, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - jwt: String, -} -``` - -#### Add admin -##### Request -```rust -{ - op: "AddAdmin", - data: { - user_id: i32, - added: bool, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - admins: Vec, -} -``` - -#### Ban user -##### Request -```rust -{ - op: "BanUser", - data: { - user_id: i32, - ban: bool, - reason: Option, - expires: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - user: UserView, - banned: bool, -} -``` - -### Site -#### List Categories -##### Request -```rust -{ - op: "ListCategories" -} -``` -##### Response -```rust -{ - op: String, - categories: Vec -} -``` - -#### Search -Search types are `Both, Comments, Posts`. - -##### Request -```rust -{ - op: "Search", - data: { - q: String, - type_: String, - community_id: Option, - sort: String, - page: Option, - limit: Option, - } -} -``` -##### Response -```rust -{ - op: String, - comments: Vec, - posts: Vec, -} -``` - -#### Get Modlog -##### Request -```rust -{ - op: "GetModlog", - data: { - mod_user_id: Option, - community_id: Option, - page: Option, - limit: Option, - } -} -``` -##### Response -```rust -{ - op: String, - removed_posts: Vec, - locked_posts: Vec, - removed_comments: Vec, - removed_communities: Vec, - banned_from_community: Vec, - banned: Vec, - added_to_community: Vec, - added: Vec, -} -``` - -#### Create Site -##### Request -```rust -{ - op: "CreateSite", - data: { - name: String, - description: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - site: SiteView, -} -``` - -#### Edit Site -##### Request -```rust -{ - op: "EditSite", - data: { - name: String, - description: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - site: SiteView, -} -``` - -#### Get Site -##### Request -```rust -{ - op: "GetSite" -} -``` -##### Response -```rust -{ - op: String, - site: Option, - admins: Vec, - banned: Vec, -} -``` - -#### Transfer Site -##### Request -```rust -{ - op: "TransferSite", - data: { - user_id: i32, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - site: Option, - admins: Vec, - banned: Vec, -} -``` - -### Community -#### Get Community -##### Request -```rust -{ - op: "GetCommunity", - data: { - id: Option, - name: Option, - auth: Option - } -} -``` -##### Response -```rust -{ - op: String, - community: CommunityView, - moderators: Vec, - admins: Vec, -} -``` - -#### Create Community -##### Request -```rust -{ - op: "CreateCommunity", - data: { - name: String, - title: String, - description: Option, - category_id: i32 , - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - community: CommunityView -} -``` - -#### List Communities -##### Request -```rust -{ - op: "ListCommunities", - data: { - sort: String, - page: Option, - limit: Option, - auth: Option - } -} -``` -##### Response -```rust -{ - op: String, - communities: Vec -} -``` - -#### Ban from Community -##### Request -```rust -{ - op: "BanFromCommunity", - data: { - community_id: i32, - user_id: i32, - ban: bool, - reason: Option, - expires: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - user: UserView, - banned: bool, -} -``` - -#### Add Mod to Community -##### Request -```rust -{ - op: "AddModToCommunity", - data: { - community_id: i32, - user_id: i32, - added: bool, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - moderators: Vec, -} -``` - -#### Edit Community -Mods and admins can remove and lock a community, creators can delete it. - -##### Request -```rust -{ - op: "EditCommunity", - data: { - edit_id: i32, - name: String, - title: String, - description: Option, - category_id: i32, - removed: Option, - deleted: Option, - reason: Option, - expires: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - community: CommunityView -} -``` - -#### Follow Community -##### Request -```rust -{ - op: "FollowCommunity", - data: { - community_id: i32, - follow: bool, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - community: CommunityView -} -``` - -#### Get Followed Communities -##### Request -```rust -{ - op: "GetFollowedCommunities", - data: { - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - communities: Vec -} -``` - -#### Transfer Community -##### Request -```rust -{ - op: "TransferCommunity", - data: { - community_id: i32, - user_id: i32, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - community: CommunityView, - moderators: Vec, - admins: Vec, -} -``` - -### Post -#### Create Post -##### Request -```rust -{ - op: "CreatePost", - data: { - name: String, - url: Option, - body: Option, - community_id: i32, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - post: PostView -} -``` - -#### Get Post -##### Request -```rust -{ - op: "GetPost", - data: { - id: i32, - auth: Option - } -} -``` -##### Response -```rust -{ - op: String, - post: PostView, - comments: Vec, - community: CommunityView, - moderators: Vec, - admins: Vec, -} -``` - -#### Get Posts -Post listing types are `All, Subscribed, Community` - -##### Request -```rust -{ - op: "GetPosts", - data: { - type_: String, - sort: String, - page: Option, - limit: Option, - community_id: Option, - auth: Option - } -} -``` -##### Response -```rust -{ - op: String, - posts: Vec, -} -``` - -#### Create Post Like -`score` can be 0, -1, or 1 - -##### Request -```rust -{ - op: "CreatePostLike", - data: { - post_id: i32, - score: i16, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - post: PostView -} -``` - -#### Edit Post -Mods and admins can remove and lock a post, creators can delete it. - -##### Request -```rust -{ - op: "EditPost", - data: { - edit_id: i32, - creator_id: i32, - community_id: i32, - name: String, - url: Option, - body: Option, - removed: Option, - deleted: Option, - locked: Option, - reason: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - post: PostView -} -``` - -#### Save Post -##### Request -```rust -{ - op: "SavePost", - data: { - post_id: i32, - save: bool, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - post: PostView -} -``` - -### Comment -#### Create Comment -##### Request -```rust -{ - op: "CreateComment", - data: { - content: String, - parent_id: Option, - edit_id: Option, - post_id: i32, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - comment: CommentView -} -``` - -#### Edit Comment -Mods and admins can remove a comment, creators can delete it. - -##### Request -```rust -{ - op: "EditComment", - data: { - content: String, - parent_id: Option, - edit_id: i32, - creator_id: i32, - post_id: i32, - removed: Option, - deleted: Option, - reason: Option, - read: Option, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - comment: CommentView -} -``` - -#### Save Comment -##### Request -```rust -{ - op: "SaveComment", - data: { - comment_id: i32, - save: bool, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - comment: CommentView -} -``` - -#### Create Comment Like -`score` can be 0, -1, or 1 - -##### Request -```rust -{ - op: "CreateCommentLike", - data: { - comment_id: i32, - post_id: i32, - score: i16, - auth: String - } -} -``` -##### Response -```rust -{ - op: String, - comment: CommentView -} -``` - -### RSS / Atom feeds - -#### All - -`/feeds/all.xml?sort=Hot` - -#### Community - -`/feeds/c/community-name.xml?sort=Hot` - -#### User - -`/feeds/u/user-name.xml?sort=Hot` - diff --git a/docs/apub_api_outline.md b/docs/apub_api_outline.md deleted file mode 100644 index e2776308..00000000 --- a/docs/apub_api_outline.md +++ /dev/null @@ -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. - - - -- [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) - - - -## 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 -} -``` - diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 00000000..55cce8c0 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,6 @@ +[book] +authors = ["Felix Ableitner"] +language = "en" +multilingual = false +src = "src" +title = "Lemmy Documentation" diff --git a/docs/goals.md b/docs/goals.md deleted file mode 100644 index d8a71794..00000000 --- a/docs/goals.md +++ /dev/null @@ -1,44 +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 -- 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/) -- [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) -- 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/ - diff --git a/docs/ranking.md b/docs/ranking.md deleted file mode 100644 index 361dc24d..00000000 --- a/docs/ranking.md +++ /dev/null @@ -1,29 +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 -``` - -- 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://i.imgur.com/w8oBLlL.png) diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 00000000..9fc0fa87 --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,17 @@ +# Summary + +- [About](about.md) + - [Features](about_features.md) + - [Goals](about_goals.md) + - [Post and Comment Ranking](about_ranking.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) +- [Contributing](contributing.md) + - [Translations](contributing_translations.md) + - [Docker Development](contributing_docker_development.md) + - [Local Development](contributing_local_development.md) + - [Websocket API](contributing_websocket_api.md) + - [ActivityPub API Outline](contributing_apub_api_outline.md) diff --git a/docs/src/about.md b/docs/src/about.md new file mode 100644 index 00000000..14743df2 --- /dev/null +++ b/docs/src/about.md @@ -0,0 +1,22 @@ +

A link aggregator / reddit clone for the fediverse. +
+

+ +[Lemmy Dev instance](https://dev.lemmy.ml) *for testing purposes only* + +[Lemmy](https://github.com/dessalines/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse). + +For a link aggregator, this means a user registered on one server can subscribe to forums on any other server, and can have discussions with users registered elsewhere. + +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. + +### Why's it called Lemmy? + +- Lead singer from [Motörhead](https://invidio.us/watch?v=pWB5JZRGl0U). +- The old school [video game](). +- The [Koopa from Super Mario](https://www.mariowiki.com/Lemmy_Koopa). +- The [furry rodents](http://sunchild.fpwc.org/lemming-the-little-giant-of-the-north/). + +Made with [Rust](https://www.rust-lang.org), [Actix](https://actix.rs/), [Inferno](https://www.infernojs.org), [Typescript](https://www.typescriptlang.org/) and [Diesel](http://diesel.rs/). diff --git a/docs/src/about_features.md b/docs/src/about_features.md new file mode 100644 index 00000000..dab859c1 --- /dev/null +++ b/docs/src/about_features.md @@ -0,0 +1,26 @@ +- Open source, [AGPL License](/LICENSE). +- Self hostable, easy to deploy. + - Comes with [Docker](#docker), [Ansible](#ansible), [Kubernetes](#kubernetes). +- Clean, mobile-friendly interface. + - 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 `#`. + - Notifications, on comment replies and when you're tagged. + - 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. + - 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. \ No newline at end of file diff --git a/docs/src/about_goals.md b/docs/src/about_goals.md new file mode 100644 index 00000000..d8a71794 --- /dev/null +++ b/docs/src/about_goals.md @@ -0,0 +1,44 @@ +# 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 +- 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/) +- [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) +- 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/ + diff --git a/docs/src/about_ranking.md b/docs/src/about_ranking.md new file mode 100644 index 00000000..361dc24d --- /dev/null +++ b/docs/src/about_ranking.md @@ -0,0 +1,29 @@ +# 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 +``` + +- 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://i.imgur.com/w8oBLlL.png) diff --git a/docs/src/administration.md b/docs/src/administration.md new file mode 100644 index 00000000..c4c2b01f --- /dev/null +++ b/docs/src/administration.md @@ -0,0 +1 @@ +Information for Lemmy instance admins, and those who want to start an instance. \ No newline at end of file diff --git a/docs/src/administration_configuration.md b/docs/src/administration_configuration.md new file mode 100644 index 00000000..73ea3504 --- /dev/null +++ b/docs/src/administration_configuration.md @@ -0,0 +1,6 @@ +The configuration is based on the file [defaults.hjson](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. + +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:password@lemmy_db:5432/lemmy`, passing all connection details at once. diff --git a/docs/src/administration_install_ansible.md b/docs/src/administration_install_ansible.md new file mode 100644 index 00000000..03642b89 --- /dev/null +++ b/docs/src/administration_install_ansible.md @@ -0,0 +1,11 @@ +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/dessalines/lemmy.git +cd lemmy/ansible/ +cp inventory.example inventory +nano inventory # enter your server, domain, contact email +ansible-playbook lemmy.yml --become +``` diff --git a/docs/src/administration_install_docker.md b/docs/src/administration_install_docker.md new file mode 100644 index 00000000..64abe737 --- /dev/null +++ b/docs/src/administration_install_docker.md @@ -0,0 +1,28 @@ +Make sure you have both docker and docker-compose(>=`1.24.0`) installed: + +```bash +mkdir lemmy/ +cd lemmy/ +wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml +wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/lemmy.hjson +# Edit lemmy.hjson to do more configuration +docker-compose up -d +``` + +and go to http://localhost:8536. + +[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 +``` +#### Updating + +To update to the newest version, run: + +```bash +wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml +docker-compose up -d +``` diff --git a/docs/src/administration_install_kubernetes.md b/docs/src/administration_install_kubernetes.md new file mode 100644 index 00000000..886558dc --- /dev/null +++ b/docs/src/administration_install_kubernetes.md @@ -0,0 +1,22 @@ +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. diff --git a/docs/src/contributing.md b/docs/src/contributing.md new file mode 100644 index 00000000..4f29af3d --- /dev/null +++ b/docs/src/contributing.md @@ -0,0 +1 @@ +Information about contributing to Lemmy, whether it is translating, testing, designing or programming. \ No newline at end of file diff --git a/docs/src/contributing_apub_api_outline.md b/docs/src/contributing_apub_api_outline.md new file mode 100644 index 00000000..e2776308 --- /dev/null +++ b/docs/src/contributing_apub_api_outline.md @@ -0,0 +1,378 @@ +# 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. + + + +- [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) + + + +## 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 +} +``` + diff --git a/docs/src/contributing_docker_development.md b/docs/src/contributing_docker_development.md new file mode 100644 index 00000000..0ed5bde5 --- /dev/null +++ b/docs/src/contributing_docker_development.md @@ -0,0 +1,11 @@ +Run: + +```bash +git clone https://github.com/dessalines/lemmy +cd lemmy/docker/dev +./docker_update.sh # This builds and runs it, updating for your changes +``` + +and go to http://localhost:8536. + +Note that compile times are relatively long with Docker, because builds can't be properly cached. If this is a problem for you, you should use [Local Development](contributing_local_development.md). \ No newline at end of file diff --git a/docs/src/contributing_local_development.md b/docs/src/contributing_local_development.md new file mode 100644 index 00000000..a681eeb0 --- /dev/null +++ b/docs/src/contributing_local_development.md @@ -0,0 +1,24 @@ +#### Requirements + +- [Rust](https://www.rust-lang.org/) +- [Yarn](https://yarnpkg.com/en/) +- [Postgres](https://www.postgresql.org/) + +#### Set up Postgres DB + +```bash + psql -c "create user lemmy with password 'password' superuser;" -U postgres + psql -c 'create database lemmy with owner lemmy;' -U postgres + export DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy +``` + +#### Running + +```bash +git clone https://github.com/dessalines/lemmy +cd lemmy +./install.sh +# For live coding, where both the front and back end, automagically reload on any save, do: +# cd ui && yarn start +# cd server && cargo watch -x run +``` diff --git a/docs/src/contributing_translations.md b/docs/src/contributing_translations.md new file mode 100644 index 00000000..de890770 --- /dev/null +++ b/docs/src/contributing_translations.md @@ -0,0 +1,23 @@ +If you'd like to add translations, take a look a look at the [English translation file](ui/src/translations/en.ts). + +- Languages supported: English (`en`), Chinese (`zh`), Dutch (`nl`), Esperanto (`eo`), French (`fr`), Spanish (`es`), Swedish (`sv`), German (`de`), Russian (`ru`), Italian (`it`). + +lang | done | missing +--- | --- | --- +de | 97% | avatar,downvotes_disabled,enable_downvotes,open_registration,registration_closed,enable_nsfw +eo | 84% | number_of_communities,preview,upload_image,avatar,formatting_help,view_source,sticky,unsticky,archive_link,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,forgot_password,reset_password_mail_sent,password_change,new_password,no_email_setup,language,browser_default,downvotes_disabled